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:
authorSiddhartha Jejurkar <f20180617@goa.bits-pilani.ac.in>2021-12-17 16:01:32 +0300
committerSiddhartha Jejurkar <f20180617@goa.bits-pilani.ac.in>2021-12-17 16:01:32 +0300
commitdbc41b30f88b96f7d8c6e995b17f5930eb55cc77 (patch)
treec6c495328443ea3621e5df2ef483b0e0dd504496
parent99a2af76d10e05a18987be5d554ada197b1ca086 (diff)
parent7c9e4099854a4fc8eab4db97173c1aacd25f9e08 (diff)
Merge branch 'master' into soc-2021-uv-edge-select-supportsoc-2021-uv-edge-select-support
-rw-r--r--.clang-tidy7
-rw-r--r--CMakeLists.txt68
-rw-r--r--build_files/cmake/config/blender_lite.cmake3
-rw-r--r--build_files/cmake/config/blender_release.cmake1
-rw-r--r--build_files/cmake/platform/platform_apple.cmake7
-rw-r--r--build_files/cmake/platform/platform_unix.cmake9
-rw-r--r--build_files/cmake/platform/platform_win32.cmake8
-rw-r--r--doc/doxygen/doxygen.intern.h117
-rw-r--r--doc/doxygen/doxygen.source.h21
-rwxr-xr-xdoc/manpage/blender.1.py4
-rw-r--r--doc/python_api/rst/bgl.rst18
-rw-r--r--doc/python_api/sphinx_doc_gen.py4
-rw-r--r--extern/hipew/README12
-rw-r--r--extern/hipew/README.blender5
-rw-r--r--extern/hipew/include/hipew.h43
-rw-r--r--extern/hipew/src/hipew.c40
-rw-r--r--extern/nanosvg/README.blender2
-rw-r--r--intern/atomic/atomic_ops.h2
-rw-r--r--intern/atomic/intern/atomic_ops_ext.h4
-rw-r--r--intern/atomic/intern/atomic_ops_msvc.h8
-rw-r--r--intern/atomic/intern/atomic_ops_unix.h4
-rw-r--r--intern/atomic/intern/atomic_ops_utils.h4
-rw-r--r--intern/clog/CLG_log.h8
-rw-r--r--intern/clog/clog.c4
-rw-r--r--intern/cycles/blender/CMakeLists.txt7
-rw-r--r--intern/cycles/blender/addon/camera.py84
-rw-r--r--intern/cycles/blender/addon/engine.py2
-rw-r--r--intern/cycles/blender/addon/properties.py57
-rw-r--r--intern/cycles/blender/addon/ui.py38
-rw-r--r--intern/cycles/blender/camera.cpp21
-rw-r--r--intern/cycles/blender/curves.cpp14
-rw-r--r--intern/cycles/blender/device.cpp4
-rw-r--r--intern/cycles/blender/geometry.cpp24
-rw-r--r--intern/cycles/blender/image.cpp10
-rw-r--r--intern/cycles/blender/image.h2
-rw-r--r--intern/cycles/blender/mesh.cpp6
-rw-r--r--intern/cycles/blender/object.cpp5
-rw-r--r--intern/cycles/blender/output_driver.cpp2
-rw-r--r--intern/cycles/blender/pointcloud.cpp253
-rw-r--r--intern/cycles/blender/python.cpp17
-rw-r--r--intern/cycles/blender/session.cpp9
-rw-r--r--intern/cycles/blender/shader.cpp25
-rw-r--r--intern/cycles/blender/sync.cpp9
-rw-r--r--intern/cycles/blender/sync.h9
-rw-r--r--intern/cycles/blender/util.h4
-rw-r--r--intern/cycles/bvh/CMakeLists.txt12
-rw-r--r--intern/cycles/bvh/build.cpp130
-rw-r--r--intern/cycles/bvh/build.h2
-rw-r--r--intern/cycles/bvh/bvh.cpp14
-rw-r--r--intern/cycles/bvh/bvh2.cpp28
-rw-r--r--intern/cycles/bvh/embree.cpp106
-rw-r--r--intern/cycles/bvh/embree.h5
-rw-r--r--intern/cycles/bvh/metal.h35
-rw-r--r--intern/cycles/bvh/metal.mm33
-rw-r--r--intern/cycles/bvh/optix.cpp10
-rw-r--r--intern/cycles/bvh/optix.h6
-rw-r--r--intern/cycles/bvh/params.h17
-rw-r--r--intern/cycles/bvh/split.cpp48
-rw-r--r--intern/cycles/bvh/split.h14
-rw-r--r--intern/cycles/cmake/external_libs.cmake19
-rw-r--r--intern/cycles/device/CMakeLists.txt49
-rw-r--r--intern/cycles/device/cpu/device_impl.cpp8
-rw-r--r--intern/cycles/device/cuda/device_impl.cpp20
-rw-r--r--intern/cycles/device/cuda/queue.cpp6
-rw-r--r--intern/cycles/device/cuda/queue.h4
-rw-r--r--intern/cycles/device/device.cpp40
-rw-r--r--intern/cycles/device/device.h3
-rw-r--r--intern/cycles/device/hip/device.cpp13
-rw-r--r--intern/cycles/device/hip/device_impl.cpp19
-rw-r--r--intern/cycles/device/hip/queue.cpp6
-rw-r--r--intern/cycles/device/hip/queue.h4
-rw-r--r--intern/cycles/device/memory.cpp39
-rw-r--r--intern/cycles/device/memory.h12
-rw-r--r--intern/cycles/device/metal/bvh.h66
-rw-r--r--intern/cycles/device/metal/bvh.mm813
-rw-r--r--intern/cycles/device/metal/device.h37
-rw-r--r--intern/cycles/device/metal/device.mm136
-rw-r--r--intern/cycles/device/metal/device_impl.h166
-rw-r--r--intern/cycles/device/metal/device_impl.mm1008
-rw-r--r--intern/cycles/device/metal/kernel.h168
-rw-r--r--intern/cycles/device/metal/kernel.mm525
-rw-r--r--intern/cycles/device/metal/queue.h99
-rw-r--r--intern/cycles/device/metal/queue.mm610
-rw-r--r--intern/cycles/device/metal/util.h101
-rw-r--r--intern/cycles/device/metal/util.mm218
-rw-r--r--intern/cycles/device/multi/device.cpp18
-rw-r--r--intern/cycles/device/optix/device_impl.cpp361
-rw-r--r--intern/cycles/device/optix/device_impl.h12
-rw-r--r--intern/cycles/device/optix/queue.cpp8
-rw-r--r--intern/cycles/device/optix/queue.h4
-rw-r--r--intern/cycles/device/queue.h70
-rw-r--r--intern/cycles/graph/node.h2
-rw-r--r--intern/cycles/integrator/denoiser_oidn.cpp13
-rw-r--r--intern/cycles/integrator/pass_accessor_gpu.cpp36
-rw-r--r--intern/cycles/integrator/path_trace.cpp8
-rw-r--r--intern/cycles/integrator/path_trace_work_gpu.cpp148
-rw-r--r--intern/cycles/integrator/render_scheduler.cpp8
-rw-r--r--intern/cycles/integrator/shader_eval.cpp14
-rw-r--r--intern/cycles/integrator/tile.cpp5
-rw-r--r--intern/cycles/integrator/tile.h3
-rw-r--r--intern/cycles/integrator/work_tile_scheduler.cpp7
-rw-r--r--intern/cycles/integrator/work_tile_scheduler.h6
-rw-r--r--intern/cycles/kernel/CMakeLists.txt4
-rw-r--r--intern/cycles/kernel/bvh/bvh.h312
-rw-r--r--intern/cycles/kernel/bvh/metal.h47
-rw-r--r--intern/cycles/kernel/bvh/shadow_all.h29
-rw-r--r--intern/cycles/kernel/bvh/traversal.h28
-rw-r--r--intern/cycles/kernel/bvh/types.h1
-rw-r--r--intern/cycles/kernel/bvh/util.h24
-rw-r--r--intern/cycles/kernel/camera/projection.h57
-rw-r--r--intern/cycles/kernel/closure/bsdf.h2
-rw-r--r--intern/cycles/kernel/device/gpu/kernel.h38
-rw-r--r--intern/cycles/kernel/device/gpu/work_stealing.h25
-rw-r--r--intern/cycles/kernel/device/metal/compat.h31
-rw-r--r--intern/cycles/kernel/device/metal/context_begin.h4
-rw-r--r--intern/cycles/kernel/device/metal/kernel.metal562
-rw-r--r--intern/cycles/kernel/device/optix/compat.h1
-rw-r--r--intern/cycles/kernel/device/optix/kernel.cu74
-rw-r--r--intern/cycles/kernel/film/accumulate.h2
-rw-r--r--intern/cycles/kernel/film/passes.h2
-rw-r--r--intern/cycles/kernel/film/read.h2
-rw-r--r--intern/cycles/kernel/geom/geom.h3
-rw-r--r--intern/cycles/kernel/geom/motion_point.h74
-rw-r--r--intern/cycles/kernel/geom/motion_triangle_intersect.h32
-rw-r--r--intern/cycles/kernel/geom/point.h124
-rw-r--r--intern/cycles/kernel/geom/point_intersect.h133
-rw-r--r--intern/cycles/kernel/geom/primitive.h49
-rw-r--r--intern/cycles/kernel/geom/shader_data.h7
-rw-r--r--intern/cycles/kernel/geom/triangle_intersect.h45
-rw-r--r--intern/cycles/kernel/integrator/intersect_closest.h3
-rw-r--r--intern/cycles/kernel/integrator/path_state.h7
-rw-r--r--intern/cycles/kernel/integrator/shade_volume.h6
-rw-r--r--intern/cycles/kernel/integrator/subsurface_disk.h4
-rw-r--r--intern/cycles/kernel/integrator/subsurface_random_walk.h6
-rw-r--r--intern/cycles/kernel/light/common.h2
-rw-r--r--intern/cycles/kernel/light/light.h132
-rw-r--r--intern/cycles/kernel/light/sample.h3
-rw-r--r--intern/cycles/kernel/osl/services.cpp12
-rw-r--r--intern/cycles/kernel/osl/services.h2
-rw-r--r--intern/cycles/kernel/osl/shaders/CMakeLists.txt1
-rw-r--r--intern/cycles/kernel/osl/shaders/node_magic_texture.osl15
-rw-r--r--intern/cycles/kernel/osl/shaders/node_vector_map_range.osl74
-rw-r--r--intern/cycles/kernel/svm/aov.h3
-rw-r--r--intern/cycles/kernel/svm/magic.h26
-rw-r--r--intern/cycles/kernel/svm/map_range.h74
-rw-r--r--intern/cycles/kernel/svm/svm.h3
-rw-r--r--intern/cycles/kernel/svm/types.h1
-rw-r--r--intern/cycles/kernel/svm/wireframe.h2
-rw-r--r--intern/cycles/kernel/tables.h2
-rw-r--r--intern/cycles/kernel/textures.h5
-rw-r--r--intern/cycles/kernel/types.h37
-rw-r--r--intern/cycles/scene/CMakeLists.txt2
-rw-r--r--intern/cycles/scene/alembic.cpp87
-rw-r--r--intern/cycles/scene/alembic.h10
-rw-r--r--intern/cycles/scene/alembic_read.cpp49
-rw-r--r--intern/cycles/scene/alembic_read.h20
-rw-r--r--intern/cycles/scene/attribute.cpp33
-rw-r--r--intern/cycles/scene/camera.cpp10
-rw-r--r--intern/cycles/scene/camera.h6
-rw-r--r--intern/cycles/scene/geometry.cpp97
-rw-r--r--intern/cycles/scene/geometry.h12
-rw-r--r--intern/cycles/scene/integrator.cpp2
-rw-r--r--intern/cycles/scene/object.cpp36
-rw-r--r--intern/cycles/scene/object.h1
-rw-r--r--intern/cycles/scene/pointcloud.cpp304
-rw-r--r--intern/cycles/scene/pointcloud.h114
-rw-r--r--intern/cycles/scene/scene.cpp29
-rw-r--r--intern/cycles/scene/scene.h10
-rw-r--r--intern/cycles/scene/shader_nodes.cpp73
-rw-r--r--intern/cycles/scene/shader_nodes.h15
-rw-r--r--intern/cycles/session/merge.cpp181
-rw-r--r--intern/cycles/test/integrator_tile_test.cpp17
-rw-r--r--intern/cycles/util/math.h14
-rw-r--r--intern/cycles/util/math_fast.h2
-rw-r--r--intern/cycles/util/math_float3.h4
-rw-r--r--intern/cycles/util/math_intersect.h77
-rw-r--r--intern/cycles/util/math_matrix.h2
-rw-r--r--intern/cycles/util/path.cpp161
-rw-r--r--intern/cycles/util/path.h3
-rw-r--r--intern/cycles/util/transform.h10
-rw-r--r--intern/dualcon/intern/MemoryAllocator.h2
-rw-r--r--intern/eigen/eigen_capi.h4
-rw-r--r--intern/eigen/intern/eigenvalues.h4
-rw-r--r--intern/eigen/intern/linear_solver.cc4
-rw-r--r--intern/eigen/intern/linear_solver.h4
-rw-r--r--intern/eigen/intern/matrix.cc4
-rw-r--r--intern/eigen/intern/matrix.h4
-rw-r--r--intern/eigen/intern/svd.cc4
-rw-r--r--intern/eigen/intern/svd.h4
-rw-r--r--intern/ghost/CMakeLists.txt4
-rw-r--r--intern/ghost/intern/GHOST_SystemPathsCocoa.mm169
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.cpp5
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.cpp5
-rw-r--r--intern/ghost/intern/GHOST_Window.h5
-rw-r--r--intern/ghost/intern/GHOST_WindowViewCocoa.h8
-rw-r--r--intern/ghost/intern/GHOST_Wintab.h2
-rw-r--r--intern/ghost/intern/GHOST_XrControllerModel.cpp22
-rw-r--r--intern/ghost/intern/GHOST_XrControllerModel.h2
-rw-r--r--intern/ghost/intern/GHOST_XrSession.cpp1
-rw-r--r--intern/ghost/intern/GHOST_XrSession.h2
-rw-r--r--intern/glew-mx/glew-mx.h2
-rw-r--r--intern/glew-mx/intern/gl-deprecated.h2
-rw-r--r--intern/glew-mx/intern/glew-mx.c2
-rw-r--r--intern/glew-mx/intern/symbol-binding.h2
-rw-r--r--intern/guardedalloc/MEM_guardedalloc.h2
-rw-r--r--intern/guardedalloc/cpp/mallocn.cpp2
-rw-r--r--intern/guardedalloc/intern/leak_detector.cc6
-rw-r--r--intern/guardedalloc/intern/mallocn.c2
-rw-r--r--intern/guardedalloc/intern/mallocn_guarded_impl.c2
-rw-r--r--intern/guardedalloc/intern/mallocn_inline.h2
-rw-r--r--intern/guardedalloc/intern/mallocn_intern.h2
-rw-r--r--intern/guardedalloc/intern/mallocn_lockfree_impl.c2
-rw-r--r--intern/iksolver/extern/IK_solver.h2
-rw-r--r--intern/iksolver/intern/IK_Math.h4
-rw-r--r--intern/iksolver/intern/IK_QJacobian.cpp2
-rw-r--r--intern/iksolver/intern/IK_QJacobian.h2
-rw-r--r--intern/iksolver/intern/IK_QJacobianSolver.cpp2
-rw-r--r--intern/iksolver/intern/IK_QJacobianSolver.h2
-rw-r--r--intern/iksolver/intern/IK_QSegment.cpp2
-rw-r--r--intern/iksolver/intern/IK_QSegment.h2
-rw-r--r--intern/iksolver/intern/IK_QTask.cpp2
-rw-r--r--intern/iksolver/intern/IK_QTask.h2
-rw-r--r--intern/iksolver/intern/IK_Solver.cpp2
-rw-r--r--intern/itasc/Armature.cpp2
-rw-r--r--intern/itasc/Cache.cpp2
-rw-r--r--intern/itasc/ConstraintSet.cpp2
-rw-r--r--intern/itasc/ControlledObject.cpp2
-rw-r--r--intern/itasc/CopyPose.cpp2
-rw-r--r--intern/itasc/Distance.cpp2
-rw-r--r--intern/itasc/FixedObject.cpp2
-rw-r--r--intern/itasc/MovingFrame.cpp2
-rw-r--r--intern/itasc/Scene.cpp2
-rw-r--r--intern/itasc/UncontrolledObject.cpp2
-rw-r--r--intern/itasc/WDLSSolver.cpp2
-rw-r--r--intern/itasc/WSDLSSolver.cpp2
-rw-r--r--intern/itasc/WorldObject.cpp2
-rw-r--r--intern/itasc/eigen_types.cpp2
-rw-r--r--intern/itasc/kdl/chain.cpp2
-rw-r--r--intern/itasc/kdl/chainfksolverpos_recursive.cpp2
-rw-r--r--intern/itasc/kdl/chainjnttojacsolver.cpp2
-rw-r--r--intern/itasc/kdl/frameacc.cpp2
-rw-r--r--intern/itasc/kdl/frames.cpp2
-rw-r--r--intern/itasc/kdl/frames_io.cpp2
-rw-r--r--intern/itasc/kdl/framevel.cpp2
-rw-r--r--intern/itasc/kdl/inertia.cpp2
-rw-r--r--intern/itasc/kdl/jacobian.cpp2
-rw-r--r--intern/itasc/kdl/jntarray.cpp2
-rw-r--r--intern/itasc/kdl/jntarrayacc.cpp2
-rw-r--r--intern/itasc/kdl/jntarrayvel.cpp2
-rw-r--r--intern/itasc/kdl/joint.cpp2
-rw-r--r--intern/itasc/kdl/kinfam_io.cpp2
-rw-r--r--intern/itasc/kdl/segment.cpp2
-rw-r--r--intern/itasc/kdl/tree.cpp2
-rw-r--r--intern/itasc/kdl/treefksolverpos_recursive.cpp2
-rw-r--r--intern/itasc/kdl/treejnttojacsolver.cpp2
-rw-r--r--intern/itasc/kdl/utilities/error_stack.cpp2
-rw-r--r--intern/itasc/kdl/utilities/kdl-config.h2
-rw-r--r--intern/itasc/kdl/utilities/traits.h2
-rw-r--r--intern/itasc/kdl/utilities/utility.cpp2
-rw-r--r--intern/itasc/kdl/utilities/utility_io.cpp2
-rw-r--r--intern/libc_compat/libc_compat.c4
-rw-r--r--intern/libmv/libmv/multiview/fundamental.cc2
-rw-r--r--intern/libmv/libmv/multiview/homography.cc2
-rw-r--r--intern/locale/boost_locale_wrapper.cpp4
-rw-r--r--intern/locale/boost_locale_wrapper.h4
-rw-r--r--intern/locale/osx_user_locale.mm4
-rw-r--r--intern/mantaflow/extern/manta_fluid_API.h2
-rw-r--r--intern/mantaflow/extern/manta_python_API.h2
-rw-r--r--intern/mantaflow/intern/MANTA_main.cpp2
-rw-r--r--intern/mantaflow/intern/MANTA_main.h2
-rw-r--r--intern/mantaflow/intern/manta_fluid_API.cpp2
-rw-r--r--intern/mantaflow/intern/manta_python_API.cpp2
-rw-r--r--intern/mantaflow/intern/strings/fluid_script.h2
-rw-r--r--intern/mantaflow/intern/strings/liquid_script.h2
-rw-r--r--intern/mantaflow/intern/strings/smoke_script.h2
-rw-r--r--intern/memutil/MEM_Allocator.h2
-rw-r--r--intern/memutil/MEM_CacheLimiter.h2
-rw-r--r--intern/memutil/MEM_CacheLimiterC-Api.h2
-rw-r--r--intern/memutil/MEM_RefCounted.h2
-rw-r--r--intern/memutil/MEM_RefCountedC-Api.h2
-rw-r--r--intern/memutil/intern/MEM_CacheLimiterC-Api.cpp2
-rw-r--r--intern/memutil/intern/MEM_RefCountedC-Api.cpp2
-rw-r--r--intern/numaapi/include/numaapi.h4
-rw-r--r--intern/numaapi/source/build_config.h4
-rw-r--r--intern/numaapi/source/numaapi.c4
-rw-r--r--intern/numaapi/source/numaapi_linux.c4
-rw-r--r--intern/numaapi/source/numaapi_stub.c4
-rw-r--r--intern/numaapi/source/numaapi_win32.c4
-rw-r--r--intern/opencolorio/fallback_impl.cc8
-rw-r--r--intern/opencolorio/ocio_capi.cc18
-rw-r--r--intern/opencolorio/ocio_impl.cc4
-rw-r--r--intern/opensubdiv/internal/base/opensubdiv_capi.cc8
-rw-r--r--intern/opensubdiv/internal/evaluator/evaluator_impl.h2
-rw-r--r--intern/opensubdiv/stub/opensubdiv_stub.cc8
-rw-r--r--intern/rigidbody/RBI_api.h2
-rw-r--r--intern/rigidbody/RBI_hull_api.h4
-rw-r--r--intern/rigidbody/rb_bullet_api.cpp2
-rw-r--r--intern/rigidbody/rb_convex_hull_api.cpp4
-rw-r--r--intern/sky/include/sky_model.h4
-rw-r--r--intern/sky/source/sky_float3.h4
-rw-r--r--intern/sky/source/sky_model.cpp4
-rw-r--r--intern/sky/source/sky_model_data.h4
-rw-r--r--intern/sky/source/sky_nishita.cpp61
-rw-r--r--intern/utfconv/utf_winfunc.c4
-rw-r--r--intern/utfconv/utf_winfunc.h5
-rw-r--r--intern/utfconv/utfconv.c5
-rw-r--r--intern/utfconv/utfconv.h5
-rw-r--r--release/datafiles/blender_icons.svg155
-rw-r--r--release/datafiles/blender_icons16/icon16_current_file.datbin0 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_file_backup.datbin1048 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_file_blend.datbin1048 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_current_file.datbin0 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_file_backup.datbin4120 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_file_blend.datbin4120 -> 4120 bytes
m---------release/datafiles/locale0
-rw-r--r--release/datafiles/preview.blendbin1471916 -> 1412458 bytes
-rw-r--r--release/datafiles/splash.pngbin795994 -> 842492 bytes
-rw-r--r--release/freedesktop/org.blender.Blender.appdata.xml25
-rw-r--r--release/license/THIRD-PARTY-LICENSES.txt123
m---------release/scripts/addons0
-rw-r--r--release/scripts/freestyle/modules/parameter_editor.py2
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/blender_default.py4
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py4
-rw-r--r--release/scripts/startup/bl_operators/assets.py10
-rw-r--r--release/scripts/startup/bl_operators/wm.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_data_camera.py8
-rw-r--r--release/scripts/startup/bl_ui/space_dopesheet.py34
-rw-r--r--release/scripts/startup/bl_ui/space_filebrowser.py12
-rw-r--r--release/scripts/startup/bl_ui/space_nla.py17
-rw-r--r--release/scripts/startup/bl_ui/space_node.py5
-rw-r--r--release/scripts/startup/bl_ui/space_sequencer.py20
-rw-r--r--release/scripts/startup/bl_ui/space_toolsystem_toolbar.py7
-rw-r--r--release/scripts/startup/bl_ui/space_topbar.py2
-rw-r--r--release/scripts/startup/bl_ui/space_userpref.py30
-rw-r--r--release/scripts/startup/bl_ui/space_view3d_toolbar.py4
-rw-r--r--release/scripts/startup/nodeitems_builtins.py14
-rw-r--r--release/windows/msix/AppxManifest.xml.template2
-rw-r--r--source/blender/blendthumb/src/blendthumb.hh4
-rw-r--r--source/blender/blendthumb/src/blendthumb_extract.cc4
-rw-r--r--source/blender/blenfont/BLF_api.h135
-rw-r--r--source/blender/blenfont/intern/blf.c11
-rw-r--r--source/blender/blenfont/intern/blf_dir.c4
-rw-r--r--source/blender/blenfont/intern/blf_font.c5
-rw-r--r--source/blender/blenfont/intern/blf_glyph.c9
-rw-r--r--source/blender/blenfont/intern/blf_internal.h16
-rw-r--r--source/blender/blenfont/intern/blf_thumbs.c5
-rw-r--r--source/blender/blenkernel/BKE_DerivedMesh.h78
-rw-r--r--source/blender/blenkernel/BKE_action.h187
-rw-r--r--source/blender/blenkernel/BKE_anim_data.h63
-rw-r--r--source/blender/blenkernel/BKE_anim_path.h11
-rw-r--r--source/blender/blenkernel/BKE_anim_visualization.h21
-rw-r--r--source/blender/blenkernel/BKE_animsys.h60
-rw-r--r--source/blender/blenkernel/BKE_appdir.h100
-rw-r--r--source/blender/blenkernel/BKE_armature.h193
-rw-r--r--source/blender/blenkernel/BKE_asset.h3
-rw-r--r--source/blender/blenkernel/BKE_asset_catalog.hh17
-rw-r--r--source/blender/blenkernel/BKE_attribute_access.hh27
-rw-r--r--source/blender/blenkernel/BKE_autoexec.h4
-rw-r--r--source/blender/blenkernel/BKE_blender.h11
-rw-r--r--source/blender/blenkernel/BKE_blender_copybuffer.h40
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h2
-rw-r--r--source/blender/blenkernel/BKE_blendfile.h43
-rw-r--r--source/blender/blenkernel/BKE_blendfile_link_append.h222
-rw-r--r--source/blender/blenkernel/BKE_boids.h6
-rw-r--r--source/blender/blenkernel/BKE_bpath.h211
-rw-r--r--source/blender/blenkernel/BKE_brush.h73
-rw-r--r--source/blender/blenkernel/BKE_bvhutils.h67
-rw-r--r--source/blender/blenkernel/BKE_cachefile.h6
-rw-r--r--source/blender/blenkernel/BKE_callbacks.h3
-rw-r--r--source/blender/blenkernel/BKE_camera.h29
-rw-r--r--source/blender/blenkernel/BKE_cloth.h2
-rw-r--r--source/blender/blenkernel/BKE_collection.h112
-rw-r--r--source/blender/blenkernel/BKE_collision.h20
-rw-r--r--source/blender/blenkernel/BKE_colortools.h75
-rw-r--r--source/blender/blenkernel/BKE_constraint.h109
-rw-r--r--source/blender/blenkernel/BKE_context.h33
-rw-r--r--source/blender/blenkernel/BKE_crazyspace.h8
-rw-r--r--source/blender/blenkernel/BKE_cryptomatte.h3
-rw-r--r--source/blender/blenkernel/BKE_cryptomatte.hh20
-rw-r--r--source/blender/blenkernel/BKE_curve.h108
-rw-r--r--source/blender/blenkernel/BKE_curve_to_mesh.hh14
-rw-r--r--source/blender/blenkernel/BKE_curveprofile.h83
-rw-r--r--source/blender/blenkernel/BKE_customdata.h313
-rw-r--r--source/blender/blenkernel/BKE_data_transfer.h10
-rw-r--r--source/blender/blenkernel/BKE_deform.h105
-rw-r--r--source/blender/blenkernel/BKE_displist.h6
-rw-r--r--source/blender/blenkernel/BKE_duplilist.h3
-rw-r--r--source/blender/blenkernel/BKE_dynamicpaint.h40
-rw-r--r--source/blender/blenkernel/BKE_editmesh.h20
-rw-r--r--source/blender/blenkernel/BKE_editmesh_bvh.h10
-rw-r--r--source/blender/blenkernel/BKE_editmesh_tangent.h7
-rw-r--r--source/blender/blenkernel/BKE_effect.h29
-rw-r--r--source/blender/blenkernel/BKE_fcurve.h247
-rw-r--r--source/blender/blenkernel/BKE_fcurve_driver.h51
-rw-r--r--source/blender/blenkernel/BKE_fluid.h4
-rw-r--r--source/blender/blenkernel/BKE_freestyle.h4
-rw-r--r--source/blender/blenkernel/BKE_geometry_set.h2
-rw-r--r--source/blender/blenkernel/BKE_geometry_set.hh323
-rw-r--r--source/blender/blenkernel/BKE_geometry_set_instances.hh15
-rw-r--r--source/blender/blenkernel/BKE_global.h88
-rw-r--r--source/blender/blenkernel/BKE_gpencil.h408
-rw-r--r--source/blender/blenkernel/BKE_gpencil_curve.h29
-rw-r--r--source/blender/blenkernel/BKE_gpencil_geom.h276
-rw-r--r--source/blender/blenkernel/BKE_gpencil_modifier.h126
-rw-r--r--source/blender/blenkernel/BKE_icons.h104
-rw-r--r--source/blender/blenkernel/BKE_idprop.h139
-rw-r--r--source/blender/blenkernel/BKE_idtype.h94
-rw-r--r--source/blender/blenkernel/BKE_image.h217
-rw-r--r--source/blender/blenkernel/BKE_ipo.h13
-rw-r--r--source/blender/blenkernel/BKE_key.h83
-rw-r--r--source/blender/blenkernel/BKE_keyconfig.h12
-rw-r--r--source/blender/blenkernel/BKE_lattice.h1
-rw-r--r--source/blender/blenkernel/BKE_layer.h128
-rw-r--r--source/blender/blenkernel/BKE_lib_id.h289
-rw-r--r--source/blender/blenkernel/BKE_lib_override.h227
-rw-r--r--source/blender/blenkernel/BKE_lib_query.h75
-rw-r--r--source/blender/blenkernel/BKE_lib_remap.h31
-rw-r--r--source/blender/blenkernel/BKE_linestyle.h4
-rw-r--r--source/blender/blenkernel/BKE_main.h114
-rw-r--r--source/blender/blenkernel/BKE_main_idmap.h11
-rw-r--r--source/blender/blenkernel/BKE_mask.h128
-rw-r--r--source/blender/blenkernel/BKE_material.h88
-rw-r--r--source/blender/blenkernel/BKE_mball.h42
-rw-r--r--source/blender/blenkernel/BKE_mesh.h347
-rw-r--r--source/blender/blenkernel/BKE_mesh_boolean_convert.hh10
-rw-r--r--source/blender/blenkernel/BKE_mesh_iterators.h5
-rw-r--r--source/blender/blenkernel/BKE_mesh_mapping.h79
-rw-r--r--source/blender/blenkernel/BKE_mesh_mirror.h14
-rw-r--r--source/blender/blenkernel/BKE_mesh_remap.h13
-rw-r--r--source/blender/blenkernel/BKE_mesh_runtime.h26
-rw-r--r--source/blender/blenkernel/BKE_mesh_tangent.h21
-rw-r--r--source/blender/blenkernel/BKE_modifier.h72
-rw-r--r--source/blender/blenkernel/BKE_movieclip.h30
-rw-r--r--source/blender/blenkernel/BKE_multires.h72
-rw-r--r--source/blender/blenkernel/BKE_nla.h198
-rw-r--r--source/blender/blenkernel/BKE_node.h319
-rw-r--r--source/blender/blenkernel/BKE_object.h276
-rw-r--r--source/blender/blenkernel/BKE_object_deform.h88
-rw-r--r--source/blender/blenkernel/BKE_ocean.h42
-rw-r--r--source/blender/blenkernel/BKE_packedFile.h44
-rw-r--r--source/blender/blenkernel/BKE_paint.h103
-rw-r--r--source/blender/blenkernel/BKE_particle.h121
-rw-r--r--source/blender/blenkernel/BKE_pbvh.h75
-rw-r--r--source/blender/blenkernel/BKE_pointcache.h81
-rw-r--r--source/blender/blenkernel/BKE_pointcloud.h2
-rw-r--r--source/blender/blenkernel/BKE_preferences.h10
-rw-r--r--source/blender/blenkernel/BKE_report.h7
-rw-r--r--source/blender/blenkernel/BKE_rigidbody.h129
-rw-r--r--source/blender/blenkernel/BKE_scene.h122
-rw-r--r--source/blender/blenkernel/BKE_screen.h80
-rw-r--r--source/blender/blenkernel/BKE_shader_fx.h22
-rw-r--r--source/blender/blenkernel/BKE_shrinkwrap.h86
-rw-r--r--source/blender/blenkernel/BKE_softbody.h39
-rw-r--r--source/blender/blenkernel/BKE_spline.hh168
-rw-r--r--source/blender/blenkernel/BKE_studiolight.h8
-rw-r--r--source/blender/blenkernel/BKE_subsurf.h18
-rw-r--r--source/blender/blenkernel/BKE_text.h48
-rw-r--r--source/blender/blenkernel/BKE_texture.h12
-rw-r--r--source/blender/blenkernel/BKE_tracking.h267
-rw-r--r--source/blender/blenkernel/BKE_type_conversions.hh (renamed from source/blender/nodes/NOD_type_conversions.hh)6
-rw-r--r--source/blender/blenkernel/BKE_undo_system.h103
-rw-r--r--source/blender/blenkernel/BKE_unit.h54
-rw-r--r--source/blender/blenkernel/BKE_vfont.h3
-rw-r--r--source/blender/blenkernel/BKE_vfontdata.h6
-rw-r--r--source/blender/blenkernel/BKE_volume.h5
-rw-r--r--source/blender/blenkernel/BKE_volume_to_mesh.hh2
-rw-r--r--source/blender/blenkernel/BKE_workspace.h59
-rw-r--r--source/blender/blenkernel/BKE_writeavi.h4
-rw-r--r--source/blender/blenkernel/CMakeLists.txt10
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf.c4
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf.h17
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_legacy.c4
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.cc67
-rw-r--r--source/blender/blenkernel/intern/action.c128
-rw-r--r--source/blender/blenkernel/intern/anim_data.c83
-rw-r--r--source/blender/blenkernel/intern/anim_path.c12
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c71
-rw-r--r--source/blender/blenkernel/intern/anim_visualization.c14
-rw-r--r--source/blender/blenkernel/intern/appdir.c107
-rw-r--r--source/blender/blenkernel/intern/armature.c192
-rw-r--r--source/blender/blenkernel/intern/armature_deform.c1
-rw-r--r--source/blender/blenkernel/intern/armature_update.c90
-rw-r--r--source/blender/blenkernel/intern/asset.cc5
-rw-r--r--source/blender/blenkernel/intern/asset_catalog.cc31
-rw-r--r--source/blender/blenkernel/intern/asset_catalog_path.cc2
-rw-r--r--source/blender/blenkernel/intern/asset_library.cc4
-rw-r--r--source/blender/blenkernel/intern/asset_library_service.cc3
-rw-r--r--source/blender/blenkernel/intern/asset_library_service_test.cc4
-rw-r--r--source/blender/blenkernel/intern/attribute_access.cc135
-rw-r--r--source/blender/blenkernel/intern/autoexec.c4
-rw-r--r--source/blender/blenkernel/intern/blender.c9
-rw-r--r--source/blender/blenkernel/intern/blender_copybuffer.c153
-rw-r--r--source/blender/blenkernel/intern/blender_undo.c4
-rw-r--r--source/blender/blenkernel/intern/blender_user_menu.c2
-rw-r--r--source/blender/blenkernel/intern/blendfile.c70
-rw-r--r--source/blender/blenkernel/intern/blendfile_link_append.c1615
-rw-r--r--source/blender/blenkernel/intern/boids.c2
-rw-r--r--source/blender/blenkernel/intern/bpath.c914
-rw-r--r--source/blender/blenkernel/intern/bpath_test.cc181
-rw-r--r--source/blender/blenkernel/intern/brush.c36
-rw-r--r--source/blender/blenkernel/intern/bvhutils.cc63
-rw-r--r--source/blender/blenkernel/intern/cachefile.c15
-rw-r--r--source/blender/blenkernel/intern/callbacks.c1
-rw-r--r--source/blender/blenkernel/intern/camera.c8
-rw-r--r--source/blender/blenkernel/intern/cloth.c3
-rw-r--r--source/blender/blenkernel/intern/collection.c112
-rw-r--r--source/blender/blenkernel/intern/collision.c8
-rw-r--r--source/blender/blenkernel/intern/colortools.c30
-rw-r--r--source/blender/blenkernel/intern/constraint.c55
-rw-r--r--source/blender/blenkernel/intern/context.c13
-rw-r--r--source/blender/blenkernel/intern/crazyspace.c5
-rw-r--r--source/blender/blenkernel/intern/cryptomatte.cc18
-rw-r--r--source/blender/blenkernel/intern/curve.cc (renamed from source/blender/blenkernel/intern/curve.c)560
-rw-r--r--source/blender/blenkernel/intern/curve_bevel.c44
-rw-r--r--source/blender/blenkernel/intern/curve_deform.c6
-rw-r--r--source/blender/blenkernel/intern/curve_eval.cc56
-rw-r--r--source/blender/blenkernel/intern/curve_to_mesh_convert.cc14
-rw-r--r--source/blender/blenkernel/intern/curveprofile.cc79
-rw-r--r--source/blender/blenkernel/intern/customdata.c105
-rw-r--r--source/blender/blenkernel/intern/data_transfer.c10
-rw-r--r--source/blender/blenkernel/intern/data_transfer_intern.h4
-rw-r--r--source/blender/blenkernel/intern/deform.c134
-rw-r--r--source/blender/blenkernel/intern/displist.cc45
-rw-r--r--source/blender/blenkernel/intern/displist_tangent.c4
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c20
-rw-r--r--source/blender/blenkernel/intern/editmesh.c16
-rw-r--r--source/blender/blenkernel/intern/editmesh_bvh.c6
-rw-r--r--source/blender/blenkernel/intern/editmesh_tangent.c7
-rw-r--r--source/blender/blenkernel/intern/effect.c62
-rw-r--r--source/blender/blenkernel/intern/fcurve.c108
-rw-r--r--source/blender/blenkernel/intern/fcurve_cache.c5
-rw-r--r--source/blender/blenkernel/intern/fcurve_driver.c26
-rw-r--r--source/blender/blenkernel/intern/fluid.c6
-rw-r--r--source/blender/blenkernel/intern/fmodifier.c56
-rw-r--r--source/blender/blenkernel/intern/freestyle.c4
-rw-r--r--source/blender/blenkernel/intern/geometry_component_curve.cc227
-rw-r--r--source/blender/blenkernel/intern/geometry_component_instances.cc175
-rw-r--r--source/blender/blenkernel/intern/geometry_component_mesh.cc62
-rw-r--r--source/blender/blenkernel/intern/geometry_component_pointcloud.cc9
-rw-r--r--source/blender/blenkernel/intern/geometry_component_volume.cc7
-rw-r--r--source/blender/blenkernel/intern/geometry_set.cc196
-rw-r--r--source/blender/blenkernel/intern/geometry_set_instances.cc389
-rw-r--r--source/blender/blenkernel/intern/gpencil.c403
-rw-r--r--source/blender/blenkernel/intern/gpencil_curve.c29
-rw-r--r--source/blender/blenkernel/intern/gpencil_geom.cc370
-rw-r--r--source/blender/blenkernel/intern/gpencil_modifier.c221
-rw-r--r--source/blender/blenkernel/intern/hair.c5
-rw-r--r--source/blender/blenkernel/intern/icons.cc98
-rw-r--r--source/blender/blenkernel/intern/idprop.c124
-rw-r--r--source/blender/blenkernel/intern/idtype.c71
-rw-r--r--source/blender/blenkernel/intern/image.c169
-rw-r--r--source/blender/blenkernel/intern/image_gpu.cc (renamed from source/blender/blenkernel/intern/image_gpu.c)128
-rw-r--r--source/blender/blenkernel/intern/ipo.c13
-rw-r--r--source/blender/blenkernel/intern/key.c72
-rw-r--r--source/blender/blenkernel/intern/keyconfig.c5
-rw-r--r--source/blender/blenkernel/intern/lattice.c2
-rw-r--r--source/blender/blenkernel/intern/layer.c174
-rw-r--r--source/blender/blenkernel/intern/layer_utils.c8
-rw-r--r--source/blender/blenkernel/intern/lib_id.c280
-rw-r--r--source/blender/blenkernel/intern/lib_id_delete.c49
-rw-r--r--source/blender/blenkernel/intern/lib_id_eval.c5
-rw-r--r--source/blender/blenkernel/intern/lib_override.c304
-rw-r--r--source/blender/blenkernel/intern/lib_query.c70
-rw-r--r--source/blender/blenkernel/intern/lib_remap.c34
-rw-r--r--source/blender/blenkernel/intern/library.c23
-rw-r--r--source/blender/blenkernel/intern/light.c2
-rw-r--r--source/blender/blenkernel/intern/lightprobe.c2
-rw-r--r--source/blender/blenkernel/intern/linestyle.c6
-rw-r--r--source/blender/blenkernel/intern/main.c106
-rw-r--r--source/blender/blenkernel/intern/main_idmap.c12
-rw-r--r--source/blender/blenkernel/intern/mask.c32
-rw-r--r--source/blender/blenkernel/intern/mask_evaluate.c5
-rw-r--r--source/blender/blenkernel/intern/mask_rasterize.c3
-rw-r--r--source/blender/blenkernel/intern/material.c25
-rw-r--r--source/blender/blenkernel/intern/mball.c72
-rw-r--r--source/blender/blenkernel/intern/mball_tessellate.c18
-rw-r--r--source/blender/blenkernel/intern/mesh.cc143
-rw-r--r--source/blender/blenkernel/intern/mesh_boolean_convert.cc10
-rw-r--r--source/blender/blenkernel/intern/mesh_convert.cc5
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.cc81
-rw-r--r--source/blender/blenkernel/intern/mesh_iterators.c9
-rw-r--r--source/blender/blenkernel/intern/mesh_mapping.c88
-rw-r--r--source/blender/blenkernel/intern/mesh_merge.c32
-rw-r--r--source/blender/blenkernel/intern/mesh_mirror.c50
-rw-r--r--source/blender/blenkernel/intern/mesh_normals.cc62
-rw-r--r--source/blender/blenkernel/intern/mesh_remap.c21
-rw-r--r--source/blender/blenkernel/intern/mesh_runtime.c34
-rw-r--r--source/blender/blenkernel/intern/mesh_tangent.c21
-rw-r--r--source/blender/blenkernel/intern/mesh_tessellate.c22
-rw-r--r--source/blender/blenkernel/intern/mesh_validate.c55
-rw-r--r--source/blender/blenkernel/intern/mesh_validate.cc3
-rw-r--r--source/blender/blenkernel/intern/modifier.c83
-rw-r--r--source/blender/blenkernel/intern/movieclip.c25
-rw-r--r--source/blender/blenkernel/intern/multires.c15
-rw-r--r--source/blender/blenkernel/intern/multires_reshape.c4
-rw-r--r--source/blender/blenkernel/intern/multires_reshape.h123
-rw-r--r--source/blender/blenkernel/intern/multires_reshape_util.c7
-rw-r--r--source/blender/blenkernel/intern/multires_reshape_vertcos.c1
-rw-r--r--source/blender/blenkernel/intern/nla.c212
-rw-r--r--source/blender/blenkernel/intern/node.cc261
-rw-r--r--source/blender/blenkernel/intern/object.cc451
-rw-r--r--source/blender/blenkernel/intern/object_deform.c84
-rw-r--r--source/blender/blenkernel/intern/object_dupli.cc55
-rw-r--r--source/blender/blenkernel/intern/object_update.c19
-rw-r--r--source/blender/blenkernel/intern/ocean.c12
-rw-r--r--source/blender/blenkernel/intern/ocean_spectrum.c17
-rw-r--r--source/blender/blenkernel/intern/packedFile.c21
-rw-r--r--source/blender/blenkernel/intern/paint.c39
-rw-r--r--source/blender/blenkernel/intern/paint_toolslots.c4
-rw-r--r--source/blender/blenkernel/intern/particle.c59
-rw-r--r--source/blender/blenkernel/intern/particle_distribute.c7
-rw-r--r--source/blender/blenkernel/intern/particle_system.c22
-rw-r--r--source/blender/blenkernel/intern/pbvh.c16
-rw-r--r--source/blender/blenkernel/intern/pbvh_bmesh.c6
-rw-r--r--source/blender/blenkernel/intern/pbvh_intern.h9
-rw-r--r--source/blender/blenkernel/intern/pointcache.c93
-rw-r--r--source/blender/blenkernel/intern/pointcloud.cc5
-rw-r--r--source/blender/blenkernel/intern/preferences.c10
-rw-r--r--source/blender/blenkernel/intern/report.c5
-rw-r--r--source/blender/blenkernel/intern/rigidbody.c25
-rw-r--r--source/blender/blenkernel/intern/scene.c113
-rw-r--r--source/blender/blenkernel/intern/screen.c75
-rw-r--r--source/blender/blenkernel/intern/shader_fx.c14
-rw-r--r--source/blender/blenkernel/intern/shrinkwrap.c80
-rw-r--r--source/blender/blenkernel/intern/simulation.cc2
-rw-r--r--source/blender/blenkernel/intern/softbody.c19
-rw-r--r--source/blender/blenkernel/intern/sound.c26
-rw-r--r--source/blender/blenkernel/intern/speaker.c2
-rw-r--r--source/blender/blenkernel/intern/spline_base.cc35
-rw-r--r--source/blender/blenkernel/intern/spline_bezier.cc63
-rw-r--r--source/blender/blenkernel/intern/spline_nurbs.cc3
-rw-r--r--source/blender/blenkernel/intern/spline_poly.cc9
-rw-r--r--source/blender/blenkernel/intern/studiolight.c6
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c5
-rw-r--r--source/blender/blenkernel/intern/text.c52
-rw-r--r--source/blender/blenkernel/intern/texture.c9
-rw-r--r--source/blender/blenkernel/intern/tracking.c121
-rw-r--r--source/blender/blenkernel/intern/tracking_auto.c2
-rw-r--r--source/blender/blenkernel/intern/tracking_detect.c2
-rw-r--r--source/blender/blenkernel/intern/tracking_plane_tracker.c1
-rw-r--r--source/blender/blenkernel/intern/tracking_region_tracker.c6
-rw-r--r--source/blender/blenkernel/intern/tracking_solver.c22
-rw-r--r--source/blender/blenkernel/intern/tracking_stabilize.c36
-rw-r--r--source/blender/blenkernel/intern/tracking_util.c17
-rw-r--r--source/blender/blenkernel/intern/type_conversions.cc (renamed from source/blender/nodes/intern/type_conversions.cc)31
-rw-r--r--source/blender/blenkernel/intern/undo_system.c146
-rw-r--r--source/blender/blenkernel/intern/unit.c17
-rw-r--r--source/blender/blenkernel/intern/vfont.c23
-rw-r--r--source/blender/blenkernel/intern/vfontdata_freetype.c8
-rw-r--r--source/blender/blenkernel/intern/volume.cc17
-rw-r--r--source/blender/blenkernel/intern/workspace.c46
-rw-r--r--source/blender/blenkernel/intern/world.c2
-rw-r--r--source/blender/blenkernel/intern/writeavi.c1
-rw-r--r--source/blender/blenkernel/intern/writeffmpeg.c26
-rw-r--r--source/blender/blenkernel/nla_private.h33
-rw-r--r--source/blender/blenkernel/tracking_private.h38
-rw-r--r--source/blender/blenlib/BLI_array.h49
-rw-r--r--source/blender/blenlib/BLI_array_store.h67
-rw-r--r--source/blender/blenlib/BLI_array_utils.h60
-rw-r--r--source/blender/blenlib/BLI_astar.h50
-rw-r--r--source/blender/blenlib/BLI_bitmap.h59
-rw-r--r--source/blender/blenlib/BLI_bitmap_draw_2d.h20
-rw-r--r--source/blender/blenlib/BLI_boxpack_2d.h29
-rw-r--r--source/blender/blenlib/BLI_buffer.h28
-rw-r--r--source/blender/blenlib/BLI_convexhull_2d.h33
-rw-r--r--source/blender/blenlib/BLI_dlrbTree.h138
-rw-r--r--source/blender/blenlib/BLI_dynstr.h62
-rw-r--r--source/blender/blenlib/BLI_edgehash.h91
-rw-r--r--source/blender/blenlib/BLI_expr_pylike_eval.h22
-rw-r--r--source/blender/blenlib/BLI_fileops.h167
-rw-r--r--source/blender/blenlib/BLI_ghash.h243
-rw-r--r--source/blender/blenlib/BLI_gsqueue.h20
-rw-r--r--source/blender/blenlib/BLI_hash_md5.h19
-rw-r--r--source/blender/blenlib/BLI_hash_mm2a.h3
-rw-r--r--source/blender/blenlib/BLI_heap.h36
-rw-r--r--source/blender/blenlib/BLI_heap_simple.h15
-rw-r--r--source/blender/blenlib/BLI_index_mask.hh23
-rw-r--r--source/blender/blenlib/BLI_kdopbvh.h126
-rw-r--r--source/blender/blenlib/BLI_lasso_2d.h3
-rw-r--r--source/blender/blenlib/BLI_linklist.h13
-rw-r--r--source/blender/blenlib/BLI_listbase.h160
-rw-r--r--source/blender/blenlib/BLI_math_base.h76
-rw-r--r--source/blender/blenlib/BLI_math_boolean.hh27
-rw-r--r--source/blender/blenlib/BLI_math_color.h87
-rw-r--r--source/blender/blenlib/BLI_math_geom.h633
-rw-r--r--source/blender/blenlib/BLI_math_interp.h3
-rw-r--r--source/blender/blenlib/BLI_math_matrix.h228
-rw-r--r--source/blender/blenlib/BLI_math_rotation.h212
-rw-r--r--source/blender/blenlib/BLI_math_solvers.h62
-rw-r--r--source/blender/blenlib/BLI_math_statistics.h26
-rw-r--r--source/blender/blenlib/BLI_math_time.h29
-rw-r--r--source/blender/blenlib/BLI_math_vector.h269
-rw-r--r--source/blender/blenlib/BLI_memarena.h18
-rw-r--r--source/blender/blenlib/BLI_memblock.h9
-rw-r--r--source/blender/blenlib/BLI_memiter.h21
-rw-r--r--source/blender/blenlib/BLI_mempool.h44
-rw-r--r--source/blender/blenlib/BLI_mesh_intersect.hh28
-rw-r--r--source/blender/blenlib/BLI_noise.h78
-rw-r--r--source/blender/blenlib/BLI_noise.hh162
-rw-r--r--source/blender/blenlib/BLI_path_util.h284
-rw-r--r--source/blender/blenlib/BLI_polyfill_2d.h16
-rw-r--r--source/blender/blenlib/BLI_polyfill_2d_beautify.h21
-rw-r--r--source/blender/blenlib/BLI_rand.h27
-rw-r--r--source/blender/blenlib/BLI_rand.hh6
-rw-r--r--source/blender/blenlib/BLI_rect.h56
-rw-r--r--source/blender/blenlib/BLI_scanfill.h6
-rw-r--r--source/blender/blenlib/BLI_smallhash.h22
-rw-r--r--source/blender/blenlib/BLI_stack.h49
-rw-r--r--source/blender/blenlib/BLI_string.h318
-rw-r--r--source/blender/blenlib/BLI_string_search.h30
-rw-r--r--source/blender/blenlib/BLI_string_utf8.h116
-rw-r--r--source/blender/blenlib/BLI_string_utils.h78
-rw-r--r--source/blender/blenlib/BLI_task.h201
-rw-r--r--source/blender/blenlib/BLI_task.hh15
-rw-r--r--source/blender/blenlib/BLI_threads.h20
-rw-r--r--source/blender/blenlib/BLI_timecode.h34
-rw-r--r--source/blender/blenlib/BLI_utildefines.h3
-rw-r--r--source/blender/blenlib/BLI_uvproject.h24
-rw-r--r--source/blender/blenlib/BLI_virtual_array.hh241
-rw-r--r--source/blender/blenlib/BLI_voxel.h6
-rw-r--r--source/blender/blenlib/intern/BLI_array.c5
-rw-r--r--source/blender/blenlib/intern/BLI_assert.c13
-rw-r--r--source/blender/blenlib/intern/BLI_dynstr.c61
-rw-r--r--source/blender/blenlib/intern/BLI_filelist.c33
-rw-r--r--source/blender/blenlib/intern/BLI_ghash.c225
-rw-r--r--source/blender/blenlib/intern/BLI_ghash_utils.c12
-rw-r--r--source/blender/blenlib/intern/BLI_heap.c31
-rw-r--r--source/blender/blenlib/intern/BLI_heap_simple.c15
-rw-r--r--source/blender/blenlib/intern/BLI_kdopbvh.c47
-rw-r--r--source/blender/blenlib/intern/BLI_linklist.c10
-rw-r--r--source/blender/blenlib/intern/BLI_memarena.c14
-rw-r--r--source/blender/blenlib/intern/BLI_memblock.c5
-rw-r--r--source/blender/blenlib/intern/BLI_memiter.c10
-rw-r--r--source/blender/blenlib/intern/BLI_mempool.c61
-rw-r--r--source/blender/blenlib/intern/BLI_mempool_private.h18
-rw-r--r--source/blender/blenlib/intern/DLRB_tree.c15
-rw-r--r--source/blender/blenlib/intern/array_store.c60
-rw-r--r--source/blender/blenlib/intern/array_utils.c60
-rw-r--r--source/blender/blenlib/intern/astar.c50
-rw-r--r--source/blender/blenlib/intern/bitmap.c5
-rw-r--r--source/blender/blenlib/intern/bitmap_draw_2d.c20
-rw-r--r--source/blender/blenlib/intern/boxpack_2d.c29
-rw-r--r--source/blender/blenlib/intern/buffer.c7
-rw-r--r--source/blender/blenlib/intern/convexhull_2d.c33
-rw-r--r--source/blender/blenlib/intern/edgehash.c90
-rw-r--r--source/blender/blenlib/intern/expr_pylike_eval.c14
-rw-r--r--source/blender/blenlib/intern/fileops.c27
-rw-r--r--source/blender/blenlib/intern/filereader_zstd.c3
-rw-r--r--source/blender/blenlib/intern/gsqueue.c20
-rw-r--r--source/blender/blenlib/intern/hash_md5.c10
-rw-r--r--source/blender/blenlib/intern/hash_mm2a.c1
-rw-r--r--source/blender/blenlib/intern/index_mask.cc20
-rw-r--r--source/blender/blenlib/intern/lasso_2d.c1
-rw-r--r--source/blender/blenlib/intern/listbase.c157
-rw-r--r--source/blender/blenlib/intern/math_base.c22
-rw-r--r--source/blender/blenlib/intern/math_base_inline.c36
-rw-r--r--source/blender/blenlib/intern/math_boolean.cc15
-rw-r--r--source/blender/blenlib/intern/math_color.c33
-rw-r--r--source/blender/blenlib/intern/math_color_inline.c20
-rw-r--r--source/blender/blenlib/intern/math_geom.c438
-rw-r--r--source/blender/blenlib/intern/math_geom_inline.c29
-rw-r--r--source/blender/blenlib/intern/math_interp.c3
-rw-r--r--source/blender/blenlib/intern/math_matrix.c190
-rw-r--r--source/blender/blenlib/intern/math_rotation.c103
-rw-r--r--source/blender/blenlib/intern/math_solvers.c46
-rw-r--r--source/blender/blenlib/intern/math_statistics.c20
-rw-r--r--source/blender/blenlib/intern/math_time.c7
-rw-r--r--source/blender/blenlib/intern/math_vector.c112
-rw-r--r--source/blender/blenlib/intern/math_vector_inline.c51
-rw-r--r--source/blender/blenlib/intern/memory_utils.c3
-rw-r--r--source/blender/blenlib/intern/mesh_boolean.cc13
-rw-r--r--source/blender/blenlib/intern/mesh_intersect.cc156
-rw-r--r--source/blender/blenlib/intern/noise.c76
-rw-r--r--source/blender/blenlib/intern/noise.cc205
-rw-r--r--source/blender/blenlib/intern/path_util.c275
-rw-r--r--source/blender/blenlib/intern/polyfill_2d.c16
-rw-r--r--source/blender/blenlib/intern/polyfill_2d_beautify.c21
-rw-r--r--source/blender/blenlib/intern/rand.cc29
-rw-r--r--source/blender/blenlib/intern/rct.c88
-rw-r--r--source/blender/blenlib/intern/scanfill_utils.c5
-rw-r--r--source/blender/blenlib/intern/smallhash.c14
-rw-r--r--source/blender/blenlib/intern/stack.c49
-rw-r--r--source/blender/blenlib/intern/storage.c61
-rw-r--r--source/blender/blenlib/intern/storage_apple.mm19
-rw-r--r--source/blender/blenlib/intern/string.c568
-rw-r--r--source/blender/blenlib/intern/string_search.cc42
-rw-r--r--source/blender/blenlib/intern/string_utf8.c135
-rw-r--r--source/blender/blenlib/intern/string_utils.c68
-rw-r--r--source/blender/blenlib/intern/system.c3
-rw-r--r--source/blender/blenlib/intern/system_win32.c3
-rw-r--r--source/blender/blenlib/intern/task_iterator.c36
-rw-r--r--source/blender/blenlib/intern/threads.cc38
-rw-r--r--source/blender/blenlib/intern/timecode.c33
-rw-r--r--source/blender/blenlib/intern/uuid.cc2
-rw-r--r--source/blender/blenlib/intern/uvproject.c3
-rw-r--r--source/blender/blenlib/intern/voxel.c2
-rw-r--r--source/blender/blenlib/tests/BLI_color_test.cc4
-rw-r--r--source/blender/blenlib/tests/BLI_virtual_array_test.cc2
-rw-r--r--source/blender/blenloader/BLO_blend_validate.h7
-rw-r--r--source/blender/blenloader/BLO_read_write.h120
-rw-r--r--source/blender/blenloader/BLO_readfile.h198
-rw-r--r--source/blender/blenloader/BLO_undofile.h21
-rw-r--r--source/blender/blenloader/BLO_writefile.h16
-rw-r--r--source/blender/blenloader/CMakeLists.txt2
-rw-r--r--source/blender/blenloader/intern/blend_validate.c5
-rw-r--r--source/blender/blenloader/intern/readblenentry.c96
-rw-r--r--source/blender/blenloader/intern/readfile.c555
-rw-r--r--source/blender/blenloader/intern/readfile.h56
-rw-r--r--source/blender/blenloader/intern/readfile_tempload.c2
-rw-r--r--source/blender/blenloader/intern/undofile.c9
-rw-r--r--source/blender/blenloader/intern/versioning_260.c2
-rw-r--r--source/blender/blenloader/intern/versioning_300.c103
-rw-r--r--source/blender/blenloader/intern/versioning_common.cc43
-rw-r--r--source/blender/blenloader/intern/versioning_common.h36
-rw-r--r--source/blender/blenloader/intern/versioning_defaults.c9
-rw-r--r--source/blender/blenloader/intern/versioning_dna.c10
-rw-r--r--source/blender/blenloader/intern/versioning_legacy.c2
-rw-r--r--source/blender/blenloader/intern/versioning_userdef.c1
-rw-r--r--source/blender/blenloader/intern/writefile.c60
-rw-r--r--source/blender/blentranslation/BLT_lang.h9
-rw-r--r--source/blender/blentranslation/BLT_translation.h5
-rw-r--r--source/blender/blentranslation/intern/blt_lang.c13
-rw-r--r--source/blender/bmesh/intern/bmesh_construct.c97
-rw-r--r--source/blender/bmesh/intern/bmesh_construct.h92
-rw-r--r--source/blender/bmesh/intern/bmesh_core.c287
-rw-r--r--source/blender/bmesh/intern/bmesh_core.h290
-rw-r--r--source/blender/bmesh/intern/bmesh_delete.c8
-rw-r--r--source/blender/bmesh/intern/bmesh_delete.h8
-rw-r--r--source/blender/bmesh/intern/bmesh_edgeloop.c13
-rw-r--r--source/blender/bmesh/intern/bmesh_edgeloop.h17
-rw-r--r--source/blender/bmesh/intern/bmesh_error.h18
-rw-r--r--source/blender/bmesh/intern/bmesh_interp.c46
-rw-r--r--source/blender/bmesh/intern/bmesh_interp.h46
-rw-r--r--source/blender/bmesh/intern/bmesh_iterators.c45
-rw-r--r--source/blender/bmesh/intern/bmesh_iterators.h60
-rw-r--r--source/blender/bmesh/intern/bmesh_log.c119
-rw-r--r--source/blender/bmesh/intern/bmesh_log.h119
-rw-r--r--source/blender/bmesh/intern/bmesh_marking.c73
-rw-r--r--source/blender/bmesh/intern/bmesh_marking.h86
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.c81
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.h88
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_convert.c31
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_convert.h31
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_duplicate.c3
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_duplicate.h3
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_normals.c44
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_normals.h41
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_partial_update.c28
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_partial_update.h28
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_tessellate.c3
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_tessellate.h3
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_validate.c6
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_validate.h6
-rw-r--r--source/blender/bmesh/intern/bmesh_mods.c187
-rw-r--r--source/blender/bmesh/intern/bmesh_mods.h187
-rw-r--r--source/blender/bmesh/intern/bmesh_operator_api.h272
-rw-r--r--source/blender/bmesh/intern/bmesh_operators.c148
-rw-r--r--source/blender/bmesh/intern/bmesh_operators.h42
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon.c186
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon.h180
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon_edgenet.c16
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon_edgenet.h18
-rw-r--r--source/blender/bmesh/intern/bmesh_private.h12
-rw-r--r--source/blender/bmesh/intern/bmesh_query.c533
-rw-r--r--source/blender/bmesh/intern/bmesh_query.h526
-rw-r--r--source/blender/bmesh/intern/bmesh_query_uv.c23
-rw-r--r--source/blender/bmesh/intern/bmesh_query_uv.h23
-rw-r--r--source/blender/bmesh/intern/bmesh_structure.c60
-rw-r--r--source/blender/bmesh/intern/bmesh_structure.h60
-rw-r--r--source/blender/bmesh/intern/bmesh_walkers.c53
-rw-r--r--source/blender/bmesh/intern/bmesh_walkers.h52
-rw-r--r--source/blender/bmesh/intern/bmesh_walkers_impl.c17
-rw-r--r--source/blender/bmesh/operators/bmo_connect_pair.c11
-rw-r--r--source/blender/bmesh/operators/bmo_create.c7
-rw-r--r--source/blender/bmesh/operators/bmo_dissolve.c1
-rw-r--r--source/blender/bmesh/operators/bmo_primitive.c42
-rw-r--r--source/blender/bmesh/operators/bmo_split_edges.c1
-rw-r--r--source/blender/bmesh/operators/bmo_subdivide.c6
-rw-r--r--source/blender/bmesh/operators/bmo_subdivide_edgering.c3
-rw-r--r--source/blender/bmesh/operators/bmo_unsubdivide.c5
-rw-r--r--source/blender/bmesh/tools/bmesh_beautify.c9
-rw-r--r--source/blender/bmesh/tools/bmesh_beautify.h9
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.c12
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.h12
-rw-r--r--source/blender/bmesh/tools/bmesh_bisect_plane.c7
-rw-r--r--source/blender/bmesh/tools/bmesh_bisect_plane.h5
-rw-r--r--source/blender/bmesh/tools/bmesh_boolean.cc8
-rw-r--r--source/blender/bmesh/tools/bmesh_boolean.h10
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate.h16
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate_collapse.c14
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c2
-rw-r--r--source/blender/bmesh/tools/bmesh_edgenet.c9
-rw-r--r--source/blender/bmesh/tools/bmesh_edgenet.h9
-rw-r--r--source/blender/bmesh/tools/bmesh_edgesplit.c5
-rw-r--r--source/blender/bmesh/tools/bmesh_edgesplit.h5
-rw-r--r--source/blender/bmesh/tools/bmesh_intersect.c8
-rw-r--r--source/blender/bmesh/tools/bmesh_intersect.h8
-rw-r--r--source/blender/bmesh/tools/bmesh_path.c1
-rw-r--r--source/blender/bmesh/tools/bmesh_path_uv.c1
-rw-r--r--source/blender/bmesh/tools/bmesh_region_match.c7
-rw-r--r--source/blender/bmesh/tools/bmesh_region_match.h6
-rw-r--r--source/blender/bmesh/tools/bmesh_separate.c4
-rw-r--r--source/blender/bmesh/tools/bmesh_separate.h4
-rw-r--r--source/blender/bmesh/tools/bmesh_wireframe.c6
-rw-r--r--source/blender/bmesh/tools/bmesh_wireframe.h6
-rw-r--r--source/blender/compositor/COM_compositor.h11
-rw-r--r--source/blender/compositor/intern/COM_ConstantFolder.cc8
-rw-r--r--source/blender/compositor/intern/COM_ConstantFolder.h8
-rw-r--r--source/blender/compositor/intern/COM_ExecutionGroup.cc4
-rw-r--r--source/blender/compositor/intern/COM_ExecutionGroup.h4
-rw-r--r--source/blender/compositor/intern/COM_ExecutionSystem.cc3
-rw-r--r--source/blender/compositor/intern/COM_ExecutionSystem.h3
-rw-r--r--source/blender/compositor/intern/COM_FullFrameExecutionModel.cc18
-rw-r--r--source/blender/compositor/intern/COM_FullFrameExecutionModel.h22
-rw-r--r--source/blender/compositor/intern/COM_MemoryBuffer.cc12
-rw-r--r--source/blender/compositor/intern/COM_MemoryBuffer.h12
-rw-r--r--source/blender/compositor/intern/COM_MemoryProxy.cc1
-rw-r--r--source/blender/compositor/intern/COM_MetaData.cc4
-rw-r--r--source/blender/compositor/intern/COM_MetaData.h6
-rw-r--r--source/blender/compositor/intern/COM_NodeOperation.cc43
-rw-r--r--source/blender/compositor/intern/COM_NodeOperation.h42
-rw-r--r--source/blender/compositor/intern/COM_NodeOperationBuilder.cc2
-rw-r--r--source/blender/compositor/intern/COM_NodeOperationBuilder.h2
-rw-r--r--source/blender/compositor/intern/COM_SharedOperationBuffers.cc34
-rw-r--r--source/blender/compositor/intern/COM_SharedOperationBuffers.h29
-rw-r--r--source/blender/compositor/operations/COM_BlurBaseOperation.cc2
-rw-r--r--source/blender/compositor/operations/COM_BlurBaseOperation.h4
-rw-r--r--source/blender/compositor/operations/COM_ColorCurveOperation.cc4
-rw-r--r--source/blender/compositor/operations/COM_DilateErodeOperation.cc5
-rw-r--r--source/blender/compositor/operations/COM_DilateErodeOperation.h5
-rw-r--r--source/blender/compositor/operations/COM_InpaintOperation.cc1
-rw-r--r--source/blender/compositor/operations/COM_InpaintOperation.h1
-rw-r--r--source/blender/compositor/operations/COM_MathBaseOperation.cc2
-rw-r--r--source/blender/compositor/operations/COM_MixOperation.cc2
-rw-r--r--source/blender/compositor/operations/COM_PlaneTrackOperation.h4
-rw-r--r--source/blender/compositor/operations/COM_RenderLayersProg.cc3
-rw-r--r--source/blender/compositor/operations/COM_RotateOperation.cc2
-rw-r--r--source/blender/compositor/operations/COM_SMAAOperation.cc6
-rw-r--r--source/blender/compositor/operations/COM_SMAAOperation.h6
-rw-r--r--source/blender/compositor/operations/COM_ScaleOperation.cc5
-rw-r--r--source/blender/compositor/operations/COM_ScaleOperation.h1
-rw-r--r--source/blender/compositor/operations/COM_SplitOperation.cc2
-rw-r--r--source/blender/compositor/operations/COM_TextureOperation.cc2
-rw-r--r--source/blender/compositor/operations/COM_TransformOperation.cc4
-rw-r--r--source/blender/compositor/operations/COM_TransformOperation.h8
-rw-r--r--source/blender/compositor/operations/COM_TranslateOperation.cc2
-rw-r--r--source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cc4
-rw-r--r--source/blender/compositor/operations/COM_VectorBlurOperation.cc1
-rw-r--r--source/blender/depsgraph/DEG_depsgraph.h116
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_build.h43
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_debug.h14
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_query.h94
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder.cc17
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.cc70
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.h21
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc3
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h6
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc20
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.h5
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_drivers.cc1
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_drivers.h7
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc7
-rw-r--r--source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc11
-rw-r--r--source/blender/depsgraph/intern/depsgraph.cc8
-rw-r--r--source/blender/depsgraph/intern/depsgraph.h2
-rw-r--r--source/blender/depsgraph/intern/depsgraph_build.cc4
-rw-r--r--source/blender/depsgraph/intern/depsgraph_debug.cc6
-rw-r--r--source/blender/depsgraph/intern/depsgraph_eval.cc2
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query.cc1
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query_foreach.cc6
-rw-r--r--source/blender/depsgraph/intern/depsgraph_tag.cc12
-rw-r--r--source/blender/depsgraph/intern/depsgraph_type.cc6
-rw-r--r--source/blender/depsgraph/intern/depsgraph_update.cc1
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval.cc7
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc10
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h22
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_flush.cc4
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_flush.h8
-rw-r--r--source/blender/depsgraph/intern/node/deg_node.cc15
-rw-r--r--source/blender/depsgraph/intern/node/deg_node.h18
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_component.cc30
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_component.h12
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_id.cc1
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_id.h1
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_operation.cc2
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_operation.h4
-rw-r--r--source/blender/draw/CMakeLists.txt3
-rw-r--r--source/blender/draw/DRW_engine.h52
-rw-r--r--source/blender/draw/DRW_select_buffer.h28
-rw-r--r--source/blender/draw/engines/basic/basic_engine.c1
-rw-r--r--source/blender/draw/engines/eevee/eevee_cryptomatte.c3
-rw-r--r--source/blender/draw/engines/eevee/eevee_effects.c6
-rw-r--r--source/blender/draw/engines/eevee/eevee_engine.c1
-rw-r--r--source/blender/draw/engines/eevee/eevee_lightcache.c3
-rw-r--r--source/blender/draw/engines/eevee/eevee_lightcache.h15
-rw-r--r--source/blender/draw/engines/eevee/eevee_lightprobes.c6
-rw-r--r--source/blender/draw/engines/eevee/eevee_lights.c1
-rw-r--r--source/blender/draw/engines/eevee/eevee_materials.c3
-rw-r--r--source/blender/draw/engines/eevee/eevee_motion_blur.c9
-rw-r--r--source/blender/draw/engines/eevee/eevee_private.h96
-rw-r--r--source/blender/draw/engines/eevee/eevee_render.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_renderpasses.c11
-rw-r--r--source/blender/draw/engines/eevee/eevee_sampling.c6
-rw-r--r--source/blender/draw/engines/eevee/eevee_shaders.c4
-rw-r--r--source/blender/draw/engines/eevee/eevee_shadows.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_shadows_cube.c1
-rw-r--r--source/blender/draw/engines/eevee/eevee_temporal_sampling.c2
-rw-r--r--source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl4
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_dof_bokeh_frag.glsl4
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_dof_gather_frag.glsl4
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl2
-rw-r--r--source/blender/draw/engines/external/external_engine.c3
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_draw_data.c8
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_engine.c1
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_engine.h12
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_render.c1
-rw-r--r--source/blender/draw/engines/image/image_drawing_mode_image_space.hh (renamed from source/blender/draw/engines/image/image_drawing_mode.hh)22
-rw-r--r--source/blender/draw/engines/image/image_engine.cc11
-rw-r--r--source/blender/draw/engines/overlay/overlay_armature.c37
-rw-r--r--source/blender/draw/engines/overlay/overlay_engine.c1
-rw-r--r--source/blender/draw/engines/overlay/overlay_image.c2
-rw-r--r--source/blender/draw/engines/overlay/overlay_private.h7
-rw-r--r--source/blender/draw/engines/overlay/overlay_wireframe.c38
-rw-r--r--source/blender/draw/engines/select/select_debug_engine.c1
-rw-r--r--source/blender/draw/engines/select/select_engine.c1
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_transparent_accum_frag.glsl2
-rw-r--r--source/blender/draw/engines/workbench/workbench_effect_antialiasing.c1
-rw-r--r--source/blender/draw/engines/workbench/workbench_engine.c3
-rw-r--r--source/blender/draw/engines/workbench/workbench_materials.c1
-rw-r--r--source/blender/draw/engines/workbench/workbench_private.h14
-rw-r--r--source/blender/draw/engines/workbench/workbench_transparent.c2
-rw-r--r--source/blender/draw/intern/DRW_render.h244
-rw-r--r--source/blender/draw/intern/draw_cache.c48
-rw-r--r--source/blender/draw/intern/draw_cache.h52
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh.cc7
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh_render_data.c9
-rw-r--r--source/blender/draw/intern/draw_cache_impl.h146
-rw-r--r--source/blender/draw/intern/draw_cache_impl_gpencil.c27
-rw-r--r--source/blender/draw/intern/draw_cache_impl_hair.c1
-rw-r--r--source/blender/draw/intern/draw_cache_impl_mesh.c11
-rw-r--r--source/blender/draw/intern/draw_cache_impl_metaball.c9
-rw-r--r--source/blender/draw/intern/draw_cache_impl_particles.c1
-rw-r--r--source/blender/draw/intern/draw_color_management.cc1
-rw-r--r--source/blender/draw/intern/draw_color_management.h3
-rw-r--r--source/blender/draw/intern/draw_common.c8
-rw-r--r--source/blender/draw/intern/draw_common.h14
-rw-r--r--source/blender/draw/intern/draw_debug.c1
-rw-r--r--source/blender/draw/intern/draw_debug.h3
-rw-r--r--source/blender/draw/intern/draw_fluid.c3
-rw-r--r--source/blender/draw/intern/draw_hair.c1
-rw-r--r--source/blender/draw/intern/draw_hair_private.h6
-rw-r--r--source/blender/draw/intern/draw_instance_data.c23
-rw-r--r--source/blender/draw/intern/draw_instance_data.h48
-rw-r--r--source/blender/draw/intern/draw_manager.c144
-rw-r--r--source/blender/draw/intern/draw_manager.h5
-rw-r--r--source/blender/draw/intern/draw_manager_data.c40
-rw-r--r--source/blender/draw/intern/draw_manager_exec.c17
-rw-r--r--source/blender/draw/intern/draw_manager_profiling.c3
-rw-r--r--source/blender/draw/intern/draw_manager_profiling.h7
-rw-r--r--source/blender/draw/intern/draw_manager_shader.c2
-rw-r--r--source/blender/draw/intern/draw_manager_text.c1
-rw-r--r--source/blender/draw/intern/draw_manager_text.h1
-rw-r--r--source/blender/draw/intern/draw_select_buffer.c26
-rw-r--r--source/blender/draw/intern/draw_texture_pool.cc7
-rw-r--r--source/blender/draw/intern/draw_texture_pool.h7
-rw-r--r--source/blender/draw/intern/draw_view.c4
-rw-r--r--source/blender/draw/intern/draw_view_data.cc11
-rw-r--r--source/blender/draw/intern/draw_view_data.h11
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh.h10
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc2
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc3
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc6
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc6
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc5
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_nor.cc2
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc1
-rw-r--r--source/blender/draw/intern/shaders/common_fxaa_lib.glsl2
-rw-r--r--source/blender/draw/intern/shaders/common_view_lib.glsl2
-rw-r--r--source/blender/editors/animation/CMakeLists.txt12
-rw-r--r--source/blender/editors/animation/anim_channels_defines.c28
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c18
-rw-r--r--source/blender/editors/animation/anim_deps.c6
-rw-r--r--source/blender/editors/animation/anim_draw.c82
-rw-r--r--source/blender/editors/animation/anim_filter.c21
-rw-r--r--source/blender/editors/animation/anim_ipo_utils.c8
-rw-r--r--source/blender/editors/animation/anim_markers.c31
-rw-r--r--source/blender/editors/animation/anim_motion_paths.c14
-rw-r--r--source/blender/editors/animation/drivers.c53
-rw-r--r--source/blender/editors/animation/fmodifier_ui.c11
-rw-r--r--source/blender/editors/animation/keyframes_edit.c34
-rw-r--r--source/blender/editors/animation/keyframes_general.c116
-rw-r--r--source/blender/editors/animation/keyframes_keylist.cc2
-rw-r--r--source/blender/editors/animation/keyframes_keylist_test.cc144
-rw-r--r--source/blender/editors/animation/keyframing.c125
-rw-r--r--source/blender/editors/animation/keyingsets.c40
-rw-r--r--source/blender/editors/armature/armature_add.c7
-rw-r--r--source/blender/editors/armature/armature_edit.c8
-rw-r--r--source/blender/editors/armature/armature_intern.h94
-rw-r--r--source/blender/editors/armature/armature_naming.c16
-rw-r--r--source/blender/editors/armature/armature_ops.c3
-rw-r--r--source/blender/editors/armature/armature_relations.c3
-rw-r--r--source/blender/editors/armature/armature_select.c14
-rw-r--r--source/blender/editors/armature/armature_utils.c84
-rw-r--r--source/blender/editors/armature/editarmature_undo.c1
-rw-r--r--source/blender/editors/armature/pose_edit.c9
-rw-r--r--source/blender/editors/armature/pose_select.c16
-rw-r--r--source/blender/editors/armature/pose_transform.c4
-rw-r--r--source/blender/editors/armature/pose_utils.c13
-rw-r--r--source/blender/editors/asset/CMakeLists.txt2
-rw-r--r--source/blender/editors/asset/ED_asset_catalog.h2
-rw-r--r--source/blender/editors/asset/ED_asset_catalog.hh25
-rw-r--r--source/blender/editors/asset/ED_asset_filter.h14
-rw-r--r--source/blender/editors/asset/ED_asset_handle.h6
-rw-r--r--source/blender/editors/asset/ED_asset_indexer.h50
-rw-r--r--source/blender/editors/asset/ED_asset_library.h20
-rw-r--r--source/blender/editors/asset/ED_asset_list.h26
-rw-r--r--source/blender/editors/asset/ED_asset_temp_id_consumer.h5
-rw-r--r--source/blender/editors/asset/intern/asset_catalog.cc23
-rw-r--r--source/blender/editors/asset/intern/asset_filter.cc12
-rw-r--r--source/blender/editors/asset/intern/asset_handle.cc6
-rw-r--r--source/blender/editors/asset/intern/asset_indexer.cc781
-rw-r--r--source/blender/editors/asset/intern/asset_library_reference_enum.cc46
-rw-r--r--source/blender/editors/asset/intern/asset_list.cc36
-rw-r--r--source/blender/editors/asset/intern/asset_ops.cc330
-rw-r--r--source/blender/editors/curve/curve_intern.h13
-rw-r--r--source/blender/editors/curve/editcurve.c23
-rw-r--r--source/blender/editors/curve/editcurve_paint.c4
-rw-r--r--source/blender/editors/curve/editcurve_select.c2
-rw-r--r--source/blender/editors/curve/editcurve_undo.c1
-rw-r--r--source/blender/editors/curve/editfont.c5
-rw-r--r--source/blender/editors/curve/editfont_undo.c1
-rw-r--r--source/blender/editors/datafiles/CMakeLists.txt1
-rw-r--r--source/blender/editors/gizmo_library/gizmo_draw_utils.c3
-rw-r--r--source/blender/editors/gizmo_library/gizmo_library_intern.h7
-rw-r--r--source/blender/editors/gizmo_library/gizmo_library_utils.c4
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c10
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c8
-rw-r--r--source/blender/editors/gpencil/annotate_draw.c11
-rw-r--r--source/blender/editors/gpencil/annotate_paint.c18
-rw-r--r--source/blender/editors/gpencil/drawgpencil.c1
-rw-r--r--source/blender/editors/gpencil/editaction_gpencil.c25
-rw-r--r--source/blender/editors/gpencil/gpencil_add_blank.c1
-rw-r--r--source/blender/editors/gpencil/gpencil_add_lineart.c1
-rw-r--r--source/blender/editors/gpencil/gpencil_add_monkey.c8
-rw-r--r--source/blender/editors/gpencil/gpencil_add_stroke.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_convert.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_data.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c25
-rw-r--r--source/blender/editors/gpencil/gpencil_edit_curve.c10
-rw-r--r--source/blender/editors/gpencil/gpencil_fill.c4
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h130
-rw-r--r--source/blender/editors/gpencil/gpencil_interpolate.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c15
-rw-r--r--source/blender/editors/gpencil/gpencil_primitive.c10
-rw-r--r--source/blender/editors/gpencil/gpencil_sculpt_paint.c3
-rw-r--r--source/blender/editors/gpencil/gpencil_select.c1
-rw-r--r--source/blender/editors/gpencil/gpencil_trace.h32
-rw-r--r--source/blender/editors/gpencil/gpencil_trace_utils.c32
-rw-r--r--source/blender/editors/gpencil/gpencil_undo.c3
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c189
-rw-r--r--source/blender/editors/include/BIF_glutil.h26
-rw-r--r--source/blender/editors/include/ED_anim_api.h366
-rw-r--r--source/blender/editors/include/ED_armature.h137
-rw-r--r--source/blender/editors/include/ED_buttons.h5
-rw-r--r--source/blender/editors/include/ED_clip.h15
-rw-r--r--source/blender/editors/include/ED_curve.h24
-rw-r--r--source/blender/editors/include/ED_file_indexer.h153
-rw-r--r--source/blender/editors/include/ED_fileselect.h30
-rw-r--r--source/blender/editors/include/ED_gizmo_library.h10
-rw-r--r--source/blender/editors/include/ED_gpencil.h268
-rw-r--r--source/blender/editors/include/ED_image.h37
-rw-r--r--source/blender/editors/include/ED_info.h5
-rw-r--r--source/blender/editors/include/ED_keyframes_edit.h127
-rw-r--r--source/blender/editors/include/ED_keyframing.h349
-rw-r--r--source/blender/editors/include/ED_lattice.h4
-rw-r--r--source/blender/editors/include/ED_markers.h63
-rw-r--r--source/blender/editors/include/ED_mask.h49
-rw-r--r--source/blender/editors/include/ED_mball.h18
-rw-r--r--source/blender/editors/include/ED_mesh.h196
-rw-r--r--source/blender/editors/include/ED_node.h46
-rw-r--r--source/blender/editors/include/ED_numinput.h6
-rw-r--r--source/blender/editors/include/ED_object.h161
-rw-r--r--source/blender/editors/include/ED_outliner.h17
-rw-r--r--source/blender/editors/include/ED_paint.h16
-rw-r--r--source/blender/editors/include/ED_particle.h6
-rw-r--r--source/blender/editors/include/ED_render.h22
-rw-r--r--source/blender/editors/include/ED_scene.h7
-rw-r--r--source/blender/editors/include/ED_screen.h261
-rw-r--r--source/blender/editors/include/ED_sculpt.h9
-rw-r--r--source/blender/editors/include/ED_select_utils.h14
-rw-r--r--source/blender/editors/include/ED_sequencer.h10
-rw-r--r--source/blender/editors/include/ED_space_api.h20
-rw-r--r--source/blender/editors/include/ED_text.h9
-rw-r--r--source/blender/editors/include/ED_transform.h17
-rw-r--r--source/blender/editors/include/ED_transform_snap_object_context.h23
-rw-r--r--source/blender/editors/include/ED_undo.h49
-rw-r--r--source/blender/editors/include/ED_util.h34
-rw-r--r--source/blender/editors/include/ED_uvedit.h14
-rw-r--r--source/blender/editors/include/ED_view3d.h426
-rw-r--r--source/blender/editors/include/ED_view3d_offscreen.h18
-rw-r--r--source/blender/editors/include/UI_icons.h2
-rw-r--r--source/blender/editors/include/UI_interface.h575
-rw-r--r--source/blender/editors/include/UI_interface.hh3
-rw-r--r--source/blender/editors/include/UI_interface_icons.h18
-rw-r--r--source/blender/editors/include/UI_resources.h99
-rw-r--r--source/blender/editors/include/UI_tree_view.hh195
-rw-r--r--source/blender/editors/include/UI_view2d.h193
-rw-r--r--source/blender/editors/interface/CMakeLists.txt2
-rw-r--r--source/blender/editors/interface/interface.c211
-rw-r--r--source/blender/editors/interface/interface_align.c7
-rw-r--r--source/blender/editors/interface/interface_anim.c5
-rw-r--r--source/blender/editors/interface/interface_button_group.c4
-rw-r--r--source/blender/editors/interface/interface_context_menu.c3
-rw-r--r--source/blender/editors/interface/interface_context_path.cc4
-rw-r--r--source/blender/editors/interface/interface_draw.c20
-rw-r--r--source/blender/editors/interface/interface_eyedropper.c11
-rw-r--r--source/blender/editors/interface/interface_eyedropper_color.c19
-rw-r--r--source/blender/editors/interface/interface_eyedropper_intern.h18
-rw-r--r--source/blender/editors/interface/interface_handlers.c184
-rw-r--r--source/blender/editors/interface/interface_icons.c25
-rw-r--r--source/blender/editors/interface/interface_intern.h264
-rw-r--r--source/blender/editors/interface/interface_layout.c79
-rw-r--r--source/blender/editors/interface/interface_ops.c138
-rw-r--r--source/blender/editors/interface/interface_panel.c111
-rw-r--r--source/blender/editors/interface/interface_query.c9
-rw-r--r--source/blender/editors/interface/interface_region_color_picker.c3
-rw-r--r--source/blender/editors/interface/interface_region_hud.c1
-rw-r--r--source/blender/editors/interface/interface_region_menu_pie.c7
-rw-r--r--source/blender/editors/interface/interface_region_menu_popup.c8
-rw-r--r--source/blender/editors/interface/interface_region_popover.c7
-rw-r--r--source/blender/editors/interface/interface_region_popup.c8
-rw-r--r--source/blender/editors/interface/interface_region_search.cc29
-rw-r--r--source/blender/editors/interface/interface_region_tooltip.c11
-rw-r--r--source/blender/editors/interface/interface_style.c25
-rw-r--r--source/blender/editors/interface/interface_template_asset_view.cc2
-rw-r--r--source/blender/editors/interface/interface_template_attribute_search.cc2
-rw-r--r--source/blender/editors/interface/interface_template_list.cc8
-rw-r--r--source/blender/editors/interface/interface_template_search_menu.cc (renamed from source/blender/editors/interface/interface_template_search_menu.c)286
-rw-r--r--source/blender/editors/interface/interface_templates.c321
-rw-r--r--source/blender/editors/interface/interface_undo.c11
-rw-r--r--source/blender/editors/interface/interface_utils.c36
-rw-r--r--source/blender/editors/interface/interface_view.cc8
-rw-r--r--source/blender/editors/interface/interface_widgets.c339
-rw-r--r--source/blender/editors/interface/resources.c18
-rw-r--r--source/blender/editors/interface/tree_view.cc292
-rw-r--r--source/blender/editors/interface/view2d.c110
-rw-r--r--source/blender/editors/interface/view2d_gizmo_navigate.c1
-rw-r--r--source/blender/editors/interface/view2d_ops.c3
-rw-r--r--source/blender/editors/lattice/editlattice_tools.c2
-rw-r--r--source/blender/editors/lattice/editlattice_undo.c1
-rw-r--r--source/blender/editors/mask/mask_draw.c58
-rw-r--r--source/blender/editors/mask/mask_editaction.c11
-rw-r--r--source/blender/editors/mask/mask_intern.h12
-rw-r--r--source/blender/editors/mask/mask_ops.c4
-rw-r--r--source/blender/editors/mask/mask_query.c3
-rw-r--r--source/blender/editors/mask/mask_relationships.c1
-rw-r--r--source/blender/editors/mask/mask_select.c1
-rw-r--r--source/blender/editors/mesh/editface.c11
-rw-r--r--source/blender/editors/mesh/editmesh_extrude.c1
-rw-r--r--source/blender/editors/mesh/editmesh_intersect.c1
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c7
-rw-r--r--source/blender/editors/mesh/editmesh_preselect_elem.c1
-rw-r--r--source/blender/editors/mesh/editmesh_select.c41
-rw-r--r--source/blender/editors/mesh/editmesh_select_similar.c2
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c1
-rw-r--r--source/blender/editors/mesh/editmesh_undo.c1
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c53
-rw-r--r--source/blender/editors/mesh/mesh_data.c23
-rw-r--r--source/blender/editors/mesh/mesh_intern.h55
-rw-r--r--source/blender/editors/mesh/mesh_ops.c1
-rw-r--r--source/blender/editors/mesh/meshtools.c30
-rw-r--r--source/blender/editors/metaball/editmball_undo.c1
-rw-r--r--source/blender/editors/metaball/mball_edit.c11
-rw-r--r--source/blender/editors/object/object_add.c27
-rw-r--r--source/blender/editors/object/object_constraint.c11
-rw-r--r--source/blender/editors/object/object_data_transfer.c1
-rw-r--r--source/blender/editors/object/object_edit.c35
-rw-r--r--source/blender/editors/object/object_facemap_ops.c2
-rw-r--r--source/blender/editors/object/object_intern.h34
-rw-r--r--source/blender/editors/object/object_modes.c9
-rw-r--r--source/blender/editors/object/object_modifier.c24
-rw-r--r--source/blender/editors/object/object_relations.c9
-rw-r--r--source/blender/editors/object/object_remesh.cc3
-rw-r--r--source/blender/editors/object/object_select.c31
-rw-r--r--source/blender/editors/object/object_shader_fx.c2
-rw-r--r--source/blender/editors/object/object_utils.c4
-rw-r--r--source/blender/editors/object/object_vgroup.c25
-rw-r--r--source/blender/editors/object/object_volume.c1
-rw-r--r--source/blender/editors/physics/dynamicpaint_ops.c2
-rw-r--r--source/blender/editors/physics/particle_edit.c3
-rw-r--r--source/blender/editors/physics/particle_edit_undo.c1
-rw-r--r--source/blender/editors/physics/physics_intern.h24
-rw-r--r--source/blender/editors/render/render_intern.h9
-rw-r--r--source/blender/editors/render/render_internal.c1
-rw-r--r--source/blender/editors/render/render_preview.c164
-rw-r--r--source/blender/editors/render/render_shading.c4
-rw-r--r--source/blender/editors/render/render_update.c3
-rw-r--r--source/blender/editors/render/render_view.c1
-rw-r--r--source/blender/editors/scene/scene_edit.c5
-rw-r--r--source/blender/editors/screen/area.c79
-rw-r--r--source/blender/editors/screen/area_query.c11
-rw-r--r--source/blender/editors/screen/area_utils.c6
-rw-r--r--source/blender/editors/screen/glutil.c23
-rw-r--r--source/blender/editors/screen/screen_context.c89
-rw-r--r--source/blender/editors/screen/screen_draw.c12
-rw-r--r--source/blender/editors/screen/screen_edit.c86
-rw-r--r--source/blender/editors/screen/screen_geometry.c18
-rw-r--r--source/blender/editors/screen/screen_intern.h65
-rw-r--r--source/blender/editors/screen/screen_ops.c31
-rw-r--r--source/blender/editors/screen/screendump.c5
-rw-r--r--source/blender/editors/screen/workspace_edit.c22
-rw-r--r--source/blender/editors/screen/workspace_layout_edit.c13
-rw-r--r--source/blender/editors/sculpt_paint/CMakeLists.txt1
-rw-r--r--source/blender/editors/sculpt_paint/paint_cursor.c1
-rw-r--r--source/blender/editors/sculpt_paint/paint_curve_undo.c1
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c48
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d.c104
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d_curve_mask.cc188
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c39
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h128
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c4
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c8
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c3
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_color_utils.c6
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c5
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c11
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c152
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_boundary.c3
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_cloth.c3
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_detail.c34
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_face_set.c1
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_mesh.c1
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h156
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c1
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_pose.c8
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_smooth.c2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c1
-rw-r--r--source/blender/editors/space_action/action_data.c3
-rw-r--r--source/blender/editors/space_action/action_draw.c57
-rw-r--r--source/blender/editors/space_action/action_intern.h7
-rw-r--r--source/blender/editors/space_action/space_action.c10
-rw-r--r--source/blender/editors/space_api/spacetypes.c5
-rw-r--r--source/blender/editors/space_buttons/buttons_intern.h6
-rw-r--r--source/blender/editors/space_buttons/buttons_ops.c1
-rw-r--r--source/blender/editors/space_buttons/buttons_texture.c1
-rw-r--r--source/blender/editors/space_buttons/space_buttons.c8
-rw-r--r--source/blender/editors/space_clip/clip_draw.c1
-rw-r--r--source/blender/editors/space_clip/clip_editor.c11
-rw-r--r--source/blender/editors/space_clip/clip_intern.h16
-rw-r--r--source/blender/editors/space_clip/clip_ops.c15
-rw-r--r--source/blender/editors/space_clip/clip_utils.c3
-rw-r--r--source/blender/editors/space_clip/space_clip.c1
-rw-r--r--source/blender/editors/space_console/space_console.c1
-rw-r--r--source/blender/editors/space_file/CMakeLists.txt3
-rw-r--r--source/blender/editors/space_file/asset_catalog_tree_view.cc205
-rw-r--r--source/blender/editors/space_file/file_draw.c6
-rw-r--r--source/blender/editors/space_file/file_indexer.cc96
-rw-r--r--source/blender/editors/space_file/file_indexer.h (renamed from source/blender/blenkernel/intern/extern_implementations.cc)25
-rw-r--r--source/blender/editors/space_file/file_intern.h58
-rw-r--r--source/blender/editors/space_file/file_ops.c54
-rw-r--r--source/blender/editors/space_file/file_panels.c18
-rw-r--r--source/blender/editors/space_file/file_utils.c3
-rw-r--r--source/blender/editors/space_file/filelist.c468
-rw-r--r--source/blender/editors/space_file/filelist.h48
-rw-r--r--source/blender/editors/space_file/filesel.c58
-rw-r--r--source/blender/editors/space_file/space_file.c14
-rw-r--r--source/blender/editors/space_graph/graph_draw.c21
-rw-r--r--source/blender/editors/space_graph/graph_intern.h50
-rw-r--r--source/blender/editors/space_graph/graph_select.c11
-rw-r--r--source/blender/editors/space_graph/graph_slider_ops.c306
-rw-r--r--source/blender/editors/space_graph/graph_utils.c17
-rw-r--r--source/blender/editors/space_graph/graph_view.c2
-rw-r--r--source/blender/editors/space_graph/space_graph.c1
-rw-r--r--source/blender/editors/space_image/image_buttons.c1
-rw-r--r--source/blender/editors/space_image/image_draw.c6
-rw-r--r--source/blender/editors/space_image/image_edit.c7
-rw-r--r--source/blender/editors/space_image/image_intern.h12
-rw-r--r--source/blender/editors/space_image/image_ops.c17
-rw-r--r--source/blender/editors/space_image/image_sequence.c1
-rw-r--r--source/blender/editors/space_image/image_undo.c6
-rw-r--r--source/blender/editors/space_image/space_image.c1
-rw-r--r--source/blender/editors/space_info/info_ops.c10
-rw-r--r--source/blender/editors/space_info/info_report.c1
-rw-r--r--source/blender/editors/space_info/info_stats.cc5
-rw-r--r--source/blender/editors/space_info/space_info.c1
-rw-r--r--source/blender/editors/space_info/textview.c7
-rw-r--r--source/blender/editors/space_info/textview.h7
-rw-r--r--source/blender/editors/space_nla/nla_channels.c2
-rw-r--r--source/blender/editors/space_nla/nla_draw.c12
-rw-r--r--source/blender/editors/space_nla/nla_edit.c15
-rw-r--r--source/blender/editors/space_nla/nla_intern.h18
-rw-r--r--source/blender/editors/space_nla/nla_ops.c3
-rw-r--r--source/blender/editors/space_nla/space_nla.c1
-rw-r--r--source/blender/editors/space_node/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_node/drawnode.cc2061
-rw-r--r--source/blender/editors/space_node/link_drag_search.cc291
-rw-r--r--source/blender/editors/space_node/node_add.cc93
-rw-r--r--source/blender/editors/space_node/node_draw.cc1526
-rw-r--r--source/blender/editors/space_node/node_edit.cc248
-rw-r--r--source/blender/editors/space_node/node_geometry_attribute_search.cc16
-rw-r--r--source/blender/editors/space_node/node_group.cc197
-rw-r--r--source/blender/editors/space_node/node_intern.hh272
-rw-r--r--source/blender/editors/space_node/node_ops.cc2
-rw-r--r--source/blender/editors/space_node/node_relationships.cc867
-rw-r--r--source/blender/editors/space_node/node_select.cc173
-rw-r--r--source/blender/editors/space_node/node_templates.cc11
-rw-r--r--source/blender/editors/space_node/node_view.cc85
-rw-r--r--source/blender/editors/space_node/space_node.cc71
-rw-r--r--source/blender/editors/space_outliner/outliner_collections.c5
-rw-r--r--source/blender/editors/space_outliner/outliner_dragdrop.c1
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c9
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c21
-rw-r--r--source/blender/editors/space_outliner/outliner_intern.h110
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c9
-rw-r--r--source/blender/editors/space_outliner/outliner_sync.c4
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c5
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.c19
-rw-r--r--source/blender/editors/space_outliner/outliner_utils.c34
-rw-r--r--source/blender/editors/space_outliner/space_outliner.c1
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display.h8
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display.hh3
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_libraries.cc1
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_orphaned.cc1
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_override_library.cc5
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_scenes.cc1
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_sequencer.cc2
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_view_layer.cc1
-rw-r--r--source/blender/editors/space_script/space_script.c1
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c12
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c53
-rw-r--r--source/blender/editors/space_sequencer/sequencer_intern.h31
-rw-r--r--source/blender/editors/space_sequencer/sequencer_select.c203
-rw-r--r--source/blender/editors/space_sequencer/sequencer_thumbnails.c2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_view.c2
-rw-r--r--source/blender/editors/space_sequencer/space_sequencer.c76
-rw-r--r--source/blender/editors/space_spreadsheet/CMakeLists.txt4
-rw-r--r--source/blender/editors/space_spreadsheet/space_spreadsheet.cc38
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh64
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_column.cc38
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh60
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc479
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh28
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc366
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.hh42
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.cc118
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.hh68
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_draw.cc8
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_intern.hh9
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_layout.cc171
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_layout.hh2
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_panels.cc (renamed from source/blender/functions/FN_multi_function_parallel.hh)34
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc413
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_row_filter.hh8
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc6
-rw-r--r--source/blender/editors/space_statusbar/space_statusbar.c1
-rw-r--r--source/blender/editors/space_text/space_text.c1
-rw-r--r--source/blender/editors/space_text/text_draw.c10
-rw-r--r--source/blender/editors/space_text/text_format.c13
-rw-r--r--source/blender/editors/space_text/text_format.h21
-rw-r--r--source/blender/editors/space_text/text_intern.h9
-rw-r--r--source/blender/editors/space_text/text_undo.c3
-rw-r--r--source/blender/editors/space_topbar/space_topbar.c56
-rw-r--r--source/blender/editors/space_userpref/space_userpref.c1
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c21
-rw-r--r--source/blender/editors/space_view3d/view3d_camera_control.c16
-rw-r--r--source/blender/editors/space_view3d/view3d_cursor_snap.c31
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c67
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c25
-rw-r--r--source/blender/editors/space_view3d/view3d_intern.h66
-rw-r--r--source/blender/editors/space_view3d/view3d_iterators.c10
-rw-r--r--source/blender/editors/space_view3d/view3d_navigate_fly.c1
-rw-r--r--source/blender/editors/space_view3d/view3d_navigate_walk.c1
-rw-r--r--source/blender/editors/space_view3d/view3d_project.c127
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c38
-rw-r--r--source/blender/editors/space_view3d/view3d_snap.c4
-rw-r--r--source/blender/editors/space_view3d/view3d_utils.c161
-rw-r--r--source/blender/editors/space_view3d/view3d_view.c71
-rw-r--r--source/blender/editors/transform/transform.c10
-rw-r--r--source/blender/editors/transform/transform.h43
-rw-r--r--source/blender/editors/transform/transform_constraints.c25
-rw-r--r--source/blender/editors/transform/transform_constraints.h25
-rw-r--r--source/blender/editors/transform/transform_convert.c36
-rw-r--r--source/blender/editors/transform/transform_convert.h82
-rw-r--r--source/blender/editors/transform/transform_convert_action.c1
-rw-r--r--source/blender/editors/transform/transform_convert_armature.c7
-rw-r--r--source/blender/editors/transform/transform_convert_gpencil.c22
-rw-r--r--source/blender/editors/transform/transform_convert_graph.c10
-rw-r--r--source/blender/editors/transform/transform_convert_mesh.c9
-rw-r--r--source/blender/editors/transform/transform_convert_mesh_skin.c1
-rw-r--r--source/blender/editors/transform/transform_convert_mesh_uv.c1
-rw-r--r--source/blender/editors/transform/transform_convert_nla.c1
-rw-r--r--source/blender/editors/transform/transform_convert_object.c1
-rw-r--r--source/blender/editors/transform/transform_convert_object_texspace.c3
-rw-r--r--source/blender/editors/transform/transform_convert_sequencer.c1
-rw-r--r--source/blender/editors/transform/transform_convert_sequencer_image.c13
-rw-r--r--source/blender/editors/transform/transform_convert_tracking.c1
-rw-r--r--source/blender/editors/transform/transform_draw_cursors.c8
-rw-r--r--source/blender/editors/transform/transform_draw_cursors.h9
-rw-r--r--source/blender/editors/transform/transform_generics.c108
-rw-r--r--source/blender/editors/transform/transform_gizmo_2d.c79
-rw-r--r--source/blender/editors/transform/transform_gizmo_3d.c3
-rw-r--r--source/blender/editors/transform/transform_mode.c19
-rw-r--r--source/blender/editors/transform/transform_mode.h15
-rw-r--r--source/blender/editors/transform/transform_mode_align.c1
-rw-r--r--source/blender/editors/transform/transform_mode_baketime.c1
-rw-r--r--source/blender/editors/transform/transform_mode_bbone_resize.c2
-rw-r--r--source/blender/editors/transform/transform_mode_bend.c1
-rw-r--r--source/blender/editors/transform/transform_mode_boneenvelope.c2
-rw-r--r--source/blender/editors/transform/transform_mode_boneroll.c3
-rw-r--r--source/blender/editors/transform/transform_mode_curveshrinkfatten.c3
-rw-r--r--source/blender/editors/transform/transform_mode_edge_bevelweight.c3
-rw-r--r--source/blender/editors/transform/transform_mode_edge_crease.c2
-rw-r--r--source/blender/editors/transform/transform_mode_edge_rotate_normal.c3
-rw-r--r--source/blender/editors/transform/transform_mode_edge_slide.c3
-rw-r--r--source/blender/editors/transform/transform_mode_gpopacity.c3
-rw-r--r--source/blender/editors/transform/transform_mode_gpshrinkfatten.c3
-rw-r--r--source/blender/editors/transform/transform_mode_maskshrinkfatten.c3
-rw-r--r--source/blender/editors/transform/transform_mode_mirror.c1
-rw-r--r--source/blender/editors/transform/transform_mode_push_pull.c3
-rw-r--r--source/blender/editors/transform/transform_mode_resize.c1
-rw-r--r--source/blender/editors/transform/transform_mode_rotate.c1
-rw-r--r--source/blender/editors/transform/transform_mode_shear.c3
-rw-r--r--source/blender/editors/transform/transform_mode_shrink_fatten.c3
-rw-r--r--source/blender/editors/transform/transform_mode_skin_resize.c2
-rw-r--r--source/blender/editors/transform/transform_mode_tilt.c3
-rw-r--r--source/blender/editors/transform/transform_mode_timescale.c1
-rw-r--r--source/blender/editors/transform/transform_mode_timeslide.c1
-rw-r--r--source/blender/editors/transform/transform_mode_timetranslate.c1
-rw-r--r--source/blender/editors/transform/transform_mode_tosphere.c3
-rw-r--r--source/blender/editors/transform/transform_mode_trackball.c1
-rw-r--r--source/blender/editors/transform/transform_mode_translate.c1
-rw-r--r--source/blender/editors/transform/transform_mode_vert_slide.c3
-rw-r--r--source/blender/editors/transform/transform_orientations.c17
-rw-r--r--source/blender/editors/transform/transform_orientations.h13
-rw-r--r--source/blender/editors/transform/transform_snap.c49
-rw-r--r--source/blender/editors/transform/transform_snap.h12
-rw-r--r--source/blender/editors/transform/transform_snap_animation.c9
-rw-r--r--source/blender/editors/transform/transform_snap_object.c160
-rw-r--r--source/blender/editors/undo/ed_undo.c146
-rw-r--r--source/blender/editors/undo/memfile_undo.c58
-rw-r--r--source/blender/editors/undo/undo_intern.h2
-rw-r--r--source/blender/editors/util/ed_draw.c15
-rw-r--r--source/blender/editors/util/ed_util.c20
-rw-r--r--source/blender/editors/util/ed_util_ops.cc4
-rw-r--r--source/blender/editors/util/gizmo_utils.c1
-rw-r--r--source/blender/editors/util/numinput.c4
-rw-r--r--source/blender/editors/util/select_utils.c10
-rw-r--r--source/blender/editors/uvedit/uvedit_intern.h13
-rw-r--r--source/blender/editors/uvedit/uvedit_islands.c3
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c1
-rw-r--r--source/blender/editors/uvedit/uvedit_select.c17
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c2
-rw-r--r--source/blender/freestyle/FRS_freestyle.h4
-rw-r--r--source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp4
-rw-r--r--source/blender/freestyle/intern/image/GaussianFilter.h14
-rw-r--r--source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.h2
-rw-r--r--source/blender/freestyle/intern/system/PythonInterpreter.h2
-rw-r--r--source/blender/freestyle/intern/winged_edge/Curvature.cpp66
-rw-r--r--source/blender/freestyle/intern/winged_edge/Curvature.h63
-rw-r--r--source/blender/functions/CMakeLists.txt5
-rw-r--r--source/blender/functions/FN_cpp_type.hh12
-rw-r--r--source/blender/functions/FN_field.hh161
-rw-r--r--source/blender/functions/FN_field_cpp_type.hh95
-rw-r--r--source/blender/functions/FN_generic_span.hh10
-rw-r--r--source/blender/functions/FN_generic_virtual_array.hh62
-rw-r--r--source/blender/functions/FN_multi_function.hh36
-rw-r--r--source/blender/functions/FN_multi_function_builder.hh34
-rw-r--r--source/blender/functions/FN_multi_function_params.hh29
-rw-r--r--source/blender/functions/FN_multi_function_procedure_executor.hh5
-rw-r--r--source/blender/functions/FN_multi_function_procedure_optimization.hh61
-rw-r--r--source/blender/functions/FN_multi_function_signature.hh47
-rw-r--r--source/blender/functions/intern/field.cc184
-rw-r--r--source/blender/functions/intern/generic_virtual_array.cc180
-rw-r--r--source/blender/functions/intern/multi_function.cc132
-rw-r--r--source/blender/functions/intern/multi_function_builder.cc36
-rw-r--r--source/blender/functions/intern/multi_function_parallel.cc93
-rw-r--r--source/blender/functions/intern/multi_function_params.cc44
-rw-r--r--source/blender/functions/intern/multi_function_procedure.cc2
-rw-r--r--source/blender/functions/intern/multi_function_procedure_executor.cc141
-rw-r--r--source/blender/functions/intern/multi_function_procedure_optimization.cc90
-rw-r--r--source/blender/functions/tests/FN_field_test.cc12
-rw-r--r--source/blender/functions/tests/FN_multi_function_procedure_test.cc14
-rw-r--r--source/blender/functions/tests/FN_multi_function_test.cc2
-rw-r--r--source/blender/geometry/CMakeLists.txt3
-rw-r--r--source/blender/geometry/GEO_mesh_to_curve.hh5
-rw-r--r--source/blender/geometry/GEO_realize_instances.hh52
-rw-r--r--source/blender/geometry/intern/mesh_to_curve_convert.cc5
-rw-r--r--source/blender/geometry/intern/realize_instances.cc1347
-rw-r--r--source/blender/gpencil_modifiers/CMakeLists.txt1
-rw-r--r--source/blender/gpencil_modifiers/MOD_gpencil_lineart.h1
-rw-r--r--source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h1
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c16
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.h12
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c3
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h6
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencildash.c2
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencillength.c107
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c350
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c2
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h28
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c12
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c36
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c4
-rw-r--r--source/blender/gpu/GPU_batch.h37
-rw-r--r--source/blender/gpu/GPU_batch_presets.h6
-rw-r--r--source/blender/gpu/GPU_batch_utils.h16
-rw-r--r--source/blender/gpu/GPU_buffers.h47
-rw-r--r--source/blender/gpu/GPU_capabilities.h3
-rw-r--r--source/blender/gpu/GPU_context.h6
-rw-r--r--source/blender/gpu/GPU_debug.h7
-rw-r--r--source/blender/gpu/GPU_framebuffer.h29
-rw-r--r--source/blender/gpu/GPU_immediate.h29
-rw-r--r--source/blender/gpu/GPU_immediate_util.h89
-rw-r--r--source/blender/gpu/GPU_material.h22
-rw-r--r--source/blender/gpu/GPU_matrix.h33
-rw-r--r--source/blender/gpu/GPU_platform.h3
-rw-r--r--source/blender/gpu/GPU_select.h33
-rw-r--r--source/blender/gpu/GPU_shader.h26
-rw-r--r--source/blender/gpu/GPU_state.h24
-rw-r--r--source/blender/gpu/GPU_texture.h44
-rw-r--r--source/blender/gpu/GPU_uniform_buffer.h6
-rw-r--r--source/blender/gpu/GPU_vertex_buffer.h48
-rw-r--r--source/blender/gpu/GPU_vertex_format.h35
-rw-r--r--source/blender/gpu/GPU_viewport.h26
-rw-r--r--source/blender/gpu/intern/gpu_batch.cc14
-rw-r--r--source/blender/gpu/intern/gpu_batch_presets.c2
-rw-r--r--source/blender/gpu/intern/gpu_batch_utils.c9
-rw-r--r--source/blender/gpu/intern/gpu_buffers.c12
-rw-r--r--source/blender/gpu/intern/gpu_capabilities.cc47
-rw-r--r--source/blender/gpu/intern/gpu_context.cc10
-rw-r--r--source/blender/gpu/intern/gpu_debug.cc7
-rw-r--r--source/blender/gpu/intern/gpu_framebuffer.cc43
-rw-r--r--source/blender/gpu/intern/gpu_immediate.cc2
-rw-r--r--source/blender/gpu/intern/gpu_immediate_util.c126
-rw-r--r--source/blender/gpu/intern/gpu_index_buffer.cc2
-rw-r--r--source/blender/gpu/intern/gpu_material.c13
-rw-r--r--source/blender/gpu/intern/gpu_matrix.cc26
-rw-r--r--source/blender/gpu/intern/gpu_node_graph.c2
-rw-r--r--source/blender/gpu/intern/gpu_node_graph.h9
-rw-r--r--source/blender/gpu/intern/gpu_platform.cc11
-rw-r--r--source/blender/gpu/intern/gpu_select.c23
-rw-r--r--source/blender/gpu/intern/gpu_select_pick.c1
-rw-r--r--source/blender/gpu/intern/gpu_select_private.h5
-rw-r--r--source/blender/gpu/intern/gpu_select_sample_query.cc2
-rw-r--r--source/blender/gpu/intern/gpu_shader.cc22
-rw-r--r--source/blender/gpu/intern/gpu_shader_interface.cc9
-rw-r--r--source/blender/gpu/intern/gpu_shader_interface.hh4
-rw-r--r--source/blender/gpu/intern/gpu_state.cc11
-rw-r--r--source/blender/gpu/intern/gpu_texture.cc14
-rw-r--r--source/blender/gpu/intern/gpu_uniform_buffer.cc8
-rw-r--r--source/blender/gpu/intern/gpu_vertex_buffer.cc13
-rw-r--r--source/blender/gpu/intern/gpu_vertex_format.cc27
-rw-r--r--source/blender/gpu/intern/gpu_viewport.c29
-rw-r--r--source/blender/gpu/opengl/gl_backend.cc12
-rw-r--r--source/blender/gpu/opengl/gl_batch.cc5
-rw-r--r--source/blender/gpu/opengl/gl_batch.hh19
-rw-r--r--source/blender/gpu/opengl/gl_context.hh6
-rw-r--r--source/blender/gpu/opengl/gl_debug.cc1
-rw-r--r--source/blender/gpu/opengl/gl_debug.hh8
-rw-r--r--source/blender/gpu/opengl/gl_debug_layer.cc5
-rw-r--r--source/blender/gpu/opengl/gl_drawlist.cc2
-rw-r--r--source/blender/gpu/opengl/gl_framebuffer.cc4
-rw-r--r--source/blender/gpu/opengl/gl_framebuffer.hh6
-rw-r--r--source/blender/gpu/opengl/gl_shader.cc2
-rw-r--r--source/blender/gpu/opengl/gl_shader.hh6
-rw-r--r--source/blender/gpu/opengl/gl_state.cc2
-rw-r--r--source/blender/gpu/opengl/gl_state.hh6
-rw-r--r--source/blender/gpu/opengl/gl_texture.cc22
-rw-r--r--source/blender/gpu/opengl/gl_texture.hh19
-rw-r--r--source/blender/gpu/opengl/gl_vertex_array.cc2
-rw-r--r--source/blender/gpu/opengl/gl_vertex_array.hh6
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_line_dashed_frag.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl147
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_magic.glsl3
-rw-r--r--source/blender/ikplugin/intern/itasc_plugin.cpp9
-rw-r--r--source/blender/imbuf/CMakeLists.txt1
-rw-r--r--source/blender/imbuf/IMB_colormanagement.h198
-rw-r--r--source/blender/imbuf/IMB_imbuf.h239
-rw-r--r--source/blender/imbuf/IMB_imbuf_types.h29
-rw-r--r--source/blender/imbuf/IMB_moviecache.h3
-rw-r--r--source/blender/imbuf/IMB_thumbs.h39
-rw-r--r--source/blender/imbuf/intern/IMB_filetype.h107
-rw-r--r--source/blender/imbuf/intern/IMB_filter.h3
-rw-r--r--source/blender/imbuf/intern/allocimbuf.c15
-rw-r--r--source/blender/imbuf/intern/bmp.c1
-rw-r--r--source/blender/imbuf/intern/cache.c2
-rw-r--r--source/blender/imbuf/intern/colormanagement.c59
-rw-r--r--source/blender/imbuf/intern/colormanagement_inline.c12
-rw-r--r--source/blender/imbuf/intern/dds/BlockDXT.cpp18
-rw-r--r--source/blender/imbuf/intern/dds/BlockDXT.h18
-rw-r--r--source/blender/imbuf/intern/dds/ColorBlock.cpp5
-rw-r--r--source/blender/imbuf/intern/dds/ColorBlock.h5
-rw-r--r--source/blender/imbuf/intern/dds/DirectDrawSurface.cpp2
-rw-r--r--source/blender/imbuf/intern/dds/DirectDrawSurface.h7
-rw-r--r--source/blender/imbuf/intern/dds/FlipDXT.cpp1
-rw-r--r--source/blender/imbuf/intern/dds/FlipDXT.h6
-rw-r--r--source/blender/imbuf/intern/divers.c27
-rw-r--r--source/blender/imbuf/intern/filter.c8
-rw-r--r--source/blender/imbuf/intern/imageprocess.c186
-rw-r--r--source/blender/imbuf/intern/iris.c6
-rw-r--r--source/blender/imbuf/intern/moviecache.c2
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.cpp23
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.h4
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_multi.h27
-rw-r--r--source/blender/imbuf/intern/rectop.c35
-rw-r--r--source/blender/imbuf/intern/scaling.c11
-rw-r--r--source/blender/imbuf/intern/stereoimbuf.c2
-rw-r--r--source/blender/imbuf/intern/thumbs.c3
-rw-r--r--source/blender/imbuf/intern/tiff.c24
-rw-r--r--source/blender/imbuf/intern/transform.cc604
-rw-r--r--source/blender/imbuf/intern/util.c2
-rw-r--r--source/blender/imbuf/intern/util_gpu.c5
-rw-r--r--source/blender/io/alembic/exporter/abc_archive.cc2
-rw-r--r--source/blender/io/alembic/exporter/abc_subdiv_disabler.cc2
-rw-r--r--source/blender/io/alembic/exporter/abc_subdiv_disabler.h4
-rw-r--r--source/blender/io/alembic/exporter/abc_writer_points.cc2
-rw-r--r--source/blender/io/alembic/intern/abc_axis_conversion.cc4
-rw-r--r--source/blender/io/alembic/intern/abc_axis_conversion.h17
-rw-r--r--source/blender/io/alembic/intern/abc_customdata.cc26
-rw-r--r--source/blender/io/alembic/intern/abc_customdata.h8
-rw-r--r--source/blender/io/alembic/intern/abc_reader_curves.cc6
-rw-r--r--source/blender/io/alembic/intern/abc_reader_curves.h7
-rw-r--r--source/blender/io/alembic/intern/abc_reader_object.cc1
-rw-r--r--source/blender/io/alembic/intern/abc_reader_object.h1
-rw-r--r--source/blender/io/alembic/intern/abc_util.cc9
-rw-r--r--source/blender/io/alembic/intern/abc_util.h9
-rw-r--r--source/blender/io/collada/AnimationExporter.cpp27
-rw-r--r--source/blender/io/collada/AnimationExporter.h48
-rw-r--r--source/blender/io/collada/AnimationImporter.cpp29
-rw-r--r--source/blender/io/collada/AnimationImporter.h56
-rw-r--r--source/blender/io/collada/ArmatureExporter.cpp2
-rw-r--r--source/blender/io/collada/ArmatureExporter.h8
-rw-r--r--source/blender/io/collada/ArmatureImporter.cpp13
-rw-r--r--source/blender/io/collada/ArmatureImporter.h17
-rw-r--r--source/blender/io/collada/BCAnimationSampler.cpp11
-rw-r--r--source/blender/io/collada/BCAnimationSampler.h14
-rw-r--r--source/blender/io/collada/BCMath.cpp2
-rw-r--r--source/blender/io/collada/BCMath.h4
-rw-r--r--source/blender/io/collada/BCSampleData.cpp1
-rw-r--r--source/blender/io/collada/BCSampleData.h1
-rw-r--r--source/blender/io/collada/BlenderContext.cpp6
-rw-r--r--source/blender/io/collada/BlenderContext.h6
-rw-r--r--source/blender/io/collada/ControllerExporter.cpp3
-rw-r--r--source/blender/io/collada/ControllerExporter.h6
-rw-r--r--source/blender/io/collada/DocumentImporter.cpp58
-rw-r--r--source/blender/io/collada/DocumentImporter.h60
-rw-r--r--source/blender/io/collada/GeometryExporter.cpp4
-rw-r--r--source/blender/io/collada/GeometryExporter.h8
-rw-r--r--source/blender/io/collada/Materials.cpp1
-rw-r--r--source/blender/io/collada/Materials.h1
-rw-r--r--source/blender/io/collada/MeshImporter.cpp69
-rw-r--r--source/blender/io/collada/MeshImporter.h70
-rw-r--r--source/blender/io/collada/SkinInfo.cpp14
-rw-r--r--source/blender/io/collada/SkinInfo.h26
-rw-r--r--source/blender/io/collada/collada_internal.cpp1
-rw-r--r--source/blender/io/collada/collada_internal.h1
-rw-r--r--source/blender/io/collada/collada_utils.cpp68
-rw-r--r--source/blender/io/collada/collada_utils.h61
-rw-r--r--source/blender/io/gpencil/gpencil_io.h6
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_base.cc10
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_base.hh10
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_capi.cc2
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc11
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_export_pdf.hh15
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_export_svg.cc37
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_export_svg.hh41
-rw-r--r--source/blender/io/usd/intern/usd_capi_export.cc2
-rw-r--r--source/blender/io/usd/intern/usd_reader_curve.cc6
-rw-r--r--source/blender/io/usd/intern/usd_reader_material.cc10
-rw-r--r--source/blender/io/usd/intern/usd_reader_material.h16
-rw-r--r--source/blender/io/usd/intern/usd_reader_mesh.cc1
-rw-r--r--source/blender/io/usd/intern/usd_reader_mesh.h1
-rw-r--r--source/blender/io/usd/intern/usd_reader_nurbs.cc4
-rw-r--r--source/blender/io/usd/intern/usd_reader_stage.cc10
-rw-r--r--source/blender/io/usd/intern/usd_reader_stage.h14
-rw-r--r--source/blender/io/usd/intern/usd_writer_abstract.cc3
-rw-r--r--source/blender/io/usd/intern/usd_writer_abstract.h14
-rw-r--r--source/blender/makesdna/DNA_ID.h2
-rw-r--r--source/blender/makesdna/DNA_action_types.h8
-rw-r--r--source/blender/makesdna/DNA_curve_defaults.h2
-rw-r--r--source/blender/makesdna/DNA_curve_types.h13
-rw-r--r--source/blender/makesdna/DNA_defaults.h4
-rw-r--r--source/blender/makesdna/DNA_effect_types.h2
-rw-r--r--source/blender/makesdna/DNA_fileglobal_types.h2
-rw-r--r--source/blender/makesdna/DNA_genfile.h64
-rw-r--r--source/blender/makesdna/DNA_gpencil_modifier_defaults.h26
-rw-r--r--source/blender/makesdna/DNA_gpencil_modifier_types.h66
-rw-r--r--source/blender/makesdna/DNA_mesh_types.h257
-rw-r--r--source/blender/makesdna/DNA_meshdata_types.h26
-rw-r--r--source/blender/makesdna/DNA_meta_types.h4
-rw-r--r--source/blender/makesdna/DNA_modifier_defaults.h1
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h10
-rw-r--r--source/blender/makesdna/DNA_node_types.h58
-rw-r--r--source/blender/makesdna/DNA_outliner_types.h6
-rw-r--r--source/blender/makesdna/DNA_pointcache_types.h2
-rw-r--r--source/blender/makesdna/DNA_scene_defaults.h2
-rw-r--r--source/blender/makesdna/DNA_scene_types.h1
-rw-r--r--source/blender/makesdna/DNA_screen_types.h6
-rw-r--r--source/blender/makesdna/DNA_sequence_types.h3
-rw-r--r--source/blender/makesdna/DNA_space_types.h6
-rw-r--r--source/blender/makesdna/intern/dna_defaults.c8
-rw-r--r--source/blender/makesdna/intern/dna_genfile.c57
-rw-r--r--source/blender/makesdna/intern/dna_rename_defs.h30
-rw-r--r--source/blender/makesdna/intern/dna_utils.c32
-rw-r--r--source/blender/makesdna/intern/dna_utils.h17
-rw-r--r--source/blender/makesrna/RNA_access.h258
-rw-r--r--source/blender/makesrna/RNA_define.h52
-rw-r--r--source/blender/makesrna/RNA_enum_items.h6
-rw-r--r--source/blender/makesrna/RNA_enum_types.h6
-rw-r--r--source/blender/makesrna/intern/rna_access.c207
-rw-r--r--source/blender/makesrna/intern/rna_access_compare_override.c64
-rw-r--r--source/blender/makesrna/intern/rna_access_internal.h7
-rw-r--r--source/blender/makesrna/intern/rna_action.c114
-rw-r--r--source/blender/makesrna/intern/rna_armature.c4
-rw-r--r--source/blender/makesrna/intern/rna_asset.c5
-rw-r--r--source/blender/makesrna/intern/rna_constraint.c3
-rw-r--r--source/blender/makesrna/intern/rna_curve.c12
-rw-r--r--source/blender/makesrna/intern/rna_define.c36
-rw-r--r--source/blender/makesrna/intern/rna_gpencil_modifier.c259
-rw-r--r--source/blender/makesrna/intern/rna_image_api.c49
-rw-r--r--source/blender/makesrna/intern/rna_internal.h17
-rw-r--r--source/blender/makesrna/intern/rna_linestyle.c12
-rw-r--r--source/blender/makesrna/intern/rna_main.c11
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c80
-rw-r--r--source/blender/makesrna/intern/rna_nla.c4
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c262
-rw-r--r--source/blender/makesrna/intern/rna_pose.c1
-rw-r--r--source/blender/makesrna/intern/rna_rna.c2
-rw-r--r--source/blender/makesrna/intern/rna_scene.c5
-rw-r--r--source/blender/makesrna/intern/rna_sequencer.c3
-rw-r--r--source/blender/makesrna/intern/rna_space.c62
-rw-r--r--source/blender/makesrna/intern/rna_texture_api.c4
-rw-r--r--source/blender/makesrna/intern/rna_wm.c5
-rw-r--r--source/blender/modifiers/CMakeLists.txt1
-rw-r--r--source/blender/modifiers/MOD_modifiertypes.h4
-rw-r--r--source/blender/modifiers/MOD_nodes.h5
-rw-r--r--source/blender/modifiers/intern/MOD_curve.c2
-rw-r--r--source/blender/modifiers/intern/MOD_mirror.c10
-rw-r--r--source/blender/modifiers/intern/MOD_nodes.cc73
-rw-r--r--source/blender/modifiers/intern/MOD_nodes_evaluator.cc414
-rw-r--r--source/blender/modifiers/intern/MOD_solidify_extrude.c1
-rw-r--r--source/blender/modifiers/intern/MOD_solidify_nonmanifold.c14
-rw-r--r--source/blender/modifiers/intern/MOD_ui_common.c19
-rw-r--r--source/blender/modifiers/intern/MOD_ui_common.h15
-rw-r--r--source/blender/modifiers/intern/MOD_util.c6
-rw-r--r--source/blender/modifiers/intern/MOD_util.h6
-rw-r--r--source/blender/modifiers/intern/MOD_weightvg_util.c21
-rw-r--r--source/blender/modifiers/intern/MOD_weightvg_util.h30
-rw-r--r--source/blender/modifiers/intern/MOD_weld.c4
-rw-r--r--source/blender/nodes/CMakeLists.txt105
-rw-r--r--source/blender/nodes/NOD_common.h4
-rw-r--r--source/blender/nodes/NOD_derived_node_tree.hh42
-rw-r--r--source/blender/nodes/NOD_function.h2
-rw-r--r--source/blender/nodes/NOD_geometry.h16
-rw-r--r--source/blender/nodes/NOD_geometry_exec.hh56
-rw-r--r--source/blender/nodes/NOD_geometry_nodes_eval_log.hh33
-rw-r--r--source/blender/nodes/NOD_math_functions.hh10
-rw-r--r--source/blender/nodes/NOD_node_declaration.hh77
-rw-r--r--source/blender/nodes/NOD_node_tree_ref.hh7
-rw-r--r--source/blender/nodes/NOD_socket_declarations.hh68
-rw-r--r--source/blender/nodes/NOD_socket_declarations_geometry.hh7
-rw-r--r--source/blender/nodes/NOD_socket_search_link.hh151
-rw-r--r--source/blender/nodes/NOD_static_types.h16
-rw-r--r--source/blender/nodes/composite/node_composite_tree.cc14
-rw-r--r--source/blender/nodes/composite/node_composite_util.cc5
-rw-r--r--source/blender/nodes/composite/node_composite_util.hh5
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_alphaOver.cc38
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_antialiasing.cc30
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_bilateralblur.cc38
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_blur.cc67
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_bokehblur.cc36
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_bokehimage.cc21
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_boxmask.cc40
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_brightness.cc13
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_channelMatte.cc70
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_chromaMatte.cc47
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_colorMatte.cc48
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_colorSpill.cc75
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_colorbalance.cc86
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_colorcorrection.cc223
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_common.cc7
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_composite.cc12
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_cornerpin.cc46
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_crop.cc49
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc14
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_curves.cc34
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_defocus.cc73
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_denoise.cc47
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_despeckle.cc37
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_diffMatte.cc41
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_dilate.cc36
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_directionalblur.cc43
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_displace.cc33
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_distanceMatte.cc48
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_doubleEdgeMask.cc51
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_ellipsemask.cc38
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_exposure.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_filter.cc37
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_flip.cc30
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_gamma.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_glare.cc65
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_hueSatVal.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_huecorrect.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_idMask.cc12
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_image.cc68
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_inpaint.cc25
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_invert.cc15
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_keying.cc56
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_keyingscreen.cc51
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_lensdist.cc44
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_levels.cc11
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_lummaMatte.cc38
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_mapRange.cc46
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_mapUV.cc34
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_mapValue.cc49
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_mask.cc43
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_math.cc29
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_mixrgb.cc27
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_movieclip.cc52
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_moviedistortion.cc55
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_normal.cc31
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_normalize.cc17
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_outputFile.cc168
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_pixelate.cc16
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_planetrackdeform.cc75
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_posterize.cc25
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_premulkey.cc11
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_rgb.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_rotate.cc36
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_scale.cc45
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.cc4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.cc4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.cc4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.cc4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_setalpha.cc11
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_splitViewer.cc37
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_stabilize2d.cc51
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sunbeams.cc36
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_switch.cc34
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_switchview.cc22
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_texture.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_tonemap.cc30
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_trackpos.cc56
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_transform.cc45
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_translate.cc37
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_valToRgb.cc4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_value.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_vecBlur.cc46
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_viewer.cc31
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_zcombine.cc46
-rw-r--r--source/blender/nodes/function/node_function_util.cc5
-rw-r--r--source/blender/nodes/function/nodes/node_fn_boolean_math.cc7
-rw-r--r--source/blender/nodes/function/nodes/node_fn_compare.cc540
-rw-r--r--source/blender/nodes/function/nodes/node_fn_float_compare.cc121
-rw-r--r--source/blender/nodes/function/nodes/node_fn_float_to_int.cc7
-rw-r--r--source/blender/nodes/function/nodes/node_fn_random_value.cc67
-rw-r--r--source/blender/nodes/geometry/CMakeLists.txt97
-rw-r--r--source/blender/nodes/geometry/node_geometry_tree.cc11
-rw-r--r--source/blender/nodes/geometry/node_geometry_util.cc37
-rw-r--r--source/blender/nodes/geometry/node_geometry_util.hh10
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_align_rotation_to_vector.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_align_rotation_to_vector.cc)30
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_clamp.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_clamp.cc)28
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_color_ramp.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_color_ramp.cc)26
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_combine_xyz.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_combine_xyz.cc)30
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_compare.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_compare.cc)42
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_convert.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_convert.cc)28
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_curve_map.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_curve_map.cc)44
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_fill.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_fill.cc)28
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_map_range.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_map_range.cc)24
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_math.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_math.cc)35
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_mix.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_mix.cc)28
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_proximity.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_proximity.cc)28
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_randomize.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_randomize.cc)94
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_sample_texture.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_sample_texture.cc)16
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_separate_xyz.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_separate_xyz.cc)30
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_transfer.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_transfer.cc)32
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_math.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_math.cc)36
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_rotate.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_rotate.cc)30
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_endpoints.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_curve_endpoints.cc)22
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_reverse.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_curve_reverse.cc)16
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_curve_select_by_handle_type.cc)26
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_curve_set_handles.cc)26
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_curve_spline_type.cc)26
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_curve_subdivide.cc)28
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_curve_to_points.cc)126
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_delete_geometry.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_delete_geometry.cc)46
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_edge_split.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_edge_split.cc)16
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_material_assign.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_material_assign.cc)16
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_mesh_to_curve.cc)20
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_distribute.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_point_distribute.cc)32
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_instance.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_point_instance.cc)37
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_rotate.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_point_rotate.cc)28
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_scale.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_point_scale.cc)28
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_separate.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_point_separate.cc)32
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_translate.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_point_translate.cc)28
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_points_to_volume.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_points_to_volume.cc)30
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_raycast.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_raycast.cc)30
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_select_by_material.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_select_by_material.cc)16
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_subdivision_surface.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_subdivision_surface.cc)26
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_volume_to_mesh.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_volume_to_mesh.cc)26
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc96
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc155
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc172
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_boolean.cc26
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_collection_info.cc36
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_common.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc16
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc94
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc26
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc50
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc77
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_length.cc16
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc31
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc49
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc43
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc81
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc16
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc44
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc68
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc33
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc (renamed from source/blender/nodes/geometry/nodes/node_geo_curve_parameter.cc)127
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc67
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc88
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc81
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc342
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc36
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc847
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_edge_split.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_geometry_to_instance.cc55
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_image_texture.cc42
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_curve_tilt.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_id.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_index.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_material.cc18
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_material_index.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc93
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc188
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc96
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc158
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc101
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc155
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_normal.cc59
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_position.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_radius.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_scene_time.cc50
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_spline_cyclic.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc111
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_spline_resolution.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc40
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc130
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc72
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc361
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_material_replace.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_material_selection.cc65
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc37
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc183
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc106
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc64
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc66
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc140
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc16
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc16
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc47
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_object_info.cc41
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc16
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc56
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_proximity.cc32
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_raycast.cc88
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc29
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc36
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc36
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_separate_components.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc29
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc54
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc28
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc28
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_id.cc32
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_material.cc58
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc27
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc28
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_position.cc122
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc28
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc28
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc30
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_string_join.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc44
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc29
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_switch.cc79
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc112
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_transform.cc82
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc32
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_triangulate.cc20
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_viewer.cc81
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc53
-rw-r--r--source/blender/nodes/intern/derived_node_tree.cc18
-rw-r--r--source/blender/nodes/intern/extern_implementations.cc35
-rw-r--r--source/blender/nodes/intern/geometry_nodes_eval_log.cc79
-rw-r--r--source/blender/nodes/intern/math_functions.cc12
-rw-r--r--source/blender/nodes/intern/node_common.cc163
-rw-r--r--source/blender/nodes/intern/node_common.h10
-rw-r--r--source/blender/nodes/intern/node_declaration.cc8
-rw-r--r--source/blender/nodes/intern/node_exec.cc2
-rw-r--r--source/blender/nodes/intern/node_exec.h2
-rw-r--r--source/blender/nodes/intern/node_geometry_exec.cc19
-rw-r--r--source/blender/nodes/intern/node_socket.cc108
-rw-r--r--source/blender/nodes/intern/node_socket_declarations.cc184
-rw-r--r--source/blender/nodes/intern/node_tree_ref.cc8
-rw-r--r--source/blender/nodes/intern/node_util.c119
-rw-r--r--source/blender/nodes/intern/node_util.h67
-rw-r--r--source/blender/nodes/intern/socket_search_link.cc199
-rw-r--r--source/blender/nodes/shader/CMakeLists.txt166
-rw-r--r--source/blender/nodes/shader/node_shader_tree.c20
-rw-r--r--source/blender/nodes/shader/node_shader_util.cc (renamed from source/blender/nodes/shader/node_shader_util.c)46
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c9
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_clamp.cc2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_common.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_curves.cc6
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_map_range.cc397
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_math.cc25
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc (renamed from source/blender/nodes/shader/nodes/node_shader_mixRgb.cc)4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_rgb_to_bw.cc (renamed from source/blender/nodes/shader/nodes/node_shader_valToRgb.cc)4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.c (renamed from source/blender/nodes/shader/nodes/node_shader_sepcombHSV.c)0
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc (renamed from source/blender/nodes/shader/nodes/node_shader_sepcombRGB.cc)4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc (renamed from source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.cc)4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_shader_to_rgb.c (renamed from source/blender/nodes/shader/nodes/node_shader_shaderToRgb.c)0
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c12
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_brick.cc2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_checker.cc2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_environment.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_image.cc4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_magic.cc2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc23
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_noise.cc32
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc98
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_wave.cc2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc7
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_uv_along_stroke.c (renamed from source/blender/nodes/shader/nodes/node_shader_uvAlongStroke.c)0
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_value.cc2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vector_math.cc40
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vector_transform.c (renamed from source/blender/nodes/shader/nodes/node_shader_vectTransform.c)0
-rw-r--r--source/blender/nodes/texture/node_texture_util.c2
-rw-r--r--source/blender/nodes/texture/node_texture_util.h3
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_common.c4
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_distance.c1
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_image.c2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_math.c2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_mixRgb.c2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_output.c2
-rw-r--r--source/blender/python/BPY_extern.h36
-rw-r--r--source/blender/python/BPY_extern_python.h2
-rw-r--r--source/blender/python/BPY_extern_run.h130
-rw-r--r--source/blender/python/bmesh/bmesh_py_ops_call.c3
-rw-r--r--source/blender/python/bmesh/bmesh_py_ops_call.h3
-rw-r--r--source/blender/python/bmesh/bmesh_py_types.c15
-rw-r--r--source/blender/python/bmesh/bmesh_py_types.h17
-rw-r--r--source/blender/python/bmesh/bmesh_py_types_customdata.c7
-rw-r--r--source/blender/python/bmesh/bmesh_py_types_customdata.h15
-rw-r--r--source/blender/python/bmesh/bmesh_py_types_meshdata.c1
-rw-r--r--source/blender/python/bmesh/bmesh_py_types_meshdata.h1
-rw-r--r--source/blender/python/bmesh/bmesh_py_types_select.c3
-rw-r--r--source/blender/python/bmesh/bmesh_py_types_select.h3
-rw-r--r--source/blender/python/generic/bgl.c7
-rw-r--r--source/blender/python/generic/bgl.h9
-rw-r--r--source/blender/python/generic/bpy_threads.c2
-rw-r--r--source/blender/python/generic/idprop_py_api.c9
-rw-r--r--source/blender/python/generic/idprop_py_api.h9
-rw-r--r--source/blender/python/generic/py_capi_rna.c24
-rw-r--r--source/blender/python/generic/py_capi_rna.h24
-rw-r--r--source/blender/python/generic/py_capi_utils.c72
-rw-r--r--source/blender/python/generic/py_capi_utils.h86
-rw-r--r--source/blender/python/generic/python_utildefines.h12
-rw-r--r--source/blender/python/gpu/gpu_py.c1
-rw-r--r--source/blender/python/gpu/gpu_py_buffer.c7
-rw-r--r--source/blender/python/gpu/gpu_py_buffer.h7
-rw-r--r--source/blender/python/gpu/gpu_py_offscreen.c21
-rw-r--r--source/blender/python/gpu/gpu_py_offscreen.h4
-rw-r--r--source/blender/python/gpu/gpu_py_select.c1
-rw-r--r--source/blender/python/gpu/gpu_py_texture.c1
-rw-r--r--source/blender/python/intern/bpy.c27
-rw-r--r--source/blender/python/intern/bpy.h2
-rw-r--r--source/blender/python/intern/bpy_app_translations.c4
-rw-r--r--source/blender/python/intern/bpy_capi_utils.c3
-rw-r--r--source/blender/python/intern/bpy_capi_utils.h6
-rw-r--r--source/blender/python/intern/bpy_driver.c42
-rw-r--r--source/blender/python/intern/bpy_driver.h8
-rw-r--r--source/blender/python/intern/bpy_interface.c23
-rw-r--r--source/blender/python/intern/bpy_interface_run.c32
-rw-r--r--source/blender/python/intern/bpy_library_load.c249
-rw-r--r--source/blender/python/intern/bpy_operator_wrap.c8
-rw-r--r--source/blender/python/intern/bpy_operator_wrap.h8
-rw-r--r--source/blender/python/intern/bpy_props.c18
-rw-r--r--source/blender/python/intern/bpy_props.h4
-rw-r--r--source/blender/python/intern/bpy_rna.c16
-rw-r--r--source/blender/python/intern/bpy_rna_anim.c4
-rw-r--r--source/blender/python/intern/bpy_rna_array.c3
-rw-r--r--source/blender/python/intern/bpy_rna_data.c2
-rw-r--r--source/blender/python/intern/bpy_rna_driver.c3
-rw-r--r--source/blender/python/intern/bpy_rna_driver.h3
-rw-r--r--source/blender/python/mathutils/mathutils.c17
-rw-r--r--source/blender/python/mathutils/mathutils.h40
-rw-r--r--source/blender/python/mathutils/mathutils_Matrix.c3
-rw-r--r--source/blender/python/mathutils/mathutils_Matrix.h3
-rw-r--r--source/blender/python/mathutils/mathutils_Vector.c23
-rw-r--r--source/blender/python/mathutils/mathutils_Vector.h12
-rw-r--r--source/blender/render/RE_bake.h4
-rw-r--r--source/blender/render/RE_engine.h4
-rw-r--r--source/blender/render/RE_pipeline.h145
-rw-r--r--source/blender/render/RE_texture.h55
-rw-r--r--source/blender/render/intern/bake.c4
-rw-r--r--source/blender/render/intern/engine.c1
-rw-r--r--source/blender/render/intern/initrender.c8
-rw-r--r--source/blender/render/intern/pipeline.c38
-rw-r--r--source/blender/render/intern/pipeline.h4
-rw-r--r--source/blender/render/intern/render_result.c19
-rw-r--r--source/blender/render/intern/render_result.h37
-rw-r--r--source/blender/render/intern/texture_pointdensity.c3
-rw-r--r--source/blender/render/intern/texture_procedural.c21
-rw-r--r--source/blender/render/intern/zbuf.c4
-rw-r--r--source/blender/render/intern/zbuf.h7
-rw-r--r--source/blender/sequencer/SEQ_add.h99
-rw-r--r--source/blender/sequencer/SEQ_clipboard.h7
-rw-r--r--source/blender/sequencer/SEQ_edit.h44
-rw-r--r--source/blender/sequencer/SEQ_iterator.h154
-rw-r--r--source/blender/sequencer/SEQ_prefetch.h4
-rw-r--r--source/blender/sequencer/SEQ_relations.h22
-rw-r--r--source/blender/sequencer/SEQ_render.h18
-rw-r--r--source/blender/sequencer/SEQ_sequencer.h64
-rw-r--r--source/blender/sequencer/SEQ_time.h28
-rw-r--r--source/blender/sequencer/SEQ_transform.h47
-rw-r--r--source/blender/sequencer/SEQ_utils.h21
-rw-r--r--source/blender/sequencer/intern/clipboard.c7
-rw-r--r--source/blender/sequencer/intern/disk_cache.c2
-rw-r--r--source/blender/sequencer/intern/effects.c3
-rw-r--r--source/blender/sequencer/intern/effects.h7
-rw-r--r--source/blender/sequencer/intern/image_cache.c3
-rw-r--r--source/blender/sequencer/intern/image_cache.h4
-rw-r--r--source/blender/sequencer/intern/iterator.c161
-rw-r--r--source/blender/sequencer/intern/modifier.c1
-rw-r--r--source/blender/sequencer/intern/multiview.c1
-rw-r--r--source/blender/sequencer/intern/multiview.h3
-rw-r--r--source/blender/sequencer/intern/prefetch.c6
-rw-r--r--source/blender/sequencer/intern/prefetch.h9
-rw-r--r--source/blender/sequencer/intern/proxy.c21
-rw-r--r--source/blender/sequencer/intern/render.c49
-rw-r--r--source/blender/sequencer/intern/sequence_lookup.c21
-rw-r--r--source/blender/sequencer/intern/sequencer.c42
-rw-r--r--source/blender/sequencer/intern/sequencer.h4
-rw-r--r--source/blender/sequencer/intern/strip_add.c100
-rw-r--r--source/blender/sequencer/intern/strip_edit.c38
-rw-r--r--source/blender/sequencer/intern/strip_relations.c31
-rw-r--r--source/blender/sequencer/intern/strip_time.c36
-rw-r--r--source/blender/sequencer/intern/strip_time.h9
-rw-r--r--source/blender/sequencer/intern/strip_transform.c46
-rw-r--r--source/blender/sequencer/intern/utils.c23
-rw-r--r--source/blender/shader_fx/intern/FX_ui_common.c17
-rw-r--r--source/blender/shader_fx/intern/FX_ui_common.h15
-rw-r--r--source/blender/simulation/intern/ConstrainedConjugateGradient.h6
-rw-r--r--source/blender/simulation/intern/hair_volume.cpp6
-rw-r--r--source/blender/simulation/intern/implicit.h65
-rw-r--r--source/blender/simulation/intern/implicit_blender.c16
-rw-r--r--source/blender/windowmanager/WM_api.h613
-rw-r--r--source/blender/windowmanager/WM_keymap.h32
-rw-r--r--source/blender/windowmanager/WM_toolsystem.h21
-rw-r--r--source/blender/windowmanager/WM_types.h6
-rw-r--r--source/blender/windowmanager/gizmo/WM_gizmo_api.h121
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo.c45
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c30
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_group_type.c6
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_intern.h20
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c35
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c7
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_type.c5
-rw-r--r--source/blender/windowmanager/gizmo/wm_gizmo_wmapi.h42
-rw-r--r--source/blender/windowmanager/intern/wm.c17
-rw-r--r--source/blender/windowmanager/intern/wm_cursors.c8
-rw-r--r--source/blender/windowmanager/intern/wm_dragdrop.c43
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c1
-rw-r--r--source/blender/windowmanager/intern/wm_event_query.c24
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c102
-rw-r--r--source/blender/windowmanager/intern/wm_files.c166
-rw-r--r--source/blender/windowmanager/intern/wm_files_link.c1262
-rw-r--r--source/blender/windowmanager/intern/wm_gesture.c3
-rw-r--r--source/blender/windowmanager/intern/wm_gesture_ops.c23
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c25
-rw-r--r--source/blender/windowmanager/intern/wm_jobs.c18
-rw-r--r--source/blender/windowmanager/intern/wm_keymap.c13
-rw-r--r--source/blender/windowmanager/intern/wm_keymap_utils.c5
-rw-r--r--source/blender/windowmanager/intern/wm_menu_type.c1
-rw-r--r--source/blender/windowmanager/intern/wm_operator_props.c53
-rw-r--r--source/blender/windowmanager/intern/wm_operator_type.c33
-rw-r--r--source/blender/windowmanager/intern/wm_operator_utils.c7
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c73
-rw-r--r--source/blender/windowmanager/intern/wm_panel_type.c1
-rw-r--r--source/blender/windowmanager/intern/wm_stereo.c4
-rw-r--r--source/blender/windowmanager/intern/wm_subwindow.c1
-rw-r--r--source/blender/windowmanager/intern/wm_surface.c18
-rw-r--r--source/blender/windowmanager/intern/wm_toolsystem.c19
-rw-r--r--source/blender/windowmanager/intern/wm_uilist_type.c16
-rw-r--r--source/blender/windowmanager/intern/wm_window.c100
-rw-r--r--source/blender/windowmanager/message_bus/intern/wm_message_bus.c13
-rw-r--r--source/blender/windowmanager/message_bus/intern/wm_message_bus_intern.h3
-rw-r--r--source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c10
-rw-r--r--source/blender/windowmanager/message_bus/wm_message_bus.h12
-rw-r--r--source/blender/windowmanager/wm.h53
-rw-r--r--source/blender/windowmanager/wm_event_system.h41
-rw-r--r--source/blender/windowmanager/wm_event_types.h2
-rw-r--r--source/blender/windowmanager/wm_files.h23
-rw-r--r--source/blender/windowmanager/wm_surface.h5
-rw-r--r--source/blender/windowmanager/wm_window.h63
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_actionmap.c45
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_draw.c6
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_intern.h12
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_operators.c2
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_session.c47
-rw-r--r--source/creator/creator.c5
-rw-r--r--source/creator/creator_args.c4
-rw-r--r--source/creator/creator_signals.c9
m---------source/tools0
-rw-r--r--tests/python/CMakeLists.txt2
-rw-r--r--tests/python/bl_pyapi_idprop_datablock.py4
-rw-r--r--tests/python/modules/mesh_test.py62
-rw-r--r--tests/python/operators.py122
2336 files changed, 67469 insertions, 39780 deletions
diff --git a/.clang-tidy b/.clang-tidy
index b03163b54b9..1cc0e6e7f4a 100644
--- a/.clang-tidy
+++ b/.clang-tidy
@@ -12,6 +12,8 @@ Checks: >
-readability-avoid-const-params-in-decls,
-readability-simplify-boolean-expr,
-readability-make-member-function-const,
+ -readability-suspicious-call-argument,
+ -readability-redundant-member-init,
-readability-misleading-indentation,
@@ -25,6 +27,8 @@ Checks: >
-bugprone-branch-clone,
-bugprone-macro-parentheses,
-bugprone-reserved-identifier,
+ -bugprone-easily-swappable-parameters,
+ -bugprone-implicit-widening-of-multiplication-result,
-bugprone-sizeof-expression,
-bugprone-integer-division,
@@ -40,7 +44,8 @@ Checks: >
-modernize-pass-by-value,
# Cannot be enabled yet, because using raw string literals in tests breaks
# the windows compiler currently.
- -modernize-raw-string-literal
+ -modernize-raw-string-literal,
+ -modernize-return-braced-init-list
CheckOptions:
- key: modernize-use-default-member-init.UseAssignment
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a9c29101123..5c5b5eb317e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -187,6 +187,13 @@ mark_as_advanced(CPACK_OVERRIDE_PACKAGENAME)
mark_as_advanced(BUILDINFO_OVERRIDE_DATE)
mark_as_advanced(BUILDINFO_OVERRIDE_TIME)
+if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.16")
+ option(WITH_UNITY_BUILD "Enable unity build for modules that support it to improve compile times" ON)
+ mark_as_advanced(WITH_UNITY_BUILD)
+else()
+ set(WITH_UNITY_BUILD OFF)
+endif()
+
option(WITH_IK_ITASC "Enable ITASC IK solver (only disable for development & for incompatible C++ compilers)" ON)
option(WITH_IK_SOLVER "Enable Legacy IK solver (only disable for development)" ON)
option(WITH_FFTW3 "Enable FFTW3 support (Used for smoke, ocean sim, and audio effects)" ON)
@@ -426,30 +433,40 @@ mark_as_advanced(WITH_CYCLES_DEBUG_NAN)
mark_as_advanced(WITH_CYCLES_NATIVE_ONLY)
# NVIDIA CUDA & OptiX
-option(WITH_CYCLES_DEVICE_CUDA "Enable Cycles NVIDIA CUDA compute support" ON)
-option(WITH_CYCLES_DEVICE_OPTIX "Enable Cycles NVIDIA OptiX support" ON)
-mark_as_advanced(WITH_CYCLES_DEVICE_CUDA)
-
-option(WITH_CYCLES_CUDA_BINARIES "Build Cycles NVIDIA CUDA binaries" OFF)
-set(CYCLES_CUDA_BINARIES_ARCH sm_30 sm_35 sm_37 sm_50 sm_52 sm_60 sm_61 sm_70 sm_75 sm_86 compute_75 CACHE STRING "CUDA architectures to build binaries for")
-option(WITH_CYCLES_CUBIN_COMPILER "Build cubins with nvrtc based compiler instead of nvcc" OFF)
-option(WITH_CYCLES_CUDA_BUILD_SERIAL "Build cubins one after another (useful on machines with limited RAM)" OFF)
-option(WITH_CUDA_DYNLOAD "Dynamically load CUDA libraries at runtime (for developers, makes cuda-gdb work)" ON)
-mark_as_advanced(CYCLES_CUDA_BINARIES_ARCH)
-mark_as_advanced(WITH_CYCLES_CUBIN_COMPILER)
-mark_as_advanced(WITH_CYCLES_CUDA_BUILD_SERIAL)
-mark_as_advanced(WITH_CUDA_DYNLOAD)
+if(NOT APPLE)
+ option(WITH_CYCLES_DEVICE_CUDA "Enable Cycles NVIDIA CUDA compute support" ON)
+ option(WITH_CYCLES_DEVICE_OPTIX "Enable Cycles NVIDIA OptiX support" ON)
+ mark_as_advanced(WITH_CYCLES_DEVICE_CUDA)
+
+ option(WITH_CYCLES_CUDA_BINARIES "Build Cycles NVIDIA CUDA binaries" OFF)
+ set(CYCLES_CUDA_BINARIES_ARCH sm_30 sm_35 sm_37 sm_50 sm_52 sm_60 sm_61 sm_70 sm_75 sm_86 compute_75 CACHE STRING "CUDA architectures to build binaries for")
+ option(WITH_CYCLES_CUBIN_COMPILER "Build cubins with nvrtc based compiler instead of nvcc" OFF)
+ option(WITH_CYCLES_CUDA_BUILD_SERIAL "Build cubins one after another (useful on machines with limited RAM)" OFF)
+ option(WITH_CUDA_DYNLOAD "Dynamically load CUDA libraries at runtime (for developers, makes cuda-gdb work)" ON)
+ mark_as_advanced(CYCLES_CUDA_BINARIES_ARCH)
+ mark_as_advanced(WITH_CYCLES_CUBIN_COMPILER)
+ mark_as_advanced(WITH_CYCLES_CUDA_BUILD_SERIAL)
+ mark_as_advanced(WITH_CUDA_DYNLOAD)
+endif()
# AMD HIP
-if(WIN32)
- option(WITH_CYCLES_DEVICE_HIP "Enable Cycles AMD HIP support" ON)
-else()
- option(WITH_CYCLES_DEVICE_HIP "Enable Cycles AMD HIP support" OFF)
+if(NOT APPLE)
+ if(WIN32)
+ option(WITH_CYCLES_DEVICE_HIP "Enable Cycles AMD HIP support" ON)
+ else()
+ option(WITH_CYCLES_DEVICE_HIP "Enable Cycles AMD HIP support" OFF)
+ endif()
+
+ option(WITH_CYCLES_HIP_BINARIES "Build Cycles AMD HIP binaries" OFF)
+ set(CYCLES_HIP_BINARIES_ARCH gfx1010 gfx1011 gfx1012 gfx1030 gfx1031 gfx1032 gfx1034 CACHE STRING "AMD HIP architectures to build binaries for")
+ mark_as_advanced(WITH_CYCLES_DEVICE_HIP)
+ mark_as_advanced(CYCLES_HIP_BINARIES_ARCH)
+endif()
+
+# Apple Metal
+if(APPLE)
+ option(WITH_CYCLES_DEVICE_METAL "Enable Cycles Apple Metal compute support" ON)
endif()
-option(WITH_CYCLES_HIP_BINARIES "Build Cycles AMD HIP binaries" OFF)
-set(CYCLES_HIP_BINARIES_ARCH gfx1010 gfx1011 gfx1012 gfx1030 gfx1031 gfx1032 gfx1034 CACHE STRING "AMD HIP architectures to build binaries for")
-mark_as_advanced(WITH_CYCLES_DEVICE_HIP)
-mark_as_advanced(CYCLES_HIP_BINARIES_ARCH)
# Draw Manager
option(WITH_DRAW_DEBUG "Add extra debug capabilities to Draw Manager" OFF)
@@ -494,11 +511,10 @@ if(WIN32)
endif()
# This should be turned off when Blender enter beta/rc/release
-if("${BLENDER_VERSION_CYCLE}" STREQUAL "release" OR
- "${BLENDER_VERSION_CYCLE}" STREQUAL "rc")
- set(WITH_EXPERIMENTAL_FEATURES OFF)
-else()
+if("${BLENDER_VERSION_CYCLE}" STREQUAL "alpha")
set(WITH_EXPERIMENTAL_FEATURES ON)
+else()
+ set(WITH_EXPERIMENTAL_FEATURES OFF)
endif()
# Unit testsing
@@ -840,7 +856,7 @@ if(WITH_AUDASPACE)
endif()
# Auto-enable CUDA dynload if toolkit is not found.
-if(NOT WITH_CUDA_DYNLOAD)
+if(WITH_CYCLES AND WITH_CYCLES_DEVICE_CUDA AND NOT WITH_CUDA_DYNLOAD)
find_package(CUDA)
if(NOT CUDA_FOUND)
message(STATUS "CUDA toolkit not found, using dynamic runtime loading of libraries (WITH_CUDA_DYNLOAD) instead")
diff --git a/build_files/cmake/config/blender_lite.cmake b/build_files/cmake/config/blender_lite.cmake
index 89bd46ecd7d..d7ba48050eb 100644
--- a/build_files/cmake/config/blender_lite.cmake
+++ b/build_files/cmake/config/blender_lite.cmake
@@ -19,9 +19,6 @@ set(WITH_CODEC_SNDFILE OFF CACHE BOOL "" FORCE)
set(WITH_COMPOSITOR OFF CACHE BOOL "" FORCE)
set(WITH_COREAUDIO OFF CACHE BOOL "" FORCE)
set(WITH_CYCLES OFF CACHE BOOL "" FORCE)
-set(WITH_CYCLES_DEVICE_OPTIX OFF CACHE BOOL "" FORCE)
-set(WITH_CYCLES_EMBREE OFF CACHE BOOL "" FORCE)
-set(WITH_CYCLES_OSL OFF CACHE BOOL "" FORCE)
set(WITH_DRACO OFF CACHE BOOL "" FORCE)
set(WITH_FFTW3 OFF CACHE BOOL "" FORCE)
set(WITH_FREESTYLE OFF CACHE BOOL "" FORCE)
diff --git a/build_files/cmake/config/blender_release.cmake b/build_files/cmake/config/blender_release.cmake
index 04074db688d..da8724071b7 100644
--- a/build_files/cmake/config/blender_release.cmake
+++ b/build_files/cmake/config/blender_release.cmake
@@ -61,6 +61,7 @@ set(WITH_MEM_JEMALLOC ON CACHE BOOL "" FORCE)
# platform dependent options
if(APPLE)
set(WITH_COREAUDIO ON CACHE BOOL "" FORCE)
+ set(WITH_CYCLES_DEVICE_METAL ON CACHE BOOL "" FORCE)
endif()
if(NOT WIN32)
set(WITH_JACK ON CACHE BOOL "" FORCE)
diff --git a/build_files/cmake/platform/platform_apple.cmake b/build_files/cmake/platform/platform_apple.cmake
index 2bfdc84ec2a..15bd02230c3 100644
--- a/build_files/cmake/platform/platform_apple.cmake
+++ b/build_files/cmake/platform/platform_apple.cmake
@@ -257,9 +257,6 @@ if(WITH_BOOST)
if(WITH_INTERNATIONAL)
list(APPEND _boost_FIND_COMPONENTS locale)
endif()
- if(WITH_CYCLES_NETWORK)
- list(APPEND _boost_FIND_COMPONENTS serialization)
- endif()
if(WITH_OPENVDB)
list(APPEND _boost_FIND_COMPONENTS iostreams)
endif()
@@ -339,7 +336,7 @@ if(WITH_LLVM)
endif()
-if(WITH_CYCLES_OSL)
+if(WITH_CYCLES AND WITH_CYCLES_OSL)
set(CYCLES_OSL ${LIBDIR}/osl)
find_library(OSL_LIB_EXEC NAMES oslexec PATHS ${CYCLES_OSL}/lib)
@@ -359,7 +356,7 @@ if(WITH_CYCLES_OSL)
endif()
endif()
-if(WITH_CYCLES_EMBREE)
+if(WITH_CYCLES AND WITH_CYCLES_EMBREE)
find_package(Embree 3.8.0 REQUIRED)
# Increase stack size for Embree, only works for executables.
if(NOT WITH_PYTHON_MODULE)
diff --git a/build_files/cmake/platform/platform_unix.cmake b/build_files/cmake/platform/platform_unix.cmake
index fc0c37e4c8b..2f1a622c63d 100644
--- a/build_files/cmake/platform/platform_unix.cmake
+++ b/build_files/cmake/platform/platform_unix.cmake
@@ -241,7 +241,7 @@ if(WITH_INPUT_NDOF)
endif()
endif()
-if(WITH_CYCLES_OSL)
+if(WITH_CYCLES AND WITH_CYCLES_OSL)
set(CYCLES_OSL ${LIBDIR}/osl CACHE PATH "Path to OpenShadingLanguage installation")
if(EXISTS ${CYCLES_OSL} AND NOT OSL_ROOT)
set(OSL_ROOT ${CYCLES_OSL})
@@ -314,7 +314,7 @@ if(WITH_BOOST)
endif()
set(Boost_USE_MULTITHREADED ON)
set(__boost_packages filesystem regex thread date_time)
- if(WITH_CYCLES_OSL)
+ if(WITH_CYCLES AND WITH_CYCLES_OSL)
if(NOT (${OSL_LIBRARY_VERSION_MAJOR} EQUAL "1" AND ${OSL_LIBRARY_VERSION_MINOR} LESS "6"))
list(APPEND __boost_packages wave)
else()
@@ -323,9 +323,6 @@ if(WITH_BOOST)
if(WITH_INTERNATIONAL)
list(APPEND __boost_packages locale)
endif()
- if(WITH_CYCLES_NETWORK)
- list(APPEND __boost_packages serialization)
- endif()
if(WITH_OPENVDB)
list(APPEND __boost_packages iostreams)
endif()
@@ -403,7 +400,7 @@ if(WITH_OPENCOLORIO)
endif()
endif()
-if(WITH_CYCLES_EMBREE)
+if(WITH_CYCLES AND WITH_CYCLES_EMBREE)
find_package(Embree 3.8.0 REQUIRED)
endif()
diff --git a/build_files/cmake/platform/platform_win32.cmake b/build_files/cmake/platform/platform_win32.cmake
index e83eba74fc0..851dafc34fb 100644
--- a/build_files/cmake/platform/platform_win32.cmake
+++ b/build_files/cmake/platform/platform_win32.cmake
@@ -477,7 +477,7 @@ if(WITH_PYTHON)
endif()
if(WITH_BOOST)
- if(WITH_CYCLES_OSL)
+ if(WITH_CYCLES AND WITH_CYCLES_OSL)
set(boost_extra_libs wave)
endif()
if(WITH_INTERNATIONAL)
@@ -520,7 +520,7 @@ if(WITH_BOOST)
debug ${BOOST_LIBPATH}/libboost_thread-${BOOST_DEBUG_POSTFIX}
debug ${BOOST_LIBPATH}/libboost_chrono-${BOOST_DEBUG_POSTFIX}
)
- if(WITH_CYCLES_OSL)
+ if(WITH_CYCLES AND WITH_CYCLES_OSL)
set(BOOST_LIBRARIES ${BOOST_LIBRARIES}
optimized ${BOOST_LIBPATH}/libboost_wave-${BOOST_POSTFIX}
debug ${BOOST_LIBPATH}/libboost_wave-${BOOST_DEBUG_POSTFIX})
@@ -708,7 +708,7 @@ if(WITH_CODEC_SNDFILE)
set(LIBSNDFILE_LIBRARIES ${LIBSNDFILE_LIBPATH}/libsndfile-1.lib)
endif()
-if(WITH_CYCLES_OSL)
+if(WITH_CYCLES AND WITH_CYCLES_OSL)
set(CYCLES_OSL ${LIBDIR}/osl CACHE PATH "Path to OpenShadingLanguage installation")
set(OSL_SHADER_DIR ${CYCLES_OSL}/shaders)
# Shaders have moved around a bit between OSL versions, check multiple locations
@@ -741,7 +741,7 @@ if(WITH_CYCLES_OSL)
endif()
endif()
-if(WITH_CYCLES_EMBREE)
+if(WITH_CYCLES AND WITH_CYCLES_EMBREE)
windows_find_package(Embree)
if(NOT EMBREE_FOUND)
set(EMBREE_INCLUDE_DIRS ${LIBDIR}/embree/include)
diff --git a/doc/doxygen/doxygen.intern.h b/doc/doxygen/doxygen.intern.h
index b08b868a7e3..b6145e22a90 100644
--- a/doc/doxygen/doxygen.intern.h
+++ b/doc/doxygen/doxygen.intern.h
@@ -6,91 +6,90 @@
* as part of the normal development process.
*/
-/** \defgroup MEM Guarded memory (de)allocation
- * \ingroup intern
+/* TODO: other modules.
+ * - `libmv`
+ * - `cycles`
+ * - `opencolorio`
+ * - `opensubdiv`
+ * - `openvdb`
+ * - `quadriflow`
*/
-/** \defgroup clog C-Logging (CLOG)
- * \ingroup intern
- */
+/** \defgroup intern_atomic Atomic Operations
+ * \ingroup intern */
-/** \defgroup ctr container
- * \ingroup intern
- */
+/** \defgroup intern_clog C-Logging (CLOG)
+ * \ingroup intern */
-/** \defgroup iksolver iksolver
- * \ingroup intern
- */
+/** \defgroup intern_eigen Eigen
+ * \ingroup intern */
-/** \defgroup itasc itasc
- * \ingroup intern
- */
+/** \defgroup intern_glew-mx GLEW with Multiple Rendering Context's
+ * \ingroup intern */
-/** \defgroup memutil memutil
- * \ingroup intern
- */
+/** \defgroup intern_iksolver Inverse Kinematics (Solver)
+ * \ingroup intern */
-/** \defgroup mikktspace mikktspace
- * \ingroup intern
- */
+/** \defgroup intern_itasc Inverse Kinematics (ITASC)
+ * \ingroup intern */
-/** \defgroup moto moto
- * \ingroup intern
- */
+/** \defgroup intern_libc_compat libc Compatibility For Linux
+ * \ingroup intern */
-/** \defgroup eigen eigen
- * \ingroup intern
- */
+/** \defgroup intern_locale Locale
+ * \ingroup intern */
-/** \defgroup smoke smoke
- * \ingroup intern
- */
+/** \defgroup intern_mantaflow Manta-Flow Fluid Simulation
+ * \ingroup intern */
-/** \defgroup string string
- * \ingroup intern
- */
+/** \defgroup intern_mem Guarded Memory (de)allocation
+ * \ingroup intern */
+
+/** \defgroup intern_memutil Memory Utilities (memutil)
+ * \ingroup intern */
+
+/** \defgroup intern_mikktspace MikktSpace
+ * \ingroup intern */
+
+/** \defgroup intern_numaapi NUMA (Non Uniform Memory Architecture)
+ * \ingroup intern */
+
+/** \defgroup intern_rigidbody Rigid-Body C-API
+ * \ingroup intern */
+
+/** \defgroup intern_sky_model Sky Model
+ * \ingroup intern */
+
+/** \defgroup intern_utf_conv UTF-8/16 Conversion (utfconv)
+ * \ingroup intern */
/** \defgroup audaspace Audaspace
* \ingroup intern undoc
- * \todo add to doxygen
- */
+ * \todo add to doxygen */
/** \defgroup audcoreaudio Audaspace CoreAudio
- * \ingroup audaspace
- */
+ * \ingroup audaspace */
/** \defgroup audfx Audaspace FX
- * \ingroup audaspace
- */
+ * \ingroup audaspace */
/** \defgroup audopenal Audaspace OpenAL
- * \ingroup audaspace
- */
+ * \ingroup audaspace */
/** \defgroup audpulseaudio Audaspace PulseAudio
- * \ingroup audaspace
- */
+ * \ingroup audaspace */
/** \defgroup audwasapi Audaspace WASAPI
- * \ingroup audaspace
- */
+ * \ingroup audaspace */
/** \defgroup audpython Audaspace Python
- * \ingroup audaspace
- */
+ * \ingroup audaspace */
/** \defgroup audsdl Audaspace SDL
- * \ingroup audaspace
- */
+ * \ingroup audaspace */
/** \defgroup audsrc Audaspace SRC
- *
- * \ingroup audaspace
- */
+ * \ingroup audaspace */
/** \defgroup audffmpeg Audaspace FFMpeg
- * \ingroup audaspace
- */
+ * \ingroup audaspace */
/** \defgroup audfftw Audaspace FFTW
- * \ingroup audaspace
- */
+ * \ingroup audaspace */
/** \defgroup audjack Audaspace Jack
- * \ingroup audaspace
- */
+ * \ingroup audaspace */
/** \defgroup audsndfile Audaspace sndfile
- * \ingroup audaspace
- */
+ * \ingroup audaspace */
/** \defgroup GHOST GHOST API
* \ingroup intern GUI
diff --git a/doc/doxygen/doxygen.source.h b/doc/doxygen/doxygen.source.h
index 510f3fe8ffe..4e351c9cc04 100644
--- a/doc/doxygen/doxygen.source.h
+++ b/doc/doxygen/doxygen.source.h
@@ -5,7 +5,8 @@
/** \defgroup bmesh BMesh
* \ingroup blender
*/
-/** \defgroup compositor Compositing */
+/** \defgroup compositor Compositing
+ * \ingroup blender */
/** \defgroup python Python
* \ingroup blender
@@ -78,7 +79,8 @@
* \ingroup blender
*/
-/** \defgroup data DNA, RNA and .blend access*/
+/** \defgroup data DNA, RNA and .blend access
+ * \ingroup blender */
/** \defgroup gpu GPU
* \ingroup blender
@@ -101,11 +103,12 @@
* merged in docs.
*/
-/** \defgroup gui GUI */
+/**
+ * \defgroup gui GUI
+ * \ingroup blender */
/** \defgroup wm Window Manager
- * \ingroup blender gui
- */
+ * \ingroup gui */
/* ================================ */
@@ -279,7 +282,8 @@
* \ingroup gui
*/
-/** \defgroup externformats External Formats */
+/** \defgroup externformats External Formats
+ * \ingroup blender */
/** \defgroup collada COLLADA
* \ingroup externformats
@@ -308,4 +312,7 @@
/* ================================ */
/** \defgroup undoc Undocumented
- * \brief Modules and libraries that are still undocumented, or lacking proper integration into the doxygen system, are marked in this group. */
+ *
+ * \brief Modules and libraries that are still undocumented,
+ * or lacking proper integration into the doxygen system, are marked in this group.
+ */
diff --git a/doc/manpage/blender.1.py b/doc/manpage/blender.1.py
index 020bab05a21..5e7226d7d4c 100755
--- a/doc/manpage/blender.1.py
+++ b/doc/manpage/blender.1.py
@@ -61,7 +61,7 @@ def blender_extract_info(blender_bin: str) -> Dict[str, str]:
stdout=subprocess.PIPE,
).stdout.decode(encoding="utf-8")
- blender_version_ouput = subprocess.run(
+ blender_version_output = subprocess.run(
[blender_bin, "--version"],
env=blender_env,
check=True,
@@ -73,7 +73,7 @@ def blender_extract_info(blender_bin: str) -> Dict[str, str]:
# check for each lines prefix to ensure these aren't included.
blender_version = ""
blender_date = ""
- for l in blender_version_ouput.split("\n"):
+ for l in blender_version_output.split("\n"):
if l.startswith("Blender "):
# Remove 'Blender' prefix.
blender_version = l.split(" ", 1)[1].strip()
diff --git a/doc/python_api/rst/bgl.rst b/doc/python_api/rst/bgl.rst
index fd6366494e3..2369a422396 100644
--- a/doc/python_api/rst/bgl.rst
+++ b/doc/python_api/rst/bgl.rst
@@ -106,24 +106,6 @@ including advanced features.
floating-point values. These values are interpreted as a plane equation.
-.. function:: glColor (red, green, blue, alpha):
-
- B{glColor3b, glColor3d, glColor3f, glColor3i, glColor3s, glColor3ub, glColor3ui, glColor3us,
- glColor4b, glColor4d, glColor4f, glColor4i, glColor4s, glColor4ub, glColor4ui, glColor4us,
- glColor3bv, glColor3dv, glColor3fv, glColor3iv, glColor3sv, glColor3ubv, glColor3uiv,
- glColor3usv, glColor4bv, glColor4dv, glColor4fv, glColor4iv, glColor4sv, glColor4ubv,
- glColor4uiv, glColor4usv}
-
- Set a new color.
-
- .. seealso:: `OpenGL Docs <https://khronos.org/registry/OpenGL-Refpages/gl4/html/glColor.xhtml>`__
-
- :type red, green, blue, alpha: Depends on function prototype.
- :arg red, green, blue: Specify new red, green, and blue values for the current color.
- :arg alpha: Specifies a new alpha value for the current color. Included only in the
- four-argument glColor4 commands. (With '4' colors only)
-
-
.. function:: glColorMask(red, green, blue, alpha):
Enable and disable writing of frame buffer color components
diff --git a/doc/python_api/sphinx_doc_gen.py b/doc/python_api/sphinx_doc_gen.py
index 7e2be8ddf75..fda47194be0 100644
--- a/doc/python_api/sphinx_doc_gen.py
+++ b/doc/python_api/sphinx_doc_gen.py
@@ -1103,6 +1103,7 @@ context_type_map = {
"selectable_objects": ("Object", True),
"selected_asset_files": ("FileSelectEntry", True),
"selected_bones": ("EditBone", True),
+ "selected_editable_actions": ("Action", True),
"selected_editable_bones": ("EditBone", True),
"selected_editable_fcurves": ("FCurve", True),
"selected_editable_keyframes": ("Keyframe", True),
@@ -1118,12 +1119,13 @@ context_type_map = {
"selected_pose_bones": ("PoseBone", True),
"selected_pose_bones_from_active_object": ("PoseBone", True),
"selected_sequences": ("Sequence", True),
+ "selected_visible_actions": ("Action", True),
"selected_visible_fcurves": ("FCurve", True),
"sequences": ("Sequence", True),
"soft_body": ("SoftBodyModifier", False),
"speaker": ("Speaker", False),
"texture": ("Texture", False),
- "texture_slot": ("MaterialTextureSlot", False),
+ "texture_slot": ("TextureSlot", False),
"texture_user": ("ID", False),
"texture_user_property": ("Property", False),
"ui_list": ("UIList", False),
diff --git a/extern/hipew/README b/extern/hipew/README
new file mode 100644
index 00000000000..cdb34f9a359
--- /dev/null
+++ b/extern/hipew/README
@@ -0,0 +1,12 @@
+The HIP Extension Wrangler Library (HIPEW) is a cross-platform open-source
+C/C++ library to dynamically load the HIP library.
+
+HIP (Heterogeneous-Compute Interface for Portability) is an API for C++
+programming on AMD GPUs.
+
+It is maintained as part of the Blender project, but included in extern/
+for consistency with CUEW and CLEW libraries.
+
+LICENSE
+
+HIPEW is released under the Apache 2.0 license.
diff --git a/extern/hipew/README.blender b/extern/hipew/README.blender
new file mode 100644
index 00000000000..25a44a250ec
--- /dev/null
+++ b/extern/hipew/README.blender
@@ -0,0 +1,5 @@
+Project: Blender
+URL: https://git.blender.org/blender.git
+License: Apache 2.0
+Upstream version: N/A
+Local modifications: None
diff --git a/extern/hipew/include/hipew.h b/extern/hipew/include/hipew.h
index d18cf67524d..50f6d6607ec 100644
--- a/extern/hipew/include/hipew.h
+++ b/extern/hipew/include/hipew.h
@@ -804,31 +804,29 @@ typedef enum hipDeviceP2PAttr {
} hipDeviceP2PAttr;
typedef struct HIP_MEMCPY3D {
- size_t srcXInBytes;
- size_t srcY;
- size_t srcZ;
- size_t srcLOD;
+ unsigned int srcXInBytes;
+ unsigned int srcY;
+ unsigned int srcZ;
+ unsigned int srcLOD;
hipMemoryType srcMemoryType;
const void* srcHost;
hipDeviceptr_t srcDevice;
- hArray * srcArray;
- void* reserved0;
- size_t srcPitch;
- size_t srcHeight;
- size_t dstXInBytes;
- size_t dstY;
- size_t dstZ;
- size_t dstLOD;
+ hArray srcArray;
+ unsigned int srcPitch;
+ unsigned int srcHeight;
+ unsigned int dstXInBytes;
+ unsigned int dstY;
+ unsigned int dstZ;
+ unsigned int dstLOD;
hipMemoryType dstMemoryType;
void* dstHost;
hipDeviceptr_t dstDevice;
- hArray * dstArray;
- void* reserved1;
- size_t dstPitch;
- size_t dstHeight;
- size_t WidthInBytes;
- size_t Height;
- size_t Depth;
+ hArray dstArray;
+ unsigned int dstPitch;
+ unsigned int dstHeight;
+ unsigned int WidthInBytes;
+ unsigned int Height;
+ unsigned int Depth;
} HIP_MEMCPY3D;
typedef struct HIP_MEMCPY3D_PEER_st {
@@ -879,7 +877,7 @@ typedef struct HIP_RESOURCE_DESC_st {
hipResourceType resType;
union {
struct {
- hArray * h_Array;
+ hArray h_Array;
} array;
struct {
hipMipmappedArray_t hMipmappedArray;
@@ -1074,9 +1072,10 @@ typedef enum hiprtcResult {
typedef hipError_t HIPAPI thipGetErrorName(hipError_t error, const char** pStr);
typedef hipError_t HIPAPI thipInit(unsigned int Flags);
typedef hipError_t HIPAPI thipDriverGetVersion(int* driverVersion);
-typedef hipError_t HIPAPI thipGetDevice(hipDevice_t* device, int ordinal);
+typedef hipError_t HIPAPI thipGetDevice(int* device);
typedef hipError_t HIPAPI thipGetDeviceCount(int* count);
typedef hipError_t HIPAPI thipGetDeviceProperties(hipDeviceProp_t* props, int deviceId);
+typedef hipError_t HIPAPI thipDeviceGet(hipDevice_t* device, int ordinal);
typedef hipError_t HIPAPI thipDeviceGetName(char* name, int len, hipDevice_t dev);
typedef hipError_t HIPAPI thipDeviceGetAttribute(int* pi, hipDeviceAttribute_t attrib, hipDevice_t dev);
typedef hipError_t HIPAPI thipDeviceComputeCapability(int* major, int* minor, hipDevice_t dev);
@@ -1209,6 +1208,7 @@ extern thipDriverGetVersion *hipDriverGetVersion;
extern thipGetDevice *hipGetDevice;
extern thipGetDeviceCount *hipGetDeviceCount;
extern thipGetDeviceProperties *hipGetDeviceProperties;
+extern thipDeviceGet* hipDeviceGet;
extern thipDeviceGetName *hipDeviceGetName;
extern thipDeviceGetAttribute *hipDeviceGetAttribute;
extern thipDeviceComputeCapability *hipDeviceComputeCapability;
@@ -1333,6 +1333,7 @@ enum {
HIPEW_SUCCESS = 0,
HIPEW_ERROR_OPEN_FAILED = -1,
HIPEW_ERROR_ATEXIT_FAILED = -2,
+ HIPEW_ERROR_OLD_DRIVER = -3,
};
enum {
diff --git a/extern/hipew/src/hipew.c b/extern/hipew/src/hipew.c
index 02cec1ba28f..010c361fa46 100644
--- a/extern/hipew/src/hipew.c
+++ b/extern/hipew/src/hipew.c
@@ -71,6 +71,7 @@ thipDriverGetVersion *hipDriverGetVersion;
thipGetDevice *hipGetDevice;
thipGetDeviceCount *hipGetDeviceCount;
thipGetDeviceProperties *hipGetDeviceProperties;
+thipDeviceGet* hipDeviceGet;
thipDeviceGetName *hipDeviceGetName;
thipDeviceGetAttribute *hipDeviceGetAttribute;
thipDeviceComputeCapability *hipDeviceComputeCapability;
@@ -213,6 +214,36 @@ static void hipewHipExit(void) {
}
}
+#ifdef _WIN32
+static int hipewHasOldDriver(const char *hip_path) {
+ DWORD verHandle = 0;
+ DWORD verSize = GetFileVersionInfoSize(hip_path, &verHandle);
+ int old_driver = 0;
+ if (verSize != 0) {
+ LPSTR verData = (LPSTR)malloc(verSize);
+ if (GetFileVersionInfo(hip_path, verHandle, verSize, verData)) {
+ LPBYTE lpBuffer = NULL;
+ UINT size = 0;
+ 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) {
+ unsigned int fileVersionLS0 = (verInfo->dwFileVersionLS >> 16) & 0xffff;
+ unsigned int fileversionLS1 = (verInfo->dwFileVersionLS >> 0) & 0xffff;
+ /* Corresponds to versions older than AMD Radeon Pro 21.Q4. */
+ old_driver = ((fileVersionLS0 < 3354) || (fileVersionLS0 == 3354 && fileversionLS1 < 13));
+ }
+ }
+ }
+ }
+ free(verData);
+ }
+ return old_driver;
+}
+#endif
+
static int hipewHipInit(void) {
/* Library paths. */
#ifdef _WIN32
@@ -240,6 +271,14 @@ static int hipewHipInit(void) {
return result;
}
+#ifdef _WIN32
+ /* Test for driver version. */
+ if(hipewHasOldDriver(hip_paths[0])) {
+ result = HIPEW_ERROR_OLD_DRIVER;
+ return result;
+ }
+#endif
+
/* Load library. */
hip_lib = dynamic_library_open_find(hip_paths);
@@ -255,6 +294,7 @@ static int hipewHipInit(void) {
HIP_LIBRARY_FIND_CHECKED(hipGetDevice);
HIP_LIBRARY_FIND_CHECKED(hipGetDeviceCount);
HIP_LIBRARY_FIND_CHECKED(hipGetDeviceProperties);
+ HIP_LIBRARY_FIND_CHECKED(hipDeviceGet);
HIP_LIBRARY_FIND_CHECKED(hipDeviceGetName);
HIP_LIBRARY_FIND_CHECKED(hipDeviceGetAttribute);
HIP_LIBRARY_FIND_CHECKED(hipDeviceComputeCapability);
diff --git a/extern/nanosvg/README.blender b/extern/nanosvg/README.blender
index 701b5100ca5..455c6580304 100644
--- a/extern/nanosvg/README.blender
+++ b/extern/nanosvg/README.blender
@@ -1,7 +1,7 @@
Project: NanoSVG
URL: https://github.com/memononen/nanosvg
License: zlib
-Upstream version:
+Upstream version: 3cdd4a9d7886
Local modifications: Added some functionality to manage grease pencil layers
Added a fix to SVG import arc and float errors (https://developer.blender.org/rB11dc674c78b49fc4e0b7c134c375b6c8b8eacbcc)
diff --git a/intern/atomic/atomic_ops.h b/intern/atomic/atomic_ops.h
index ad404c756ce..6a4d6d263c0 100644
--- a/intern/atomic/atomic_ops.h
+++ b/intern/atomic/atomic_ops.h
@@ -45,7 +45,7 @@
*/
/** \file
- * \ingroup Atomic
+ * \ingroup intern_atomic
*
* \brief Provides wrapper around system-specific atomic primitives,
* and some extensions (faked-atomic operations over float numbers).
diff --git a/intern/atomic/intern/atomic_ops_ext.h b/intern/atomic/intern/atomic_ops_ext.h
index 4dbc1153506..aedf0985169 100644
--- a/intern/atomic/intern/atomic_ops_ext.h
+++ b/intern/atomic/intern/atomic_ops_ext.h
@@ -44,6 +44,10 @@
* The Original Code is: adapted from jemalloc.
*/
+/** \file
+ * \ingroup intern_atomic
+ */
+
#ifndef __ATOMIC_OPS_EXT_H__
#define __ATOMIC_OPS_EXT_H__
diff --git a/intern/atomic/intern/atomic_ops_msvc.h b/intern/atomic/intern/atomic_ops_msvc.h
index c9ad1a46ab9..ea5ae666db9 100644
--- a/intern/atomic/intern/atomic_ops_msvc.h
+++ b/intern/atomic/intern/atomic_ops_msvc.h
@@ -5,7 +5,7 @@
* All rights reserved.
* Copyright (C) 2007-2012 Mozilla Foundation. All rights reserved.
* Copyright (C) 2009-2013 Facebook, Inc. All rights reserved.
-
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice(s),
@@ -13,7 +13,7 @@
* 2. Redistributions in binary form must reproduce the above copyright notice(s),
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
-
+ *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
@@ -26,6 +26,10 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+/** \file
+ * \ingroup intern_atomic
+ */
+
#ifndef __ATOMIC_OPS_MSVC_H__
#define __ATOMIC_OPS_MSVC_H__
diff --git a/intern/atomic/intern/atomic_ops_unix.h b/intern/atomic/intern/atomic_ops_unix.h
index dcafbc67949..2fcfe34d03c 100644
--- a/intern/atomic/intern/atomic_ops_unix.h
+++ b/intern/atomic/intern/atomic_ops_unix.h
@@ -44,6 +44,10 @@
* The Original Code is: adapted from jemalloc.
*/
+/** \file
+ * \ingroup intern_atomic
+ */
+
#ifndef __ATOMIC_OPS_UNIX_H__
#define __ATOMIC_OPS_UNIX_H__
diff --git a/intern/atomic/intern/atomic_ops_utils.h b/intern/atomic/intern/atomic_ops_utils.h
index 01f4284284a..533cfbe9e1f 100644
--- a/intern/atomic/intern/atomic_ops_utils.h
+++ b/intern/atomic/intern/atomic_ops_utils.h
@@ -44,6 +44,10 @@
* The Original Code is: adapted from jemalloc.
*/
+/** \file
+ * \ingroup intern_atomic
+ */
+
#ifndef __ATOMIC_OPS_UTILS_H__
#define __ATOMIC_OPS_UTILS_H__
diff --git a/intern/clog/CLG_log.h b/intern/clog/CLG_log.h
index 8a26eb035cf..3664ade2981 100644
--- a/intern/clog/CLG_log.h
+++ b/intern/clog/CLG_log.h
@@ -14,11 +14,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef __CLG_LOG_H__
-#define __CLG_LOG_H__
-
/** \file
- * \ingroup clog
+ * \ingroup intern_clog
*
* C Logging Library (clog)
* ========================
@@ -68,6 +65,9 @@
* - 4+: May be used for more details than 3, should be avoided but not prevented.
*/
+#ifndef __CLG_LOG_H__
+#define __CLG_LOG_H__
+
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
diff --git a/intern/clog/clog.c b/intern/clog/clog.c
index 13f656d67ab..88cc0fbc4cb 100644
--- a/intern/clog/clog.c
+++ b/intern/clog/clog.c
@@ -15,7 +15,7 @@
*/
/** \file
- * \ingroup clog
+ * \ingroup intern_clog
*/
#include <assert.h>
@@ -388,7 +388,7 @@ static void clg_ctx_fatal_action(CLogContext *ctx)
static void clg_ctx_backtrace(CLogContext *ctx)
{
- /* Note: we avoid writing to 'FILE', for back-trace we make an exception,
+ /* NOTE: we avoid writing to 'FILE', for back-trace we make an exception,
* if necessary we could have a version of the callback that writes to file
* descriptor all at once. */
ctx->callbacks.backtrace_fn(ctx->output_file);
diff --git a/intern/cycles/blender/CMakeLists.txt b/intern/cycles/blender/CMakeLists.txt
index f0540486656..fe7d0b89bb0 100644
--- a/intern/cycles/blender/CMakeLists.txt
+++ b/intern/cycles/blender/CMakeLists.txt
@@ -40,6 +40,7 @@ set(SRC
object_cull.cpp
output_driver.cpp
particles.cpp
+ pointcloud.cpp
curves.cpp
logging.cpp
python.cpp
@@ -87,6 +88,7 @@ endif()
set(ADDON_FILES
addon/__init__.py
+ addon/camera.py
addon/engine.py
addon/operators.py
addon/osl.py
@@ -101,6 +103,11 @@ add_definitions(${GL_DEFINITIONS})
if(WITH_CYCLES_DEVICE_HIP)
add_definitions(-DWITH_HIP)
endif()
+
+if(WITH_CYCLES_DEVICE_METAL)
+ add_definitions(-DWITH_METAL)
+endif()
+
if(WITH_MOD_FLUID)
add_definitions(-DWITH_FLUID)
endif()
diff --git a/intern/cycles/blender/addon/camera.py b/intern/cycles/blender/addon/camera.py
new file mode 100644
index 00000000000..d4133796875
--- /dev/null
+++ b/intern/cycles/blender/addon/camera.py
@@ -0,0 +1,84 @@
+#
+# Copyright 2011-2021 Blender Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# <pep8 compliant>
+
+# Fit to match default projective camera with focal_length 50 and sensor_width 36.
+default_fisheye_polynomial = [-1.1735143712967577e-05,
+ -0.019988736953434998,
+ -3.3525322965709175e-06,
+ 3.099275275886036e-06,
+ -2.6064646454854524e-08]
+
+# Utilities to generate lens polynomials to match built-in camera types, only here
+# for reference at the moment, not used by the code.
+def create_grid(sensor_height, sensor_width):
+ import numpy as np
+ if sensor_height is None:
+ sensor_height = sensor_width / (16 / 9) # Default aspect ration 16:9
+ uu, vv = np.meshgrid(np.linspace(0, 1, 100), np.linspace(0, 1, 100))
+ uu = (uu - 0.5) * sensor_width
+ vv = (vv - 0.5) * sensor_height
+ rr = np.sqrt(uu ** 2 + vv ** 2)
+ return rr
+
+
+def fisheye_lens_polynomial_from_projective(focal_length=50, sensor_width=36, sensor_height=None):
+ import numpy as np
+ rr = create_grid(sensor_height, sensor_width)
+ polynomial = np.polyfit(rr.flat, (-np.arctan(rr / focal_length)).flat, 4)
+ return list(reversed(polynomial))
+
+
+def fisheye_lens_polynomial_from_projective_fov(fov, sensor_width=36, sensor_height=None):
+ import numpy as np
+ f = sensor_width / 2 / np.tan(fov / 2)
+ return fisheye_lens_polynomial_from_projective(f, sensor_width, sensor_height)
+
+
+def fisheye_lens_polynomial_from_equisolid(lens=10.5, sensor_width=36, sensor_height=None):
+ import numpy as np
+ rr = create_grid(sensor_height, sensor_width)
+ x = rr.reshape(-1)
+ x = np.stack([x**i for i in [1, 2, 3, 4]])
+ y = (-2 * np.arcsin(rr / (2 * lens))).reshape(-1)
+ polynomial = np.linalg.lstsq(x.T, y.T, rcond=None)[0]
+ return [0] + list(polynomial)
+
+
+def fisheye_lens_polynomial_from_equidistant(fov=180, sensor_width=36, sensor_height=None):
+ import numpy as np
+ return [0, -np.radians(fov) / sensor_width, 0, 0, 0]
+
+
+def fisheye_lens_polynomial_from_distorted_projective_polynomial(k1, k2, k3, focal_length=50, sensor_width=36, sensor_height=None):
+ import numpy as np
+ rr = create_grid(sensor_height, sensor_width)
+ r2 = (rr / focal_length) ** 2
+ r4 = r2 * r2
+ r6 = r4 * r2
+ r_coeff = 1 + k1 * r2 + k2 * r4 + k3 * r6
+ polynomial = np.polyfit(rr.flat, (-np.arctan(rr / focal_length * r_coeff)).flat, 4)
+ return list(reversed(polynomial))
+
+def fisheye_lens_polynomial_from_distorted_projective_divisions(k1, k2, focal_length=50, sensor_width=36, sensor_height=None):
+ import numpy as np
+ rr = create_grid(sensor_height, sensor_width)
+ r2 = (rr / focal_length) ** 2
+ r4 = r2 * r2
+ r_coeff = 1 + k1 * r2 + k2 * r4
+ polynomial = np.polyfit(rr.flat, (-np.arctan(rr / focal_length / r_coeff)).flat, 4)
+ return list(reversed(polynomial))
diff --git a/intern/cycles/blender/addon/engine.py b/intern/cycles/blender/addon/engine.py
index e5bb77a834a..910ac4a373e 100644
--- a/intern/cycles/blender/addon/engine.py
+++ b/intern/cycles/blender/addon/engine.py
@@ -28,7 +28,7 @@ def _configure_argument_parser():
action='store_true')
parser.add_argument("--cycles-device",
help="Set the device to use for Cycles, overriding user preferences and the scene setting."
- "Valid options are 'CPU', 'CUDA', 'OPTIX', or 'HIP'"
+ "Valid options are 'CPU', 'CUDA', 'OPTIX', 'HIP' or 'METAL'."
"Additionally, you can append '+CPU' to any GPU type for hybrid rendering.",
default=None)
return parser
diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py
index 1e267ccdf4a..a7deae2c05d 100644
--- a/intern/cycles/blender/addon/properties.py
+++ b/intern/cycles/blender/addon/properties.py
@@ -33,6 +33,7 @@ from math import pi
# enums
from . import engine
+from . import camera
enum_devices = (
('CPU', "CPU", "Use CPU for rendering"),
@@ -72,6 +73,8 @@ enum_panorama_types = (
('FISHEYE_EQUISOLID', "Fisheye Equisolid",
"Similar to most fisheye modern lens, takes sensor dimensions into consideration"),
('MIRRORBALL', "Mirror Ball", "Uses the mirror ball mapping"),
+ ('FISHEYE_LENS_POLYNOMIAL', "Fisheye Lens Polynomial",
+ "Defines the lens projection as polynomial to allow real world camera lenses to be mimicked."),
)
enum_curve_shape = (
@@ -111,7 +114,8 @@ enum_device_type = (
('CPU', "CPU", "CPU", 0),
('CUDA', "CUDA", "CUDA", 1),
('OPTIX', "OptiX", "OptiX", 3),
- ("HIP", "HIP", "HIP", 4)
+ ('HIP', "HIP", "HIP", 4),
+ ('METAL', "Metal", "Metal", 5)
)
enum_texture_limit = (
@@ -359,7 +363,7 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
name="Scrambling Distance",
default=1.0,
min=0.0, max=1.0,
- description="Lower values give faster rendering with GPU rendering and less noise with all devices at the cost of possible artifacts if set too low. Only works when not using adaptive sampling",
+ description="Reduce randomization between pixels to improve GPU rendering performance, at the cost of possible rendering artifacts if set too low. Only works when not using adaptive sampling",
)
preview_scrambling_distance: BoolProperty(
name="Scrambling Distance viewport",
@@ -367,10 +371,10 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
description="Uses the Scrambling Distance value for the viewport. Faster but may flicker",
)
- adaptive_scrambling_distance: BoolProperty(
- name="Adaptive Scrambling Distance",
+ auto_scrambling_distance: BoolProperty(
+ name="Automatic Scrambling Distance",
default=False,
- description="Uses a formula to adapt the scrambling distance strength based on the sample count",
+ description="Automatically reduce the randomization between pixels to improve GPU rendering performance, at the cost of possible rendering artifacts. Only works when not using adaptive sampling",
)
use_layer_samples: EnumProperty(
@@ -429,7 +433,7 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
)
direct_light_sampling_type: EnumProperty(
- name="Direct Light Sampling Type",
+ name="Direct Light Sampling",
description="The type of strategy used for sampling direct light contributions",
items=enum_direct_light_sampling_type,
default='MULTIPLE_IMPORTANCE_SAMPLING',
@@ -790,8 +794,8 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
)
use_auto_tile: BoolProperty(
- name="Auto Tiles",
- description="Automatically render high resolution images in tiles to reduce memory usage, using the specified tile size. Tiles are cached to disk while rendering to save memory",
+ name="Use Tiling",
+ description="Render high resolution images in tiles to reduce memory usage, using the specified tile size. Tiles are cached to disk while rendering to save memory",
default=True,
)
tile_size: IntProperty(
@@ -890,6 +894,32 @@ class CyclesCameraSettings(bpy.types.PropertyGroup):
default=pi,
)
+ fisheye_polynomial_k0: FloatProperty(
+ name="Fisheye Polynomial K0",
+ description="Coefficient K0 of the lens polinomial",
+ default=camera.default_fisheye_polynomial[0], precision=6, step=0.1, subtype='ANGLE',
+ )
+ fisheye_polynomial_k1: FloatProperty(
+ name="Fisheye Polynomial K1",
+ description="Coefficient K1 of the lens polinomial",
+ default=camera.default_fisheye_polynomial[1], precision=6, step=0.1, subtype='ANGLE',
+ )
+ fisheye_polynomial_k2: FloatProperty(
+ name="Fisheye Polynomial K2",
+ description="Coefficient K2 of the lens polinomial",
+ default=camera.default_fisheye_polynomial[2], precision=6, step=0.1, subtype='ANGLE',
+ )
+ fisheye_polynomial_k3: FloatProperty(
+ name="Fisheye Polynomial K3",
+ description="Coefficient K3 of the lens polinomial",
+ default=camera.default_fisheye_polynomial[3], precision=6, step=0.1, subtype='ANGLE',
+ )
+ fisheye_polynomial_k4: FloatProperty(
+ name="Fisheye Polynomial K4",
+ description="Coefficient K4 of the lens polinomial",
+ default=camera.default_fisheye_polynomial[4], precision=6, step=0.1, subtype='ANGLE',
+ )
+
@classmethod
def register(cls):
bpy.types.Camera.cycles = PointerProperty(
@@ -1312,8 +1342,7 @@ class CyclesPreferences(bpy.types.AddonPreferences):
def get_device_types(self, context):
import _cycles
- has_cuda, has_optix, has_hip = _cycles.get_device_types()
-
+ has_cuda, has_optix, has_hip, has_metal = _cycles.get_device_types()
list = [('NONE', "None", "Don't use compute device", 0)]
if has_cuda:
list.append(('CUDA', "CUDA", "Use CUDA for GPU acceleration", 1))
@@ -1321,6 +1350,8 @@ class CyclesPreferences(bpy.types.AddonPreferences):
list.append(('OPTIX', "OptiX", "Use OptiX for GPU acceleration", 3))
if has_hip:
list.append(('HIP', "HIP", "Use HIP for GPU acceleration", 4))
+ if has_metal:
+ list.append(('METAL', "Metal", "Use Metal for GPU acceleration", 5))
return list
@@ -1346,7 +1377,7 @@ class CyclesPreferences(bpy.types.AddonPreferences):
def update_device_entries(self, device_list):
for device in device_list:
- if not device[1] in {'CUDA', 'OPTIX', 'CPU', 'HIP'}:
+ if not device[1] in {'CUDA', 'OPTIX', 'CPU', 'HIP', 'METAL'}:
continue
# Try to find existing Device entry
entry = self.find_existing_device_entry(device)
@@ -1390,7 +1421,7 @@ class CyclesPreferences(bpy.types.AddonPreferences):
import _cycles
# Ensure `self.devices` is not re-allocated when the second call to
# get_devices_for_type is made, freeing items from the first list.
- for device_type in ('CUDA', 'OPTIX', 'HIP'):
+ for device_type in ('CUDA', 'OPTIX', 'HIP', 'METAL'):
self.update_device_entries(_cycles.available_devices(device_type))
# Deprecated: use refresh_devices instead.
@@ -1442,6 +1473,8 @@ class CyclesPreferences(bpy.types.AddonPreferences):
col.label(text="Requires discrete AMD GPU with RDNA architecture", icon='BLANK1')
if sys.platform[:3] == "win":
col.label(text="and AMD Radeon Pro 21.Q4 driver or newer", icon='BLANK1')
+ elif device_type == 'METAL':
+ col.label(text="Requires Apple Silicon and macOS 12.0 or newer", icon='BLANK1')
return
for device in devices:
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
index 635d92c2629..e4fbc898070 100644
--- a/intern/cycles/blender/addon/ui.py
+++ b/intern/cycles/blender/addon/ui.py
@@ -97,6 +97,11 @@ def use_cpu(context):
return (get_device_type(context) == 'NONE' or cscene.device == 'CPU')
+def use_metal(context):
+ cscene = context.scene.cycles
+
+ return (get_device_type(context) == 'METAL' and cscene.device == 'GPU')
+
def use_cuda(context):
cscene = context.scene.cycles
@@ -295,13 +300,13 @@ class CYCLES_RENDER_PT_sampling_advanced(CyclesButtonsPanel, Panel):
layout.separator()
- col = layout.column(align=True)
- col.active = not (cscene.use_adaptive_sampling and cscene.use_preview_adaptive_sampling)
- col.prop(cscene, "scrambling_distance", text="Scrambling Distance")
- col.prop(cscene, "adaptive_scrambling_distance", text="Adaptive")
- sub = col.row(align=True)
+ heading = layout.column(align=True, heading="Scrambling Distance")
+ heading.active = not (cscene.use_adaptive_sampling and cscene.use_preview_adaptive_sampling)
+ heading.prop(cscene, "auto_scrambling_distance", text="Automatic")
+ sub = heading.row()
sub.active = not cscene.use_preview_adaptive_sampling
sub.prop(cscene, "preview_scrambling_distance", text="Viewport")
+ heading.prop(cscene, "scrambling_distance", text="Multiplier")
layout.separator()
@@ -1015,7 +1020,7 @@ class CYCLES_OBJECT_PT_motion_blur(CyclesButtonsPanel, Panel):
def poll(cls, context):
ob = context.object
if CyclesButtonsPanel.poll(context) and ob:
- if ob.type in {'MESH', 'CURVE', 'CURVE', 'SURFACE', 'FONT', 'META', 'CAMERA'}:
+ if ob.type in {'MESH', 'CURVE', 'CURVE', 'SURFACE', 'FONT', 'META', 'CAMERA', 'HAIR', 'POINTCLOUD'}:
return True
if ob.instance_type == 'COLLECTION' and ob.instance_collection:
return True
@@ -1819,37 +1824,38 @@ class CYCLES_RENDER_PT_debug(CyclesDebugButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False # No animation.
scene = context.scene
cscene = scene.cycles
- col = layout.column()
+ col = layout.column(heading="CPU")
- col.label(text="CPU Flags:")
row = col.row(align=True)
row.prop(cscene, "debug_use_cpu_sse2", toggle=True)
row.prop(cscene, "debug_use_cpu_sse3", toggle=True)
row.prop(cscene, "debug_use_cpu_sse41", toggle=True)
row.prop(cscene, "debug_use_cpu_avx", toggle=True)
row.prop(cscene, "debug_use_cpu_avx2", toggle=True)
- col.prop(cscene, "debug_bvh_layout")
+ col.prop(cscene, "debug_bvh_layout", text="BVH")
col.separator()
- col = layout.column()
- col.label(text="CUDA Flags:")
+ col = layout.column(heading="CUDA")
col.prop(cscene, "debug_use_cuda_adaptive_compile")
+ col = layout.column(heading="OptiX")
+ col.prop(cscene, "debug_use_optix_debug", text="Module Debug")
col.separator()
- col = layout.column()
- col.label(text="OptiX Flags:")
- col.prop(cscene, "debug_use_optix_debug")
+ col.prop(cscene, "debug_bvh_type", text="Viewport BVH")
col.separator()
- col = layout.column()
- col.prop(cscene, "debug_bvh_type")
+ import _cycles
+ if _cycles.with_debug:
+ col.prop(cscene, "direct_light_sampling_type")
class CYCLES_RENDER_PT_simplify(CyclesButtonsPanel, Panel):
diff --git a/intern/cycles/blender/camera.cpp b/intern/cycles/blender/camera.cpp
index b5afcfa7fda..dffcceed42a 100644
--- a/intern/cycles/blender/camera.cpp
+++ b/intern/cycles/blender/camera.cpp
@@ -69,6 +69,12 @@ struct BlenderCamera {
float pole_merge_angle_from;
float pole_merge_angle_to;
+ float fisheye_polynomial_k0;
+ float fisheye_polynomial_k1;
+ float fisheye_polynomial_k2;
+ float fisheye_polynomial_k3;
+ float fisheye_polynomial_k4;
+
enum { AUTO, HORIZONTAL, VERTICAL } sensor_fit;
float sensor_width;
float sensor_height;
@@ -200,6 +206,12 @@ static void blender_camera_from_object(BlenderCamera *bcam,
bcam->longitude_min = RNA_float_get(&ccamera, "longitude_min");
bcam->longitude_max = RNA_float_get(&ccamera, "longitude_max");
+ bcam->fisheye_polynomial_k0 = RNA_float_get(&ccamera, "fisheye_polynomial_k0");
+ bcam->fisheye_polynomial_k1 = RNA_float_get(&ccamera, "fisheye_polynomial_k1");
+ bcam->fisheye_polynomial_k2 = RNA_float_get(&ccamera, "fisheye_polynomial_k2");
+ bcam->fisheye_polynomial_k3 = RNA_float_get(&ccamera, "fisheye_polynomial_k3");
+ bcam->fisheye_polynomial_k4 = RNA_float_get(&ccamera, "fisheye_polynomial_k4");
+
bcam->interocular_distance = b_camera.stereo().interocular_distance();
if (b_camera.stereo().convergence_mode() == BL::CameraStereoData::convergence_mode_PARALLEL) {
bcam->convergence_distance = FLT_MAX;
@@ -422,7 +434,8 @@ static void blender_camera_sync(Camera *cam,
cam->set_full_height(height);
/* panorama sensor */
- if (bcam->type == CAMERA_PANORAMA && bcam->panorama_type == PANORAMA_FISHEYE_EQUISOLID) {
+ if (bcam->type == CAMERA_PANORAMA && (bcam->panorama_type == PANORAMA_FISHEYE_EQUISOLID ||
+ bcam->panorama_type == PANORAMA_FISHEYE_LENS_POLYNOMIAL)) {
float fit_xratio = (float)bcam->render_width * bcam->pixelaspect.x;
float fit_yratio = (float)bcam->render_height * bcam->pixelaspect.y;
bool horizontal_fit;
@@ -465,6 +478,12 @@ static void blender_camera_sync(Camera *cam,
cam->set_latitude_min(bcam->latitude_min);
cam->set_latitude_max(bcam->latitude_max);
+ cam->set_fisheye_polynomial_k0(bcam->fisheye_polynomial_k0);
+ cam->set_fisheye_polynomial_k1(bcam->fisheye_polynomial_k1);
+ cam->set_fisheye_polynomial_k2(bcam->fisheye_polynomial_k2);
+ cam->set_fisheye_polynomial_k3(bcam->fisheye_polynomial_k3);
+ cam->set_fisheye_polynomial_k4(bcam->fisheye_polynomial_k4);
+
cam->set_longitude_min(bcam->longitude_min);
cam->set_longitude_max(bcam->longitude_max);
diff --git a/intern/cycles/blender/curves.cpp b/intern/cycles/blender/curves.cpp
index ffe0c553738..65a02d041cc 100644
--- a/intern/cycles/blender/curves.cpp
+++ b/intern/cycles/blender/curves.cpp
@@ -199,7 +199,7 @@ static bool ObtainCacheParticleUV(Hair *hair,
b_mesh->uv_layers.begin(l);
float2 uv = zero_float2();
- if (b_mesh->uv_layers.length())
+ if (!b_mesh->uv_layers.empty())
b_psys.uv_on_emitter(psmd, *b_pa, pa_no, uv_num, &uv.x);
CData->curve_uv.push_back_slow(uv);
@@ -261,7 +261,7 @@ static bool ObtainCacheParticleVcol(Hair *hair,
b_mesh->vertex_colors.begin(l);
float4 vcol = make_float4(0.0f, 0.0f, 0.0f, 1.0f);
- if (b_mesh->vertex_colors.length())
+ if (!b_mesh->vertex_colors.empty())
b_psys.mcol_on_emitter(psmd, *b_pa, pa_no, vcol_num, &vcol.x);
CData->curve_vcol.push_back_slow(vcol);
@@ -819,11 +819,14 @@ void BlenderSync::sync_hair(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, H
new_hair.set_used_shaders(used_shaders);
if (view_layer.use_hair) {
+#ifdef WITH_HAIR_NODES
if (b_ob_info.object_data.is_a(&RNA_Hair)) {
/* Hair object. */
sync_hair(&new_hair, b_ob_info, false);
}
- else {
+ else
+#endif
+ {
/* Particle hair. */
bool need_undeformed = new_hair.need_attribute(scene, ATTR_STD_GENERATED);
BL::Mesh b_mesh = object_to_mesh(
@@ -870,12 +873,15 @@ void BlenderSync::sync_hair_motion(BL::Depsgraph b_depsgraph,
/* Export deformed coordinates. */
if (ccl::BKE_object_is_deform_modified(b_ob_info, b_scene, preview)) {
+#ifdef WITH_HAIR_NODES
if (b_ob_info.object_data.is_a(&RNA_Hair)) {
/* Hair object. */
sync_hair(hair, b_ob_info, true, motion_step);
return;
}
- else {
+ else
+#endif
+ {
/* Particle hair. */
BL::Mesh b_mesh = object_to_mesh(
b_data, b_ob_info, b_depsgraph, false, Mesh::SUBDIVISION_NONE);
diff --git a/intern/cycles/blender/device.cpp b/intern/cycles/blender/device.cpp
index 9fabc33a96b..d39381ac6f1 100644
--- a/intern/cycles/blender/device.cpp
+++ b/intern/cycles/blender/device.cpp
@@ -27,6 +27,7 @@ enum ComputeDevice {
COMPUTE_DEVICE_CUDA = 1,
COMPUTE_DEVICE_OPTIX = 3,
COMPUTE_DEVICE_HIP = 4,
+ COMPUTE_DEVICE_METAL = 5,
COMPUTE_DEVICE_NUM
};
@@ -85,6 +86,9 @@ DeviceInfo blender_device_info(BL::Preferences &b_preferences, BL::Scene &b_scen
else if (compute_device == COMPUTE_DEVICE_HIP) {
mask |= DEVICE_MASK_HIP;
}
+ else if (compute_device == COMPUTE_DEVICE_METAL) {
+ mask |= DEVICE_MASK_METAL;
+ }
vector<DeviceInfo> devices = Device::available_devices(mask);
/* Match device preferences and available devices. */
diff --git a/intern/cycles/blender/geometry.cpp b/intern/cycles/blender/geometry.cpp
index 479e76f68bc..78c803b7adb 100644
--- a/intern/cycles/blender/geometry.cpp
+++ b/intern/cycles/blender/geometry.cpp
@@ -19,6 +19,7 @@
#include "scene/hair.h"
#include "scene/mesh.h"
#include "scene/object.h"
+#include "scene/pointcloud.h"
#include "scene/volume.h"
#include "blender/sync.h"
@@ -31,10 +32,18 @@ CCL_NAMESPACE_BEGIN
static Geometry::Type determine_geom_type(BObjectInfo &b_ob_info, bool use_particle_hair)
{
+#ifdef WITH_HAIR_NODES
if (b_ob_info.object_data.is_a(&RNA_Hair) || use_particle_hair) {
+#else
+ if (use_particle_hair) {
+#endif
return Geometry::HAIR;
}
+ if (b_ob_info.object_data.is_a(&RNA_PointCloud)) {
+ return Geometry::POINTCLOUD;
+ }
+
if (b_ob_info.object_data.is_a(&RNA_Volume) ||
(b_ob_info.object_data == b_ob_info.real_object.data() &&
object_fluid_gas_domain_find(b_ob_info.real_object))) {
@@ -107,6 +116,9 @@ Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph,
else if (geom_type == Geometry::VOLUME) {
geom = scene->create_node<Volume>();
}
+ else if (geom_type == Geometry::POINTCLOUD) {
+ geom = scene->create_node<PointCloud>();
+ }
else {
geom = scene->create_node<Mesh>();
}
@@ -166,6 +178,10 @@ Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph,
Volume *volume = static_cast<Volume *>(geom);
sync_volume(b_ob_info, volume);
}
+ else if (geom_type == Geometry::POINTCLOUD) {
+ PointCloud *pointcloud = static_cast<PointCloud *>(geom);
+ sync_pointcloud(pointcloud, b_ob_info);
+ }
else {
Mesh *mesh = static_cast<Mesh *>(geom);
sync_mesh(b_depsgraph, b_ob_info, mesh);
@@ -215,7 +231,11 @@ void BlenderSync::sync_geometry_motion(BL::Depsgraph &b_depsgraph,
if (progress.get_cancel())
return;
+#ifdef WITH_HAIR_NODES
if (b_ob_info.object_data.is_a(&RNA_Hair) || use_particle_hair) {
+#else
+ if (use_particle_hair) {
+#endif
Hair *hair = static_cast<Hair *>(geom);
sync_hair_motion(b_depsgraph, b_ob_info, hair, motion_step);
}
@@ -223,6 +243,10 @@ void BlenderSync::sync_geometry_motion(BL::Depsgraph &b_depsgraph,
object_fluid_gas_domain_find(b_ob_info.real_object)) {
/* No volume motion blur support yet. */
}
+ else if (b_ob_info.object_data.is_a(&RNA_PointCloud)) {
+ PointCloud *pointcloud = static_cast<PointCloud *>(geom);
+ sync_pointcloud_motion(pointcloud, b_ob_info, motion_step);
+ }
else {
Mesh *mesh = static_cast<Mesh *>(geom);
sync_mesh_motion(b_depsgraph, b_ob_info, mesh, motion_step);
diff --git a/intern/cycles/blender/image.cpp b/intern/cycles/blender/image.cpp
index 3ea3a47c1f4..4f5744d86a8 100644
--- a/intern/cycles/blender/image.cpp
+++ b/intern/cycles/blender/image.cpp
@@ -24,8 +24,14 @@ CCL_NAMESPACE_BEGIN
/* Packed Images */
-BlenderImageLoader::BlenderImageLoader(BL::Image b_image, int frame)
- : b_image(b_image), frame(frame), free_cache(!b_image.has_data())
+BlenderImageLoader::BlenderImageLoader(BL::Image b_image,
+ const int frame,
+ const bool is_preview_render)
+ : b_image(b_image),
+ frame(frame),
+ /* Don't free cache for preview render to avoid race condition from T93560, to be fixed
+ properly later as we are close to release. */
+ free_cache(!is_preview_render && !b_image.has_data())
{
}
diff --git a/intern/cycles/blender/image.h b/intern/cycles/blender/image.h
index 6f1e72c21af..b4aa4299ed1 100644
--- a/intern/cycles/blender/image.h
+++ b/intern/cycles/blender/image.h
@@ -25,7 +25,7 @@ CCL_NAMESPACE_BEGIN
class BlenderImageLoader : public ImageLoader {
public:
- BlenderImageLoader(BL::Image b_image, int frame);
+ BlenderImageLoader(BL::Image b_image, const int frame, const bool is_preview_render);
bool load_metadata(const ImageDeviceFeatures &features, ImageMetaData &metadata) override;
bool load_pixels(const ImageMetaData &metadata,
diff --git a/intern/cycles/blender/mesh.cpp b/intern/cycles/blender/mesh.cpp
index b69bf88c213..bb17cfdcb45 100644
--- a/intern/cycles/blender/mesh.cpp
+++ b/intern/cycles/blender/mesh.cpp
@@ -555,7 +555,7 @@ static void attr_create_vertex_color(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh,
/* Create uv map attributes. */
static void attr_create_uv_map(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh)
{
- if (b_mesh.uv_layers.length() != 0) {
+ if (!b_mesh.uv_layers.empty()) {
for (BL::MeshUVLoopLayer &l : b_mesh.uv_layers) {
const bool active_render = l.active_render();
AttributeStandard uv_std = (active_render) ? ATTR_STD_UV : ATTR_STD_NONE;
@@ -619,7 +619,7 @@ static void attr_create_uv_map(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh)
static void attr_create_subd_uv_map(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh, bool subdivide_uvs)
{
- if (b_mesh.uv_layers.length() != 0) {
+ if (!b_mesh.uv_layers.empty()) {
BL::Mesh::uv_layers_iterator l;
int i = 0;
@@ -951,7 +951,7 @@ static void create_mesh(Scene *scene,
N = attr_N->data_float3();
/* create generated coordinates from undeformed coordinates */
- const bool need_default_tangent = (subdivision == false) && (b_mesh.uv_layers.length() == 0) &&
+ const bool need_default_tangent = (subdivision == false) && (b_mesh.uv_layers.empty()) &&
(mesh->need_attribute(scene, ATTR_STD_UV_TANGENT));
if (mesh->need_attribute(scene, ATTR_STD_GENERATED) || need_default_tangent) {
Attribute *attr = attributes.add(ATTR_STD_GENERATED);
diff --git a/intern/cycles/blender/object.cpp b/intern/cycles/blender/object.cpp
index d6c52f7faf9..86314d3b196 100644
--- a/intern/cycles/blender/object.cpp
+++ b/intern/cycles/blender/object.cpp
@@ -72,7 +72,8 @@ bool BlenderSync::object_is_geometry(BObjectInfo &b_ob_info)
BL::Object::type_enum type = b_ob_info.iter_object.type();
- if (type == BL::Object::type_VOLUME || type == BL::Object::type_HAIR) {
+ if (type == BL::Object::type_VOLUME || type == BL::Object::type_HAIR ||
+ type == BL::Object::type_POINTCLOUD) {
/* Will be exported attached to mesh. */
return true;
}
@@ -206,7 +207,7 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
return NULL;
}
- /* only interested in object that we can create meshes from */
+ /* only interested in object that we can create geometry from */
if (!object_is_geometry(b_ob_info)) {
return NULL;
}
diff --git a/intern/cycles/blender/output_driver.cpp b/intern/cycles/blender/output_driver.cpp
index 2b3586af668..f0164fa409b 100644
--- a/intern/cycles/blender/output_driver.cpp
+++ b/intern/cycles/blender/output_driver.cpp
@@ -66,7 +66,7 @@ bool BlenderOutputDriver::read_render_tile(const Tile &tile)
bool BlenderOutputDriver::update_render_tile(const Tile &tile)
{
- /* Use final write for preview renders, otherwise render result wouldn't be be updated
+ /* Use final write for preview renders, otherwise render result wouldn't be updated
* quickly on Blender side. For all other cases we use the display driver. */
if (b_engine_.is_preview()) {
write_render_tile(tile);
diff --git a/intern/cycles/blender/pointcloud.cpp b/intern/cycles/blender/pointcloud.cpp
new file mode 100644
index 00000000000..a9e616a468f
--- /dev/null
+++ b/intern/cycles/blender/pointcloud.cpp
@@ -0,0 +1,253 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "scene/pointcloud.h"
+#include "scene/attribute.h"
+#include "scene/scene.h"
+
+#include "blender/sync.h"
+#include "blender/util.h"
+
+#include "util/foreach.h"
+#include "util/hash.h"
+
+CCL_NAMESPACE_BEGIN
+
+template<typename TypeInCycles, typename GetValueAtIndex>
+static void fill_generic_attribute(BL::PointCloud &b_pointcloud,
+ TypeInCycles *data,
+ const GetValueAtIndex &get_value_at_index)
+{
+ const int num_points = b_pointcloud.points.length();
+ for (int i = 0; i < num_points; i++) {
+ data[i] = get_value_at_index(i);
+ }
+}
+
+static void copy_attributes(PointCloud *pointcloud, BL::PointCloud b_pointcloud)
+{
+ AttributeSet &attributes = pointcloud->attributes;
+ for (BL::Attribute &b_attribute : b_pointcloud.attributes) {
+ const ustring name{b_attribute.name().c_str()};
+
+ if (attributes.find(name)) {
+ continue;
+ }
+
+ const AttributeElement element = ATTR_ELEMENT_VERTEX;
+ const BL::Attribute::data_type_enum b_data_type = b_attribute.data_type();
+ switch (b_data_type) {
+ case BL::Attribute::data_type_FLOAT: {
+ BL::FloatAttribute b_float_attribute{b_attribute};
+ Attribute *attr = attributes.add(name, TypeFloat, element);
+ float *data = attr->data_float();
+ fill_generic_attribute(
+ b_pointcloud, data, [&](int i) { return b_float_attribute.data[i].value(); });
+ break;
+ }
+ case BL::Attribute::data_type_BOOLEAN: {
+ BL::BoolAttribute b_bool_attribute{b_attribute};
+ Attribute *attr = attributes.add(name, TypeFloat, element);
+ float *data = attr->data_float();
+ fill_generic_attribute(
+ b_pointcloud, data, [&](int i) { return (float)b_bool_attribute.data[i].value(); });
+ break;
+ }
+ case BL::Attribute::data_type_INT: {
+ BL::IntAttribute b_int_attribute{b_attribute};
+ Attribute *attr = attributes.add(name, TypeFloat, element);
+ float *data = attr->data_float();
+ fill_generic_attribute(
+ b_pointcloud, data, [&](int i) { return (float)b_int_attribute.data[i].value(); });
+ break;
+ }
+ case BL::Attribute::data_type_FLOAT_VECTOR: {
+ BL::FloatVectorAttribute b_vector_attribute{b_attribute};
+ Attribute *attr = attributes.add(name, TypeVector, element);
+ float3 *data = attr->data_float3();
+ fill_generic_attribute(b_pointcloud, data, [&](int i) {
+ BL::Array<float, 3> v = b_vector_attribute.data[i].vector();
+ return make_float3(v[0], v[1], v[2]);
+ });
+ break;
+ }
+ case BL::Attribute::data_type_FLOAT_COLOR: {
+ BL::FloatColorAttribute b_color_attribute{b_attribute};
+ Attribute *attr = attributes.add(name, TypeRGBA, element);
+ float4 *data = attr->data_float4();
+ fill_generic_attribute(b_pointcloud, data, [&](int i) {
+ BL::Array<float, 4> v = b_color_attribute.data[i].color();
+ return make_float4(v[0], v[1], v[2], v[3]);
+ });
+ break;
+ }
+ case BL::Attribute::data_type_FLOAT2: {
+ BL::Float2Attribute b_float2_attribute{b_attribute};
+ Attribute *attr = attributes.add(name, TypeFloat2, element);
+ float2 *data = attr->data_float2();
+ fill_generic_attribute(b_pointcloud, data, [&](int i) {
+ BL::Array<float, 2> v = b_float2_attribute.data[i].vector();
+ return make_float2(v[0], v[1]);
+ });
+ break;
+ }
+ default:
+ /* Not supported. */
+ break;
+ }
+ }
+}
+
+static void export_pointcloud(Scene *scene, PointCloud *pointcloud, BL::PointCloud b_pointcloud)
+{
+ /* TODO: optimize so we can straight memcpy arrays from Blender? */
+
+ /* Add requested attributes. */
+ Attribute *attr_random = NULL;
+ if (pointcloud->need_attribute(scene, ATTR_STD_POINT_RANDOM)) {
+ attr_random = pointcloud->attributes.add(ATTR_STD_POINT_RANDOM);
+ }
+
+ /* Reserve memory. */
+ const int num_points = b_pointcloud.points.length();
+ pointcloud->reserve(num_points);
+
+ /* Export points. */
+ BL::PointCloud::points_iterator b_point_iter;
+ for (b_pointcloud.points.begin(b_point_iter); b_point_iter != b_pointcloud.points.end();
+ ++b_point_iter) {
+ BL::Point b_point = *b_point_iter;
+ const float3 co = get_float3(b_point.co());
+ const float radius = b_point.radius();
+ pointcloud->add_point(co, radius);
+
+ /* Random number per point. */
+ if (attr_random != NULL) {
+ attr_random->add(hash_uint2_to_float(b_point.index(), 0));
+ }
+ }
+
+ /* Export attributes */
+ copy_attributes(pointcloud, b_pointcloud);
+}
+
+static void export_pointcloud_motion(PointCloud *pointcloud,
+ BL::PointCloud b_pointcloud,
+ int motion_step)
+{
+ /* Find or add attribute. */
+ Attribute *attr_mP = pointcloud->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ bool new_attribute = false;
+
+ if (!attr_mP) {
+ attr_mP = pointcloud->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION);
+ new_attribute = true;
+ }
+
+ /* Export motion points. */
+ const int num_points = pointcloud->num_points();
+ float3 *mP = attr_mP->data_float3() + motion_step * num_points;
+ bool have_motion = false;
+ int num_motion_points = 0;
+ const array<float3> &pointcloud_points = pointcloud->get_points();
+
+ BL::PointCloud::points_iterator b_point_iter;
+ for (b_pointcloud.points.begin(b_point_iter); b_point_iter != b_pointcloud.points.end();
+ ++b_point_iter) {
+ BL::Point b_point = *b_point_iter;
+
+ if (num_motion_points < num_points) {
+ float3 P = get_float3(b_point.co());
+ P.w = b_point.radius();
+ mP[num_motion_points] = P;
+ have_motion = have_motion || (P != pointcloud_points[num_motion_points]);
+ num_motion_points++;
+ }
+ }
+
+ /* In case of new attribute, we verify if there really was any motion. */
+ if (new_attribute) {
+ if (num_motion_points != num_points || !have_motion) {
+ pointcloud->attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION);
+ }
+ else if (motion_step > 0) {
+ /* Motion, fill up previous steps that we might have skipped because
+ * they had no motion, but we need them anyway now. */
+ for (int step = 0; step < motion_step; step++) {
+ pointcloud->copy_center_to_motion_step(step);
+ }
+ }
+ }
+
+ /* Export attributes */
+ copy_attributes(pointcloud, b_pointcloud);
+}
+
+void BlenderSync::sync_pointcloud(PointCloud *pointcloud, BObjectInfo &b_ob_info)
+{
+ size_t old_numpoints = pointcloud->num_points();
+
+ array<Node *> used_shaders = pointcloud->get_used_shaders();
+
+ PointCloud new_pointcloud;
+ new_pointcloud.set_used_shaders(used_shaders);
+
+ /* TODO: add option to filter out points in the view layer. */
+ BL::PointCloud b_pointcloud(b_ob_info.object_data);
+ export_pointcloud(scene, &new_pointcloud, b_pointcloud);
+
+ /* update original sockets */
+ for (const SocketType &socket : new_pointcloud.type->inputs) {
+ /* Those sockets are updated in sync_object, so do not modify them. */
+ if (socket.name == "use_motion_blur" || socket.name == "motion_steps" ||
+ socket.name == "used_shaders") {
+ continue;
+ }
+ pointcloud->set_value(socket, new_pointcloud, socket);
+ }
+
+ pointcloud->attributes.clear();
+ foreach (Attribute &attr, new_pointcloud.attributes.attributes) {
+ pointcloud->attributes.attributes.push_back(std::move(attr));
+ }
+
+ /* tag update */
+ const bool rebuild = (pointcloud && old_numpoints != pointcloud->num_points());
+ pointcloud->tag_update(scene, rebuild);
+}
+
+void BlenderSync::sync_pointcloud_motion(PointCloud *pointcloud,
+ BObjectInfo &b_ob_info,
+ int motion_step)
+{
+ /* Skip if nothing exported. */
+ if (pointcloud->num_points() == 0) {
+ return;
+ }
+
+ /* Export deformed coordinates. */
+ if (ccl::BKE_object_is_deform_modified(b_ob_info, b_scene, preview)) {
+ /* PointCloud object. */
+ BL::PointCloud b_pointcloud(b_ob_info.object_data);
+ export_pointcloud_motion(pointcloud, b_pointcloud, motion_step);
+ }
+ else {
+ /* No deformation on this frame, copy coordinates if other frames did have it. */
+ pointcloud->copy_center_to_motion_step(motion_step);
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/python.cpp b/intern/cycles/blender/python.cpp
index bb9b0a74424..024dae306b0 100644
--- a/intern/cycles/blender/python.cpp
+++ b/intern/cycles/blender/python.cpp
@@ -906,16 +906,18 @@ static PyObject *enable_print_stats_func(PyObject * /*self*/, PyObject * /*args*
static PyObject *get_device_types_func(PyObject * /*self*/, PyObject * /*args*/)
{
vector<DeviceType> device_types = Device::available_types();
- bool has_cuda = false, has_optix = false, has_hip = false;
+ bool has_cuda = false, has_optix = false, has_hip = false, has_metal = false;
foreach (DeviceType device_type, device_types) {
has_cuda |= (device_type == DEVICE_CUDA);
has_optix |= (device_type == DEVICE_OPTIX);
has_hip |= (device_type == DEVICE_HIP);
+ has_metal |= (device_type == DEVICE_METAL);
}
- PyObject *list = PyTuple_New(3);
+ PyObject *list = PyTuple_New(4);
PyTuple_SET_ITEM(list, 0, PyBool_FromLong(has_cuda));
PyTuple_SET_ITEM(list, 1, PyBool_FromLong(has_optix));
PyTuple_SET_ITEM(list, 2, PyBool_FromLong(has_hip));
+ PyTuple_SET_ITEM(list, 3, PyBool_FromLong(has_metal));
return list;
}
@@ -944,6 +946,9 @@ static PyObject *set_device_override_func(PyObject * /*self*/, PyObject *arg)
else if (override == "HIP") {
BlenderSession::device_override = DEVICE_MASK_HIP;
}
+ else if (override == "METAL") {
+ BlenderSession::device_override = DEVICE_MASK_METAL;
+ }
else {
printf("\nError: %s is not a valid Cycles device.\n", override.c_str());
Py_RETURN_FALSE;
@@ -1054,5 +1059,13 @@ void *CCL_python_module_init()
Py_INCREF(Py_False);
}
+#ifdef WITH_CYCLES_DEBUG
+ PyModule_AddObject(mod, "with_debug", Py_True);
+ Py_INCREF(Py_True);
+#else /* WITH_CYCLES_DEBUG */
+ PyModule_AddObject(mod, "with_debug", Py_False);
+ Py_INCREF(Py_False);
+#endif /* WITH_CYCLES_DEBUG */
+
return (void *)mod;
}
diff --git a/intern/cycles/blender/session.cpp b/intern/cycles/blender/session.cpp
index 2c4e57404b8..b6f72707fe0 100644
--- a/intern/cycles/blender/session.cpp
+++ b/intern/cycles/blender/session.cpp
@@ -396,6 +396,13 @@ void BlenderSession::render(BL::Depsgraph &b_depsgraph_)
/* set the current view */
b_engine.active_view_set(b_rview_name.c_str());
+ /* Force update in this case, since the camera transform on each frame changes
+ * in different views. This could be optimized by somehow storing the animated
+ * camera transforms separate from the fixed stereo transform. */
+ if ((scene->need_motion() != Scene::MOTION_NONE) && view_index > 0) {
+ sync->tag_update();
+ }
+
/* update scene */
BL::Object b_camera_override(b_engine.camera_override());
sync->sync_camera(b_render, b_camera_override, width, height, b_rview_name.c_str());
@@ -629,7 +636,7 @@ void BlenderSession::bake(BL::Depsgraph &b_depsgraph_,
integrator->set_use_emission((bake_filter & BL::BakeSettings::pass_filter_EMIT) != 0);
}
- /* Always use transpanent background for baking. */
+ /* Always use transparent background for baking. */
scene->background->set_transparent(true);
/* Load built-in images from Blender. */
diff --git a/intern/cycles/blender/shader.cpp b/intern/cycles/blender/shader.cpp
index 0cd9052b47a..70acfce6891 100644
--- a/intern/cycles/blender/shader.cpp
+++ b/intern/cycles/blender/shader.cpp
@@ -378,10 +378,19 @@ static ShaderNode *add_node(Scene *scene,
}
else if (b_node.is_a(&RNA_ShaderNodeMapRange)) {
BL::ShaderNodeMapRange b_map_range_node(b_node);
- MapRangeNode *map_range_node = graph->create_node<MapRangeNode>();
- map_range_node->set_clamp(b_map_range_node.clamp());
- map_range_node->set_range_type((NodeMapRangeType)b_map_range_node.interpolation_type());
- node = map_range_node;
+ if (b_map_range_node.data_type() == BL::ShaderNodeMapRange::data_type_FLOAT_VECTOR) {
+ VectorMapRangeNode *vector_map_range_node = graph->create_node<VectorMapRangeNode>();
+ vector_map_range_node->set_use_clamp(b_map_range_node.clamp());
+ vector_map_range_node->set_range_type(
+ (NodeMapRangeType)b_map_range_node.interpolation_type());
+ node = vector_map_range_node;
+ }
+ else {
+ MapRangeNode *map_range_node = graph->create_node<MapRangeNode>();
+ map_range_node->set_clamp(b_map_range_node.clamp());
+ map_range_node->set_range_type((NodeMapRangeType)b_map_range_node.interpolation_type());
+ node = map_range_node;
+ }
}
else if (b_node.is_a(&RNA_ShaderNodeClamp)) {
BL::ShaderNodeClamp b_clamp_node(b_node);
@@ -762,7 +771,8 @@ static ShaderNode *add_node(Scene *scene,
int scene_frame = b_scene.frame_current();
int image_frame = image_user_frame_number(b_image_user, b_image, scene_frame);
image->handle = scene->image_manager->add_image(
- new BlenderImageLoader(b_image, image_frame), image->image_params());
+ new BlenderImageLoader(b_image, image_frame, b_engine.is_preview()),
+ image->image_params());
}
else {
ustring filename = ustring(
@@ -797,8 +807,9 @@ static ShaderNode *add_node(Scene *scene,
if (is_builtin) {
int scene_frame = b_scene.frame_current();
int image_frame = image_user_frame_number(b_image_user, b_image, scene_frame);
- env->handle = scene->image_manager->add_image(new BlenderImageLoader(b_image, image_frame),
- env->image_params());
+ env->handle = scene->image_manager->add_image(
+ new BlenderImageLoader(b_image, image_frame, b_engine.is_preview()),
+ env->image_params());
}
else {
env->set_filename(
diff --git a/intern/cycles/blender/sync.cpp b/intern/cycles/blender/sync.cpp
index 7e40b88cc1a..56137374d8e 100644
--- a/intern/cycles/blender/sync.cpp
+++ b/intern/cycles/blender/sync.cpp
@@ -95,6 +95,11 @@ void BlenderSync::reset(BL::BlendData &b_data, BL::Scene &b_scene)
this->b_scene = b_scene;
}
+void BlenderSync::tag_update()
+{
+ has_updates_ = true;
+}
+
/* Sync */
void BlenderSync::sync_recalc(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d)
@@ -365,8 +370,8 @@ void BlenderSync::sync_integrator(BL::ViewLayer &b_view_layer, bool background)
int samples = get_int(cscene, "samples");
float scrambling_distance = get_float(cscene, "scrambling_distance");
- bool adaptive_scrambling_distance = get_boolean(cscene, "adaptive_scrambling_distance");
- if (adaptive_scrambling_distance) {
+ bool auto_scrambling_distance = get_boolean(cscene, "auto_scrambling_distance");
+ if (auto_scrambling_distance) {
scrambling_distance *= 4.0f / sqrtf(samples);
}
diff --git a/intern/cycles/blender/sync.h b/intern/cycles/blender/sync.h
index 98197564bec..d074f90bb1b 100644
--- a/intern/cycles/blender/sync.h
+++ b/intern/cycles/blender/sync.h
@@ -66,6 +66,8 @@ class BlenderSync {
void reset(BL::BlendData &b_data, BL::Scene &b_scene);
+ void tag_update();
+
/* sync */
void sync_recalc(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d);
void sync_data(BL::RenderSettings &b_render,
@@ -167,12 +169,16 @@ class BlenderSync {
Hair *hair, BL::Mesh &b_mesh, BObjectInfo &b_ob_info, bool motion, int motion_step = 0);
bool object_has_particle_hair(BL::Object b_ob);
+ /* Point Cloud */
+ void sync_pointcloud(PointCloud *pointcloud, BObjectInfo &b_ob_info);
+ void sync_pointcloud_motion(PointCloud *pointcloud, BObjectInfo &b_ob_info, int motion_step = 0);
+
/* Camera */
void sync_camera_motion(
BL::RenderSettings &b_render, BL::Object &b_ob, int width, int height, float motion_time);
/* Geometry */
- Geometry *sync_geometry(BL::Depsgraph &b_depsgrpah,
+ Geometry *sync_geometry(BL::Depsgraph &b_depsgraph,
BObjectInfo &b_ob_info,
bool object_updated,
bool use_particle_hair,
@@ -267,7 +273,6 @@ class BlenderSync {
Progress &progress;
- protected:
/* Indicates that `sync_recalc()` detected changes in the scene.
* If this flag is false then the data is considered to be up-to-date and will not be
* synchronized at all. */
diff --git a/intern/cycles/blender/util.h b/intern/cycles/blender/util.h
index 33fd2c416c8..be36bcdaaa8 100644
--- a/intern/cycles/blender/util.h
+++ b/intern/cycles/blender/util.h
@@ -303,7 +303,7 @@ static inline string image_user_file_path(BL::ImageUser &iuser,
string filepath_str = string(filepath);
if (load_tiled && ima.source() == BL::Image::source_TILED) {
string udim;
- if (ima.tiles.length() > 0) {
+ if (!ima.tiles.empty()) {
udim = to_string(ima.tiles[0].number());
}
string_replace(filepath_str, udim, "<UDIM>");
@@ -647,7 +647,7 @@ static inline Mesh::SubdivisionType object_subdivision_type(BL::Object &b_ob,
{
PointerRNA cobj = RNA_pointer_get(&b_ob.ptr, "cycles");
- if (cobj.data && b_ob.modifiers.length() > 0 && experimental) {
+ if (cobj.data && !b_ob.modifiers.empty() && experimental) {
BL::Modifier mod = b_ob.modifiers[b_ob.modifiers.length() - 1];
bool enabled = preview ? mod.show_viewport() : mod.show_render();
diff --git a/intern/cycles/bvh/CMakeLists.txt b/intern/cycles/bvh/CMakeLists.txt
index 9edc30cf9c4..b5c80f78f09 100644
--- a/intern/cycles/bvh/CMakeLists.txt
+++ b/intern/cycles/bvh/CMakeLists.txt
@@ -33,6 +33,17 @@ set(SRC
unaligned.cpp
)
+set(SRC_METAL
+ metal.mm
+)
+
+if(WITH_CYCLES_DEVICE_METAL)
+ list(APPEND SRC
+ ${SRC_METAL}
+ )
+ add_definitions(-DWITH_METAL)
+endif()
+
set(SRC_HEADERS
bvh.h
bvh2.h
@@ -46,6 +57,7 @@ set(SRC_HEADERS
sort.h
split.h
unaligned.h
+ metal.h
)
set(LIB
diff --git a/intern/cycles/bvh/build.cpp b/intern/cycles/bvh/build.cpp
index 3ce268dfb25..91198e4e2a2 100644
--- a/intern/cycles/bvh/build.cpp
+++ b/intern/cycles/bvh/build.cpp
@@ -26,6 +26,7 @@
#include "scene/hair.h"
#include "scene/mesh.h"
#include "scene/object.h"
+#include "scene/pointcloud.h"
#include "scene/scene.h"
#include "util/algorithm.h"
@@ -113,9 +114,9 @@ void BVHBuild::add_reference_triangles(BoundBox &root,
else {
/* Motion triangles, trace optimized case: we split triangle
* primitives into separate nodes for each of the time steps.
- * This way we minimize overlap of neighbor curve primitives.
+ * This way we minimize overlap of neighbor triangle primitives.
*/
- const int num_bvh_steps = params.num_motion_curve_steps * 2 + 1;
+ const int num_bvh_steps = params.num_motion_triangle_steps * 2 + 1;
const float num_bvh_steps_inv_1 = 1.0f / (num_bvh_steps - 1);
const size_t num_verts = mesh->verts.size();
const size_t num_steps = mesh->motion_steps;
@@ -269,6 +270,101 @@ void BVHBuild::add_reference_curves(BoundBox &root, BoundBox &center, Hair *hair
}
}
+void BVHBuild::add_reference_points(BoundBox &root,
+ BoundBox &center,
+ PointCloud *pointcloud,
+ int i)
+{
+ const Attribute *point_attr_mP = NULL;
+ if (pointcloud->has_motion_blur()) {
+ point_attr_mP = pointcloud->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ }
+
+ const float3 *points_data = &pointcloud->points[0];
+ const float *radius_data = &pointcloud->radius[0];
+ const size_t num_points = pointcloud->num_points();
+ const float3 *motion_data = (point_attr_mP) ? point_attr_mP->data_float3() : NULL;
+ const size_t num_steps = pointcloud->get_motion_steps();
+
+ if (point_attr_mP == NULL) {
+ /* Really simple logic for static points. */
+ for (uint j = 0; j < num_points; j++) {
+ const PointCloud::Point point = pointcloud->get_point(j);
+ BoundBox bounds = BoundBox::empty;
+ point.bounds_grow(points_data, radius_data, bounds);
+ if (bounds.valid()) {
+ references.push_back(BVHReference(bounds, j, i, PRIMITIVE_POINT));
+ root.grow(bounds);
+ center.grow(bounds.center2());
+ }
+ }
+ }
+ else if (params.num_motion_point_steps == 0 || params.use_spatial_split) {
+ /* Simple case of motion points: single node for the whole
+ * shutter time. Lowest memory usage but less optimal
+ * rendering.
+ */
+ /* TODO(sergey): Support motion steps for spatially split BVH. */
+ for (uint j = 0; j < num_points; j++) {
+ const PointCloud::Point point = pointcloud->get_point(j);
+ BoundBox bounds = BoundBox::empty;
+ point.bounds_grow(points_data, radius_data, bounds);
+ for (size_t step = 0; step < num_steps - 1; step++) {
+ point.bounds_grow(motion_data + step * num_points, radius_data, bounds);
+ }
+ if (bounds.valid()) {
+ references.push_back(BVHReference(bounds, j, i, PRIMITIVE_MOTION_POINT));
+ root.grow(bounds);
+ center.grow(bounds.center2());
+ }
+ }
+ }
+ else {
+ /* Motion points, trace optimized case: we split point
+ * primitives into separate nodes for each of the time steps.
+ * This way we minimize overlap of neighbor point primitives.
+ */
+ const int num_bvh_steps = params.num_motion_point_steps * 2 + 1;
+ const float num_bvh_steps_inv_1 = 1.0f / (num_bvh_steps - 1);
+
+ for (uint j = 0; j < num_points; j++) {
+ const PointCloud::Point point = pointcloud->get_point(j);
+ const size_t num_steps = pointcloud->get_motion_steps();
+ const float3 *point_steps = point_attr_mP->data_float3();
+
+ /* Calculate bounding box of the previous time step.
+ * Will be reused later to avoid duplicated work on
+ * calculating BVH time step boundbox.
+ */
+ float4 prev_key = point.motion_key(
+ points_data, radius_data, point_steps, num_points, num_steps, 0.0f, j);
+ BoundBox prev_bounds = BoundBox::empty;
+ point.bounds_grow(prev_key, prev_bounds);
+ /* Create all primitive time steps, */
+ for (int bvh_step = 1; bvh_step < num_bvh_steps; ++bvh_step) {
+ const float curr_time = (float)(bvh_step)*num_bvh_steps_inv_1;
+ float4 curr_key = point.motion_key(
+ points_data, radius_data, point_steps, num_points, num_steps, curr_time, j);
+ BoundBox curr_bounds = BoundBox::empty;
+ point.bounds_grow(curr_key, curr_bounds);
+ BoundBox bounds = prev_bounds;
+ bounds.grow(curr_bounds);
+ if (bounds.valid()) {
+ const float prev_time = (float)(bvh_step - 1) * num_bvh_steps_inv_1;
+ references.push_back(
+ BVHReference(bounds, j, i, PRIMITIVE_MOTION_POINT, prev_time, curr_time));
+ root.grow(bounds);
+ center.grow(bounds.center2());
+ }
+ /* Current time boundbox becomes previous one for the
+ * next time step.
+ */
+ prev_bounds = curr_bounds;
+ }
+ }
+ }
+}
+
void BVHBuild::add_reference_geometry(BoundBox &root,
BoundBox &center,
Geometry *geom,
@@ -282,6 +378,10 @@ void BVHBuild::add_reference_geometry(BoundBox &root,
Hair *hair = static_cast<Hair *>(geom);
add_reference_curves(root, center, hair, object_index);
}
+ else if (geom->geometry_type == Geometry::POINTCLOUD) {
+ PointCloud *pointcloud = static_cast<PointCloud *>(geom);
+ add_reference_points(root, center, pointcloud, object_index);
+ }
}
void BVHBuild::add_reference_object(BoundBox &root, BoundBox &center, Object *ob, int i)
@@ -311,6 +411,10 @@ static size_t count_primitives(Geometry *geom)
Hair *hair = static_cast<Hair *>(geom);
return count_curve_segments(hair);
}
+ else if (geom->geometry_type == Geometry::POINTCLOUD) {
+ PointCloud *pointcloud = static_cast<PointCloud *>(geom);
+ return pointcloud->num_points();
+ }
return 0;
}
@@ -328,8 +432,9 @@ void BVHBuild::add_references(BVHRange &root)
if (!ob->get_geometry()->is_instanced()) {
num_alloc_references += count_primitives(ob->get_geometry());
}
- else
+ else {
num_alloc_references++;
+ }
}
else {
num_alloc_references += count_primitives(ob->get_geometry());
@@ -394,7 +499,7 @@ BVHNode *BVHBuild::run()
spatial_min_overlap = root.bounds().safe_area() * params.spatial_split_alpha;
spatial_free_index = 0;
- need_prim_time = params.num_motion_curve_steps > 0 || params.num_motion_triangle_steps > 0;
+ need_prim_time = params.use_motion_steps();
/* init progress updates */
double build_start_time;
@@ -535,7 +640,8 @@ bool BVHBuild::range_within_max_leaf_size(const BVHRange &range,
const vector<BVHReference> &references) const
{
size_t size = range.size();
- size_t max_leaf_size = max(params.max_triangle_leaf_size, params.max_curve_leaf_size);
+ size_t max_leaf_size = max(max(params.max_triangle_leaf_size, params.max_curve_leaf_size),
+ params.max_point_leaf_size);
if (size > max_leaf_size)
return false;
@@ -544,6 +650,8 @@ bool BVHBuild::range_within_max_leaf_size(const BVHRange &range,
size_t num_motion_triangles = 0;
size_t num_curves = 0;
size_t num_motion_curves = 0;
+ size_t num_points = 0;
+ size_t num_motion_points = 0;
for (int i = 0; i < size; i++) {
const BVHReference &ref = references[range.start() + i];
@@ -564,12 +672,22 @@ bool BVHBuild::range_within_max_leaf_size(const BVHRange &range,
num_triangles++;
}
}
+ else if (ref.prim_type() & PRIMITIVE_ALL_POINT) {
+ if (ref.prim_type() & PRIMITIVE_ALL_MOTION) {
+ num_motion_points++;
+ }
+ else {
+ num_points++;
+ }
+ }
}
return (num_triangles <= params.max_triangle_leaf_size) &&
(num_motion_triangles <= params.max_motion_triangle_leaf_size) &&
(num_curves <= params.max_curve_leaf_size) &&
- (num_motion_curves <= params.max_motion_curve_leaf_size);
+ (num_motion_curves <= params.max_motion_curve_leaf_size) &&
+ (num_points <= params.max_point_leaf_size) &&
+ (num_motion_points <= params.max_motion_point_leaf_size);
}
/* multithreaded binning builder */
diff --git a/intern/cycles/bvh/build.h b/intern/cycles/bvh/build.h
index 06b318f1ee0..5b9bb59d9f8 100644
--- a/intern/cycles/bvh/build.h
+++ b/intern/cycles/bvh/build.h
@@ -39,6 +39,7 @@ class Geometry;
class Hair;
class Mesh;
class Object;
+class PointCloud;
class Progress;
/* BVH Builder */
@@ -68,6 +69,7 @@ class BVHBuild {
/* Adding references. */
void add_reference_triangles(BoundBox &root, BoundBox &center, Mesh *mesh, int i);
void add_reference_curves(BoundBox &root, BoundBox &center, Hair *hair, int i);
+ void add_reference_points(BoundBox &root, BoundBox &center, PointCloud *pointcloud, int i);
void add_reference_geometry(BoundBox &root, BoundBox &center, Geometry *geom, int i);
void add_reference_object(BoundBox &root, BoundBox &center, Object *ob, int i);
void add_references(BVHRange &root);
diff --git a/intern/cycles/bvh/bvh.cpp b/intern/cycles/bvh/bvh.cpp
index ae6655eb27b..703639e29f3 100644
--- a/intern/cycles/bvh/bvh.cpp
+++ b/intern/cycles/bvh/bvh.cpp
@@ -19,6 +19,7 @@
#include "bvh/bvh2.h"
#include "bvh/embree.h"
+#include "bvh/metal.h"
#include "bvh/multi.h"
#include "bvh/optix.h"
@@ -40,8 +41,12 @@ const char *bvh_layout_name(BVHLayout layout)
return "EMBREE";
case BVH_LAYOUT_OPTIX:
return "OPTIX";
+ case BVH_LAYOUT_METAL:
+ return "METAL";
case BVH_LAYOUT_MULTI_OPTIX:
+ case BVH_LAYOUT_MULTI_METAL:
case BVH_LAYOUT_MULTI_OPTIX_EMBREE:
+ case BVH_LAYOUT_MULTI_METAL_EMBREE:
return "MULTI";
case BVH_LAYOUT_ALL:
return "ALL";
@@ -103,8 +108,17 @@ BVH *BVH::create(const BVHParams &params,
(void)device;
break;
#endif
+ case BVH_LAYOUT_METAL:
+#ifdef WITH_METAL
+ return bvh_metal_create(params, geometry, objects, device);
+#else
+ (void)device;
+ break;
+#endif
case BVH_LAYOUT_MULTI_OPTIX:
+ case BVH_LAYOUT_MULTI_METAL:
case BVH_LAYOUT_MULTI_OPTIX_EMBREE:
+ case BVH_LAYOUT_MULTI_METAL_EMBREE:
return new BVHMulti(params, geometry, objects);
case BVH_LAYOUT_NONE:
case BVH_LAYOUT_ALL:
diff --git a/intern/cycles/bvh/bvh2.cpp b/intern/cycles/bvh/bvh2.cpp
index 04290602145..744e7fa9898 100644
--- a/intern/cycles/bvh/bvh2.cpp
+++ b/intern/cycles/bvh/bvh2.cpp
@@ -20,6 +20,7 @@
#include "scene/hair.h"
#include "scene/mesh.h"
#include "scene/object.h"
+#include "scene/pointcloud.h"
#include "bvh/build.h"
#include "bvh/node.h"
@@ -409,6 +410,30 @@ void BVH2::refit_primitives(int start, int end, BoundBox &bbox, uint &visibility
}
}
}
+ else if (pack.prim_type[prim] & PRIMITIVE_ALL_POINT) {
+ /* Points. */
+ const PointCloud *pointcloud = static_cast<const PointCloud *>(ob->get_geometry());
+ int prim_offset = (params.top_level) ? pointcloud->prim_offset : 0;
+ const float3 *points = &pointcloud->points[0];
+ const float *radius = &pointcloud->radius[0];
+ PointCloud::Point point = pointcloud->get_point(pidx - prim_offset);
+
+ point.bounds_grow(points, radius, bbox);
+
+ /* Motion points. */
+ if (pointcloud->get_use_motion_blur()) {
+ Attribute *attr = pointcloud->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+
+ if (attr) {
+ size_t pointcloud_size = pointcloud->points.size();
+ size_t steps = pointcloud->get_motion_steps() - 1;
+ float3 *point_steps = attr->data_float3();
+
+ for (size_t i = 0; i < steps; i++)
+ point.bounds_grow(point_steps + i * pointcloud_size, radius, bbox);
+ }
+ }
+ }
else {
/* Triangles. */
const Mesh *mesh = static_cast<const Mesh *>(ob->get_geometry());
@@ -505,7 +530,8 @@ void BVH2::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
pack.leaf_nodes.resize(leaf_nodes_size);
pack.object_node.resize(objects.size());
- if (params.num_motion_curve_steps > 0 || params.num_motion_triangle_steps > 0) {
+ if (params.num_motion_curve_steps > 0 || params.num_motion_triangle_steps > 0 ||
+ params.num_motion_point_steps > 0) {
pack.prim_time.resize(prim_index_size);
}
diff --git a/intern/cycles/bvh/embree.cpp b/intern/cycles/bvh/embree.cpp
index b54b38f2798..eab193f45cb 100644
--- a/intern/cycles/bvh/embree.cpp
+++ b/intern/cycles/bvh/embree.cpp
@@ -45,6 +45,7 @@
# include "scene/hair.h"
# include "scene/mesh.h"
# include "scene/object.h"
+# include "scene/pointcloud.h"
# include "util/foreach.h"
# include "util/log.h"
@@ -245,7 +246,7 @@ static void rtc_filter_occluded_func(const RTCFilterFunctionNArguments *args)
}
}
-static void rtc_filter_func_thick_curve(const RTCFilterFunctionNArguments *args)
+static void rtc_filter_func_backface_cull(const RTCFilterFunctionNArguments *args)
{
const RTCRay *ray = (RTCRay *)args->ray;
RTCHit *hit = (RTCHit *)args->hit;
@@ -258,7 +259,7 @@ static void rtc_filter_func_thick_curve(const RTCFilterFunctionNArguments *args)
}
}
-static void rtc_filter_occluded_func_thick_curve(const RTCFilterFunctionNArguments *args)
+static void rtc_filter_occluded_func_backface_cull(const RTCFilterFunctionNArguments *args)
{
const RTCRay *ray = (RTCRay *)args->ray;
RTCHit *hit = (RTCHit *)args->hit;
@@ -410,6 +411,12 @@ void BVHEmbree::add_object(Object *ob, int i)
add_curves(ob, hair, i);
}
}
+ else if (geom->geometry_type == Geometry::POINTCLOUD) {
+ PointCloud *pointcloud = static_cast<PointCloud *>(geom);
+ if (pointcloud->num_points() > 0) {
+ add_points(ob, pointcloud, i);
+ }
+ }
}
void BVHEmbree::add_instance(Object *ob, int i)
@@ -624,6 +631,89 @@ void BVHEmbree::set_curve_vertex_buffer(RTCGeometry geom_id, const Hair *hair, c
}
}
+void BVHEmbree::set_point_vertex_buffer(RTCGeometry geom_id,
+ const PointCloud *pointcloud,
+ const bool update)
+{
+ const Attribute *attr_mP = NULL;
+ size_t num_motion_steps = 1;
+ if (pointcloud->has_motion_blur()) {
+ attr_mP = pointcloud->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ if (attr_mP) {
+ num_motion_steps = pointcloud->get_motion_steps();
+ }
+ }
+
+ const size_t num_points = pointcloud->num_points();
+
+ /* Copy the point data to Embree */
+ const int t_mid = (num_motion_steps - 1) / 2;
+ const float *radius = pointcloud->get_radius().data();
+ for (int t = 0; t < num_motion_steps; ++t) {
+ const float3 *verts;
+ if (t == t_mid || attr_mP == NULL) {
+ verts = pointcloud->get_points().data();
+ }
+ else {
+ int t_ = (t > t_mid) ? (t - 1) : t;
+ verts = &attr_mP->data_float3()[t_ * num_points];
+ }
+
+ float4 *rtc_verts = (update) ? (float4 *)rtcGetGeometryBufferData(
+ geom_id, RTC_BUFFER_TYPE_VERTEX, t) :
+ (float4 *)rtcSetNewGeometryBuffer(geom_id,
+ RTC_BUFFER_TYPE_VERTEX,
+ t,
+ RTC_FORMAT_FLOAT4,
+ sizeof(float) * 4,
+ num_points);
+
+ assert(rtc_verts);
+ if (rtc_verts) {
+ for (size_t j = 0; j < num_points; ++j) {
+ rtc_verts[j] = float3_to_float4(verts[j]);
+ rtc_verts[j].w = radius[j];
+ }
+ }
+
+ if (update) {
+ rtcUpdateGeometryBuffer(geom_id, RTC_BUFFER_TYPE_VERTEX, t);
+ }
+ }
+}
+
+void BVHEmbree::add_points(const Object *ob, const PointCloud *pointcloud, int i)
+{
+ size_t prim_offset = pointcloud->prim_offset;
+
+ const Attribute *attr_mP = NULL;
+ size_t num_motion_steps = 1;
+ if (pointcloud->has_motion_blur()) {
+ attr_mP = pointcloud->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ if (attr_mP) {
+ num_motion_steps = pointcloud->get_motion_steps();
+ }
+ }
+
+ enum RTCGeometryType type = RTC_GEOMETRY_TYPE_SPHERE_POINT;
+
+ RTCGeometry geom_id = rtcNewGeometry(rtc_device, type);
+
+ rtcSetGeometryBuildQuality(geom_id, build_quality);
+ rtcSetGeometryTimeStepCount(geom_id, num_motion_steps);
+
+ set_point_vertex_buffer(geom_id, pointcloud, false);
+
+ rtcSetGeometryUserData(geom_id, (void *)prim_offset);
+ rtcSetGeometryIntersectFilterFunction(geom_id, rtc_filter_func_backface_cull);
+ rtcSetGeometryOccludedFilterFunction(geom_id, rtc_filter_occluded_func_backface_cull);
+ rtcSetGeometryMask(geom_id, ob->visibility_for_tracing());
+
+ rtcCommitGeometry(geom_id);
+ rtcAttachGeometryByID(scene, geom_id, i * 2);
+ rtcReleaseGeometry(geom_id);
+}
+
void BVHEmbree::add_curves(const Object *ob, const Hair *hair, int i)
{
size_t prim_offset = hair->curve_segment_offset;
@@ -678,8 +768,8 @@ void BVHEmbree::add_curves(const Object *ob, const Hair *hair, int i)
rtcSetGeometryOccludedFilterFunction(geom_id, rtc_filter_occluded_func);
}
else {
- rtcSetGeometryIntersectFilterFunction(geom_id, rtc_filter_func_thick_curve);
- rtcSetGeometryOccludedFilterFunction(geom_id, rtc_filter_occluded_func_thick_curve);
+ rtcSetGeometryIntersectFilterFunction(geom_id, rtc_filter_func_backface_cull);
+ rtcSetGeometryOccludedFilterFunction(geom_id, rtc_filter_occluded_func_backface_cull);
}
rtcSetGeometryMask(geom_id, ob->visibility_for_tracing());
@@ -716,6 +806,14 @@ void BVHEmbree::refit(Progress &progress)
rtcCommitGeometry(geom);
}
}
+ else if (geom->geometry_type == Geometry::POINTCLOUD) {
+ PointCloud *pointcloud = static_cast<PointCloud *>(geom);
+ if (pointcloud->num_points() > 0) {
+ RTCGeometry geom = rtcGetGeometry(scene, geom_id);
+ set_point_vertex_buffer(geom, pointcloud, true);
+ rtcCommitGeometry(geom);
+ }
+ }
}
geom_id += 2;
}
diff --git a/intern/cycles/bvh/embree.h b/intern/cycles/bvh/embree.h
index 746ca97b504..3b30b2bbcf7 100644
--- a/intern/cycles/bvh/embree.h
+++ b/intern/cycles/bvh/embree.h
@@ -33,6 +33,7 @@ CCL_NAMESPACE_BEGIN
class Hair;
class Mesh;
+class PointCloud;
class BVHEmbree : public BVH {
public:
@@ -51,11 +52,15 @@ class BVHEmbree : public BVH {
void add_object(Object *ob, int i);
void add_instance(Object *ob, int i);
void add_curves(const Object *ob, const Hair *hair, int i);
+ void add_points(const Object *ob, const PointCloud *pointcloud, int i);
void add_triangles(const Object *ob, const Mesh *mesh, int i);
private:
void set_tri_vertex_buffer(RTCGeometry geom_id, const Mesh *mesh, const bool update);
void set_curve_vertex_buffer(RTCGeometry geom_id, const Hair *hair, const bool update);
+ void set_point_vertex_buffer(RTCGeometry geom_id,
+ const PointCloud *pointcloud,
+ const bool update);
RTCDevice rtc_device;
enum RTCBuildQuality build_quality;
diff --git a/intern/cycles/bvh/metal.h b/intern/cycles/bvh/metal.h
new file mode 100644
index 00000000000..8de07927e61
--- /dev/null
+++ b/intern/cycles/bvh/metal.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __BVH_METAL_H__
+#define __BVH_METAL_H__
+
+#ifdef WITH_METAL
+
+# include "bvh/bvh.h"
+
+CCL_NAMESPACE_BEGIN
+
+BVH *bvh_metal_create(const BVHParams &params,
+ const vector<Geometry *> &geometry,
+ const vector<Object *> &objects,
+ Device *device);
+
+CCL_NAMESPACE_END
+
+#endif /* WITH_METAL */
+
+#endif /* __BVH_METAL_H__ */
diff --git a/intern/cycles/bvh/metal.mm b/intern/cycles/bvh/metal.mm
new file mode 100644
index 00000000000..90a52012f12
--- /dev/null
+++ b/intern/cycles/bvh/metal.mm
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifdef WITH_METAL
+
+# include "device/metal/bvh.h"
+
+CCL_NAMESPACE_BEGIN
+
+BVH *bvh_metal_create(const BVHParams &params,
+ const vector<Geometry *> &geometry,
+ const vector<Object *> &objects,
+ Device *device)
+{
+ return new BVHMetal(params, geometry, objects, device);
+}
+
+CCL_NAMESPACE_END
+
+#endif /* WITH_METAL */
diff --git a/intern/cycles/bvh/optix.cpp b/intern/cycles/bvh/optix.cpp
index ebc3fa68b97..671e1a42a31 100644
--- a/intern/cycles/bvh/optix.cpp
+++ b/intern/cycles/bvh/optix.cpp
@@ -30,15 +30,17 @@ BVHOptiX::BVHOptiX(const BVHParams &params_,
: BVH(params_, geometry_, objects_),
device(device),
traversable_handle(0),
- as_data(device, params_.top_level ? "optix tlas" : "optix blas", false),
- motion_transform_data(device, "optix motion transform", false)
+ as_data(make_unique<device_only_memory<char>>(
+ device, params.top_level ? "optix tlas" : "optix blas", false)),
+ motion_transform_data(
+ make_unique<device_only_memory<char>>(device, "optix motion transform", false))
{
}
BVHOptiX::~BVHOptiX()
{
- // Acceleration structure memory is delayed freed on device, since deleting the
- // BVH may happen while still being used for rendering.
+ /* Acceleration structure memory is delayed freed on device, since deleting the
+ * BVH may happen while still being used for rendering. */
device->release_optix_bvh(this);
}
diff --git a/intern/cycles/bvh/optix.h b/intern/cycles/bvh/optix.h
index 037e54980bd..cb855d786bf 100644
--- a/intern/cycles/bvh/optix.h
+++ b/intern/cycles/bvh/optix.h
@@ -25,14 +25,16 @@
# include "device/memory.h"
+# include "util/unique_ptr.h"
+
CCL_NAMESPACE_BEGIN
class BVHOptiX : public BVH {
public:
Device *device;
uint64_t traversable_handle;
- device_only_memory<char> as_data;
- device_only_memory<char> motion_transform_data;
+ unique_ptr<device_only_memory<char>> as_data;
+ unique_ptr<device_only_memory<char>> motion_transform_data;
protected:
friend class BVH;
diff --git a/intern/cycles/bvh/params.h b/intern/cycles/bvh/params.h
index 8f185a2640f..16edf2e88e4 100644
--- a/intern/cycles/bvh/params.h
+++ b/intern/cycles/bvh/params.h
@@ -83,6 +83,8 @@ class BVHParams {
int max_motion_triangle_leaf_size;
int max_curve_leaf_size;
int max_motion_curve_leaf_size;
+ int max_point_leaf_size;
+ int max_motion_point_leaf_size;
/* object or mesh level bvh */
bool top_level;
@@ -98,13 +100,13 @@ class BVHParams {
/* Split time range to this number of steps and create leaf node for each
* of this time steps.
*
- * Speeds up rendering of motion curve primitives in the cost of higher
- * memory usage.
+ * Speeds up rendering of motion primitives in the cost of higher memory usage.
*/
- int num_motion_curve_steps;
/* Same as above, but for triangle primitives. */
int num_motion_triangle_steps;
+ int num_motion_curve_steps;
+ int num_motion_point_steps;
/* Same as in SceneParams. */
int bvh_type;
@@ -132,6 +134,8 @@ class BVHParams {
max_motion_triangle_leaf_size = 8;
max_curve_leaf_size = 1;
max_motion_curve_leaf_size = 4;
+ max_point_leaf_size = 8;
+ max_motion_point_leaf_size = 8;
top_level = false;
bvh_layout = BVH_LAYOUT_BVH2;
@@ -139,6 +143,7 @@ class BVHParams {
num_motion_curve_steps = 0;
num_motion_triangle_steps = 0;
+ num_motion_point_steps = 0;
bvh_type = 0;
@@ -166,6 +171,12 @@ class BVHParams {
return (size <= min_leaf_size || level >= MAX_DEPTH);
}
+ bool use_motion_steps()
+ {
+ return num_motion_curve_steps > 0 || num_motion_triangle_steps > 0 ||
+ num_motion_point_steps > 0;
+ }
+
/* Gets best matching BVH.
*
* If the requested layout is supported by the device, it will be used.
diff --git a/intern/cycles/bvh/split.cpp b/intern/cycles/bvh/split.cpp
index 102c50e2979..34d12de97c0 100644
--- a/intern/cycles/bvh/split.cpp
+++ b/intern/cycles/bvh/split.cpp
@@ -23,6 +23,7 @@
#include "scene/hair.h"
#include "scene/mesh.h"
#include "scene/object.h"
+#include "scene/pointcloud.h"
#include "util/algorithm.h"
@@ -426,6 +427,32 @@ void BVHSpatialSplit::split_curve_primitive(const Hair *hair,
}
}
+void BVHSpatialSplit::split_point_primitive(const PointCloud *pointcloud,
+ const Transform *tfm,
+ int prim_index,
+ int dim,
+ float pos,
+ BoundBox &left_bounds,
+ BoundBox &right_bounds)
+{
+ /* No real splitting support for points, assume they are small enough for it
+ * not to matter. */
+ float3 point = pointcloud->get_points()[prim_index];
+
+ if (tfm != NULL) {
+ point = transform_point(tfm, point);
+ }
+ point = get_unaligned_point(point);
+
+ if (point[dim] <= pos) {
+ left_bounds.grow(point);
+ }
+
+ if (point[dim] >= pos) {
+ right_bounds.grow(point);
+ }
+}
+
void BVHSpatialSplit::split_triangle_reference(const BVHReference &ref,
const Mesh *mesh,
int dim,
@@ -453,6 +480,16 @@ void BVHSpatialSplit::split_curve_reference(const BVHReference &ref,
right_bounds);
}
+void BVHSpatialSplit::split_point_reference(const BVHReference &ref,
+ const PointCloud *pointcloud,
+ int dim,
+ float pos,
+ BoundBox &left_bounds,
+ BoundBox &right_bounds)
+{
+ split_point_primitive(pointcloud, NULL, ref.prim_index(), dim, pos, left_bounds, right_bounds);
+}
+
void BVHSpatialSplit::split_object_reference(
const Object *object, int dim, float pos, BoundBox &left_bounds, BoundBox &right_bounds)
{
@@ -475,6 +512,13 @@ void BVHSpatialSplit::split_object_reference(
}
}
}
+ else if (geom->geometry_type == Geometry::POINTCLOUD) {
+ PointCloud *pointcloud = static_cast<PointCloud *>(geom);
+ for (int point_idx = 0; point_idx < pointcloud->num_points(); ++point_idx) {
+ split_point_primitive(
+ pointcloud, &object->get_tfm(), point_idx, dim, pos, left_bounds, right_bounds);
+ }
+ }
}
void BVHSpatialSplit::split_reference(const BVHBuild &builder,
@@ -499,6 +543,10 @@ void BVHSpatialSplit::split_reference(const BVHBuild &builder,
Hair *hair = static_cast<Hair *>(ob->get_geometry());
split_curve_reference(ref, hair, dim, pos, left_bounds, right_bounds);
}
+ else if (ref.prim_type() & PRIMITIVE_ALL_POINT) {
+ PointCloud *pointcloud = static_cast<PointCloud *>(ob->get_geometry());
+ split_point_reference(ref, pointcloud, dim, pos, left_bounds, right_bounds);
+ }
else {
split_object_reference(ob, dim, pos, left_bounds, right_bounds);
}
diff --git a/intern/cycles/bvh/split.h b/intern/cycles/bvh/split.h
index 2650a500ea9..92953c40040 100644
--- a/intern/cycles/bvh/split.h
+++ b/intern/cycles/bvh/split.h
@@ -26,6 +26,7 @@ CCL_NAMESPACE_BEGIN
class BVHBuild;
class Hair;
class Mesh;
+class PointCloud;
struct Transform;
/* Object Split */
@@ -123,6 +124,13 @@ class BVHSpatialSplit {
float pos,
BoundBox &left_bounds,
BoundBox &right_bounds);
+ void split_point_primitive(const PointCloud *pointcloud,
+ const Transform *tfm,
+ int prim_index,
+ int dim,
+ float pos,
+ BoundBox &left_bounds,
+ BoundBox &right_bounds);
/* Lower-level functions which calculates boundaries of left and right nodes
* needed for spatial split.
@@ -141,6 +149,12 @@ class BVHSpatialSplit {
float pos,
BoundBox &left_bounds,
BoundBox &right_bounds);
+ void split_point_reference(const BVHReference &ref,
+ const PointCloud *pointcloud,
+ int dim,
+ float pos,
+ BoundBox &left_bounds,
+ BoundBox &right_bounds);
void split_object_reference(
const Object *object, int dim, float pos, BoundBox &left_bounds, BoundBox &right_bounds);
diff --git a/intern/cycles/cmake/external_libs.cmake b/intern/cycles/cmake/external_libs.cmake
index c1244ab740b..f46d18a4926 100644
--- a/intern/cycles/cmake/external_libs.cmake
+++ b/intern/cycles/cmake/external_libs.cmake
@@ -551,4 +551,23 @@ if(NOT WITH_HIP_DYNLOAD)
set(WITH_HIP_DYNLOAD ON)
endif()
+###########################################################################
+# Metal
+###########################################################################
+
+if(WITH_CYCLES_DEVICE_METAL)
+ find_library(METAL_LIBRARY Metal)
+
+ # This file was added in the 12.0 SDK, use it as a way to detect the version.
+ if (METAL_LIBRARY AND NOT EXISTS "${METAL_LIBRARY}/Headers/MTLFunctionStitching.h")
+ message(STATUS "Metal version too old, must be SDK 12.0 or newer, disabling WITH_CYCLES_DEVICE_METAL")
+ set(WITH_CYCLES_DEVICE_METAL OFF)
+ elseif (NOT METAL_LIBRARY)
+ message(STATUS "Metal not found, disabling WITH_CYCLES_DEVICE_METAL")
+ set(WITH_CYCLES_DEVICE_METAL OFF)
+ else()
+ message(STATUS "Found Metal: ${METAL_LIBRARY}")
+ endif()
+endif()
+
unset(_cycles_lib_dir)
diff --git a/intern/cycles/device/CMakeLists.txt b/intern/cycles/device/CMakeLists.txt
index 99b1fc8135d..7f1e9ff3d0f 100644
--- a/intern/cycles/device/CMakeLists.txt
+++ b/intern/cycles/device/CMakeLists.txt
@@ -43,7 +43,7 @@ if(WITH_CYCLES_DEVICE_HIP AND WITH_HIP_DYNLOAD)
add_definitions(-DWITH_HIP_DYNLOAD)
endif()
-set(SRC
+set(SRC_BASE
device.cpp
denoise.cpp
graphics_interop.cpp
@@ -104,6 +104,21 @@ set(SRC_MULTI
multi/device.h
)
+set(SRC_METAL
+ metal/bvh.mm
+ metal/bvh.h
+ metal/device.mm
+ metal/device.h
+ metal/device_impl.mm
+ metal/device_impl.h
+ metal/kernel.mm
+ metal/kernel.h
+ metal/queue.mm
+ metal/queue.h
+ metal/util.mm
+ metal/util.h
+)
+
set(SRC_OPTIX
optix/device.cpp
optix/device.h
@@ -123,6 +138,17 @@ set(SRC_HEADERS
queue.h
)
+set(SRC
+ ${SRC_BASE}
+ ${SRC_CPU}
+ ${SRC_CUDA}
+ ${SRC_HIP}
+ ${SRC_DUMMY}
+ ${SRC_MULTI}
+ ${SRC_OPTIX}
+ ${SRC_HEADERS}
+)
+
set(LIB
cycles_kernel
cycles_util
@@ -158,6 +184,15 @@ endif()
if(WITH_CYCLES_DEVICE_OPTIX)
add_definitions(-DWITH_OPTIX)
endif()
+if(WITH_CYCLES_DEVICE_METAL)
+ list(APPEND LIB
+ ${METAL_LIBRARY}
+ )
+ add_definitions(-DWITH_METAL)
+ list(APPEND SRC
+ ${SRC_METAL}
+ )
+endif()
if(WITH_OPENIMAGEDENOISE)
list(APPEND LIB
@@ -168,20 +203,12 @@ endif()
include_directories(${INC})
include_directories(SYSTEM ${INC_SYS})
-cycles_add_library(cycles_device "${LIB}"
- ${SRC}
- ${SRC_CPU}
- ${SRC_CUDA}
- ${SRC_HIP}
- ${SRC_DUMMY}
- ${SRC_MULTI}
- ${SRC_OPTIX}
- ${SRC_HEADERS}
-)
+cycles_add_library(cycles_device "${LIB}" ${SRC})
source_group("cpu" FILES ${SRC_CPU})
source_group("cuda" FILES ${SRC_CUDA})
source_group("dummy" FILES ${SRC_DUMMY})
source_group("multi" FILES ${SRC_MULTI})
+source_group("metal" FILES ${SRC_METAL})
source_group("optix" FILES ${SRC_OPTIX})
source_group("common" FILES ${SRC} ${SRC_HEADERS})
diff --git a/intern/cycles/device/cpu/device_impl.cpp b/intern/cycles/device/cpu/device_impl.cpp
index 2ad76de70ca..6f3c8b42124 100644
--- a/intern/cycles/device/cpu/device_impl.cpp
+++ b/intern/cycles/device/cpu/device_impl.cpp
@@ -129,8 +129,7 @@ void CPUDevice::mem_alloc(device_memory &mem)
<< string_human_readable_size(mem.memory_size()) << ")";
}
- if (mem.type == MEM_DEVICE_ONLY) {
- assert(!mem.host_pointer);
+ if (mem.type == MEM_DEVICE_ONLY || !mem.host_pointer) {
size_t alignment = MIN_ALIGNMENT_CPU_DATA_TYPES;
void *data = util_aligned_malloc(mem.memory_size(), alignment);
mem.device_pointer = (device_ptr)data;
@@ -189,7 +188,7 @@ void CPUDevice::mem_free(device_memory &mem)
tex_free((device_texture &)mem);
}
else if (mem.device_pointer) {
- if (mem.type == MEM_DEVICE_ONLY) {
+ if (mem.type == MEM_DEVICE_ONLY || !mem.host_pointer) {
util_aligned_free((void *)mem.device_pointer);
}
mem.device_pointer = 0;
@@ -274,7 +273,8 @@ void CPUDevice::build_bvh(BVH *bvh, Progress &progress, bool refit)
{
#ifdef WITH_EMBREE
if (bvh->params.bvh_layout == BVH_LAYOUT_EMBREE ||
- bvh->params.bvh_layout == BVH_LAYOUT_MULTI_OPTIX_EMBREE) {
+ bvh->params.bvh_layout == BVH_LAYOUT_MULTI_OPTIX_EMBREE ||
+ bvh->params.bvh_layout == BVH_LAYOUT_MULTI_METAL_EMBREE) {
BVHEmbree *const bvh_embree = static_cast<BVHEmbree *>(bvh);
if (refit) {
bvh_embree->refit(progress);
diff --git a/intern/cycles/device/cuda/device_impl.cpp b/intern/cycles/device/cuda/device_impl.cpp
index f7b3c5ad77f..8d022040414 100644
--- a/intern/cycles/device/cuda/device_impl.cpp
+++ b/intern/cycles/device/cuda/device_impl.cpp
@@ -477,10 +477,10 @@ void CUDADevice::reserve_local_memory(const uint kernel_features)
* still to make it faster. */
CUDADeviceQueue queue(this);
- void *d_path_index = nullptr;
- void *d_render_buffer = nullptr;
+ device_ptr d_path_index = 0;
+ device_ptr d_render_buffer = 0;
int d_work_size = 0;
- void *args[] = {&d_path_index, &d_render_buffer, &d_work_size};
+ DeviceKernelArguments args(&d_path_index, &d_render_buffer, &d_work_size);
queue.init_execution();
queue.enqueue(test_kernel, 1, args);
@@ -678,7 +678,7 @@ CUDADevice::CUDAMem *CUDADevice::generic_alloc(device_memory &mem, size_t pitch_
void *shared_pointer = 0;
- if (mem_alloc_result != CUDA_SUCCESS && can_map_host) {
+ if (mem_alloc_result != CUDA_SUCCESS && can_map_host && mem.type != MEM_DEVICE_ONLY) {
if (mem.shared_pointer) {
/* Another device already allocated host memory. */
mem_alloc_result = CUDA_SUCCESS;
@@ -701,8 +701,14 @@ CUDADevice::CUDAMem *CUDADevice::generic_alloc(device_memory &mem, size_t pitch_
}
if (mem_alloc_result != CUDA_SUCCESS) {
- status = " failed, out of device and host memory";
- set_error("System is out of GPU and shared host memory");
+ if (mem.type == MEM_DEVICE_ONLY) {
+ status = " failed, out of device memory";
+ set_error("System is out of GPU memory");
+ }
+ else {
+ status = " failed, out of device and host memory";
+ set_error("System is out of GPU and shared host memory");
+ }
}
if (mem.name) {
@@ -775,6 +781,7 @@ void CUDADevice::generic_free(device_memory &mem)
if (mem.device_pointer) {
CUDAContextScope scope(this);
thread_scoped_lock lock(cuda_mem_map_mutex);
+ DCHECK(cuda_mem_map.find(&mem) != cuda_mem_map.end());
const CUDAMem &cmem = cuda_mem_map[&mem];
/* If cmem.use_mapped_host is true, reference counting is used
@@ -1141,6 +1148,7 @@ void CUDADevice::tex_free(device_texture &mem)
if (mem.device_pointer) {
CUDAContextScope scope(this);
thread_scoped_lock lock(cuda_mem_map_mutex);
+ DCHECK(cuda_mem_map.find(&mem) != cuda_mem_map.end());
const CUDAMem &cmem = cuda_mem_map[&mem];
if (cmem.texobject) {
diff --git a/intern/cycles/device/cuda/queue.cpp b/intern/cycles/device/cuda/queue.cpp
index 09352a84181..ca57882adbf 100644
--- a/intern/cycles/device/cuda/queue.cpp
+++ b/intern/cycles/device/cuda/queue.cpp
@@ -89,7 +89,9 @@ bool CUDADeviceQueue::kernel_available(DeviceKernel kernel) const
return cuda_device_->kernels.available(kernel);
}
-bool CUDADeviceQueue::enqueue(DeviceKernel kernel, const int work_size, void *args[])
+bool CUDADeviceQueue::enqueue(DeviceKernel kernel,
+ const int work_size,
+ DeviceKernelArguments const &args)
{
if (cuda_device_->have_error()) {
return false;
@@ -133,7 +135,7 @@ bool CUDADeviceQueue::enqueue(DeviceKernel kernel, const int work_size, void *ar
1,
shared_mem_bytes,
cuda_stream_,
- args,
+ const_cast<void **>(args.values),
0),
"enqueue");
diff --git a/intern/cycles/device/cuda/queue.h b/intern/cycles/device/cuda/queue.h
index 28613cda071..0836af12098 100644
--- a/intern/cycles/device/cuda/queue.h
+++ b/intern/cycles/device/cuda/queue.h
@@ -42,7 +42,9 @@ class CUDADeviceQueue : public DeviceQueue {
virtual bool kernel_available(DeviceKernel kernel) const override;
- virtual bool enqueue(DeviceKernel kernel, const int work_size, void *args[]) override;
+ virtual bool enqueue(DeviceKernel kernel,
+ const int work_size,
+ DeviceKernelArguments const &args) override;
virtual bool synchronize() override;
diff --git a/intern/cycles/device/device.cpp b/intern/cycles/device/device.cpp
index bfbcdb20d5e..2b067d57158 100644
--- a/intern/cycles/device/device.cpp
+++ b/intern/cycles/device/device.cpp
@@ -27,6 +27,7 @@
#include "device/cuda/device.h"
#include "device/dummy/device.h"
#include "device/hip/device.h"
+#include "device/metal/device.h"
#include "device/multi/device.h"
#include "device/optix/device.h"
@@ -49,6 +50,7 @@ vector<DeviceInfo> Device::cuda_devices;
vector<DeviceInfo> Device::optix_devices;
vector<DeviceInfo> Device::cpu_devices;
vector<DeviceInfo> Device::hip_devices;
+vector<DeviceInfo> Device::metal_devices;
uint Device::devices_initialized_mask = 0;
/* Device */
@@ -105,6 +107,12 @@ Device *Device::create(const DeviceInfo &info, Stats &stats, Profiler &profiler)
break;
#endif
+#ifdef WITH_METAL
+ case DEVICE_METAL:
+ if (device_metal_init())
+ device = device_metal_create(info, stats, profiler);
+ break;
+#endif
default:
break;
}
@@ -128,6 +136,8 @@ DeviceType Device::type_from_string(const char *name)
return DEVICE_MULTI;
else if (strcmp(name, "HIP") == 0)
return DEVICE_HIP;
+ else if (strcmp(name, "METAL") == 0)
+ return DEVICE_METAL;
return DEVICE_NONE;
}
@@ -144,6 +154,8 @@ string Device::string_from_type(DeviceType type)
return "MULTI";
else if (type == DEVICE_HIP)
return "HIP";
+ else if (type == DEVICE_METAL)
+ return "METAL";
return "";
}
@@ -161,7 +173,9 @@ vector<DeviceType> Device::available_types()
#ifdef WITH_HIP
types.push_back(DEVICE_HIP);
#endif
-
+#ifdef WITH_METAL
+ types.push_back(DEVICE_METAL);
+#endif
return types;
}
@@ -227,6 +241,20 @@ vector<DeviceInfo> Device::available_devices(uint mask)
}
}
+#ifdef WITH_METAL
+ if (mask & DEVICE_MASK_METAL) {
+ if (!(devices_initialized_mask & DEVICE_MASK_METAL)) {
+ if (device_metal_init()) {
+ device_metal_info(metal_devices);
+ }
+ devices_initialized_mask |= DEVICE_MASK_METAL;
+ }
+ foreach (DeviceInfo &info, metal_devices) {
+ devices.push_back(info);
+ }
+ }
+#endif
+
return devices;
}
@@ -266,6 +294,15 @@ string Device::device_capabilities(uint mask)
}
#endif
+#ifdef WITH_METAL
+ if (mask & DEVICE_MASK_METAL) {
+ if (device_metal_init()) {
+ capabilities += "\nMetal device capabilities:\n";
+ capabilities += device_metal_capabilities();
+ }
+ }
+#endif
+
return capabilities;
}
@@ -354,6 +391,7 @@ void Device::free_memory()
optix_devices.free_memory();
hip_devices.free_memory();
cpu_devices.free_memory();
+ metal_devices.free_memory();
}
unique_ptr<DeviceQueue> Device::gpu_queue_create()
diff --git a/intern/cycles/device/device.h b/intern/cycles/device/device.h
index 346632de314..c032773ddd0 100644
--- a/intern/cycles/device/device.h
+++ b/intern/cycles/device/device.h
@@ -52,6 +52,7 @@ enum DeviceType {
DEVICE_MULTI,
DEVICE_OPTIX,
DEVICE_HIP,
+ DEVICE_METAL,
DEVICE_DUMMY,
};
@@ -60,6 +61,7 @@ enum DeviceTypeMask {
DEVICE_MASK_CUDA = (1 << DEVICE_CUDA),
DEVICE_MASK_OPTIX = (1 << DEVICE_OPTIX),
DEVICE_MASK_HIP = (1 << DEVICE_HIP),
+ DEVICE_MASK_METAL = (1 << DEVICE_METAL),
DEVICE_MASK_ALL = ~0
};
@@ -281,6 +283,7 @@ class Device {
static vector<DeviceInfo> optix_devices;
static vector<DeviceInfo> cpu_devices;
static vector<DeviceInfo> hip_devices;
+ static vector<DeviceInfo> metal_devices;
static uint devices_initialized_mask;
};
diff --git a/intern/cycles/device/hip/device.cpp b/intern/cycles/device/hip/device.cpp
index 25e932ef080..a9c7b1ba841 100644
--- a/intern/cycles/device/hip/device.cpp
+++ b/intern/cycles/device/hip/device.cpp
@@ -57,9 +57,16 @@ bool device_hip_init()
}
}
else {
- VLOG(1) << "HIPEW initialization failed: "
- << ((hipew_result == HIPEW_ERROR_ATEXIT_FAILED) ? "Error setting up atexit() handler" :
- "Error opening the library");
+ if (hipew_result == HIPEW_ERROR_ATEXIT_FAILED) {
+ VLOG(1) << "HIPEW initialization failed: Error setting up atexit() handler";
+ }
+ else if (hipew_result == HIPEW_ERROR_OLD_DRIVER) {
+ VLOG(1) << "HIPEW initialization failed: Driver version too old, requires AMD Radeon Pro "
+ "21.Q4 driver or newer";
+ }
+ else {
+ VLOG(1) << "HIPEW initialization failed: Error opening HIP dynamic library";
+ }
}
return result;
diff --git a/intern/cycles/device/hip/device_impl.cpp b/intern/cycles/device/hip/device_impl.cpp
index 950fcaf1816..4f1cbabc89b 100644
--- a/intern/cycles/device/hip/device_impl.cpp
+++ b/intern/cycles/device/hip/device_impl.cpp
@@ -93,7 +93,7 @@ HIPDevice::HIPDevice(const DeviceInfo &info, Stats &stats, Profiler &profiler)
}
/* Setup device and context. */
- result = hipGetDevice(&hipDevice, hipDevId);
+ result = hipDeviceGet(&hipDevice, hipDevId);
if (result != hipSuccess) {
set_error(string_printf("Failed to get HIP device handle from ordinal (%s)",
hipewErrorString(result)));
@@ -440,10 +440,10 @@ void HIPDevice::reserve_local_memory(const uint kernel_features)
* still to make it faster. */
HIPDeviceQueue queue(this);
- void *d_path_index = nullptr;
- void *d_render_buffer = nullptr;
+ device_ptr d_path_index = 0;
+ device_ptr d_render_buffer = 0;
int d_work_size = 0;
- void *args[] = {&d_path_index, &d_render_buffer, &d_work_size};
+ DeviceKernelArguments args(&d_path_index, &d_render_buffer, &d_work_size);
queue.init_execution();
queue.enqueue(test_kernel, 1, args);
@@ -738,6 +738,7 @@ void HIPDevice::generic_free(device_memory &mem)
if (mem.device_pointer) {
HIPContextScope scope(this);
thread_scoped_lock lock(hip_mem_map_mutex);
+ DCHECK(hip_mem_map.find(&mem) != hip_mem_map.end());
const HIPMem &cmem = hip_mem_map[&mem];
/* If cmem.use_mapped_host is true, reference counting is used
@@ -980,16 +981,16 @@ void HIPDevice::tex_alloc(device_texture &mem)
<< string_human_readable_number(mem.memory_size()) << " bytes. ("
<< string_human_readable_size(mem.memory_size()) << ")";
- hip_assert(hipArray3DCreate(&array_3d, &desc));
+ hip_assert(hipArray3DCreate((hArray *)&array_3d, &desc));
if (!array_3d) {
return;
}
HIP_MEMCPY3D param;
- memset(&param, 0, sizeof(param));
+ memset(&param, 0, sizeof(HIP_MEMCPY3D));
param.dstMemoryType = hipMemoryTypeArray;
- param.dstArray = &array_3d;
+ param.dstArray = array_3d;
param.srcMemoryType = hipMemoryTypeHost;
param.srcHost = mem.host_pointer;
param.srcPitch = src_pitch;
@@ -1055,12 +1056,13 @@ void HIPDevice::tex_alloc(device_texture &mem)
if (mem.info.data_type != IMAGE_DATA_TYPE_NANOVDB_FLOAT &&
mem.info.data_type != IMAGE_DATA_TYPE_NANOVDB_FLOAT3) {
+ /* Bindless textures. */
hipResourceDesc resDesc;
memset(&resDesc, 0, sizeof(resDesc));
if (array_3d) {
resDesc.resType = hipResourceTypeArray;
- resDesc.res.array.h_Array = &array_3d;
+ resDesc.res.array.h_Array = array_3d;
resDesc.flags = 0;
}
else if (mem.data_height > 0) {
@@ -1105,6 +1107,7 @@ void HIPDevice::tex_free(device_texture &mem)
if (mem.device_pointer) {
HIPContextScope scope(this);
thread_scoped_lock lock(hip_mem_map_mutex);
+ DCHECK(hip_mem_map.find(&mem) != hip_mem_map.end());
const HIPMem &cmem = hip_mem_map[&mem];
if (cmem.texobject) {
diff --git a/intern/cycles/device/hip/queue.cpp b/intern/cycles/device/hip/queue.cpp
index 0f053ccbeb5..81b283e8cf5 100644
--- a/intern/cycles/device/hip/queue.cpp
+++ b/intern/cycles/device/hip/queue.cpp
@@ -89,7 +89,9 @@ bool HIPDeviceQueue::kernel_available(DeviceKernel kernel) const
return hip_device_->kernels.available(kernel);
}
-bool HIPDeviceQueue::enqueue(DeviceKernel kernel, const int work_size, void *args[])
+bool HIPDeviceQueue::enqueue(DeviceKernel kernel,
+ const int work_size,
+ DeviceKernelArguments const &args)
{
if (hip_device_->have_error()) {
return false;
@@ -132,7 +134,7 @@ bool HIPDeviceQueue::enqueue(DeviceKernel kernel, const int work_size, void *arg
1,
shared_mem_bytes,
hip_stream_,
- args,
+ const_cast<void **>(args.values),
0),
"enqueue");
diff --git a/intern/cycles/device/hip/queue.h b/intern/cycles/device/hip/queue.h
index 95d1afaff0f..8040d367798 100644
--- a/intern/cycles/device/hip/queue.h
+++ b/intern/cycles/device/hip/queue.h
@@ -42,7 +42,9 @@ class HIPDeviceQueue : public DeviceQueue {
virtual bool kernel_available(DeviceKernel kernel) const override;
- virtual bool enqueue(DeviceKernel kernel, const int work_size, void *args[]) override;
+ virtual bool enqueue(DeviceKernel kernel,
+ const int work_size,
+ DeviceKernelArguments const &args) override;
virtual bool synchronize() override;
diff --git a/intern/cycles/device/memory.cpp b/intern/cycles/device/memory.cpp
index 259bc2e5334..ba2d993fb9e 100644
--- a/intern/cycles/device/memory.cpp
+++ b/intern/cycles/device/memory.cpp
@@ -44,45 +44,6 @@ device_memory::device_memory(Device *device, const char *name, MemoryType type)
{
}
-device_memory::device_memory(device_memory &&other) noexcept
- : data_type(other.data_type),
- data_elements(other.data_elements),
- data_size(other.data_size),
- device_size(other.device_size),
- data_width(other.data_width),
- data_height(other.data_height),
- data_depth(other.data_depth),
- type(other.type),
- name(other.name),
- device(other.device),
- device_pointer(other.device_pointer),
- host_pointer(other.host_pointer),
- shared_pointer(other.shared_pointer),
- shared_counter(other.shared_counter),
- original_device_ptr(other.original_device_ptr),
- original_device_size(other.original_device_size),
- original_device(other.original_device),
- need_realloc_(other.need_realloc_),
- modified(other.modified)
-{
- other.data_elements = 0;
- other.data_size = 0;
- other.device_size = 0;
- other.data_width = 0;
- other.data_height = 0;
- other.data_depth = 0;
- other.device = 0;
- other.device_pointer = 0;
- other.host_pointer = 0;
- other.shared_pointer = 0;
- other.shared_counter = 0;
- other.original_device_ptr = 0;
- other.original_device_size = 0;
- other.original_device = 0;
- other.need_realloc_ = false;
- other.modified = false;
-}
-
device_memory::~device_memory()
{
assert(shared_pointer == 0);
diff --git a/intern/cycles/device/memory.h b/intern/cycles/device/memory.h
index b2aa88b4e97..2db3ac9a440 100644
--- a/intern/cycles/device/memory.h
+++ b/intern/cycles/device/memory.h
@@ -263,14 +263,20 @@ class device_memory {
friend class CUDADevice;
friend class OptiXDevice;
friend class HIPDevice;
+ friend class MetalDevice;
/* Only create through subclasses. */
device_memory(Device *device, const char *name, MemoryType type);
- device_memory(device_memory &&other) noexcept;
- /* No copying allowed. */
+ /* No copying and allowed.
+ *
+ * This is because device implementation might need to register device memory in an allocation
+ * map of some sort and use pointer as a key to identify blocks. Moving data from one place to
+ * another bypassing device allocation routines will make those maps hard to maintain. */
device_memory(const device_memory &) = delete;
+ device_memory(device_memory &&other) noexcept = delete;
device_memory &operator=(const device_memory &) = delete;
+ device_memory &operator=(device_memory &&) = delete;
/* Host allocation on the device. All host_pointer memory should be
* allocated with these functions, for devices that support using
@@ -576,7 +582,7 @@ template<typename T> class device_vector : public device_memory {
* from an already allocated base memory. It is freed automatically when it
* goes out of scope, which should happen before base memory is freed.
*
- * Note: some devices require offset and size of the sub_ptr to be properly
+ * NOTE: some devices require offset and size of the sub_ptr to be properly
* aligned to device->mem_address_alingment(). */
class device_sub_ptr {
diff --git a/intern/cycles/device/metal/bvh.h b/intern/cycles/device/metal/bvh.h
new file mode 100644
index 00000000000..cbc5ca7d2c3
--- /dev/null
+++ b/intern/cycles/device/metal/bvh.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#ifdef WITH_METAL
+
+# include "bvh/bvh.h"
+# include "bvh/params.h"
+# include "device/memory.h"
+
+# include <Metal/Metal.h>
+
+CCL_NAMESPACE_BEGIN
+
+class BVHMetal : public BVH {
+ public:
+ API_AVAILABLE(macos(11.0))
+ id<MTLAccelerationStructure> accel_struct = nil;
+ bool accel_struct_building = false;
+
+ API_AVAILABLE(macos(11.0))
+ vector<id<MTLAccelerationStructure>> blas_array;
+
+ bool motion_blur = false;
+
+ Stats &stats;
+
+ bool build(Progress &progress, id<MTLDevice> device, id<MTLCommandQueue> queue, bool refit);
+
+ BVHMetal(const BVHParams &params,
+ const vector<Geometry *> &geometry,
+ const vector<Object *> &objects,
+ Device *device);
+ virtual ~BVHMetal();
+
+ bool build_BLAS(Progress &progress, id<MTLDevice> device, id<MTLCommandQueue> queue, bool refit);
+ bool build_BLAS_mesh(Progress &progress,
+ id<MTLDevice> device,
+ id<MTLCommandQueue> queue,
+ Geometry *const geom,
+ bool refit);
+ bool build_BLAS_hair(Progress &progress,
+ id<MTLDevice> device,
+ id<MTLCommandQueue> queue,
+ Geometry *const geom,
+ bool refit);
+ bool build_TLAS(Progress &progress, id<MTLDevice> device, id<MTLCommandQueue> queue, bool refit);
+};
+
+CCL_NAMESPACE_END
+
+#endif /* WITH_METAL */
diff --git a/intern/cycles/device/metal/bvh.mm b/intern/cycles/device/metal/bvh.mm
new file mode 100644
index 00000000000..1953102cb41
--- /dev/null
+++ b/intern/cycles/device/metal/bvh.mm
@@ -0,0 +1,813 @@
+/*
+ * Copyright 2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifdef WITH_METAL
+
+# include "scene/hair.h"
+# include "scene/mesh.h"
+# include "scene/object.h"
+
+# include "util/progress.h"
+
+# include "device/metal/bvh.h"
+
+CCL_NAMESPACE_BEGIN
+
+# define BVH_status(...) \
+ { \
+ string str = string_printf(__VA_ARGS__); \
+ progress.set_substatus(str); \
+ }
+
+BVHMetal::BVHMetal(const BVHParams &params_,
+ const vector<Geometry *> &geometry_,
+ const vector<Object *> &objects_,
+ Device *device)
+ : BVH(params_, geometry_, objects_), stats(device->stats)
+{
+}
+
+BVHMetal::~BVHMetal()
+{
+ if (@available(macos 12.0, *)) {
+ if (accel_struct) {
+ stats.mem_free(accel_struct.allocatedSize);
+ [accel_struct release];
+ }
+ }
+}
+
+bool BVHMetal::build_BLAS_mesh(Progress &progress,
+ id<MTLDevice> device,
+ id<MTLCommandQueue> queue,
+ Geometry *const geom,
+ bool refit)
+{
+ if (@available(macos 12.0, *)) {
+ /* Build BLAS for triangle primitives */
+ Mesh *const mesh = static_cast<Mesh *const>(geom);
+ if (mesh->num_triangles() == 0) {
+ return false;
+ }
+
+ /*------------------------------------------------*/
+ BVH_status(
+ "Building mesh BLAS | %7d tris | %s", (int)mesh->num_triangles(), geom->name.c_str());
+ /*------------------------------------------------*/
+
+ const bool use_fast_trace_bvh = (params.bvh_type == BVH_TYPE_STATIC);
+
+ const array<float3> &verts = mesh->get_verts();
+ const array<int> &tris = mesh->get_triangles();
+ const size_t num_verts = verts.size();
+ const size_t num_indices = tris.size();
+
+ size_t num_motion_steps = 1;
+ Attribute *motion_keys = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ if (motion_blur && mesh->get_use_motion_blur() && motion_keys) {
+ num_motion_steps = mesh->get_motion_steps();
+ }
+
+ MTLResourceOptions storage_mode;
+ if (device.hasUnifiedMemory) {
+ storage_mode = MTLResourceStorageModeShared;
+ }
+ else {
+ storage_mode = MTLResourceStorageModeManaged;
+ }
+
+ /* Upload the mesh data to the GPU */
+ id<MTLBuffer> posBuf = nil;
+ id<MTLBuffer> indexBuf = [device newBufferWithBytes:tris.data()
+ length:num_indices * sizeof(tris.data()[0])
+ options:storage_mode];
+
+ if (num_motion_steps == 1) {
+ posBuf = [device newBufferWithBytes:verts.data()
+ length:num_verts * sizeof(verts.data()[0])
+ options:storage_mode];
+ }
+ else {
+ posBuf = [device newBufferWithLength:num_verts * num_motion_steps * sizeof(verts.data()[0])
+ options:storage_mode];
+ float3 *dest_data = (float3 *)[posBuf contents];
+ size_t center_step = (num_motion_steps - 1) / 2;
+ for (size_t step = 0; step < num_motion_steps; ++step) {
+ const float3 *verts = mesh->get_verts().data();
+
+ /* The center step for motion vertices is not stored in the attribute. */
+ if (step != center_step) {
+ verts = motion_keys->data_float3() + (step > center_step ? step - 1 : step) * num_verts;
+ }
+ memcpy(dest_data + num_verts * step, verts, num_verts * sizeof(float3));
+ }
+ if (storage_mode == MTLResourceStorageModeManaged) {
+ [posBuf didModifyRange:NSMakeRange(0, posBuf.length)];
+ }
+ }
+
+ /* Create an acceleration structure. */
+ MTLAccelerationStructureGeometryDescriptor *geomDesc;
+ if (num_motion_steps > 1) {
+ std::vector<MTLMotionKeyframeData *> vertex_ptrs;
+ vertex_ptrs.reserve(num_motion_steps);
+ for (size_t step = 0; step < num_motion_steps; ++step) {
+ MTLMotionKeyframeData *k = [MTLMotionKeyframeData data];
+ k.buffer = posBuf;
+ k.offset = num_verts * step * sizeof(float3);
+ vertex_ptrs.push_back(k);
+ }
+
+ MTLAccelerationStructureMotionTriangleGeometryDescriptor *geomDescMotion =
+ [MTLAccelerationStructureMotionTriangleGeometryDescriptor descriptor];
+ geomDescMotion.vertexBuffers = [NSArray arrayWithObjects:vertex_ptrs.data()
+ count:vertex_ptrs.size()];
+ geomDescMotion.vertexStride = sizeof(verts.data()[0]);
+ geomDescMotion.indexBuffer = indexBuf;
+ geomDescMotion.indexBufferOffset = 0;
+ geomDescMotion.indexType = MTLIndexTypeUInt32;
+ geomDescMotion.triangleCount = num_indices / 3;
+ geomDescMotion.intersectionFunctionTableOffset = 0;
+
+ geomDesc = geomDescMotion;
+ }
+ else {
+ MTLAccelerationStructureTriangleGeometryDescriptor *geomDescNoMotion =
+ [MTLAccelerationStructureTriangleGeometryDescriptor descriptor];
+ geomDescNoMotion.vertexBuffer = posBuf;
+ geomDescNoMotion.vertexBufferOffset = 0;
+ geomDescNoMotion.vertexStride = sizeof(verts.data()[0]);
+ geomDescNoMotion.indexBuffer = indexBuf;
+ geomDescNoMotion.indexBufferOffset = 0;
+ geomDescNoMotion.indexType = MTLIndexTypeUInt32;
+ geomDescNoMotion.triangleCount = num_indices / 3;
+ geomDescNoMotion.intersectionFunctionTableOffset = 0;
+
+ geomDesc = geomDescNoMotion;
+ }
+
+ /* Force a single any-hit call, so shadow record-all behavior works correctly */
+ /* (Match optix behavior: unsigned int build_flags =
+ * OPTIX_GEOMETRY_FLAG_REQUIRE_SINGLE_ANYHIT_CALL;) */
+ geomDesc.allowDuplicateIntersectionFunctionInvocation = false;
+
+ MTLPrimitiveAccelerationStructureDescriptor *accelDesc =
+ [MTLPrimitiveAccelerationStructureDescriptor descriptor];
+ accelDesc.geometryDescriptors = @[ geomDesc ];
+ if (num_motion_steps > 1) {
+ accelDesc.motionStartTime = 0.0f;
+ accelDesc.motionEndTime = 1.0f;
+ accelDesc.motionStartBorderMode = MTLMotionBorderModeClamp;
+ accelDesc.motionEndBorderMode = MTLMotionBorderModeClamp;
+ accelDesc.motionKeyframeCount = num_motion_steps;
+ }
+
+ if (!use_fast_trace_bvh) {
+ accelDesc.usage |= (MTLAccelerationStructureUsageRefit |
+ MTLAccelerationStructureUsagePreferFastBuild);
+ }
+
+ MTLAccelerationStructureSizes accelSizes = [device
+ accelerationStructureSizesWithDescriptor:accelDesc];
+ id<MTLAccelerationStructure> accel_uncompressed = [device
+ newAccelerationStructureWithSize:accelSizes.accelerationStructureSize];
+ id<MTLBuffer> scratchBuf = [device newBufferWithLength:accelSizes.buildScratchBufferSize
+ options:MTLResourceStorageModePrivate];
+ id<MTLBuffer> sizeBuf = [device newBufferWithLength:8 options:MTLResourceStorageModeShared];
+ id<MTLCommandBuffer> accelCommands = [queue commandBuffer];
+ id<MTLAccelerationStructureCommandEncoder> accelEnc =
+ [accelCommands accelerationStructureCommandEncoder];
+ if (refit) {
+ [accelEnc refitAccelerationStructure:accel_struct
+ descriptor:accelDesc
+ destination:accel_uncompressed
+ scratchBuffer:scratchBuf
+ scratchBufferOffset:0];
+ }
+ else {
+ [accelEnc buildAccelerationStructure:accel_uncompressed
+ descriptor:accelDesc
+ scratchBuffer:scratchBuf
+ scratchBufferOffset:0];
+ }
+ if (use_fast_trace_bvh) {
+ [accelEnc writeCompactedAccelerationStructureSize:accel_uncompressed
+ toBuffer:sizeBuf
+ offset:0
+ sizeDataType:MTLDataTypeULong];
+ }
+ [accelEnc endEncoding];
+ [accelCommands addCompletedHandler:^(id<MTLCommandBuffer> command_buffer) {
+ /* free temp resources */
+ [scratchBuf release];
+ [indexBuf release];
+ [posBuf release];
+
+ if (use_fast_trace_bvh) {
+ /* Compact the accel structure */
+ uint64_t compressed_size = *(uint64_t *)sizeBuf.contents;
+
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+ id<MTLCommandBuffer> accelCommands = [queue commandBuffer];
+ id<MTLAccelerationStructureCommandEncoder> accelEnc =
+ [accelCommands accelerationStructureCommandEncoder];
+ id<MTLAccelerationStructure> accel = [device
+ newAccelerationStructureWithSize:compressed_size];
+ [accelEnc copyAndCompactAccelerationStructure:accel_uncompressed
+ toAccelerationStructure:accel];
+ [accelEnc endEncoding];
+ [accelCommands addCompletedHandler:^(id<MTLCommandBuffer> command_buffer) {
+ uint64_t allocated_size = [accel allocatedSize];
+ stats.mem_alloc(allocated_size);
+ accel_struct = accel;
+ [accel_uncompressed release];
+ accel_struct_building = false;
+ }];
+ [accelCommands commit];
+ });
+ }
+ else {
+ /* set our acceleration structure to the uncompressed structure */
+ accel_struct = accel_uncompressed;
+
+ uint64_t allocated_size = [accel_struct allocatedSize];
+ stats.mem_alloc(allocated_size);
+ accel_struct_building = false;
+ }
+ [sizeBuf release];
+ }];
+
+ accel_struct_building = true;
+ [accelCommands commit];
+
+ return true;
+ }
+ return false;
+}
+
+bool BVHMetal::build_BLAS_hair(Progress &progress,
+ id<MTLDevice> device,
+ id<MTLCommandQueue> queue,
+ Geometry *const geom,
+ bool refit)
+{
+ if (@available(macos 12.0, *)) {
+ /* Build BLAS for hair curves */
+ Hair *hair = static_cast<Hair *>(geom);
+ if (hair->num_curves() == 0) {
+ return false;
+ }
+
+ /*------------------------------------------------*/
+ BVH_status(
+ "Building hair BLAS | %7d curves | %s", (int)hair->num_curves(), geom->name.c_str());
+ /*------------------------------------------------*/
+
+ const bool use_fast_trace_bvh = (params.bvh_type == BVH_TYPE_STATIC);
+ const size_t num_segments = hair->num_segments();
+
+ size_t num_motion_steps = 1;
+ Attribute *motion_keys = hair->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ if (motion_blur && hair->get_use_motion_blur() && motion_keys) {
+ num_motion_steps = hair->get_motion_steps();
+ }
+
+ const size_t num_aabbs = num_segments * num_motion_steps;
+
+ MTLResourceOptions storage_mode;
+ if (device.hasUnifiedMemory) {
+ storage_mode = MTLResourceStorageModeShared;
+ }
+ else {
+ storage_mode = MTLResourceStorageModeManaged;
+ }
+
+ /* Allocate a GPU buffer for the AABB data and populate it */
+ id<MTLBuffer> aabbBuf = [device
+ newBufferWithLength:num_aabbs * sizeof(MTLAxisAlignedBoundingBox)
+ options:storage_mode];
+ MTLAxisAlignedBoundingBox *aabb_data = (MTLAxisAlignedBoundingBox *)[aabbBuf contents];
+
+ /* Get AABBs for each motion step */
+ size_t center_step = (num_motion_steps - 1) / 2;
+ for (size_t step = 0; step < num_motion_steps; ++step) {
+ /* The center step for motion vertices is not stored in the attribute */
+ const float3 *keys = hair->get_curve_keys().data();
+ if (step != center_step) {
+ size_t attr_offset = (step > center_step) ? step - 1 : step;
+ /* Technically this is a float4 array, but sizeof(float3) == sizeof(float4) */
+ keys = motion_keys->data_float3() + attr_offset * hair->get_curve_keys().size();
+ }
+
+ for (size_t j = 0, i = 0; j < hair->num_curves(); ++j) {
+ const Hair::Curve curve = hair->get_curve(j);
+
+ for (int segment = 0; segment < curve.num_segments(); ++segment, ++i) {
+ {
+ BoundBox bounds = BoundBox::empty;
+ curve.bounds_grow(segment, keys, hair->get_curve_radius().data(), bounds);
+
+ const size_t index = step * num_segments + i;
+ aabb_data[index].min = (MTLPackedFloat3 &)bounds.min;
+ aabb_data[index].max = (MTLPackedFloat3 &)bounds.max;
+ }
+ }
+ }
+ }
+
+ if (storage_mode == MTLResourceStorageModeManaged) {
+ [aabbBuf didModifyRange:NSMakeRange(0, aabbBuf.length)];
+ }
+
+# if 0
+ for (size_t i=0; i<num_aabbs && i < 400; i++) {
+ MTLAxisAlignedBoundingBox& bb = aabb_data[i];
+ printf(" %d: %.1f,%.1f,%.1f -- %.1f,%.1f,%.1f\n", int(i), bb.min.x, bb.min.y, bb.min.z, bb.max.x, bb.max.y, bb.max.z);
+ }
+# endif
+
+ MTLAccelerationStructureGeometryDescriptor *geomDesc;
+ if (motion_blur) {
+ std::vector<MTLMotionKeyframeData *> aabb_ptrs;
+ aabb_ptrs.reserve(num_motion_steps);
+ for (size_t step = 0; step < num_motion_steps; ++step) {
+ MTLMotionKeyframeData *k = [MTLMotionKeyframeData data];
+ k.buffer = aabbBuf;
+ k.offset = step * num_segments * sizeof(MTLAxisAlignedBoundingBox);
+ aabb_ptrs.push_back(k);
+ }
+
+ MTLAccelerationStructureMotionBoundingBoxGeometryDescriptor *geomDescMotion =
+ [MTLAccelerationStructureMotionBoundingBoxGeometryDescriptor descriptor];
+ geomDescMotion.boundingBoxBuffers = [NSArray arrayWithObjects:aabb_ptrs.data()
+ count:aabb_ptrs.size()];
+ geomDescMotion.boundingBoxCount = num_segments;
+ geomDescMotion.boundingBoxStride = sizeof(aabb_data[0]);
+ geomDescMotion.intersectionFunctionTableOffset = 1;
+
+ /* Force a single any-hit call, so shadow record-all behavior works correctly */
+ /* (Match optix behavior: unsigned int build_flags =
+ * OPTIX_GEOMETRY_FLAG_REQUIRE_SINGLE_ANYHIT_CALL;) */
+ geomDescMotion.allowDuplicateIntersectionFunctionInvocation = false;
+ geomDescMotion.opaque = true;
+ geomDesc = geomDescMotion;
+ }
+ else {
+ MTLAccelerationStructureBoundingBoxGeometryDescriptor *geomDescNoMotion =
+ [MTLAccelerationStructureBoundingBoxGeometryDescriptor descriptor];
+ geomDescNoMotion.boundingBoxBuffer = aabbBuf;
+ geomDescNoMotion.boundingBoxBufferOffset = 0;
+ geomDescNoMotion.boundingBoxCount = int(num_aabbs);
+ geomDescNoMotion.boundingBoxStride = sizeof(aabb_data[0]);
+ geomDescNoMotion.intersectionFunctionTableOffset = 1;
+
+ /* Force a single any-hit call, so shadow record-all behavior works correctly */
+ /* (Match optix behavior: unsigned int build_flags =
+ * OPTIX_GEOMETRY_FLAG_REQUIRE_SINGLE_ANYHIT_CALL;) */
+ geomDescNoMotion.allowDuplicateIntersectionFunctionInvocation = false;
+ geomDescNoMotion.opaque = true;
+ geomDesc = geomDescNoMotion;
+ }
+
+ MTLPrimitiveAccelerationStructureDescriptor *accelDesc =
+ [MTLPrimitiveAccelerationStructureDescriptor descriptor];
+ accelDesc.geometryDescriptors = @[ geomDesc ];
+
+ if (motion_blur) {
+ accelDesc.motionStartTime = 0.0f;
+ accelDesc.motionEndTime = 1.0f;
+ accelDesc.motionStartBorderMode = MTLMotionBorderModeVanish;
+ accelDesc.motionEndBorderMode = MTLMotionBorderModeVanish;
+ accelDesc.motionKeyframeCount = num_motion_steps;
+ }
+
+ if (!use_fast_trace_bvh) {
+ accelDesc.usage |= (MTLAccelerationStructureUsageRefit |
+ MTLAccelerationStructureUsagePreferFastBuild);
+ }
+
+ MTLAccelerationStructureSizes accelSizes = [device
+ accelerationStructureSizesWithDescriptor:accelDesc];
+ id<MTLAccelerationStructure> accel_uncompressed = [device
+ newAccelerationStructureWithSize:accelSizes.accelerationStructureSize];
+ id<MTLBuffer> scratchBuf = [device newBufferWithLength:accelSizes.buildScratchBufferSize
+ options:MTLResourceStorageModePrivate];
+ id<MTLBuffer> sizeBuf = [device newBufferWithLength:8 options:MTLResourceStorageModeShared];
+ id<MTLCommandBuffer> accelCommands = [queue commandBuffer];
+ id<MTLAccelerationStructureCommandEncoder> accelEnc =
+ [accelCommands accelerationStructureCommandEncoder];
+ if (refit) {
+ [accelEnc refitAccelerationStructure:accel_struct
+ descriptor:accelDesc
+ destination:accel_uncompressed
+ scratchBuffer:scratchBuf
+ scratchBufferOffset:0];
+ }
+ else {
+ [accelEnc buildAccelerationStructure:accel_uncompressed
+ descriptor:accelDesc
+ scratchBuffer:scratchBuf
+ scratchBufferOffset:0];
+ }
+ if (use_fast_trace_bvh) {
+ [accelEnc writeCompactedAccelerationStructureSize:accel_uncompressed
+ toBuffer:sizeBuf
+ offset:0
+ sizeDataType:MTLDataTypeULong];
+ }
+ [accelEnc endEncoding];
+ [accelCommands addCompletedHandler:^(id<MTLCommandBuffer> command_buffer) {
+ /* free temp resources */
+ [scratchBuf release];
+ [aabbBuf release];
+
+ if (use_fast_trace_bvh) {
+ /* Compact the accel structure */
+ uint64_t compressed_size = *(uint64_t *)sizeBuf.contents;
+
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+ id<MTLCommandBuffer> accelCommands = [queue commandBuffer];
+ id<MTLAccelerationStructureCommandEncoder> accelEnc =
+ [accelCommands accelerationStructureCommandEncoder];
+ id<MTLAccelerationStructure> accel = [device
+ newAccelerationStructureWithSize:compressed_size];
+ [accelEnc copyAndCompactAccelerationStructure:accel_uncompressed
+ toAccelerationStructure:accel];
+ [accelEnc endEncoding];
+ [accelCommands addCompletedHandler:^(id<MTLCommandBuffer> command_buffer) {
+ uint64_t allocated_size = [accel allocatedSize];
+ stats.mem_alloc(allocated_size);
+ accel_struct = accel;
+ [accel_uncompressed release];
+ accel_struct_building = false;
+ }];
+ [accelCommands commit];
+ });
+ }
+ else {
+ /* set our acceleration structure to the uncompressed structure */
+ accel_struct = accel_uncompressed;
+
+ uint64_t allocated_size = [accel_struct allocatedSize];
+ stats.mem_alloc(allocated_size);
+ accel_struct_building = false;
+ }
+ [sizeBuf release];
+ }];
+
+ accel_struct_building = true;
+ [accelCommands commit];
+ return true;
+ }
+ return false;
+}
+
+bool BVHMetal::build_BLAS(Progress &progress,
+ id<MTLDevice> device,
+ id<MTLCommandQueue> queue,
+ bool refit)
+{
+ if (@available(macos 12.0, *)) {
+ assert(objects.size() == 1 && geometry.size() == 1);
+
+ /* Build bottom level acceleration structures (BLAS) */
+ Geometry *const geom = geometry[0];
+ switch (geom->geometry_type) {
+ case Geometry::VOLUME:
+ case Geometry::MESH:
+ return build_BLAS_mesh(progress, device, queue, geom, refit);
+ case Geometry::HAIR:
+ return build_BLAS_hair(progress, device, queue, geom, refit);
+ default:
+ return false;
+ }
+ }
+ return false;
+}
+
+bool BVHMetal::build_TLAS(Progress &progress,
+ id<MTLDevice> device,
+ id<MTLCommandQueue> queue,
+ bool refit)
+{
+ if (@available(macos 12.0, *)) {
+
+ /* we need to sync here and ensure that all BLAS have completed async generation by both GCD
+ * and Metal */
+ {
+ __block bool complete_bvh = false;
+ while (!complete_bvh) {
+ dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+ complete_bvh = true;
+ for (Object *ob : objects) {
+ /* Skip non-traceable objects */
+ if (!ob->is_traceable())
+ continue;
+
+ Geometry const *geom = ob->get_geometry();
+ BVHMetal const *blas = static_cast<BVHMetal const *>(geom->bvh);
+ if (blas->accel_struct_building) {
+ complete_bvh = false;
+
+ /* We're likely waiting on a command buffer that's in flight to complete.
+ * Queue up a command buffer and wait for it complete before checking the BLAS again
+ */
+ id<MTLCommandBuffer> command_buffer = [queue commandBuffer];
+ [command_buffer commit];
+ [command_buffer waitUntilCompleted];
+ break;
+ }
+ }
+ });
+ }
+ }
+
+ uint32_t num_instances = 0;
+ uint32_t num_motion_transforms = 0;
+ for (Object *ob : objects) {
+ /* Skip non-traceable objects */
+ if (!ob->is_traceable())
+ continue;
+ num_instances++;
+
+ if (ob->use_motion()) {
+ num_motion_transforms += max(1, ob->get_motion().size());
+ }
+ else {
+ num_motion_transforms++;
+ }
+ }
+
+ /*------------------------------------------------*/
+ BVH_status("Building TLAS | %7d instances", (int)num_instances);
+ /*------------------------------------------------*/
+
+ const bool use_fast_trace_bvh = (params.bvh_type == BVH_TYPE_STATIC);
+
+ NSMutableArray *all_blas = [NSMutableArray array];
+ unordered_map<BVHMetal const *, int> instance_mapping;
+
+ /* Lambda function to build/retrieve the BLAS index mapping */
+ auto get_blas_index = [&](BVHMetal const *blas) {
+ auto it = instance_mapping.find(blas);
+ if (it != instance_mapping.end()) {
+ return it->second;
+ }
+ else {
+ int blas_index = (int)[all_blas count];
+ instance_mapping[blas] = blas_index;
+ if (@available(macos 12.0, *)) {
+ [all_blas addObject:blas->accel_struct];
+ }
+ return blas_index;
+ }
+ };
+
+ MTLResourceOptions storage_mode;
+ if (device.hasUnifiedMemory) {
+ storage_mode = MTLResourceStorageModeShared;
+ }
+ else {
+ storage_mode = MTLResourceStorageModeManaged;
+ }
+
+ size_t instance_size;
+ if (motion_blur) {
+ instance_size = sizeof(MTLAccelerationStructureMotionInstanceDescriptor);
+ }
+ else {
+ instance_size = sizeof(MTLAccelerationStructureUserIDInstanceDescriptor);
+ }
+
+ /* Allocate a GPU buffer for the instance data and populate it */
+ id<MTLBuffer> instanceBuf = [device newBufferWithLength:num_instances * instance_size
+ options:storage_mode];
+ id<MTLBuffer> motion_transforms_buf = nil;
+ MTLPackedFloat4x3 *motion_transforms = nullptr;
+ if (motion_blur && num_motion_transforms) {
+ motion_transforms_buf = [device
+ newBufferWithLength:num_motion_transforms * sizeof(MTLPackedFloat4x3)
+ options:storage_mode];
+ motion_transforms = (MTLPackedFloat4x3 *)motion_transforms_buf.contents;
+ }
+
+ uint32_t instance_index = 0;
+ uint32_t motion_transform_index = 0;
+ for (Object *ob : objects) {
+ /* Skip non-traceable objects */
+ if (!ob->is_traceable())
+ continue;
+
+ Geometry const *geom = ob->get_geometry();
+
+ BVHMetal const *blas = static_cast<BVHMetal const *>(geom->bvh);
+ uint32_t accel_struct_index = get_blas_index(blas);
+
+ /* Add some of the object visibility bits to the mask.
+ * __prim_visibility contains the combined visibility bits of all instances, so is not
+ * reliable if they differ between instances.
+ *
+ * METAL_WIP: OptiX visibility mask can only contain 8 bits, so have to trade-off here
+ * and select just a few important ones.
+ */
+ uint32_t mask = ob->visibility_for_tracing() & 0xFF;
+
+ /* Have to have at least one bit in the mask, or else instance would always be culled. */
+ if (0 == mask) {
+ mask = 0xFF;
+ }
+
+ /* Set user instance ID to object index */
+ int object_index = ob->get_device_index();
+ uint32_t user_id = uint32_t(object_index);
+
+ /* Bake into the appropriate descriptor */
+ if (motion_blur) {
+ MTLAccelerationStructureMotionInstanceDescriptor *instances =
+ (MTLAccelerationStructureMotionInstanceDescriptor *)[instanceBuf contents];
+ MTLAccelerationStructureMotionInstanceDescriptor &desc = instances[instance_index++];
+
+ desc.accelerationStructureIndex = accel_struct_index;
+ desc.userID = user_id;
+ desc.mask = mask;
+ desc.motionStartTime = 0.0f;
+ desc.motionEndTime = 1.0f;
+ desc.motionTransformsStartIndex = motion_transform_index;
+ desc.motionStartBorderMode = MTLMotionBorderModeVanish;
+ desc.motionEndBorderMode = MTLMotionBorderModeVanish;
+ desc.intersectionFunctionTableOffset = 0;
+
+ int key_count = ob->get_motion().size();
+ if (key_count) {
+ desc.motionTransformsCount = key_count;
+
+ Transform *keys = ob->get_motion().data();
+ for (int i = 0; i < key_count; i++) {
+ float *t = (float *)&motion_transforms[motion_transform_index++];
+ /* Transpose transform */
+ auto src = (float const *)&keys[i];
+ for (int i = 0; i < 12; i++) {
+ t[i] = src[(i / 3) + 4 * (i % 3)];
+ }
+ }
+ }
+ else {
+ desc.motionTransformsCount = 1;
+
+ float *t = (float *)&motion_transforms[motion_transform_index++];
+ if (ob->get_geometry()->is_instanced()) {
+ /* Transpose transform */
+ auto src = (float const *)&ob->get_tfm();
+ for (int i = 0; i < 12; i++) {
+ t[i] = src[(i / 3) + 4 * (i % 3)];
+ }
+ }
+ else {
+ /* Clear transform to identity matrix */
+ t[0] = t[4] = t[8] = 1.0f;
+ }
+ }
+ }
+ else {
+ MTLAccelerationStructureUserIDInstanceDescriptor *instances =
+ (MTLAccelerationStructureUserIDInstanceDescriptor *)[instanceBuf contents];
+ MTLAccelerationStructureUserIDInstanceDescriptor &desc = instances[instance_index++];
+
+ desc.accelerationStructureIndex = accel_struct_index;
+ desc.userID = user_id;
+ desc.mask = mask;
+ desc.intersectionFunctionTableOffset = 0;
+
+ float *t = (float *)&desc.transformationMatrix;
+ if (ob->get_geometry()->is_instanced()) {
+ /* Transpose transform */
+ auto src = (float const *)&ob->get_tfm();
+ for (int i = 0; i < 12; i++) {
+ t[i] = src[(i / 3) + 4 * (i % 3)];
+ }
+ }
+ else {
+ /* Clear transform to identity matrix */
+ t[0] = t[4] = t[8] = 1.0f;
+ }
+ }
+ }
+
+ if (storage_mode == MTLResourceStorageModeManaged) {
+ [instanceBuf didModifyRange:NSMakeRange(0, instanceBuf.length)];
+ if (motion_transforms_buf) {
+ [motion_transforms_buf didModifyRange:NSMakeRange(0, motion_transforms_buf.length)];
+ assert(num_motion_transforms == motion_transform_index);
+ }
+ }
+
+ MTLInstanceAccelerationStructureDescriptor *accelDesc =
+ [MTLInstanceAccelerationStructureDescriptor descriptor];
+ accelDesc.instanceCount = num_instances;
+ accelDesc.instanceDescriptorType = MTLAccelerationStructureInstanceDescriptorTypeUserID;
+ accelDesc.instanceDescriptorBuffer = instanceBuf;
+ accelDesc.instanceDescriptorBufferOffset = 0;
+ accelDesc.instanceDescriptorStride = instance_size;
+ accelDesc.instancedAccelerationStructures = all_blas;
+
+ if (motion_blur) {
+ accelDesc.instanceDescriptorType = MTLAccelerationStructureInstanceDescriptorTypeMotion;
+ accelDesc.motionTransformBuffer = motion_transforms_buf;
+ accelDesc.motionTransformCount = num_motion_transforms;
+ }
+
+ if (!use_fast_trace_bvh) {
+ accelDesc.usage |= (MTLAccelerationStructureUsageRefit |
+ MTLAccelerationStructureUsagePreferFastBuild);
+ }
+
+ MTLAccelerationStructureSizes accelSizes = [device
+ accelerationStructureSizesWithDescriptor:accelDesc];
+ id<MTLAccelerationStructure> accel = [device
+ newAccelerationStructureWithSize:accelSizes.accelerationStructureSize];
+ id<MTLBuffer> scratchBuf = [device newBufferWithLength:accelSizes.buildScratchBufferSize
+ options:MTLResourceStorageModePrivate];
+ id<MTLCommandBuffer> accelCommands = [queue commandBuffer];
+ id<MTLAccelerationStructureCommandEncoder> accelEnc =
+ [accelCommands accelerationStructureCommandEncoder];
+ if (refit) {
+ [accelEnc refitAccelerationStructure:accel_struct
+ descriptor:accelDesc
+ destination:accel
+ scratchBuffer:scratchBuf
+ scratchBufferOffset:0];
+ }
+ else {
+ [accelEnc buildAccelerationStructure:accel
+ descriptor:accelDesc
+ scratchBuffer:scratchBuf
+ scratchBufferOffset:0];
+ }
+ [accelEnc endEncoding];
+ [accelCommands commit];
+ [accelCommands waitUntilCompleted];
+
+ if (motion_transforms_buf) {
+ [motion_transforms_buf release];
+ }
+ [instanceBuf release];
+ [scratchBuf release];
+
+ uint64_t allocated_size = [accel allocatedSize];
+ stats.mem_alloc(allocated_size);
+
+ /* Cache top and bottom-level acceleration structs */
+ accel_struct = accel;
+ blas_array.clear();
+ blas_array.reserve(all_blas.count);
+ for (id<MTLAccelerationStructure> blas in all_blas) {
+ blas_array.push_back(blas);
+ }
+
+ return true;
+ }
+ return false;
+}
+
+bool BVHMetal::build(Progress &progress,
+ id<MTLDevice> device,
+ id<MTLCommandQueue> queue,
+ bool refit)
+{
+ if (@available(macos 12.0, *)) {
+ if (refit && params.bvh_type != BVH_TYPE_STATIC) {
+ assert(accel_struct);
+ }
+ else {
+ if (accel_struct) {
+ stats.mem_free(accel_struct.allocatedSize);
+ [accel_struct release];
+ accel_struct = nil;
+ }
+ }
+ }
+
+ if (!params.top_level) {
+ return build_BLAS(progress, device, queue, refit);
+ }
+ else {
+ return build_TLAS(progress, device, queue, refit);
+ }
+}
+
+CCL_NAMESPACE_END
+
+#endif /* WITH_METAL */
diff --git a/intern/cycles/device/metal/device.h b/intern/cycles/device/metal/device.h
new file mode 100644
index 00000000000..254fbfee42b
--- /dev/null
+++ b/intern/cycles/device/metal/device.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "util/string.h"
+#include "util/vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+class Device;
+class DeviceInfo;
+class Profiler;
+class Stats;
+
+bool device_metal_init();
+
+Device *device_metal_create(const DeviceInfo &info, Stats &stats, Profiler &profiler);
+
+void device_metal_info(vector<DeviceInfo> &devices);
+
+string device_metal_capabilities();
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/device/metal/device.mm b/intern/cycles/device/metal/device.mm
new file mode 100644
index 00000000000..bc893adea17
--- /dev/null
+++ b/intern/cycles/device/metal/device.mm
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifdef WITH_METAL
+
+# include "device/metal/device.h"
+# include "device/metal/device_impl.h"
+
+#endif
+
+#include "util/debug.h"
+#include "util/set.h"
+#include "util/system.h"
+
+CCL_NAMESPACE_BEGIN
+
+#ifdef WITH_METAL
+
+Device *device_metal_create(const DeviceInfo &info, Stats &stats, Profiler &profiler)
+{
+ return new MetalDevice(info, stats, profiler);
+}
+
+bool device_metal_init()
+{
+ return true;
+}
+
+static int device_metal_get_num_devices_safe(uint32_t *num_devices)
+{
+ *num_devices = MTLCopyAllDevices().count;
+ return 0;
+}
+
+void device_metal_info(vector<DeviceInfo> &devices)
+{
+ uint32_t num_devices = 0;
+ device_metal_get_num_devices_safe(&num_devices);
+ if (num_devices == 0) {
+ return;
+ }
+
+ vector<MetalPlatformDevice> usable_devices;
+ MetalInfo::get_usable_devices(&usable_devices);
+ /* Devices are numbered consecutively across platforms. */
+ set<string> unique_ids;
+ int device_index = 0;
+ for (MetalPlatformDevice &device : usable_devices) {
+ /* Compute unique ID for persistent user preferences. */
+ const string &device_name = device.device_name;
+ string id = string("METAL_") + device_name;
+
+ /* Hardware ID might not be unique, add device number in that case. */
+ if (unique_ids.find(id) != unique_ids.end()) {
+ id += string_printf("_ID_%d", num_devices);
+ }
+ unique_ids.insert(id);
+
+ /* Create DeviceInfo. */
+ DeviceInfo info;
+ info.type = DEVICE_METAL;
+ info.description = string_remove_trademark(string(device_name));
+
+ /* Ensure unique naming on Apple Silicon / SoC devices which return the same string for CPU and
+ * GPU */
+ if (info.description == system_cpu_brand_string()) {
+ info.description += " (GPU)";
+ }
+
+ info.num = device_index;
+ /* We don't know if it's used for display, but assume it is. */
+ info.display_device = true;
+ info.denoisers = DENOISER_NONE;
+ info.id = id;
+
+ devices.push_back(info);
+ device_index++;
+ }
+}
+
+string device_metal_capabilities()
+{
+ string result = "";
+ string error_msg = "";
+ uint32_t num_devices = 0;
+ assert(device_metal_get_num_devices_safe(&num_devices));
+ if (num_devices == 0) {
+ return "No Metal devices found\n";
+ }
+ result += string_printf("Number of devices: %u\n", num_devices);
+
+ NSArray<id<MTLDevice>> *allDevices = MTLCopyAllDevices();
+ for (id<MTLDevice> device in allDevices) {
+ result += string_printf("\t\tDevice: %s\n", [device.name UTF8String]);
+ }
+
+ return result;
+}
+
+#else
+
+Device *device_metal_create(const DeviceInfo &info, Stats &stats, Profiler &profiler)
+{
+ return nullptr;
+}
+
+bool device_metal_init()
+{
+ return false;
+}
+
+void device_metal_info(vector<DeviceInfo> &devices)
+{
+}
+
+string device_metal_capabilities()
+{
+ return "";
+}
+
+#endif
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/device/metal/device_impl.h b/intern/cycles/device/metal/device_impl.h
new file mode 100644
index 00000000000..a420a3ba704
--- /dev/null
+++ b/intern/cycles/device/metal/device_impl.h
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#ifdef WITH_METAL
+
+# include "bvh/bvh.h"
+# include "device/device.h"
+# include "device/metal/bvh.h"
+# include "device/metal/device.h"
+# include "device/metal/kernel.h"
+# include "device/metal/queue.h"
+# include "device/metal/util.h"
+
+# include <Metal/Metal.h>
+
+CCL_NAMESPACE_BEGIN
+
+class DeviceQueue;
+
+class MetalDevice : public Device {
+ public:
+ id<MTLDevice> mtlDevice = nil;
+ id<MTLLibrary> mtlLibrary[PSO_NUM] = {nil};
+ id<MTLArgumentEncoder> mtlBufferKernelParamsEncoder =
+ nil; /* encoder used for fetching device pointers from MTLBuffers */
+ id<MTLCommandQueue> mtlGeneralCommandQueue = nil;
+ id<MTLArgumentEncoder> mtlAncillaryArgEncoder =
+ nil; /* encoder used for fetching device pointers from MTLBuffers */
+ string source_used_for_compile[PSO_NUM];
+
+ KernelParamsMetal launch_params = {0};
+
+ /* MetalRT members ----------------------------------*/
+ BVHMetal *bvhMetalRT = nullptr;
+ bool motion_blur = false;
+ id<MTLArgumentEncoder> mtlASArgEncoder =
+ nil; /* encoder used for fetching device pointers from MTLAccelerationStructure */
+ /*---------------------------------------------------*/
+
+ string device_name;
+ MetalGPUVendor device_vendor;
+
+ uint kernel_features;
+ MTLResourceOptions default_storage_mode;
+ int max_threads_per_threadgroup;
+
+ int mtlDevId = 0;
+ bool first_error = true;
+
+ struct MetalMem {
+ device_memory *mem = nullptr;
+ int pointer_index = -1;
+ id<MTLBuffer> mtlBuffer = nil;
+ id<MTLTexture> mtlTexture = nil;
+ uint64_t offset = 0;
+ uint64_t size = 0;
+ void *hostPtr = nullptr;
+ bool use_UMA = false; /* If true, UMA memory in shared_pointer is being used. */
+ };
+ typedef map<device_memory *, unique_ptr<MetalMem>> MetalMemMap;
+ MetalMemMap metal_mem_map;
+ std::vector<id<MTLResource>> delayed_free_list;
+ std::recursive_mutex metal_mem_map_mutex;
+
+ /* Bindless Textures */
+ device_vector<TextureInfo> texture_info;
+ bool need_texture_info;
+ id<MTLArgumentEncoder> mtlTextureArgEncoder = nil;
+ id<MTLBuffer> texture_bindings_2d = nil;
+ id<MTLBuffer> texture_bindings_3d = nil;
+ std::vector<id<MTLTexture>> texture_slot_map;
+
+ MetalDeviceKernels kernels;
+ bool use_metalrt = false;
+ bool use_function_specialisation = false;
+
+ virtual BVHLayoutMask get_bvh_layout_mask() const override;
+
+ void set_error(const string &error) override;
+
+ MetalDevice(const DeviceInfo &info, Stats &stats, Profiler &profiler);
+
+ virtual ~MetalDevice();
+
+ bool support_device(const uint /*kernel_features*/);
+
+ bool check_peer_access(Device *peer_device) override;
+
+ bool use_adaptive_compilation();
+
+ string get_source(const uint kernel_features);
+
+ string compile_kernel(const uint kernel_features, const char *name);
+
+ virtual bool load_kernels(const uint kernel_features) override;
+
+ void reserve_local_memory(const uint kernel_features);
+
+ void init_host_memory();
+
+ void load_texture_info();
+
+ virtual bool should_use_graphics_interop() override;
+
+ virtual unique_ptr<DeviceQueue> gpu_queue_create() override;
+
+ virtual void build_bvh(BVH *bvh, Progress &progress, bool refit) override;
+
+ /* ------------------------------------------------------------------ */
+ /* low-level memory management */
+
+ MetalMem *generic_alloc(device_memory &mem);
+
+ void generic_copy_to(device_memory &mem);
+
+ void generic_free(device_memory &mem);
+
+ void mem_alloc(device_memory &mem) override;
+
+ void mem_copy_to(device_memory &mem) override;
+
+ void mem_copy_from(device_memory &mem)
+ {
+ mem_copy_from(mem, -1, -1, -1, -1);
+ }
+ void mem_copy_from(device_memory &mem, size_t y, size_t w, size_t h, size_t elem) override;
+
+ void mem_zero(device_memory &mem) override;
+
+ void mem_free(device_memory &mem) override;
+
+ device_ptr mem_alloc_sub_ptr(device_memory &mem, size_t offset, size_t /*size*/) override;
+
+ virtual void const_copy_to(const char *name, void *host, size_t size) override;
+
+ void global_alloc(device_memory &mem);
+
+ void global_free(device_memory &mem);
+
+ void tex_alloc(device_texture &mem);
+
+ void tex_alloc_as_buffer(device_texture &mem);
+
+ void tex_free(device_texture &mem);
+
+ void flush_delayed_free_list();
+};
+
+CCL_NAMESPACE_END
+
+#endif
diff --git a/intern/cycles/device/metal/device_impl.mm b/intern/cycles/device/metal/device_impl.mm
new file mode 100644
index 00000000000..4ad5a3caebc
--- /dev/null
+++ b/intern/cycles/device/metal/device_impl.mm
@@ -0,0 +1,1008 @@
+/*
+ * Copyright 2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifdef WITH_METAL
+
+# include "device/metal/device_impl.h"
+# include "device/metal/device.h"
+
+# include "util/debug.h"
+# include "util/md5.h"
+# include "util/path.h"
+
+CCL_NAMESPACE_BEGIN
+
+class MetalDevice;
+
+BVHLayoutMask MetalDevice::get_bvh_layout_mask() const
+{
+ return use_metalrt ? BVH_LAYOUT_METAL : BVH_LAYOUT_BVH2;
+}
+
+void MetalDevice::set_error(const string &error)
+{
+ static std::mutex s_error_mutex;
+ std::lock_guard<std::mutex> lock(s_error_mutex);
+
+ Device::set_error(error);
+
+ if (first_error) {
+ fprintf(stderr, "\nRefer to the Cycles GPU rendering documentation for possible solutions:\n");
+ fprintf(stderr,
+ "https://docs.blender.org/manual/en/latest/render/cycles/gpu_rendering.html\n\n");
+ first_error = false;
+ }
+}
+
+MetalDevice::MetalDevice(const DeviceInfo &info, Stats &stats, Profiler &profiler)
+ : Device(info, stats, profiler), texture_info(this, "__texture_info", MEM_GLOBAL)
+{
+ mtlDevId = info.num;
+
+ /* select chosen device */
+ vector<MetalPlatformDevice> usable_devices;
+ MetalInfo::get_usable_devices(&usable_devices);
+ if (usable_devices.size() == 0) {
+ set_error("Metal: no devices found.");
+ return;
+ }
+ assert(mtlDevId < usable_devices.size());
+ MetalPlatformDevice &platform_device = usable_devices[mtlDevId];
+ mtlDevice = platform_device.device_id;
+ device_name = platform_device.device_name;
+ device_vendor = MetalInfo::get_vendor_from_device_name(device_name);
+ assert(device_vendor != METAL_GPU_UNKNOWN);
+ metal_printf("Creating new Cycles device for Metal: %s\n", device_name.c_str());
+
+ /* determine default storage mode based on whether UMA is supported */
+
+ default_storage_mode = MTLResourceStorageModeManaged;
+
+ if (@available(macos 11.0, *)) {
+ if ([mtlDevice hasUnifiedMemory]) {
+ default_storage_mode = MTLResourceStorageModeShared;
+ init_host_memory();
+ }
+ }
+
+ texture_bindings_2d = [mtlDevice newBufferWithLength:4096 options:default_storage_mode];
+ texture_bindings_3d = [mtlDevice newBufferWithLength:4096 options:default_storage_mode];
+
+ stats.mem_alloc(texture_bindings_2d.allocatedSize + texture_bindings_3d.allocatedSize);
+
+ switch (device_vendor) {
+ default:
+ break;
+ case METAL_GPU_INTEL: {
+ use_metalrt = false;
+ max_threads_per_threadgroup = 64;
+ break;
+ }
+ case METAL_GPU_AMD: {
+ use_metalrt = false;
+ max_threads_per_threadgroup = 128;
+ break;
+ }
+ case METAL_GPU_APPLE: {
+ use_metalrt = true;
+ max_threads_per_threadgroup = 512;
+ break;
+ }
+ }
+
+ if (auto metalrt = getenv("CYCLES_METALRT")) {
+ use_metalrt = (atoi(metalrt) != 0);
+ }
+
+ MTLArgumentDescriptor *arg_desc_params = [[MTLArgumentDescriptor alloc] init];
+ arg_desc_params.dataType = MTLDataTypePointer;
+ arg_desc_params.access = MTLArgumentAccessReadOnly;
+ arg_desc_params.arrayLength = sizeof(KernelParamsMetal) / sizeof(device_ptr);
+ mtlBufferKernelParamsEncoder = [mtlDevice newArgumentEncoderWithArguments:@[ arg_desc_params ]];
+
+ MTLArgumentDescriptor *arg_desc_texture = [[MTLArgumentDescriptor alloc] init];
+ arg_desc_texture.dataType = MTLDataTypeTexture;
+ arg_desc_texture.access = MTLArgumentAccessReadOnly;
+ mtlTextureArgEncoder = [mtlDevice newArgumentEncoderWithArguments:@[ arg_desc_texture ]];
+
+ /* command queue for non-tracing work on the GPU */
+ mtlGeneralCommandQueue = [mtlDevice newCommandQueue];
+
+ /* Acceleration structure arg encoder, if needed */
+ if (@available(macos 12.0, *)) {
+ if (use_metalrt) {
+ MTLArgumentDescriptor *arg_desc_as = [[MTLArgumentDescriptor alloc] init];
+ arg_desc_as.dataType = MTLDataTypeInstanceAccelerationStructure;
+ arg_desc_as.access = MTLArgumentAccessReadOnly;
+ mtlASArgEncoder = [mtlDevice newArgumentEncoderWithArguments:@[ arg_desc_as ]];
+ [arg_desc_as release];
+ }
+ }
+
+ /* Build the arg encoder for the ancillary bindings */
+ {
+ NSMutableArray *ancillary_desc = [[NSMutableArray alloc] init];
+
+ int index = 0;
+ MTLArgumentDescriptor *arg_desc_tex = [[MTLArgumentDescriptor alloc] init];
+ arg_desc_tex.dataType = MTLDataTypePointer;
+ arg_desc_tex.access = MTLArgumentAccessReadOnly;
+
+ arg_desc_tex.index = index++;
+ [ancillary_desc addObject:[arg_desc_tex copy]]; /* metal_tex_2d */
+ arg_desc_tex.index = index++;
+ [ancillary_desc addObject:[arg_desc_tex copy]]; /* metal_tex_3d */
+
+ [arg_desc_tex release];
+
+ if (@available(macos 12.0, *)) {
+ if (use_metalrt) {
+ MTLArgumentDescriptor *arg_desc_as = [[MTLArgumentDescriptor alloc] init];
+ arg_desc_as.dataType = MTLDataTypeInstanceAccelerationStructure;
+ arg_desc_as.access = MTLArgumentAccessReadOnly;
+
+ MTLArgumentDescriptor *arg_desc_ift = [[MTLArgumentDescriptor alloc] init];
+ arg_desc_ift.dataType = MTLDataTypeIntersectionFunctionTable;
+ arg_desc_ift.access = MTLArgumentAccessReadOnly;
+
+ arg_desc_as.index = index++;
+ [ancillary_desc addObject:[arg_desc_as copy]]; /* accel_struct */
+ arg_desc_ift.index = index++;
+ [ancillary_desc addObject:[arg_desc_ift copy]]; /* ift_default */
+ arg_desc_ift.index = index++;
+ [ancillary_desc addObject:[arg_desc_ift copy]]; /* ift_shadow */
+ arg_desc_ift.index = index++;
+ [ancillary_desc addObject:[arg_desc_ift copy]]; /* ift_local */
+
+ [arg_desc_ift release];
+ [arg_desc_as release];
+ }
+ }
+
+ mtlAncillaryArgEncoder = [mtlDevice newArgumentEncoderWithArguments:ancillary_desc];
+
+ for (int i = 0; i < ancillary_desc.count; i++) {
+ [ancillary_desc[i] release];
+ }
+ [ancillary_desc release];
+ }
+ [arg_desc_params release];
+ [arg_desc_texture release];
+}
+
+MetalDevice::~MetalDevice()
+{
+ for (auto &tex : texture_slot_map) {
+ if (tex) {
+ [tex release];
+ tex = nil;
+ }
+ }
+ flush_delayed_free_list();
+
+ if (texture_bindings_2d) {
+ stats.mem_free(texture_bindings_2d.allocatedSize + texture_bindings_3d.allocatedSize);
+
+ [texture_bindings_2d release];
+ [texture_bindings_3d release];
+ }
+ [mtlTextureArgEncoder release];
+ [mtlBufferKernelParamsEncoder release];
+ [mtlASArgEncoder release];
+ [mtlAncillaryArgEncoder release];
+ [mtlGeneralCommandQueue release];
+ [mtlDevice release];
+
+ texture_info.free();
+}
+
+bool MetalDevice::support_device(const uint kernel_features /*requested_features*/)
+{
+ return true;
+}
+
+bool MetalDevice::check_peer_access(Device *peer_device)
+{
+ assert(0);
+ /* does peer access make sense? */
+ return false;
+}
+
+bool MetalDevice::use_adaptive_compilation()
+{
+ return DebugFlags().metal.adaptive_compile;
+}
+
+string MetalDevice::get_source(const uint kernel_features)
+{
+ string build_options;
+
+ if (use_adaptive_compilation()) {
+ build_options += " -D__KERNEL_FEATURES__=" + to_string(kernel_features);
+ }
+
+ if (use_metalrt) {
+ build_options += "-D__METALRT__ ";
+ if (motion_blur) {
+ build_options += "-D__METALRT_MOTION__ ";
+ }
+ }
+
+# ifdef WITH_CYCLES_DEBUG
+ build_options += "-D__KERNEL_DEBUG__ ";
+# endif
+
+ switch (device_vendor) {
+ default:
+ break;
+ case METAL_GPU_INTEL:
+ build_options += "-D__KERNEL_METAL_INTEL__ ";
+ break;
+ case METAL_GPU_AMD:
+ build_options += "-D__KERNEL_METAL_AMD__ ";
+ break;
+ case METAL_GPU_APPLE:
+ build_options += "-D__KERNEL_METAL_APPLE__ ";
+ break;
+ }
+
+ /* reformat -D defines list into compilable form */
+ vector<string> components;
+ string_replace(build_options, "-D", "");
+ string_split(components, build_options, " ");
+
+ string globalDefines;
+ for (const string &component : components) {
+ vector<string> assignments;
+ string_split(assignments, component, "=");
+ if (assignments.size() == 2)
+ globalDefines += string_printf(
+ "#define %s %s\n", assignments[0].c_str(), assignments[1].c_str());
+ else
+ globalDefines += string_printf("#define %s\n", assignments[0].c_str());
+ }
+
+ string source = globalDefines + "\n#include \"kernel/device/metal/kernel.metal\"\n";
+ source = path_source_replace_includes(source, path_get("source"));
+
+ metal_printf("Global defines:\n%s\n", globalDefines.c_str());
+
+ return source;
+}
+
+bool MetalDevice::load_kernels(const uint _kernel_features)
+{
+ kernel_features = _kernel_features;
+
+ /* check if GPU is supported */
+ if (!support_device(kernel_features))
+ return false;
+
+ /* Keep track of whether motion blur is enabled, so to enable/disable motion in BVH builds
+ * This is necessary since objects may be reported to have motion if the Vector pass is
+ * active, but may still need to be rendered without motion blur if that isn't active as well. */
+ motion_blur = kernel_features & KERNEL_FEATURE_OBJECT_MOTION;
+
+ NSError *error = NULL;
+
+ for (int i = 0; i < PSO_NUM; i++) {
+ if (mtlLibrary[i]) {
+ [mtlLibrary[i] release];
+ mtlLibrary[i] = nil;
+ }
+ }
+
+ MTLCompileOptions *options = [[MTLCompileOptions alloc] init];
+
+ options.fastMathEnabled = YES;
+ if (@available(macOS 12.0, *)) {
+ options.languageVersion = MTLLanguageVersion2_4;
+ }
+ else {
+ return false;
+ }
+
+ string metalsrc;
+
+ /* local helper: dump source to disk and return filepath */
+ auto dump_source = [&](int kernel_type) -> string {
+ string &source = source_used_for_compile[kernel_type];
+ string metalsrc = path_cache_get(path_join("kernels",
+ string_printf("%s.%s.metal",
+ kernel_type_as_string(kernel_type),
+ util_md5_string(source).c_str())));
+ path_write_text(metalsrc, source);
+ return metalsrc;
+ };
+
+ /* local helper: fetch the kernel source code, adjust it for specific PSO_.. kernel_type flavor,
+ * then compile it into a MTLLibrary */
+ auto fetch_and_compile_source = [&](int kernel_type) {
+ /* Record the source used to compile this library, for hash building later. */
+ string &source = source_used_for_compile[kernel_type];
+
+ switch (kernel_type) {
+ case PSO_GENERIC: {
+ source = get_source(kernel_features);
+ break;
+ }
+ case PSO_SPECIALISED: {
+ /* PSO_SPECIALISED derives from PSO_GENERIC */
+ string &generic_source = source_used_for_compile[PSO_GENERIC];
+ if (generic_source.empty()) {
+ generic_source = get_source(kernel_features);
+ }
+ source = "#define __KERNEL_METAL_USE_FUNCTION_SPECIALISATION__\n" + generic_source;
+ break;
+ }
+ default:
+ assert(0);
+ }
+
+ /* create MTLLibrary (front-end compilation) */
+ mtlLibrary[kernel_type] = [mtlDevice newLibraryWithSource:@(source.c_str())
+ options:options
+ error:&error];
+
+ bool do_source_dump = (getenv("CYCLES_METAL_DUMP_SOURCE") != nullptr);
+
+ if (!mtlLibrary[kernel_type] || do_source_dump) {
+ string metalsrc = dump_source(kernel_type);
+
+ if (!mtlLibrary[kernel_type]) {
+ NSString *err = [error localizedDescription];
+ set_error(string_printf("Failed to compile library:\n%s", [err UTF8String]));
+
+ return false;
+ }
+ }
+ return true;
+ };
+
+ fetch_and_compile_source(PSO_GENERIC);
+
+ if (use_function_specialisation) {
+ fetch_and_compile_source(PSO_SPECIALISED);
+ }
+
+ metal_printf("Front-end compilation finished\n");
+
+ bool result = kernels.load(this, PSO_GENERIC);
+
+ [options release];
+ reserve_local_memory(kernel_features);
+
+ return result;
+}
+
+void MetalDevice::reserve_local_memory(const uint kernel_features)
+{
+ /* METAL_WIP - implement this */
+}
+
+void MetalDevice::init_host_memory()
+{
+ /* METAL_WIP - implement this */
+}
+
+void MetalDevice::load_texture_info()
+{
+ if (need_texture_info) {
+ /* Unset flag before copying. */
+ need_texture_info = false;
+ texture_info.copy_to_device();
+
+ int num_textures = texture_info.size();
+
+ for (int tex = 0; tex < num_textures; tex++) {
+ uint64_t offset = tex * sizeof(void *);
+
+ id<MTLTexture> metal_texture = texture_slot_map[tex];
+ if (!metal_texture) {
+ [mtlTextureArgEncoder setArgumentBuffer:texture_bindings_2d offset:offset];
+ [mtlTextureArgEncoder setTexture:nil atIndex:0];
+ [mtlTextureArgEncoder setArgumentBuffer:texture_bindings_3d offset:offset];
+ [mtlTextureArgEncoder setTexture:nil atIndex:0];
+ }
+ else {
+ MTLTextureType type = metal_texture.textureType;
+ [mtlTextureArgEncoder setArgumentBuffer:texture_bindings_2d offset:offset];
+ [mtlTextureArgEncoder setTexture:type == MTLTextureType2D ? metal_texture : nil atIndex:0];
+ [mtlTextureArgEncoder setArgumentBuffer:texture_bindings_3d offset:offset];
+ [mtlTextureArgEncoder setTexture:type == MTLTextureType3D ? metal_texture : nil atIndex:0];
+ }
+ }
+ if (default_storage_mode == MTLResourceStorageModeManaged) {
+ [texture_bindings_2d didModifyRange:NSMakeRange(0, num_textures * sizeof(void *))];
+ [texture_bindings_3d didModifyRange:NSMakeRange(0, num_textures * sizeof(void *))];
+ }
+ }
+}
+
+MetalDevice::MetalMem *MetalDevice::generic_alloc(device_memory &mem)
+{
+ size_t size = mem.memory_size();
+
+ mem.device_pointer = 0;
+
+ id<MTLBuffer> metal_buffer = nil;
+ if (size > 0) {
+ MTLResourceOptions options = default_storage_mode;
+ if (mem.type == MEM_DEVICE_ONLY) {
+ options = MTLResourceStorageModePrivate;
+ }
+
+ metal_buffer = [mtlDevice newBufferWithLength:size options:options];
+
+ if (!metal_buffer) {
+ set_error("System is out of GPU memory");
+ return nullptr;
+ }
+ }
+
+ if (mem.name) {
+ VLOG(2) << "Buffer allocate: " << mem.name << ", "
+ << string_human_readable_number(mem.memory_size()) << " bytes. ("
+ << string_human_readable_size(mem.memory_size()) << ")";
+ }
+
+ mem.device_size = metal_buffer.allocatedSize;
+ stats.mem_alloc(mem.device_size);
+
+ metal_buffer.label = [[NSString alloc] initWithFormat:@"%s", mem.name];
+
+ std::lock_guard<std::recursive_mutex> lock(metal_mem_map_mutex);
+
+ assert(metal_mem_map.count(&mem) == 0); /* assert against double-alloc */
+ MetalMem *mmem = new MetalMem;
+ metal_mem_map[&mem] = std::unique_ptr<MetalMem>(mmem);
+
+ mmem->mem = &mem;
+ mmem->mtlBuffer = metal_buffer;
+ mmem->offset = 0;
+ mmem->size = size;
+ if (mem.type != MEM_DEVICE_ONLY) {
+ mmem->hostPtr = [metal_buffer contents];
+ }
+ else {
+ mmem->hostPtr = nullptr;
+ }
+
+ /* encode device_pointer as (MetalMem*) in order to handle resource relocation and device pointer
+ * recalculation */
+ mem.device_pointer = device_ptr(mmem);
+
+ if (metal_buffer.storageMode == MTLResourceStorageModeShared) {
+ /* Replace host pointer with our host allocation. */
+
+ if (mem.host_pointer && mem.host_pointer != mmem->hostPtr) {
+ memcpy(mmem->hostPtr, mem.host_pointer, size);
+
+ mem.host_free();
+ mem.host_pointer = mmem->hostPtr;
+ }
+ mem.shared_pointer = mmem->hostPtr;
+ mem.shared_counter++;
+ mmem->use_UMA = true;
+ }
+ else {
+ mmem->use_UMA = false;
+ }
+
+ return mmem;
+}
+
+void MetalDevice::generic_copy_to(device_memory &mem)
+{
+ if (!mem.host_pointer || !mem.device_pointer) {
+ return;
+ }
+
+ std::lock_guard<std::recursive_mutex> lock(metal_mem_map_mutex);
+ if (!metal_mem_map.at(&mem)->use_UMA || mem.host_pointer != mem.shared_pointer) {
+ MetalMem &mmem = *metal_mem_map.at(&mem);
+ memcpy(mmem.hostPtr, mem.host_pointer, mem.memory_size());
+ if (mmem.mtlBuffer.storageMode == MTLStorageModeManaged) {
+ [mmem.mtlBuffer didModifyRange:NSMakeRange(0, mem.memory_size())];
+ }
+ }
+}
+
+void MetalDevice::generic_free(device_memory &mem)
+{
+ if (mem.device_pointer) {
+ std::lock_guard<std::recursive_mutex> lock(metal_mem_map_mutex);
+ MetalMem &mmem = *metal_mem_map.at(&mem);
+ size_t size = mmem.size;
+
+ /* If mmem.use_uma is true, reference counting is used
+ * to safely free memory. */
+
+ bool free_mtlBuffer = false;
+
+ if (mmem.use_UMA) {
+ assert(mem.shared_pointer);
+ if (mem.shared_pointer) {
+ assert(mem.shared_counter > 0);
+ if (--mem.shared_counter == 0) {
+ free_mtlBuffer = true;
+ }
+ }
+ }
+ else {
+ free_mtlBuffer = true;
+ }
+
+ if (free_mtlBuffer) {
+ if (mem.host_pointer && mem.host_pointer == mem.shared_pointer) {
+ /* Safely move the device-side data back to the host before it is freed. */
+ mem.host_pointer = mem.host_alloc(size);
+ memcpy(mem.host_pointer, mem.shared_pointer, size);
+ mmem.use_UMA = false;
+ }
+
+ mem.shared_pointer = 0;
+
+ /* Free device memory. */
+ delayed_free_list.push_back(mmem.mtlBuffer);
+ mmem.mtlBuffer = nil;
+ }
+
+ stats.mem_free(mem.device_size);
+ mem.device_pointer = 0;
+ mem.device_size = 0;
+
+ metal_mem_map.erase(&mem);
+ }
+}
+
+void MetalDevice::mem_alloc(device_memory &mem)
+{
+ if (mem.type == MEM_TEXTURE) {
+ assert(!"mem_alloc not supported for textures.");
+ }
+ else if (mem.type == MEM_GLOBAL) {
+ generic_alloc(mem);
+ }
+ else {
+ generic_alloc(mem);
+ }
+}
+
+void MetalDevice::mem_copy_to(device_memory &mem)
+{
+ if (mem.type == MEM_GLOBAL) {
+ global_free(mem);
+ global_alloc(mem);
+ }
+ else if (mem.type == MEM_TEXTURE) {
+ tex_free((device_texture &)mem);
+ tex_alloc((device_texture &)mem);
+ }
+ else {
+ if (!mem.device_pointer) {
+ generic_alloc(mem);
+ }
+ generic_copy_to(mem);
+ }
+}
+
+void MetalDevice::mem_copy_from(device_memory &mem, size_t y, size_t w, size_t h, size_t elem)
+{
+ if (mem.host_pointer) {
+
+ bool subcopy = (w >= 0 && h >= 0);
+ const size_t size = subcopy ? (elem * w * h) : mem.memory_size();
+ const size_t offset = subcopy ? (elem * y * w) : 0;
+
+ if (mem.device_pointer) {
+ std::lock_guard<std::recursive_mutex> lock(metal_mem_map_mutex);
+ MetalMem &mmem = *metal_mem_map.at(&mem);
+
+ if ([mmem.mtlBuffer storageMode] == MTLStorageModeManaged) {
+
+ id<MTLCommandBuffer> cmdBuffer = [mtlGeneralCommandQueue commandBuffer];
+ id<MTLBlitCommandEncoder> blitEncoder = [cmdBuffer blitCommandEncoder];
+ [blitEncoder synchronizeResource:mmem.mtlBuffer];
+ [blitEncoder endEncoding];
+ [cmdBuffer commit];
+ [cmdBuffer waitUntilCompleted];
+ }
+
+ if (mem.host_pointer != mmem.hostPtr) {
+ memcpy((uchar *)mem.host_pointer + offset, (uchar *)mmem.hostPtr + offset, size);
+ }
+ }
+ else {
+ memset((char *)mem.host_pointer + offset, 0, size);
+ }
+ }
+}
+
+void MetalDevice::mem_zero(device_memory &mem)
+{
+ if (!mem.device_pointer) {
+ mem_alloc(mem);
+ }
+ if (!mem.device_pointer) {
+ return;
+ }
+
+ size_t size = mem.memory_size();
+ std::lock_guard<std::recursive_mutex> lock(metal_mem_map_mutex);
+ MetalMem &mmem = *metal_mem_map.at(&mem);
+ memset(mmem.hostPtr, 0, size);
+ if ([mmem.mtlBuffer storageMode] == MTLStorageModeManaged) {
+ [mmem.mtlBuffer didModifyRange:NSMakeRange(0, size)];
+ }
+}
+
+void MetalDevice::mem_free(device_memory &mem)
+{
+ if (mem.type == MEM_GLOBAL) {
+ global_free(mem);
+ }
+ else if (mem.type == MEM_TEXTURE) {
+ tex_free((device_texture &)mem);
+ }
+ else {
+ generic_free(mem);
+ }
+}
+
+device_ptr MetalDevice::mem_alloc_sub_ptr(device_memory &mem, size_t offset, size_t /*size*/)
+{
+ /* METAL_WIP - revive if necessary */
+ assert(0);
+ return 0;
+}
+
+void MetalDevice::const_copy_to(const char *name, void *host, size_t size)
+{
+ if (strcmp(name, "__data") == 0) {
+ assert(size == sizeof(KernelData));
+ memcpy((uint8_t *)&launch_params + offsetof(KernelParamsMetal, data), host, size);
+ return;
+ }
+
+ auto update_launch_pointers =
+ [&](size_t offset, void *data, size_t data_size, size_t pointers_size) {
+ memcpy((uint8_t *)&launch_params + offset, data, data_size);
+
+ MetalMem **mmem = (MetalMem **)data;
+ int pointer_count = pointers_size / sizeof(device_ptr);
+ int pointer_index = offset / sizeof(device_ptr);
+ for (int i = 0; i < pointer_count; i++) {
+ if (mmem[i]) {
+ mmem[i]->pointer_index = pointer_index + i;
+ }
+ }
+ };
+
+ /* Update data storage pointers in launch parameters. */
+ if (strcmp(name, "__integrator_state") == 0) {
+ /* IntegratorStateGPU is contiguous pointers */
+ const size_t pointer_block_size = sizeof(IntegratorStateGPU);
+ update_launch_pointers(
+ offsetof(KernelParamsMetal, __integrator_state), host, size, pointer_block_size);
+ }
+# define KERNEL_TEX(data_type, tex_name) \
+ else if (strcmp(name, #tex_name) == 0) \
+ { \
+ update_launch_pointers(offsetof(KernelParamsMetal, tex_name), host, size, size); \
+ }
+# include "kernel/textures.h"
+# undef KERNEL_TEX
+}
+
+void MetalDevice::global_alloc(device_memory &mem)
+{
+ if (mem.is_resident(this)) {
+ generic_alloc(mem);
+ generic_copy_to(mem);
+ }
+
+ const_copy_to(mem.name, &mem.device_pointer, sizeof(mem.device_pointer));
+}
+
+void MetalDevice::global_free(device_memory &mem)
+{
+ if (mem.is_resident(this) && mem.device_pointer) {
+ generic_free(mem);
+ }
+}
+
+void MetalDevice::tex_alloc_as_buffer(device_texture &mem)
+{
+ generic_alloc(mem);
+ generic_copy_to(mem);
+
+ /* Resize once */
+ const uint slot = mem.slot;
+ if (slot >= texture_info.size()) {
+ /* Allocate some slots in advance, to reduce amount
+ * of re-allocations. */
+ texture_info.resize(round_up(slot + 1, 128));
+ }
+
+ mem.info.data = (uint64_t)mem.device_pointer;
+
+ /* Set Mapping and tag that we need to (re-)upload to device */
+ texture_info[slot] = mem.info;
+ need_texture_info = true;
+}
+
+void MetalDevice::tex_alloc(device_texture &mem)
+{
+ MTLStorageMode storage_mode = MTLStorageModeManaged;
+ if (@available(macos 10.15, *)) {
+ if ([mtlDevice hasUnifiedMemory] &&
+ device_vendor !=
+ METAL_GPU_INTEL) { /* Intel GPUs don't support MTLStorageModeShared for MTLTextures */
+ storage_mode = MTLStorageModeShared;
+ }
+ }
+
+ /* General variables for both architectures */
+ string bind_name = mem.name;
+ size_t dsize = datatype_size(mem.data_type);
+ size_t size = mem.memory_size();
+
+ /* sampler_index maps into the GPU's constant 'metal_samplers' array */
+ uint64_t sampler_index = mem.info.extension;
+ if (mem.info.interpolation != INTERPOLATION_CLOSEST) {
+ sampler_index += 3;
+ }
+
+ /* Image Texture Storage */
+ MTLPixelFormat format;
+ switch (mem.data_type) {
+ case TYPE_UCHAR: {
+ MTLPixelFormat formats[] = {MTLPixelFormatR8Unorm,
+ MTLPixelFormatRG8Unorm,
+ MTLPixelFormatInvalid,
+ MTLPixelFormatRGBA8Unorm};
+ format = formats[mem.data_elements - 1];
+ } break;
+ case TYPE_UINT16: {
+ MTLPixelFormat formats[] = {MTLPixelFormatR16Unorm,
+ MTLPixelFormatRG16Unorm,
+ MTLPixelFormatInvalid,
+ MTLPixelFormatRGBA16Unorm};
+ format = formats[mem.data_elements - 1];
+ } break;
+ case TYPE_UINT: {
+ MTLPixelFormat formats[] = {MTLPixelFormatR32Uint,
+ MTLPixelFormatRG32Uint,
+ MTLPixelFormatInvalid,
+ MTLPixelFormatRGBA32Uint};
+ format = formats[mem.data_elements - 1];
+ } break;
+ case TYPE_INT: {
+ MTLPixelFormat formats[] = {MTLPixelFormatR32Sint,
+ MTLPixelFormatRG32Sint,
+ MTLPixelFormatInvalid,
+ MTLPixelFormatRGBA32Sint};
+ format = formats[mem.data_elements - 1];
+ } break;
+ case TYPE_FLOAT: {
+ MTLPixelFormat formats[] = {MTLPixelFormatR32Float,
+ MTLPixelFormatRG32Float,
+ MTLPixelFormatInvalid,
+ MTLPixelFormatRGBA32Float};
+ format = formats[mem.data_elements - 1];
+ } break;
+ case TYPE_HALF: {
+ MTLPixelFormat formats[] = {MTLPixelFormatR16Float,
+ MTLPixelFormatRG16Float,
+ MTLPixelFormatInvalid,
+ MTLPixelFormatRGBA16Float};
+ format = formats[mem.data_elements - 1];
+ } break;
+ default:
+ assert(0);
+ return;
+ }
+
+ assert(format != MTLPixelFormatInvalid);
+
+ id<MTLTexture> mtlTexture = nil;
+ size_t src_pitch = mem.data_width * dsize * mem.data_elements;
+
+ if (mem.data_depth > 1) {
+ /* 3D texture using array */
+ MTLTextureDescriptor *desc;
+
+ desc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:format
+ width:mem.data_width
+ height:mem.data_height
+ mipmapped:NO];
+
+ desc.storageMode = storage_mode;
+ desc.usage = MTLTextureUsageShaderRead;
+
+ desc.textureType = MTLTextureType3D;
+ desc.depth = mem.data_depth;
+
+ VLOG(2) << "Texture 3D allocate: " << mem.name << ", "
+ << string_human_readable_number(mem.memory_size()) << " bytes. ("
+ << string_human_readable_size(mem.memory_size()) << ")";
+
+ mtlTexture = [mtlDevice newTextureWithDescriptor:desc];
+ assert(mtlTexture);
+
+ if (!mtlTexture) {
+ return;
+ }
+
+ const size_t imageBytes = src_pitch * mem.data_height;
+ for (size_t d = 0; d < mem.data_depth; d++) {
+ const size_t offset = d * imageBytes;
+ [mtlTexture replaceRegion:MTLRegionMake3D(0, 0, d, mem.data_width, mem.data_height, 1)
+ mipmapLevel:0
+ slice:0
+ withBytes:(uint8_t *)mem.host_pointer + offset
+ bytesPerRow:src_pitch
+ bytesPerImage:0];
+ }
+ }
+ else if (mem.data_height > 0) {
+ /* 2D texture */
+ MTLTextureDescriptor *desc;
+
+ desc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:format
+ width:mem.data_width
+ height:mem.data_height
+ mipmapped:NO];
+
+ desc.storageMode = storage_mode;
+ desc.usage = MTLTextureUsageShaderRead;
+
+ VLOG(2) << "Texture 2D allocate: " << mem.name << ", "
+ << string_human_readable_number(mem.memory_size()) << " bytes. ("
+ << string_human_readable_size(mem.memory_size()) << ")";
+
+ mtlTexture = [mtlDevice newTextureWithDescriptor:desc];
+ assert(mtlTexture);
+
+ [mtlTexture replaceRegion:MTLRegionMake2D(0, 0, mem.data_width, mem.data_height)
+ mipmapLevel:0
+ withBytes:mem.host_pointer
+ bytesPerRow:src_pitch];
+ }
+ else {
+ assert(0);
+ /* 1D texture, using linear memory. */
+ }
+
+ mem.device_pointer = (device_ptr)mtlTexture;
+ mem.device_size = size;
+ stats.mem_alloc(size);
+
+ std::lock_guard<std::recursive_mutex> lock(metal_mem_map_mutex);
+ MetalMem *mmem = new MetalMem;
+ metal_mem_map[&mem] = std::unique_ptr<MetalMem>(mmem);
+ mmem->mem = &mem;
+ mmem->mtlTexture = mtlTexture;
+
+ /* Resize once */
+ const uint slot = mem.slot;
+ if (slot >= texture_info.size()) {
+ /* Allocate some slots in advance, to reduce amount
+ * of re-allocations. */
+ texture_info.resize(slot + 128);
+ texture_slot_map.resize(slot + 128);
+
+ ssize_t min_buffer_length = sizeof(void *) * texture_info.size();
+ if (!texture_bindings_2d || (texture_bindings_2d.length < min_buffer_length)) {
+ if (texture_bindings_2d) {
+ delayed_free_list.push_back(texture_bindings_2d);
+ delayed_free_list.push_back(texture_bindings_3d);
+
+ stats.mem_free(texture_bindings_2d.allocatedSize + texture_bindings_3d.allocatedSize);
+ }
+ texture_bindings_2d = [mtlDevice newBufferWithLength:min_buffer_length
+ options:default_storage_mode];
+ texture_bindings_3d = [mtlDevice newBufferWithLength:min_buffer_length
+ options:default_storage_mode];
+
+ stats.mem_alloc(texture_bindings_2d.allocatedSize + texture_bindings_3d.allocatedSize);
+ }
+ }
+
+ if (@available(macos 10.14, *)) {
+ /* Optimize the texture for GPU access. */
+ id<MTLCommandBuffer> commandBuffer = [mtlGeneralCommandQueue commandBuffer];
+ id<MTLBlitCommandEncoder> blitCommandEncoder = [commandBuffer blitCommandEncoder];
+ [blitCommandEncoder optimizeContentsForGPUAccess:mtlTexture];
+ [blitCommandEncoder endEncoding];
+ [commandBuffer commit];
+ }
+
+ /* Set Mapping and tag that we need to (re-)upload to device */
+ texture_slot_map[slot] = mtlTexture;
+ texture_info[slot] = mem.info;
+ need_texture_info = true;
+
+ texture_info[slot].data = uint64_t(slot) | (sampler_index << 32);
+}
+
+void MetalDevice::tex_free(device_texture &mem)
+{
+ if (metal_mem_map.count(&mem)) {
+ std::lock_guard<std::recursive_mutex> lock(metal_mem_map_mutex);
+ MetalMem &mmem = *metal_mem_map.at(&mem);
+
+ assert(texture_slot_map[mem.slot] == mmem.mtlTexture);
+ texture_slot_map[mem.slot] = nil;
+
+ if (mmem.mtlTexture) {
+ /* Free bindless texture. */
+ delayed_free_list.push_back(mmem.mtlTexture);
+ mmem.mtlTexture = nil;
+ }
+ stats.mem_free(mem.device_size);
+ mem.device_pointer = 0;
+ mem.device_size = 0;
+ metal_mem_map.erase(&mem);
+ }
+}
+
+unique_ptr<DeviceQueue> MetalDevice::gpu_queue_create()
+{
+ return make_unique<MetalDeviceQueue>(this);
+}
+
+bool MetalDevice::should_use_graphics_interop()
+{
+ /* METAL_WIP - provide fast interop */
+ return false;
+}
+
+void MetalDevice::flush_delayed_free_list()
+{
+ /* free any Metal buffers that may have been freed by host while a command
+ * buffer was being generated. This function should be called after each
+ * completion of a command buffer */
+ std::lock_guard<std::recursive_mutex> lock(metal_mem_map_mutex);
+ for (auto &it : delayed_free_list) {
+ [it release];
+ }
+ delayed_free_list.clear();
+}
+
+void MetalDevice::build_bvh(BVH *bvh, Progress &progress, bool refit)
+{
+ if (bvh->params.bvh_layout == BVH_LAYOUT_BVH2) {
+ Device::build_bvh(bvh, progress, refit);
+ return;
+ }
+
+ BVHMetal *bvh_metal = static_cast<BVHMetal *>(bvh);
+ bvh_metal->motion_blur = motion_blur;
+ if (bvh_metal->build(progress, mtlDevice, mtlGeneralCommandQueue, refit)) {
+
+ if (@available(macos 11.0, *)) {
+ if (bvh->params.top_level) {
+ bvhMetalRT = bvh_metal;
+ }
+ }
+ }
+}
+
+CCL_NAMESPACE_END
+
+#endif
diff --git a/intern/cycles/device/metal/kernel.h b/intern/cycles/device/metal/kernel.h
new file mode 100644
index 00000000000..4874af1bfa6
--- /dev/null
+++ b/intern/cycles/device/metal/kernel.h
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#ifdef WITH_METAL
+
+# include "device/kernel.h"
+# include <Metal/Metal.h>
+
+CCL_NAMESPACE_BEGIN
+
+class MetalDevice;
+
+enum {
+ METALRT_FUNC_DEFAULT_TRI,
+ METALRT_FUNC_DEFAULT_BOX,
+ METALRT_FUNC_SHADOW_TRI,
+ METALRT_FUNC_SHADOW_BOX,
+ METALRT_FUNC_LOCAL_TRI,
+ METALRT_FUNC_LOCAL_BOX,
+ METALRT_FUNC_CURVE_RIBBON,
+ METALRT_FUNC_CURVE_RIBBON_SHADOW,
+ METALRT_FUNC_CURVE_ALL,
+ METALRT_FUNC_CURVE_ALL_SHADOW,
+ METALRT_FUNC_NUM
+};
+
+enum { METALRT_TABLE_DEFAULT, METALRT_TABLE_SHADOW, METALRT_TABLE_LOCAL, METALRT_TABLE_NUM };
+
+/* Pipeline State Object types */
+enum {
+ /* A kernel that can be used with all scenes, supporting all features.
+ * It is slow to compile, but only needs to be compiled once and is then
+ * cached for future render sessions. This allows a render to get underway
+ * on the GPU quickly.
+ */
+ PSO_GENERIC,
+
+ /* A kernel that is relatively quick to compile, but is specialized for the
+ * scene being rendered. It only contains the functionality and even baked in
+ * constants for values that means it needs to be recompiled whenever a
+ * dependent setting is changed. The render performance of this kernel is
+ * significantly faster though, and justifies the extra compile time.
+ */
+ /* METAL_WIP: This isn't used and will require more changes to enable. */
+ PSO_SPECIALISED,
+
+ PSO_NUM
+};
+
+const char *kernel_type_as_string(int kernel_type);
+
+struct MetalKernelPipeline {
+ void release()
+ {
+ if (pipeline) {
+ [pipeline release];
+ pipeline = nil;
+ if (@available(macOS 11.0, *)) {
+ for (int i = 0; i < METALRT_TABLE_NUM; i++) {
+ if (intersection_func_table[i]) {
+ [intersection_func_table[i] release];
+ intersection_func_table[i] = nil;
+ }
+ }
+ }
+ }
+ if (function) {
+ [function release];
+ function = nil;
+ }
+ if (@available(macOS 11.0, *)) {
+ for (int i = 0; i < METALRT_TABLE_NUM; i++) {
+ if (intersection_func_table[i]) {
+ [intersection_func_table[i] release];
+ }
+ }
+ }
+ }
+
+ bool loaded = false;
+ id<MTLFunction> function = nil;
+ id<MTLComputePipelineState> pipeline = nil;
+
+ API_AVAILABLE(macos(11.0))
+ id<MTLIntersectionFunctionTable> intersection_func_table[METALRT_TABLE_NUM] = {nil};
+};
+
+struct MetalKernelLoadDesc {
+ int pso_index = 0;
+ const char *function_name = nullptr;
+ int kernel_index = 0;
+ int threads_per_threadgroup = 0;
+ MTLFunctionConstantValues *constant_values = nullptr;
+ NSArray *linked_functions = nullptr;
+
+ struct IntersectorFunctions {
+ NSArray *defaults;
+ NSArray *shadow;
+ NSArray *local;
+ NSArray *operator[](int index) const
+ {
+ if (index == METALRT_TABLE_DEFAULT)
+ return defaults;
+ if (index == METALRT_TABLE_SHADOW)
+ return shadow;
+ return local;
+ }
+ } intersector_functions = {nullptr};
+};
+
+/* Metal kernel and associate occupancy information. */
+class MetalDeviceKernel {
+ public:
+ ~MetalDeviceKernel();
+
+ bool load(MetalDevice *device, MetalKernelLoadDesc const &desc, class MD5Hash const &md5);
+
+ void mark_loaded(int pso_index)
+ {
+ pso[pso_index].loaded = true;
+ }
+
+ int get_num_threads_per_block() const
+ {
+ return num_threads_per_block;
+ }
+ const MetalKernelPipeline &get_pso() const;
+
+ double load_duration = 0.0;
+
+ private:
+ MetalKernelPipeline pso[PSO_NUM];
+
+ int num_threads_per_block = 0;
+};
+
+/* Cache of Metal kernels for each DeviceKernel. */
+class MetalDeviceKernels {
+ public:
+ bool load(MetalDevice *device, int kernel_type);
+ bool available(DeviceKernel kernel) const;
+ const MetalDeviceKernel &get(DeviceKernel kernel) const;
+
+ MetalDeviceKernel kernels_[DEVICE_KERNEL_NUM];
+
+ id<MTLFunction> rt_intersection_funcs[PSO_NUM][METALRT_FUNC_NUM] = {{nil}};
+
+ string loaded_md5[PSO_NUM];
+};
+
+CCL_NAMESPACE_END
+
+#endif /* WITH_METAL */
diff --git a/intern/cycles/device/metal/kernel.mm b/intern/cycles/device/metal/kernel.mm
new file mode 100644
index 00000000000..f948a8a0a0f
--- /dev/null
+++ b/intern/cycles/device/metal/kernel.mm
@@ -0,0 +1,525 @@
+/*
+ * Copyright 2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifdef WITH_METAL
+
+# include "device/metal/kernel.h"
+# include "device/metal/device_impl.h"
+# include "util/md5.h"
+# include "util/path.h"
+# include "util/tbb.h"
+# include "util/time.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* limit to 2 MTLCompiler instances */
+int max_mtlcompiler_threads = 2;
+
+const char *kernel_type_as_string(int kernel_type)
+{
+ switch (kernel_type) {
+ case PSO_GENERIC:
+ return "PSO_GENERIC";
+ case PSO_SPECIALISED:
+ return "PSO_SPECIALISED";
+ default:
+ assert(0);
+ }
+ return "";
+}
+
+MetalDeviceKernel::~MetalDeviceKernel()
+{
+ for (int i = 0; i < PSO_NUM; i++) {
+ pso[i].release();
+ }
+}
+
+bool MetalDeviceKernel::load(MetalDevice *device,
+ MetalKernelLoadDesc const &desc_in,
+ MD5Hash const &md5)
+{
+ __block MetalKernelLoadDesc const desc(desc_in);
+ if (desc.kernel_index == DEVICE_KERNEL_INTEGRATOR_MEGAKERNEL) {
+ /* skip megakernel */
+ return true;
+ }
+
+ bool use_binary_archive = true;
+ if (getenv("CYCLES_METAL_DISABLE_BINARY_ARCHIVES")) {
+ use_binary_archive = false;
+ }
+
+ id<MTLBinaryArchive> archive = nil;
+ string metalbin_path;
+ if (use_binary_archive) {
+ NSProcessInfo *processInfo = [NSProcessInfo processInfo];
+ string osVersion = [[processInfo operatingSystemVersionString] UTF8String];
+ MD5Hash local_md5(md5);
+ local_md5.append(osVersion);
+ string metalbin_name = string(desc.function_name) + "." + local_md5.get_hex() +
+ to_string(desc.pso_index) + ".bin";
+ metalbin_path = path_cache_get(path_join("kernels", metalbin_name));
+ path_create_directories(metalbin_path);
+
+ if (path_exists(metalbin_path) && use_binary_archive) {
+ if (@available(macOS 11.0, *)) {
+ MTLBinaryArchiveDescriptor *archiveDesc = [[MTLBinaryArchiveDescriptor alloc] init];
+ archiveDesc.url = [NSURL fileURLWithPath:@(metalbin_path.c_str())];
+ archive = [device->mtlDevice newBinaryArchiveWithDescriptor:archiveDesc error:nil];
+ [archiveDesc release];
+ }
+ }
+ }
+
+ NSString *entryPoint = [@(desc.function_name) copy];
+
+ NSError *error = NULL;
+ if (@available(macOS 11.0, *)) {
+ MTLFunctionDescriptor *func_desc = [MTLIntersectionFunctionDescriptor functionDescriptor];
+ func_desc.name = entryPoint;
+ if (desc.constant_values) {
+ func_desc.constantValues = desc.constant_values;
+ }
+ pso[desc.pso_index].function = [device->mtlLibrary[desc.pso_index]
+ newFunctionWithDescriptor:func_desc
+ error:&error];
+ }
+ [entryPoint release];
+
+ if (pso[desc.pso_index].function == nil) {
+ NSString *err = [error localizedDescription];
+ string errors = [err UTF8String];
+
+ device->set_error(
+ string_printf("Error getting function \"%s\": %s", desc.function_name, errors.c_str()));
+ return false;
+ }
+
+ pso[desc.pso_index].function.label = [@(desc.function_name) copy];
+
+ __block MTLComputePipelineDescriptor *computePipelineStateDescriptor =
+ [[MTLComputePipelineDescriptor alloc] init];
+
+ computePipelineStateDescriptor.buffers[0].mutability = MTLMutabilityImmutable;
+ computePipelineStateDescriptor.buffers[1].mutability = MTLMutabilityImmutable;
+ computePipelineStateDescriptor.buffers[2].mutability = MTLMutabilityImmutable;
+
+ if (@available(macos 10.14, *)) {
+ computePipelineStateDescriptor.maxTotalThreadsPerThreadgroup = desc.threads_per_threadgroup;
+ }
+ computePipelineStateDescriptor.threadGroupSizeIsMultipleOfThreadExecutionWidth = true;
+
+ computePipelineStateDescriptor.computeFunction = pso[desc.pso_index].function;
+ if (@available(macOS 11.0, *)) {
+ /* Attach the additional functions to an MTLLinkedFunctions object */
+ if (desc.linked_functions) {
+ computePipelineStateDescriptor.linkedFunctions = [[MTLLinkedFunctions alloc] init];
+ computePipelineStateDescriptor.linkedFunctions.functions = desc.linked_functions;
+ }
+
+ computePipelineStateDescriptor.maxCallStackDepth = 1;
+ }
+
+ /* Create a new Compute pipeline state object */
+ MTLPipelineOption pipelineOptions = MTLPipelineOptionNone;
+
+ bool creating_new_archive = false;
+ if (@available(macOS 11.0, *)) {
+ if (use_binary_archive) {
+ if (!archive) {
+ MTLBinaryArchiveDescriptor *archiveDesc = [[MTLBinaryArchiveDescriptor alloc] init];
+ archiveDesc.url = nil;
+ archive = [device->mtlDevice newBinaryArchiveWithDescriptor:archiveDesc error:nil];
+ creating_new_archive = true;
+
+ double starttime = time_dt();
+
+ if (![archive addComputePipelineFunctionsWithDescriptor:computePipelineStateDescriptor
+ error:&error]) {
+ NSString *errStr = [error localizedDescription];
+ metal_printf("Failed to add PSO to archive:\n%s\n",
+ errStr ? [errStr UTF8String] : "nil");
+ }
+ else {
+ double duration = time_dt() - starttime;
+ metal_printf("%2d | %-55s | %7.2fs\n",
+ desc.kernel_index,
+ device_kernel_as_string((DeviceKernel)desc.kernel_index),
+ duration);
+
+ if (desc.pso_index == PSO_GENERIC) {
+ this->load_duration = duration;
+ }
+ }
+ }
+ computePipelineStateDescriptor.binaryArchives = [NSArray arrayWithObjects:archive, nil];
+ pipelineOptions = MTLPipelineOptionFailOnBinaryArchiveMiss;
+ }
+ }
+
+ double starttime = time_dt();
+
+ MTLNewComputePipelineStateWithReflectionCompletionHandler completionHandler = ^(
+ id<MTLComputePipelineState> computePipelineState,
+ MTLComputePipelineReflection *reflection,
+ NSError *error) {
+ bool recreate_archive = false;
+ if (computePipelineState == nil && archive && !creating_new_archive) {
+
+ assert(0);
+
+ NSString *errStr = [error localizedDescription];
+ metal_printf(
+ "Failed to create compute pipeline state \"%s\" from archive - attempting recreation... "
+ "(error: %s)\n",
+ device_kernel_as_string((DeviceKernel)desc.kernel_index),
+ errStr ? [errStr UTF8String] : "nil");
+ computePipelineState = [device->mtlDevice
+ newComputePipelineStateWithDescriptor:computePipelineStateDescriptor
+ options:MTLPipelineOptionNone
+ reflection:nullptr
+ error:&error];
+ recreate_archive = true;
+ }
+
+ double duration = time_dt() - starttime;
+
+ if (computePipelineState == nil) {
+ NSString *errStr = [error localizedDescription];
+ device->set_error(string_printf("Failed to create compute pipeline state \"%s\", error: \n",
+ device_kernel_as_string((DeviceKernel)desc.kernel_index)) +
+ (errStr ? [errStr UTF8String] : "nil"));
+ metal_printf("%2d | %-55s | %7.2fs | FAILED!\n",
+ desc.kernel_index,
+ device_kernel_as_string((DeviceKernel)desc.kernel_index),
+ duration);
+ return;
+ }
+
+ pso[desc.pso_index].pipeline = computePipelineState;
+ num_threads_per_block = round_down(computePipelineState.maxTotalThreadsPerThreadgroup,
+ computePipelineState.threadExecutionWidth);
+ num_threads_per_block = std::max(num_threads_per_block,
+ (int)computePipelineState.threadExecutionWidth);
+
+ if (!use_binary_archive) {
+ metal_printf("%2d | %-55s | %7.2fs\n",
+ desc.kernel_index,
+ device_kernel_as_string((DeviceKernel)desc.kernel_index),
+ duration);
+
+ if (desc.pso_index == PSO_GENERIC) {
+ this->load_duration = duration;
+ }
+ }
+
+ if (@available(macOS 11.0, *)) {
+ if (creating_new_archive || recreate_archive) {
+ if (![archive serializeToURL:[NSURL fileURLWithPath:@(metalbin_path.c_str())]
+ error:&error]) {
+ metal_printf("Failed to save binary archive, error:\n%s\n",
+ [[error localizedDescription] UTF8String]);
+ }
+ }
+ }
+
+ [computePipelineStateDescriptor release];
+ computePipelineStateDescriptor = nil;
+
+ if (device->use_metalrt && desc.linked_functions) {
+ for (int table = 0; table < METALRT_TABLE_NUM; table++) {
+ if (@available(macOS 11.0, *)) {
+ MTLIntersectionFunctionTableDescriptor *ift_desc =
+ [[MTLIntersectionFunctionTableDescriptor alloc] init];
+ ift_desc.functionCount = desc.intersector_functions[table].count;
+
+ pso[desc.pso_index].intersection_func_table[table] = [pso[desc.pso_index].pipeline
+ newIntersectionFunctionTableWithDescriptor:ift_desc];
+
+ /* Finally write the function handles into this pipeline's table */
+ for (int i = 0; i < 2; i++) {
+ id<MTLFunctionHandle> handle = [pso[desc.pso_index].pipeline
+ functionHandleWithFunction:desc.intersector_functions[table][i]];
+ [pso[desc.pso_index].intersection_func_table[table] setFunction:handle atIndex:i];
+ }
+ }
+ }
+ }
+
+ mark_loaded(desc.pso_index);
+ };
+
+ if (desc.pso_index == PSO_SPECIALISED) {
+ /* Asynchronous load */
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+ NSError *error;
+ id<MTLComputePipelineState> pipeline = [device->mtlDevice
+ newComputePipelineStateWithDescriptor:computePipelineStateDescriptor
+ options:pipelineOptions
+ reflection:nullptr
+ error:&error];
+ completionHandler(pipeline, nullptr, error);
+ });
+ }
+ else {
+ /* Block on load to ensure we continue with a valid kernel function */
+ id<MTLComputePipelineState> pipeline = [device->mtlDevice
+ newComputePipelineStateWithDescriptor:computePipelineStateDescriptor
+ options:pipelineOptions
+ reflection:nullptr
+ error:&error];
+ completionHandler(pipeline, nullptr, error);
+ }
+
+ return true;
+}
+
+const MetalKernelPipeline &MetalDeviceKernel::get_pso() const
+{
+ if (pso[PSO_SPECIALISED].loaded) {
+ return pso[PSO_SPECIALISED];
+ }
+
+ assert(pso[PSO_GENERIC].loaded);
+ return pso[PSO_GENERIC];
+}
+
+bool MetalDeviceKernels::load(MetalDevice *device, int kernel_type)
+{
+ bool any_error = false;
+
+ MD5Hash md5;
+
+ /* Build the function constant table */
+ MTLFunctionConstantValues *constant_values = nullptr;
+ if (kernel_type == PSO_SPECIALISED) {
+ constant_values = [MTLFunctionConstantValues new];
+
+# define KERNEL_FILM(_type, name) \
+ [constant_values setConstantValue:&data.film.name \
+ type:get_MTLDataType_##_type() \
+ atIndex:KernelData_film_##name]; \
+ md5.append((uint8_t *)&data.film.name, sizeof(data.film.name));
+
+# define KERNEL_BACKGROUND(_type, name) \
+ [constant_values setConstantValue:&data.background.name \
+ type:get_MTLDataType_##_type() \
+ atIndex:KernelData_background_##name]; \
+ md5.append((uint8_t *)&data.background.name, sizeof(data.background.name));
+
+# define KERNEL_INTEGRATOR(_type, name) \
+ [constant_values setConstantValue:&data.integrator.name \
+ type:get_MTLDataType_##_type() \
+ atIndex:KernelData_integrator_##name]; \
+ md5.append((uint8_t *)&data.integrator.name, sizeof(data.integrator.name));
+
+# define KERNEL_BVH(_type, name) \
+ [constant_values setConstantValue:&data.bvh.name \
+ type:get_MTLDataType_##_type() \
+ atIndex:KernelData_bvh_##name]; \
+ md5.append((uint8_t *)&data.bvh.name, sizeof(data.bvh.name));
+
+ /* METAL_WIP: populate constant_values based on KernelData */
+ assert(0);
+ /*
+ const KernelData &data = device->launch_params.data;
+ # include "kernel/types/background.h"
+ # include "kernel/types/bvh.h"
+ # include "kernel/types/film.h"
+ # include "kernel/types/integrator.h"
+ */
+ }
+
+ if (device->use_metalrt) {
+ if (@available(macOS 11.0, *)) {
+ /* create the id<MTLFunction> for each intersection function */
+ const char *function_names[] = {
+ "__anyhit__cycles_metalrt_visibility_test_tri",
+ "__anyhit__cycles_metalrt_visibility_test_box",
+ "__anyhit__cycles_metalrt_shadow_all_hit_tri",
+ "__anyhit__cycles_metalrt_shadow_all_hit_box",
+ "__anyhit__cycles_metalrt_local_hit_tri",
+ "__anyhit__cycles_metalrt_local_hit_box",
+ "__intersection__curve_ribbon",
+ "__intersection__curve_ribbon_shadow",
+ "__intersection__curve_all",
+ "__intersection__curve_all_shadow",
+ };
+ assert(sizeof(function_names) / sizeof(function_names[0]) == METALRT_FUNC_NUM);
+
+ MTLFunctionDescriptor *desc = [MTLIntersectionFunctionDescriptor functionDescriptor];
+ if (kernel_type == PSO_SPECIALISED) {
+ desc.constantValues = constant_values;
+ }
+ for (int i = 0; i < METALRT_FUNC_NUM; i++) {
+ const char *function_name = function_names[i];
+ desc.name = [@(function_name) copy];
+
+ NSError *error = NULL;
+ rt_intersection_funcs[kernel_type][i] = [device->mtlLibrary[kernel_type]
+ newFunctionWithDescriptor:desc
+ error:&error];
+
+ if (rt_intersection_funcs[kernel_type][i] == nil) {
+ NSString *err = [error localizedDescription];
+ string errors = [err UTF8String];
+
+ device->set_error(string_printf(
+ "Error getting intersection function \"%s\": %s", function_name, errors.c_str()));
+ any_error = true;
+ break;
+ }
+
+ rt_intersection_funcs[kernel_type][i].label = [@(function_name) copy];
+ }
+ }
+ }
+ md5.append(device->source_used_for_compile[kernel_type]);
+
+ string hash = md5.get_hex();
+ if (loaded_md5[kernel_type] == hash) {
+ return true;
+ }
+
+ if (!any_error) {
+ NSArray *table_functions[METALRT_TABLE_NUM] = {nil};
+ NSArray *function_list = nil;
+
+ if (device->use_metalrt) {
+ id<MTLFunction> box_intersect_default = nil;
+ id<MTLFunction> box_intersect_shadow = nil;
+ if (device->kernel_features & KERNEL_FEATURE_HAIR) {
+ /* Add curve intersection programs. */
+ if (device->kernel_features & KERNEL_FEATURE_HAIR_THICK) {
+ /* Slower programs for thick hair since that also slows down ribbons.
+ * Ideally this should not be needed. */
+ box_intersect_default = rt_intersection_funcs[kernel_type][METALRT_FUNC_CURVE_ALL];
+ box_intersect_shadow = rt_intersection_funcs[kernel_type][METALRT_FUNC_CURVE_ALL_SHADOW];
+ }
+ else {
+ box_intersect_default = rt_intersection_funcs[kernel_type][METALRT_FUNC_CURVE_RIBBON];
+ box_intersect_shadow =
+ rt_intersection_funcs[kernel_type][METALRT_FUNC_CURVE_RIBBON_SHADOW];
+ }
+ }
+ table_functions[METALRT_TABLE_DEFAULT] = [NSArray
+ arrayWithObjects:rt_intersection_funcs[kernel_type][METALRT_FUNC_DEFAULT_TRI],
+ box_intersect_default ?
+ box_intersect_default :
+ rt_intersection_funcs[kernel_type][METALRT_FUNC_DEFAULT_BOX],
+ nil];
+ table_functions[METALRT_TABLE_SHADOW] = [NSArray
+ arrayWithObjects:rt_intersection_funcs[kernel_type][METALRT_FUNC_SHADOW_TRI],
+ box_intersect_shadow ?
+ box_intersect_shadow :
+ rt_intersection_funcs[kernel_type][METALRT_FUNC_SHADOW_BOX],
+ nil];
+ table_functions[METALRT_TABLE_LOCAL] = [NSArray
+ arrayWithObjects:rt_intersection_funcs[kernel_type][METALRT_FUNC_LOCAL_TRI],
+ rt_intersection_funcs[kernel_type][METALRT_FUNC_LOCAL_BOX],
+ nil];
+
+ NSMutableSet *unique_functions = [NSMutableSet
+ setWithArray:table_functions[METALRT_TABLE_DEFAULT]];
+ [unique_functions addObjectsFromArray:table_functions[METALRT_TABLE_SHADOW]];
+ [unique_functions addObjectsFromArray:table_functions[METALRT_TABLE_LOCAL]];
+
+ function_list = [[NSArray arrayWithArray:[unique_functions allObjects]]
+ sortedArrayUsingComparator:^NSComparisonResult(id<MTLFunction> f1, id<MTLFunction> f2) {
+ return [f1.label compare:f2.label];
+ }];
+
+ unique_functions = nil;
+ }
+
+ metal_printf("Starting %s \"cycles_metal_...\" pipeline builds\n",
+ kernel_type_as_string(kernel_type));
+
+ tbb::task_arena local_arena(max_mtlcompiler_threads);
+ local_arena.execute([&]() {
+ tbb::parallel_for(int(0), int(DEVICE_KERNEL_NUM), [&](int i) {
+ /* skip megakernel */
+ if (i == DEVICE_KERNEL_INTEGRATOR_MEGAKERNEL) {
+ return;
+ }
+
+ /* Only specialize kernels where it can make an impact. */
+ if (kernel_type == PSO_SPECIALISED) {
+ if (i < DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST ||
+ i > DEVICE_KERNEL_INTEGRATOR_MEGAKERNEL) {
+ return;
+ }
+ }
+
+ MetalDeviceKernel &kernel = kernels_[i];
+
+ const std::string function_name = std::string("cycles_metal_") +
+ device_kernel_as_string((DeviceKernel)i);
+ int threads_per_threadgroup = device->max_threads_per_threadgroup;
+ if (i > DEVICE_KERNEL_INTEGRATOR_MEGAKERNEL && i < DEVICE_KERNEL_INTEGRATOR_RESET) {
+ /* Always use 512 for the sorting kernels */
+ threads_per_threadgroup = 512;
+ }
+
+ NSArray *kernel_function_list = nil;
+
+ if (i == DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST ||
+ i == DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW ||
+ i == DEVICE_KERNEL_INTEGRATOR_INTERSECT_SUBSURFACE ||
+ i == DEVICE_KERNEL_INTEGRATOR_INTERSECT_VOLUME_STACK ||
+ i == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE) {
+ kernel_function_list = function_list;
+ }
+
+ MetalKernelLoadDesc desc;
+ desc.pso_index = kernel_type;
+ desc.kernel_index = i;
+ desc.linked_functions = kernel_function_list;
+ desc.intersector_functions.defaults = table_functions[METALRT_TABLE_DEFAULT];
+ desc.intersector_functions.shadow = table_functions[METALRT_TABLE_SHADOW];
+ desc.intersector_functions.local = table_functions[METALRT_TABLE_LOCAL];
+ desc.constant_values = constant_values;
+ desc.threads_per_threadgroup = threads_per_threadgroup;
+ desc.function_name = function_name.c_str();
+
+ bool success = kernel.load(device, desc, md5);
+
+ any_error |= !success;
+ });
+ });
+ }
+
+ bool loaded = !any_error;
+ if (loaded) {
+ loaded_md5[kernel_type] = hash;
+ }
+ return loaded;
+}
+
+const MetalDeviceKernel &MetalDeviceKernels::get(DeviceKernel kernel) const
+{
+ return kernels_[(int)kernel];
+}
+
+bool MetalDeviceKernels::available(DeviceKernel kernel) const
+{
+ return kernels_[(int)kernel].get_pso().function != nil;
+}
+
+CCL_NAMESPACE_END
+
+#endif /* WITH_METAL*/
diff --git a/intern/cycles/device/metal/queue.h b/intern/cycles/device/metal/queue.h
new file mode 100644
index 00000000000..64c8bb79c49
--- /dev/null
+++ b/intern/cycles/device/metal/queue.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#ifdef WITH_METAL
+
+# include "device/kernel.h"
+# include "device/memory.h"
+# include "device/queue.h"
+
+# include "device/metal/util.h"
+# include "kernel/device/metal/globals.h"
+
+# define metal_printf VLOG(4) << string_printf
+
+CCL_NAMESPACE_BEGIN
+
+class MetalDevice;
+
+/* Base class for Metal queues. */
+class MetalDeviceQueue : public DeviceQueue {
+ public:
+ MetalDeviceQueue(MetalDevice *device);
+ ~MetalDeviceQueue();
+
+ virtual int num_concurrent_states(const size_t) const override;
+ virtual int num_concurrent_busy_states() const override;
+
+ virtual void init_execution() override;
+
+ virtual bool enqueue(DeviceKernel kernel,
+ const int work_size,
+ DeviceKernelArguments const &args) override;
+
+ virtual bool synchronize() override;
+
+ virtual void zero_to_device(device_memory &mem) override;
+ virtual void copy_to_device(device_memory &mem) override;
+ virtual void copy_from_device(device_memory &mem) override;
+
+ virtual bool kernel_available(DeviceKernel kernel) const override;
+
+ protected:
+ void prepare_resources(DeviceKernel kernel);
+
+ id<MTLComputeCommandEncoder> get_compute_encoder(DeviceKernel kernel);
+ id<MTLBlitCommandEncoder> get_blit_encoder();
+
+ MetalDevice *metal_device;
+ MetalBufferPool temp_buffer_pool;
+
+ API_AVAILABLE(macos(11.0), ios(14.0))
+ MTLCommandBufferDescriptor *command_buffer_desc = nullptr;
+ id<MTLDevice> mtlDevice = nil;
+ id<MTLCommandQueue> mtlCommandQueue = nil;
+ id<MTLCommandBuffer> mtlCommandBuffer = nil;
+ id<MTLComputeCommandEncoder> mtlComputeEncoder = nil;
+ id<MTLBlitCommandEncoder> mtlBlitEncoder = nil;
+ API_AVAILABLE(macos(10.14), ios(14.0))
+ id<MTLSharedEvent> shared_event = nil;
+ API_AVAILABLE(macos(10.14), ios(14.0))
+ MTLSharedEventListener *shared_event_listener = nil;
+
+ dispatch_queue_t event_queue;
+ dispatch_semaphore_t wait_semaphore;
+
+ struct CopyBack {
+ void *host_pointer;
+ void *gpu_mem;
+ uint64_t size;
+ };
+ std::vector<CopyBack> copy_back_mem;
+
+ uint64_t shared_event_id;
+ uint64_t command_buffers_submitted = 0;
+ uint64_t command_buffers_completed = 0;
+ Stats &stats;
+
+ void close_compute_encoder();
+ void close_blit_encoder();
+};
+
+CCL_NAMESPACE_END
+
+#endif /* WITH_METAL */
diff --git a/intern/cycles/device/metal/queue.mm b/intern/cycles/device/metal/queue.mm
new file mode 100644
index 00000000000..d04df09f49a
--- /dev/null
+++ b/intern/cycles/device/metal/queue.mm
@@ -0,0 +1,610 @@
+/*
+ * Copyright 2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifdef WITH_METAL
+
+# include "device/metal/queue.h"
+
+# include "device/metal/device_impl.h"
+# include "device/metal/kernel.h"
+
+# include "util/path.h"
+# include "util/string.h"
+# include "util/time.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* MetalDeviceQueue */
+
+MetalDeviceQueue::MetalDeviceQueue(MetalDevice *device)
+ : DeviceQueue(device), metal_device(device), stats(device->stats)
+{
+ if (@available(macos 11.0, *)) {
+ command_buffer_desc = [[MTLCommandBufferDescriptor alloc] init];
+ command_buffer_desc.errorOptions = MTLCommandBufferErrorOptionEncoderExecutionStatus;
+ }
+
+ mtlDevice = device->mtlDevice;
+ mtlCommandQueue = [mtlDevice newCommandQueue];
+
+ if (@available(macos 10.14, *)) {
+ shared_event = [mtlDevice newSharedEvent];
+ shared_event_id = 1;
+
+ /* Shareable event listener */
+ event_queue = dispatch_queue_create("com.cycles.metal.event_queue", NULL);
+ shared_event_listener = [[MTLSharedEventListener alloc] initWithDispatchQueue:event_queue];
+ }
+
+ wait_semaphore = dispatch_semaphore_create(0);
+}
+
+MetalDeviceQueue::~MetalDeviceQueue()
+{
+ /* Tidying up here isn't really practical - we should expect and require the work
+ * queue to be empty here. */
+ assert(mtlCommandBuffer == nil);
+ assert(command_buffers_submitted == command_buffers_completed);
+
+ if (@available(macos 10.14, *)) {
+ [shared_event_listener release];
+ [shared_event release];
+ }
+
+ if (@available(macos 11.0, *)) {
+ [command_buffer_desc release];
+ }
+ if (mtlCommandQueue) {
+ [mtlCommandQueue release];
+ mtlCommandQueue = nil;
+ }
+}
+
+int MetalDeviceQueue::num_concurrent_states(const size_t /*state_size*/) const
+{
+ /* METAL_WIP */
+ /* TODO: compute automatically. */
+ /* TODO: must have at least num_threads_per_block. */
+ int result = 1048576;
+ if (metal_device->device_vendor == METAL_GPU_AMD) {
+ result *= 2;
+ }
+ else if (metal_device->device_vendor == METAL_GPU_APPLE) {
+ result *= 4;
+ }
+ return result;
+}
+
+int MetalDeviceQueue::num_concurrent_busy_states() const
+{
+ /* METAL_WIP */
+ /* TODO: compute automatically. */
+ int result = 65536;
+ if (metal_device->device_vendor == METAL_GPU_AMD) {
+ result *= 2;
+ }
+ else if (metal_device->device_vendor == METAL_GPU_APPLE) {
+ result *= 4;
+ }
+ return result;
+}
+
+void MetalDeviceQueue::init_execution()
+{
+ /* Synchronize all textures and memory copies before executing task. */
+ metal_device->load_texture_info();
+
+ synchronize();
+}
+
+bool MetalDeviceQueue::enqueue(DeviceKernel kernel,
+ const int work_size,
+ DeviceKernelArguments const &args)
+{
+ if (metal_device->have_error()) {
+ return false;
+ }
+
+ VLOG(3) << "Metal queue launch " << device_kernel_as_string(kernel) << ", work_size "
+ << work_size;
+
+ const MetalDeviceKernel &metal_kernel = metal_device->kernels.get(kernel);
+ const MetalKernelPipeline &metal_kernel_pso = metal_kernel.get_pso();
+
+ id<MTLComputeCommandEncoder> mtlComputeCommandEncoder = get_compute_encoder(kernel);
+
+ /* Determine size requirement for argument buffer. */
+ size_t arg_buffer_length = 0;
+ for (size_t i = 0; i < args.count; i++) {
+ size_t size_in_bytes = args.sizes[i];
+ arg_buffer_length = round_up(arg_buffer_length, size_in_bytes) + size_in_bytes;
+ }
+ /* 256 is the Metal offset alignment for constant address space bindings */
+ arg_buffer_length = round_up(arg_buffer_length, 256);
+
+ /* Globals placed after "vanilla" arguments. */
+ size_t globals_offsets = arg_buffer_length;
+ arg_buffer_length += sizeof(KernelParamsMetal);
+ arg_buffer_length = round_up(arg_buffer_length, 256);
+
+ /* Metal ancillary bindless pointers. */
+ size_t metal_offsets = arg_buffer_length;
+ arg_buffer_length += metal_device->mtlAncillaryArgEncoder.encodedLength;
+ arg_buffer_length = round_up(arg_buffer_length, metal_device->mtlAncillaryArgEncoder.alignment);
+
+ /* Temporary buffer used to prepare arg_buffer */
+ uint8_t *init_arg_buffer = (uint8_t *)alloca(arg_buffer_length);
+ memset(init_arg_buffer, 0, arg_buffer_length);
+
+ /* Prepare the non-pointer "enqueue" arguments */
+ size_t bytes_written = 0;
+ for (size_t i = 0; i < args.count; i++) {
+ size_t size_in_bytes = args.sizes[i];
+ bytes_written = round_up(bytes_written, size_in_bytes);
+ if (args.types[i] != DeviceKernelArguments::POINTER) {
+ memcpy(init_arg_buffer + bytes_written, args.values[i], size_in_bytes);
+ }
+ bytes_written += size_in_bytes;
+ }
+
+ /* Prepare any non-pointer (i.e. plain-old-data) KernelParamsMetal data */
+ /* The plain-old-data is contiguous, continuing to the end of KernelParamsMetal */
+ size_t plain_old_launch_data_offset = offsetof(KernelParamsMetal, __integrator_state) +
+ sizeof(IntegratorStateGPU);
+ size_t plain_old_launch_data_size = sizeof(KernelParamsMetal) - plain_old_launch_data_offset;
+ memcpy(init_arg_buffer + globals_offsets + plain_old_launch_data_offset,
+ (uint8_t *)&metal_device->launch_params + plain_old_launch_data_offset,
+ plain_old_launch_data_size);
+
+ /* Allocate an argument buffer. */
+ MTLResourceOptions arg_buffer_options = MTLResourceStorageModeManaged;
+ if (@available(macOS 11.0, *)) {
+ if ([mtlDevice hasUnifiedMemory]) {
+ arg_buffer_options = MTLResourceStorageModeShared;
+ }
+ }
+
+ id<MTLBuffer> arg_buffer = temp_buffer_pool.get_buffer(
+ mtlDevice, mtlCommandBuffer, arg_buffer_length, arg_buffer_options, init_arg_buffer, stats);
+
+ /* Encode the pointer "enqueue" arguments */
+ bytes_written = 0;
+ for (size_t i = 0; i < args.count; i++) {
+ size_t size_in_bytes = args.sizes[i];
+ bytes_written = round_up(bytes_written, size_in_bytes);
+ if (args.types[i] == DeviceKernelArguments::POINTER) {
+ [metal_device->mtlBufferKernelParamsEncoder setArgumentBuffer:arg_buffer
+ offset:bytes_written];
+ if (MetalDevice::MetalMem *mmem = *(MetalDevice::MetalMem **)args.values[i]) {
+ [mtlComputeCommandEncoder useResource:mmem->mtlBuffer
+ usage:MTLResourceUsageRead | MTLResourceUsageWrite];
+ [metal_device->mtlBufferKernelParamsEncoder setBuffer:mmem->mtlBuffer offset:0 atIndex:0];
+ }
+ else {
+ if (@available(macos 12.0, *)) {
+ [metal_device->mtlBufferKernelParamsEncoder setBuffer:nil offset:0 atIndex:0];
+ }
+ }
+ }
+ bytes_written += size_in_bytes;
+ }
+
+ /* Encode KernelParamsMetal buffers */
+ [metal_device->mtlBufferKernelParamsEncoder setArgumentBuffer:arg_buffer offset:globals_offsets];
+
+ /* this relies on IntegratorStateGPU layout being contiguous device_ptrs */
+ const size_t pointer_block_end = offsetof(KernelParamsMetal, __integrator_state) +
+ sizeof(IntegratorStateGPU);
+ for (size_t offset = 0; offset < pointer_block_end; offset += sizeof(device_ptr)) {
+ int pointer_index = offset / sizeof(device_ptr);
+ MetalDevice::MetalMem *mmem = *(
+ MetalDevice::MetalMem **)((uint8_t *)&metal_device->launch_params + offset);
+ if (mmem && (mmem->mtlBuffer || mmem->mtlTexture)) {
+ [metal_device->mtlBufferKernelParamsEncoder setBuffer:mmem->mtlBuffer
+ offset:0
+ atIndex:pointer_index];
+ }
+ else {
+ if (@available(macos 12.0, *)) {
+ [metal_device->mtlBufferKernelParamsEncoder setBuffer:nil offset:0 atIndex:pointer_index];
+ }
+ }
+ }
+ bytes_written = globals_offsets + sizeof(KernelParamsMetal);
+
+ /* Encode ancillaries */
+ [metal_device->mtlAncillaryArgEncoder setArgumentBuffer:arg_buffer offset:metal_offsets];
+ [metal_device->mtlAncillaryArgEncoder setBuffer:metal_device->texture_bindings_2d
+ offset:0
+ atIndex:0];
+ [metal_device->mtlAncillaryArgEncoder setBuffer:metal_device->texture_bindings_3d
+ offset:0
+ atIndex:1];
+ if (@available(macos 12.0, *)) {
+ if (metal_device->use_metalrt) {
+ if (metal_device->bvhMetalRT) {
+ id<MTLAccelerationStructure> accel_struct = metal_device->bvhMetalRT->accel_struct;
+ [metal_device->mtlAncillaryArgEncoder setAccelerationStructure:accel_struct atIndex:2];
+ }
+
+ for (int table = 0; table < METALRT_TABLE_NUM; table++) {
+ if (metal_kernel_pso.intersection_func_table[table]) {
+ [metal_kernel_pso.intersection_func_table[table] setBuffer:arg_buffer
+ offset:globals_offsets
+ atIndex:1];
+ [metal_device->mtlAncillaryArgEncoder
+ setIntersectionFunctionTable:metal_kernel_pso.intersection_func_table[table]
+ atIndex:3 + table];
+ [mtlComputeCommandEncoder useResource:metal_kernel_pso.intersection_func_table[table]
+ usage:MTLResourceUsageRead];
+ }
+ else {
+ [metal_device->mtlAncillaryArgEncoder setIntersectionFunctionTable:nil
+ atIndex:3 + table];
+ }
+ }
+ }
+ bytes_written = metal_offsets + metal_device->mtlAncillaryArgEncoder.encodedLength;
+ }
+
+ if (arg_buffer.storageMode == MTLStorageModeManaged) {
+ [arg_buffer didModifyRange:NSMakeRange(0, bytes_written)];
+ }
+
+ [mtlComputeCommandEncoder setBuffer:arg_buffer offset:0 atIndex:0];
+ [mtlComputeCommandEncoder setBuffer:arg_buffer offset:globals_offsets atIndex:1];
+ [mtlComputeCommandEncoder setBuffer:arg_buffer offset:metal_offsets atIndex:2];
+
+ if (metal_device->use_metalrt) {
+ if (@available(macos 12.0, *)) {
+
+ auto bvhMetalRT = metal_device->bvhMetalRT;
+ switch (kernel) {
+ case DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST:
+ case DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW:
+ case DEVICE_KERNEL_INTEGRATOR_INTERSECT_SUBSURFACE:
+ case DEVICE_KERNEL_INTEGRATOR_INTERSECT_VOLUME_STACK:
+ case DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE:
+ break;
+ default:
+ bvhMetalRT = nil;
+ break;
+ }
+
+ if (bvhMetalRT) {
+ /* Mark all Accelerations resources as used */
+ [mtlComputeCommandEncoder useResource:bvhMetalRT->accel_struct usage:MTLResourceUsageRead];
+ [mtlComputeCommandEncoder useResources:bvhMetalRT->blas_array.data()
+ count:bvhMetalRT->blas_array.size()
+ usage:MTLResourceUsageRead];
+ }
+ }
+ }
+
+ [mtlComputeCommandEncoder setComputePipelineState:metal_kernel_pso.pipeline];
+
+ /* Compute kernel launch parameters. */
+ const int num_threads_per_block = metal_kernel.get_num_threads_per_block();
+
+ int shared_mem_bytes = 0;
+
+ switch (kernel) {
+ case DEVICE_KERNEL_INTEGRATOR_QUEUED_PATHS_ARRAY:
+ case DEVICE_KERNEL_INTEGRATOR_QUEUED_SHADOW_PATHS_ARRAY:
+ case DEVICE_KERNEL_INTEGRATOR_ACTIVE_PATHS_ARRAY:
+ case DEVICE_KERNEL_INTEGRATOR_TERMINATED_PATHS_ARRAY:
+ case DEVICE_KERNEL_INTEGRATOR_SORTED_PATHS_ARRAY:
+ case DEVICE_KERNEL_INTEGRATOR_COMPACT_PATHS_ARRAY:
+ case DEVICE_KERNEL_INTEGRATOR_TERMINATED_SHADOW_PATHS_ARRAY:
+ case DEVICE_KERNEL_INTEGRATOR_COMPACT_SHADOW_PATHS_ARRAY:
+ /* See parallel_active_index.h for why this amount of shared memory is needed.
+ * Rounded up to 16 bytes for Metal */
+ shared_mem_bytes = round_up((num_threads_per_block + 1) * sizeof(int), 16);
+ [mtlComputeCommandEncoder setThreadgroupMemoryLength:shared_mem_bytes atIndex:0];
+ break;
+
+ default:
+ break;
+ }
+
+ MTLSize size_threadgroups_per_dispatch = MTLSizeMake(
+ divide_up(work_size, num_threads_per_block), 1, 1);
+ MTLSize size_threads_per_threadgroup = MTLSizeMake(num_threads_per_block, 1, 1);
+ [mtlComputeCommandEncoder dispatchThreadgroups:size_threadgroups_per_dispatch
+ threadsPerThreadgroup:size_threads_per_threadgroup];
+
+ [mtlCommandBuffer addCompletedHandler:^(id<MTLCommandBuffer> command_buffer) {
+ NSString *kernel_name = metal_kernel_pso.function.label;
+
+ /* Enhanced command buffer errors are only available in 11.0+ */
+ if (@available(macos 11.0, *)) {
+ if (command_buffer.status == MTLCommandBufferStatusError && command_buffer.error != nil) {
+ printf("CommandBuffer Failed: %s\n", [kernel_name UTF8String]);
+ NSArray<id<MTLCommandBufferEncoderInfo>> *encoderInfos = [command_buffer.error.userInfo
+ valueForKey:MTLCommandBufferEncoderInfoErrorKey];
+ if (encoderInfos != nil) {
+ for (id<MTLCommandBufferEncoderInfo> encoderInfo : encoderInfos) {
+ NSLog(@"%@", encoderInfo);
+ }
+ }
+ id<MTLLogContainer> logs = command_buffer.logs;
+ for (id<MTLFunctionLog> log in logs) {
+ NSLog(@"%@", log);
+ }
+ }
+ else if (command_buffer.error) {
+ printf("CommandBuffer Failed: %s\n", [kernel_name UTF8String]);
+ }
+ }
+ }];
+
+ return !(metal_device->have_error());
+}
+
+bool MetalDeviceQueue::synchronize()
+{
+ if (metal_device->have_error()) {
+ return false;
+ }
+
+ if (mtlComputeEncoder) {
+ close_compute_encoder();
+ }
+ close_blit_encoder();
+
+ if (mtlCommandBuffer) {
+ uint64_t shared_event_id = this->shared_event_id++;
+
+ if (@available(macos 10.14, *)) {
+ __block dispatch_semaphore_t block_sema = wait_semaphore;
+ [shared_event notifyListener:shared_event_listener
+ atValue:shared_event_id
+ block:^(id<MTLSharedEvent> sharedEvent, uint64_t value) {
+ dispatch_semaphore_signal(block_sema);
+ }];
+
+ [mtlCommandBuffer encodeSignalEvent:shared_event value:shared_event_id];
+ [mtlCommandBuffer commit];
+ dispatch_semaphore_wait(wait_semaphore, DISPATCH_TIME_FOREVER);
+ }
+
+ [mtlCommandBuffer release];
+
+ for (const CopyBack &mmem : copy_back_mem) {
+ memcpy((uchar *)mmem.host_pointer, (uchar *)mmem.gpu_mem, mmem.size);
+ }
+ copy_back_mem.clear();
+
+ temp_buffer_pool.process_command_buffer_completion(mtlCommandBuffer);
+ metal_device->flush_delayed_free_list();
+
+ mtlCommandBuffer = nil;
+ }
+
+ return !(metal_device->have_error());
+}
+
+void MetalDeviceQueue::zero_to_device(device_memory &mem)
+{
+ assert(mem.type != MEM_GLOBAL && mem.type != MEM_TEXTURE);
+
+ if (mem.memory_size() == 0) {
+ return;
+ }
+
+ /* Allocate on demand. */
+ if (mem.device_pointer == 0) {
+ metal_device->mem_alloc(mem);
+ }
+
+ /* Zero memory on device. */
+ assert(mem.device_pointer != 0);
+
+ std::lock_guard<std::recursive_mutex> lock(metal_device->metal_mem_map_mutex);
+ MetalDevice::MetalMem &mmem = *metal_device->metal_mem_map.at(&mem);
+ if (mmem.mtlBuffer) {
+ id<MTLBlitCommandEncoder> blitEncoder = get_blit_encoder();
+ [blitEncoder fillBuffer:mmem.mtlBuffer range:NSMakeRange(mmem.offset, mmem.size) value:0];
+ }
+ else {
+ metal_device->mem_zero(mem);
+ }
+}
+
+void MetalDeviceQueue::copy_to_device(device_memory &mem)
+{
+ if (mem.memory_size() == 0) {
+ return;
+ }
+
+ /* Allocate on demand. */
+ if (mem.device_pointer == 0) {
+ metal_device->mem_alloc(mem);
+ }
+
+ assert(mem.device_pointer != 0);
+ assert(mem.host_pointer != nullptr);
+
+ std::lock_guard<std::recursive_mutex> lock(metal_device->metal_mem_map_mutex);
+ auto result = metal_device->metal_mem_map.find(&mem);
+ if (result != metal_device->metal_mem_map.end()) {
+ if (mem.host_pointer == mem.shared_pointer) {
+ return;
+ }
+
+ MetalDevice::MetalMem &mmem = *result->second;
+ id<MTLBlitCommandEncoder> blitEncoder = get_blit_encoder();
+
+ id<MTLBuffer> buffer = temp_buffer_pool.get_buffer(mtlDevice,
+ mtlCommandBuffer,
+ mmem.size,
+ MTLResourceStorageModeShared,
+ mem.host_pointer,
+ stats);
+
+ [blitEncoder copyFromBuffer:buffer
+ sourceOffset:0
+ toBuffer:mmem.mtlBuffer
+ destinationOffset:mmem.offset
+ size:mmem.size];
+ }
+ else {
+ metal_device->mem_copy_to(mem);
+ }
+}
+
+void MetalDeviceQueue::copy_from_device(device_memory &mem)
+{
+ assert(mem.type != MEM_GLOBAL && mem.type != MEM_TEXTURE);
+
+ if (mem.memory_size() == 0) {
+ return;
+ }
+
+ assert(mem.device_pointer != 0);
+ assert(mem.host_pointer != nullptr);
+
+ std::lock_guard<std::recursive_mutex> lock(metal_device->metal_mem_map_mutex);
+ MetalDevice::MetalMem &mmem = *metal_device->metal_mem_map.at(&mem);
+ if (mmem.mtlBuffer) {
+ const size_t size = mem.memory_size();
+
+ if (mem.device_pointer) {
+ if ([mmem.mtlBuffer storageMode] == MTLStorageModeManaged) {
+ id<MTLBlitCommandEncoder> blitEncoder = get_blit_encoder();
+ [blitEncoder synchronizeResource:mmem.mtlBuffer];
+ }
+ if (mem.host_pointer != mmem.hostPtr) {
+ if (mtlCommandBuffer) {
+ copy_back_mem.push_back({mem.host_pointer, mmem.hostPtr, size});
+ }
+ else {
+ memcpy((uchar *)mem.host_pointer, (uchar *)mmem.hostPtr, size);
+ }
+ }
+ }
+ else {
+ memset((char *)mem.host_pointer, 0, size);
+ }
+ }
+ else {
+ metal_device->mem_copy_from(mem);
+ }
+}
+
+bool MetalDeviceQueue::kernel_available(DeviceKernel kernel) const
+{
+ return metal_device->kernels.available(kernel);
+}
+
+void MetalDeviceQueue::prepare_resources(DeviceKernel kernel)
+{
+ std::lock_guard<std::recursive_mutex> lock(metal_device->metal_mem_map_mutex);
+
+ /* declare resource usage */
+ for (auto &it : metal_device->metal_mem_map) {
+ device_memory *mem = it.first;
+
+ MTLResourceUsage usage = MTLResourceUsageRead;
+ if (mem->type != MEM_GLOBAL && mem->type != MEM_READ_ONLY && mem->type != MEM_TEXTURE) {
+ usage |= MTLResourceUsageWrite;
+ }
+
+ if (it.second->mtlBuffer) {
+ /* METAL_WIP - use array version (i.e. useResources) */
+ [mtlComputeEncoder useResource:it.second->mtlBuffer usage:usage];
+ }
+ else if (it.second->mtlTexture) {
+ /* METAL_WIP - use array version (i.e. useResources) */
+ [mtlComputeEncoder useResource:it.second->mtlTexture usage:usage | MTLResourceUsageSample];
+ }
+ }
+
+ /* ancillaries */
+ [mtlComputeEncoder useResource:metal_device->texture_bindings_2d usage:MTLResourceUsageRead];
+ [mtlComputeEncoder useResource:metal_device->texture_bindings_3d usage:MTLResourceUsageRead];
+}
+
+id<MTLComputeCommandEncoder> MetalDeviceQueue::get_compute_encoder(DeviceKernel kernel)
+{
+ bool concurrent = (kernel < DEVICE_KERNEL_INTEGRATOR_NUM);
+
+ if (@available(macos 10.14, *)) {
+ if (mtlComputeEncoder) {
+ if (mtlComputeEncoder.dispatchType == concurrent ? MTLDispatchTypeConcurrent :
+ MTLDispatchTypeSerial) {
+ /* declare usage of MTLBuffers etc */
+ prepare_resources(kernel);
+
+ return mtlComputeEncoder;
+ }
+ close_compute_encoder();
+ }
+
+ close_blit_encoder();
+
+ if (!mtlCommandBuffer) {
+ mtlCommandBuffer = [mtlCommandQueue commandBuffer];
+ [mtlCommandBuffer retain];
+ }
+
+ mtlComputeEncoder = [mtlCommandBuffer
+ computeCommandEncoderWithDispatchType:concurrent ? MTLDispatchTypeConcurrent :
+ MTLDispatchTypeSerial];
+
+ /* declare usage of MTLBuffers etc */
+ prepare_resources(kernel);
+ }
+
+ return mtlComputeEncoder;
+}
+
+id<MTLBlitCommandEncoder> MetalDeviceQueue::get_blit_encoder()
+{
+ if (mtlBlitEncoder) {
+ return mtlBlitEncoder;
+ }
+
+ if (mtlComputeEncoder) {
+ close_compute_encoder();
+ }
+
+ if (!mtlCommandBuffer) {
+ mtlCommandBuffer = [mtlCommandQueue commandBuffer];
+ [mtlCommandBuffer retain];
+ }
+
+ mtlBlitEncoder = [mtlCommandBuffer blitCommandEncoder];
+ return mtlBlitEncoder;
+}
+
+void MetalDeviceQueue::close_compute_encoder()
+{
+ [mtlComputeEncoder endEncoding];
+ mtlComputeEncoder = nil;
+}
+
+void MetalDeviceQueue::close_blit_encoder()
+{
+ if (mtlBlitEncoder) {
+ [mtlBlitEncoder endEncoding];
+ mtlBlitEncoder = nil;
+ }
+}
+
+CCL_NAMESPACE_END
+
+#endif /* WITH_METAL */
diff --git a/intern/cycles/device/metal/util.h b/intern/cycles/device/metal/util.h
new file mode 100644
index 00000000000..dbeb3a5d064
--- /dev/null
+++ b/intern/cycles/device/metal/util.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#ifdef WITH_METAL
+
+# include <Metal/Metal.h>
+# include <string>
+
+# include "device/metal/device.h"
+# include "device/metal/kernel.h"
+# include "device/queue.h"
+
+# include "util/thread.h"
+
+CCL_NAMESPACE_BEGIN
+
+enum MetalGPUVendor {
+ METAL_GPU_UNKNOWN = 0,
+ METAL_GPU_APPLE = 1,
+ METAL_GPU_AMD = 2,
+ METAL_GPU_INTEL = 3,
+};
+
+/* Retains a named MTLDevice for device enumeration. */
+struct MetalPlatformDevice {
+ MetalPlatformDevice(id<MTLDevice> device, const string &device_name)
+ : device_id(device), device_name(device_name)
+ {
+ [device_id retain];
+ }
+ ~MetalPlatformDevice()
+ {
+ [device_id release];
+ }
+ id<MTLDevice> device_id;
+ string device_name;
+};
+
+/* Contains static Metal helper functions. */
+struct MetalInfo {
+ static bool device_version_check(id<MTLDevice> device);
+ static void get_usable_devices(vector<MetalPlatformDevice> *usable_devices);
+ static MetalGPUVendor get_vendor_from_device_name(string const &device_name);
+
+ /* Platform information. */
+ static bool get_num_devices(uint32_t *num_platforms);
+ static uint32_t get_num_devices();
+
+ static bool get_device_name(id<MTLDevice> device_id, string *device_name);
+ static string get_device_name(id<MTLDevice> device_id);
+};
+
+/* Pool of MTLBuffers whose lifetime is linked to a single MTLCommandBuffer */
+class MetalBufferPool {
+ struct MetalBufferListEntry {
+ MetalBufferListEntry(id<MTLBuffer> buffer, id<MTLCommandBuffer> command_buffer)
+ : buffer(buffer), command_buffer(command_buffer)
+ {
+ }
+
+ MetalBufferListEntry() = delete;
+
+ id<MTLBuffer> buffer;
+ id<MTLCommandBuffer> command_buffer;
+ };
+ std::vector<MetalBufferListEntry> buffer_free_list;
+ std::vector<MetalBufferListEntry> buffer_in_use_list;
+ thread_mutex buffer_mutex;
+ size_t total_temp_mem_size = 0;
+
+ public:
+ MetalBufferPool() = default;
+ ~MetalBufferPool();
+
+ id<MTLBuffer> get_buffer(id<MTLDevice> device,
+ id<MTLCommandBuffer> command_buffer,
+ NSUInteger length,
+ MTLResourceOptions options,
+ const void *pointer,
+ Stats &stats);
+ void process_command_buffer_completion(id<MTLCommandBuffer> command_buffer);
+};
+
+CCL_NAMESPACE_END
+
+#endif /* WITH_METAL */
diff --git a/intern/cycles/device/metal/util.mm b/intern/cycles/device/metal/util.mm
new file mode 100644
index 00000000000..763a37cb503
--- /dev/null
+++ b/intern/cycles/device/metal/util.mm
@@ -0,0 +1,218 @@
+/*
+ * Copyright 2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifdef WITH_METAL
+
+# include "device/metal/util.h"
+# include "device/metal/device_impl.h"
+# include "util/md5.h"
+# include "util/path.h"
+# include "util/string.h"
+# include "util/time.h"
+
+# include <pwd.h>
+# include <sys/shm.h>
+# include <time.h>
+
+CCL_NAMESPACE_BEGIN
+
+MetalGPUVendor MetalInfo::get_vendor_from_device_name(string const &device_name)
+{
+ if (device_name.find("Intel") != string::npos) {
+ return METAL_GPU_INTEL;
+ }
+ else if (device_name.find("AMD") != string::npos) {
+ return METAL_GPU_AMD;
+ }
+ else if (device_name.find("Apple") != string::npos) {
+ return METAL_GPU_APPLE;
+ }
+ return METAL_GPU_UNKNOWN;
+}
+
+bool MetalInfo::device_version_check(id<MTLDevice> device)
+{
+ /* Metal Cycles doesn't work correctly on macOS versions older than 12.0 */
+ if (@available(macos 12.0, *)) {
+ MetalGPUVendor vendor = get_vendor_from_device_name([[device name] UTF8String]);
+
+ /* Metal Cycles works on Apple Silicon GPUs at present */
+ return (vendor == METAL_GPU_APPLE);
+ }
+
+ return false;
+}
+
+void MetalInfo::get_usable_devices(vector<MetalPlatformDevice> *usable_devices)
+{
+ static bool first_time = true;
+# define FIRST_VLOG(severity) \
+ if (first_time) \
+ VLOG(severity)
+
+ usable_devices->clear();
+
+ NSArray<id<MTLDevice>> *allDevices = MTLCopyAllDevices();
+ for (id<MTLDevice> device in allDevices) {
+ string device_name;
+ if (!get_device_name(device, &device_name)) {
+ FIRST_VLOG(2) << "Failed to get device name, ignoring.";
+ continue;
+ }
+
+ static const char *forceIntelStr = getenv("CYCLES_METAL_FORCE_INTEL");
+ bool forceIntel = forceIntelStr ? (atoi(forceIntelStr) != 0) : false;
+ if (forceIntel && device_name.find("Intel") == string::npos) {
+ FIRST_VLOG(2) << "CYCLES_METAL_FORCE_INTEL causing non-Intel device " << device_name
+ << " to be ignored.";
+ continue;
+ }
+
+ if (!device_version_check(device)) {
+ FIRST_VLOG(2) << "Ignoring device " << device_name << " due to too old compiler version.";
+ continue;
+ }
+ FIRST_VLOG(2) << "Adding new device " << device_name << ".";
+ string hardware_id;
+ usable_devices->push_back(MetalPlatformDevice(device, device_name));
+ }
+ first_time = false;
+}
+
+bool MetalInfo::get_num_devices(uint32_t *num_devices)
+{
+ *num_devices = MTLCopyAllDevices().count;
+ return true;
+}
+
+uint32_t MetalInfo::get_num_devices()
+{
+ uint32_t num_devices;
+ if (!get_num_devices(&num_devices)) {
+ return 0;
+ }
+ return num_devices;
+}
+
+bool MetalInfo::get_device_name(id<MTLDevice> device, string *platform_name)
+{
+ *platform_name = [device.name UTF8String];
+ return true;
+}
+
+string MetalInfo::get_device_name(id<MTLDevice> device)
+{
+ string platform_name;
+ if (!get_device_name(device, &platform_name)) {
+ return "";
+ }
+ return platform_name;
+}
+
+id<MTLBuffer> MetalBufferPool::get_buffer(id<MTLDevice> device,
+ id<MTLCommandBuffer> command_buffer,
+ NSUInteger length,
+ MTLResourceOptions options,
+ const void *pointer,
+ Stats &stats)
+{
+ id<MTLBuffer> buffer;
+
+ MTLStorageMode storageMode = MTLStorageMode((options & MTLResourceStorageModeMask) >>
+ MTLResourceStorageModeShift);
+ MTLCPUCacheMode cpuCacheMode = MTLCPUCacheMode((options & MTLResourceCPUCacheModeMask) >>
+ MTLResourceCPUCacheModeShift);
+
+ buffer_mutex.lock();
+ for (auto entry = buffer_free_list.begin(); entry != buffer_free_list.end(); entry++) {
+ MetalBufferListEntry bufferEntry = *entry;
+
+ /* Check if buffer matches size and storage mode and is old enough to reuse */
+ if (bufferEntry.buffer.length == length && storageMode == bufferEntry.buffer.storageMode &&
+ cpuCacheMode == bufferEntry.buffer.cpuCacheMode) {
+ buffer = bufferEntry.buffer;
+ buffer_free_list.erase(entry);
+ bufferEntry.command_buffer = command_buffer;
+ buffer_in_use_list.push_back(bufferEntry);
+ buffer_mutex.unlock();
+
+ /* Copy over data */
+ if (pointer) {
+ memcpy(buffer.contents, pointer, length);
+ if (bufferEntry.buffer.storageMode == MTLStorageModeManaged) {
+ [buffer didModifyRange:NSMakeRange(0, length)];
+ }
+ }
+
+ return buffer;
+ }
+ }
+ // NSLog(@"Creating buffer of length %lu (%lu)", length, frameCount);
+ if (pointer) {
+ buffer = [device newBufferWithBytes:pointer length:length options:options];
+ }
+ else {
+ buffer = [device newBufferWithLength:length options:options];
+ }
+
+ MetalBufferListEntry buffer_entry(buffer, command_buffer);
+
+ stats.mem_alloc(buffer.allocatedSize);
+
+ total_temp_mem_size += buffer.allocatedSize;
+ buffer_in_use_list.push_back(buffer_entry);
+ buffer_mutex.unlock();
+
+ return buffer;
+}
+
+void MetalBufferPool::process_command_buffer_completion(id<MTLCommandBuffer> command_buffer)
+{
+ assert(command_buffer);
+ thread_scoped_lock lock(buffer_mutex);
+ /* Release all buffers that have not been recently reused back into the free pool */
+ for (auto entry = buffer_in_use_list.begin(); entry != buffer_in_use_list.end();) {
+ MetalBufferListEntry buffer_entry = *entry;
+ if (buffer_entry.command_buffer == command_buffer) {
+ entry = buffer_in_use_list.erase(entry);
+ buffer_entry.command_buffer = nil;
+ buffer_free_list.push_back(buffer_entry);
+ }
+ else {
+ entry++;
+ }
+ }
+}
+
+MetalBufferPool::~MetalBufferPool()
+{
+ thread_scoped_lock lock(buffer_mutex);
+ /* Release all buffers that have not been recently reused */
+ for (auto entry = buffer_free_list.begin(); entry != buffer_free_list.end();) {
+ MetalBufferListEntry buffer_entry = *entry;
+
+ id<MTLBuffer> buffer = buffer_entry.buffer;
+ // NSLog(@"Releasing buffer of length %lu (%lu) (%lu outstanding)", buffer.length, frameCount,
+ // bufferFreeList.size());
+ total_temp_mem_size -= buffer.allocatedSize;
+ [buffer release];
+ entry = buffer_free_list.erase(entry);
+ }
+}
+
+CCL_NAMESPACE_END
+
+#endif /* WITH_METAL */
diff --git a/intern/cycles/device/multi/device.cpp b/intern/cycles/device/multi/device.cpp
index e319246d4f4..5ec3ef1b785 100644
--- a/intern/cycles/device/multi/device.cpp
+++ b/intern/cycles/device/multi/device.cpp
@@ -124,11 +124,20 @@ class MultiDevice : public Device {
return BVH_LAYOUT_MULTI_OPTIX;
}
+ /* With multiple Metal devices, every device needs its own acceleration structure */
+ if (bvh_layout_mask == BVH_LAYOUT_METAL) {
+ return BVH_LAYOUT_MULTI_METAL;
+ }
+
/* When devices do not share a common BVH layout, fall back to creating one for each */
const BVHLayoutMask BVH_LAYOUT_OPTIX_EMBREE = (BVH_LAYOUT_OPTIX | BVH_LAYOUT_EMBREE);
if ((bvh_layout_mask_all & BVH_LAYOUT_OPTIX_EMBREE) == BVH_LAYOUT_OPTIX_EMBREE) {
return BVH_LAYOUT_MULTI_OPTIX_EMBREE;
}
+ const BVHLayoutMask BVH_LAYOUT_METAL_EMBREE = (BVH_LAYOUT_METAL | BVH_LAYOUT_EMBREE);
+ if ((bvh_layout_mask_all & BVH_LAYOUT_METAL_EMBREE) == BVH_LAYOUT_METAL_EMBREE) {
+ return BVH_LAYOUT_MULTI_METAL_EMBREE;
+ }
return bvh_layout_mask;
}
@@ -151,7 +160,9 @@ class MultiDevice : public Device {
}
assert(bvh->params.bvh_layout == BVH_LAYOUT_MULTI_OPTIX ||
- bvh->params.bvh_layout == BVH_LAYOUT_MULTI_OPTIX_EMBREE);
+ bvh->params.bvh_layout == BVH_LAYOUT_MULTI_METAL ||
+ bvh->params.bvh_layout == BVH_LAYOUT_MULTI_OPTIX_EMBREE ||
+ bvh->params.bvh_layout == BVH_LAYOUT_MULTI_METAL_EMBREE);
BVHMulti *const bvh_multi = static_cast<BVHMulti *>(bvh);
bvh_multi->sub_bvhs.resize(devices.size());
@@ -174,9 +185,14 @@ class MultiDevice : public Device {
BVHParams params = bvh->params;
if (bvh->params.bvh_layout == BVH_LAYOUT_MULTI_OPTIX)
params.bvh_layout = BVH_LAYOUT_OPTIX;
+ else if (bvh->params.bvh_layout == BVH_LAYOUT_MULTI_METAL)
+ params.bvh_layout = BVH_LAYOUT_METAL;
else if (bvh->params.bvh_layout == BVH_LAYOUT_MULTI_OPTIX_EMBREE)
params.bvh_layout = sub.device->info.type == DEVICE_OPTIX ? BVH_LAYOUT_OPTIX :
BVH_LAYOUT_EMBREE;
+ else if (bvh->params.bvh_layout == BVH_LAYOUT_MULTI_METAL_EMBREE)
+ params.bvh_layout = sub.device->info.type == DEVICE_METAL ? BVH_LAYOUT_METAL :
+ BVH_LAYOUT_EMBREE;
/* Skip building a bottom level acceleration structure for non-instanced geometry on Embree
* (since they are put into the top level directly, see bvh_embree.cpp) */
diff --git a/intern/cycles/device/optix/device_impl.cpp b/intern/cycles/device/optix/device_impl.cpp
index bb690551c04..38cc3330ebd 100644
--- a/intern/cycles/device/optix/device_impl.cpp
+++ b/intern/cycles/device/optix/device_impl.cpp
@@ -28,6 +28,7 @@
# include "scene/mesh.h"
# include "scene/object.h"
# include "scene/pass.h"
+# include "scene/pointcloud.h"
# include "scene/scene.h"
# include "util/debug.h"
@@ -41,17 +42,19 @@
# define __KERNEL_OPTIX__
# include "kernel/device/optix/globals.h"
+# include <optix_denoiser_tiling.h>
+
CCL_NAMESPACE_BEGIN
OptiXDevice::Denoiser::Denoiser(OptiXDevice *device)
- : device(device), queue(device), state(device, "__denoiser_state")
+ : device(device), queue(device), state(device, "__denoiser_state", true)
{
}
OptiXDevice::OptiXDevice(const DeviceInfo &info, Stats &stats, Profiler &profiler)
: CUDADevice(info, stats, profiler),
sbt_data(this, "__sbt", MEM_READ_ONLY),
- launch_params(this, "__params"),
+ launch_params(this, "__params", false),
denoiser_(this)
{
/* Make the CUDA context current. */
@@ -208,11 +211,15 @@ bool OptiXDevice::load_kernels(const uint kernel_features)
}
else {
module_options.optLevel = OPTIX_COMPILE_OPTIMIZATION_LEVEL_3;
- module_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_LINEINFO;
+ module_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_NONE;
}
module_options.boundValues = nullptr;
module_options.numBoundValues = 0;
+# if OPTIX_ABI_VERSION >= 55
+ module_options.payloadTypes = nullptr;
+ module_options.numPayloadTypes = 0;
+# endif
OptixPipelineCompileOptions pipeline_options = {};
/* Default to no motion blur and two-level graph, since it is the fastest option. */
@@ -227,11 +234,18 @@ bool OptiXDevice::load_kernels(const uint kernel_features)
pipeline_options.usesPrimitiveTypeFlags = OPTIX_PRIMITIVE_TYPE_FLAGS_TRIANGLE;
if (kernel_features & KERNEL_FEATURE_HAIR) {
if (kernel_features & KERNEL_FEATURE_HAIR_THICK) {
+# if OPTIX_ABI_VERSION >= 55
+ pipeline_options.usesPrimitiveTypeFlags |= OPTIX_PRIMITIVE_TYPE_FLAGS_ROUND_CATMULLROM;
+# else
pipeline_options.usesPrimitiveTypeFlags |= OPTIX_PRIMITIVE_TYPE_FLAGS_ROUND_CUBIC_BSPLINE;
+# endif
}
else
pipeline_options.usesPrimitiveTypeFlags |= OPTIX_PRIMITIVE_TYPE_FLAGS_CUSTOM;
}
+ if (kernel_features & KERNEL_FEATURE_POINTCLOUD) {
+ pipeline_options.usesPrimitiveTypeFlags |= OPTIX_PRIMITIVE_TYPE_FLAGS_CUSTOM;
+ }
/* Keep track of whether motion blur is enabled, so to enable/disable motion in BVH builds
* This is necessary since objects may be reported to have motion if the Vector pass is
@@ -324,7 +338,13 @@ bool OptiXDevice::load_kernels(const uint kernel_features)
if (kernel_features & KERNEL_FEATURE_HAIR_THICK) {
/* Built-in thick curve intersection. */
OptixBuiltinISOptions builtin_options = {};
+# if OPTIX_ABI_VERSION >= 55
+ builtin_options.builtinISModuleType = OPTIX_PRIMITIVE_TYPE_ROUND_CATMULLROM;
+ builtin_options.buildFlags = OPTIX_BUILD_FLAG_PREFER_FAST_TRACE;
+ builtin_options.curveEndcapFlags = OPTIX_CURVE_ENDCAP_DEFAULT; /* Disable end-caps. */
+# else
builtin_options.builtinISModuleType = OPTIX_PRIMITIVE_TYPE_ROUND_CUBIC_BSPLINE;
+# endif
builtin_options.usesMotionBlur = false;
optix_assert(optixBuiltinISModuleGet(
@@ -356,6 +376,18 @@ bool OptiXDevice::load_kernels(const uint kernel_features)
}
}
+ /* Pointclouds */
+ if (kernel_features & KERNEL_FEATURE_POINTCLOUD) {
+ group_descs[PG_HITD_POINTCLOUD] = group_descs[PG_HITD];
+ group_descs[PG_HITD_POINTCLOUD].kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP;
+ group_descs[PG_HITD_POINTCLOUD].hitgroup.moduleIS = optix_module;
+ group_descs[PG_HITD_POINTCLOUD].hitgroup.entryFunctionNameIS = "__intersection__point";
+ group_descs[PG_HITS_POINTCLOUD] = group_descs[PG_HITS];
+ group_descs[PG_HITS_POINTCLOUD].kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP;
+ group_descs[PG_HITS_POINTCLOUD].hitgroup.moduleIS = optix_module;
+ group_descs[PG_HITS_POINTCLOUD].hitgroup.entryFunctionNameIS = "__intersection__point";
+ }
+
if (kernel_features & (KERNEL_FEATURE_SUBSURFACE | KERNEL_FEATURE_NODE_RAYTRACE)) {
/* Add hit group for local intersections. */
group_descs[PG_HITL].kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP;
@@ -403,6 +435,10 @@ bool OptiXDevice::load_kernels(const uint kernel_features)
stack_size[PG_HITD_MOTION].cssIS + stack_size[PG_HITD_MOTION].cssAH);
trace_css = std::max(trace_css,
stack_size[PG_HITS_MOTION].cssIS + stack_size[PG_HITS_MOTION].cssAH);
+ trace_css = std::max(
+ trace_css, stack_size[PG_HITD_POINTCLOUD].cssIS + stack_size[PG_HITD_POINTCLOUD].cssAH);
+ trace_css = std::max(
+ trace_css, stack_size[PG_HITS_POINTCLOUD].cssIS + stack_size[PG_HITS_POINTCLOUD].cssAH);
OptixPipelineLinkOptions link_options = {};
link_options.maxTraceDepth = 1;
@@ -411,7 +447,7 @@ bool OptiXDevice::load_kernels(const uint kernel_features)
link_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_FULL;
}
else {
- link_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_LINEINFO;
+ link_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_NONE;
}
if (kernel_features & KERNEL_FEATURE_NODE_RAYTRACE) {
@@ -428,6 +464,10 @@ bool OptiXDevice::load_kernels(const uint kernel_features)
pipeline_groups.push_back(groups[PG_HITD_MOTION]);
pipeline_groups.push_back(groups[PG_HITS_MOTION]);
}
+ if (kernel_features & KERNEL_FEATURE_POINTCLOUD) {
+ pipeline_groups.push_back(groups[PG_HITD_POINTCLOUD]);
+ pipeline_groups.push_back(groups[PG_HITS_POINTCLOUD]);
+ }
pipeline_groups.push_back(groups[PG_CALL_SVM_AO]);
pipeline_groups.push_back(groups[PG_CALL_SVM_BEVEL]);
@@ -467,6 +507,10 @@ bool OptiXDevice::load_kernels(const uint kernel_features)
pipeline_groups.push_back(groups[PG_HITD_MOTION]);
pipeline_groups.push_back(groups[PG_HITS_MOTION]);
}
+ if (kernel_features & KERNEL_FEATURE_POINTCLOUD) {
+ pipeline_groups.push_back(groups[PG_HITD_POINTCLOUD]);
+ pipeline_groups.push_back(groups[PG_HITS_POINTCLOUD]);
+ }
optix_assert(optixPipelineCreate(context,
&pipeline_options,
@@ -507,7 +551,7 @@ class OptiXDevice::DenoiseContext {
: denoise_params(task.params),
render_buffers(task.render_buffers),
buffer_params(task.buffer_params),
- guiding_buffer(device, "denoiser guiding passes buffer"),
+ guiding_buffer(device, "denoiser guiding passes buffer", true),
num_samples(task.num_samples)
{
num_input_passes = 1;
@@ -522,9 +566,9 @@ class OptiXDevice::DenoiseContext {
}
}
- const int num_guiding_passes = num_input_passes - 1;
+ use_guiding_passes = (num_input_passes - 1) > 0;
- if (num_guiding_passes) {
+ if (use_guiding_passes) {
if (task.allow_inplace_modification) {
guiding_params.device_pointer = render_buffers->buffer.device_pointer;
@@ -577,6 +621,7 @@ class OptiXDevice::DenoiseContext {
/* Number of input passes. Including the color and extra auxiliary passes. */
int num_input_passes = 0;
+ bool use_guiding_passes = false;
bool use_pass_albedo = false;
bool use_pass_normal = false;
@@ -653,22 +698,22 @@ bool OptiXDevice::denoise_filter_guiding_preprocess(DenoiseContext &context)
const int work_size = buffer_params.width * buffer_params.height;
- void *args[] = {const_cast<device_ptr *>(&context.guiding_params.device_pointer),
- const_cast<int *>(&context.guiding_params.pass_stride),
- const_cast<int *>(&context.guiding_params.pass_albedo),
- const_cast<int *>(&context.guiding_params.pass_normal),
- &context.render_buffers->buffer.device_pointer,
- const_cast<int *>(&buffer_params.offset),
- const_cast<int *>(&buffer_params.stride),
- const_cast<int *>(&buffer_params.pass_stride),
- const_cast<int *>(&context.pass_sample_count),
- const_cast<int *>(&context.pass_denoising_albedo),
- const_cast<int *>(&context.pass_denoising_normal),
- const_cast<int *>(&buffer_params.full_x),
- const_cast<int *>(&buffer_params.full_y),
- const_cast<int *>(&buffer_params.width),
- const_cast<int *>(&buffer_params.height),
- const_cast<int *>(&context.num_samples)};
+ DeviceKernelArguments args(&context.guiding_params.device_pointer,
+ &context.guiding_params.pass_stride,
+ &context.guiding_params.pass_albedo,
+ &context.guiding_params.pass_normal,
+ &context.render_buffers->buffer.device_pointer,
+ &buffer_params.offset,
+ &buffer_params.stride,
+ &buffer_params.pass_stride,
+ &context.pass_sample_count,
+ &context.pass_denoising_albedo,
+ &context.pass_denoising_normal,
+ &buffer_params.full_x,
+ &buffer_params.full_y,
+ &buffer_params.width,
+ &buffer_params.height,
+ &context.num_samples);
return denoiser_.queue.enqueue(DEVICE_KERNEL_FILTER_GUIDING_PREPROCESS, work_size, args);
}
@@ -679,11 +724,11 @@ bool OptiXDevice::denoise_filter_guiding_set_fake_albedo(DenoiseContext &context
const int work_size = buffer_params.width * buffer_params.height;
- void *args[] = {const_cast<device_ptr *>(&context.guiding_params.device_pointer),
- const_cast<int *>(&context.guiding_params.pass_stride),
- const_cast<int *>(&context.guiding_params.pass_albedo),
- const_cast<int *>(&buffer_params.width),
- const_cast<int *>(&buffer_params.height)};
+ DeviceKernelArguments args(&context.guiding_params.device_pointer,
+ &context.guiding_params.pass_stride,
+ &context.guiding_params.pass_albedo,
+ &buffer_params.width,
+ &buffer_params.height);
return denoiser_.queue.enqueue(DEVICE_KERNEL_FILTER_GUIDING_SET_FAKE_ALBEDO, work_size, args);
}
@@ -708,7 +753,7 @@ void OptiXDevice::denoise_pass(DenoiseContext &context, PassType pass_type)
return;
}
}
- else if (!context.albedo_replaced_with_fake) {
+ else if (context.use_guiding_passes && !context.albedo_replaced_with_fake) {
context.albedo_replaced_with_fake = true;
if (!denoise_filter_guiding_set_fake_albedo(context)) {
LOG(ERROR) << "Error replacing real albedo with the fake one.";
@@ -779,15 +824,15 @@ bool OptiXDevice::denoise_filter_color_preprocess(DenoiseContext &context, const
const int work_size = buffer_params.width * buffer_params.height;
- void *args[] = {&context.render_buffers->buffer.device_pointer,
- const_cast<int *>(&buffer_params.full_x),
- const_cast<int *>(&buffer_params.full_y),
- const_cast<int *>(&buffer_params.width),
- const_cast<int *>(&buffer_params.height),
- const_cast<int *>(&buffer_params.offset),
- const_cast<int *>(&buffer_params.stride),
- const_cast<int *>(&buffer_params.pass_stride),
- const_cast<int *>(&pass.denoised_offset)};
+ DeviceKernelArguments args(&context.render_buffers->buffer.device_pointer,
+ &buffer_params.full_x,
+ &buffer_params.full_y,
+ &buffer_params.width,
+ &buffer_params.height,
+ &buffer_params.offset,
+ &buffer_params.stride,
+ &buffer_params.pass_stride,
+ &pass.denoised_offset);
return denoiser_.queue.enqueue(DEVICE_KERNEL_FILTER_COLOR_PREPROCESS, work_size, args);
}
@@ -799,20 +844,20 @@ bool OptiXDevice::denoise_filter_color_postprocess(DenoiseContext &context,
const int work_size = buffer_params.width * buffer_params.height;
- void *args[] = {&context.render_buffers->buffer.device_pointer,
- const_cast<int *>(&buffer_params.full_x),
- const_cast<int *>(&buffer_params.full_y),
- const_cast<int *>(&buffer_params.width),
- const_cast<int *>(&buffer_params.height),
- const_cast<int *>(&buffer_params.offset),
- const_cast<int *>(&buffer_params.stride),
- const_cast<int *>(&buffer_params.pass_stride),
- const_cast<int *>(&context.num_samples),
- const_cast<int *>(&pass.noisy_offset),
- const_cast<int *>(&pass.denoised_offset),
- const_cast<int *>(&context.pass_sample_count),
- const_cast<int *>(&pass.num_components),
- const_cast<bool *>(&pass.use_compositing)};
+ DeviceKernelArguments args(&context.render_buffers->buffer.device_pointer,
+ &buffer_params.full_x,
+ &buffer_params.full_y,
+ &buffer_params.width,
+ &buffer_params.height,
+ &buffer_params.offset,
+ &buffer_params.stride,
+ &buffer_params.pass_stride,
+ &context.num_samples,
+ &pass.noisy_offset,
+ &pass.denoised_offset,
+ &context.pass_sample_count,
+ &pass.num_components,
+ &pass.use_compositing);
return denoiser_.queue.enqueue(DEVICE_KERNEL_FILTER_COLOR_POSTPROCESS, work_size, args);
}
@@ -870,35 +915,33 @@ bool OptiXDevice::denoise_create_if_needed(DenoiseContext &context)
bool OptiXDevice::denoise_configure_if_needed(DenoiseContext &context)
{
- if (denoiser_.is_configured && (denoiser_.configured_size.x == context.buffer_params.width &&
- denoiser_.configured_size.y == context.buffer_params.height)) {
+ /* Limit maximum tile size denoiser can be invoked with. */
+ const int2 tile_size = make_int2(min(context.buffer_params.width, 4096),
+ min(context.buffer_params.height, 4096));
+
+ if (denoiser_.is_configured &&
+ (denoiser_.configured_size.x == tile_size.x && denoiser_.configured_size.y == tile_size.y)) {
return true;
}
- const BufferParams &buffer_params = context.buffer_params;
-
- OptixDenoiserSizes sizes = {};
optix_assert(optixDenoiserComputeMemoryResources(
- denoiser_.optix_denoiser, buffer_params.width, buffer_params.height, &sizes));
-
- /* Denoiser is invoked on whole images only, so no overlap needed (would be used for tiling). */
- denoiser_.scratch_size = sizes.withoutOverlapScratchSizeInBytes;
- denoiser_.scratch_offset = sizes.stateSizeInBytes;
+ denoiser_.optix_denoiser, tile_size.x, tile_size.y, &denoiser_.sizes));
/* Allocate denoiser state if tile size has changed since last setup. */
- denoiser_.state.alloc_to_device(denoiser_.scratch_offset + denoiser_.scratch_size);
+ denoiser_.state.alloc_to_device(denoiser_.sizes.stateSizeInBytes +
+ denoiser_.sizes.withOverlapScratchSizeInBytes);
/* Initialize denoiser state for the current tile size. */
const OptixResult result = optixDenoiserSetup(
denoiser_.optix_denoiser,
0, /* Work around bug in r495 drivers that causes artifacts when denoiser setup is called
on a stream that is not the default stream */
- buffer_params.width,
- buffer_params.height,
+ tile_size.x + denoiser_.sizes.overlapWindowSizeInPixels * 2,
+ tile_size.y + denoiser_.sizes.overlapWindowSizeInPixels * 2,
denoiser_.state.device_pointer,
- denoiser_.scratch_offset,
- denoiser_.state.device_pointer + denoiser_.scratch_offset,
- denoiser_.scratch_size);
+ denoiser_.sizes.stateSizeInBytes,
+ denoiser_.state.device_pointer + denoiser_.sizes.stateSizeInBytes,
+ denoiser_.sizes.withOverlapScratchSizeInBytes);
if (result != OPTIX_SUCCESS) {
set_error("Failed to set up OptiX denoiser");
return false;
@@ -907,8 +950,7 @@ bool OptiXDevice::denoise_configure_if_needed(DenoiseContext &context)
cuda_assert(cuCtxSynchronize());
denoiser_.is_configured = true;
- denoiser_.configured_size.x = buffer_params.width;
- denoiser_.configured_size.y = buffer_params.height;
+ denoiser_.configured_size = tile_size;
return true;
}
@@ -979,18 +1021,20 @@ bool OptiXDevice::denoise_run(DenoiseContext &context, const DenoisePass &pass)
guide_layers.albedo = albedo_layer;
guide_layers.normal = normal_layer;
- optix_assert(optixDenoiserInvoke(denoiser_.optix_denoiser,
- denoiser_.queue.stream(),
- &params,
- denoiser_.state.device_pointer,
- denoiser_.scratch_offset,
- &guide_layers,
- &image_layers,
- 1,
- 0,
- 0,
- denoiser_.state.device_pointer + denoiser_.scratch_offset,
- denoiser_.scratch_size));
+ optix_assert(optixUtilDenoiserInvokeTiled(denoiser_.optix_denoiser,
+ denoiser_.queue.stream(),
+ &params,
+ denoiser_.state.device_pointer,
+ denoiser_.sizes.stateSizeInBytes,
+ &guide_layers,
+ &image_layers,
+ 1,
+ denoiser_.state.device_pointer +
+ denoiser_.sizes.stateSizeInBytes,
+ denoiser_.sizes.withOverlapScratchSizeInBytes,
+ denoiser_.sizes.overlapWindowSizeInPixels,
+ denoiser_.configured_size.x,
+ denoiser_.configured_size.y));
return true;
}
@@ -1000,6 +1044,13 @@ bool OptiXDevice::build_optix_bvh(BVHOptiX *bvh,
const OptixBuildInput &build_input,
uint16_t num_motion_steps)
{
+ /* Allocate and build acceleration structures only one at a time, to prevent parallel builds
+ * from running out of memory (since both original and compacted acceleration structure memory
+ * may be allocated at the same time for the duration of this function). The builds would
+ * otherwise happen on the same CUDA stream anyway. */
+ static thread_mutex mutex;
+ thread_scoped_lock lock(mutex);
+
const CUDAContextScope scope(this);
const bool use_fast_trace_bvh = (bvh->params.bvh_type == BVH_TYPE_STATIC);
@@ -1025,14 +1076,15 @@ bool OptiXDevice::build_optix_bvh(BVHOptiX *bvh,
optix_assert(optixAccelComputeMemoryUsage(context, &options, &build_input, 1, &sizes));
/* Allocate required output buffers. */
- device_only_memory<char> temp_mem(this, "optix temp as build mem");
+ device_only_memory<char> temp_mem(this, "optix temp as build mem", true);
temp_mem.alloc_to_device(align_up(sizes.tempSizeInBytes, 8) + 8);
if (!temp_mem.device_pointer) {
/* Make sure temporary memory allocation succeeded. */
return false;
}
- device_only_memory<char> &out_data = bvh->as_data;
+ /* Acceleration structure memory has to be allocated on the device (not allowed on the host). */
+ device_only_memory<char> &out_data = *bvh->as_data;
if (operation == OPTIX_BUILD_OPERATION_BUILD) {
assert(out_data.device == this);
out_data.alloc_to_device(sizes.outputSizeInBytes);
@@ -1080,12 +1132,13 @@ bool OptiXDevice::build_optix_bvh(BVHOptiX *bvh,
/* There is no point compacting if the size does not change. */
if (compacted_size < sizes.outputSizeInBytes) {
- device_only_memory<char> compacted_data(this, "optix compacted as");
+ device_only_memory<char> compacted_data(this, "optix compacted as", false);
compacted_data.alloc_to_device(compacted_size);
- if (!compacted_data.device_pointer)
+ if (!compacted_data.device_pointer) {
/* Do not compact if memory allocation for compacted acceleration structure fails.
* Can just use the uncompacted one then, so succeed here regardless. */
return !have_error();
+ }
optix_assert(optixAccelCompact(
context, NULL, out_handle, compacted_data.device_pointer, compacted_size, &out_handle));
@@ -1096,6 +1149,8 @@ bool OptiXDevice::build_optix_bvh(BVHOptiX *bvh,
std::swap(out_data.device_size, compacted_data.device_size);
std::swap(out_data.device_pointer, compacted_data.device_pointer);
+ /* Original acceleration structure memory is freed when 'compacted_data' goes out of scope.
+ */
}
}
@@ -1123,7 +1178,7 @@ void OptiXDevice::build_bvh(BVH *bvh, Progress &progress, bool refit)
operation = OPTIX_BUILD_OPERATION_UPDATE;
}
else {
- bvh_optix->as_data.free();
+ bvh_optix->as_data->free();
bvh_optix->traversable_handle = 0;
}
@@ -1178,20 +1233,27 @@ void OptiXDevice::build_bvh(BVH *bvh, Progress &progress, bool refit)
int ka = max(k0 - 1, curve.first_key);
int kb = min(k1 + 1, curve.first_key + curve.num_keys - 1);
+ index_data[i] = i * 4;
+ float4 *const v = vertex_data.data() + step * num_vertices + index_data[i];
+
+# if OPTIX_ABI_VERSION >= 55
+ v[0] = make_float4(keys[ka].x, keys[ka].y, keys[ka].z, curve_radius[ka]);
+ v[1] = make_float4(keys[k0].x, keys[k0].y, keys[k0].z, curve_radius[k0]);
+ v[2] = make_float4(keys[k1].x, keys[k1].y, keys[k1].z, curve_radius[k1]);
+ v[3] = make_float4(keys[kb].x, keys[kb].y, keys[kb].z, curve_radius[kb]);
+# else
const float4 px = make_float4(keys[ka].x, keys[k0].x, keys[k1].x, keys[kb].x);
const float4 py = make_float4(keys[ka].y, keys[k0].y, keys[k1].y, keys[kb].y);
const float4 pz = make_float4(keys[ka].z, keys[k0].z, keys[k1].z, keys[kb].z);
const float4 pw = make_float4(
curve_radius[ka], curve_radius[k0], curve_radius[k1], curve_radius[kb]);
- /* Convert Catmull-Rom data to Bezier spline. */
+ /* Convert Catmull-Rom data to B-spline. */
static const float4 cr2bsp0 = make_float4(+7, -4, +5, -2) / 6.f;
static const float4 cr2bsp1 = make_float4(-2, 11, -4, +1) / 6.f;
static const float4 cr2bsp2 = make_float4(+1, -4, 11, -2) / 6.f;
static const float4 cr2bsp3 = make_float4(-2, +5, -4, +7) / 6.f;
- index_data[i] = i * 4;
- float4 *const v = vertex_data.data() + step * num_vertices + index_data[i];
v[0] = make_float4(
dot(cr2bsp0, px), dot(cr2bsp0, py), dot(cr2bsp0, pz), dot(cr2bsp0, pw));
v[1] = make_float4(
@@ -1200,6 +1262,7 @@ void OptiXDevice::build_bvh(BVH *bvh, Progress &progress, bool refit)
dot(cr2bsp2, px), dot(cr2bsp2, py), dot(cr2bsp2, pz), dot(cr2bsp2, pw));
v[3] = make_float4(
dot(cr2bsp3, px), dot(cr2bsp3, py), dot(cr2bsp3, pz), dot(cr2bsp3, pw));
+# endif
}
else {
BoundBox bounds = BoundBox::empty;
@@ -1241,7 +1304,11 @@ void OptiXDevice::build_bvh(BVH *bvh, Progress &progress, bool refit)
OptixBuildInput build_input = {};
if (hair->curve_shape == CURVE_THICK) {
build_input.type = OPTIX_BUILD_INPUT_TYPE_CURVES;
+# if OPTIX_ABI_VERSION >= 55
+ build_input.curveArray.curveType = OPTIX_PRIMITIVE_TYPE_ROUND_CATMULLROM;
+# else
build_input.curveArray.curveType = OPTIX_PRIMITIVE_TYPE_ROUND_CUBIC_BSPLINE;
+# endif
build_input.curveArray.numPrimitives = num_segments;
build_input.curveArray.vertexBuffers = (CUdeviceptr *)vertex_ptrs.data();
build_input.curveArray.numVertices = num_vertices;
@@ -1255,7 +1322,7 @@ void OptiXDevice::build_bvh(BVH *bvh, Progress &progress, bool refit)
}
else {
/* Disable visibility test any-hit program, since it is already checked during
- * intersection. Those trace calls that require anyhit can force it with a ray flag. */
+ * intersection. Those trace calls that require any-hit can force it with a ray flag. */
build_flags |= OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT;
build_input.type = OPTIX_BUILD_INPUT_TYPE_CUSTOM_PRIMITIVES;
@@ -1339,14 +1406,94 @@ void OptiXDevice::build_bvh(BVH *bvh, Progress &progress, bool refit)
progress.set_error("Failed to build OptiX acceleration structure");
}
}
+ else if (geom->geometry_type == Geometry::POINTCLOUD) {
+ /* Build BLAS for points primitives. */
+ PointCloud *const pointcloud = static_cast<PointCloud *const>(geom);
+ const size_t num_points = pointcloud->num_points();
+ if (num_points == 0) {
+ return;
+ }
+
+ size_t num_motion_steps = 1;
+ Attribute *motion_points = pointcloud->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ if (motion_blur && pointcloud->get_use_motion_blur() && motion_points) {
+ num_motion_steps = pointcloud->get_motion_steps();
+ }
+
+ device_vector<OptixAabb> aabb_data(this, "optix temp aabb data", MEM_READ_ONLY);
+ aabb_data.alloc(num_points * num_motion_steps);
+
+ /* Get AABBs for each motion step. */
+ for (size_t step = 0; step < num_motion_steps; ++step) {
+ /* The center step for motion vertices is not stored in the attribute. */
+ const float3 *points = pointcloud->get_points().data();
+ const float *radius = pointcloud->get_radius().data();
+ size_t center_step = (num_motion_steps - 1) / 2;
+ if (step != center_step) {
+ size_t attr_offset = (step > center_step) ? step - 1 : step;
+ /* Technically this is a float4 array, but sizeof(float3) == sizeof(float4). */
+ points = motion_points->data_float3() + attr_offset * num_points;
+ }
+
+ for (size_t i = 0; i < num_points; ++i) {
+ const PointCloud::Point point = pointcloud->get_point(i);
+ BoundBox bounds = BoundBox::empty;
+ point.bounds_grow(points, radius, bounds);
+
+ const size_t index = step * num_points + i;
+ aabb_data[index].minX = bounds.min.x;
+ aabb_data[index].minY = bounds.min.y;
+ aabb_data[index].minZ = bounds.min.z;
+ aabb_data[index].maxX = bounds.max.x;
+ aabb_data[index].maxY = bounds.max.y;
+ aabb_data[index].maxZ = bounds.max.z;
+ }
+ }
+
+ /* Upload AABB data to GPU. */
+ aabb_data.copy_to_device();
+
+ vector<device_ptr> aabb_ptrs;
+ aabb_ptrs.reserve(num_motion_steps);
+ for (size_t step = 0; step < num_motion_steps; ++step) {
+ aabb_ptrs.push_back(aabb_data.device_pointer + step * num_points * sizeof(OptixAabb));
+ }
+
+ /* Disable visibility test any-hit program, since it is already checked during
+ * intersection. Those trace calls that require anyhit can force it with a ray flag.
+ * For those, force a single any-hit call, so shadow record-all behavior works correctly. */
+ unsigned int build_flags = OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT |
+ OPTIX_GEOMETRY_FLAG_REQUIRE_SINGLE_ANYHIT_CALL;
+ OptixBuildInput build_input = {};
+ build_input.type = OPTIX_BUILD_INPUT_TYPE_CUSTOM_PRIMITIVES;
+# if OPTIX_ABI_VERSION < 23
+ build_input.aabbArray.aabbBuffers = (CUdeviceptr *)aabb_ptrs.data();
+ build_input.aabbArray.numPrimitives = num_points;
+ build_input.aabbArray.strideInBytes = sizeof(OptixAabb);
+ build_input.aabbArray.flags = &build_flags;
+ build_input.aabbArray.numSbtRecords = 1;
+ build_input.aabbArray.primitiveIndexOffset = pointcloud->prim_offset;
+# else
+ build_input.customPrimitiveArray.aabbBuffers = (CUdeviceptr *)aabb_ptrs.data();
+ build_input.customPrimitiveArray.numPrimitives = num_points;
+ build_input.customPrimitiveArray.strideInBytes = sizeof(OptixAabb);
+ build_input.customPrimitiveArray.flags = &build_flags;
+ build_input.customPrimitiveArray.numSbtRecords = 1;
+ build_input.customPrimitiveArray.primitiveIndexOffset = pointcloud->prim_offset;
+# endif
+
+ if (!build_optix_bvh(bvh_optix, operation, build_input, num_motion_steps)) {
+ progress.set_error("Failed to build OptiX acceleration structure");
+ }
+ }
}
else {
unsigned int num_instances = 0;
unsigned int max_num_instances = 0xFFFFFFFF;
- bvh_optix->as_data.free();
+ bvh_optix->as_data->free();
bvh_optix->traversable_handle = 0;
- bvh_optix->motion_transform_data.free();
+ bvh_optix->motion_transform_data->free();
optixDeviceContextGetProperty(context,
OPTIX_DEVICE_PROPERTY_LIMIT_MAX_INSTANCE_ID,
@@ -1379,8 +1526,8 @@ void OptiXDevice::build_bvh(BVH *bvh, Progress &progress, bool refit)
}
}
- assert(bvh_optix->motion_transform_data.device == this);
- bvh_optix->motion_transform_data.alloc_to_device(total_motion_transform_size);
+ assert(bvh_optix->motion_transform_data->device == this);
+ bvh_optix->motion_transform_data->alloc_to_device(total_motion_transform_size);
}
for (Object *ob : bvh->objects) {
@@ -1422,9 +1569,22 @@ void OptiXDevice::build_bvh(BVH *bvh, Progress &progress, bool refit)
instance.sbtOffset = PG_HITD_MOTION - PG_HITD;
}
}
- else {
+ else if (ob->get_geometry()->geometry_type == Geometry::POINTCLOUD) {
+ /* Use the hit group that has an intersection program for point clouds. */
+ instance.sbtOffset = PG_HITD_POINTCLOUD - PG_HITD;
+
+ /* Also skip point clouds in local trace calls. */
+ instance.visibilityMask |= 4;
+ }
+
+# if OPTIX_ABI_VERSION < 55
+ /* Cannot disable any-hit program for thick curves, since it needs to filter out end-caps. */
+ else
+# endif
+ {
/* Can disable __anyhit__kernel_optix_visibility_test by default (except for thick curves,
* since it needs to filter out end-caps there).
+
* It is enabled where necessary (visibility mask exceeds 8 bits or the other any-hit
* programs like __anyhit__kernel_optix_shadow_all_hit) via OPTIX_RAY_FLAG_ENFORCE_ANYHIT.
*/
@@ -1441,7 +1601,7 @@ void OptiXDevice::build_bvh(BVH *bvh, Progress &progress, bool refit)
motion_transform_offset = align_up(motion_transform_offset,
OPTIX_TRANSFORM_BYTE_ALIGNMENT);
- CUdeviceptr motion_transform_gpu = bvh_optix->motion_transform_data.device_pointer +
+ CUdeviceptr motion_transform_gpu = bvh_optix->motion_transform_data->device_pointer +
motion_transform_offset;
motion_transform_offset += motion_transform_size;
@@ -1494,9 +1654,6 @@ void OptiXDevice::build_bvh(BVH *bvh, Progress &progress, bool refit)
cuMemcpyHtoD(motion_transform_gpu, &motion_transform, motion_transform_size);
delete[] reinterpret_cast<uint8_t *>(&motion_transform);
- /* Disable instance transform if object uses motion transform already. */
- instance.flags |= OPTIX_INSTANCE_FLAG_DISABLE_TRANSFORM;
-
/* Get traversable handle to motion transform. */
optixConvertPointerToTraversableHandle(context,
motion_transform_gpu,
@@ -1510,10 +1667,6 @@ void OptiXDevice::build_bvh(BVH *bvh, Progress &progress, bool refit)
/* Set transform matrix. */
memcpy(instance.transform, &ob->get_tfm(), sizeof(instance.transform));
}
- else {
- /* Disable instance transform if geometry already has it applied to vertex data. */
- instance.flags |= OPTIX_INSTANCE_FLAG_DISABLE_TRANSFORM;
- }
}
}
diff --git a/intern/cycles/device/optix/device_impl.h b/intern/cycles/device/optix/device_impl.h
index 5cfc249b430..25073c60e69 100644
--- a/intern/cycles/device/optix/device_impl.h
+++ b/intern/cycles/device/optix/device_impl.h
@@ -23,6 +23,7 @@
# include "device/optix/queue.h"
# include "device/optix/util.h"
# include "kernel/types.h"
+# include "util/unique_ptr.h"
CCL_NAMESPACE_BEGIN
@@ -43,6 +44,8 @@ enum {
PG_HITV, /* __VOLUME__ hit group. */
PG_HITD_MOTION,
PG_HITS_MOTION,
+ PG_HITD_POINTCLOUD,
+ PG_HITS_POINTCLOUD,
PG_CALL_SVM_AO,
PG_CALL_SVM_BEVEL,
NUM_PROGRAM_GROUPS
@@ -51,9 +54,9 @@ enum {
static const int MISS_PROGRAM_GROUP_OFFSET = PG_MISS;
static const int NUM_MIS_PROGRAM_GROUPS = 1;
static const int HIT_PROGAM_GROUP_OFFSET = PG_HITD;
-static const int NUM_HIT_PROGRAM_GROUPS = 6;
+static const int NUM_HIT_PROGRAM_GROUPS = 8;
static const int CALLABLE_PROGRAM_GROUPS_BASE = PG_CALL_SVM_AO;
-static const int NUM_CALLABLE_PROGRAM_GROUPS = 3;
+static const int NUM_CALLABLE_PROGRAM_GROUPS = 2;
/* List of OptiX pipelines. */
enum { PIP_SHADE_RAYTRACE, PIP_INTERSECT, NUM_PIPELINES };
@@ -76,7 +79,7 @@ class OptiXDevice : public CUDADevice {
device_only_memory<KernelParamsOptiX> launch_params;
OptixTraversableHandle tlas_handle = 0;
- vector<device_only_memory<char>> delayed_free_bvh_memory;
+ vector<unique_ptr<device_only_memory<char>>> delayed_free_bvh_memory;
thread_mutex delayed_free_bvh_mutex;
class Denoiser {
@@ -97,8 +100,7 @@ class OptiXDevice : public CUDADevice {
/* OptiX denoiser state and scratch buffers, stored in a single memory buffer.
* The memory layout goes as following: [denoiser state][scratch buffer]. */
device_only_memory<unsigned char> state;
- size_t scratch_offset = 0;
- size_t scratch_size = 0;
+ OptixDenoiserSizes sizes = {};
bool use_pass_albedo = false;
bool use_pass_normal = false;
diff --git a/intern/cycles/device/optix/queue.cpp b/intern/cycles/device/optix/queue.cpp
index e3946d94f5d..1a437878b5f 100644
--- a/intern/cycles/device/optix/queue.cpp
+++ b/intern/cycles/device/optix/queue.cpp
@@ -47,7 +47,9 @@ static bool is_optix_specific_kernel(DeviceKernel kernel)
kernel == DEVICE_KERNEL_INTEGRATOR_INTERSECT_VOLUME_STACK);
}
-bool OptiXDeviceQueue::enqueue(DeviceKernel kernel, const int work_size, void *args[])
+bool OptiXDeviceQueue::enqueue(DeviceKernel kernel,
+ const int work_size,
+ DeviceKernelArguments const &args)
{
if (!is_optix_specific_kernel(kernel)) {
return CUDADeviceQueue::enqueue(kernel, work_size, args);
@@ -69,7 +71,7 @@ bool OptiXDeviceQueue::enqueue(DeviceKernel kernel, const int work_size, void *a
cuda_device_assert(
cuda_device_,
cuMemcpyHtoDAsync(launch_params_ptr + offsetof(KernelParamsOptiX, path_index_array),
- args[0], // &d_path_index
+ args.values[0], // &d_path_index
sizeof(device_ptr),
cuda_stream_));
@@ -78,7 +80,7 @@ bool OptiXDeviceQueue::enqueue(DeviceKernel kernel, const int work_size, void *a
cuda_device_assert(
cuda_device_,
cuMemcpyHtoDAsync(launch_params_ptr + offsetof(KernelParamsOptiX, render_buffer),
- args[1], // &d_render_buffer
+ args.values[1], // &d_render_buffer
sizeof(device_ptr),
cuda_stream_));
}
diff --git a/intern/cycles/device/optix/queue.h b/intern/cycles/device/optix/queue.h
index 0de422ccc71..5f0e09dff2c 100644
--- a/intern/cycles/device/optix/queue.h
+++ b/intern/cycles/device/optix/queue.h
@@ -31,7 +31,9 @@ class OptiXDeviceQueue : public CUDADeviceQueue {
virtual void init_execution() override;
- virtual bool enqueue(DeviceKernel kernel, const int work_size, void *args[]) override;
+ virtual bool enqueue(DeviceKernel kernel,
+ const int work_size,
+ DeviceKernelArguments const &args) override;
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/device/queue.h b/intern/cycles/device/queue.h
index 188162f4b74..4e9f41f7875 100644
--- a/intern/cycles/device/queue.h
+++ b/intern/cycles/device/queue.h
@@ -31,6 +31,72 @@ class device_memory;
struct KernelWorkTile;
+/* Container for device kernel arguments with type correctness ensured by API. */
+struct DeviceKernelArguments {
+
+ enum Type {
+ POINTER,
+ INT32,
+ FLOAT32,
+ BOOLEAN,
+ KERNEL_FILM_CONVERT,
+ };
+
+ static const int MAX_ARGS = 16;
+ Type types[MAX_ARGS];
+ void *values[MAX_ARGS];
+ size_t sizes[MAX_ARGS];
+ size_t count = 0;
+
+ DeviceKernelArguments()
+ {
+ }
+
+ template<class T> DeviceKernelArguments(const T *arg)
+ {
+ add(arg);
+ }
+
+ template<class T, class... Args> DeviceKernelArguments(const T *first, Args... args)
+ {
+ add(first);
+ add(args...);
+ }
+
+ void add(const KernelFilmConvert *value)
+ {
+ add(KERNEL_FILM_CONVERT, value, sizeof(KernelFilmConvert));
+ }
+ void add(const device_ptr *value)
+ {
+ add(POINTER, value, sizeof(device_ptr));
+ }
+ void add(const int32_t *value)
+ {
+ add(INT32, value, sizeof(int32_t));
+ }
+ void add(const float *value)
+ {
+ add(FLOAT32, value, sizeof(float));
+ }
+ void add(const bool *value)
+ {
+ add(BOOLEAN, value, 4);
+ }
+ void add(const Type type, const void *value, size_t size)
+ {
+ types[count] = type;
+ values[count] = (void *)value;
+ sizes[count] = size;
+ count++;
+ }
+ template<typename T, typename... Args> void add(const T *first, Args... args)
+ {
+ add(first);
+ add(args...);
+ }
+};
+
/* Abstraction of a command queue for a device.
* Provides API to schedule kernel execution in a specific queue with minimal possible overhead
* from driver side.
@@ -66,7 +132,9 @@ class DeviceQueue {
* - int: pass pointer to the int
* - device memory: pass pointer to device_memory.device_pointer
* Return false if there was an error executing this or a previous kernel. */
- virtual bool enqueue(DeviceKernel kernel, const int work_size, void *args[]) = 0;
+ virtual bool enqueue(DeviceKernel kernel,
+ const int work_size,
+ DeviceKernelArguments const &args) = 0;
/* Wait unit all enqueued kernels have finished execution.
* Return false if there was an error executing any of the enqueued kernels. */
diff --git a/intern/cycles/graph/node.h b/intern/cycles/graph/node.h
index a00162a3b9a..8b505c0eb9e 100644
--- a/intern/cycles/graph/node.h
+++ b/intern/cycles/graph/node.h
@@ -31,7 +31,7 @@ struct Node;
struct NodeType;
struct Transform;
-/* Note: in the following macros we use "type const &" instead of "const type &"
+/* NOTE: in the following macros we use "type const &" instead of "const type &"
* to avoid issues when pasting a pointer type. */
#define NODE_SOCKET_API_BASE_METHODS(type_, name, string_name) \
const SocketType *get_##name##_socket() const \
diff --git a/intern/cycles/integrator/denoiser_oidn.cpp b/intern/cycles/integrator/denoiser_oidn.cpp
index b09b95a11b0..a08aec513fc 100644
--- a/intern/cycles/integrator/denoiser_oidn.cpp
+++ b/intern/cycles/integrator/denoiser_oidn.cpp
@@ -47,9 +47,6 @@ static bool oidn_progress_monitor_function(void *user_ptr, double /*n*/)
OIDNDenoiser *oidn_denoiser = reinterpret_cast<OIDNDenoiser *>(user_ptr);
return !oidn_denoiser->is_cancelled();
}
-#endif
-
-#ifdef WITH_OPENIMAGEDENOISE
class OIDNPass {
public:
@@ -547,7 +544,6 @@ class OIDNDenoiseContext {
* the fake values and denoising of passes which do need albedo can no longer happen. */
bool albedo_replaced_with_fake_ = false;
};
-#endif
static unique_ptr<DeviceQueue> create_device_queue(const RenderBuffers *render_buffers)
{
@@ -582,18 +578,20 @@ static void copy_render_buffers_to_device(unique_ptr<DeviceQueue> &queue,
}
}
+#endif
+
bool OIDNDenoiser::denoise_buffer(const BufferParams &buffer_params,
RenderBuffers *render_buffers,
const int num_samples,
bool allow_inplace_modification)
{
+#ifdef WITH_OPENIMAGEDENOISE
thread_scoped_lock lock(mutex_);
/* Make sure the host-side data is available for denoising. */
unique_ptr<DeviceQueue> queue = create_device_queue(render_buffers);
copy_render_buffers_from_device(queue, render_buffers);
-#ifdef WITH_OPENIMAGEDENOISE
OIDNDenoiseContext context(
this, params_, buffer_params, render_buffers, num_samples, allow_inplace_modification);
@@ -620,6 +618,11 @@ bool OIDNDenoiser::denoise_buffer(const BufferParams &buffer_params,
* copies data from the device it doesn't overwrite the denoiser buffers. */
copy_render_buffers_to_device(queue, render_buffers);
}
+#else
+ (void)buffer_params;
+ (void)render_buffers;
+ (void)num_samples;
+ (void)allow_inplace_modification;
#endif
/* This code is not supposed to run when compiled without OIDN support, so can assume if we made
diff --git a/intern/cycles/integrator/pass_accessor_gpu.cpp b/intern/cycles/integrator/pass_accessor_gpu.cpp
index c03ef64a2b2..3fd973749b8 100644
--- a/intern/cycles/integrator/pass_accessor_gpu.cpp
+++ b/intern/cycles/integrator/pass_accessor_gpu.cpp
@@ -54,30 +54,30 @@ void PassAccessorGPU::run_film_convert_kernels(DeviceKernel kernel,
if (destination.d_pixels) {
DCHECK_EQ(destination.stride, 0) << "Custom stride for float destination is not implemented.";
- void *args[] = {const_cast<KernelFilmConvert *>(&kfilm_convert),
- const_cast<device_ptr *>(&destination.d_pixels),
- const_cast<device_ptr *>(&render_buffers->buffer.device_pointer),
- const_cast<int *>(&work_size),
- const_cast<int *>(&buffer_params.window_width),
- const_cast<int *>(&offset),
- const_cast<int *>(&buffer_params.stride),
- const_cast<int *>(&destination.offset),
- const_cast<int *>(&destination_stride)};
+ DeviceKernelArguments args(&kfilm_convert,
+ &destination.d_pixels,
+ &render_buffers->buffer.device_pointer,
+ &work_size,
+ &buffer_params.window_width,
+ &offset,
+ &buffer_params.stride,
+ &destination.offset,
+ &destination_stride);
queue_->enqueue(kernel, work_size, args);
}
if (destination.d_pixels_half_rgba) {
const DeviceKernel kernel_half_float = static_cast<DeviceKernel>(kernel + 1);
- void *args[] = {const_cast<KernelFilmConvert *>(&kfilm_convert),
- const_cast<device_ptr *>(&destination.d_pixels_half_rgba),
- const_cast<device_ptr *>(&render_buffers->buffer.device_pointer),
- const_cast<int *>(&work_size),
- const_cast<int *>(&buffer_params.window_width),
- const_cast<int *>(&offset),
- const_cast<int *>(&buffer_params.stride),
- const_cast<int *>(&destination.offset),
- const_cast<int *>(&destination_stride)};
+ DeviceKernelArguments args(&kfilm_convert,
+ &destination.d_pixels_half_rgba,
+ &render_buffers->buffer.device_pointer,
+ &work_size,
+ &buffer_params.window_width,
+ &offset,
+ &buffer_params.stride,
+ &destination.offset,
+ &destination_stride);
queue_->enqueue(kernel_half_float, work_size, args);
}
diff --git a/intern/cycles/integrator/path_trace.cpp b/intern/cycles/integrator/path_trace.cpp
index ec90681b78a..bdc18b1c0a1 100644
--- a/intern/cycles/integrator/path_trace.cpp
+++ b/intern/cycles/integrator/path_trace.cpp
@@ -482,7 +482,11 @@ void PathTrace::set_denoiser_params(const DenoiseParams &params)
}
denoiser_ = Denoiser::create(device_, params);
- denoiser_->is_cancelled_cb = [this]() { return is_cancel_requested(); };
+
+ /* Only take into account the "immediate" cancel to have interactive rendering responding to
+ * navigation as quickly as possible, but allow to run denoiser after user hit Esc button while
+ * doing offline rendering. */
+ denoiser_->is_cancelled_cb = [this]() { return render_cancel_.is_requested; };
}
void PathTrace::set_adaptive_sampling(const AdaptiveSampling &adaptive_sampling)
@@ -1089,6 +1093,8 @@ static const char *device_type_for_description(const DeviceType type)
return "Dummy";
case DEVICE_MULTI:
return "Multi";
+ case DEVICE_METAL:
+ return "Metal";
}
return "UNKNOWN";
diff --git a/intern/cycles/integrator/path_trace_work_gpu.cpp b/intern/cycles/integrator/path_trace_work_gpu.cpp
index 956aa6a8c90..e5062c6c47e 100644
--- a/intern/cycles/integrator/path_trace_work_gpu.cpp
+++ b/intern/cycles/integrator/path_trace_work_gpu.cpp
@@ -258,7 +258,8 @@ void PathTraceWorkGPU::render_samples(RenderStatistics &statistics,
* become busy after adding new tiles). This is especially important for the shadow catcher which
* schedules work in halves of available number of paths. */
work_tile_scheduler_.set_max_num_path_states(max_num_paths_ / 8);
-
+ work_tile_scheduler_.set_accelerated_rt((device_->get_bvh_layout_mask() & BVH_LAYOUT_OPTIX) !=
+ 0);
work_tile_scheduler_.reset(effective_buffer_params_,
start_sample,
samples_num,
@@ -333,7 +334,8 @@ DeviceKernel PathTraceWorkGPU::get_most_queued_kernel() const
void PathTraceWorkGPU::enqueue_reset()
{
- void *args[] = {&max_num_paths_};
+ DeviceKernelArguments args(&max_num_paths_);
+
queue_->enqueue(DEVICE_KERNEL_INTEGRATOR_RESET, max_num_paths_, args);
queue_->zero_to_device(integrator_queue_counter_);
queue_->zero_to_device(integrator_shader_sort_counter_);
@@ -404,7 +406,7 @@ bool PathTraceWorkGPU::enqueue_path_iteration()
void PathTraceWorkGPU::enqueue_path_iteration(DeviceKernel kernel, const int num_paths_limit)
{
- void *d_path_index = (void *)NULL;
+ device_ptr d_path_index = 0;
/* Create array of path indices for which this kernel is queued to be executed. */
int work_size = kernel_max_active_main_path_index(kernel);
@@ -415,14 +417,14 @@ void PathTraceWorkGPU::enqueue_path_iteration(DeviceKernel kernel, const int num
if (kernel_uses_sorting(kernel)) {
/* Compute array of active paths, sorted by shader. */
work_size = num_queued;
- d_path_index = (void *)queued_paths_.device_pointer;
+ d_path_index = queued_paths_.device_pointer;
compute_sorted_queued_paths(
DEVICE_KERNEL_INTEGRATOR_SORTED_PATHS_ARRAY, kernel, num_paths_limit);
}
else if (num_queued < work_size) {
work_size = num_queued;
- d_path_index = (void *)queued_paths_.device_pointer;
+ d_path_index = queued_paths_.device_pointer;
if (kernel_is_shadow_path(kernel)) {
/* Compute array of active shadow paths for specific kernel. */
@@ -441,8 +443,7 @@ void PathTraceWorkGPU::enqueue_path_iteration(DeviceKernel kernel, const int num
switch (kernel) {
case DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST: {
/* Closest ray intersection kernels with integrator state and render buffer. */
- void *d_render_buffer = (void *)buffers_->buffer.device_pointer;
- void *args[] = {&d_path_index, &d_render_buffer, const_cast<int *>(&work_size)};
+ DeviceKernelArguments args(&d_path_index, &buffers_->buffer.device_pointer, &work_size);
queue_->enqueue(kernel, work_size, args);
break;
@@ -452,7 +453,7 @@ void PathTraceWorkGPU::enqueue_path_iteration(DeviceKernel kernel, const int num
case DEVICE_KERNEL_INTEGRATOR_INTERSECT_SUBSURFACE:
case DEVICE_KERNEL_INTEGRATOR_INTERSECT_VOLUME_STACK: {
/* Ray intersection kernels with integrator state. */
- void *args[] = {&d_path_index, const_cast<int *>(&work_size)};
+ DeviceKernelArguments args(&d_path_index, &work_size);
queue_->enqueue(kernel, work_size, args);
break;
@@ -464,8 +465,7 @@ void PathTraceWorkGPU::enqueue_path_iteration(DeviceKernel kernel, const int num
case DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE:
case DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME: {
/* Shading kernels with integrator state and render buffer. */
- void *d_render_buffer = (void *)buffers_->buffer.device_pointer;
- void *args[] = {&d_path_index, &d_render_buffer, const_cast<int *>(&work_size)};
+ DeviceKernelArguments args(&d_path_index, &buffers_->buffer.device_pointer, &work_size);
queue_->enqueue(kernel, work_size, args);
break;
@@ -483,15 +483,17 @@ void PathTraceWorkGPU::compute_sorted_queued_paths(DeviceKernel kernel,
const int num_paths_limit)
{
int d_queued_kernel = queued_kernel;
- void *d_counter = integrator_state_gpu_.sort_key_counter[d_queued_kernel];
- void *d_prefix_sum = (void *)integrator_shader_sort_prefix_sum_.device_pointer;
- assert(d_counter != nullptr && d_prefix_sum != nullptr);
+ device_ptr d_counter = (device_ptr)integrator_state_gpu_.sort_key_counter[d_queued_kernel];
+ device_ptr d_prefix_sum = integrator_shader_sort_prefix_sum_.device_pointer;
+ assert(d_counter != 0 && d_prefix_sum != 0);
/* Compute prefix sum of number of active paths with each shader. */
{
const int work_size = 1;
int max_shaders = device_scene_->data.max_shaders;
- void *args[] = {&d_counter, &d_prefix_sum, &max_shaders};
+
+ DeviceKernelArguments args(&d_counter, &d_prefix_sum, &max_shaders);
+
queue_->enqueue(DEVICE_KERNEL_PREFIX_SUM, work_size, args);
}
@@ -506,15 +508,16 @@ void PathTraceWorkGPU::compute_sorted_queued_paths(DeviceKernel kernel,
* end of the array since compaction would need to do less work. */
const int work_size = kernel_max_active_main_path_index(queued_kernel);
- void *d_queued_paths = (void *)queued_paths_.device_pointer;
- void *d_num_queued_paths = (void *)num_queued_paths_.device_pointer;
- void *args[] = {const_cast<int *>(&work_size),
- const_cast<int *>(&num_paths_limit),
- &d_queued_paths,
- &d_num_queued_paths,
- &d_counter,
- &d_prefix_sum,
- &d_queued_kernel};
+ device_ptr d_queued_paths = queued_paths_.device_pointer;
+ device_ptr d_num_queued_paths = num_queued_paths_.device_pointer;
+
+ DeviceKernelArguments args(&work_size,
+ &num_paths_limit,
+ &d_queued_paths,
+ &d_num_queued_paths,
+ &d_counter,
+ &d_prefix_sum,
+ &d_queued_kernel);
queue_->enqueue(kernel, work_size, args);
}
@@ -526,10 +529,10 @@ void PathTraceWorkGPU::compute_queued_paths(DeviceKernel kernel, DeviceKernel qu
/* Launch kernel to fill the active paths arrays. */
const int work_size = kernel_max_active_main_path_index(queued_kernel);
- void *d_queued_paths = (void *)queued_paths_.device_pointer;
- void *d_num_queued_paths = (void *)num_queued_paths_.device_pointer;
- void *args[] = {
- const_cast<int *>(&work_size), &d_queued_paths, &d_num_queued_paths, &d_queued_kernel};
+ device_ptr d_queued_paths = queued_paths_.device_pointer;
+ device_ptr d_num_queued_paths = num_queued_paths_.device_pointer;
+
+ DeviceKernelArguments args(&work_size, &d_queued_paths, &d_num_queued_paths, &d_queued_kernel);
queue_->zero_to_device(num_queued_paths_);
queue_->enqueue(kernel, work_size, args);
@@ -605,15 +608,17 @@ void PathTraceWorkGPU::compact_paths(const int num_active_paths,
{
/* Compact fragmented path states into the start of the array, moving any paths
* with index higher than the number of active paths into the gaps. */
- void *d_compact_paths = (void *)queued_paths_.device_pointer;
- void *d_num_queued_paths = (void *)num_queued_paths_.device_pointer;
+ device_ptr d_compact_paths = queued_paths_.device_pointer;
+ device_ptr d_num_queued_paths = num_queued_paths_.device_pointer;
/* Create array with terminated paths that we can write to. */
{
/* TODO: can the work size be reduced here? */
int offset = num_active_paths;
int work_size = num_active_paths;
- void *args[] = {&work_size, &d_compact_paths, &d_num_queued_paths, &offset};
+
+ DeviceKernelArguments args(&work_size, &d_compact_paths, &d_num_queued_paths, &offset);
+
queue_->zero_to_device(num_queued_paths_);
queue_->enqueue(terminated_paths_kernel, work_size, args);
}
@@ -622,8 +627,10 @@ void PathTraceWorkGPU::compact_paths(const int num_active_paths,
* than the number of active paths. */
{
int work_size = max_active_path_index;
- void *args[] = {
- &work_size, &d_compact_paths, &d_num_queued_paths, const_cast<int *>(&num_active_paths)};
+
+ DeviceKernelArguments args(
+ &work_size, &d_compact_paths, &d_num_queued_paths, &num_active_paths);
+
queue_->zero_to_device(num_queued_paths_);
queue_->enqueue(compact_paths_kernel, work_size, args);
}
@@ -638,8 +645,10 @@ void PathTraceWorkGPU::compact_paths(const int num_active_paths,
int work_size = num_compact_paths;
int active_states_offset = 0;
int terminated_states_offset = num_active_paths;
- void *args[] = {
- &d_compact_paths, &active_states_offset, &terminated_states_offset, &work_size};
+
+ DeviceKernelArguments args(
+ &d_compact_paths, &active_states_offset, &terminated_states_offset, &work_size);
+
queue_->enqueue(compact_kernel, work_size, args);
}
}
@@ -768,14 +777,12 @@ void PathTraceWorkGPU::enqueue_work_tiles(DeviceKernel kernel,
queue_->copy_to_device(work_tiles_);
- void *d_work_tiles = (void *)work_tiles_.device_pointer;
- void *d_render_buffer = (void *)buffers_->buffer.device_pointer;
+ device_ptr d_work_tiles = work_tiles_.device_pointer;
+ device_ptr d_render_buffer = buffers_->buffer.device_pointer;
/* Launch kernel. */
- void *args[] = {&d_work_tiles,
- const_cast<int *>(&num_work_tiles),
- &d_render_buffer,
- const_cast<int *>(&max_tile_work_size)};
+ DeviceKernelArguments args(
+ &d_work_tiles, &num_work_tiles, &d_render_buffer, &max_tile_work_size);
queue_->enqueue(kernel, max_tile_work_size * num_work_tiles, args);
@@ -965,16 +972,16 @@ int PathTraceWorkGPU::adaptive_sampling_convergence_check_count_active(float thr
const int work_size = effective_buffer_params_.width * effective_buffer_params_.height;
- void *args[] = {&buffers_->buffer.device_pointer,
- const_cast<int *>(&effective_buffer_params_.full_x),
- const_cast<int *>(&effective_buffer_params_.full_y),
- const_cast<int *>(&effective_buffer_params_.width),
- const_cast<int *>(&effective_buffer_params_.height),
- &threshold,
- &reset,
- &effective_buffer_params_.offset,
- &effective_buffer_params_.stride,
- &num_active_pixels.device_pointer};
+ DeviceKernelArguments args(&buffers_->buffer.device_pointer,
+ &effective_buffer_params_.full_x,
+ &effective_buffer_params_.full_y,
+ &effective_buffer_params_.width,
+ &effective_buffer_params_.height,
+ &threshold,
+ &reset,
+ &effective_buffer_params_.offset,
+ &effective_buffer_params_.stride,
+ &num_active_pixels.device_pointer);
queue_->enqueue(DEVICE_KERNEL_ADAPTIVE_SAMPLING_CONVERGENCE_CHECK, work_size, args);
@@ -988,13 +995,13 @@ void PathTraceWorkGPU::enqueue_adaptive_sampling_filter_x()
{
const int work_size = effective_buffer_params_.height;
- void *args[] = {&buffers_->buffer.device_pointer,
- &effective_buffer_params_.full_x,
- &effective_buffer_params_.full_y,
- &effective_buffer_params_.width,
- &effective_buffer_params_.height,
- &effective_buffer_params_.offset,
- &effective_buffer_params_.stride};
+ DeviceKernelArguments args(&buffers_->buffer.device_pointer,
+ &effective_buffer_params_.full_x,
+ &effective_buffer_params_.full_y,
+ &effective_buffer_params_.width,
+ &effective_buffer_params_.height,
+ &effective_buffer_params_.offset,
+ &effective_buffer_params_.stride);
queue_->enqueue(DEVICE_KERNEL_ADAPTIVE_SAMPLING_CONVERGENCE_FILTER_X, work_size, args);
}
@@ -1003,13 +1010,13 @@ void PathTraceWorkGPU::enqueue_adaptive_sampling_filter_y()
{
const int work_size = effective_buffer_params_.width;
- void *args[] = {&buffers_->buffer.device_pointer,
- &effective_buffer_params_.full_x,
- &effective_buffer_params_.full_y,
- &effective_buffer_params_.width,
- &effective_buffer_params_.height,
- &effective_buffer_params_.offset,
- &effective_buffer_params_.stride};
+ DeviceKernelArguments args(&buffers_->buffer.device_pointer,
+ &effective_buffer_params_.full_x,
+ &effective_buffer_params_.full_y,
+ &effective_buffer_params_.width,
+ &effective_buffer_params_.height,
+ &effective_buffer_params_.offset,
+ &effective_buffer_params_.stride);
queue_->enqueue(DEVICE_KERNEL_ADAPTIVE_SAMPLING_CONVERGENCE_FILTER_Y, work_size, args);
}
@@ -1018,10 +1025,10 @@ void PathTraceWorkGPU::cryptomatte_postproces()
{
const int work_size = effective_buffer_params_.width * effective_buffer_params_.height;
- void *args[] = {&buffers_->buffer.device_pointer,
- const_cast<int *>(&work_size),
- &effective_buffer_params_.offset,
- &effective_buffer_params_.stride};
+ DeviceKernelArguments args(&buffers_->buffer.device_pointer,
+ &work_size,
+ &effective_buffer_params_.offset,
+ &effective_buffer_params_.stride);
queue_->enqueue(DEVICE_KERNEL_CRYPTOMATTE_POSTPROCESS, work_size, args);
}
@@ -1070,8 +1077,9 @@ int PathTraceWorkGPU::shadow_catcher_count_possible_splits()
queue_->zero_to_device(num_queued_paths_);
const int work_size = max_active_main_path_index_;
- void *d_num_queued_paths = (void *)num_queued_paths_.device_pointer;
- void *args[] = {const_cast<int *>(&work_size), &d_num_queued_paths};
+ device_ptr d_num_queued_paths = num_queued_paths_.device_pointer;
+
+ DeviceKernelArguments args(&work_size, &d_num_queued_paths);
queue_->enqueue(DEVICE_KERNEL_INTEGRATOR_SHADOW_CATCHER_COUNT_POSSIBLE_SPLITS, work_size, args);
queue_->copy_from_device(num_queued_paths_);
diff --git a/intern/cycles/integrator/render_scheduler.cpp b/intern/cycles/integrator/render_scheduler.cpp
index 971173a5e96..02e457c2b1b 100644
--- a/intern/cycles/integrator/render_scheduler.cpp
+++ b/intern/cycles/integrator/render_scheduler.cpp
@@ -112,7 +112,7 @@ int RenderScheduler::get_rendered_sample() const
{
DCHECK_GT(get_num_rendered_samples(), 0);
- return start_sample_ + get_num_rendered_samples() - 1;
+ return start_sample_ + get_num_rendered_samples() - 1 - sample_offset_;
}
int RenderScheduler::get_num_rendered_samples() const
@@ -406,6 +406,9 @@ bool RenderScheduler::set_postprocess_render_work(RenderWork *render_work)
any_scheduled = true;
}
+ /* Force update. */
+ any_scheduled = true;
+
if (any_scheduled) {
render_work->display.update = true;
}
@@ -874,7 +877,8 @@ int RenderScheduler::get_num_samples_to_path_trace() const
* is to ensure that the final render is pixel-matched regardless of how many samples per second
* compute device can do. */
- return adaptive_sampling_.align_samples(path_trace_start_sample, num_samples_to_render);
+ return adaptive_sampling_.align_samples(path_trace_start_sample - sample_offset_,
+ num_samples_to_render);
}
int RenderScheduler::get_num_samples_during_navigation(int resolution_divider) const
diff --git a/intern/cycles/integrator/shader_eval.cpp b/intern/cycles/integrator/shader_eval.cpp
index 9ec530c81df..95a1adeb016 100644
--- a/intern/cycles/integrator/shader_eval.cpp
+++ b/intern/cycles/integrator/shader_eval.cpp
@@ -158,14 +158,16 @@ bool ShaderEval::eval_gpu(Device *device,
/* Execute work on GPU in chunk, so we can cancel.
* TODO : query appropriate size from device.*/
- const int64_t chunk_size = 65536;
+ const int32_t chunk_size = 65536;
- void *d_input = (void *)input.device_pointer;
- void *d_output = (void *)output.device_pointer;
+ device_ptr d_input = input.device_pointer;
+ device_ptr d_output = output.device_pointer;
- for (int64_t d_offset = 0; d_offset < work_size; d_offset += chunk_size) {
- int64_t d_work_size = std::min(chunk_size, work_size - d_offset);
- void *args[] = {&d_input, &d_output, &d_offset, &d_work_size};
+ assert(work_size <= 0x7fffffff);
+ for (int32_t d_offset = 0; d_offset < int32_t(work_size); d_offset += chunk_size) {
+ int32_t d_work_size = std::min(chunk_size, int32_t(work_size) - d_offset);
+
+ DeviceKernelArguments args(&d_input, &d_output, &d_offset, &d_work_size);
queue->enqueue(kernel, d_work_size, args);
queue->synchronize();
diff --git a/intern/cycles/integrator/tile.cpp b/intern/cycles/integrator/tile.cpp
index 4a1558cce09..e9a3cbd38aa 100644
--- a/intern/cycles/integrator/tile.cpp
+++ b/intern/cycles/integrator/tile.cpp
@@ -46,7 +46,8 @@ ccl_device_inline uint round_up_to_power_of_two(uint x)
return next_power_of_two(x);
}
-TileSize tile_calculate_best_size(const int2 &image_size,
+TileSize tile_calculate_best_size(const bool accel_rt,
+ const int2 &image_size,
const int num_samples,
const int max_num_path_states,
const float scrambling_distance)
@@ -73,7 +74,7 @@ TileSize tile_calculate_best_size(const int2 &image_size,
TileSize tile_size;
const int num_path_states_per_sample = max_num_path_states / num_samples;
- if (scrambling_distance < 0.9f) {
+ if (scrambling_distance < 0.9f && accel_rt) {
/* Prefer large tiles for scrambling distance, bounded by max num path states. */
tile_size.width = min(image_size.x, max_num_path_states);
tile_size.height = min(image_size.y, max(max_num_path_states / tile_size.width, 1));
diff --git a/intern/cycles/integrator/tile.h b/intern/cycles/integrator/tile.h
index 61f7d736115..05b1e0af6b1 100644
--- a/intern/cycles/integrator/tile.h
+++ b/intern/cycles/integrator/tile.h
@@ -49,7 +49,8 @@ std::ostream &operator<<(std::ostream &os, const TileSize &tile_size);
* of active path states.
* Will attempt to provide best guess to keep path tracing threads of a device as localized as
* possible, and have as many threads active for every tile as possible. */
-TileSize tile_calculate_best_size(const int2 &image_size,
+TileSize tile_calculate_best_size(const bool accel_rt,
+ const int2 &image_size,
const int num_samples,
const int max_num_path_states,
const float scrambling_distance);
diff --git a/intern/cycles/integrator/work_tile_scheduler.cpp b/intern/cycles/integrator/work_tile_scheduler.cpp
index d60f7149bf4..353c357475d 100644
--- a/intern/cycles/integrator/work_tile_scheduler.cpp
+++ b/intern/cycles/integrator/work_tile_scheduler.cpp
@@ -28,6 +28,11 @@ WorkTileScheduler::WorkTileScheduler()
{
}
+void WorkTileScheduler::set_accelerated_rt(bool accelerated_rt)
+{
+ accelerated_rt_ = accelerated_rt;
+}
+
void WorkTileScheduler::set_max_num_path_states(int max_num_path_states)
{
max_num_path_states_ = max_num_path_states;
@@ -61,7 +66,7 @@ void WorkTileScheduler::reset(const BufferParams &buffer_params,
void WorkTileScheduler::reset_scheduler_state()
{
tile_size_ = tile_calculate_best_size(
- image_size_px_, samples_num_, max_num_path_states_, scrambling_distance_);
+ accelerated_rt_, image_size_px_, samples_num_, max_num_path_states_, scrambling_distance_);
VLOG(3) << "Will schedule tiles of size " << tile_size_;
diff --git a/intern/cycles/integrator/work_tile_scheduler.h b/intern/cycles/integrator/work_tile_scheduler.h
index 2d6395799f7..b9cef7be7c4 100644
--- a/intern/cycles/integrator/work_tile_scheduler.h
+++ b/intern/cycles/integrator/work_tile_scheduler.h
@@ -31,6 +31,9 @@ class WorkTileScheduler {
public:
WorkTileScheduler();
+ /* To indicate if there is accelerated RT support. */
+ void set_accelerated_rt(bool state);
+
/* MAximum path states which are allowed to be used by a single scheduled work tile.
*
* Affects the scheduled work size: the work size will be as big as possible, but will not exceed
@@ -55,6 +58,9 @@ class WorkTileScheduler {
protected:
void reset_scheduler_state();
+ /* Used to indicate if there is accelerated ray tracing. */
+ bool accelerated_rt_ = false;
+
/* Maximum allowed path states to be used.
*
* TODO(sergey): Naming can be improved. The fact that this is a limiting factor based on the
diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt
index d759399b04d..51158b86c5a 100644
--- a/intern/cycles/kernel/CMakeLists.txt
+++ b/intern/cycles/kernel/CMakeLists.txt
@@ -179,11 +179,14 @@ set(SRC_KERNEL_GEOM_HEADERS
geom/curve.h
geom/curve_intersect.h
geom/motion_curve.h
+ geom/motion_point.h
geom/motion_triangle.h
geom/motion_triangle_intersect.h
geom/motion_triangle_shader.h
geom/object.h
geom/patch.h
+ geom/point.h
+ geom/point_intersect.h
geom/primitive.h
geom/shader_data.h
geom/subd_triangle.h
@@ -207,6 +210,7 @@ set(SRC_KERNEL_BVH_HEADERS
bvh/volume.h
bvh/volume_all.h
bvh/embree.h
+ bvh/metal.h
)
set(SRC_KERNEL_CAMERA_HEADERS
diff --git a/intern/cycles/kernel/bvh/bvh.h b/intern/cycles/kernel/bvh/bvh.h
index 0e083812355..67804fb1d0d 100644
--- a/intern/cycles/kernel/bvh/bvh.h
+++ b/intern/cycles/kernel/bvh/bvh.h
@@ -31,6 +31,10 @@
# include "kernel/bvh/embree.h"
#endif
+#ifdef __METALRT__
+# include "kernel/bvh/metal.h"
+#endif
+
#include "kernel/bvh/types.h"
#include "kernel/bvh/util.h"
@@ -38,31 +42,31 @@
CCL_NAMESPACE_BEGIN
-#ifndef __KERNEL_OPTIX__
+#if !defined(__KERNEL_GPU_RAYTRACING__)
/* Regular BVH traversal */
# include "kernel/bvh/nodes.h"
# define BVH_FUNCTION_NAME bvh_intersect
-# define BVH_FUNCTION_FEATURES 0
+# define BVH_FUNCTION_FEATURES BVH_POINTCLOUD
# include "kernel/bvh/traversal.h"
# if defined(__HAIR__)
# define BVH_FUNCTION_NAME bvh_intersect_hair
-# define BVH_FUNCTION_FEATURES BVH_HAIR
+# define BVH_FUNCTION_FEATURES BVH_HAIR | BVH_POINTCLOUD
# include "kernel/bvh/traversal.h"
# endif
# if defined(__OBJECT_MOTION__)
# define BVH_FUNCTION_NAME bvh_intersect_motion
-# define BVH_FUNCTION_FEATURES BVH_MOTION
+# define BVH_FUNCTION_FEATURES BVH_MOTION | BVH_POINTCLOUD
# include "kernel/bvh/traversal.h"
# endif
# if defined(__HAIR__) && defined(__OBJECT_MOTION__)
# define BVH_FUNCTION_NAME bvh_intersect_hair_motion
-# define BVH_FUNCTION_FEATURES BVH_HAIR | BVH_MOTION
+# define BVH_FUNCTION_FEATURES BVH_HAIR | BVH_MOTION | BVH_POINTCLOUD
# include "kernel/bvh/traversal.h"
# endif
@@ -98,26 +102,27 @@ CCL_NAMESPACE_BEGIN
# if defined(__SHADOW_RECORD_ALL__)
# define BVH_FUNCTION_NAME bvh_intersect_shadow_all
-# define BVH_FUNCTION_FEATURES 0
+# define BVH_FUNCTION_FEATURES BVH_POINTCLOUD
# include "kernel/bvh/shadow_all.h"
# if defined(__HAIR__)
# define BVH_FUNCTION_NAME bvh_intersect_shadow_all_hair
-# define BVH_FUNCTION_FEATURES BVH_HAIR
+# define BVH_FUNCTION_FEATURES BVH_HAIR | BVH_POINTCLOUD
# include "kernel/bvh/shadow_all.h"
# endif
# if defined(__OBJECT_MOTION__)
# define BVH_FUNCTION_NAME bvh_intersect_shadow_all_motion
-# define BVH_FUNCTION_FEATURES BVH_MOTION
+# define BVH_FUNCTION_FEATURES BVH_MOTION | BVH_POINTCLOUD
# include "kernel/bvh/shadow_all.h"
# endif
# if defined(__HAIR__) && defined(__OBJECT_MOTION__)
# define BVH_FUNCTION_NAME bvh_intersect_shadow_all_hair_motion
-# define BVH_FUNCTION_FEATURES BVH_HAIR | BVH_MOTION
+# define BVH_FUNCTION_FEATURES BVH_HAIR | BVH_MOTION | BVH_POINTCLOUD
# include "kernel/bvh/shadow_all.h"
# endif
+
# endif /* __SHADOW_RECORD_ALL__ */
/* Record all intersections - Volume BVH traversal. */
@@ -139,7 +144,7 @@ CCL_NAMESPACE_BEGIN
# undef BVH_NAME_EVAL
# undef BVH_FUNCTION_FULL_NAME
-#endif /* __KERNEL_OPTIX__ */
+#endif /* !defined(__KERNEL_GPU_RAYTRACING__) */
ccl_device_inline bool scene_intersect_valid(ccl_private const Ray *ray)
{
@@ -205,7 +210,95 @@ ccl_device_intersect bool scene_intersect(KernelGlobals kg,
isect->type = p5;
return p5 != PRIMITIVE_NONE;
-#else /* __KERNEL_OPTIX__ */
+#elif defined(__METALRT__)
+
+ if (!scene_intersect_valid(ray)) {
+ isect->t = ray->t;
+ isect->type = PRIMITIVE_NONE;
+ return false;
+ }
+
+# if defined(__KERNEL_DEBUG__)
+ if (is_null_instance_acceleration_structure(metal_ancillaries->accel_struct)) {
+ isect->t = ray->t;
+ isect->type = PRIMITIVE_NONE;
+ kernel_assert(!"Invalid metal_ancillaries->accel_struct pointer");
+ return false;
+ }
+
+ if (is_null_intersection_function_table(metal_ancillaries->ift_default)) {
+ isect->t = ray->t;
+ isect->type = PRIMITIVE_NONE;
+ kernel_assert(!"Invalid ift_default");
+ return false;
+ }
+# endif
+
+ metal::raytracing::ray r(ray->P, ray->D, 0.0f, ray->t);
+ metalrt_intersector_type metalrt_intersect;
+
+ if (!kernel_data.bvh.have_curves) {
+ metalrt_intersect.assume_geometry_type(metal::raytracing::geometry_type::triangle);
+ }
+
+ MetalRTIntersectionPayload payload;
+ payload.u = 0.0f;
+ payload.v = 0.0f;
+ payload.visibility = visibility;
+
+ typename metalrt_intersector_type::result_type intersection;
+
+ uint ray_mask = visibility & 0xFF;
+ if (0 == ray_mask && (visibility & ~0xFF) != 0) {
+ ray_mask = 0xFF;
+ /* No further intersector setup required: Default MetalRT behavior is any-hit. */
+ }
+ else if (visibility & PATH_RAY_SHADOW_OPAQUE) {
+ /* No further intersector setup required: Shadow ray early termination is controlled by the
+ * intersection handler */
+ }
+
+# if defined(__METALRT_MOTION__)
+ payload.time = ray->time;
+ intersection = metalrt_intersect.intersect(r,
+ metal_ancillaries->accel_struct,
+ ray_mask,
+ ray->time,
+ metal_ancillaries->ift_default,
+ payload);
+# else
+ intersection = metalrt_intersect.intersect(
+ r, metal_ancillaries->accel_struct, ray_mask, metal_ancillaries->ift_default, payload);
+# endif
+
+ if (intersection.type == intersection_type::none) {
+ isect->t = ray->t;
+ isect->type = PRIMITIVE_NONE;
+
+ return false;
+ }
+
+ isect->t = intersection.distance;
+
+ isect->prim = payload.prim;
+ isect->type = payload.type;
+ isect->object = intersection.user_instance_id;
+
+ isect->t = intersection.distance;
+ if (intersection.type == intersection_type::triangle) {
+ isect->u = 1.0f - intersection.triangle_barycentric_coord.y -
+ intersection.triangle_barycentric_coord.x;
+ isect->v = intersection.triangle_barycentric_coord.x;
+ }
+ else {
+ isect->u = payload.u;
+ isect->v = payload.v;
+ }
+
+ return isect->type != PRIMITIVE_NONE;
+
+#else
+
if (!scene_intersect_valid(ray)) {
return false;
}
@@ -289,7 +382,69 @@ ccl_device_intersect bool scene_intersect_local(KernelGlobals kg,
p5);
return p5;
-# else /* __KERNEL_OPTIX__ */
+# elif defined(__METALRT__)
+ if (!scene_intersect_valid(ray)) {
+ if (local_isect) {
+ local_isect->num_hits = 0;
+ }
+ return false;
+ }
+
+# if defined(__KERNEL_DEBUG__)
+ if (is_null_instance_acceleration_structure(metal_ancillaries->accel_struct)) {
+ if (local_isect) {
+ local_isect->num_hits = 0;
+ }
+ kernel_assert(!"Invalid metal_ancillaries->accel_struct pointer");
+ return false;
+ }
+
+ if (is_null_intersection_function_table(metal_ancillaries->ift_local)) {
+ if (local_isect) {
+ local_isect->num_hits = 0;
+ }
+ kernel_assert(!"Invalid ift_local");
+ return false;
+ }
+# endif
+
+ metal::raytracing::ray r(ray->P, ray->D, 0.0f, ray->t);
+ metalrt_intersector_type metalrt_intersect;
+
+ metalrt_intersect.force_opacity(metal::raytracing::forced_opacity::non_opaque);
+ if (!kernel_data.bvh.have_curves) {
+ metalrt_intersect.assume_geometry_type(metal::raytracing::geometry_type::triangle);
+ }
+
+ MetalRTIntersectionLocalPayload payload;
+ payload.local_object = local_object;
+ payload.max_hits = max_hits;
+ payload.local_isect.num_hits = 0;
+ if (lcg_state) {
+ payload.has_lcg_state = true;
+ payload.lcg_state = *lcg_state;
+ }
+ payload.result = false;
+
+ typename metalrt_intersector_type::result_type intersection;
+
+# if defined(__METALRT_MOTION__)
+ intersection = metalrt_intersect.intersect(
+ r, metal_ancillaries->accel_struct, 0xFF, ray->time, metal_ancillaries->ift_local, payload);
+# else
+ intersection = metalrt_intersect.intersect(
+ r, metal_ancillaries->accel_struct, 0xFF, metal_ancillaries->ift_local, payload);
+# endif
+
+ if (lcg_state) {
+ *lcg_state = payload.lcg_state;
+ }
+ *local_isect = payload.local_isect;
+
+ return payload.result;
+
+# else
+
if (!scene_intersect_valid(ray)) {
if (local_isect) {
local_isect->num_hits = 0;
@@ -406,7 +561,67 @@ ccl_device_intersect bool scene_intersect_shadow_all(KernelGlobals kg,
*throughput = __uint_as_float(p1);
return p5;
-# else /* __KERNEL_OPTIX__ */
+# elif defined(__METALRT__)
+
+ if (!scene_intersect_valid(ray)) {
+ return false;
+ }
+
+# if defined(__KERNEL_DEBUG__)
+ if (is_null_instance_acceleration_structure(metal_ancillaries->accel_struct)) {
+ kernel_assert(!"Invalid metal_ancillaries->accel_struct pointer");
+ return false;
+ }
+
+ if (is_null_intersection_function_table(metal_ancillaries->ift_shadow)) {
+ kernel_assert(!"Invalid ift_shadow");
+ return false;
+ }
+# endif
+
+ metal::raytracing::ray r(ray->P, ray->D, 0.0f, ray->t);
+ metalrt_intersector_type metalrt_intersect;
+
+ metalrt_intersect.force_opacity(metal::raytracing::forced_opacity::non_opaque);
+ if (!kernel_data.bvh.have_curves) {
+ metalrt_intersect.assume_geometry_type(metal::raytracing::geometry_type::triangle);
+ }
+
+ MetalRTIntersectionShadowPayload payload;
+ payload.visibility = visibility;
+ payload.max_hits = max_hits;
+ payload.num_hits = 0;
+ payload.num_recorded_hits = 0;
+ payload.throughput = 1.0f;
+ payload.result = false;
+ payload.state = state;
+
+ uint ray_mask = visibility & 0xFF;
+ if (0 == ray_mask && (visibility & ~0xFF) != 0) {
+ ray_mask = 0xFF;
+ }
+
+ typename metalrt_intersector_type::result_type intersection;
+
+# if defined(__METALRT_MOTION__)
+ payload.time = ray->time;
+ intersection = metalrt_intersect.intersect(r,
+ metal_ancillaries->accel_struct,
+ ray_mask,
+ ray->time,
+ metal_ancillaries->ift_shadow,
+ payload);
+# else
+ intersection = metalrt_intersect.intersect(
+ r, metal_ancillaries->accel_struct, ray_mask, metal_ancillaries->ift_shadow, payload);
+# endif
+
+ *num_recorded_hits = payload.num_recorded_hits;
+ *throughput = payload.throughput;
+
+ return payload.result;
+
+# else
if (!scene_intersect_valid(ray)) {
*num_recorded_hits = 0;
*throughput = 1.0f;
@@ -503,7 +718,76 @@ ccl_device_intersect bool scene_intersect_volume(KernelGlobals kg,
isect->type = p5;
return p5 != PRIMITIVE_NONE;
-# else /* __KERNEL_OPTIX__ */
+# elif defined(__METALRT__)
+
+ if (!scene_intersect_valid(ray)) {
+ return false;
+ }
+# if defined(__KERNEL_DEBUG__)
+ if (is_null_instance_acceleration_structure(metal_ancillaries->accel_struct)) {
+ kernel_assert(!"Invalid metal_ancillaries->accel_struct pointer");
+ return false;
+ }
+
+ if (is_null_intersection_function_table(metal_ancillaries->ift_default)) {
+ kernel_assert(!"Invalid ift_default");
+ return false;
+ }
+# endif
+
+ metal::raytracing::ray r(ray->P, ray->D, 0.0f, ray->t);
+ metalrt_intersector_type metalrt_intersect;
+
+ metalrt_intersect.force_opacity(metal::raytracing::forced_opacity::non_opaque);
+ if (!kernel_data.bvh.have_curves) {
+ metalrt_intersect.assume_geometry_type(metal::raytracing::geometry_type::triangle);
+ }
+
+ MetalRTIntersectionPayload payload;
+ payload.visibility = visibility;
+
+ typename metalrt_intersector_type::result_type intersection;
+
+ uint ray_mask = visibility & 0xFF;
+ if (0 == ray_mask && (visibility & ~0xFF) != 0) {
+ ray_mask = 0xFF;
+ }
+
+# if defined(__METALRT_MOTION__)
+ payload.time = ray->time;
+ intersection = metalrt_intersect.intersect(r,
+ metal_ancillaries->accel_struct,
+ ray_mask,
+ ray->time,
+ metal_ancillaries->ift_default,
+ payload);
+# else
+ intersection = metalrt_intersect.intersect(
+ r, metal_ancillaries->accel_struct, ray_mask, metal_ancillaries->ift_default, payload);
+# endif
+
+ if (intersection.type == intersection_type::none) {
+ return false;
+ }
+
+ isect->prim = payload.prim;
+ isect->type = payload.type;
+ isect->object = intersection.user_instance_id;
+
+ isect->t = intersection.distance;
+ if (intersection.type == intersection_type::triangle) {
+ isect->u = 1.0f - intersection.triangle_barycentric_coord.y -
+ intersection.triangle_barycentric_coord.x;
+ isect->v = intersection.triangle_barycentric_coord.x;
+ }
+ else {
+ isect->u = payload.u;
+ isect->v = payload.v;
+ }
+
+ return isect->type != PRIMITIVE_NONE;
+
+# else
if (!scene_intersect_valid(ray)) {
return false;
}
diff --git a/intern/cycles/kernel/bvh/metal.h b/intern/cycles/kernel/bvh/metal.h
new file mode 100644
index 00000000000..55456d15f50
--- /dev/null
+++ b/intern/cycles/kernel/bvh/metal.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+struct MetalRTIntersectionPayload {
+ uint visibility;
+ float u, v;
+ int prim;
+ int type;
+#if defined(__METALRT_MOTION__)
+ float time;
+#endif
+};
+
+struct MetalRTIntersectionLocalPayload {
+ uint local_object;
+ uint lcg_state;
+ short max_hits;
+ bool has_lcg_state;
+ bool result;
+ LocalIntersection local_isect;
+};
+
+struct MetalRTIntersectionShadowPayload {
+ uint visibility;
+#if defined(__METALRT_MOTION__)
+ float time;
+#endif
+ int state;
+ float throughput;
+ short max_hits;
+ short num_hits;
+ short num_recorded_hits;
+ bool result;
+};
diff --git a/intern/cycles/kernel/bvh/shadow_all.h b/intern/cycles/kernel/bvh/shadow_all.h
index 049c6a03fe0..caca85aac1a 100644
--- a/intern/cycles/kernel/bvh/shadow_all.h
+++ b/intern/cycles/kernel/bvh/shadow_all.h
@@ -28,6 +28,7 @@
* without new features slowing things down.
*
* BVH_HAIR: hair curve rendering
+ * BVH_POINTCLOUD: point cloud rendering
* BVH_MOTION: motion blur rendering
*/
@@ -199,6 +200,34 @@ ccl_device_inline
break;
}
#endif
+#if BVH_FEATURE(BVH_POINTCLOUD)
+ case PRIMITIVE_POINT:
+ case PRIMITIVE_MOTION_POINT: {
+ if ((type & PRIMITIVE_ALL_MOTION) && kernel_data.bvh.use_bvh_steps) {
+ const float2 prim_time = kernel_tex_fetch(__prim_time, prim_addr);
+ if (ray->time < prim_time.x || ray->time > prim_time.y) {
+ hit = false;
+ break;
+ }
+ }
+
+ const int point_object = (object == OBJECT_NONE) ?
+ kernel_tex_fetch(__prim_object, prim_addr) :
+ object;
+ const int point_prim = kernel_tex_fetch(__prim_index, prim_addr);
+ const int point_type = kernel_tex_fetch(__prim_type, prim_addr);
+ hit = point_intersect(kg,
+ &isect,
+ P,
+ dir,
+ t_max_current,
+ point_object,
+ point_prim,
+ ray->time,
+ point_type);
+ break;
+ }
+#endif /* BVH_FEATURE(BVH_POINTCLOUD) */
default: {
hit = false;
break;
diff --git a/intern/cycles/kernel/bvh/traversal.h b/intern/cycles/kernel/bvh/traversal.h
index 1c17ebf767f..180f19d11c5 100644
--- a/intern/cycles/kernel/bvh/traversal.h
+++ b/intern/cycles/kernel/bvh/traversal.h
@@ -28,6 +28,7 @@
* without new features slowing things down.
*
* BVH_HAIR: hair curve rendering
+ * BVH_POINTCLOUD: point cloud rendering
* BVH_MOTION: motion blur rendering
*/
@@ -188,6 +189,33 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals kg,
break;
}
#endif /* BVH_FEATURE(BVH_HAIR) */
+#if BVH_FEATURE(BVH_POINTCLOUD)
+ case PRIMITIVE_POINT:
+ case PRIMITIVE_MOTION_POINT: {
+ for (; prim_addr < prim_addr2; prim_addr++) {
+ if ((type & PRIMITIVE_ALL_MOTION) && kernel_data.bvh.use_bvh_steps) {
+ const float2 prim_time = kernel_tex_fetch(__prim_time, prim_addr);
+ if (ray->time < prim_time.x || ray->time > prim_time.y) {
+ continue;
+ }
+ }
+
+ const int point_object = (object == OBJECT_NONE) ?
+ kernel_tex_fetch(__prim_object, prim_addr) :
+ object;
+ const int point_prim = kernel_tex_fetch(__prim_index, prim_addr);
+ const int point_type = kernel_tex_fetch(__prim_type, prim_addr);
+ const bool hit = point_intersect(
+ kg, isect, P, dir, isect->t, point_object, point_prim, ray->time, point_type);
+ if (hit) {
+ /* shadow ray early termination */
+ if (visibility & PATH_RAY_SHADOW_OPAQUE)
+ return true;
+ }
+ }
+ break;
+ }
+#endif /* BVH_FEATURE(BVH_POINTCLOUD) */
}
}
else {
diff --git a/intern/cycles/kernel/bvh/types.h b/intern/cycles/kernel/bvh/types.h
index 6039e707fc3..f16f43333f8 100644
--- a/intern/cycles/kernel/bvh/types.h
+++ b/intern/cycles/kernel/bvh/types.h
@@ -34,6 +34,7 @@ CCL_NAMESPACE_BEGIN
#define BVH_MOTION 1
#define BVH_HAIR 2
+#define BVH_POINTCLOUD 4
#define BVH_NAME_JOIN(x, y) x##_##y
#define BVH_NAME_EVAL(x, y) BVH_NAME_JOIN(x, y)
diff --git a/intern/cycles/kernel/bvh/util.h b/intern/cycles/kernel/bvh/util.h
index 26ba136dd79..57593e42a88 100644
--- a/intern/cycles/kernel/bvh/util.h
+++ b/intern/cycles/kernel/bvh/util.h
@@ -118,14 +118,16 @@ ccl_device_forceinline int intersection_get_shader_flags(KernelGlobals kg,
{
int shader = 0;
-#ifdef __HAIR__
- if (type & PRIMITIVE_ALL_TRIANGLE)
-#endif
- {
+ if (type & PRIMITIVE_ALL_TRIANGLE) {
shader = kernel_tex_fetch(__tri_shader, prim);
}
+#ifdef __POINTCLOUD__
+ else if (type & PRIMITIVE_ALL_POINT) {
+ shader = kernel_tex_fetch(__points_shader, prim);
+ }
+#endif
#ifdef __HAIR__
- else {
+ else if (type & PRIMITIVE_ALL_CURVE) {
shader = kernel_tex_fetch(__curves, prim).shader_id;
}
#endif
@@ -139,14 +141,16 @@ ccl_device_forceinline int intersection_get_shader_from_isect_prim(KernelGlobals
{
int shader = 0;
-#ifdef __HAIR__
- if (isect_type & PRIMITIVE_ALL_TRIANGLE)
-#endif
- {
+ if (isect_type & PRIMITIVE_ALL_TRIANGLE) {
shader = kernel_tex_fetch(__tri_shader, prim);
}
+#ifdef __POINTCLOUD__
+ else if (isect_type & PRIMITIVE_ALL_POINT) {
+ shader = kernel_tex_fetch(__points_shader, prim);
+ }
+#endif
#ifdef __HAIR__
- else {
+ else if (isect_type & PRIMITIVE_ALL_CURVE) {
shader = kernel_tex_fetch(__curves, prim).shader_id;
}
#endif
diff --git a/intern/cycles/kernel/camera/projection.h b/intern/cycles/kernel/camera/projection.h
index 0aea82fa812..7b4e23e4ed0 100644
--- a/intern/cycles/kernel/camera/projection.h
+++ b/intern/cycles/kernel/camera/projection.h
@@ -146,6 +146,49 @@ fisheye_equisolid_to_direction(float u, float v, float lens, float fov, float wi
return make_float3(cosf(theta), -cosf(phi) * sinf(theta), sinf(phi) * sinf(theta));
}
+ccl_device_inline float3 fisheye_lens_polynomial_to_direction(
+ float u, float v, float coeff0, float4 coeffs, float fov, float width, float height)
+{
+ u = (u - 0.5f) * width;
+ v = (v - 0.5f) * height;
+
+ float r = sqrtf(u * u + v * v);
+ float r2 = r * r;
+ float4 rr = make_float4(r, r2, r2 * r, r2 * r2);
+ float theta = -(coeff0 + dot(coeffs, rr));
+
+ if (fabsf(theta) > 0.5f * fov)
+ return zero_float3();
+
+ float phi = safe_acosf((r != 0.0f) ? u / r : 0.0f);
+
+ if (v < 0.0f)
+ phi = -phi;
+
+ return make_float3(cosf(theta), -cosf(phi) * sinf(theta), sinf(phi) * sinf(theta));
+}
+
+ccl_device float2 direction_to_fisheye_lens_polynomial(
+ float3 dir, float coeff0, float4 coeffs, float width, float height)
+{
+ float theta = -safe_acosf(dir.x);
+
+ float r = (theta - coeff0) / coeffs.x;
+
+ for (int i = 0; i < 20; i++) {
+ float r2 = r * r;
+ float4 rr = make_float4(r, r2, r2 * r, r2 * r2);
+ r = (theta - (coeff0 + dot(coeffs, rr))) / coeffs.x;
+ }
+
+ float phi = atan2f(dir.z, dir.y);
+
+ float u = r * cosf(phi) / width + 0.5f;
+ float v = r * sinf(phi) / height + 0.5f;
+
+ return make_float2(u, v);
+}
+
/* Mirror Ball <-> Cartesion direction */
ccl_device float3 mirrorball_to_direction(float u, float v)
@@ -191,6 +234,14 @@ ccl_device_inline float3 panorama_to_direction(ccl_constant KernelCamera *cam, f
return mirrorball_to_direction(u, v);
case PANORAMA_FISHEYE_EQUIDISTANT:
return fisheye_to_direction(u, v, cam->fisheye_fov);
+ case PANORAMA_FISHEYE_LENS_POLYNOMIAL:
+ return fisheye_lens_polynomial_to_direction(u,
+ v,
+ cam->fisheye_lens_polynomial_bias,
+ cam->fisheye_lens_polynomial_coefficients,
+ cam->fisheye_fov,
+ cam->sensorwidth,
+ cam->sensorheight);
case PANORAMA_FISHEYE_EQUISOLID:
default:
return fisheye_equisolid_to_direction(
@@ -207,6 +258,12 @@ ccl_device_inline float2 direction_to_panorama(ccl_constant KernelCamera *cam, f
return direction_to_mirrorball(dir);
case PANORAMA_FISHEYE_EQUIDISTANT:
return direction_to_fisheye(dir, cam->fisheye_fov);
+ case PANORAMA_FISHEYE_LENS_POLYNOMIAL:
+ return direction_to_fisheye_lens_polynomial(dir,
+ cam->fisheye_lens_polynomial_bias,
+ cam->fisheye_lens_polynomial_coefficients,
+ cam->sensorwidth,
+ cam->sensorheight);
case PANORAMA_FISHEYE_EQUISOLID:
default:
return direction_to_fisheye_equisolid(
diff --git a/intern/cycles/kernel/closure/bsdf.h b/intern/cycles/kernel/closure/bsdf.h
index 28c889f2841..f0ce45d1c2c 100644
--- a/intern/cycles/kernel/closure/bsdf.h
+++ b/intern/cycles/kernel/closure/bsdf.h
@@ -438,7 +438,7 @@ ccl_device_inline int bsdf_sample(KernelGlobals kg,
if (label & LABEL_TRANSMIT) {
float threshold_squared = kernel_data.background.transparent_roughness_squared_threshold;
- if (threshold_squared >= 0.0f) {
+ if (threshold_squared >= 0.0f && !(label & LABEL_DIFFUSE)) {
if (bsdf_get_specular_roughness_squared(sc) <= threshold_squared) {
label |= LABEL_TRANSMIT_TRANSPARENT;
}
diff --git a/intern/cycles/kernel/device/gpu/kernel.h b/intern/cycles/kernel/device/gpu/kernel.h
index 22e2a61a06d..b50f492e8c7 100644
--- a/intern/cycles/kernel/device/gpu/kernel.h
+++ b/intern/cycles/kernel/device/gpu/kernel.h
@@ -19,7 +19,8 @@
#include "kernel/device/gpu/parallel_active_index.h"
#include "kernel/device/gpu/parallel_prefix_sum.h"
#include "kernel/device/gpu/parallel_sorted_index.h"
-#include "kernel/device/gpu/work_stealing.h"
+
+#include "kernel/sample/lcg.h"
/* Include constant tables before entering Metal's context class scope (context_begin.h) */
#include "kernel/tables.h"
@@ -28,6 +29,8 @@
# include "kernel/device/metal/context_begin.h"
#endif
+#include "kernel/device/gpu/work_stealing.h"
+
#include "kernel/integrator/state.h"
#include "kernel/integrator/state_flow.h"
#include "kernel/integrator/state_util.h"
@@ -94,7 +97,7 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
const int state = tile->path_index_offset + tile_work_index;
uint x, y, sample;
- get_work_pixel(tile, tile_work_index, &x, &y, &sample);
+ ccl_gpu_kernel_call(get_work_pixel(tile, tile_work_index, &x, &y, &sample));
ccl_gpu_kernel_call(
integrator_init_from_camera(nullptr, state, tile, render_buffer, x, y, sample));
@@ -125,7 +128,7 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
const int state = tile->path_index_offset + tile_work_index;
uint x, y, sample;
- get_work_pixel(tile, tile_work_index, &x, &y, &sample);
+ ccl_gpu_kernel_call(get_work_pixel(tile, tile_work_index, &x, &y, &sample));
ccl_gpu_kernel_call(
integrator_init_from_bake(nullptr, state, tile, render_buffer, x, y, sample));
@@ -547,6 +550,33 @@ ccl_device_inline void kernel_gpu_film_convert_half_write(ccl_global uchar4 *rgb
#endif
}
+#ifdef __KERNEL_METAL__
+
+/* Fetch into a local variable on Metal - there is minimal overhead. Templating the
+ * film_get_pass_pixel_... functions works on MSL, but not on other compilers. */
+# define FILM_GET_PASS_PIXEL_F32(variant, input_channel_count) \
+ float local_pixel[4]; \
+ film_get_pass_pixel_##variant(&kfilm_convert, buffer, local_pixel); \
+ if (input_channel_count >= 1) { \
+ pixel[0] = local_pixel[0]; \
+ } \
+ if (input_channel_count >= 2) { \
+ pixel[1] = local_pixel[1]; \
+ } \
+ if (input_channel_count >= 3) { \
+ pixel[2] = local_pixel[2]; \
+ } \
+ if (input_channel_count >= 4) { \
+ pixel[3] = local_pixel[3]; \
+ }
+
+#else
+
+# define FILM_GET_PASS_PIXEL_F32(variant, input_channel_count) \
+ film_get_pass_pixel_##variant(&kfilm_convert, buffer, pixel);
+
+#endif
+
#define KERNEL_FILM_CONVERT_VARIANT(variant, input_channel_count) \
ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) \
ccl_gpu_kernel_signature(film_convert_##variant, \
@@ -574,7 +604,7 @@ ccl_device_inline void kernel_gpu_film_convert_half_write(ccl_global uchar4 *rgb
ccl_global float *pixel = pixels + \
(render_pixel_index + rgba_offset) * kfilm_convert.pixel_stride; \
\
- film_get_pass_pixel_##variant(&kfilm_convert, buffer, pixel); \
+ FILM_GET_PASS_PIXEL_F32(variant, input_channel_count); \
} \
\
ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) \
diff --git a/intern/cycles/kernel/device/gpu/work_stealing.h b/intern/cycles/kernel/device/gpu/work_stealing.h
index fab0915c38e..c3083948057 100644
--- a/intern/cycles/kernel/device/gpu/work_stealing.h
+++ b/intern/cycles/kernel/device/gpu/work_stealing.h
@@ -29,17 +29,20 @@ ccl_device_inline void get_work_pixel(ccl_global const KernelWorkTile *tile,
ccl_private uint *y,
ccl_private uint *sample)
{
-#if 0
- /* Keep threads for the same sample together. */
- uint tile_pixels = tile->w * tile->h;
- uint sample_offset = global_work_index / tile_pixels;
- uint pixel_offset = global_work_index - sample_offset * tile_pixels;
-#else
- /* Keeping threads for the same pixel together.
- * Appears to improve performance by a few % on CUDA and OptiX. */
- uint sample_offset = global_work_index % tile->num_samples;
- uint pixel_offset = global_work_index / tile->num_samples;
-#endif
+ uint sample_offset, pixel_offset;
+
+ if (kernel_data.integrator.scrambling_distance < 0.9f) {
+ /* Keep threads for the same sample together. */
+ uint tile_pixels = tile->w * tile->h;
+ sample_offset = global_work_index / tile_pixels;
+ pixel_offset = global_work_index - sample_offset * tile_pixels;
+ }
+ else {
+ /* Keeping threads for the same pixel together.
+ * Appears to improve performance by a few % on CUDA and OptiX. */
+ sample_offset = global_work_index % tile->num_samples;
+ pixel_offset = global_work_index / tile->num_samples;
+ }
uint y_offset = pixel_offset / tile->w;
uint x_offset = pixel_offset - y_offset * tile->w;
diff --git a/intern/cycles/kernel/device/metal/compat.h b/intern/cycles/kernel/device/metal/compat.h
index 61597a4acfc..a51afc37fc0 100644
--- a/intern/cycles/kernel/device/metal/compat.h
+++ b/intern/cycles/kernel/device/metal/compat.h
@@ -32,6 +32,10 @@
using namespace metal;
+#ifdef __METALRT__
+using namespace metal::raytracing;
+#endif
+
#pragma clang diagnostic ignored "-Wunused-variable"
#pragma clang diagnostic ignored "-Wsign-compare"
#pragma clang diagnostic ignored "-Wuninitialized"
@@ -47,7 +51,7 @@ using namespace metal;
#define ccl_global device
#define ccl_inline_constant static constant constexpr
#define ccl_device_constant constant
-#define ccl_constant const device
+#define ccl_constant constant
#define ccl_gpu_shared threadgroup
#define ccl_private thread
#define ccl_may_alias
@@ -113,7 +117,7 @@ struct kernel_gpu_##name \
uint simd_group_index, \
uint num_simd_groups) ccl_global const; \
}; \
-kernel void kernel_metal_##name(device const kernel_gpu_##name *params_struct, \
+kernel void cycles_metal_##name(device const kernel_gpu_##name *params_struct, \
constant KernelParamsMetal &ccl_restrict _launch_params_metal, \
constant MetalAncillaries *_metal_ancillaries, \
threadgroup int *simdgroup_offset[[ threadgroup(0) ]], \
@@ -246,6 +250,22 @@ void kernel_gpu_##name::run(thread MetalKernelContext& context, \
#define __device__
+#ifdef __METALRT__
+
+# define __KERNEL_GPU_RAYTRACING__
+
+# if defined(__METALRT_MOTION__)
+# define METALRT_TAGS instancing, instance_motion, primitive_motion
+# else
+# define METALRT_TAGS instancing
+# endif /* __METALRT_MOTION__ */
+
+typedef acceleration_structure<METALRT_TAGS> metalrt_as_type;
+typedef intersection_function_table<triangle_data, METALRT_TAGS> metalrt_ift_type;
+typedef metal::raytracing::intersector<triangle_data, METALRT_TAGS> metalrt_intersector_type;
+
+#endif /* __METALRT__ */
+
/* texture bindings and sampler setup */
struct Texture2DParamsMetal {
@@ -258,6 +278,13 @@ struct Texture3DParamsMetal {
struct MetalAncillaries {
device Texture2DParamsMetal *textures_2d;
device Texture3DParamsMetal *textures_3d;
+
+#ifdef __METALRT__
+ metalrt_as_type accel_struct;
+ metalrt_ift_type ift_default;
+ metalrt_ift_type ift_shadow;
+ metalrt_ift_type ift_local;
+#endif
};
#include "util/half.h"
diff --git a/intern/cycles/kernel/device/metal/context_begin.h b/intern/cycles/kernel/device/metal/context_begin.h
index 8c9e1c54077..2eefd795aa1 100644
--- a/intern/cycles/kernel/device/metal/context_begin.h
+++ b/intern/cycles/kernel/device/metal/context_begin.h
@@ -27,6 +27,10 @@ class MetalKernelContext {
: launch_params_metal(_launch_params_metal), metal_ancillaries(_metal_ancillaries)
{}
+ MetalKernelContext(constant KernelParamsMetal &_launch_params_metal)
+ : launch_params_metal(_launch_params_metal)
+ {}
+
/* texture fetch adapter functions */
typedef uint64_t ccl_gpu_tex_object;
diff --git a/intern/cycles/kernel/device/metal/kernel.metal b/intern/cycles/kernel/device/metal/kernel.metal
index feca20ff475..27dc1f44c6f 100644
--- a/intern/cycles/kernel/device/metal/kernel.metal
+++ b/intern/cycles/kernel/device/metal/kernel.metal
@@ -16,10 +16,566 @@
/* Metal kernel entry points */
-// clang-format off
-
#include "kernel/device/metal/compat.h"
#include "kernel/device/metal/globals.h"
#include "kernel/device/gpu/kernel.h"
-// clang-format on \ No newline at end of file
+/* MetalRT intersection handlers */
+#ifdef __METALRT__
+
+/* Return type for a bounding box intersection function. */
+struct BoundingBoxIntersectionResult
+{
+ bool accept [[accept_intersection]];
+ bool continue_search [[continue_search]];
+ float distance [[distance]];
+};
+
+/* Return type for a triangle intersection function. */
+struct TriangleIntersectionResult
+{
+ bool accept [[accept_intersection]];
+ bool continue_search [[continue_search]];
+};
+
+enum { METALRT_HIT_TRIANGLE, METALRT_HIT_BOUNDING_BOX };
+
+template<typename TReturn, uint intersection_type>
+TReturn metalrt_local_hit(constant KernelParamsMetal &launch_params_metal,
+ ray_data MetalKernelContext::MetalRTIntersectionLocalPayload &payload,
+ const uint object,
+ const uint primitive_id,
+ const float2 barycentrics,
+ const float ray_tmax)
+{
+ TReturn result;
+
+#ifdef __BVH_LOCAL__
+ uint prim = primitive_id + kernel_tex_fetch(__object_prim_offset, object);
+
+ if (object != payload.local_object) {
+ /* Only intersect with matching object */
+ result.accept = false;
+ result.continue_search = true;
+ return result;
+ }
+
+ const short max_hits = payload.max_hits;
+ if (max_hits == 0) {
+ /* Special case for when no hit information is requested, just report that something was hit */
+ payload.result = true;
+ result.accept = true;
+ result.continue_search = false;
+ return result;
+ }
+
+ int hit = 0;
+ if (payload.has_lcg_state) {
+ for (short i = min(max_hits, short(payload.local_isect.num_hits)) - 1; i >= 0; --i) {
+ if (ray_tmax == payload.local_isect.hits[i].t) {
+ result.accept = false;
+ result.continue_search = true;
+ return result;
+ }
+ }
+
+ hit = payload.local_isect.num_hits++;
+
+ if (payload.local_isect.num_hits > max_hits) {
+ hit = lcg_step_uint(&payload.lcg_state) % payload.local_isect.num_hits;
+ if (hit >= max_hits) {
+ result.accept = false;
+ result.continue_search = true;
+ return result;
+ }
+ }
+ }
+ else {
+ if (payload.local_isect.num_hits && ray_tmax > payload.local_isect.hits[0].t) {
+ /* Record closest intersection only. Do not terminate ray here, since there is no guarantee about distance ordering in any-hit */
+ result.accept = false;
+ result.continue_search = true;
+ return result;
+ }
+
+ payload.local_isect.num_hits = 1;
+ }
+
+ ray_data Intersection *isect = &payload.local_isect.hits[hit];
+ isect->t = ray_tmax;
+ isect->prim = prim;
+ isect->object = object;
+ isect->type = kernel_tex_fetch(__objects, object).primitive_type;
+
+ isect->u = 1.0f - barycentrics.y - barycentrics.x;
+ isect->v = barycentrics.x;
+
+ /* Record geometric normal */
+ const uint tri_vindex = kernel_tex_fetch(__tri_vindex, isect->prim).w;
+ const float3 tri_a = float3(kernel_tex_fetch(__tri_verts, tri_vindex + 0));
+ const float3 tri_b = float3(kernel_tex_fetch(__tri_verts, tri_vindex + 1));
+ const float3 tri_c = float3(kernel_tex_fetch(__tri_verts, tri_vindex + 2));
+ payload.local_isect.Ng[hit] = normalize(cross(tri_b - tri_a, tri_c - tri_a));
+
+ /* Continue tracing (without this the trace call would return after the first hit) */
+ result.accept = false;
+ result.continue_search = true;
+ return result;
+#endif
+}
+
+[[intersection(triangle, triangle_data, METALRT_TAGS)]]
+TriangleIntersectionResult
+__anyhit__cycles_metalrt_local_hit_tri(constant KernelParamsMetal &launch_params_metal [[buffer(1)]],
+ ray_data MetalKernelContext::MetalRTIntersectionLocalPayload &payload [[payload]],
+ uint instance_id [[user_instance_id]],
+ uint primitive_id [[primitive_id]],
+ float2 barycentrics [[barycentric_coord]],
+ float ray_tmax [[distance]])
+{
+ return metalrt_local_hit<TriangleIntersectionResult, METALRT_HIT_TRIANGLE>(
+ launch_params_metal, payload, instance_id, primitive_id, barycentrics, ray_tmax);
+}
+
+[[intersection(bounding_box, triangle_data, METALRT_TAGS)]]
+BoundingBoxIntersectionResult
+__anyhit__cycles_metalrt_local_hit_box(const float ray_tmax [[max_distance]])
+{
+ /* unused function */
+ BoundingBoxIntersectionResult result;
+ result.distance = ray_tmax;
+ result.accept = false;
+ result.continue_search = false;
+ return result;
+}
+
+template<uint intersection_type>
+bool metalrt_shadow_all_hit(constant KernelParamsMetal &launch_params_metal,
+ ray_data MetalKernelContext::MetalRTIntersectionShadowPayload &payload,
+ uint object,
+ uint prim,
+ const float2 barycentrics,
+ const float ray_tmax)
+{
+#ifdef __SHADOW_RECORD_ALL__
+# ifdef __VISIBILITY_FLAG__
+ const uint visibility = payload.visibility;
+ if ((kernel_tex_fetch(__objects, object).visibility & visibility) == 0) {
+ /* continue search */
+ return true;
+ }
+# endif
+
+ float u = 0.0f, v = 0.0f;
+ int type = 0;
+ if (intersection_type == METALRT_HIT_TRIANGLE) {
+ u = 1.0f - barycentrics.y - barycentrics.x;
+ v = barycentrics.x;
+ type = kernel_tex_fetch(__objects, object).primitive_type;
+ }
+# ifdef __HAIR__
+ else {
+ u = barycentrics.x;
+ v = barycentrics.y;
+
+ const KernelCurveSegment segment = kernel_tex_fetch(__curve_segments, prim);
+ type = segment.type;
+ prim = segment.prim;
+
+ /* Filter out curve endcaps */
+ if (u == 0.0f || u == 1.0f) {
+ /* continue search */
+ return true;
+ }
+ }
+# endif
+
+# ifndef __TRANSPARENT_SHADOWS__
+ /* No transparent shadows support compiled in, make opaque. */
+ payload.result = true;
+ /* terminate ray */
+ return false;
+# else
+ short max_hits = payload.max_hits;
+ short num_hits = payload.num_hits;
+ short num_recorded_hits = payload.num_recorded_hits;
+
+ MetalKernelContext context(launch_params_metal);
+
+ /* If no transparent shadows, all light is blocked and we can stop immediately. */
+ if (num_hits >= max_hits ||
+ !(context.intersection_get_shader_flags(NULL, prim, type) & SD_HAS_TRANSPARENT_SHADOW)) {
+ payload.result = true;
+ /* terminate ray */
+ return false;
+ }
+
+ /* Always use baked shadow transparency for curves. */
+ if (type & PRIMITIVE_ALL_CURVE) {
+ float throughput = payload.throughput;
+ throughput *= context.intersection_curve_shadow_transparency(nullptr, object, prim, u);
+ payload.throughput = throughput;
+ payload.num_hits += 1;
+
+ if (throughput < CURVE_SHADOW_TRANSPARENCY_CUTOFF) {
+ /* Accept result and terminate if throughput is sufficiently low */
+ payload.result = true;
+ return false;
+ }
+ else {
+ return true;
+ }
+ }
+
+ payload.num_hits += 1;
+ payload.num_recorded_hits += 1;
+
+ uint record_index = num_recorded_hits;
+
+ const IntegratorShadowState state = payload.state;
+
+ const uint max_record_hits = min(uint(max_hits), INTEGRATOR_SHADOW_ISECT_SIZE);
+ if (record_index >= max_record_hits) {
+ /* If maximum number of hits reached, find a hit to replace. */
+ float max_recorded_t = INTEGRATOR_STATE_ARRAY(state, shadow_isect, 0, t);
+ uint max_recorded_hit = 0;
+
+ for (int i = 1; i < max_record_hits; i++) {
+ const float isect_t = INTEGRATOR_STATE_ARRAY(state, shadow_isect, i, t);
+ if (isect_t > max_recorded_t) {
+ max_recorded_t = isect_t;
+ max_recorded_hit = i;
+ }
+ }
+
+ if (ray_tmax >= max_recorded_t) {
+ /* Accept hit, so that we don't consider any more hits beyond the distance of the
+ * current hit anymore. */
+ payload.result = true;
+ return true;
+ }
+
+ record_index = max_recorded_hit;
+ }
+
+ INTEGRATOR_STATE_ARRAY_WRITE(state, shadow_isect, record_index, u) = u;
+ INTEGRATOR_STATE_ARRAY_WRITE(state, shadow_isect, record_index, v) = v;
+ INTEGRATOR_STATE_ARRAY_WRITE(state, shadow_isect, record_index, t) = ray_tmax;
+ INTEGRATOR_STATE_ARRAY_WRITE(state, shadow_isect, record_index, prim) = prim;
+ INTEGRATOR_STATE_ARRAY_WRITE(state, shadow_isect, record_index, object) = object;
+ INTEGRATOR_STATE_ARRAY_WRITE(state, shadow_isect, record_index, type) = type;
+
+ /* Continue tracing. */
+# endif /* __TRANSPARENT_SHADOWS__ */
+#endif /* __SHADOW_RECORD_ALL__ */
+
+ return true;
+}
+
+[[intersection(triangle, triangle_data, METALRT_TAGS)]]
+TriangleIntersectionResult
+__anyhit__cycles_metalrt_shadow_all_hit_tri(constant KernelParamsMetal &launch_params_metal [[buffer(1)]],
+ ray_data MetalKernelContext::MetalRTIntersectionShadowPayload &payload [[payload]],
+ unsigned int object [[user_instance_id]],
+ unsigned int primitive_id [[primitive_id]],
+ float2 barycentrics [[barycentric_coord]],
+ float ray_tmax [[distance]])
+{
+ uint prim = primitive_id + kernel_tex_fetch(__object_prim_offset, object);
+
+ TriangleIntersectionResult result;
+ result.continue_search = metalrt_shadow_all_hit<METALRT_HIT_TRIANGLE>(
+ launch_params_metal, payload, object, prim, barycentrics, ray_tmax);
+ result.accept = !result.continue_search;
+ return result;
+}
+
+[[intersection(bounding_box, triangle_data, METALRT_TAGS)]]
+BoundingBoxIntersectionResult
+__anyhit__cycles_metalrt_shadow_all_hit_box(const float ray_tmax [[max_distance]])
+{
+ /* unused function */
+ BoundingBoxIntersectionResult result;
+ result.distance = ray_tmax;
+ result.accept = false;
+ result.continue_search = false;
+ return result;
+}
+
+template<typename TReturnType, uint intersection_type>
+inline TReturnType metalrt_visibility_test(constant KernelParamsMetal &launch_params_metal,
+ ray_data MetalKernelContext::MetalRTIntersectionPayload &payload,
+ const uint object,
+ const uint prim,
+ const float u)
+{
+ TReturnType result;
+
+# ifdef __HAIR__
+ if (intersection_type == METALRT_HIT_BOUNDING_BOX) {
+ /* Filter out curve endcaps. */
+ if (u == 0.0f || u == 1.0f) {
+ result.accept = false;
+ result.continue_search = true;
+ return result;
+ }
+ }
+# endif
+
+# ifdef __VISIBILITY_FLAG__
+ uint visibility = payload.visibility;
+ if ((kernel_tex_fetch(__objects, object).visibility & visibility) == 0) {
+ result.accept = false;
+ result.continue_search = true;
+ return result;
+ }
+
+ /* Shadow ray early termination. */
+ if (visibility & PATH_RAY_SHADOW_OPAQUE) {
+ result.accept = true;
+ result.continue_search = false;
+ return result;
+ }
+# endif
+
+ result.accept = true;
+ result.continue_search = true;
+ return result;
+}
+
+[[intersection(triangle, triangle_data, METALRT_TAGS)]]
+TriangleIntersectionResult
+__anyhit__cycles_metalrt_visibility_test_tri(constant KernelParamsMetal &launch_params_metal [[buffer(1)]],
+ ray_data MetalKernelContext::MetalRTIntersectionPayload &payload [[payload]],
+ unsigned int object [[user_instance_id]],
+ unsigned int primitive_id [[primitive_id]])
+{
+ uint prim = primitive_id + kernel_tex_fetch(__object_prim_offset, object);
+ TriangleIntersectionResult result = metalrt_visibility_test<TriangleIntersectionResult, METALRT_HIT_TRIANGLE>(
+ launch_params_metal, payload, object, prim, 0.0f);
+ if (result.accept) {
+ payload.prim = prim;
+ payload.type = kernel_tex_fetch(__objects, object).primitive_type;
+ }
+ return result;
+}
+
+[[intersection(bounding_box, triangle_data, METALRT_TAGS)]]
+BoundingBoxIntersectionResult
+__anyhit__cycles_metalrt_visibility_test_box(const float ray_tmax [[max_distance]])
+{
+ /* Unused function */
+ BoundingBoxIntersectionResult result;
+ result.accept = false;
+ result.continue_search = true;
+ result.distance = ray_tmax;
+ return result;
+}
+
+#ifdef __HAIR__
+ccl_device_inline
+void metalrt_intersection_curve(constant KernelParamsMetal &launch_params_metal,
+ ray_data MetalKernelContext::MetalRTIntersectionPayload &payload,
+ const uint object,
+ const uint prim,
+ const uint type,
+ const float3 ray_origin,
+ const float3 ray_direction,
+ float time,
+ const float ray_tmax,
+ thread BoundingBoxIntersectionResult &result)
+{
+# ifdef __VISIBILITY_FLAG__
+ const uint visibility = payload.visibility;
+ if ((kernel_tex_fetch(__objects, object).visibility & visibility) == 0) {
+ return;
+ }
+# endif
+
+ float3 P = ray_origin;
+ float3 dir = ray_direction;
+
+ /* The direction is not normalized by default, but the curve intersection routine expects that */
+ float len;
+ dir = normalize_len(dir, &len);
+
+ Intersection isect;
+ isect.t = ray_tmax;
+ /* Transform maximum distance into object space. */
+ if (isect.t != FLT_MAX)
+ isect.t *= len;
+
+ MetalKernelContext context(launch_params_metal);
+ if (context.curve_intersect(NULL, &isect, P, dir, isect.t, object, prim, time, type)) {
+ result = metalrt_visibility_test<BoundingBoxIntersectionResult, METALRT_HIT_BOUNDING_BOX>(
+ launch_params_metal, payload, object, prim, isect.u);
+ if (result.accept) {
+ result.distance = isect.t / len;
+ payload.u = isect.u;
+ payload.v = isect.v;
+ payload.prim = prim;
+ payload.type = type;
+ }
+ }
+}
+
+ccl_device_inline
+void metalrt_intersection_curve_shadow(constant KernelParamsMetal &launch_params_metal,
+ ray_data MetalKernelContext::MetalRTIntersectionShadowPayload &payload,
+ const uint object,
+ const uint prim,
+ const uint type,
+ const float3 ray_origin,
+ const float3 ray_direction,
+ float time,
+ const float ray_tmax,
+ thread BoundingBoxIntersectionResult &result)
+{
+ const uint visibility = payload.visibility;
+
+ float3 P = ray_origin;
+ float3 dir = ray_direction;
+
+ /* The direction is not normalized by default, but the curve intersection routine expects that */
+ float len;
+ dir = normalize_len(dir, &len);
+
+ Intersection isect;
+ isect.t = ray_tmax;
+ /* Transform maximum distance into object space */
+ if (isect.t != FLT_MAX)
+ isect.t *= len;
+
+ MetalKernelContext context(launch_params_metal);
+ if (context.curve_intersect(NULL, &isect, P, dir, isect.t, object, prim, time, type)) {
+ result.continue_search = metalrt_shadow_all_hit<METALRT_HIT_BOUNDING_BOX>(
+ launch_params_metal, payload, object, prim, float2(isect.u, isect.v), ray_tmax);
+ result.accept = !result.continue_search;
+
+ if (result.accept) {
+ result.distance = isect.t / len;
+ }
+ }
+}
+
+[[intersection(bounding_box, triangle_data, METALRT_TAGS)]]
+BoundingBoxIntersectionResult
+__intersection__curve_ribbon(constant KernelParamsMetal &launch_params_metal [[buffer(1)]],
+ ray_data MetalKernelContext::MetalRTIntersectionPayload &payload [[payload]],
+ const uint object [[user_instance_id]],
+ const uint primitive_id [[primitive_id]],
+ const float3 ray_origin [[origin]],
+ const float3 ray_direction [[direction]],
+ const float ray_tmax [[max_distance]])
+{
+ uint prim = primitive_id + kernel_tex_fetch(__object_prim_offset, object);
+ const KernelCurveSegment segment = kernel_tex_fetch(__curve_segments, prim);
+
+ BoundingBoxIntersectionResult result;
+ result.accept = false;
+ result.continue_search = true;
+ result.distance = ray_tmax;
+
+ if (segment.type & (PRIMITIVE_CURVE_RIBBON | PRIMITIVE_MOTION_CURVE_RIBBON)) {
+ metalrt_intersection_curve(launch_params_metal, payload, object, segment.prim, segment.type, ray_origin, ray_direction,
+# if defined(__METALRT_MOTION__)
+ payload.time,
+# else
+ 0.0f,
+# endif
+ ray_tmax, result);
+ }
+
+ return result;
+}
+
+[[intersection(bounding_box, triangle_data, METALRT_TAGS)]]
+BoundingBoxIntersectionResult
+__intersection__curve_ribbon_shadow(constant KernelParamsMetal &launch_params_metal [[buffer(1)]],
+ ray_data MetalKernelContext::MetalRTIntersectionShadowPayload &payload [[payload]],
+ const uint object [[user_instance_id]],
+ const uint primitive_id [[primitive_id]],
+ const float3 ray_origin [[origin]],
+ const float3 ray_direction [[direction]],
+ const float ray_tmax [[max_distance]])
+{
+ uint prim = primitive_id + kernel_tex_fetch(__object_prim_offset, object);
+ const KernelCurveSegment segment = kernel_tex_fetch(__curve_segments, prim);
+
+ BoundingBoxIntersectionResult result;
+ result.accept = false;
+ result.continue_search = true;
+ result.distance = ray_tmax;
+
+ if (segment.type & (PRIMITIVE_CURVE_RIBBON | PRIMITIVE_MOTION_CURVE_RIBBON)) {
+ metalrt_intersection_curve_shadow(launch_params_metal, payload, object, segment.prim, segment.type, ray_origin, ray_direction,
+# if defined(__METALRT_MOTION__)
+ payload.time,
+# else
+ 0.0f,
+# endif
+ ray_tmax, result);
+ }
+
+ return result;
+}
+
+[[intersection(bounding_box, triangle_data, METALRT_TAGS)]]
+BoundingBoxIntersectionResult
+__intersection__curve_all(constant KernelParamsMetal &launch_params_metal [[buffer(1)]],
+ ray_data MetalKernelContext::MetalRTIntersectionPayload &payload [[payload]],
+ const uint object [[user_instance_id]],
+ const uint primitive_id [[primitive_id]],
+ const float3 ray_origin [[origin]],
+ const float3 ray_direction [[direction]],
+ const float ray_tmax [[max_distance]])
+{
+ uint prim = primitive_id + kernel_tex_fetch(__object_prim_offset, object);
+ const KernelCurveSegment segment = kernel_tex_fetch(__curve_segments, prim);
+
+ BoundingBoxIntersectionResult result;
+ result.accept = false;
+ result.continue_search = true;
+ result.distance = ray_tmax;
+ metalrt_intersection_curve(launch_params_metal, payload, object, segment.prim, segment.type, ray_origin, ray_direction,
+# if defined(__METALRT_MOTION__)
+ payload.time,
+# else
+ 0.0f,
+# endif
+ ray_tmax, result);
+
+ return result;
+}
+
+[[intersection(bounding_box, triangle_data, METALRT_TAGS)]]
+BoundingBoxIntersectionResult
+__intersection__curve_all_shadow(constant KernelParamsMetal &launch_params_metal [[buffer(1)]],
+ ray_data MetalKernelContext::MetalRTIntersectionShadowPayload &payload [[payload]],
+ const uint object [[user_instance_id]],
+ const uint primitive_id [[primitive_id]],
+ const float3 ray_origin [[origin]],
+ const float3 ray_direction [[direction]],
+ const float ray_tmax [[max_distance]])
+{
+ uint prim = primitive_id + kernel_tex_fetch(__object_prim_offset, object);
+ const KernelCurveSegment segment = kernel_tex_fetch(__curve_segments, prim);
+
+ BoundingBoxIntersectionResult result;
+ result.accept = false;
+ result.continue_search = true;
+ result.distance = ray_tmax;
+
+ metalrt_intersection_curve_shadow(launch_params_metal, payload, object, segment.prim, segment.type, ray_origin, ray_direction,
+# if defined(__METALRT_MOTION__)
+ payload.time,
+# else
+ 0.0f,
+# endif
+ ray_tmax, result);
+
+ return result;
+}
+
+#endif /* __HAIR__ */
+#endif /* __METALRT__ */
diff --git a/intern/cycles/kernel/device/optix/compat.h b/intern/cycles/kernel/device/optix/compat.h
index 0619c135c39..db4233624b9 100644
--- a/intern/cycles/kernel/device/optix/compat.h
+++ b/intern/cycles/kernel/device/optix/compat.h
@@ -21,6 +21,7 @@
#include <optix.h>
#define __KERNEL_GPU__
+#define __KERNEL_GPU_RAYTRACING__
#define __KERNEL_CUDA__ /* OptiX kernels are implicitly CUDA kernels too */
#define __KERNEL_OPTIX__
#define CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/kernel/device/optix/kernel.cu b/intern/cycles/kernel/device/optix/kernel.cu
index 4feed59d018..c639dc87f35 100644
--- a/intern/cycles/kernel/device/optix/kernel.cu
+++ b/intern/cycles/kernel/device/optix/kernel.cu
@@ -31,9 +31,11 @@
#include "kernel/integrator/intersect_shadow.h"
#include "kernel/integrator/intersect_subsurface.h"
#include "kernel/integrator/intersect_volume_stack.h"
-
// clang-format on
+#define OPTIX_DEFINE_ABI_VERSION_ONLY
+#include <optix_function_table.h>
+
template<typename T> ccl_device_forceinline T *get_payload_ptr_0()
{
return pointer_unpack_from_uint<T>(optixGetPayload_0(), optixGetPayload_1());
@@ -95,9 +97,9 @@ extern "C" __global__ void __miss__kernel_optix_miss()
extern "C" __global__ void __anyhit__kernel_optix_local_hit()
{
-#ifdef __HAIR__
+#if defined(__HAIR__) || defined(__POINTCLOUD__)
if (!optixIsTriangleHit()) {
- /* Ignore curves. */
+ /* Ignore curves and points. */
return optixIgnoreIntersection();
}
#endif
@@ -192,7 +194,7 @@ extern "C" __global__ void __anyhit__kernel_optix_shadow_all_hit()
type = kernel_tex_fetch(__objects, object).primitive_type;
}
# ifdef __HAIR__
- else {
+ else if (optixGetHitKind() & PRIMITIVE_ALL_CURVE) {
u = __uint_as_float(optixGetAttribute_0());
v = __uint_as_float(optixGetAttribute_1());
@@ -200,12 +202,19 @@ extern "C" __global__ void __anyhit__kernel_optix_shadow_all_hit()
type = segment.type;
prim = segment.prim;
+# if OPTIX_ABI_VERSION < 55
/* Filter out curve endcaps. */
if (u == 0.0f || u == 1.0f) {
return optixIgnoreIntersection();
}
+# endif
}
# endif
+ else {
+ type = kernel_tex_fetch(__objects, object).primitive_type;
+ u = 0.0f;
+ v = 0.0f;
+ }
# ifndef __TRANSPARENT_SHADOWS__
/* No transparent shadows support compiled in, make opaque. */
@@ -232,7 +241,7 @@ extern "C" __global__ void __anyhit__kernel_optix_shadow_all_hit()
optixSetPayload_2(uint16_pack_to_uint(num_recorded_hits, num_hits + 1));
if (throughput < CURVE_SHADOW_TRANSPARENCY_CUTOFF) {
- optixSetPayload_4(true);
+ optixSetPayload_5(true);
return optixTerminateRay();
}
else {
@@ -287,7 +296,7 @@ extern "C" __global__ void __anyhit__kernel_optix_shadow_all_hit()
extern "C" __global__ void __anyhit__kernel_optix_volume_test()
{
-#ifdef __HAIR__
+#if defined(__HAIR__) || defined(__POINTCLOUD__)
if (!optixIsTriangleHit()) {
/* Ignore curves. */
return optixIgnoreIntersection();
@@ -310,13 +319,15 @@ extern "C" __global__ void __anyhit__kernel_optix_volume_test()
extern "C" __global__ void __anyhit__kernel_optix_visibility_test()
{
#ifdef __HAIR__
- if (!optixIsTriangleHit()) {
+# if OPTIX_ABI_VERSION < 55
+ if (optixGetHitKind() & PRIMITIVE_ALL_CURVE) {
/* Filter out curve endcaps. */
const float u = __uint_as_float(optixGetAttribute_0());
if (u == 0.0f || u == 1.0f) {
return optixIgnoreIntersection();
}
}
+# endif
#endif
#ifdef __VISIBILITY_FLAG__
@@ -348,13 +359,19 @@ extern "C" __global__ void __closesthit__kernel_optix_hit()
optixSetPayload_3(prim);
optixSetPayload_5(kernel_tex_fetch(__objects, object).primitive_type);
}
- else {
+ else if (optixGetHitKind() & PRIMITIVE_ALL_CURVE) {
const KernelCurveSegment segment = kernel_tex_fetch(__curve_segments, prim);
optixSetPayload_1(optixGetAttribute_0()); /* Same as 'optixGetCurveParameter()' */
optixSetPayload_2(optixGetAttribute_1());
optixSetPayload_3(segment.prim);
optixSetPayload_5(segment.type);
}
+ else {
+ optixSetPayload_1(0);
+ optixSetPayload_2(0);
+ optixSetPayload_3(prim);
+ optixSetPayload_5(kernel_tex_fetch(__objects, object).primitive_type);
+ }
}
#ifdef __HAIR__
@@ -405,4 +422,45 @@ extern "C" __global__ void __intersection__curve_ribbon()
optix_intersection_curve(prim, type);
}
}
+
+#endif
+
+#ifdef __POINTCLOUD__
+extern "C" __global__ void __intersection__point()
+{
+ const int prim = optixGetPrimitiveIndex();
+ const int object = get_object_id();
+ const int type = kernel_tex_fetch(__objects, object).primitive_type;
+
+# ifdef __VISIBILITY_FLAG__
+ const uint visibility = optixGetPayload_4();
+ if ((kernel_tex_fetch(__objects, object).visibility & visibility) == 0) {
+ return;
+ }
+# endif
+
+ float3 P = optixGetObjectRayOrigin();
+ float3 dir = optixGetObjectRayDirection();
+
+ /* The direction is not normalized by default, the point intersection routine expects that. */
+ float len;
+ dir = normalize_len(dir, &len);
+
+# ifdef __OBJECT_MOTION__
+ const float time = optixGetRayTime();
+# else
+ const float time = 0.0f;
+# endif
+
+ Intersection isect;
+ isect.t = optixGetRayTmax();
+ /* Transform maximum distance into object space. */
+ if (isect.t != FLT_MAX) {
+ isect.t *= len;
+ }
+
+ if (point_intersect(NULL, &isect, P, dir, isect.t, object, prim, time, type)) {
+ optixReportIntersection(isect.t / len, type & PRIMITIVE_ALL);
+ }
+}
#endif
diff --git a/intern/cycles/kernel/film/accumulate.h b/intern/cycles/kernel/film/accumulate.h
index 9ee0d27cc8c..fb52b1cd05f 100644
--- a/intern/cycles/kernel/film/accumulate.h
+++ b/intern/cycles/kernel/film/accumulate.h
@@ -502,7 +502,7 @@ ccl_device_inline void kernel_accum_light(KernelGlobals kg,
/* Write shadow pass. */
if (kernel_data.film.pass_shadow != PASS_UNUSED && (path_flag & PATH_RAY_SHADOW_FOR_LIGHT) &&
- (path_flag & PATH_RAY_CAMERA)) {
+ (path_flag & PATH_RAY_TRANSPARENT_BACKGROUND)) {
const float3 unshadowed_throughput = INTEGRATOR_STATE(
state, shadow_path, unshadowed_throughput);
const float3 shadowed_throughput = INTEGRATOR_STATE(state, shadow_path, throughput);
diff --git a/intern/cycles/kernel/film/passes.h b/intern/cycles/kernel/film/passes.h
index 77761709a78..269e3620388 100644
--- a/intern/cycles/kernel/film/passes.h
+++ b/intern/cycles/kernel/film/passes.h
@@ -177,7 +177,7 @@ ccl_device_inline void kernel_write_data_passes(KernelGlobals kg,
#ifdef __PASSES__
const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
- if (!(path_flag & PATH_RAY_CAMERA)) {
+ if (!(path_flag & PATH_RAY_TRANSPARENT_BACKGROUND)) {
return;
}
diff --git a/intern/cycles/kernel/film/read.h b/intern/cycles/kernel/film/read.h
index d308a9818e2..18a593a75b1 100644
--- a/intern/cycles/kernel/film/read.h
+++ b/intern/cycles/kernel/film/read.h
@@ -460,7 +460,7 @@ ccl_device_inline float4 film_calculate_shadow_catcher_matte_with_shadow(
const float transparency = in_matte[3] * scale;
const float alpha = saturatef(1.0f - transparency);
- const float alpha_matte = (1.0f - alpha) * (1.0f - average(shadow_catcher)) + alpha;
+ const float alpha_matte = (1.0f - alpha) * (1.0f - saturatef(average(shadow_catcher))) + alpha;
if (kfilm_convert->use_approximate_shadow_catcher_background) {
kernel_assert(kfilm_convert->pass_background != PASS_UNUSED);
diff --git a/intern/cycles/kernel/geom/geom.h b/intern/cycles/kernel/geom/geom.h
index 9d023375a35..efc296c8d39 100644
--- a/intern/cycles/kernel/geom/geom.h
+++ b/intern/cycles/kernel/geom/geom.h
@@ -29,6 +29,9 @@
#include "kernel/geom/motion_triangle_intersect.h"
#include "kernel/geom/motion_triangle_shader.h"
#include "kernel/geom/motion_curve.h"
+#include "kernel/geom/motion_point.h"
+#include "kernel/geom/point.h"
+#include "kernel/geom/point_intersect.h"
#include "kernel/geom/curve.h"
#include "kernel/geom/curve_intersect.h"
#include "kernel/geom/volume.h"
diff --git a/intern/cycles/kernel/geom/motion_point.h b/intern/cycles/kernel/geom/motion_point.h
new file mode 100644
index 00000000000..d7ffc80c045
--- /dev/null
+++ b/intern/cycles/kernel/geom/motion_point.h
@@ -0,0 +1,74 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/* Motion Point Primitive
+ *
+ * These are stored as regular points, plus extra positions and radii at times
+ * other than the frame center. Computing the point at a given ray time is
+ * a matter of interpolation of the two steps between which the ray time lies.
+ *
+ * The extra points are stored as ATTR_STD_MOTION_VERTEX_POSITION.
+ */
+
+#ifdef __POINTCLOUD__
+
+ccl_device_inline float4
+motion_point_for_step(KernelGlobals kg, int offset, int numkeys, int numsteps, int step, int prim)
+{
+ if (step == numsteps) {
+ /* center step: regular key location */
+ return kernel_tex_fetch(__points, prim);
+ }
+ else {
+ /* center step is not stored in this array */
+ if (step > numsteps)
+ step--;
+
+ offset += step * numkeys;
+
+ return kernel_tex_fetch(__attributes_float4, offset + prim);
+ }
+}
+
+/* return 2 point key locations */
+ccl_device_inline float4 motion_point(KernelGlobals kg, int object, int prim, float time)
+{
+ /* get motion info */
+ int numsteps, numkeys;
+ object_motion_info(kg, object, &numsteps, NULL, &numkeys);
+
+ /* figure out which steps we need to fetch and their interpolation factor */
+ int maxstep = numsteps * 2;
+ int step = min((int)(time * maxstep), maxstep - 1);
+ float t = time * maxstep - step;
+
+ /* find attribute */
+ int offset = intersection_find_attribute(kg, object, ATTR_STD_MOTION_VERTEX_POSITION);
+ kernel_assert(offset != ATTR_STD_NOT_FOUND);
+
+ /* fetch key coordinates */
+ float4 point = motion_point_for_step(kg, offset, numkeys, numsteps, step, prim);
+ float4 next_point = motion_point_for_step(kg, offset, numkeys, numsteps, step + 1, prim);
+
+ /* interpolate between steps */
+ return (1.0f - t) * point + t * next_point;
+}
+
+#endif
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/geom/motion_triangle_intersect.h b/intern/cycles/kernel/geom/motion_triangle_intersect.h
index 256e7add21e..3bbb7be685d 100644
--- a/intern/cycles/kernel/geom/motion_triangle_intersect.h
+++ b/intern/cycles/kernel/geom/motion_triangle_intersect.h
@@ -101,8 +101,8 @@ ccl_device_inline
const int isect_prim,
float3 verts[3])
{
-# ifdef __KERNEL_OPTIX__
- /* t is always in world space with OptiX. */
+# if defined(__KERNEL_GPU_RAYTRACING__)
+ /* t is always in world space with OptiX and MetalRT. */
return motion_triangle_refine(kg, sd, P, D, t, isect_object, isect_prim, verts);
# else
# ifdef __INTERSECTION_REFINE__
@@ -163,19 +163,7 @@ ccl_device_inline bool motion_triangle_intersect(KernelGlobals kg,
motion_triangle_vertices(kg, fobject, prim, time, verts);
/* Ray-triangle intersection, unoptimized. */
float t, u, v;
- if (ray_triangle_intersect(P,
- dir,
- tmax,
-#if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__)
- (ssef *)verts,
-#else
- verts[0],
- verts[1],
- verts[2],
-#endif
- &u,
- &v,
- &t)) {
+ if (ray_triangle_intersect(P, dir, tmax, verts[0], verts[1], verts[2], &u, &v, &t)) {
#ifdef __VISIBILITY_FLAG__
/* Visibility flag test. we do it here under the assumption
* that most triangles are culled by node flags.
@@ -229,19 +217,7 @@ ccl_device_inline bool motion_triangle_intersect_local(KernelGlobals kg,
motion_triangle_vertices(kg, local_object, prim, time, verts);
/* Ray-triangle intersection, unoptimized. */
float t, u, v;
- if (!ray_triangle_intersect(P,
- dir,
- tmax,
-# if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__)
- (ssef *)verts,
-# else
- verts[0],
- verts[1],
- verts[2],
-# endif
- &u,
- &v,
- &t)) {
+ if (!ray_triangle_intersect(P, dir, tmax, verts[0], verts[1], verts[2], &u, &v, &t)) {
return false;
}
diff --git a/intern/cycles/kernel/geom/point.h b/intern/cycles/kernel/geom/point.h
new file mode 100644
index 00000000000..021135b76fb
--- /dev/null
+++ b/intern/cycles/kernel/geom/point.h
@@ -0,0 +1,124 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/* Point Primitive
+ *
+ * Point primitive for rendering point clouds.
+ */
+
+#ifdef __POINTCLOUD__
+
+/* Reading attributes on various point elements */
+
+ccl_device float point_attribute_float(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ const AttributeDescriptor desc,
+ ccl_private float *dx,
+ ccl_private float *dy)
+{
+# ifdef __RAY_DIFFERENTIALS__
+ if (dx)
+ *dx = 0.0f;
+ if (dy)
+ *dy = 0.0f;
+# endif
+
+ if (desc.element == ATTR_ELEMENT_VERTEX) {
+ return kernel_tex_fetch(__attributes_float, desc.offset + sd->prim);
+ }
+ else {
+ return 0.0f;
+ }
+}
+
+ccl_device float2 point_attribute_float2(
+ KernelGlobals kg, const ShaderData *sd, const AttributeDescriptor desc, float2 *dx, float2 *dy)
+{
+# ifdef __RAY_DIFFERENTIALS__
+ if (dx)
+ *dx = make_float2(0.0f, 0.0f);
+ if (dy)
+ *dy = make_float2(0.0f, 0.0f);
+# endif
+
+ if (desc.element == ATTR_ELEMENT_VERTEX) {
+ return kernel_tex_fetch(__attributes_float2, desc.offset + sd->prim);
+ }
+ else {
+ return make_float2(0.0f, 0.0f);
+ }
+}
+
+ccl_device float3 point_attribute_float3(
+ KernelGlobals kg, const ShaderData *sd, const AttributeDescriptor desc, float3 *dx, float3 *dy)
+{
+# ifdef __RAY_DIFFERENTIALS__
+ if (dx)
+ *dx = make_float3(0.0f, 0.0f, 0.0f);
+ if (dy)
+ *dy = make_float3(0.0f, 0.0f, 0.0f);
+# endif
+
+ if (desc.element == ATTR_ELEMENT_VERTEX) {
+ return float4_to_float3(kernel_tex_fetch(__attributes_float4, desc.offset + sd->prim));
+ }
+ else {
+ return make_float3(0.0f, 0.0f, 0.0f);
+ }
+}
+
+ccl_device float4 point_attribute_float4(
+ KernelGlobals kg, const ShaderData *sd, const AttributeDescriptor desc, float4 *dx, float4 *dy)
+{
+# ifdef __RAY_DIFFERENTIALS__
+ if (dx)
+ *dx = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ if (dy)
+ *dy = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+# endif
+
+ if (desc.element == ATTR_ELEMENT_VERTEX) {
+ return kernel_tex_fetch(__attributes_float4, desc.offset + sd->prim);
+ }
+ else {
+ return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ }
+}
+
+/* Point radius */
+
+ccl_device float point_radius(KernelGlobals kg, ccl_private const ShaderData *sd)
+{
+ if (sd->type & PRIMITIVE_ALL_POINT) {
+ return kernel_tex_fetch(__points, sd->prim).w;
+ }
+
+ return 0.0f;
+}
+
+/* Point location for motion pass, linear interpolation between keys and
+ * ignoring radius because we do the same for the motion keys */
+
+ccl_device float3 point_motion_center_location(KernelGlobals kg, ccl_private const ShaderData *sd)
+{
+ return float4_to_float3(kernel_tex_fetch(__points, sd->prim));
+}
+
+#endif /* __POINTCLOUD__ */
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/geom/point_intersect.h b/intern/cycles/kernel/geom/point_intersect.h
new file mode 100644
index 00000000000..24afa33c53a
--- /dev/null
+++ b/intern/cycles/kernel/geom/point_intersect.h
@@ -0,0 +1,133 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Based on Embree code, copyright 2009-2020 Intel Corporation.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/* Point primitive intersection functions. */
+
+#ifdef __POINTCLOUD__
+
+ccl_device_forceinline bool point_intersect_test(
+ const float4 point, const float3 P, const float3 dir, const float tmax, float *t)
+{
+ const float3 center = float4_to_float3(point);
+ const float radius = point.w;
+
+ const float rd2 = 1.0f / dot(dir, dir);
+
+ const float3 c0 = center - P;
+ const float projC0 = dot(c0, dir) * rd2;
+ const float3 perp = c0 - projC0 * dir;
+ const float l2 = dot(perp, perp);
+ const float r2 = radius * radius;
+ if (!(l2 <= r2)) {
+ return false;
+ }
+
+ const float td = sqrt((r2 - l2) * rd2);
+ const float t_front = projC0 - td;
+ const bool valid_front = (0.0f <= t_front) & (t_front <= tmax);
+
+ /* Always back-face culling for now. */
+# if 0
+ const float t_back = projC0 + td;
+ const bool valid_back = (0.0f <= t_back) & (t_back <= tmax);
+
+ /* check if there is a first hit */
+ const bool valid_first = valid_front | valid_back;
+ if (!valid_first) {
+ return false;
+ }
+
+ *t = (valid_front) ? t_front : t_back;
+ return true;
+# else
+ if (!valid_front) {
+ return false;
+ }
+ *t = t_front;
+ return true;
+# endif
+}
+
+ccl_device_forceinline bool point_intersect(KernelGlobals kg,
+ ccl_private Intersection *isect,
+ const float3 P,
+ const float3 dir,
+ const float tmax,
+ const int object,
+ const int prim,
+ const float time,
+ const int type)
+{
+ const float4 point = (type & PRIMITIVE_ALL_MOTION) ? motion_point(kg, object, prim, time) :
+ kernel_tex_fetch(__points, prim);
+
+ if (!point_intersect_test(point, P, dir, tmax, &isect->t)) {
+ return false;
+ }
+
+ isect->prim = prim;
+ isect->object = object;
+ isect->type = type;
+ isect->u = 0.0f;
+ isect->v = 0.0f;
+ return true;
+}
+
+ccl_device_inline void point_shader_setup(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private const Intersection *isect,
+ const Ray *ray)
+{
+ sd->shader = kernel_tex_fetch(__points_shader, isect->prim);
+ sd->P = ray->P + ray->D * isect->t;
+
+ /* Texture coordinates, zero for now. */
+# ifdef __UV__
+ sd->u = isect->u;
+ sd->v = isect->v;
+# endif
+
+ /* Computer point center for normal. */
+ float3 center = float4_to_float3((isect->type & PRIMITIVE_ALL_MOTION) ?
+ motion_point(kg, sd->object, sd->prim, sd->time) :
+ kernel_tex_fetch(__points, sd->prim));
+
+ if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
+ const Transform tfm = object_get_transform(kg, sd);
+
+# ifndef __KERNEL_OPTIX__
+ center = transform_point(&tfm, center);
+# endif
+ }
+
+ /* Normal */
+ sd->Ng = normalize(sd->P - center);
+ sd->N = sd->Ng;
+
+# ifdef __DPDU__
+ /* dPdu/dPdv */
+ sd->dPdu = make_float3(0.0f, 0.0f, 0.0f);
+ sd->dPdv = make_float3(0.0f, 0.0f, 0.0f);
+# endif
+}
+
+#endif
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/geom/primitive.h b/intern/cycles/kernel/geom/primitive.h
index 6d7b550d82f..9416385638c 100644
--- a/intern/cycles/kernel/geom/primitive.h
+++ b/intern/cycles/kernel/geom/primitive.h
@@ -48,6 +48,11 @@ ccl_device_inline float primitive_surface_attribute_float(KernelGlobals kg,
return curve_attribute_float(kg, sd, desc, dx, dy);
}
#endif
+#ifdef __POINTCLOUD__
+ else if (sd->type & PRIMITIVE_ALL_POINT) {
+ return point_attribute_float(kg, sd, desc, dx, dy);
+ }
+#endif
else {
if (dx)
*dx = 0.0f;
@@ -74,6 +79,11 @@ ccl_device_inline float2 primitive_surface_attribute_float2(KernelGlobals kg,
return curve_attribute_float2(kg, sd, desc, dx, dy);
}
#endif
+#ifdef __POINTCLOUD__
+ else if (sd->type & PRIMITIVE_ALL_POINT) {
+ return point_attribute_float2(kg, sd, desc, dx, dy);
+ }
+#endif
else {
if (dx)
*dx = make_float2(0.0f, 0.0f);
@@ -100,6 +110,11 @@ ccl_device_inline float3 primitive_surface_attribute_float3(KernelGlobals kg,
return curve_attribute_float3(kg, sd, desc, dx, dy);
}
#endif
+#ifdef __POINTCLOUD__
+ else if (sd->type & PRIMITIVE_ALL_POINT) {
+ return point_attribute_float3(kg, sd, desc, dx, dy);
+ }
+#endif
else {
if (dx)
*dx = make_float3(0.0f, 0.0f, 0.0f);
@@ -126,6 +141,11 @@ ccl_device_forceinline float4 primitive_surface_attribute_float4(KernelGlobals k
return curve_attribute_float4(kg, sd, desc, dx, dy);
}
#endif
+#ifdef __POINTCLOUD__
+ else if (sd->type & PRIMITIVE_ALL_POINT) {
+ return point_attribute_float4(kg, sd, desc, dx, dy);
+ }
+#endif
else {
if (dx)
*dx = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
@@ -225,8 +245,8 @@ ccl_device bool primitive_ptex(KernelGlobals kg,
ccl_device float3 primitive_tangent(KernelGlobals kg, ccl_private ShaderData *sd)
{
-#ifdef __HAIR__
- if (sd->type & PRIMITIVE_ALL_CURVE)
+#if defined(__HAIR__) || defined(__POINTCLOUD__)
+ if (sd->type & (PRIMITIVE_ALL_CURVE | PRIMITIVE_ALL_POINT))
# ifdef __DPDU__
return normalize(sd->dPdu);
# else
@@ -261,10 +281,21 @@ ccl_device_inline float4 primitive_motion_vector(KernelGlobals kg,
/* center position */
float3 center;
-#ifdef __HAIR__
- bool is_curve_primitive = sd->type & PRIMITIVE_ALL_CURVE;
- if (is_curve_primitive) {
- center = curve_motion_center_location(kg, sd);
+#if defined(__HAIR__) || defined(__POINTCLOUD__)
+ bool is_curve_or_point = sd->type & (PRIMITIVE_ALL_CURVE | PRIMITIVE_ALL_POINT);
+ if (is_curve_or_point) {
+ center = make_float3(0.0f, 0.0f, 0.0f);
+
+ if (sd->type & PRIMITIVE_ALL_CURVE) {
+# if defined(__HAIR__)
+ center = curve_motion_center_location(kg, sd);
+# endif
+ }
+ else if (sd->type & PRIMITIVE_ALL_POINT) {
+# if defined(__POINTCLOUD__)
+ center = point_motion_center_location(kg, sd);
+# endif
+ }
if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
object_position_transform(kg, sd, &center);
@@ -272,7 +303,9 @@ ccl_device_inline float4 primitive_motion_vector(KernelGlobals kg,
}
else
#endif
+ {
center = sd->P;
+ }
float3 motion_pre = center, motion_post = center;
@@ -284,8 +317,8 @@ ccl_device_inline float4 primitive_motion_vector(KernelGlobals kg,
int numverts, numkeys;
object_motion_info(kg, sd->object, NULL, &numverts, &numkeys);
-#ifdef __HAIR__
- if (is_curve_primitive) {
+#if defined(__HAIR__) || defined(__POINTCLOUD__)
+ if (is_curve_or_point) {
motion_pre = float4_to_float3(curve_attribute_float4(kg, sd, desc, NULL, NULL));
desc.offset += numkeys;
motion_post = float4_to_float3(curve_attribute_float4(kg, sd, desc, NULL, NULL));
diff --git a/intern/cycles/kernel/geom/shader_data.h b/intern/cycles/kernel/geom/shader_data.h
index 46bda2b656c..d3932545ef6 100644
--- a/intern/cycles/kernel/geom/shader_data.h
+++ b/intern/cycles/kernel/geom/shader_data.h
@@ -75,6 +75,13 @@ ccl_device_inline void shader_setup_from_ray(KernelGlobals kg,
}
else
#endif
+#ifdef __POINTCLOUD__
+ if (sd->type & PRIMITIVE_ALL_POINT) {
+ /* point */
+ point_shader_setup(kg, sd, isect, ray);
+ }
+ else
+#endif
if (sd->type & PRIMITIVE_TRIANGLE) {
/* static triangle */
float3 Ng = triangle_normal(kg, sd);
diff --git a/intern/cycles/kernel/geom/triangle_intersect.h b/intern/cycles/kernel/geom/triangle_intersect.h
index 720eceec4ed..4a7f38131da 100644
--- a/intern/cycles/kernel/geom/triangle_intersect.h
+++ b/intern/cycles/kernel/geom/triangle_intersect.h
@@ -37,27 +37,11 @@ ccl_device_inline bool triangle_intersect(KernelGlobals kg,
{
const int prim = kernel_tex_fetch(__prim_index, prim_addr);
const uint tri_vindex = kernel_tex_fetch(__tri_vindex, prim).w;
-#if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__)
- const ssef *ssef_verts = (ssef *)&kg->__tri_verts.data[tri_vindex];
-#else
const float3 tri_a = kernel_tex_fetch(__tri_verts, tri_vindex + 0),
tri_b = kernel_tex_fetch(__tri_verts, tri_vindex + 1),
tri_c = kernel_tex_fetch(__tri_verts, tri_vindex + 2);
-#endif
float t, u, v;
- if (ray_triangle_intersect(P,
- dir,
- tmax,
-#if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__)
- ssef_verts,
-#else
- tri_a,
- tri_b,
- tri_c,
-#endif
- &u,
- &v,
- &t)) {
+ if (ray_triangle_intersect(P, dir, tmax, tri_a, tri_b, tri_c, &u, &v, &t)) {
#ifdef __VISIBILITY_FLAG__
/* Visibility flag test. we do it here under the assumption
* that most triangles are culled by node flags.
@@ -106,27 +90,11 @@ ccl_device_inline bool triangle_intersect_local(KernelGlobals kg,
const int prim = kernel_tex_fetch(__prim_index, prim_addr);
const uint tri_vindex = kernel_tex_fetch(__tri_vindex, prim).w;
-# if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__)
- const ssef *ssef_verts = (ssef *)&kg->__tri_verts.data[tri_vindex];
-# else
const float3 tri_a = kernel_tex_fetch(__tri_verts, tri_vindex + 0),
tri_b = kernel_tex_fetch(__tri_verts, tri_vindex + 1),
tri_c = kernel_tex_fetch(__tri_verts, tri_vindex + 2);
-# endif
float t, u, v;
- if (!ray_triangle_intersect(P,
- dir,
- tmax,
-# if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__)
- ssef_verts,
-# else
- tri_a,
- tri_b,
- tri_c,
-# endif
- &u,
- &v,
- &t)) {
+ if (!ray_triangle_intersect(P, dir, tmax, tri_a, tri_b, tri_c, &u, &v, &t)) {
return false;
}
@@ -178,11 +146,6 @@ ccl_device_inline bool triangle_intersect_local(KernelGlobals kg,
isect->t = t;
/* Record geometric normal. */
-# if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__)
- const float3 tri_a = kernel_tex_fetch(__tri_verts, tri_vindex + 0),
- tri_b = kernel_tex_fetch(__tri_verts, tri_vindex + 1),
- tri_c = kernel_tex_fetch(__tri_verts, tri_vindex + 2);
-# endif
local_isect->Ng[hit] = normalize(cross(tri_b - tri_a, tri_c - tri_a));
return false;
@@ -264,8 +227,8 @@ ccl_device_inline float3 triangle_refine_local(KernelGlobals kg,
const int isect_object,
const int isect_prim)
{
-#ifdef __KERNEL_OPTIX__
- /* t is always in world space with OptiX. */
+#if defined(__KERNEL_GPU_RAYTRACING__)
+ /* t is always in world space with OptiX and MetalRT. */
return triangle_refine(kg, sd, P, D, t, isect_object, isect_prim);
#else
if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
diff --git a/intern/cycles/kernel/integrator/intersect_closest.h b/intern/cycles/kernel/integrator/intersect_closest.h
index 366bfba7aca..df710dc1d82 100644
--- a/intern/cycles/kernel/integrator/intersect_closest.h
+++ b/intern/cycles/kernel/integrator/intersect_closest.h
@@ -341,9 +341,8 @@ ccl_device void integrator_intersect_closest(KernelGlobals kg,
* these in the path_state_init. */
const int last_type = INTEGRATOR_STATE(state, isect, type);
const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
-
hit = lights_intersect(
- kg, &ray, &isect, last_isect_prim, last_isect_object, last_type, path_flag) ||
+ kg, state, &ray, &isect, last_isect_prim, last_isect_object, last_type, path_flag) ||
hit;
}
diff --git a/intern/cycles/kernel/integrator/path_state.h b/intern/cycles/kernel/integrator/path_state.h
index eac9ceeae70..ff6b55a73c3 100644
--- a/intern/cycles/kernel/integrator/path_state.h
+++ b/intern/cycles/kernel/integrator/path_state.h
@@ -70,6 +70,9 @@ ccl_device_inline void path_state_init_integrator(KernelGlobals kg,
INTEGRATOR_STATE_WRITE(state, path, continuation_probability) = 1.0f;
INTEGRATOR_STATE_WRITE(state, path, throughput) = make_float3(1.0f, 1.0f, 1.0f);
+ INTEGRATOR_STATE_WRITE(state, isect, object) = OBJECT_NONE;
+ INTEGRATOR_STATE_WRITE(state, isect, prim) = PRIM_NONE;
+
if (kernel_data.kernel_features & KERNEL_FEATURE_VOLUME) {
INTEGRATOR_STATE_ARRAY_WRITE(state, volume_stack, 0, object) = OBJECT_NONE;
INTEGRATOR_STATE_ARRAY_WRITE(
@@ -122,7 +125,7 @@ ccl_device_inline void path_state_next(KernelGlobals kg, IntegratorState state,
/* volume scatter */
flag |= PATH_RAY_VOLUME_SCATTER;
flag &= ~PATH_RAY_TRANSPARENT_BACKGROUND;
- if (bounce == 1) {
+ if (!(flag & PATH_RAY_ANY_PASS)) {
flag |= PATH_RAY_VOLUME_PASS;
}
@@ -184,7 +187,7 @@ ccl_device_inline void path_state_next(KernelGlobals kg, IntegratorState state,
}
/* Render pass categories. */
- if (bounce == 1) {
+ if (!(flag & PATH_RAY_ANY_PASS) && !(flag & PATH_RAY_TRANSPARENT_BACKGROUND)) {
flag |= PATH_RAY_SURFACE_PASS;
}
}
diff --git a/intern/cycles/kernel/integrator/shade_volume.h b/intern/cycles/kernel/integrator/shade_volume.h
index 8fc9351b3e3..712c22357b8 100644
--- a/intern/cycles/kernel/integrator/shade_volume.h
+++ b/intern/cycles/kernel/integrator/shade_volume.h
@@ -699,8 +699,10 @@ ccl_device_forceinline bool integrate_volume_sample_light(
float light_u, light_v;
path_state_rng_2D(kg, rng_state, PRNG_LIGHT_U, &light_u, &light_v);
- light_distribution_sample_from_volume_segment(
- kg, light_u, light_v, sd->time, sd->P, bounce, path_flag, ls);
+ if (!light_distribution_sample_from_volume_segment(
+ kg, light_u, light_v, sd->time, sd->P, bounce, path_flag, ls)) {
+ return false;
+ }
if (ls->shader & SHADER_EXCLUDE_SCATTER) {
return false;
diff --git a/intern/cycles/kernel/integrator/subsurface_disk.h b/intern/cycles/kernel/integrator/subsurface_disk.h
index 22327268e02..cc6f5048cda 100644
--- a/intern/cycles/kernel/integrator/subsurface_disk.h
+++ b/intern/cycles/kernel/integrator/subsurface_disk.h
@@ -137,8 +137,8 @@ ccl_device_inline bool subsurface_disk(KernelGlobals kg,
Transform tfm = object_fetch_transform_motion_test(kg, object, time, &itfm);
hit_Ng = normalize(transform_direction_transposed(&itfm, hit_Ng));
- /* Transform t to world space, except for OptiX where it already is. */
-#ifdef __KERNEL_OPTIX__
+ /* Transform t to world space, except for OptiX and MetalRT where it already is. */
+#ifdef __KERNEL_GPU_RAYTRACING__
(void)tfm;
#else
float3 D = transform_direction(&itfm, ray.D);
diff --git a/intern/cycles/kernel/integrator/subsurface_random_walk.h b/intern/cycles/kernel/integrator/subsurface_random_walk.h
index f0712758174..7a8b467e199 100644
--- a/intern/cycles/kernel/integrator/subsurface_random_walk.h
+++ b/intern/cycles/kernel/integrator/subsurface_random_walk.h
@@ -212,7 +212,7 @@ ccl_device_inline bool subsurface_random_walk(KernelGlobals kg,
ray.dP = ray_dP;
ray.dD = differential_zero_compact();
-#ifndef __KERNEL_OPTIX__
+#ifndef __KERNEL_GPU_RAYTRACING__
/* Compute or fetch object transforms. */
Transform ob_itfm ccl_optional_struct_init;
Transform ob_tfm = object_fetch_transform_motion_test(kg, object, time, &ob_itfm);
@@ -382,8 +382,8 @@ ccl_device_inline bool subsurface_random_walk(KernelGlobals kg,
hit = (ss_isect.num_hits > 0);
if (hit) {
-#ifdef __KERNEL_OPTIX__
- /* t is always in world space with OptiX. */
+#ifdef __KERNEL_GPU_RAYTRACING__
+ /* t is always in world space with OptiX and MetalRT. */
ray.t = ss_isect.hits[0].t;
#else
/* Compute world space distance to surface hit. */
diff --git a/intern/cycles/kernel/light/common.h b/intern/cycles/kernel/light/common.h
index 75331d32d44..07f59ae48c2 100644
--- a/intern/cycles/kernel/light/common.h
+++ b/intern/cycles/kernel/light/common.h
@@ -29,7 +29,7 @@ CCL_NAMESPACE_BEGIN
*
* https://www.solidangle.com/research/egsr2013_spherical_rectangle.pdf
*
- * Note: light_p is modified when sample_coord is true.
+ * NOTE: light_p is modified when sample_coord is true.
*/
ccl_device_inline float rect_light_sample(float3 P,
ccl_private float3 *light_p,
diff --git a/intern/cycles/kernel/light/light.h b/intern/cycles/kernel/light/light.h
index 2e7f862a715..6e445f862db 100644
--- a/intern/cycles/kernel/light/light.h
+++ b/intern/cycles/kernel/light/light.h
@@ -73,7 +73,7 @@ ccl_device_inline bool light_sample(KernelGlobals kg,
ls->P = zero_float3();
ls->Ng = zero_float3();
ls->D = zero_float3();
- ls->pdf = true;
+ ls->pdf = 1.0f;
ls->t = FLT_MAX;
return true;
}
@@ -112,35 +112,58 @@ ccl_device_inline bool light_sample(KernelGlobals kg,
else {
ls->P = make_float3(klight->co[0], klight->co[1], klight->co[2]);
- if (type == LIGHT_POINT || type == LIGHT_SPOT) {
+ if (type == LIGHT_SPOT) {
+ ls->Ng = make_float3(klight->spot.dir[0], klight->spot.dir[1], klight->spot.dir[2]);
float radius = klight->spot.radius;
if (radius > 0.0f)
/* sphere light */
- ls->P += sphere_light_sample(P, ls->P, radius, randu, randv);
+ ls->P += disk_light_sample(ls->Ng, randu, randv) * radius;
ls->D = normalize_len(ls->P - P, &ls->t);
- ls->Ng = -ls->D;
float invarea = klight->spot.invarea;
ls->eval_fac = (0.25f * M_1_PI_F) * invarea;
ls->pdf = invarea;
- if (type == LIGHT_SPOT) {
- /* spot light attenuation */
- float3 dir = make_float3(klight->spot.dir[0], klight->spot.dir[1], klight->spot.dir[2]);
- ls->eval_fac *= spot_light_attenuation(
- dir, klight->spot.spot_angle, klight->spot.spot_smooth, ls->Ng);
- if (ls->eval_fac == 0.0f) {
- return false;
- }
+ /* spot light attenuation */
+ ls->eval_fac *= spot_light_attenuation(
+ ls->Ng, klight->spot.spot_angle, klight->spot.spot_smooth, -ls->D);
+ if (!in_volume_segment && ls->eval_fac == 0.0f) {
+ return false;
}
+
float2 uv = map_to_sphere(ls->Ng);
ls->u = uv.x;
ls->v = uv.y;
ls->pdf *= lamp_light_pdf(kg, ls->Ng, -ls->D, ls->t);
}
+ else if (type == LIGHT_POINT) {
+ float3 center = make_float3(klight->co[0], klight->co[1], klight->co[2]);
+ float radius = klight->spot.radius;
+ ls->P = center;
+ float pdf = 1.0;
+
+ if (radius > 0.0f) {
+ ls->Ng = normalize(P - center);
+ ls->P += disk_light_sample(ls->Ng, randu, randv) * radius;
+ pdf = klight->spot.invarea;
+ ls->D = normalize_len(ls->P - P, &ls->t);
+ }
+ else {
+ ls->Ng = normalize(P - center);
+ }
+
+ ls->D = normalize_len(ls->P - P, &ls->t);
+ ls->pdf = pdf;
+ ls->eval_fac = M_1_PI_F * 0.25f * klight->spot.invarea;
+
+ float2 uv = map_to_sphere(ls->Ng);
+ ls->u = uv.x;
+ ls->v = uv.y;
+ ls->pdf *= lamp_light_pdf(kg, ls->Ng, -ls->D, ls->t);
+ }
else {
/* area light */
float3 axisu = make_float3(
@@ -170,7 +193,7 @@ ccl_device_inline bool light_sample(KernelGlobals kg,
float3 sample_axisu = axisu;
float3 sample_axisv = axisv;
- if (klight->area.tan_spread > 0.0f) {
+ if (!in_volume_segment && klight->area.tan_spread > 0.0f) {
if (!light_spread_clamp_area_light(
P, Ng, &ls->P, &sample_axisu, &sample_axisv, klight->area.tan_spread)) {
return false;
@@ -203,10 +226,11 @@ ccl_device_inline bool light_sample(KernelGlobals kg,
ls->pdf *= kernel_data.integrator.pdf_lights;
- return (ls->pdf > 0.0f);
+ return in_volume_segment || (ls->pdf > 0.0f);
}
ccl_device bool lights_intersect(KernelGlobals kg,
+ IntegratorState state,
ccl_private const Ray *ccl_restrict ray,
ccl_private Intersection *ccl_restrict isect,
const int last_prim,
@@ -237,8 +261,31 @@ ccl_device bool lights_intersect(KernelGlobals kg,
LightType type = (LightType)klight->type;
float t = 0.0f, u = 0.0f, v = 0.0f;
- if (type == LIGHT_POINT || type == LIGHT_SPOT) {
- /* Sphere light. */
+ if (type == LIGHT_SPOT) {
+ /* Spot/Disk light. */
+ const float3 lightP = make_float3(klight->co[0], klight->co[1], klight->co[2]);
+ const float3 lightN = make_float3(
+ klight->spot.dir[0], klight->spot.dir[1], klight->spot.dir[2]);
+ const float radius = klight->spot.radius;
+ if (radius == 0.0f) {
+ continue;
+ }
+
+ /* One sided. */
+ if (dot(ray->D, lightN) >= 0.0f) {
+ continue;
+ }
+
+ float3 P;
+ if (!ray_disk_intersect(ray->P, ray->D, ray->t, lightP, lightN, radius, &P, &t)) {
+ continue;
+ }
+ }
+ else if (type == LIGHT_POINT) {
+ /* Sphere light (aka, aligned disk light). */
+ const float mis_ray_t = INTEGRATOR_STATE(state, path, mis_ray_t);
+ const float3 ray_P = ray->P - ray->D * mis_ray_t;
+
const float3 lightP = make_float3(klight->co[0], klight->co[1], klight->co[2]);
const float radius = klight->spot.radius;
if (radius == 0.0f) {
@@ -246,7 +293,8 @@ ccl_device bool lights_intersect(KernelGlobals kg,
}
float3 P;
- if (!ray_aligned_disk_intersect(ray->P, ray->D, ray->t, lightP, radius, &P, &t)) {
+ const float3 lsN = normalize(ray_P - lightP);
+ if (!ray_disk_intersect(ray->P, ray->D, ray->t, lightP, lsN, radius, &P, &t)) {
continue;
}
}
@@ -378,23 +426,21 @@ ccl_device bool light_sample_from_intersection(KernelGlobals kg,
ls->P = ray_P + ray_D * ls->t;
ls->D = ray_D;
- if (type == LIGHT_POINT || type == LIGHT_SPOT) {
- ls->Ng = -ray_D;
+ if (type == LIGHT_SPOT) {
+ ls->Ng = make_float3(klight->spot.dir[0], klight->spot.dir[1], klight->spot.dir[2]);
float invarea = klight->spot.invarea;
ls->eval_fac = (0.25f * M_1_PI_F) * invarea;
ls->pdf = invarea;
- if (type == LIGHT_SPOT) {
- /* spot light attenuation */
- float3 dir = make_float3(klight->spot.dir[0], klight->spot.dir[1], klight->spot.dir[2]);
- ls->eval_fac *= spot_light_attenuation(
- dir, klight->spot.spot_angle, klight->spot.spot_smooth, ls->Ng);
+ /* spot light attenuation */
+ ls->eval_fac *= spot_light_attenuation(
+ ls->Ng, klight->spot.spot_angle, klight->spot.spot_smooth, -ls->D);
- if (ls->eval_fac == 0.0f) {
- return false;
- }
+ if (ls->eval_fac == 0.0f) {
+ return false;
}
+
float2 uv = map_to_sphere(ls->Ng);
ls->u = uv.x;
ls->v = uv.y;
@@ -403,6 +449,24 @@ ccl_device bool light_sample_from_intersection(KernelGlobals kg,
if (ls->t != FLT_MAX)
ls->pdf *= lamp_light_pdf(kg, ls->Ng, -ls->D, ls->t);
}
+ else if (type == LIGHT_POINT) {
+ float3 center = make_float3(klight->co[0], klight->co[1], klight->co[2]);
+
+ ls->Ng = normalize(ray_P - center);
+ float invarea = klight->spot.invarea;
+ ls->eval_fac = (0.25f * M_1_PI_F) * invarea;
+ ls->pdf = invarea;
+
+ float2 uv = map_to_sphere(ls->Ng);
+ ls->u = uv.x;
+ ls->v = uv.y;
+
+ /* compute pdf */
+ if (ls->t != FLT_MAX)
+ ls->pdf *= lamp_light_pdf(kg, ls->Ng, -ls->D, ls->t);
+ else
+ ls->pdf = 0.f;
+ }
else if (type == LIGHT_AREA) {
/* area light */
float invarea = fabsf(klight->area.invarea);
@@ -676,19 +740,7 @@ ccl_device_forceinline void triangle_light_sample(KernelGlobals kg,
ls->D = z * B + safe_sqrtf(1.0f - z * z) * safe_normalize(C_ - dot(C_, B) * B);
/* calculate intersection with the planar triangle */
- if (!ray_triangle_intersect(P,
- ls->D,
- FLT_MAX,
-#if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__)
- (ssef *)V,
-#else
- V[0],
- V[1],
- V[2],
-#endif
- &ls->u,
- &ls->v,
- &ls->t)) {
+ if (!ray_triangle_intersect(P, ls->D, FLT_MAX, V[0], V[1], V[2], &ls->u, &ls->v, &ls->t)) {
ls->pdf = 0.0f;
return;
}
diff --git a/intern/cycles/kernel/light/sample.h b/intern/cycles/kernel/light/sample.h
index ff5d43ed8cd..83f6d733d3a 100644
--- a/intern/cycles/kernel/light/sample.h
+++ b/intern/cycles/kernel/light/sample.h
@@ -200,6 +200,9 @@ ccl_device_inline float3 shadow_ray_offset(KernelGlobals kg,
if (offset_cutoff > 0.0f) {
float NgL = dot(Ng, L);
float offset_amount = 0.0f;
+ if (NL < 0) {
+ NL = -NL;
+ }
if (NL < offset_cutoff) {
offset_amount = clamp(2.0f - (NgL + NL) / offset_cutoff, 0.0f, 1.0f);
}
diff --git a/intern/cycles/kernel/osl/services.cpp b/intern/cycles/kernel/osl/services.cpp
index 389c1e2b746..4007005dee7 100644
--- a/intern/cycles/kernel/osl/services.cpp
+++ b/intern/cycles/kernel/osl/services.cpp
@@ -28,6 +28,7 @@
#include "scene/colorspace.h"
#include "scene/mesh.h"
#include "scene/object.h"
+#include "scene/pointcloud.h"
#include "scene/scene.h"
#include "kernel/osl/closures.h"
@@ -113,6 +114,8 @@ ustring OSLRenderServices::u_curve_thickness("geom:curve_thickness");
ustring OSLRenderServices::u_curve_length("geom:curve_length");
ustring OSLRenderServices::u_curve_tangent_normal("geom:curve_tangent_normal");
ustring OSLRenderServices::u_curve_random("geom:curve_random");
+ustring OSLRenderServices::u_is_point("geom:is_point");
+ustring OSLRenderServices::u_point_radius("geom:point_radius");
ustring OSLRenderServices::u_normal_map_normal("geom:normal_map_normal");
ustring OSLRenderServices::u_path_ray_length("path:ray_length");
ustring OSLRenderServices::u_path_ray_depth("path:ray_depth");
@@ -994,6 +997,15 @@ bool OSLRenderServices::get_object_standard_attribute(const KernelGlobalsCPU *kg
float3 f = curve_tangent_normal(kg, sd);
return set_attribute_float3(f, type, derivatives, val);
}
+ /* point attributes */
+ else if (name == u_is_point) {
+ float f = (sd->type & PRIMITIVE_ALL_POINT) != 0;
+ return set_attribute_float(f, type, derivatives, val);
+ }
+ else if (name == u_point_radius) {
+ float f = point_radius(kg, sd);
+ return set_attribute_float(f, type, derivatives, val);
+ }
else if (name == u_normal_map_normal) {
if (sd->type & PRIMITIVE_ALL_TRIANGLE) {
float3 f = triangle_smooth_normal_unnormalized(kg, sd, sd->Ng, sd->prim, sd->u, sd->v);
diff --git a/intern/cycles/kernel/osl/services.h b/intern/cycles/kernel/osl/services.h
index d9f57c642ad..9526c92b8fb 100644
--- a/intern/cycles/kernel/osl/services.h
+++ b/intern/cycles/kernel/osl/services.h
@@ -297,6 +297,8 @@ class OSLRenderServices : public OSL::RendererServices {
static ustring u_curve_length;
static ustring u_curve_tangent_normal;
static ustring u_curve_random;
+ static ustring u_is_point;
+ static ustring u_point_radius;
static ustring u_normal_map_normal;
static ustring u_path_ray_length;
static ustring u_path_ray_depth;
diff --git a/intern/cycles/kernel/osl/shaders/CMakeLists.txt b/intern/cycles/kernel/osl/shaders/CMakeLists.txt
index 6b62e7bb52f..4cafdb2a6d7 100644
--- a/intern/cycles/kernel/osl/shaders/CMakeLists.txt
+++ b/intern/cycles/kernel/osl/shaders/CMakeLists.txt
@@ -92,6 +92,7 @@ set(SRC_OSL
node_value.osl
node_vector_curves.osl
node_vector_math.osl
+ node_vector_map_range.osl
node_vector_rotate.osl
node_vector_transform.osl
node_velvet_bsdf.osl
diff --git a/intern/cycles/kernel/osl/shaders/node_magic_texture.osl b/intern/cycles/kernel/osl/shaders/node_magic_texture.osl
index 476c6895f05..0ed83aae3b8 100644
--- a/intern/cycles/kernel/osl/shaders/node_magic_texture.osl
+++ b/intern/cycles/kernel/osl/shaders/node_magic_texture.osl
@@ -17,14 +17,17 @@
#include "stdcycles.h"
/* Magic */
-
-color magic(point p, int n, float distortion)
+color magic(point p, float scale, int n, float distortion)
{
float dist = distortion;
- float x = sin((p[0] + p[1] + p[2]) * 5.0);
- float y = cos((-p[0] + p[1] - p[2]) * 5.0);
- float z = -cos((-p[0] - p[1] + p[2]) * 5.0);
+ float a = mod(p.x * scale, M_2PI);
+ float b = mod(p.y * scale, M_2PI);
+ float c = mod(p.z * scale, M_2PI);
+
+ float x = sin((a + b + c) * 5.0);
+ float y = cos((-a + b - c) * 5.0);
+ float z = -cos((-a - b + c) * 5.0);
if (n > 0) {
x *= dist;
@@ -103,6 +106,6 @@ shader node_magic_texture(int use_mapping = 0,
if (use_mapping)
p = transform(mapping, p);
- Color = magic(p * Scale, depth, Distortion);
+ Color = magic(p, Scale, depth, Distortion);
Fac = (Color[0] + Color[1] + Color[2]) * (1.0 / 3.0);
}
diff --git a/intern/cycles/kernel/osl/shaders/node_vector_map_range.osl b/intern/cycles/kernel/osl/shaders/node_vector_map_range.osl
new file mode 100644
index 00000000000..1a59691fc45
--- /dev/null
+++ b/intern/cycles/kernel/osl/shaders/node_vector_map_range.osl
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2011-2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "stdcycles.h"
+
+float safe_divide(float a, float b)
+{
+ return (b != 0.0) ? a / b : 0.0;
+}
+
+point safe_divide(point a, point b)
+{
+ return point(safe_divide(a.x, b.x), safe_divide(a.y, b.y), safe_divide(a.z, b.z));
+}
+
+shader node_vector_map_range(string range_type = "linear",
+ int use_clamp = 0,
+ point VectorIn = point(1.0, 1.0, 1.0),
+ point From_Min_FLOAT3 = point(0.0, 0.0, 0.0),
+ point From_Max_FLOAT3 = point(1.0, 1.0, 1.0),
+ point To_Min_FLOAT3 = point(0.0, 0.0, 0.0),
+ point To_Max_FLOAT3 = point(1.0, 1.0, 1.0),
+ point Steps_FLOAT3 = point(4.0, 4.0, 4.0),
+ output point VectorOut = point(0.0, 0.0, 0.0))
+{
+ point factor = VectorIn;
+ point from_min = From_Min_FLOAT3;
+ point from_max = From_Max_FLOAT3;
+ point to_min = To_Min_FLOAT3;
+ point to_max = To_Max_FLOAT3;
+ point steps = Steps_FLOAT3;
+
+ if (range_type == "stepped") {
+ factor = safe_divide((factor - from_min), (from_max - from_min));
+ factor = point((steps.x > 0.0) ? floor(factor.x * (steps.x + 1.0)) / steps.x : 0.0,
+ (steps.y > 0.0) ? floor(factor.y * (steps.y + 1.0)) / steps.y : 0.0,
+ (steps.z > 0.0) ? floor(factor.z * (steps.z + 1.0)) / steps.z : 0.0);
+ }
+ else if (range_type == "smoothstep") {
+ factor = safe_divide((factor - from_min), (from_max - from_min));
+ factor = clamp(factor, 0.0, 1.0);
+ factor = (3.0 - 2.0 * factor) * (factor * factor);
+ }
+ else if (range_type == "smootherstep") {
+ factor = safe_divide((factor - from_min), (from_max - from_min));
+ factor = clamp(factor, 0.0, 1.0);
+ factor = factor * factor * factor * (factor * (factor * 6.0 - 15.0) + 10.0);
+ }
+ else {
+ factor = safe_divide((factor - from_min), (from_max - from_min));
+ }
+ VectorOut = to_min + factor * (to_max - to_min);
+ if (use_clamp > 0) {
+ VectorOut.x = (to_min.x > to_max.x) ? clamp(VectorOut.x, to_max.x, to_min.x) :
+ clamp(VectorOut.x, to_min.x, to_max.x);
+ VectorOut.y = (to_min.y > to_max.y) ? clamp(VectorOut.y, to_max.y, to_min.y) :
+ clamp(VectorOut.y, to_min.y, to_max.y);
+ VectorOut.z = (to_min.z > to_max.z) ? clamp(VectorOut.z, to_max.z, to_min.z) :
+ clamp(VectorOut.z, to_min.z, to_max.z);
+ }
+}
diff --git a/intern/cycles/kernel/svm/aov.h b/intern/cycles/kernel/svm/aov.h
index 21ee7af7639..0beaf0babc6 100644
--- a/intern/cycles/kernel/svm/aov.h
+++ b/intern/cycles/kernel/svm/aov.h
@@ -23,7 +23,8 @@ CCL_NAMESPACE_BEGIN
ccl_device_inline bool svm_node_aov_check(const uint32_t path_flag,
ccl_global float *render_buffer)
{
- bool is_primary = (path_flag & PATH_RAY_CAMERA) && (!(path_flag & PATH_RAY_SINGLE_PASS_DONE));
+ bool is_primary = (path_flag & PATH_RAY_TRANSPARENT_BACKGROUND) &&
+ (!(path_flag & PATH_RAY_SINGLE_PASS_DONE));
return ((render_buffer != NULL) && is_primary);
}
diff --git a/intern/cycles/kernel/svm/magic.h b/intern/cycles/kernel/svm/magic.h
index f103a8eebcc..715a47d88cf 100644
--- a/intern/cycles/kernel/svm/magic.h
+++ b/intern/cycles/kernel/svm/magic.h
@@ -20,11 +20,27 @@ CCL_NAMESPACE_BEGIN
/* Magic */
-ccl_device_noinline_cpu float3 svm_magic(float3 p, int n, float distortion)
+ccl_device_noinline_cpu float3 svm_magic(float3 p, float scale, int n, float distortion)
{
- float x = sinf((p.x + p.y + p.z) * 5.0f);
- float y = cosf((-p.x + p.y - p.z) * 5.0f);
- float z = -cosf((-p.x - p.y + p.z) * 5.0f);
+ /*
+ * Prevent NaNs due to input p
+ * Sin and Cosine are periodic about [0 2*PI) so the following
+ * will yeild a more accurate result. As it stops the input values
+ * going out of range for floats which caused a NaN. The
+ * calculation of (px + py + pz)*5 can cause an Inf when one or more
+ * values are very large the cos or sin of this results in a NaN
+ * It also addresses the case where one dimension is large relative
+ * to another which caused banding due to the loss of precision in the
+ * smaller value. This is due to the value in the -2*PI to 2*PI range
+ * effectively being lost due to floating point precision.
+ */
+ float px = fmodf(p.x, M_2PI_F);
+ float py = fmodf(p.y, M_2PI_F);
+ float pz = fmodf(p.z, M_2PI_F);
+
+ float x = sinf((px + py + pz) * 5.0f * scale);
+ float y = cosf((-px + py - pz) * 5.0f * scale);
+ float z = -cosf((-px - py + pz) * 5.0f * scale);
if (n > 0) {
x *= distortion;
@@ -103,7 +119,7 @@ ccl_device_noinline int svm_node_tex_magic(
float scale = stack_load_float_default(stack, scale_offset, node2.x);
float distortion = stack_load_float_default(stack, distortion_offset, node2.y);
- float3 color = svm_magic(co * scale, depth, distortion);
+ float3 color = svm_magic(co, scale, depth, distortion);
if (stack_valid(fac_offset))
stack_store_float(stack, fac_offset, average(color));
diff --git a/intern/cycles/kernel/svm/map_range.h b/intern/cycles/kernel/svm/map_range.h
index fdbfc6531c4..933ea84f939 100644
--- a/intern/cycles/kernel/svm/map_range.h
+++ b/intern/cycles/kernel/svm/map_range.h
@@ -88,4 +88,78 @@ ccl_device_noinline int svm_node_map_range(KernelGlobals kg,
return offset;
}
+ccl_device_noinline int svm_node_vector_map_range(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint value_stack_offset,
+ uint parameters_stack_offsets,
+ uint results_stack_offsets,
+ int offset)
+{
+ uint from_min_stack_offset, from_max_stack_offset, to_min_stack_offset, to_max_stack_offset;
+ uint steps_stack_offset, clamp_stack_offset, range_type_stack_offset, result_stack_offset;
+ svm_unpack_node_uchar4(parameters_stack_offsets,
+ &from_min_stack_offset,
+ &from_max_stack_offset,
+ &to_min_stack_offset,
+ &to_max_stack_offset);
+ svm_unpack_node_uchar4(results_stack_offsets,
+ &steps_stack_offset,
+ &clamp_stack_offset,
+ &range_type_stack_offset,
+ &result_stack_offset);
+
+ float3 value = stack_load_float3(stack, value_stack_offset);
+ float3 from_min = stack_load_float3(stack, from_min_stack_offset);
+ float3 from_max = stack_load_float3(stack, from_max_stack_offset);
+ float3 to_min = stack_load_float3(stack, to_min_stack_offset);
+ float3 to_max = stack_load_float3(stack, to_max_stack_offset);
+ float3 steps = stack_load_float3(stack, steps_stack_offset);
+
+ int type = range_type_stack_offset;
+ int use_clamp = (type == NODE_MAP_RANGE_SMOOTHSTEP || type == NODE_MAP_RANGE_SMOOTHERSTEP) ?
+ 0 :
+ clamp_stack_offset;
+ float3 result;
+ float3 factor = value;
+ switch (range_type_stack_offset) {
+ default:
+ case NODE_MAP_RANGE_LINEAR:
+ factor = safe_divide_float3_float3((value - from_min), (from_max - from_min));
+ break;
+ case NODE_MAP_RANGE_STEPPED: {
+ factor = safe_divide_float3_float3((value - from_min), (from_max - from_min));
+ factor = make_float3((steps.x > 0.0f) ? floorf(factor.x * (steps.x + 1.0f)) / steps.x : 0.0f,
+ (steps.y > 0.0f) ? floorf(factor.y * (steps.y + 1.0f)) / steps.y : 0.0f,
+ (steps.z > 0.0f) ? floorf(factor.z * (steps.z + 1.0f)) / steps.z :
+ 0.0f);
+ break;
+ }
+ case NODE_MAP_RANGE_SMOOTHSTEP: {
+ factor = safe_divide_float3_float3((value - from_min), (from_max - from_min));
+ factor = clamp(factor, zero_float3(), one_float3());
+ factor = (make_float3(3.0f, 3.0f, 3.0f) - 2.0f * factor) * (factor * factor);
+ break;
+ }
+ case NODE_MAP_RANGE_SMOOTHERSTEP: {
+ factor = safe_divide_float3_float3((value - from_min), (from_max - from_min));
+ factor = clamp(factor, zero_float3(), one_float3());
+ factor = factor * factor * factor * (factor * (factor * 6.0f - 15.0f) + 10.0f);
+ break;
+ }
+ }
+ result = to_min + factor * (to_max - to_min);
+ if (use_clamp > 0) {
+ result.x = (to_min.x > to_max.x) ? clamp(result.x, to_max.x, to_min.x) :
+ clamp(result.x, to_min.x, to_max.x);
+ result.y = (to_min.y > to_max.y) ? clamp(result.y, to_max.y, to_min.y) :
+ clamp(result.y, to_min.y, to_max.y);
+ result.z = (to_min.z > to_max.z) ? clamp(result.z, to_max.z, to_min.z) :
+ clamp(result.z, to_min.z, to_max.z);
+ }
+
+ stack_store_float3(stack, result_stack_offset, result);
+ return offset;
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm.h b/intern/cycles/kernel/svm/svm.h
index ce32e1a520f..b226bc66771 100644
--- a/intern/cycles/kernel/svm/svm.h
+++ b/intern/cycles/kernel/svm/svm.h
@@ -562,6 +562,9 @@ ccl_device void svm_eval_nodes(KernelGlobals kg,
case NODE_MAP_RANGE:
offset = svm_node_map_range(kg, sd, stack, node.y, node.z, node.w, offset);
break;
+ case NODE_VECTOR_MAP_RANGE:
+ offset = svm_node_vector_map_range(kg, sd, stack, node.y, node.z, node.w, offset);
+ break;
case NODE_CLAMP:
offset = svm_node_clamp(kg, sd, stack, node.y, node.z, node.w, offset);
break;
diff --git a/intern/cycles/kernel/svm/types.h b/intern/cycles/kernel/svm/types.h
index 8c95c571815..384549b7f09 100644
--- a/intern/cycles/kernel/svm/types.h
+++ b/intern/cycles/kernel/svm/types.h
@@ -114,6 +114,7 @@ typedef enum ShaderNodeType {
NODE_WAVELENGTH,
NODE_BLACKBODY,
NODE_MAP_RANGE,
+ NODE_VECTOR_MAP_RANGE,
NODE_CLAMP,
NODE_BEVEL,
NODE_AMBIENT_OCCLUSION,
diff --git a/intern/cycles/kernel/svm/wireframe.h b/intern/cycles/kernel/svm/wireframe.h
index 530a9601bce..645dc59f22e 100644
--- a/intern/cycles/kernel/svm/wireframe.h
+++ b/intern/cycles/kernel/svm/wireframe.h
@@ -42,7 +42,7 @@ ccl_device_inline float wireframe(KernelGlobals kg,
int pixel_size,
ccl_private float3 *P)
{
-#ifdef __HAIR__
+#if defined(__HAIR__) || defined(__POINTCLOUD__)
if (sd->prim != PRIM_NONE && sd->type & PRIMITIVE_ALL_TRIANGLE)
#else
if (sd->prim != PRIM_NONE)
diff --git a/intern/cycles/kernel/tables.h b/intern/cycles/kernel/tables.h
index 768033d4ffe..544bf7b7add 100644
--- a/intern/cycles/kernel/tables.h
+++ b/intern/cycles/kernel/tables.h
@@ -73,4 +73,4 @@ ccl_inline_constant float cie_colour_match[][3] = {
{0.0001f, 0.0000f, 0.0000f}, {0.0001f, 0.0000f, 0.0000f}, {0.0000f, 0.0000f, 0.0000f}
};
-/* clang-format on */ \ No newline at end of file
+/* clang-format on */
diff --git a/intern/cycles/kernel/textures.h b/intern/cycles/kernel/textures.h
index 2e3ae29a19a..06074a1eca1 100644
--- a/intern/cycles/kernel/textures.h
+++ b/intern/cycles/kernel/textures.h
@@ -34,6 +34,7 @@ KERNEL_TEX(Transform, __object_motion_pass)
KERNEL_TEX(DecomposedTransform, __object_motion)
KERNEL_TEX(uint, __object_flag)
KERNEL_TEX(float, __object_volume_step)
+KERNEL_TEX(uint, __object_prim_offset)
/* cameras */
KERNEL_TEX(DecomposedTransform, __camera_motion)
@@ -54,6 +55,10 @@ KERNEL_TEX(KernelCurveSegment, __curve_segments)
/* patches */
KERNEL_TEX(uint, __patches)
+/* pointclouds */
+KERNEL_TEX(float4, __points)
+KERNEL_TEX(uint, __points_shader)
+
/* attributes */
KERNEL_TEX(uint4, __attributes_map)
KERNEL_TEX(float, __attributes_float)
diff --git a/intern/cycles/kernel/types.h b/intern/cycles/kernel/types.h
index 4a730dbfaaa..855cc97edbf 100644
--- a/intern/cycles/kernel/types.h
+++ b/intern/cycles/kernel/types.h
@@ -86,6 +86,7 @@ CCL_NAMESPACE_BEGIN
#define __AO__
#define __PASSES__
#define __HAIR__
+#define __POINTCLOUD__
#define __SVM__
#define __EMISSION__
#define __HOLDOUT__
@@ -110,9 +111,9 @@ CCL_NAMESPACE_BEGIN
# define __VOLUME_RECORD_ALL__
#endif /* __KERNEL_CPU__ */
-#ifdef __KERNEL_OPTIX__
+#ifdef __KERNEL_GPU_RAYTRACING__
# undef __BAKING__
-#endif /* __KERNEL_OPTIX__ */
+#endif /* __KERNEL_GPU_RAYTRACING__ */
/* Scene-based selective features compilation. */
#ifdef __KERNEL_FEATURES__
@@ -125,6 +126,9 @@ CCL_NAMESPACE_BEGIN
# if !(__KERNEL_FEATURES & KERNEL_FEATURE_HAIR)
# undef __HAIR__
# endif
+# if !(__KERNEL_FEATURES & KERNEL_FEATURE_POINTCLOUD)
+# undef __POINTCLOUD__
+# endif
# if !(__KERNEL_FEATURES & KERNEL_FEATURE_VOLUME)
# undef __VOLUME__
# endif
@@ -478,6 +482,7 @@ enum PanoramaType {
PANORAMA_FISHEYE_EQUIDISTANT = 1,
PANORAMA_FISHEYE_EQUISOLID = 2,
PANORAMA_MIRRORBALL = 3,
+ PANORAMA_FISHEYE_LENS_POLYNOMIAL = 4,
PANORAMA_NUM_TYPES,
};
@@ -537,19 +542,22 @@ typedef enum PrimitiveType {
PRIMITIVE_MOTION_CURVE_THICK = (1 << 3),
PRIMITIVE_CURVE_RIBBON = (1 << 4),
PRIMITIVE_MOTION_CURVE_RIBBON = (1 << 5),
- PRIMITIVE_VOLUME = (1 << 6),
- PRIMITIVE_LAMP = (1 << 7),
+ PRIMITIVE_POINT = (1 << 6),
+ PRIMITIVE_MOTION_POINT = (1 << 7),
+ PRIMITIVE_VOLUME = (1 << 8),
+ PRIMITIVE_LAMP = (1 << 9),
PRIMITIVE_ALL_TRIANGLE = (PRIMITIVE_TRIANGLE | PRIMITIVE_MOTION_TRIANGLE),
PRIMITIVE_ALL_CURVE = (PRIMITIVE_CURVE_THICK | PRIMITIVE_MOTION_CURVE_THICK |
PRIMITIVE_CURVE_RIBBON | PRIMITIVE_MOTION_CURVE_RIBBON),
+ PRIMITIVE_ALL_POINT = (PRIMITIVE_POINT | PRIMITIVE_MOTION_POINT),
PRIMITIVE_ALL_VOLUME = (PRIMITIVE_VOLUME),
PRIMITIVE_ALL_MOTION = (PRIMITIVE_MOTION_TRIANGLE | PRIMITIVE_MOTION_CURVE_THICK |
- PRIMITIVE_MOTION_CURVE_RIBBON),
+ PRIMITIVE_MOTION_CURVE_RIBBON | PRIMITIVE_MOTION_POINT),
PRIMITIVE_ALL = (PRIMITIVE_ALL_TRIANGLE | PRIMITIVE_ALL_CURVE | PRIMITIVE_ALL_VOLUME |
- PRIMITIVE_LAMP),
+ PRIMITIVE_LAMP | PRIMITIVE_ALL_POINT),
- PRIMITIVE_NUM = 8,
+ PRIMITIVE_NUM = 10,
} PrimitiveType;
#define PRIMITIVE_PACK_SEGMENT(type, segment) ((segment << PRIMITIVE_NUM) | (type))
@@ -604,6 +612,7 @@ typedef enum AttributeStandard {
ATTR_STD_CURVE_INTERCEPT,
ATTR_STD_CURVE_LENGTH,
ATTR_STD_CURVE_RANDOM,
+ ATTR_STD_POINT_RANDOM,
ATTR_STD_PTEX_FACE_ID,
ATTR_STD_PTEX_UV,
ATTR_STD_VOLUME_DENSITY,
@@ -922,6 +931,8 @@ typedef struct KernelCamera {
float fisheye_fov;
float fisheye_lens;
float4 equirectangular_range;
+ float fisheye_lens_polynomial_bias;
+ float4 fisheye_lens_polynomial_coefficients;
/* stereo */
float interocular_offset;
@@ -1204,7 +1215,7 @@ typedef struct KernelIntegrator {
/* Closure filter. */
int filter_closures;
- /* MIS debuging */
+ /* MIS debugging. */
int direct_light_sampling_type;
/* padding */
@@ -1220,10 +1231,13 @@ typedef enum KernelBVHLayout {
BVH_LAYOUT_OPTIX = (1 << 2),
BVH_LAYOUT_MULTI_OPTIX = (1 << 3),
BVH_LAYOUT_MULTI_OPTIX_EMBREE = (1 << 4),
+ BVH_LAYOUT_METAL = (1 << 5),
+ BVH_LAYOUT_MULTI_METAL = (1 << 6),
+ BVH_LAYOUT_MULTI_METAL_EMBREE = (1 << 7),
/* Default BVH layout to use for CPU. */
BVH_LAYOUT_AUTO = BVH_LAYOUT_EMBREE,
- BVH_LAYOUT_ALL = BVH_LAYOUT_BVH2 | BVH_LAYOUT_EMBREE | BVH_LAYOUT_OPTIX,
+ BVH_LAYOUT_ALL = BVH_LAYOUT_BVH2 | BVH_LAYOUT_EMBREE | BVH_LAYOUT_OPTIX | BVH_LAYOUT_METAL,
} KernelBVHLayout;
typedef struct KernelBVH {
@@ -1238,6 +1252,8 @@ typedef struct KernelBVH {
/* Custom BVH */
#ifdef __KERNEL_OPTIX__
OptixTraversableHandle scene;
+#elif defined __METALRT__
+ metalrt_as_type scene;
#else
# ifdef __EMBREE__
RTCScene scene;
@@ -1596,6 +1612,9 @@ enum KernelFeatureFlag : unsigned int {
KERNEL_FEATURE_AO_PASS = (1U << 25U),
KERNEL_FEATURE_AO_ADDITIVE = (1U << 26U),
KERNEL_FEATURE_AO = (KERNEL_FEATURE_AO_PASS | KERNEL_FEATURE_AO_ADDITIVE),
+
+ /* Point clouds. */
+ KERNEL_FEATURE_POINTCLOUD = (1U << 27U),
};
/* Shader node feature mask, to specialize shader evaluation for kernels. */
diff --git a/intern/cycles/scene/CMakeLists.txt b/intern/cycles/scene/CMakeLists.txt
index a3fde99306b..6f8b97a4998 100644
--- a/intern/cycles/scene/CMakeLists.txt
+++ b/intern/cycles/scene/CMakeLists.txt
@@ -40,6 +40,7 @@ set(SRC
mesh_displace.cpp
mesh_subdivision.cpp
procedural.cpp
+ pointcloud.cpp
object.cpp
osl.cpp
particles.cpp
@@ -81,6 +82,7 @@ set(SRC_HEADERS
particles.h
pass.h
procedural.h
+ pointcloud.h
curves.h
scene.h
shader.h
diff --git a/intern/cycles/scene/alembic.cpp b/intern/cycles/scene/alembic.cpp
index 39b5f467736..71fa1863b8b 100644
--- a/intern/cycles/scene/alembic.cpp
+++ b/intern/cycles/scene/alembic.cpp
@@ -21,6 +21,7 @@
#include "scene/curves.h"
#include "scene/mesh.h"
#include "scene/object.h"
+#include "scene/pointcloud.h"
#include "scene/scene.h"
#include "scene/shader.h"
@@ -99,6 +100,9 @@ void CachedData::clear()
triangles.clear();
uv_loops.clear();
vertices.clear();
+ points.clear();
+ radiuses.clear();
+ points_shader.clear();
for (CachedAttribute &attr : attributes) {
attr.data.clear();
@@ -146,6 +150,9 @@ bool CachedData::is_constant() const
CHECK_IF_CONSTANT(triangles)
CHECK_IF_CONSTANT(uv_loops)
CHECK_IF_CONSTANT(vertices)
+ CHECK_IF_CONSTANT(points)
+ CHECK_IF_CONSTANT(radiuses)
+ CHECK_IF_CONSTANT(points_shader)
for (const CachedAttribute &attr : attributes) {
if (!attr.data.is_constant()) {
@@ -185,6 +192,9 @@ void CachedData::invalidate_last_loaded_time(bool attributes_only)
triangles.invalidate_last_loaded_time();
uv_loops.invalidate_last_loaded_time();
vertices.invalidate_last_loaded_time();
+ points.invalidate_last_loaded_time();
+ radiuses.invalidate_last_loaded_time();
+ points_shader.invalidate_last_loaded_time();
}
void CachedData::set_time_sampling(TimeSampling time_sampling)
@@ -206,6 +216,9 @@ void CachedData::set_time_sampling(TimeSampling time_sampling)
triangles.set_time_sampling(time_sampling);
uv_loops.set_time_sampling(time_sampling);
vertices.set_time_sampling(time_sampling);
+ points.set_time_sampling(time_sampling);
+ radiuses.set_time_sampling(time_sampling);
+ points_shader.set_time_sampling(time_sampling);
for (CachedAttribute &attr : attributes) {
attr.data.set_time_sampling(time_sampling);
@@ -233,6 +246,9 @@ size_t CachedData::memory_used() const
mem_used += triangles.memory_used();
mem_used += uv_loops.memory_used();
mem_used += vertices.memory_used();
+ mem_used += points.memory_used();
+ mem_used += radiuses.memory_used();
+ mem_used += points_shader.memory_used();
for (const CachedAttribute &attr : attributes) {
mem_used += attr.data.memory_used();
@@ -901,6 +917,9 @@ void AlembicProcedural::generate(Scene *scene, Progress &progress)
else if (object->schema_type == AlembicObject::CURVES) {
read_curves(object, frame_time);
}
+ else if (object->schema_type == AlembicObject::POINTS) {
+ read_points(object, frame_time);
+ }
else if (object->schema_type == AlembicObject::SUBD) {
read_subd(object, frame_time);
}
@@ -970,6 +989,9 @@ void AlembicProcedural::load_objects(Progress &progress)
if (abc_object->schema_type == AlembicObject::CURVES) {
geometry = scene_->create_node<Hair>();
}
+ else if (abc_object->schema_type == AlembicObject::POINTS) {
+ geometry = scene_->create_node<PointCloud>();
+ }
else if (abc_object->schema_type == AlembicObject::POLY_MESH ||
abc_object->schema_type == AlembicObject::SUBD) {
geometry = scene_->create_node<Mesh>();
@@ -1202,6 +1224,45 @@ void AlembicProcedural::read_curves(AlembicObject *abc_object, Abc::chrono_t fra
hair->tag_update(scene_, rebuild);
}
+void AlembicProcedural::read_points(AlembicObject *abc_object, Abc::chrono_t frame_time)
+{
+ CachedData &cached_data = abc_object->get_cached_data();
+
+ /* update sockets */
+
+ Object *object = abc_object->get_object();
+ cached_data.transforms.copy_to_socket(frame_time, object, object->get_tfm_socket());
+
+ if (object->is_modified()) {
+ object->tag_update(scene_);
+ }
+
+ /* Only update sockets for the original Geometry. */
+ if (abc_object->instance_of) {
+ return;
+ }
+
+ PointCloud *point_cloud = static_cast<PointCloud *>(object->get_geometry());
+
+ /* Make sure shader ids are also updated. */
+ if (point_cloud->used_shaders_is_modified()) {
+ point_cloud->tag_shader_modified();
+ }
+
+ cached_data.points.copy_to_socket(frame_time, point_cloud, point_cloud->get_points_socket());
+ cached_data.radiuses.copy_to_socket(frame_time, point_cloud, point_cloud->get_radius_socket());
+ cached_data.points_shader.copy_to_socket(
+ frame_time, point_cloud, point_cloud->get_shader_socket());
+
+ /* update attributes */
+
+ update_attributes(point_cloud->attributes, cached_data, frame_time);
+
+ const bool rebuild = (point_cloud->points_is_modified() || point_cloud->radius_is_modified() ||
+ point_cloud->shader_is_modified());
+ point_cloud->tag_update(scene_, rebuild);
+}
+
void AlembicProcedural::walk_hierarchy(
IObject parent,
const ObjectHeader &header,
@@ -1314,7 +1375,23 @@ void AlembicProcedural::walk_hierarchy(
// ignore the face set, it will be read along with the data
}
else if (IPoints::matches(header)) {
- // unsupported for now
+ IPoints points(parent, header.getName());
+
+ unordered_map<std::string, AlembicObject *>::const_iterator iter;
+ iter = object_map.find(points.getFullName());
+
+ if (iter != object_map.end()) {
+ AlembicObject *abc_object = iter->second;
+ abc_object->iobject = points;
+ abc_object->schema_type = AlembicObject::POINTS;
+
+ if (matrix_samples_data.samples) {
+ abc_object->xform_samples = *matrix_samples_data.samples;
+ abc_object->xform_time_sampling = matrix_samples_data.time_sampling;
+ }
+ }
+
+ next_object = points;
}
else if (INuPatch::matches(header)) {
// unsupported for now
@@ -1391,6 +1468,14 @@ void AlembicProcedural::build_caches(Progress &progress)
object->load_data_in_cache(object->get_cached_data(), this, schema, progress);
}
}
+ else if (object->schema_type == AlembicObject::POINTS) {
+ if (!object->has_data_loaded() || default_radius_is_modified() ||
+ object->radius_scale_is_modified()) {
+ IPoints points(object->iobject, Alembic::Abc::kWrapExisting);
+ IPointsSchema schema = points.getSchema();
+ object->load_data_in_cache(object->get_cached_data(), this, schema, progress);
+ }
+ }
else if (object->schema_type == AlembicObject::SUBD) {
if (!object->has_data_loaded()) {
ISubD subd_mesh(object->iobject, Alembic::Abc::kWrapExisting);
diff --git a/intern/cycles/scene/alembic.h b/intern/cycles/scene/alembic.h
index 77aafd0ab32..3a4d37da3ff 100644
--- a/intern/cycles/scene/alembic.h
+++ b/intern/cycles/scene/alembic.h
@@ -327,6 +327,11 @@ struct CachedData {
DataStore<array<int>> curve_first_key;
DataStore<array<int>> curve_shader;
+ /* point data */
+ DataStore<array<float3>> points;
+ DataStore<array<float>> radiuses;
+ DataStore<array<int>> points_shader;
+
struct CachedAttribute {
AttributeStandard std;
AttributeElement element;
@@ -414,6 +419,7 @@ class AlembicObject : public Node {
POLY_MESH,
SUBD,
CURVES,
+ POINTS,
};
bool need_shader_update = true;
@@ -550,6 +556,10 @@ class AlembicProcedural : public Procedural {
* Object Nodes in the Cycles scene if none exist yet. */
void read_curves(AlembicObject *abc_object, Alembic::AbcGeom::Abc::chrono_t frame_time);
+ /* Read the data for an IPoints at the specified frame_time. Creates corresponding Geometry and
+ * Object Nodes in the Cycles scene if none exist yet. */
+ void read_points(AlembicObject *abc_object, Alembic::AbcGeom::Abc::chrono_t frame_time);
+
/* Read the data for an ISubD at the specified frame_time. Creates corresponding Geometry and
* Object Nodes in the Cycles scene if none exist yet. */
void read_subd(AlembicObject *abc_object, Alembic::AbcGeom::Abc::chrono_t frame_time);
diff --git a/intern/cycles/scene/alembic_read.cpp b/intern/cycles/scene/alembic_read.cpp
index 35f4854127a..07874b7528e 100644
--- a/intern/cycles/scene/alembic_read.cpp
+++ b/intern/cycles/scene/alembic_read.cpp
@@ -609,6 +609,55 @@ void read_geometry_data(AlembicProcedural *proc,
read_data_loop(proc, cached_data, data, read_curves_data, progress);
}
+/* Points Geometries. */
+
+static void read_points_data(CachedData &cached_data, const PointsSchemaData &data, chrono_t time)
+{
+ const ISampleSelector iss = ISampleSelector(time);
+
+ const P3fArraySamplePtr position = data.positions.getValue(iss);
+ FloatArraySamplePtr radiuses;
+
+ array<float3> a_positions;
+ array<float> a_radius;
+ array<int> a_shader;
+ a_positions.reserve(position->size());
+ a_radius.reserve(position->size());
+ a_shader.reserve(position->size());
+
+ if (data.radiuses.valid()) {
+ IFloatGeomParam::Sample wsample = data.radiuses.getExpandedValue(iss);
+ radiuses = wsample.getVals();
+ }
+
+ const bool do_radius = (radiuses != nullptr) && (radiuses->size() > 1);
+ float radius = (radiuses && radiuses->size() == 1) ? (*radiuses)[0] : data.default_radius;
+
+ int offset = 0;
+ for (size_t i = 0; i < position->size(); i++) {
+ const V3f &f = position->get()[offset + i];
+ a_positions.push_back_slow(make_float3_from_yup(f));
+
+ if (do_radius) {
+ radius = (*radiuses)[offset + i];
+ a_radius.push_back_slow(radius);
+ }
+
+ a_shader.push_back_slow((int)0);
+ }
+
+ cached_data.points.add_data(a_positions, time);
+ cached_data.radiuses.add_data(a_radius, time);
+ cached_data.points_shader.add_data(a_shader, time);
+}
+
+void read_geometry_data(AlembicProcedural *proc,
+ CachedData &cached_data,
+ const PointsSchemaData &data,
+ Progress &progress)
+{
+ read_data_loop(proc, cached_data, data, read_points_data, progress);
+}
/* Attributes conversions. */
/* Type traits for converting between Alembic and Cycles types.
diff --git a/intern/cycles/scene/alembic_read.h b/intern/cycles/scene/alembic_read.h
index 6b656b59481..e95750ce691 100644
--- a/intern/cycles/scene/alembic_read.h
+++ b/intern/cycles/scene/alembic_read.h
@@ -122,6 +122,26 @@ void read_geometry_data(AlembicProcedural *proc,
const CurvesSchemaData &data,
Progress &progress);
+/* Data of a ICurvesSchema that we need to read. */
+struct PointsSchemaData {
+ Alembic::AbcGeom::TimeSamplingPtr time_sampling;
+ size_t num_samples;
+
+ float default_radius;
+ float radius_scale;
+
+ Alembic::AbcGeom::IP3fArrayProperty positions;
+ Alembic::AbcGeom::IInt32ArrayProperty num_points;
+ Alembic::AbcGeom::IFloatGeomParam radiuses;
+ // Those are unsupported for now.
+ Alembic::AbcGeom::IV3fArrayProperty velocities;
+};
+
+void read_geometry_data(AlembicProcedural *proc,
+ CachedData &cached_data,
+ const PointsSchemaData &data,
+ Progress &progress);
+
void read_attributes(AlembicProcedural *proc,
CachedData &cache,
const Alembic::AbcGeom::ICompoundProperty &arb_geom_params,
diff --git a/intern/cycles/scene/attribute.cpp b/intern/cycles/scene/attribute.cpp
index 6d15f3325f7..f1021a26e8a 100644
--- a/intern/cycles/scene/attribute.cpp
+++ b/intern/cycles/scene/attribute.cpp
@@ -18,6 +18,7 @@
#include "scene/hair.h"
#include "scene/image.h"
#include "scene/mesh.h"
+#include "scene/pointcloud.h"
#include "util/foreach.h"
#include "util/log.h"
@@ -205,6 +206,10 @@ size_t Attribute::element_size(Geometry *geom, AttributePrimitive prim) const
size -= mesh->get_num_subd_verts();
}
}
+ else if (geom->geometry_type == Geometry::POINTCLOUD) {
+ PointCloud *pointcloud = static_cast<PointCloud *>(geom);
+ size = pointcloud->num_points();
+ }
break;
case ATTR_ELEMENT_VERTEX_MOTION:
if (geom->geometry_type == Geometry::MESH) {
@@ -215,6 +220,10 @@ size_t Attribute::element_size(Geometry *geom, AttributePrimitive prim) const
size -= mesh->get_num_subd_verts() * (mesh->get_motion_steps() - 1);
}
}
+ else if (geom->geometry_type == Geometry::POINTCLOUD) {
+ PointCloud *pointcloud = static_cast<PointCloud *>(geom);
+ size = pointcloud->num_points() * (pointcloud->get_motion_steps() - 1);
+ }
break;
case ATTR_ELEMENT_FACE:
if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
@@ -346,6 +355,8 @@ const char *Attribute::standard_name(AttributeStandard std)
return "curve_length";
case ATTR_STD_CURVE_RANDOM:
return "curve_random";
+ case ATTR_STD_POINT_RANDOM:
+ return "point_random";
case ATTR_STD_PTEX_FACE_ID:
return "ptex_face_id";
case ATTR_STD_PTEX_UV:
@@ -555,6 +566,28 @@ Attribute *AttributeSet::add(AttributeStandard std, ustring name)
break;
}
}
+ else if (geometry->geometry_type == Geometry::POINTCLOUD) {
+ switch (std) {
+ case ATTR_STD_UV:
+ attr = add(name, TypeFloat2, ATTR_ELEMENT_VERTEX);
+ break;
+ case ATTR_STD_GENERATED:
+ attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX);
+ break;
+ case ATTR_STD_MOTION_VERTEX_POSITION:
+ attr = add(name, TypeDesc::TypeFloat4, ATTR_ELEMENT_VERTEX_MOTION);
+ break;
+ case ATTR_STD_POINT_RANDOM:
+ attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_VERTEX);
+ break;
+ case ATTR_STD_GENERATED_TRANSFORM:
+ attr = add(name, TypeDesc::TypeMatrix, ATTR_ELEMENT_MESH);
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ }
else if (geometry->geometry_type == Geometry::VOLUME) {
switch (std) {
case ATTR_STD_VERTEX_NORMAL:
diff --git a/intern/cycles/scene/camera.cpp b/intern/cycles/scene/camera.cpp
index 5bafe736fb5..2f3b55f887f 100644
--- a/intern/cycles/scene/camera.cpp
+++ b/intern/cycles/scene/camera.cpp
@@ -100,6 +100,7 @@ NODE_DEFINE(Camera)
panorama_type_enum.insert("mirrorball", PANORAMA_MIRRORBALL);
panorama_type_enum.insert("fisheye_equidistant", PANORAMA_FISHEYE_EQUIDISTANT);
panorama_type_enum.insert("fisheye_equisolid", PANORAMA_FISHEYE_EQUISOLID);
+ panorama_type_enum.insert("fisheye_lens_polynomial", PANORAMA_FISHEYE_LENS_POLYNOMIAL);
SOCKET_ENUM(panorama_type, "Panorama Type", panorama_type_enum, PANORAMA_EQUIRECTANGULAR);
SOCKET_FLOAT(fisheye_fov, "Fisheye FOV", M_PI_F);
@@ -112,6 +113,12 @@ NODE_DEFINE(Camera)
SOCKET_FLOAT(fov_pre, "FOV Pre", M_PI_4_F);
SOCKET_FLOAT(fov_post, "FOV Post", M_PI_4_F);
+ SOCKET_FLOAT(fisheye_polynomial_k0, "Fisheye Polynomial K0", 0.0f);
+ SOCKET_FLOAT(fisheye_polynomial_k1, "Fisheye Polynomial K1", 0.0f);
+ SOCKET_FLOAT(fisheye_polynomial_k2, "Fisheye Polynomial K2", 0.0f);
+ SOCKET_FLOAT(fisheye_polynomial_k3, "Fisheye Polynomial K3", 0.0f);
+ SOCKET_FLOAT(fisheye_polynomial_k4, "Fisheye Polynomial K4", 0.0f);
+
static NodeEnum stereo_eye_enum;
stereo_eye_enum.insert("none", STEREO_NONE);
stereo_eye_enum.insert("left", STEREO_LEFT);
@@ -418,6 +425,9 @@ void Camera::update(Scene *scene)
-longitude_min,
latitude_min - latitude_max,
-latitude_min + M_PI_2_F);
+ kcam->fisheye_lens_polynomial_bias = fisheye_polynomial_k0;
+ kcam->fisheye_lens_polynomial_coefficients = make_float4(
+ fisheye_polynomial_k1, fisheye_polynomial_k2, fisheye_polynomial_k3, fisheye_polynomial_k4);
switch (stereo_eye) {
case STEREO_LEFT:
diff --git a/intern/cycles/scene/camera.h b/intern/cycles/scene/camera.h
index 58e39599267..50586287bea 100644
--- a/intern/cycles/scene/camera.h
+++ b/intern/cycles/scene/camera.h
@@ -105,6 +105,12 @@ class Camera : public Node {
NODE_SOCKET_API(float, longitude_min)
NODE_SOCKET_API(float, longitude_max)
+ NODE_SOCKET_API(float, fisheye_polynomial_k0)
+ NODE_SOCKET_API(float, fisheye_polynomial_k1)
+ NODE_SOCKET_API(float, fisheye_polynomial_k2)
+ NODE_SOCKET_API(float, fisheye_polynomial_k3)
+ NODE_SOCKET_API(float, fisheye_polynomial_k4)
+
/* panorama stereo */
NODE_SOCKET_API(StereoEye, stereo_eye)
NODE_SOCKET_API(bool, use_spherical_stereo)
diff --git a/intern/cycles/scene/geometry.cpp b/intern/cycles/scene/geometry.cpp
index bf426fc49f6..558b0e13b0f 100644
--- a/intern/cycles/scene/geometry.cpp
+++ b/intern/cycles/scene/geometry.cpp
@@ -26,6 +26,7 @@
#include "scene/light.h"
#include "scene/mesh.h"
#include "scene/object.h"
+#include "scene/pointcloud.h"
#include "scene/scene.h"
#include "scene/shader.h"
#include "scene/shader_nodes.h"
@@ -165,7 +166,8 @@ int Geometry::motion_step(float time) const
bool Geometry::need_build_bvh(BVHLayout layout) const
{
return is_instanced() || layout == BVH_LAYOUT_OPTIX || layout == BVH_LAYOUT_MULTI_OPTIX ||
- layout == BVH_LAYOUT_MULTI_OPTIX_EMBREE;
+ layout == BVH_LAYOUT_METAL || layout == BVH_LAYOUT_MULTI_OPTIX_EMBREE ||
+ layout == BVH_LAYOUT_MULTI_METAL || layout == BVH_LAYOUT_MULTI_METAL_EMBREE;
}
bool Geometry::is_instanced() const
@@ -239,6 +241,7 @@ void Geometry::compute_bvh(
params->use_bvh_unaligned_nodes;
bparams.num_motion_triangle_steps = params->num_bvh_time_steps;
bparams.num_motion_curve_steps = params->num_bvh_time_steps;
+ bparams.num_motion_point_steps = params->num_bvh_time_steps;
bparams.bvh_type = params->bvh_type;
bparams.curve_subdivisions = params->curve_subdivisions();
@@ -722,6 +725,12 @@ void GeometryManager::update_attribute_element_offset(Geometry *geom,
else if (element == ATTR_ELEMENT_CURVE_KEY_MOTION)
offset -= hair->curve_key_offset;
}
+ else if (geom->is_pointcloud()) {
+ if (element == ATTR_ELEMENT_VERTEX)
+ offset -= geom->prim_offset;
+ else if (element == ATTR_ELEMENT_VERTEX_MOTION)
+ offset -= geom->prim_offset;
+ }
}
else {
/* attribute not found */
@@ -1005,6 +1014,8 @@ void GeometryManager::mesh_calc_offset(Scene *scene, BVHLayout bvh_layout)
size_t curve_key_size = 0;
size_t curve_segment_size = 0;
+ size_t point_size = 0;
+
size_t patch_size = 0;
size_t face_size = 0;
size_t corner_size = 0;
@@ -1053,6 +1064,14 @@ void GeometryManager::mesh_calc_offset(Scene *scene, BVHLayout bvh_layout)
curve_key_size += hair->get_curve_keys().size();
curve_segment_size += hair->num_segments();
}
+ else if (geom->is_pointcloud()) {
+ PointCloud *pointcloud = static_cast<PointCloud *>(geom);
+
+ prim_offset_changed = (pointcloud->prim_offset != point_size);
+
+ pointcloud->prim_offset = point_size;
+ point_size += pointcloud->num_points();
+ }
if (prim_offset_changed) {
/* Need to rebuild BVH in OptiX, since refit only allows modified mesh data there */
@@ -1078,6 +1097,8 @@ void GeometryManager::device_update_mesh(Device *,
size_t curve_size = 0;
size_t curve_segment_size = 0;
+ size_t point_size = 0;
+
size_t patch_size = 0;
foreach (Geometry *geom, scene->geometry) {
@@ -1105,6 +1126,10 @@ void GeometryManager::device_update_mesh(Device *,
curve_size += hair->num_curves();
curve_segment_size += hair->num_segments();
}
+ else if (geom->is_pointcloud()) {
+ PointCloud *pointcloud = static_cast<PointCloud *>(geom);
+ point_size += pointcloud->num_points();
+ }
}
/* Fill in all the arrays. */
@@ -1200,6 +1225,26 @@ void GeometryManager::device_update_mesh(Device *,
dscene->curve_segments.copy_to_device_if_modified();
}
+ if (point_size != 0) {
+ progress.set_status("Updating Mesh", "Copying Point clouds to device");
+
+ float4 *points = dscene->points.alloc(point_size);
+ uint *points_shader = dscene->points_shader.alloc(point_size);
+
+ foreach (Geometry *geom, scene->geometry) {
+ if (geom->is_pointcloud()) {
+ PointCloud *pointcloud = static_cast<PointCloud *>(geom);
+ pointcloud->pack(
+ scene, &points[pointcloud->prim_offset], &points_shader[pointcloud->prim_offset]);
+ if (progress.get_cancel())
+ return;
+ }
+ }
+
+ dscene->points.copy_to_device();
+ dscene->points_shader.copy_to_device();
+ }
+
if (patch_size != 0 && dscene->patches.need_realloc()) {
progress.set_status("Updating Mesh", "Copying Patches to device");
@@ -1241,13 +1286,15 @@ void GeometryManager::device_update_bvh(Device *device,
scene->params.use_bvh_unaligned_nodes;
bparams.num_motion_triangle_steps = scene->params.num_bvh_time_steps;
bparams.num_motion_curve_steps = scene->params.num_bvh_time_steps;
+ bparams.num_motion_point_steps = scene->params.num_bvh_time_steps;
bparams.bvh_type = scene->params.bvh_type;
bparams.curve_subdivisions = scene->params.curve_subdivisions();
VLOG(1) << "Using " << bvh_layout_name(bparams.bvh_layout) << " layout.";
const bool can_refit = scene->bvh != nullptr &&
- (bparams.bvh_layout == BVHLayout::BVH_LAYOUT_OPTIX);
+ (bparams.bvh_layout == BVHLayout::BVH_LAYOUT_OPTIX ||
+ bparams.bvh_layout == BVHLayout::BVH_LAYOUT_METAL);
BVH *bvh = scene->bvh;
if (!scene->bvh) {
@@ -1321,6 +1368,7 @@ void GeometryManager::device_update_bvh(Device *device,
enum {
DEVICE_CURVE_DATA_MODIFIED = (1 << 0),
DEVICE_MESH_DATA_MODIFIED = (1 << 1),
+ DEVICE_POINT_DATA_MODIFIED = (1 << 2),
ATTR_FLOAT_MODIFIED = (1 << 2),
ATTR_FLOAT2_MODIFIED = (1 << 3),
@@ -1330,17 +1378,20 @@ enum {
CURVE_DATA_NEED_REALLOC = (1 << 7),
MESH_DATA_NEED_REALLOC = (1 << 8),
+ POINT_DATA_NEED_REALLOC = (1 << 9),
+
+ ATTR_FLOAT_NEEDS_REALLOC = (1 << 10),
+ ATTR_FLOAT2_NEEDS_REALLOC = (1 << 11),
+ ATTR_FLOAT3_NEEDS_REALLOC = (1 << 12),
+ ATTR_FLOAT4_NEEDS_REALLOC = (1 << 13),
- ATTR_FLOAT_NEEDS_REALLOC = (1 << 9),
- ATTR_FLOAT2_NEEDS_REALLOC = (1 << 10),
- ATTR_FLOAT3_NEEDS_REALLOC = (1 << 11),
- ATTR_FLOAT4_NEEDS_REALLOC = (1 << 12),
- ATTR_UCHAR4_NEEDS_REALLOC = (1 << 13),
+ ATTR_UCHAR4_NEEDS_REALLOC = (1 << 14),
ATTRS_NEED_REALLOC = (ATTR_FLOAT_NEEDS_REALLOC | ATTR_FLOAT2_NEEDS_REALLOC |
ATTR_FLOAT3_NEEDS_REALLOC | ATTR_FLOAT4_NEEDS_REALLOC |
ATTR_UCHAR4_NEEDS_REALLOC),
DEVICE_MESH_DATA_NEEDS_REALLOC = (MESH_DATA_NEED_REALLOC | ATTRS_NEED_REALLOC),
+ DEVICE_POINT_DATA_NEEDS_REALLOC = (POINT_DATA_NEED_REALLOC | ATTRS_NEED_REALLOC),
DEVICE_CURVE_DATA_NEEDS_REALLOC = (CURVE_DATA_NEED_REALLOC | ATTRS_NEED_REALLOC),
};
@@ -1527,6 +1578,17 @@ void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Pro
device_update_flags |= DEVICE_MESH_DATA_MODIFIED;
}
}
+
+ if (geom->is_pointcloud()) {
+ PointCloud *pointcloud = static_cast<PointCloud *>(geom);
+
+ if (pointcloud->need_update_rebuild) {
+ device_update_flags |= DEVICE_POINT_DATA_NEEDS_REALLOC;
+ }
+ else if (pointcloud->is_modified()) {
+ device_update_flags |= DEVICE_POINT_DATA_MODIFIED;
+ }
+ }
}
if (update_flags & (MESH_ADDED | MESH_REMOVED)) {
@@ -1537,10 +1599,15 @@ void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Pro
device_update_flags |= DEVICE_CURVE_DATA_NEEDS_REALLOC;
}
+ if (update_flags & (POINT_ADDED | POINT_REMOVED)) {
+ device_update_flags |= DEVICE_POINT_DATA_NEEDS_REALLOC;
+ }
+
/* tag the device arrays for reallocation or modification */
DeviceScene *dscene = &scene->dscene;
- if (device_update_flags & (DEVICE_MESH_DATA_NEEDS_REALLOC | DEVICE_CURVE_DATA_NEEDS_REALLOC)) {
+ if (device_update_flags & (DEVICE_MESH_DATA_NEEDS_REALLOC | DEVICE_CURVE_DATA_NEEDS_REALLOC |
+ DEVICE_POINT_DATA_NEEDS_REALLOC)) {
delete scene->bvh;
scene->bvh = nullptr;
@@ -1568,6 +1635,11 @@ void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Pro
dscene->curve_keys.tag_realloc();
dscene->curve_segments.tag_realloc();
}
+
+ if (device_update_flags & DEVICE_POINT_DATA_NEEDS_REALLOC) {
+ dscene->points.tag_realloc();
+ dscene->points_shader.tag_realloc();
+ }
}
if ((update_flags & VISIBILITY_MODIFIED) != 0) {
@@ -1628,6 +1700,11 @@ void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Pro
dscene->curve_segments.tag_modified();
}
+ if (device_update_flags & DEVICE_POINT_DATA_MODIFIED) {
+ dscene->points.tag_modified();
+ dscene->points_shader.tag_modified();
+ }
+
need_flags_update = false;
}
@@ -2062,6 +2139,8 @@ void GeometryManager::device_update(Device *device,
dscene->curves.clear_modified();
dscene->curve_keys.clear_modified();
dscene->curve_segments.clear_modified();
+ dscene->points.clear_modified();
+ dscene->points_shader.clear_modified();
dscene->patches.clear_modified();
dscene->attributes_map.clear_modified();
dscene->attributes_float.clear_modified();
@@ -2090,6 +2169,8 @@ void GeometryManager::device_free(Device *device, DeviceScene *dscene, bool forc
dscene->curves.free_if_need_realloc(force_free);
dscene->curve_keys.free_if_need_realloc(force_free);
dscene->curve_segments.free_if_need_realloc(force_free);
+ dscene->points.free_if_need_realloc(force_free);
+ dscene->points_shader.free_if_need_realloc(force_free);
dscene->patches.free_if_need_realloc(force_free);
dscene->attributes_map.free_if_need_realloc(force_free);
dscene->attributes_float.free_if_need_realloc(force_free);
diff --git a/intern/cycles/scene/geometry.h b/intern/cycles/scene/geometry.h
index 91799d7fde8..b02387c3020 100644
--- a/intern/cycles/scene/geometry.h
+++ b/intern/cycles/scene/geometry.h
@@ -55,6 +55,7 @@ class Geometry : public Node {
MESH,
HAIR,
VOLUME,
+ POINTCLOUD,
};
Type geometry_type;
@@ -155,6 +156,11 @@ class Geometry : public Node {
return geometry_type == HAIR;
}
+ bool is_pointcloud() const
+ {
+ return geometry_type == POINTCLOUD;
+ }
+
bool is_volume() const
{
return geometry_type == VOLUME;
@@ -181,12 +187,14 @@ class GeometryManager {
MESH_REMOVED = (1 << 5),
HAIR_ADDED = (1 << 6),
HAIR_REMOVED = (1 << 7),
+ POINT_ADDED = (1 << 12),
+ POINT_REMOVED = (1 << 13),
SHADER_ATTRIBUTE_MODIFIED = (1 << 8),
SHADER_DISPLACEMENT_MODIFIED = (1 << 9),
- GEOMETRY_ADDED = MESH_ADDED | HAIR_ADDED,
- GEOMETRY_REMOVED = MESH_REMOVED | HAIR_REMOVED,
+ GEOMETRY_ADDED = MESH_ADDED | HAIR_ADDED | POINT_ADDED,
+ GEOMETRY_REMOVED = MESH_REMOVED | HAIR_REMOVED | POINT_REMOVED,
TRANSFORM_MODIFIED = (1 << 10),
diff --git a/intern/cycles/scene/integrator.cpp b/intern/cycles/scene/integrator.cpp
index 31e645c1f3a..31901707c35 100644
--- a/intern/cycles/scene/integrator.cpp
+++ b/intern/cycles/scene/integrator.cpp
@@ -180,7 +180,7 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene
kintegrator->transparent_min_bounce = transparent_min_bounce + 1;
kintegrator->transparent_max_bounce = transparent_max_bounce + 1;
- kintegrator->ao_bounces = ao_bounces;
+ kintegrator->ao_bounces = (ao_factor != 0.0f) ? ao_bounces : 0;
kintegrator->ao_bounces_distance = ao_distance;
kintegrator->ao_bounces_factor = ao_factor;
kintegrator->ao_additive_factor = ao_additive_factor;
diff --git a/intern/cycles/scene/object.cpp b/intern/cycles/scene/object.cpp
index 69a2365f17c..f8110b20d6e 100644
--- a/intern/cycles/scene/object.cpp
+++ b/intern/cycles/scene/object.cpp
@@ -23,6 +23,7 @@
#include "scene/light.h"
#include "scene/mesh.h"
#include "scene/particles.h"
+#include "scene/pointcloud.h"
#include "scene/scene.h"
#include "scene/stats.h"
#include "scene/volume.h"
@@ -69,6 +70,7 @@ struct UpdateObjectTransformState {
/* Flags which will be synchronized to Integrator. */
bool have_motion;
bool have_curves;
+ // bool have_points;
/* ** Scheduling queue. ** */
Scene *scene;
@@ -435,7 +437,7 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s
state->have_motion = true;
}
- if (geom->geometry_type == Geometry::MESH) {
+ if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::POINTCLOUD) {
/* TODO: why only mesh? */
Mesh *mesh = static_cast<Mesh *>(geom);
if (mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)) {
@@ -491,6 +493,8 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s
kobject.dupli_generated[2] = ob->dupli_generated[2];
kobject.numkeys = (geom->geometry_type == Geometry::HAIR) ?
static_cast<Hair *>(geom)->get_curve_keys().size() :
+ (geom->geometry_type == Geometry::POINTCLOUD) ?
+ static_cast<PointCloud *>(geom)->num_points() :
0;
kobject.dupli_uv[0] = ob->dupli_uv[0];
kobject.dupli_uv[1] = ob->dupli_uv[1];
@@ -530,6 +534,35 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s
}
}
+void ObjectManager::device_update_prim_offsets(Device *device, DeviceScene *dscene, Scene *scene)
+{
+ BVHLayoutMask layout_mask = device->get_bvh_layout_mask();
+ if (layout_mask != BVH_LAYOUT_METAL && layout_mask != BVH_LAYOUT_MULTI_METAL &&
+ layout_mask != BVH_LAYOUT_MULTI_METAL_EMBREE) {
+ return;
+ }
+
+ /* On MetalRT, primitive / curve segment offsets can't be baked at BVH build time. Intersection
+ * handlers need to apply the offset manually. */
+ uint *object_prim_offset = dscene->object_prim_offset.alloc(scene->objects.size());
+ foreach (Object *ob, scene->objects) {
+ uint32_t prim_offset = 0;
+ if (Geometry *const geom = ob->geometry) {
+ if (geom->geometry_type == Geometry::HAIR) {
+ prim_offset = ((Hair *const)geom)->curve_segment_offset;
+ }
+ else {
+ prim_offset = geom->prim_offset;
+ }
+ }
+ uint obj_index = ob->get_device_index();
+ object_prim_offset[obj_index] = prim_offset;
+ }
+
+ dscene->object_prim_offset.copy_to_device();
+ dscene->object_prim_offset.clear_modified();
+}
+
void ObjectManager::device_update_transforms(DeviceScene *dscene, Scene *scene, Progress &progress)
{
UpdateObjectTransformState state;
@@ -840,6 +873,7 @@ void ObjectManager::device_free(Device *, DeviceScene *dscene, bool force_free)
dscene->object_motion.free_if_need_realloc(force_free);
dscene->object_flag.free_if_need_realloc(force_free);
dscene->object_volume_step.free_if_need_realloc(force_free);
+ dscene->object_prim_offset.free_if_need_realloc(force_free);
}
void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, Progress &progress)
diff --git a/intern/cycles/scene/object.h b/intern/cycles/scene/object.h
index f6dc57ee8b9..f983b58b59c 100644
--- a/intern/cycles/scene/object.h
+++ b/intern/cycles/scene/object.h
@@ -155,6 +155,7 @@ class ObjectManager {
void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress);
void device_update_transforms(DeviceScene *dscene, Scene *scene, Progress &progress);
+ void device_update_prim_offsets(Device *device, DeviceScene *dscene, Scene *scene);
void device_update_flags(Device *device,
DeviceScene *dscene,
diff --git a/intern/cycles/scene/pointcloud.cpp b/intern/cycles/scene/pointcloud.cpp
new file mode 100644
index 00000000000..4f88fe9db3d
--- /dev/null
+++ b/intern/cycles/scene/pointcloud.cpp
@@ -0,0 +1,304 @@
+/*
+ * Copyright 2011-2020 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bvh/bvh.h"
+
+#include "scene/pointcloud.h"
+#include "scene/scene.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* PointCloud Point */
+
+void PointCloud::Point::bounds_grow(const float3 *points,
+ const float *radius,
+ BoundBox &bounds) const
+{
+ bounds.grow(points[index], radius[index]);
+}
+
+void PointCloud::Point::bounds_grow(const float3 *points,
+ const float *radius,
+ const Transform &aligned_space,
+ BoundBox &bounds) const
+{
+ float3 P = transform_point(&aligned_space, points[index]);
+ bounds.grow(P, radius[index]);
+}
+
+void PointCloud::Point::bounds_grow(const float4 &point, BoundBox &bounds) const
+{
+ bounds.grow(float4_to_float3(point), point.w);
+}
+
+float4 PointCloud::Point::motion_key(const float3 *points,
+ const float *radius,
+ const float3 *point_steps,
+ size_t num_points,
+ size_t num_steps,
+ float time,
+ size_t p) const
+{
+ /* Figure out which steps we need to fetch and their
+ * interpolation factor. */
+ const size_t max_step = num_steps - 1;
+ const size_t step = min((int)(time * max_step), max_step - 1);
+ const float t = time * max_step - step;
+ /* Fetch vertex coordinates. */
+ const float4 curr_key = point_for_step(
+ points, radius, point_steps, num_points, num_steps, step, p);
+ const float4 next_key = point_for_step(
+ points, radius, point_steps, num_points, num_steps, step + 1, p);
+ /* Interpolate between steps. */
+ return (1.0f - t) * curr_key + t * next_key;
+}
+
+float4 PointCloud::Point::point_for_step(const float3 *points,
+ const float *radius,
+ const float3 *point_steps,
+ size_t num_points,
+ size_t num_steps,
+ size_t step,
+ size_t p) const
+{
+ const size_t center_step = ((num_steps - 1) / 2);
+ if (step == center_step) {
+ /* Center step: regular key location. */
+ return make_float4(points[p].x, points[p].y, points[p].z, radius[p]);
+ }
+ else {
+ /* Center step is not stored in this array. */
+ if (step > center_step) {
+ step--;
+ }
+ const size_t offset = step * num_points;
+ return make_float4(point_steps[offset + p].x,
+ point_steps[offset + p].y,
+ point_steps[offset + p].z,
+ radius[offset + p]);
+ }
+}
+
+/* PointCloud */
+
+NODE_DEFINE(PointCloud)
+{
+ NodeType *type = NodeType::add(
+ "pointcloud", create, NodeType::NONE, Geometry::get_node_base_type());
+
+ SOCKET_POINT_ARRAY(points, "Points", array<float3>());
+ SOCKET_FLOAT_ARRAY(radius, "Radius", array<float>());
+ SOCKET_INT_ARRAY(shader, "Shader", array<int>());
+
+ return type;
+}
+
+PointCloud::PointCloud() : Geometry(node_type, Geometry::POINTCLOUD)
+{
+}
+
+PointCloud::~PointCloud()
+{
+}
+
+void PointCloud::resize(int numpoints)
+{
+ points.resize(numpoints);
+ radius.resize(numpoints);
+ shader.resize(numpoints);
+ attributes.resize();
+
+ tag_points_modified();
+ tag_radius_modified();
+ tag_shader_modified();
+}
+
+void PointCloud::reserve(int numpoints)
+{
+ points.reserve(numpoints);
+ radius.reserve(numpoints);
+ shader.reserve(numpoints);
+ attributes.resize(true);
+}
+
+void PointCloud::clear(const bool preserve_shaders)
+{
+ Geometry::clear(preserve_shaders);
+
+ points.clear();
+ radius.clear();
+ shader.clear();
+ attributes.clear();
+
+ tag_points_modified();
+ tag_radius_modified();
+ tag_shader_modified();
+}
+
+void PointCloud::add_point(float3 co, float r, int shader_index)
+{
+ points.push_back_reserved(co);
+ radius.push_back_reserved(r);
+ shader.push_back_reserved(shader_index);
+
+ tag_points_modified();
+ tag_radius_modified();
+ tag_shader_modified();
+}
+
+void PointCloud::copy_center_to_motion_step(const int motion_step)
+{
+ Attribute *attr_mP = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ if (attr_mP) {
+ float3 *points_data = points.data();
+ size_t numpoints = points.size();
+ memcpy(
+ attr_mP->data_float3() + motion_step * numpoints, points_data, sizeof(float3) * numpoints);
+ }
+}
+
+void PointCloud::get_uv_tiles(ustring map, unordered_set<int> &tiles)
+{
+ Attribute *attr;
+
+ if (map.empty()) {
+ attr = attributes.find(ATTR_STD_UV);
+ }
+ else {
+ attr = attributes.find(map);
+ }
+
+ if (attr) {
+ attr->get_uv_tiles(this, ATTR_PRIM_GEOMETRY, tiles);
+ }
+}
+
+void PointCloud::compute_bounds()
+{
+ BoundBox bnds = BoundBox::empty;
+ size_t numpoints = points.size();
+
+ if (numpoints > 0) {
+ for (size_t i = 0; i < numpoints; i++) {
+ bnds.grow(points[i], radius[i]);
+ }
+
+ Attribute *attr = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ if (use_motion_blur && attr) {
+ size_t steps_size = points.size() * (motion_steps - 1);
+ float3 *point_steps = attr->data_float3();
+
+ for (size_t i = 0; i < steps_size; i++)
+ bnds.grow(point_steps[i]);
+ }
+
+ if (!bnds.valid()) {
+ bnds = BoundBox::empty;
+
+ /* skip nan or inf coordinates */
+ for (size_t i = 0; i < numpoints; i++)
+ bnds.grow_safe(points[i], radius[i]);
+
+ if (use_motion_blur && attr) {
+ size_t steps_size = points.size() * (motion_steps - 1);
+ float3 *point_steps = attr->data_float3();
+
+ for (size_t i = 0; i < steps_size; i++)
+ bnds.grow_safe(point_steps[i]);
+ }
+ }
+ }
+
+ if (!bnds.valid()) {
+ /* empty mesh */
+ bnds.grow(make_float3(0.0f, 0.0f, 0.0f));
+ }
+
+ bounds = bnds;
+}
+
+void PointCloud::apply_transform(const Transform &tfm, const bool apply_to_motion)
+{
+ /* compute uniform scale */
+ float3 c0 = transform_get_column(&tfm, 0);
+ float3 c1 = transform_get_column(&tfm, 1);
+ float3 c2 = transform_get_column(&tfm, 2);
+ float scalar = powf(fabsf(dot(cross(c0, c1), c2)), 1.0f / 3.0f);
+
+ /* apply transform to curve keys */
+ for (size_t i = 0; i < points.size(); i++) {
+ float3 co = transform_point(&tfm, points[i]);
+ float r = radius[i] * scalar;
+
+ /* scale for curve radius is only correct for uniform scale
+ */
+ points[i] = co;
+ radius[i] = r;
+ }
+
+ if (apply_to_motion) {
+ Attribute *attr = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+
+ if (attr) {
+ /* apply transform to motion curve keys */
+ size_t steps_size = points.size() * (motion_steps - 1);
+ float4 *point_steps = attr->data_float4();
+
+ for (size_t i = 0; i < steps_size; i++) {
+ float3 co = transform_point(&tfm, float4_to_float3(point_steps[i]));
+ float radius = point_steps[i].w * scalar;
+
+ /* scale for curve radius is only correct for uniform
+ * scale */
+ point_steps[i] = float3_to_float4(co);
+ point_steps[i].w = radius;
+ }
+ }
+ }
+}
+
+void PointCloud::pack(Scene *scene, float4 *packed_points, uint *packed_shader)
+{
+ size_t numpoints = points.size();
+ float3 *points_data = points.data();
+ float *radius_data = radius.data();
+ int *shader_data = shader.data();
+
+ for (size_t i = 0; i < numpoints; i++) {
+ packed_points[i] = make_float4(
+ points_data[i].x, points_data[i].y, points_data[i].z, radius_data[i]);
+ }
+
+ uint shader_id = 0;
+ uint last_shader = -1;
+ for (size_t i = 0; i < numpoints; i++) {
+ if (last_shader != shader_data[i]) {
+ last_shader = shader_data[i];
+ Shader *shader = (last_shader < used_shaders.size()) ?
+ static_cast<Shader *>(used_shaders[last_shader]) :
+ scene->default_surface;
+ shader_id = scene->shader_manager->get_shader_id(shader);
+ }
+ packed_shader[i] = shader_id;
+ }
+}
+
+PrimitiveType PointCloud::primitive_type() const
+{
+ return has_motion_blur() ? PRIMITIVE_MOTION_POINT : PRIMITIVE_POINT;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/scene/pointcloud.h b/intern/cycles/scene/pointcloud.h
new file mode 100644
index 00000000000..08987ee6c44
--- /dev/null
+++ b/intern/cycles/scene/pointcloud.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2011-2020 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#ifndef __POINTCLOUD_H__
+# define __POINTCLOUD_H__
+
+# include "scene/geometry.h"
+
+CCL_NAMESPACE_BEGIN
+
+class PointCloud : public Geometry {
+ public:
+ NODE_DECLARE
+
+ /* PointCloud Point */
+ struct Point {
+ int index;
+
+ void bounds_grow(const float3 *points, const float *radius, BoundBox &bounds) const;
+ void bounds_grow(const float3 *points,
+ const float *radius,
+ const Transform &aligned_space,
+ BoundBox &bounds) const;
+ void bounds_grow(const float4 &point, BoundBox &bounds) const;
+
+ float4 motion_key(const float3 *points,
+ const float *radius,
+ const float3 *point_steps,
+ size_t num_points,
+ size_t num_steps,
+ float time,
+ size_t p) const;
+ float4 point_for_step(const float3 *points,
+ const float *radius,
+ const float3 *point_steps,
+ size_t num_points,
+ size_t num_steps,
+ size_t step,
+ size_t p) const;
+ };
+
+ NODE_SOCKET_API_ARRAY(array<float3>, points)
+ NODE_SOCKET_API_ARRAY(array<float>, radius)
+ NODE_SOCKET_API_ARRAY(array<int>, shader)
+
+ /* Constructor/Destructor */
+ PointCloud();
+ ~PointCloud();
+
+ /* Geometry */
+ void clear(const bool preserver_shaders = false) override;
+
+ void resize(int numpoints);
+ void reserve(int numpoints);
+ void add_point(float3 loc, float radius, int shader = 0);
+
+ void copy_center_to_motion_step(const int motion_step);
+
+ void compute_bounds() override;
+ void apply_transform(const Transform &tfm, const bool apply_to_motion) override;
+
+ /* Points */
+ Point get_point(int i) const
+ {
+ Point point = {i};
+ return point;
+ }
+
+ size_t num_points() const
+ {
+ return points.size();
+ }
+
+ size_t num_attributes() const
+ {
+ return 1;
+ }
+
+ /* UDIM */
+ void get_uv_tiles(ustring map, unordered_set<int> &tiles) override;
+
+ PrimitiveType primitive_type() const override;
+
+ /* BVH */
+ void pack(Scene *scene, float4 *packed_points, uint *packed_shader);
+
+ private:
+ friend class BVH2;
+ friend class BVHBuild;
+ friend class BVHSpatialSplit;
+ friend class DiagSplit;
+ friend class EdgeDice;
+ friend class GeometryManager;
+ friend class ObjectManager;
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __POINTCLOUD_H__ */
diff --git a/intern/cycles/scene/scene.cpp b/intern/cycles/scene/scene.cpp
index 4230abe9a1b..1963ebbbb19 100644
--- a/intern/cycles/scene/scene.cpp
+++ b/intern/cycles/scene/scene.cpp
@@ -30,6 +30,7 @@
#include "scene/object.h"
#include "scene/osl.h"
#include "scene/particles.h"
+#include "scene/pointcloud.h"
#include "scene/procedural.h"
#include "scene/scene.h"
#include "scene/shader.h"
@@ -64,11 +65,14 @@ DeviceScene::DeviceScene(Device *device)
curve_keys(device, "__curve_keys", MEM_GLOBAL),
curve_segments(device, "__curve_segments", MEM_GLOBAL),
patches(device, "__patches", MEM_GLOBAL),
+ points(device, "__points", MEM_GLOBAL),
+ points_shader(device, "__points_shader", MEM_GLOBAL),
objects(device, "__objects", MEM_GLOBAL),
object_motion_pass(device, "__object_motion_pass", MEM_GLOBAL),
object_motion(device, "__object_motion", MEM_GLOBAL),
object_flag(device, "__object_flag", MEM_GLOBAL),
object_volume_step(device, "__object_volume_step", MEM_GLOBAL),
+ object_prim_offset(device, "__object_prim_offset", MEM_GLOBAL),
camera_motion(device, "__camera_motion", MEM_GLOBAL),
attributes_map(device, "__attributes_map", MEM_GLOBAL),
attributes_float(device, "__attributes_float", MEM_GLOBAL),
@@ -312,6 +316,12 @@ void Scene::device_update(Device *device_, Progress &progress)
if (progress.get_cancel() || device->have_error())
return;
+ progress.set_status("Updating Primitive Offsets");
+ object_manager->device_update_prim_offsets(device, &dscene, this);
+
+ if (progress.get_cancel() || device->have_error())
+ return;
+
progress.set_status("Updating Images");
image_manager->device_update(device, this, progress);
@@ -516,6 +526,9 @@ void Scene::update_kernel_features()
else if (geom->is_hair()) {
kernel_features |= KERNEL_FEATURE_HAIR;
}
+ else if (geom->is_pointcloud()) {
+ kernel_features |= KERNEL_FEATURE_POINTCLOUD;
+ }
}
if (bake_manager->get_baking()) {
@@ -568,6 +581,7 @@ static void log_kernel_features(const uint features)
VLOG(2) << "Use Path Tracing " << string_from_bool(features & KERNEL_FEATURE_PATH_TRACING)
<< "\n";
VLOG(2) << "Use Hair " << string_from_bool(features & KERNEL_FEATURE_HAIR) << "\n";
+ VLOG(2) << "Use Pointclouds " << string_from_bool(features & KERNEL_FEATURE_POINTCLOUD) << "\n";
VLOG(2) << "Use Object Motion " << string_from_bool(features & KERNEL_FEATURE_OBJECT_MOTION)
<< "\n";
VLOG(2) << "Use Camera Motion " << string_from_bool(features & KERNEL_FEATURE_CAMERA_MOTION)
@@ -750,6 +764,15 @@ template<> Volume *Scene::create_node<Volume>()
return node;
}
+template<> PointCloud *Scene::create_node<PointCloud>()
+{
+ PointCloud *node = new PointCloud();
+ node->set_owner(this);
+ geometry.push_back(node);
+ geometry_manager->tag_update(this, GeometryManager::POINT_ADDED);
+ return node;
+}
+
template<> Object *Scene::create_node<Object>()
{
Object *node = new Object();
@@ -837,6 +860,12 @@ template<> void Scene::delete_node_impl(Volume *node)
geometry_manager->tag_update(this, GeometryManager::MESH_REMOVED);
}
+template<> void Scene::delete_node_impl(PointCloud *node)
+{
+ delete_node_from_array(geometry, static_cast<Geometry *>(node));
+ geometry_manager->tag_update(this, GeometryManager::POINT_REMOVED);
+}
+
template<> void Scene::delete_node_impl(Geometry *node)
{
uint flag;
diff --git a/intern/cycles/scene/scene.h b/intern/cycles/scene/scene.h
index 4af05349dd3..ec935b41be6 100644
--- a/intern/cycles/scene/scene.h
+++ b/intern/cycles/scene/scene.h
@@ -54,6 +54,7 @@ class Object;
class ObjectManager;
class ParticleSystemManager;
class ParticleSystem;
+class PointCloud;
class Procedural;
class ProceduralManager;
class CurveSystemManager;
@@ -94,12 +95,17 @@ class DeviceScene {
device_vector<uint> patches;
+ /* pointcloud */
+ device_vector<float4> points;
+ device_vector<uint> points_shader;
+
/* objects */
device_vector<KernelObject> objects;
device_vector<Transform> object_motion_pass;
device_vector<DecomposedTransform> object_motion;
device_vector<uint> object_flag;
device_vector<float> object_volume_step;
+ device_vector<uint> object_prim_offset;
/* cameras */
device_vector<DecomposedTransform> camera_motion;
@@ -364,6 +370,8 @@ template<> Hair *Scene::create_node<Hair>();
template<> Volume *Scene::create_node<Volume>();
+template<> PointCloud *Scene::create_node<PointCloud>();
+
template<> ParticleSystem *Scene::create_node<ParticleSystem>();
template<> Shader *Scene::create_node<Shader>();
@@ -378,6 +386,8 @@ template<> void Scene::delete_node_impl(Mesh *node);
template<> void Scene::delete_node_impl(Volume *node);
+template<> void Scene::delete_node_impl(PointCloud *node);
+
template<> void Scene::delete_node_impl(Hair *node);
template<> void Scene::delete_node_impl(Geometry *node);
diff --git a/intern/cycles/scene/shader_nodes.cpp b/intern/cycles/scene/shader_nodes.cpp
index 8c20807a52b..c345d5bbc9a 100644
--- a/intern/cycles/scene/shader_nodes.cpp
+++ b/intern/cycles/scene/shader_nodes.cpp
@@ -2399,7 +2399,7 @@ void GlossyBsdfNode::simplify_settings(Scene *scene)
ShaderInput *roughness_input = input("Roughness");
if (integrator->get_filter_glossy() == 0.0f) {
/* Fallback to Sharp closure for Roughness close to 0.
- * Note: Keep the epsilon in sync with kernel!
+ * NOTE: Keep the epsilon in sync with kernel!
*/
if (!roughness_input->link && roughness <= 1e-4f) {
VLOG(3) << "Using sharp glossy BSDF.";
@@ -2492,7 +2492,7 @@ void GlassBsdfNode::simplify_settings(Scene *scene)
ShaderInput *roughness_input = input("Roughness");
if (integrator->get_filter_glossy() == 0.0f) {
/* Fallback to Sharp closure for Roughness close to 0.
- * Note: Keep the epsilon in sync with kernel!
+ * NOTE: Keep the epsilon in sync with kernel!
*/
if (!roughness_input->link && roughness <= 1e-4f) {
VLOG(3) << "Using sharp glass BSDF.";
@@ -2585,7 +2585,7 @@ void RefractionBsdfNode::simplify_settings(Scene *scene)
ShaderInput *roughness_input = input("Roughness");
if (integrator->get_filter_glossy() == 0.0f) {
/* Fallback to Sharp closure for Roughness close to 0.
- * Note: Keep the epsilon in sync with kernel!
+ * NOTE: Keep the epsilon in sync with kernel!
*/
if (!roughness_input->link && roughness <= 1e-4f) {
VLOG(3) << "Using sharp refraction BSDF.";
@@ -5871,6 +5871,73 @@ void MapRangeNode::compile(OSLCompiler &compiler)
compiler.add(this, "node_map_range");
}
+/* Vector Map Range Node */
+
+NODE_DEFINE(VectorMapRangeNode)
+{
+ NodeType *type = NodeType::add("vector_map_range", create, NodeType::SHADER);
+
+ static NodeEnum type_enum;
+ type_enum.insert("linear", NODE_MAP_RANGE_LINEAR);
+ type_enum.insert("stepped", NODE_MAP_RANGE_STEPPED);
+ type_enum.insert("smoothstep", NODE_MAP_RANGE_SMOOTHSTEP);
+ type_enum.insert("smootherstep", NODE_MAP_RANGE_SMOOTHERSTEP);
+ SOCKET_ENUM(range_type, "Type", type_enum, NODE_MAP_RANGE_LINEAR);
+
+ SOCKET_IN_VECTOR(vector, "Vector", zero_float3());
+ SOCKET_IN_VECTOR(from_min, "From_Min_FLOAT3", zero_float3());
+ SOCKET_IN_VECTOR(from_max, "From_Max_FLOAT3", one_float3());
+ SOCKET_IN_VECTOR(to_min, "To_Min_FLOAT3", zero_float3());
+ SOCKET_IN_VECTOR(to_max, "To_Max_FLOAT3", one_float3());
+ SOCKET_IN_VECTOR(steps, "Steps_FLOAT3", make_float3(4.0f));
+ SOCKET_BOOLEAN(use_clamp, "Use Clamp", false);
+
+ SOCKET_OUT_VECTOR(vector, "Vector");
+
+ return type;
+}
+
+VectorMapRangeNode::VectorMapRangeNode() : ShaderNode(get_node_type())
+{
+}
+
+void VectorMapRangeNode::expand(ShaderGraph *graph)
+{
+}
+
+void VectorMapRangeNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *vector_in = input("Vector");
+ ShaderInput *from_min_in = input("From_Min_FLOAT3");
+ ShaderInput *from_max_in = input("From_Max_FLOAT3");
+ ShaderInput *to_min_in = input("To_Min_FLOAT3");
+ ShaderInput *to_max_in = input("To_Max_FLOAT3");
+ ShaderInput *steps_in = input("Steps_FLOAT3");
+ ShaderOutput *vector_out = output("Vector");
+
+ int value_stack_offset = compiler.stack_assign(vector_in);
+ int from_min_stack_offset = compiler.stack_assign(from_min_in);
+ int from_max_stack_offset = compiler.stack_assign(from_max_in);
+ int to_min_stack_offset = compiler.stack_assign(to_min_in);
+ int to_max_stack_offset = compiler.stack_assign(to_max_in);
+ int steps_stack_offset = compiler.stack_assign(steps_in);
+ int result_stack_offset = compiler.stack_assign(vector_out);
+
+ compiler.add_node(
+ NODE_VECTOR_MAP_RANGE,
+ value_stack_offset,
+ compiler.encode_uchar4(
+ from_min_stack_offset, from_max_stack_offset, to_min_stack_offset, to_max_stack_offset),
+ compiler.encode_uchar4(steps_stack_offset, use_clamp, range_type, result_stack_offset));
+}
+
+void VectorMapRangeNode::compile(OSLCompiler &compiler)
+{
+ compiler.parameter(this, "range_type");
+ compiler.parameter(this, "use_clamp");
+ compiler.add(this, "node_vector_map_range");
+}
+
/* Clamp Node */
NODE_DEFINE(ClampNode)
diff --git a/intern/cycles/scene/shader_nodes.h b/intern/cycles/scene/shader_nodes.h
index 64a2b1c7843..0faefd3041f 100644
--- a/intern/cycles/scene/shader_nodes.h
+++ b/intern/cycles/scene/shader_nodes.h
@@ -1263,6 +1263,21 @@ class BlackbodyNode : public ShaderNode {
NODE_SOCKET_API(float, temperature)
};
+class VectorMapRangeNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(VectorMapRangeNode)
+ void expand(ShaderGraph *graph);
+
+ NODE_SOCKET_API(float3, vector)
+ NODE_SOCKET_API(float3, from_min)
+ NODE_SOCKET_API(float3, from_max)
+ NODE_SOCKET_API(float3, to_min)
+ NODE_SOCKET_API(float3, to_max)
+ NODE_SOCKET_API(float3, steps)
+ NODE_SOCKET_API(NodeMapRangeType, range_type)
+ NODE_SOCKET_API(bool, use_clamp)
+};
+
class MapRangeNode : public ShaderNode {
public:
SHADER_NODE_CLASS(MapRangeNode)
diff --git a/intern/cycles/session/merge.cpp b/intern/cycles/session/merge.cpp
index 9044a8c4809..0a9ed37750b 100644
--- a/intern/cycles/session/merge.cpp
+++ b/intern/cycles/session/merge.cpp
@@ -35,12 +35,15 @@ enum MergeChannelOp {
MERGE_CHANNEL_NOP,
MERGE_CHANNEL_COPY,
MERGE_CHANNEL_SUM,
- MERGE_CHANNEL_AVERAGE
+ MERGE_CHANNEL_AVERAGE,
+ MERGE_CHANNEL_SAMPLES,
};
struct MergeImagePass {
/* Full channel name. */
string channel_name;
+ /* Pass name. */
+ string name;
/* Channel format in the file. */
TypeDesc format;
/* Type of operation to perform when merging. */
@@ -51,6 +54,13 @@ struct MergeImagePass {
int merge_offset;
};
+struct SampleCount {
+ /* Total number of samples. */
+ int total;
+ /* Buffer for actual number of samples rendered per pixel. */
+ array<float> per_pixel;
+};
+
struct MergeImageLayer {
/* Layer name. */
string name;
@@ -58,6 +68,10 @@ struct MergeImageLayer {
vector<MergeImagePass> passes;
/* Sample amount that was used for rendering this layer. */
int samples;
+ /* Indicates if this layer has "Debug Sample Count" pass. */
+ bool has_sample_pass;
+ /* Offset of the "Debug Sample Count" pass if it exists. */
+ int sample_pass_offset;
};
/* Merge Image */
@@ -84,6 +98,9 @@ static MergeChannelOp parse_channel_operation(const string &pass_name)
string_startswith(pass_name, "Debug Render Time")) {
return MERGE_CHANNEL_SUM;
}
+ else if (string_startswith(pass_name, "Debug Sample Count")) {
+ return MERGE_CHANNEL_SAMPLES;
+ }
else {
return MERGE_CHANNEL_AVERAGE;
}
@@ -148,11 +165,11 @@ static bool parse_channels(const ImageSpec &in_spec,
pass.offset = i;
pass.merge_offset = i;
- string layername, passname, channelname;
+ string layername, channelname;
if (parse_channel_name(
- pass.channel_name, layername, passname, channelname, multiview_channels)) {
+ pass.channel_name, layername, pass.name, channelname, multiview_channels)) {
/* Channel part of a render layer. */
- pass.op = parse_channel_operation(passname);
+ pass.op = parse_channel_operation(pass.name);
}
else {
/* Other channels are added in unnamed layer. */
@@ -183,10 +200,7 @@ static bool parse_channels(const ImageSpec &in_spec,
/* Loop over all detected render-layers, check whether they contain a full set of input
* channels. Any channels that won't be processed internally are also passed through. */
- for (auto &i : file_layers) {
- const string &name = i.first;
- MergeImageLayer &layer = i.second;
-
+ for (auto &[name, layer] : file_layers) {
layer.name = name;
layer.samples = 0;
@@ -211,6 +225,19 @@ static bool parse_channels(const ImageSpec &in_spec,
return false;
}
+ /* Check if the layer has "Debug Sample Count" pass. */
+ auto sample_pass_it = find_if(
+ layer.passes.begin(), layer.passes.end(), [](const MergeImagePass &pass) {
+ return pass.name == "Debug Sample Count";
+ });
+ if (sample_pass_it != layer.passes.end()) {
+ layer.has_sample_pass = true;
+ layer.sample_pass_offset = distance(layer.passes.begin(), sample_pass_it);
+ }
+ else {
+ layer.has_sample_pass = false;
+ }
+
layers.push_back(layer);
}
@@ -301,9 +328,7 @@ static void merge_layer_render_time(ImageSpec &spec,
spec.attribute(name, TypeDesc::STRING, time_human_readable_from_seconds(time));
}
-static void merge_channels_metadata(vector<MergeImage> &images,
- ImageSpec &out_spec,
- vector<int> &channel_total_samples)
+static void merge_channels_metadata(vector<MergeImage> &images, ImageSpec &out_spec)
{
/* Based on first image. */
out_spec = images[0].in->spec();
@@ -317,25 +342,23 @@ static void merge_channels_metadata(vector<MergeImage> &images,
for (MergeImageLayer &layer : image.layers) {
for (MergeImagePass &pass : layer.passes) {
/* Test if matching channel already exists in merged image. */
- bool found = false;
-
- for (size_t i = 0; i < out_spec.nchannels; i++) {
- if (pass.channel_name == out_spec.channelnames[i]) {
- pass.merge_offset = i;
- channel_total_samples[i] += layer.samples;
- /* First image wins for channels that can't be averaged or summed. */
- if (pass.op == MERGE_CHANNEL_COPY) {
- pass.op = MERGE_CHANNEL_NOP;
- }
- found = true;
- break;
+ auto channel = find_if(
+ out_spec.channelnames.begin(),
+ out_spec.channelnames.end(),
+ [&pass](const auto &channel_name) { return pass.channel_name == channel_name; });
+
+ if (channel != out_spec.channelnames.end()) {
+ int index = distance(out_spec.channelnames.begin(), channel);
+ pass.merge_offset = index;
+
+ /* First image wins for channels that can't be averaged or summed. */
+ if (pass.op == MERGE_CHANNEL_COPY) {
+ pass.op = MERGE_CHANNEL_NOP;
}
}
-
- if (!found) {
+ else {
/* Add new channel. */
pass.merge_offset = out_spec.nchannels;
- channel_total_samples.push_back(layer.samples);
out_spec.channelnames.push_back(pass.channel_name);
out_spec.channelformats.push_back(pass.format);
@@ -357,13 +380,13 @@ static void merge_channels_metadata(vector<MergeImage> &images,
}
}
- for (const auto &i : layer_num_samples) {
- string name = "cycles." + i.first + ".samples";
- out_spec.attribute(name, TypeDesc::STRING, string_printf("%d", i.second));
+ for (const auto &[layer_name, layer_samples] : layer_num_samples) {
+ string name = "cycles." + layer_name + ".samples";
+ out_spec.attribute(name, TypeDesc::STRING, to_string(layer_samples));
- merge_layer_render_time(out_spec, images, i.first, "total_time", false);
- merge_layer_render_time(out_spec, images, i.first, "render_time", false);
- merge_layer_render_time(out_spec, images, i.first, "synchronization_time", true);
+ merge_layer_render_time(out_spec, images, layer_name, "total_time", false);
+ merge_layer_render_time(out_spec, images, layer_name, "render_time", false);
+ merge_layer_render_time(out_spec, images, layer_name, "synchronization_time", true);
}
}
@@ -373,13 +396,13 @@ static void alloc_pixels(const ImageSpec &spec, array<float> &pixels)
const size_t height = spec.height;
const size_t num_channels = spec.nchannels;
- const size_t num_pixels = (size_t)width * (size_t)height;
+ const size_t num_pixels = width * height;
pixels.resize(num_pixels * num_channels);
}
static bool merge_pixels(const vector<MergeImage> &images,
const ImageSpec &out_spec,
- const vector<int> &channel_total_samples,
+ const unordered_map<string, SampleCount> &layer_samples,
array<float> &out_pixels,
string &error)
{
@@ -397,9 +420,7 @@ static bool merge_pixels(const vector<MergeImage> &images,
return false;
}
- for (size_t li = 0; li < image.layers.size(); li++) {
- const MergeImageLayer &layer = image.layers[li];
-
+ for (const MergeImageLayer &layer : image.layers) {
const size_t stride = image.in->spec().nchannels;
const size_t out_stride = out_spec.nchannels;
const size_t num_pixels = pixels.size();
@@ -421,16 +442,36 @@ static bool merge_pixels(const vector<MergeImage> &images,
out_pixels[out_offset] += pixels[offset];
}
break;
- case MERGE_CHANNEL_AVERAGE:
- /* Weights based on sample metadata. Per channel since not
+ case MERGE_CHANNEL_AVERAGE: {
+ /* Weights based on sample count passes and sample metadata. Per channel since not
* all files are guaranteed to have the same channels. */
- const int total_samples = channel_total_samples[out_offset];
- const float t = (float)layer.samples / (float)total_samples;
-
- for (; offset < num_pixels; offset += stride, out_offset += out_stride) {
- out_pixels[out_offset] += t * pixels[offset];
+ size_t sample_pass_offset = layer.sample_pass_offset;
+ const auto &samples = layer_samples.at(layer.name);
+
+ for (size_t i = 0; offset < num_pixels;
+ offset += stride, sample_pass_offset += stride, out_offset += out_stride, i++) {
+ const float total_samples = samples.per_pixel[i];
+
+ float layer_samples;
+ if (layer.has_sample_pass) {
+ layer_samples = pixels[sample_pass_offset] * layer.samples;
+ }
+ else {
+ layer_samples = layer.samples;
+ }
+
+ out_pixels[out_offset] += pixels[offset] * (1.0f * layer_samples / total_samples);
}
break;
+ }
+ case MERGE_CHANNEL_SAMPLES: {
+ const auto &samples = layer_samples.at(layer.name);
+ for (size_t i = 0; offset < num_pixels;
+ offset += stride, out_offset += out_stride, i++) {
+ out_pixels[out_offset] = 1.0f * samples.per_pixel[i] / samples.total;
+ }
+ break;
+ }
}
}
}
@@ -489,6 +530,49 @@ static bool save_output(const string &filepath,
return ok;
}
+static void read_layer_samples(vector<MergeImage> &images,
+ unordered_map<string, SampleCount> &layer_samples)
+{
+ for (auto &image : images) {
+ const ImageSpec &in_spec = image.in->spec();
+
+ for (auto &layer : image.layers) {
+ bool initialize = (layer_samples.count(layer.name) == 0);
+ auto &current_layer_samples = layer_samples[layer.name];
+
+ if (initialize) {
+ current_layer_samples.total = 0;
+ current_layer_samples.per_pixel.resize(in_spec.width * in_spec.height);
+ std::fill(
+ current_layer_samples.per_pixel.begin(), current_layer_samples.per_pixel.end(), 0);
+ }
+
+ if (layer.has_sample_pass) {
+ /* Load the "Debug Sample Count" pass and add the samples to the layer's sample count. */
+ array<float> sample_count_buffer;
+ sample_count_buffer.resize(in_spec.width * in_spec.height);
+ image.in->read_image(0,
+ 0,
+ layer.sample_pass_offset,
+ layer.sample_pass_offset,
+ TypeDesc::FLOAT,
+ (void *)sample_count_buffer.data());
+
+ for (size_t i = 0; i < current_layer_samples.per_pixel.size(); i++) {
+ current_layer_samples.per_pixel[i] += sample_count_buffer[i] * layer.samples;
+ }
+ }
+ else {
+ /* Use sample count from metadata if there's no "Debug Sample Count" pass. */
+ for (size_t i = 0; i < current_layer_samples.per_pixel.size(); i++) {
+ current_layer_samples.per_pixel[i] += layer.samples;
+ }
+ }
+
+ current_layer_samples.total += layer.samples;
+ }
+ }
+}
/* Image Merger */
ImageMerger::ImageMerger()
@@ -512,14 +596,17 @@ bool ImageMerger::run()
return false;
}
+ /* Load and sum sample count for each render layer. */
+ unordered_map<string, SampleCount> layer_samples;
+ read_layer_samples(images, layer_samples);
+
/* Merge metadata and setup channels and offsets. */
ImageSpec out_spec;
- vector<int> channel_total_samples;
- merge_channels_metadata(images, out_spec, channel_total_samples);
+ merge_channels_metadata(images, out_spec);
/* Merge pixels. */
array<float> out_pixels;
- if (!merge_pixels(images, out_spec, channel_total_samples, out_pixels, error)) {
+ if (!merge_pixels(images, out_spec, layer_samples, out_pixels, error)) {
return false;
}
diff --git a/intern/cycles/test/integrator_tile_test.cpp b/intern/cycles/test/integrator_tile_test.cpp
index 8bb0856d6a9..1d078a2d19a 100644
--- a/intern/cycles/test/integrator_tile_test.cpp
+++ b/intern/cycles/test/integrator_tile_test.cpp
@@ -24,26 +24,27 @@ CCL_NAMESPACE_BEGIN
TEST(tile_calculate_best_size, Basic)
{
/* Make sure CPU-like case is handled properly. */
- EXPECT_EQ(tile_calculate_best_size(make_int2(1920, 1080), 1, 1, 1.0f), TileSize(1, 1, 1));
- EXPECT_EQ(tile_calculate_best_size(make_int2(1920, 1080), 100, 1, 1.0f), TileSize(1, 1, 1));
+ EXPECT_EQ(tile_calculate_best_size(false, make_int2(1920, 1080), 1, 1, 1.0f), TileSize(1, 1, 1));
+ EXPECT_EQ(tile_calculate_best_size(false, make_int2(1920, 1080), 100, 1, 1.0f),
+ TileSize(1, 1, 1));
/* Enough path states to fit an entire image with all samples. */
- EXPECT_EQ(tile_calculate_best_size(make_int2(1920, 1080), 1, 1920 * 1080, 1.0f),
+ EXPECT_EQ(tile_calculate_best_size(false, make_int2(1920, 1080), 1, 1920 * 1080, 1.0f),
TileSize(1920, 1080, 1));
- EXPECT_EQ(tile_calculate_best_size(make_int2(1920, 1080), 100, 1920 * 1080 * 100, 1.0f),
+ EXPECT_EQ(tile_calculate_best_size(false, make_int2(1920, 1080), 100, 1920 * 1080 * 100, 1.0f),
TileSize(1920, 1080, 100));
}
TEST(tile_calculate_best_size, Extreme)
{
- EXPECT_EQ(tile_calculate_best_size(make_int2(32, 32), 262144, 131072, 1.0f),
+ EXPECT_EQ(tile_calculate_best_size(false, make_int2(32, 32), 262144, 131072, 1.0f),
TileSize(1, 1, 512));
- EXPECT_EQ(tile_calculate_best_size(make_int2(32, 32), 1048576, 131072, 1.0f),
+ EXPECT_EQ(tile_calculate_best_size(false, make_int2(32, 32), 1048576, 131072, 1.0f),
TileSize(1, 1, 1024));
- EXPECT_EQ(tile_calculate_best_size(make_int2(32, 32), 10485760, 131072, 1.0f),
+ EXPECT_EQ(tile_calculate_best_size(false, make_int2(32, 32), 10485760, 131072, 1.0f),
TileSize(1, 1, 4096));
- EXPECT_EQ(tile_calculate_best_size(make_int2(32, 32), 8192 * 8192 * 2, 1024, 1.0f),
+ EXPECT_EQ(tile_calculate_best_size(false, make_int2(32, 32), 8192 * 8192 * 2, 1024, 1.0f),
TileSize(1, 1, 1024));
}
diff --git a/intern/cycles/util/math.h b/intern/cycles/util/math.h
index 6cfeb1aa917..18b60b70a4b 100644
--- a/intern/cycles/util/math.h
+++ b/intern/cycles/util/math.h
@@ -719,6 +719,20 @@ ccl_device_inline float pow22(float a)
return sqr(a * sqr(sqr(sqr(a)) * a));
}
+#ifdef __KERNEL_METAL__
+ccl_device_inline float lgammaf(float x)
+{
+ /* Nemes, Gergő (2010), "New asymptotic expansion for the Gamma function", Archiv der Mathematik
+ */
+ const float _1_180 = 1.0f / 180.0f;
+ const float log2pi = 1.83787706641f;
+ const float logx = log(x);
+ return (log2pi - logx +
+ x * (logx * 2.0f + log(x * sinh(1.0f / x) + (_1_180 / pow(x, 6.0f))) - 2.0f)) *
+ 0.5f;
+}
+#endif
+
ccl_device_inline float beta(float x, float y)
{
return expf(lgammaf(x) + lgammaf(y) - lgammaf(x + y));
diff --git a/intern/cycles/util/math_fast.h b/intern/cycles/util/math_fast.h
index cc924f36a71..e2a33b1c26c 100644
--- a/intern/cycles/util/math_fast.h
+++ b/intern/cycles/util/math_fast.h
@@ -3,7 +3,7 @@
*
* Copyright 2008-2014 Larry Gritz and the other authors and contributors.
* All Rights Reserved.
-
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
diff --git a/intern/cycles/util/math_float3.h b/intern/cycles/util/math_float3.h
index 1a0213f2a6d..74f1c98e649 100644
--- a/intern/cycles/util/math_float3.h
+++ b/intern/cycles/util/math_float3.h
@@ -233,7 +233,7 @@ ccl_device_inline float3 operator/=(float3 &a, float f)
return a = a * invf;
}
-#if !(defined(__KERNEL_METAL__) || defined(__KERNEL_CUDA__))
+# if !(defined(__KERNEL_METAL__) || defined(__KERNEL_CUDA__))
ccl_device_inline packed_float3 operator*=(packed_float3 &a, const float3 &b)
{
a = float3(a) * b;
@@ -257,7 +257,7 @@ ccl_device_inline packed_float3 operator/=(packed_float3 &a, float f)
a = float3(a) / f;
return a;
}
-#endif
+# endif
ccl_device_inline bool operator==(const float3 &a, const float3 &b)
{
diff --git a/intern/cycles/util/math_intersect.h b/intern/cycles/util/math_intersect.h
index 0c431a36afb..0fce9ff24fd 100644
--- a/intern/cycles/util/math_intersect.h
+++ b/intern/cycles/util/math_intersect.h
@@ -85,32 +85,48 @@ ccl_device bool ray_aligned_disk_intersect(float3 ray_P,
return true;
}
+ccl_device bool ray_disk_intersect(float3 ray_P,
+ float3 ray_D,
+ float ray_t,
+ float3 disk_P,
+ float3 disk_N,
+ float disk_radius,
+ ccl_private float3 *isect_P,
+ ccl_private float *isect_t)
+{
+ const float3 vp = ray_P - disk_P;
+ const float dp = dot(vp, disk_N);
+ const float cos_angle = dot(disk_N, -ray_D);
+ if (dp * cos_angle > 0.f) // front of light
+ {
+ float t = dp / cos_angle;
+ if (t < 0.f) { /* Ray points away from the light. */
+ return false;
+ }
+ float3 P = ray_P + t * ray_D;
+ float3 T = P - disk_P;
+ if (dot(T, T) < sqr(disk_radius) /*&& t > 0.f*/ && t <= ray_t) {
+ *isect_P = ray_P + t * ray_D;
+ *isect_t = t;
+ return true;
+ }
+ }
+ return false;
+}
+
ccl_device_forceinline bool ray_triangle_intersect(float3 ray_P,
float3 ray_dir,
float ray_t,
-#if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__)
- const ssef *ssef_verts,
-#else
const float3 tri_a,
const float3 tri_b,
const float3 tri_c,
-#endif
ccl_private float *isect_u,
ccl_private float *isect_v,
ccl_private float *isect_t)
{
-#if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__)
- typedef ssef float3;
- const float3 tri_a(ssef_verts[0]);
- const float3 tri_b(ssef_verts[1]);
- const float3 tri_c(ssef_verts[2]);
- const float3 P(ray_P);
- const float3 dir(ray_dir);
-#else
-# define dot3(a, b) dot(a, b)
+#define dot3(a, b) dot(a, b)
const float3 P = ray_P;
const float3 dir = ray_dir;
-#endif
/* Calculate vertices relative to ray origin. */
const float3 v0 = tri_c - P;
@@ -123,43 +139,16 @@ ccl_device_forceinline bool ray_triangle_intersect(float3 ray_P,
const float3 e2 = v1 - v2;
/* Perform edge tests. */
-#if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__)
- const float3 crossU = cross(v2 + v0, e0);
- const float3 crossV = cross(v0 + v1, e1);
- const float3 crossW = cross(v1 + v2, e2);
-
- ssef crossX(crossU);
- ssef crossY(crossV);
- ssef crossZ(crossW);
- ssef zero = _mm_setzero_ps();
- _MM_TRANSPOSE4_PS(crossX, crossY, crossZ, zero);
-
- const ssef dirX(ray_dir.x);
- const ssef dirY(ray_dir.y);
- const ssef dirZ(ray_dir.z);
-
- ssef UVWW = madd(crossX, dirX, madd(crossY, dirY, crossZ * dirZ));
-#else /* __KERNEL_SSE2__ */
const float U = dot(cross(v2 + v0, e0), ray_dir);
const float V = dot(cross(v0 + v1, e1), ray_dir);
const float W = dot(cross(v1 + v2, e2), ray_dir);
-#endif /* __KERNEL_SSE2__ */
-#if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__)
- int uvw_sign = movemask(UVWW) & 0x7;
- if (uvw_sign != 0) {
- if (uvw_sign != 0x7) {
- return false;
- }
- }
-#else
const float minUVW = min(U, min(V, W));
const float maxUVW = max(U, max(V, W));
if (minUVW < 0.0f && maxUVW > 0.0f) {
return false;
}
-#endif
/* Calculate geometry normal and denominator. */
const float3 Ng1 = cross(e1, e0);
@@ -180,14 +169,8 @@ ccl_device_forceinline bool ray_triangle_intersect(float3 ray_P,
}
const float inv_den = 1.0f / den;
-#if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__)
- UVWW *= inv_den;
- _mm_store_ss(isect_u, UVWW);
- _mm_store_ss(isect_v, shuffle<1, 1, 3, 3>(UVWW));
-#else
*isect_u = U * inv_den;
*isect_v = V * inv_den;
-#endif
*isect_t = T * inv_den;
return true;
diff --git a/intern/cycles/util/math_matrix.h b/intern/cycles/util/math_matrix.h
index c1be71517e3..846b028a513 100644
--- a/intern/cycles/util/math_matrix.h
+++ b/intern/cycles/util/math_matrix.h
@@ -116,7 +116,7 @@ ccl_device_inline void math_vec3_add_strided(
}
/* Elementary matrix operations.
- * Note: TriMatrix refers to a square matrix that is symmetric,
+ * NOTE: TriMatrix refers to a square matrix that is symmetric,
* and therefore its upper-triangular part isn't stored. */
ccl_device_inline void math_trimatrix_add_diagonal(ccl_global float *A,
diff --git a/intern/cycles/util/path.cpp b/intern/cycles/util/path.cpp
index aad790482d5..e27c929fba9 100644
--- a/intern/cycles/util/path.cpp
+++ b/intern/cycles/util/path.cpp
@@ -750,6 +750,167 @@ bool path_remove(const string &path)
return remove(path.c_str()) == 0;
}
+struct SourceReplaceState {
+ typedef map<string, string> ProcessedMapping;
+ /* Base director for all relative include headers. */
+ string base;
+ /* Result of processed files. */
+ ProcessedMapping processed_files;
+ /* Set of files containing #pragma once which have been included. */
+ set<string> pragma_onced;
+};
+
+static string path_source_replace_includes_recursive(const string &source,
+ const string &source_filepath,
+ SourceReplaceState *state);
+
+static string path_source_handle_preprocessor(const string &preprocessor_line,
+ const string &source_filepath,
+ SourceReplaceState *state)
+{
+ string result = preprocessor_line;
+
+ string rest_of_line = string_strip(preprocessor_line.substr(1));
+
+ if (0 == strncmp(rest_of_line.c_str(), "include", 7)) {
+ rest_of_line = string_strip(rest_of_line.substr(8));
+ if (rest_of_line[0] == '"') {
+ const size_t n_start = 1;
+ const size_t n_end = rest_of_line.find("\"", n_start);
+ const string filename = rest_of_line.substr(n_start, n_end - n_start);
+
+ string filepath = path_join(state->base, filename);
+ if (!path_exists(filepath)) {
+ filepath = path_join(path_dirname(source_filepath), filename);
+ }
+ string text;
+ if (path_read_text(filepath, text)) {
+ text = path_source_replace_includes_recursive(text, filepath, state);
+ /* Use line directives for better error messages. */
+ return "\n" + text + "\n";
+ }
+ }
+ }
+
+ return result;
+}
+
+/* Our own little c preprocessor that replaces #includes with the file
+ * contents, to work around issue of OpenCL drivers not supporting
+ * include paths with spaces in them.
+ */
+static string path_source_replace_includes_recursive(const string &_source,
+ const string &source_filepath,
+ SourceReplaceState *state)
+{
+ const string *psource = &_source;
+ string source_new;
+
+ auto pragma_once = _source.find("#pragma once");
+ if (pragma_once != string::npos) {
+ if (state->pragma_onced.find(source_filepath) != state->pragma_onced.end()) {
+ return "";
+ }
+ state->pragma_onced.insert(source_filepath);
+
+ // "#pragma once"
+ // "//prgma once"
+ source_new = _source;
+ memcpy(source_new.data() + pragma_once, "//pr", 4);
+ psource = &source_new;
+ }
+
+ /* Try to re-use processed file without spending time on replacing all
+ * include directives again.
+ */
+ SourceReplaceState::ProcessedMapping::iterator replaced_file = state->processed_files.find(
+ source_filepath);
+ if (replaced_file != state->processed_files.end()) {
+ return replaced_file->second;
+ }
+
+ const string &source = *psource;
+
+ /* Perform full file processing. */
+ string result = "";
+ const size_t source_length = source.length();
+ size_t index = 0;
+ /* Information about where we are in the source. */
+ size_t line_number = 0, column_number = 1;
+ /* Currently gathered non-preprocessor token.
+ * Store as start/length rather than token itself to avoid overhead of
+ * memory re-allocations on each character concatenation.
+ */
+ size_t token_start = 0, token_length = 0;
+ /* Denotes whether we're inside of preprocessor line, together with
+ * preprocessor line itself.
+ *
+ * TODO(sergey): Investigate whether using token start/end position
+ * gives measurable speedup.
+ */
+ bool inside_preprocessor = false;
+ string preprocessor_line = "";
+ /* Actual loop over the whole source. */
+ while (index < source_length) {
+ char ch = source[index];
+
+ if (ch == '\n') {
+ if (inside_preprocessor) {
+ string block = path_source_handle_preprocessor(preprocessor_line, source_filepath, state);
+
+ if (!block.empty()) {
+ result += block;
+ }
+
+ /* Start gathering net part of the token. */
+ token_start = index;
+ token_length = 0;
+ inside_preprocessor = false;
+ preprocessor_line = "";
+ }
+ column_number = 0;
+ ++line_number;
+ }
+ else if (ch == '#' && column_number == 1 && !inside_preprocessor) {
+ /* Append all possible non-preprocessor token to the result. */
+ if (token_length != 0) {
+ result.append(source, token_start, token_length);
+ token_start = index;
+ token_length = 0;
+ }
+ inside_preprocessor = true;
+ }
+
+ if (inside_preprocessor) {
+ preprocessor_line += ch;
+ }
+ else {
+ ++token_length;
+ }
+ ++index;
+ ++column_number;
+ }
+ /* Append possible tokens which happened before special events handled
+ * above.
+ */
+ if (token_length != 0) {
+ result.append(source, token_start, token_length);
+ }
+ if (inside_preprocessor) {
+ result += path_source_handle_preprocessor(preprocessor_line, source_filepath, state);
+ }
+ /* Store result for further reuse. */
+ state->processed_files[source_filepath] = result;
+ return result;
+}
+
+string path_source_replace_includes(const string &source, const string &path)
+{
+ SourceReplaceState state;
+ state.base = path;
+ return path_source_replace_includes_recursive(source, path, &state);
+}
+
FILE *path_fopen(const string &path, const string &mode)
{
#ifdef _WIN32
diff --git a/intern/cycles/util/path.h b/intern/cycles/util/path.h
index a1394555302..7ec5ed60d7f 100644
--- a/intern/cycles/util/path.h
+++ b/intern/cycles/util/path.h
@@ -66,6 +66,9 @@ bool path_read_text(const string &path, string &text);
/* File manipulation. */
bool path_remove(const string &path);
+/* source code utility */
+string path_source_replace_includes(const string &source, const string &path);
+
/* cache utility */
void path_cache_clear_except(const string &name, const set<string> &except);
diff --git a/intern/cycles/util/transform.h b/intern/cycles/util/transform.h
index 1d78dfd1385..84827cf6ba5 100644
--- a/intern/cycles/util/transform.h
+++ b/intern/cycles/util/transform.h
@@ -366,11 +366,11 @@ ccl_device_inline Transform transform_empty()
ccl_device_inline float4 quat_interpolate(float4 q1, float4 q2, float t)
{
- /* Optix is using lerp to interpolate motion transformations. */
-#ifdef __KERNEL_OPTIX__
+ /* Optix and MetalRT are using lerp to interpolate motion transformations. */
+#if defined(__KERNEL_GPU_RAYTRACING__)
return normalize((1.0f - t) * q1 + t * q2);
-#else /* __KERNEL_OPTIX__ */
- /* note: this does not ensure rotation around shortest angle, q1 and q2
+#else /* defined(__KERNEL_GPU_RAYTRACING__) */
+ /* NOTE: this does not ensure rotation around shortest angle, q1 and q2
* are assumed to be matched already in transform_motion_decompose */
float costheta = dot(q1, q2);
@@ -387,7 +387,7 @@ ccl_device_inline float4 quat_interpolate(float4 q1, float4 q2, float t)
float thetap = theta * t;
return q1 * cosf(thetap) + qperp * sinf(thetap);
}
-#endif /* __KERNEL_OPTIX__ */
+#endif /* defined(__KERNEL_GPU_RAYTRACING__) */
}
ccl_device_inline Transform transform_quick_inverse(Transform M)
diff --git a/intern/dualcon/intern/MemoryAllocator.h b/intern/dualcon/intern/MemoryAllocator.h
index f39e8255521..6ad4ceb5773 100644
--- a/intern/dualcon/intern/MemoryAllocator.h
+++ b/intern/dualcon/intern/MemoryAllocator.h
@@ -55,7 +55,7 @@ class VirtualMemoryAllocator {
/**
* Dynamic memory allocator - allows allocation/deallocation
*
- * Note: there are 4 bytes overhead for each allocated yet unused object.
+ * NOTE: there are 4 bytes overhead for each allocated yet unused object.
*/
template<int N> class MemoryAllocator : public VirtualMemoryAllocator {
private:
diff --git a/intern/eigen/eigen_capi.h b/intern/eigen/eigen_capi.h
index 52ec489159f..4f8ecd03a42 100644
--- a/intern/eigen/eigen_capi.h
+++ b/intern/eigen/eigen_capi.h
@@ -17,6 +17,10 @@
* All rights reserved.
*/
+/** \file
+ * \ingroup intern_eigen
+ */
+
#ifndef __EIGEN_C_API_H__
#define __EIGEN_C_API_H__
diff --git a/intern/eigen/intern/eigenvalues.h b/intern/eigen/intern/eigenvalues.h
index fabbdd87207..0f61d6ee3e8 100644
--- a/intern/eigen/intern/eigenvalues.h
+++ b/intern/eigen/intern/eigenvalues.h
@@ -17,6 +17,10 @@
* All rights reserved.
*/
+/** \file
+ * \ingroup intern_eigen
+ */
+
#ifndef __EIGEN3_EIGENVALUES_C_API_H__
#define __EIGEN3_EIGENVALUES_C_API_H__
diff --git a/intern/eigen/intern/linear_solver.cc b/intern/eigen/intern/linear_solver.cc
index bce5937409c..4edc3426dca 100644
--- a/intern/eigen/intern/linear_solver.cc
+++ b/intern/eigen/intern/linear_solver.cc
@@ -22,6 +22,10 @@
* and the reason for such modification.
*/
+/** \file
+ * \ingroup intern_eigen
+ */
+
#include "linear_solver.h"
#include <Eigen/Sparse>
diff --git a/intern/eigen/intern/linear_solver.h b/intern/eigen/intern/linear_solver.h
index 4da1ec05cd0..6b9f815ca88 100644
--- a/intern/eigen/intern/linear_solver.h
+++ b/intern/eigen/intern/linear_solver.h
@@ -22,6 +22,10 @@
* and the reason for such modification.
*/
+/** \file
+ * \ingroup intern_eigen
+ */
+
#pragma once
#include <stdbool.h>
diff --git a/intern/eigen/intern/matrix.cc b/intern/eigen/intern/matrix.cc
index 2024a1ba59a..cff0e9cf264 100644
--- a/intern/eigen/intern/matrix.cc
+++ b/intern/eigen/intern/matrix.cc
@@ -17,6 +17,10 @@
* All rights reserved.
*/
+/** \file
+ * \ingroup intern_eigen
+ */
+
#ifndef __EIGEN3_MATRIX_C_API_CC__
#define __EIGEN3_MATRIX_C_API_CC__
diff --git a/intern/eigen/intern/matrix.h b/intern/eigen/intern/matrix.h
index 91ef5e0713d..1f94e1cbe15 100644
--- a/intern/eigen/intern/matrix.h
+++ b/intern/eigen/intern/matrix.h
@@ -17,6 +17,10 @@
* All rights reserved.
*/
+/** \file
+ * \ingroup intern_eigen
+ */
+
#ifndef __EIGEN3_MATRIX_C_API_H__
#define __EIGEN3_MATRIX_C_API_H__
diff --git a/intern/eigen/intern/svd.cc b/intern/eigen/intern/svd.cc
index bfd7064353d..24aa44f4740 100644
--- a/intern/eigen/intern/svd.cc
+++ b/intern/eigen/intern/svd.cc
@@ -17,6 +17,10 @@
* All rights reserved.
*/
+/** \file
+ * \ingroup intern_eigen
+ */
+
#ifndef __EIGEN3_SVD_C_API_CC__
#define __EIGEN3_SVD_C_API_CC__
diff --git a/intern/eigen/intern/svd.h b/intern/eigen/intern/svd.h
index 80238621920..3d80137dc56 100644
--- a/intern/eigen/intern/svd.h
+++ b/intern/eigen/intern/svd.h
@@ -17,6 +17,10 @@
* All rights reserved.
*/
+/** \file
+ * \ingroup intern_eigen
+ */
+
#ifndef __EIGEN3_SVD_C_API_H__
#define __EIGEN3_SVD_C_API_H__
diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt
index 41642311185..84f156949aa 100644
--- a/intern/ghost/CMakeLists.txt
+++ b/intern/ghost/CMakeLists.txt
@@ -245,10 +245,10 @@ elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND)
if(WITH_X11_XF86VMODE)
add_definitions(-DWITH_X11_XF86VMODE)
list(APPEND INC_SYS
- ${X11_xf86vmode_INCLUDE_PATH}
+ ${X11_Xxf86vmode_INCLUDE_PATH}
)
list(APPEND LIB
- ${X11_Xf86vmode_LIB}
+ ${X11_Xxf86vmode_LIB}
)
endif()
diff --git a/intern/ghost/intern/GHOST_SystemPathsCocoa.mm b/intern/ghost/intern/GHOST_SystemPathsCocoa.mm
index 43ce0bb0533..4032c145ab4 100644
--- a/intern/ghost/intern/GHOST_SystemPathsCocoa.mm
+++ b/intern/ghost/intern/GHOST_SystemPathsCocoa.mm
@@ -36,130 +36,101 @@ GHOST_SystemPathsCocoa::~GHOST_SystemPathsCocoa()
#pragma mark Base directories retrieval
-const char *GHOST_SystemPathsCocoa::getSystemDir(int, const char *versionstr) const
+static const char *GetApplicationSupportDir(const char *versionstr,
+ const NSSearchPathDomainMask mask,
+ char *tempPath,
+ const std::size_t len_tempPath)
{
- static char tempPath[512] = "";
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- NSString *basePath;
- NSArray *paths;
-
- paths = NSSearchPathForDirectoriesInDomains(
- NSApplicationSupportDirectory, NSLocalDomainMask, YES);
-
- if ([paths count] > 0)
- basePath = [paths objectAtIndex:0];
- else {
- [pool drain];
- return NULL;
- }
+ @autoreleasepool {
+ const NSArray *const paths = NSSearchPathForDirectoriesInDomains(
+ NSApplicationSupportDirectory, mask, YES);
- snprintf(tempPath,
- sizeof(tempPath),
- "%s/Blender/%s",
- [basePath cStringUsingEncoding:NSASCIIStringEncoding],
- versionstr);
-
- [pool drain];
+ if ([paths count] == 0) {
+ return NULL;
+ }
+ const NSString *const basePath = [paths objectAtIndex:0];
+
+ snprintf(tempPath,
+ len_tempPath,
+ "%s/Blender/%s",
+ [basePath cStringUsingEncoding:NSASCIIStringEncoding],
+ versionstr);
+ }
return tempPath;
}
-const char *GHOST_SystemPathsCocoa::getUserDir(int, const char *versionstr) const
+const char *GHOST_SystemPathsCocoa::getSystemDir(int, const char *versionstr) const
{
static char tempPath[512] = "";
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- NSString *basePath;
- NSArray *paths;
-
- paths = NSSearchPathForDirectoriesInDomains(
- NSApplicationSupportDirectory, NSUserDomainMask, YES);
-
- if ([paths count] > 0)
- basePath = [paths objectAtIndex:0];
- else {
- [pool drain];
- return NULL;
- }
-
- snprintf(tempPath,
- sizeof(tempPath),
- "%s/Blender/%s",
- [basePath cStringUsingEncoding:NSASCIIStringEncoding],
- versionstr);
+ return GetApplicationSupportDir(versionstr, NSLocalDomainMask, tempPath, sizeof(tempPath));
+}
- [pool drain];
- return tempPath;
+const char *GHOST_SystemPathsCocoa::getUserDir(int, const char *versionstr) const
+{
+ static char tempPath[512] = "";
+ return GetApplicationSupportDir(versionstr, NSUserDomainMask, tempPath, sizeof(tempPath));
}
const char *GHOST_SystemPathsCocoa::getUserSpecialDir(GHOST_TUserSpecialDirTypes type) const
{
static char tempPath[512] = "";
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- NSString *basePath;
- NSArray *paths;
- NSSearchPathDirectory ns_directory;
-
- switch (type) {
- case GHOST_kUserSpecialDirDesktop:
- ns_directory = NSDesktopDirectory;
- break;
- case GHOST_kUserSpecialDirDocuments:
- ns_directory = NSDocumentDirectory;
- break;
- case GHOST_kUserSpecialDirDownloads:
- ns_directory = NSDownloadsDirectory;
- break;
- case GHOST_kUserSpecialDirMusic:
- ns_directory = NSMusicDirectory;
- break;
- case GHOST_kUserSpecialDirPictures:
- ns_directory = NSPicturesDirectory;
- break;
- case GHOST_kUserSpecialDirVideos:
- ns_directory = NSMoviesDirectory;
- break;
- case GHOST_kUserSpecialDirCaches:
- ns_directory = NSCachesDirectory;
- break;
- default:
- GHOST_ASSERT(
- false,
- "GHOST_SystemPathsCocoa::getUserSpecialDir(): Invalid enum value for type parameter");
- [pool drain];
+ @autoreleasepool {
+ NSSearchPathDirectory ns_directory;
+
+ switch (type) {
+ case GHOST_kUserSpecialDirDesktop:
+ ns_directory = NSDesktopDirectory;
+ break;
+ case GHOST_kUserSpecialDirDocuments:
+ ns_directory = NSDocumentDirectory;
+ break;
+ case GHOST_kUserSpecialDirDownloads:
+ ns_directory = NSDownloadsDirectory;
+ break;
+ case GHOST_kUserSpecialDirMusic:
+ ns_directory = NSMusicDirectory;
+ break;
+ case GHOST_kUserSpecialDirPictures:
+ ns_directory = NSPicturesDirectory;
+ break;
+ case GHOST_kUserSpecialDirVideos:
+ ns_directory = NSMoviesDirectory;
+ break;
+ case GHOST_kUserSpecialDirCaches:
+ ns_directory = NSCachesDirectory;
+ break;
+ default:
+ GHOST_ASSERT(
+ false,
+ "GHOST_SystemPathsCocoa::getUserSpecialDir(): Invalid enum value for type parameter");
+ return NULL;
+ }
+
+ const NSArray *const paths = NSSearchPathForDirectoriesInDomains(
+ ns_directory, NSUserDomainMask, YES);
+ if ([paths count] == 0) {
return NULL;
- }
-
- paths = NSSearchPathForDirectoriesInDomains(ns_directory, NSUserDomainMask, YES);
+ }
+ const NSString *const basePath = [paths objectAtIndex:0];
- if ([paths count] > 0)
- basePath = [paths objectAtIndex:0];
- else {
- [pool drain];
- return NULL;
+ strncpy(tempPath, [basePath cStringUsingEncoding:NSASCIIStringEncoding], sizeof(tempPath));
}
-
- strncpy(
- (char *)tempPath, [basePath cStringUsingEncoding:NSASCIIStringEncoding], sizeof(tempPath));
-
- [pool drain];
return tempPath;
}
const char *GHOST_SystemPathsCocoa::getBinaryDir() const
{
static char tempPath[512] = "";
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- NSString *basePath;
-
- basePath = [[NSBundle mainBundle] bundlePath];
- if (basePath == nil) {
- [pool drain];
- return NULL;
- }
+ @autoreleasepool {
+ const NSString *const basePath = [[NSBundle mainBundle] bundlePath];
- strcpy((char *)tempPath, [basePath cStringUsingEncoding:NSASCIIStringEncoding]);
+ if (basePath == nil) {
+ return NULL;
+ }
- [pool drain];
+ strcpy(tempPath, [basePath cStringUsingEncoding:NSASCIIStringEncoding]);
+ }
return tempPath;
}
diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp
index 482f20f5cd1..e4630ad1ab5 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.cpp
+++ b/intern/ghost/intern/GHOST_SystemWin32.cpp
@@ -1002,10 +1002,10 @@ void GHOST_SystemWin32::processWintabEvent(GHOST_WindowWin32 *window)
DWORD pos = GetMessagePos();
int x = GET_X_LPARAM(pos);
int y = GET_Y_LPARAM(pos);
+ GHOST_TabletData td = wt->getLastTabletData();
- /* TODO supply tablet data */
system->pushEvent(new GHOST_EventCursor(
- system->getMilliSeconds(), GHOST_kEventCursorMove, window, x, y, GHOST_TABLET_DATA_NONE));
+ system->getMilliSeconds(), GHOST_kEventCursorMove, window, x, y, td));
}
}
@@ -1472,6 +1472,7 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
case WM_IME_SETCONTEXT: {
GHOST_ImeWin32 *ime = window->getImeInput();
ime->UpdateInputLanguage();
+ ime->UpdateConversionStatus(hwnd);
ime->CreateImeWindow(hwnd);
ime->CleanupComposition(hwnd);
ime->CheckFirst(hwnd);
diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp
index ab8039ea95d..85504bd94fb 100644
--- a/intern/ghost/intern/GHOST_SystemX11.cpp
+++ b/intern/ghost/intern/GHOST_SystemX11.cpp
@@ -714,7 +714,7 @@ bool GHOST_SystemX11::processEvents(bool waitForEvent)
anyProcessed = true;
#ifdef USE_UNITY_WORKAROUND
- /* note: processEvent() can't include this code because
+ /* NOTE: processEvent() can't include this code because
* KeymapNotify event have no valid window information. */
/* the X server generates KeymapNotify event immediately after
@@ -1514,7 +1514,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
* around tablet surface */
window->GetTabletData().Active = xtablet.mode;
- /* Note: This event might be generated with incomplete data-set
+ /* NOTE: This event might be generated with incomplete data-set
* (don't exactly know why, looks like in some cases, if the value does not change,
* it is not included in subsequent #XDeviceMotionEvent events).
* So we have to check which values this event actually contains!
@@ -2278,6 +2278,7 @@ void GHOST_SystemX11::putClipboard(const char *buffer, bool selection) const
/* -------------------------------------------------------------------- */
/** \name Message Box
* \{ */
+
class DialogData {
public:
/* Width of the dialog. */
diff --git a/intern/ghost/intern/GHOST_Window.h b/intern/ghost/intern/GHOST_Window.h
index f061e07b3c8..69d0eea838c 100644
--- a/intern/ghost/intern/GHOST_Window.h
+++ b/intern/ghost/intern/GHOST_Window.h
@@ -42,10 +42,9 @@ class GHOST_Window : public GHOST_IWindow {
* Creates a new window and opens it.
* To check if the window was created properly, use the getValid() method.
* \param width: The width the window.
- * \param heigh: The height the window.
+ * \param height: The height the window.
* \param state: The state the window is initially opened with.
- * \param type: The type of drawing context installed in this window.
- * \param stereoVisual: Stereo visual for quad buffered stereo.
+ * \param wantStereoVisual: Stereo visual for quad buffered stereo.
* \param exclusive: Use to show the window ontop and ignore others (used full-screen).
*/
GHOST_Window(uint32_t width,
diff --git a/intern/ghost/intern/GHOST_WindowViewCocoa.h b/intern/ghost/intern/GHOST_WindowViewCocoa.h
index fa629528809..1bda59c3505 100644
--- a/intern/ghost/intern/GHOST_WindowViewCocoa.h
+++ b/intern/ghost/intern/GHOST_WindowViewCocoa.h
@@ -510,6 +510,14 @@
- (void)checkKeyCodeIsControlChar:(NSEvent *)event
{
ime.state_flag &= ~GHOST_IME_KEY_CONTROL_CHAR;
+
+ /* Don't use IME for command and ctrl key combinations, these are shortcuts. */
+ if ([event modifierFlags] & (NSEventModifierFlagCommand | NSEventModifierFlagControl)) {
+ ime.state_flag |= GHOST_IME_KEY_CONTROL_CHAR;
+ return;
+ }
+
+ /* Don't use IME for these control keys. */
switch ([event keyCode]) {
case kVK_ANSI_KeypadEnter:
case kVK_ANSI_KeypadClear:
diff --git a/intern/ghost/intern/GHOST_Wintab.h b/intern/ghost/intern/GHOST_Wintab.h
index 443c726d270..a6c41bf5f64 100644
--- a/intern/ghost/intern/GHOST_Wintab.h
+++ b/intern/ghost/intern/GHOST_Wintab.h
@@ -148,7 +148,7 @@ class GHOST_Wintab {
* \param wtY: Wintab cursor y position.
* \return True if Win32 and Wintab cursor positions match within tolerance.
*
- * Note: Only test coordinates on button press, not release. This prevents issues when async
+ * NOTE: Only test coordinates on button press, not release. This prevents issues when async
* mismatch causes mouse movement to replay and snap back, which is only an issue while drawing.
*/
bool testCoordinates(int sysX, int sysY, int wtX, int wtY);
diff --git a/intern/ghost/intern/GHOST_XrControllerModel.cpp b/intern/ghost/intern/GHOST_XrControllerModel.cpp
index 27f92ffe7c5..aa46aaaf89a 100644
--- a/intern/ghost/intern/GHOST_XrControllerModel.cpp
+++ b/intern/ghost/intern/GHOST_XrControllerModel.cpp
@@ -244,22 +244,10 @@ static void calc_node_transforms(const tinygltf::Node &gltf_node,
* both. */
if (gltf_node.matrix.size() == 16) {
const std::vector<double> &dm = gltf_node.matrix;
- float m[4][4] = {(float)dm[0],
- (float)dm[1],
- (float)dm[2],
- (float)dm[3],
- (float)dm[4],
- (float)dm[5],
- (float)dm[6],
- (float)dm[7],
- (float)dm[8],
- (float)dm[9],
- (float)dm[10],
- (float)dm[11],
- (float)dm[12],
- (float)dm[13],
- (float)dm[14],
- (float)dm[15]};
+ float m[4][4] = {{(float)dm[0], (float)dm[1], (float)dm[2], (float)dm[3]},
+ {(float)dm[4], (float)dm[5], (float)dm[6], (float)dm[7]},
+ {(float)dm[8], (float)dm[9], (float)dm[10], (float)dm[11]},
+ {(float)dm[12], (float)dm[13], (float)dm[14], (float)dm[15]}};
memcpy(r_local_transform, m, sizeof(float) * 16);
}
else {
@@ -534,7 +522,7 @@ void GHOST_XrControllerModel::loadControllerModel(XrSession session)
(gltf_model.defaultScene == -1) ? 0 : gltf_model.defaultScene);
const int32_t root_idx = -1;
const std::string root_name = "";
- float root_transform[4][4] = {0};
+ float root_transform[4][4] = {{0}};
root_transform[0][0] = root_transform[1][1] = root_transform[2][2] = root_transform[3][3] = 1.0f;
for (const int node_id : default_scene.nodes) {
diff --git a/intern/ghost/intern/GHOST_XrControllerModel.h b/intern/ghost/intern/GHOST_XrControllerModel.h
index 5ff72957b24..a9aed961713 100644
--- a/intern/ghost/intern/GHOST_XrControllerModel.h
+++ b/intern/ghost/intern/GHOST_XrControllerModel.h
@@ -18,7 +18,7 @@
* \ingroup GHOST
*/
-/* Note: Requires OpenXR headers to be included before this one for OpenXR types (XrInstance,
+/* NOTE: Requires OpenXR headers to be included before this one for OpenXR types (XrInstance,
* XrSession, etc.). */
#pragma once
diff --git a/intern/ghost/intern/GHOST_XrSession.cpp b/intern/ghost/intern/GHOST_XrSession.cpp
index 64aa2f515c4..c68cb5992e3 100644
--- a/intern/ghost/intern/GHOST_XrSession.cpp
+++ b/intern/ghost/intern/GHOST_XrSession.cpp
@@ -307,6 +307,7 @@ GHOST_XrSession::LifeExpectancy GHOST_XrSession::handleStateChangeEvent(
return SESSION_KEEP_ALIVE;
}
+
/** \} */ /* State Management */
/* -------------------------------------------------------------------- */
diff --git a/intern/ghost/intern/GHOST_XrSession.h b/intern/ghost/intern/GHOST_XrSession.h
index 83de44c8d8e..f5c0c04e65d 100644
--- a/intern/ghost/intern/GHOST_XrSession.h
+++ b/intern/ghost/intern/GHOST_XrSession.h
@@ -53,7 +53,7 @@ class GHOST_XrSession {
void draw(void *draw_customdata);
/** Action functions to be called pre-session start.
- * Note: The "destroy" functions can also be called post-session start. */
+ * NOTE: The "destroy" functions can also be called post-session start. */
bool createActionSet(const GHOST_XrActionSetInfo &info);
void destroyActionSet(const char *action_set_name);
bool createActions(const char *action_set_name, uint32_t count, const GHOST_XrActionInfo *infos);
diff --git a/intern/glew-mx/glew-mx.h b/intern/glew-mx/glew-mx.h
index f9b3e55179f..5977fddb387 100644
--- a/intern/glew-mx/glew-mx.h
+++ b/intern/glew-mx/glew-mx.h
@@ -18,7 +18,7 @@
*/
/** \file
- * \ingroup glew-mx
+ * \ingroup intern_glew-mx
*
* Support for GLEW Multiple rendering conteXts (MX)
* Maintained as a Blender Library.
diff --git a/intern/glew-mx/intern/gl-deprecated.h b/intern/glew-mx/intern/gl-deprecated.h
index d101591fea3..b07c865993e 100644
--- a/intern/glew-mx/intern/gl-deprecated.h
+++ b/intern/glew-mx/intern/gl-deprecated.h
@@ -18,7 +18,7 @@
*/
/** \file
- * \ingroup glew-mx
+ * \ingroup intern_glew-mx
* Utility used to check for use of deprecated functions.
*/
diff --git a/intern/glew-mx/intern/glew-mx.c b/intern/glew-mx/intern/glew-mx.c
index 541d3c5efbe..7e176ff2a76 100644
--- a/intern/glew-mx/intern/glew-mx.c
+++ b/intern/glew-mx/intern/glew-mx.c
@@ -18,7 +18,7 @@
*/
/** \file
- * \ingroup glew-mx
+ * \ingroup intern_glew-mx
*/
#include "glew-mx.h"
diff --git a/intern/glew-mx/intern/symbol-binding.h b/intern/glew-mx/intern/symbol-binding.h
index 0dc7d859fca..e65752efed4 100644
--- a/intern/glew-mx/intern/symbol-binding.h
+++ b/intern/glew-mx/intern/symbol-binding.h
@@ -18,7 +18,7 @@
*/
/** \file
- * \ingroup glew-mx
+ * \ingroup intern_glew-mx
*
* This file is for any simple stuff that is missing from GLEW when
* compiled with either the GLEW_ES_ONLY or the GLEW_NO_ES flag.
diff --git a/intern/guardedalloc/MEM_guardedalloc.h b/intern/guardedalloc/MEM_guardedalloc.h
index 874abb88ff5..3c006b9a70c 100644
--- a/intern/guardedalloc/MEM_guardedalloc.h
+++ b/intern/guardedalloc/MEM_guardedalloc.h
@@ -18,7 +18,7 @@
*/
/** \file
- * \ingroup MEM
+ * \ingroup intern_mem
*
* \brief Read \ref MEMPage
*
diff --git a/intern/guardedalloc/cpp/mallocn.cpp b/intern/guardedalloc/cpp/mallocn.cpp
index 5bde16ddb42..dadaea12cfe 100644
--- a/intern/guardedalloc/cpp/mallocn.cpp
+++ b/intern/guardedalloc/cpp/mallocn.cpp
@@ -15,7 +15,7 @@
*/
/** \file
- * \ingroup MEM
+ * \ingroup intern_mem
*/
#include "../MEM_guardedalloc.h"
diff --git a/intern/guardedalloc/intern/leak_detector.cc b/intern/guardedalloc/intern/leak_detector.cc
index 03d54f2e776..072b68fcc9f 100644
--- a/intern/guardedalloc/intern/leak_detector.cc
+++ b/intern/guardedalloc/intern/leak_detector.cc
@@ -15,7 +15,7 @@
*/
/** \file
- * \ingroup MEM
+ * \ingroup intern_mem
*/
#include <cstdio> /* Needed for `printf` on WIN32/APPLE. */
@@ -65,7 +65,7 @@ class MemLeakPrinter {
};
} // namespace
-void MEM_init_memleak_detection(void)
+void MEM_init_memleak_detection()
{
/**
* This variable is constructed when this function is first called. This should happen as soon as
@@ -84,7 +84,7 @@ void MEM_use_memleak_detection(bool enabled)
ignore_memleak = !enabled;
}
-void MEM_enable_fail_on_memleak(void)
+void MEM_enable_fail_on_memleak()
{
fail_on_memleak = true;
}
diff --git a/intern/guardedalloc/intern/mallocn.c b/intern/guardedalloc/intern/mallocn.c
index 261a23a1196..c7b12ed3457 100644
--- a/intern/guardedalloc/intern/mallocn.c
+++ b/intern/guardedalloc/intern/mallocn.c
@@ -15,7 +15,7 @@
*/
/** \file
- * \ingroup MEM
+ * \ingroup intern_mem
*
* Guarded memory allocation, and boundary-write detection.
*/
diff --git a/intern/guardedalloc/intern/mallocn_guarded_impl.c b/intern/guardedalloc/intern/mallocn_guarded_impl.c
index bba72c907eb..2720a9762bb 100644
--- a/intern/guardedalloc/intern/mallocn_guarded_impl.c
+++ b/intern/guardedalloc/intern/mallocn_guarded_impl.c
@@ -18,7 +18,7 @@
*/
/** \file
- * \ingroup MEM
+ * \ingroup intern_mem
*
* Guarded memory allocation, and boundary-write detection.
*/
diff --git a/intern/guardedalloc/intern/mallocn_inline.h b/intern/guardedalloc/intern/mallocn_inline.h
index 4e73eb9bad6..65bd40de492 100644
--- a/intern/guardedalloc/intern/mallocn_inline.h
+++ b/intern/guardedalloc/intern/mallocn_inline.h
@@ -27,7 +27,7 @@
*/
/** \file
- * \ingroup MEM
+ * \ingroup intern_mem
*/
#ifndef __MALLOCN_INLINE_H__
diff --git a/intern/guardedalloc/intern/mallocn_intern.h b/intern/guardedalloc/intern/mallocn_intern.h
index e4bd3d533a3..b57e11d9a8f 100644
--- a/intern/guardedalloc/intern/mallocn_intern.h
+++ b/intern/guardedalloc/intern/mallocn_intern.h
@@ -18,7 +18,7 @@
*/
/** \file
- * \ingroup MEM
+ * \ingroup intern_mem
*/
#ifndef __MALLOCN_INTERN_H__
diff --git a/intern/guardedalloc/intern/mallocn_lockfree_impl.c b/intern/guardedalloc/intern/mallocn_lockfree_impl.c
index a843086a1f1..5d522f4da88 100644
--- a/intern/guardedalloc/intern/mallocn_lockfree_impl.c
+++ b/intern/guardedalloc/intern/mallocn_lockfree_impl.c
@@ -15,7 +15,7 @@
*/
/** \file
- * \ingroup MEM
+ * \ingroup intern_mem
*
* Memory allocation which keeps track on allocated memory counters
*/
diff --git a/intern/iksolver/extern/IK_solver.h b/intern/iksolver/extern/IK_solver.h
index 79c57b7f44b..8e7ea11bc18 100644
--- a/intern/iksolver/extern/IK_solver.h
+++ b/intern/iksolver/extern/IK_solver.h
@@ -19,7 +19,7 @@
*/
/** \file
- * \ingroup iksolver
+ * \ingroup intern_iksolver
*/
/**
diff --git a/intern/iksolver/intern/IK_Math.h b/intern/iksolver/intern/IK_Math.h
index f8f8b774787..be115364fb7 100644
--- a/intern/iksolver/intern/IK_Math.h
+++ b/intern/iksolver/intern/IK_Math.h
@@ -18,6 +18,10 @@
* Original author: Laurence
*/
+/** \file
+ * \ingroup intern_iksolver
+ */
+
#pragma once
#include <Eigen/Core>
diff --git a/intern/iksolver/intern/IK_QJacobian.cpp b/intern/iksolver/intern/IK_QJacobian.cpp
index 82aaaf7bb9a..19d711f3fe1 100644
--- a/intern/iksolver/intern/IK_QJacobian.cpp
+++ b/intern/iksolver/intern/IK_QJacobian.cpp
@@ -18,7 +18,7 @@
*/
/** \file
- * \ingroup iksolver
+ * \ingroup intern_iksolver
*/
#include "IK_QJacobian.h"
diff --git a/intern/iksolver/intern/IK_QJacobian.h b/intern/iksolver/intern/IK_QJacobian.h
index 8d4a8a7ba65..ed2d41368ad 100644
--- a/intern/iksolver/intern/IK_QJacobian.h
+++ b/intern/iksolver/intern/IK_QJacobian.h
@@ -19,7 +19,7 @@
*/
/** \file
- * \ingroup iksolver
+ * \ingroup intern_iksolver
*/
#pragma once
diff --git a/intern/iksolver/intern/IK_QJacobianSolver.cpp b/intern/iksolver/intern/IK_QJacobianSolver.cpp
index b8ad0b2c09c..efbf271c4b2 100644
--- a/intern/iksolver/intern/IK_QJacobianSolver.cpp
+++ b/intern/iksolver/intern/IK_QJacobianSolver.cpp
@@ -18,7 +18,7 @@
*/
/** \file
- * \ingroup iksolver
+ * \ingroup intern_iksolver
*/
#include <stdio.h>
diff --git a/intern/iksolver/intern/IK_QJacobianSolver.h b/intern/iksolver/intern/IK_QJacobianSolver.h
index cef13625dc4..0c8ef661129 100644
--- a/intern/iksolver/intern/IK_QJacobianSolver.h
+++ b/intern/iksolver/intern/IK_QJacobianSolver.h
@@ -18,7 +18,7 @@
*/
/** \file
- * \ingroup iksolver
+ * \ingroup intern_iksolver
*/
#pragma once
diff --git a/intern/iksolver/intern/IK_QSegment.cpp b/intern/iksolver/intern/IK_QSegment.cpp
index dbbec621acd..544d68e99ca 100644
--- a/intern/iksolver/intern/IK_QSegment.cpp
+++ b/intern/iksolver/intern/IK_QSegment.cpp
@@ -18,7 +18,7 @@
*/
/** \file
- * \ingroup iksolver
+ * \ingroup intern_iksolver
*/
#include "IK_QSegment.h"
diff --git a/intern/iksolver/intern/IK_QSegment.h b/intern/iksolver/intern/IK_QSegment.h
index 3c8c5033d28..17b56b1cfb3 100644
--- a/intern/iksolver/intern/IK_QSegment.h
+++ b/intern/iksolver/intern/IK_QSegment.h
@@ -19,7 +19,7 @@
*/
/** \file
- * \ingroup iksolver
+ * \ingroup intern_iksolver
*/
#pragma once
diff --git a/intern/iksolver/intern/IK_QTask.cpp b/intern/iksolver/intern/IK_QTask.cpp
index f3fe24bef18..30fef1ff670 100644
--- a/intern/iksolver/intern/IK_QTask.cpp
+++ b/intern/iksolver/intern/IK_QTask.cpp
@@ -18,7 +18,7 @@
*/
/** \file
- * \ingroup iksolver
+ * \ingroup intern_iksolver
*/
#include "IK_QTask.h"
diff --git a/intern/iksolver/intern/IK_QTask.h b/intern/iksolver/intern/IK_QTask.h
index 595d1454872..faca6e2a036 100644
--- a/intern/iksolver/intern/IK_QTask.h
+++ b/intern/iksolver/intern/IK_QTask.h
@@ -19,7 +19,7 @@
*/
/** \file
- * \ingroup iksolver
+ * \ingroup intern_iksolver
*/
#pragma once
diff --git a/intern/iksolver/intern/IK_Solver.cpp b/intern/iksolver/intern/IK_Solver.cpp
index b274e005990..368546d7cef 100644
--- a/intern/iksolver/intern/IK_Solver.cpp
+++ b/intern/iksolver/intern/IK_Solver.cpp
@@ -18,7 +18,7 @@
*/
/** \file
- * \ingroup iksolver
+ * \ingroup intern_iksolver
*/
#include "../extern/IK_solver.h"
diff --git a/intern/itasc/Armature.cpp b/intern/itasc/Armature.cpp
index abbfc851eae..f365d40e9f1 100644
--- a/intern/itasc/Armature.cpp
+++ b/intern/itasc/Armature.cpp
@@ -1,5 +1,5 @@
/** \file itasc/Armature.cpp
- * \ingroup itasc
+ * \ingroup intern_itasc
*/
/*
* Armature.cpp
diff --git a/intern/itasc/Cache.cpp b/intern/itasc/Cache.cpp
index eeae070dc3e..28e6fbd22b1 100644
--- a/intern/itasc/Cache.cpp
+++ b/intern/itasc/Cache.cpp
@@ -1,5 +1,5 @@
/** \file itasc/Cache.cpp
- * \ingroup itasc
+ * \ingroup intern_itasc
*/
/*
* Cache.cpp
diff --git a/intern/itasc/ConstraintSet.cpp b/intern/itasc/ConstraintSet.cpp
index 2df5cb13df8..fda1ee9d70d 100644
--- a/intern/itasc/ConstraintSet.cpp
+++ b/intern/itasc/ConstraintSet.cpp
@@ -1,5 +1,5 @@
/** \file itasc/ConstraintSet.cpp
- * \ingroup itasc
+ * \ingroup intern_itasc
*/
/*
* ConstraintSet.cpp
diff --git a/intern/itasc/ControlledObject.cpp b/intern/itasc/ControlledObject.cpp
index 3c3e87ee09e..bb2e4117361 100644
--- a/intern/itasc/ControlledObject.cpp
+++ b/intern/itasc/ControlledObject.cpp
@@ -1,5 +1,5 @@
/** \file itasc/ControlledObject.cpp
- * \ingroup itasc
+ * \ingroup intern_itasc
*/
/*
* ControlledObject.cpp
diff --git a/intern/itasc/CopyPose.cpp b/intern/itasc/CopyPose.cpp
index 8b177bb102d..a9b6d3cd680 100644
--- a/intern/itasc/CopyPose.cpp
+++ b/intern/itasc/CopyPose.cpp
@@ -1,5 +1,5 @@
/** \file itasc/CopyPose.cpp
- * \ingroup itasc
+ * \ingroup intern_itasc
*/
/*
* CopyPose.cpp
diff --git a/intern/itasc/Distance.cpp b/intern/itasc/Distance.cpp
index eebe9bab4c6..6a368944ed3 100644
--- a/intern/itasc/Distance.cpp
+++ b/intern/itasc/Distance.cpp
@@ -1,5 +1,5 @@
/** \file itasc/Distance.cpp
- * \ingroup itasc
+ * \ingroup intern_itasc
*/
/*
* Distance.cpp
diff --git a/intern/itasc/FixedObject.cpp b/intern/itasc/FixedObject.cpp
index ff30ffac946..8a547ac2b05 100644
--- a/intern/itasc/FixedObject.cpp
+++ b/intern/itasc/FixedObject.cpp
@@ -1,5 +1,5 @@
/** \file itasc/FixedObject.cpp
- * \ingroup itasc
+ * \ingroup intern_itasc
*/
/*
* FixedObject.cpp
diff --git a/intern/itasc/MovingFrame.cpp b/intern/itasc/MovingFrame.cpp
index 1b3062765a9..e3f4d612155 100644
--- a/intern/itasc/MovingFrame.cpp
+++ b/intern/itasc/MovingFrame.cpp
@@ -1,5 +1,5 @@
/** \file itasc/MovingFrame.cpp
- * \ingroup itasc
+ * \ingroup intern_itasc
*/
/*
* MovingFrame.cpp
diff --git a/intern/itasc/Scene.cpp b/intern/itasc/Scene.cpp
index 0d2486ceac7..b5f8e4df386 100644
--- a/intern/itasc/Scene.cpp
+++ b/intern/itasc/Scene.cpp
@@ -1,5 +1,5 @@
/** \file itasc/Scene.cpp
- * \ingroup itasc
+ * \ingroup intern_itasc
*/
/*
* Scene.cpp
diff --git a/intern/itasc/UncontrolledObject.cpp b/intern/itasc/UncontrolledObject.cpp
index 9f638107c99..3083b711217 100644
--- a/intern/itasc/UncontrolledObject.cpp
+++ b/intern/itasc/UncontrolledObject.cpp
@@ -1,5 +1,5 @@
/** \file itasc/UncontrolledObject.cpp
- * \ingroup itasc
+ * \ingroup intern_itasc
*/
/*
* UncontrolledObject.cpp
diff --git a/intern/itasc/WDLSSolver.cpp b/intern/itasc/WDLSSolver.cpp
index 0a5a0afd0d8..c5221fc2767 100644
--- a/intern/itasc/WDLSSolver.cpp
+++ b/intern/itasc/WDLSSolver.cpp
@@ -1,5 +1,5 @@
/** \file itasc/WDLSSolver.cpp
- * \ingroup itasc
+ * \ingroup intern_itasc
*/
/*
* WDLSSolver.hpp.cpp
diff --git a/intern/itasc/WSDLSSolver.cpp b/intern/itasc/WSDLSSolver.cpp
index cc009d7ae46..32273828acc 100644
--- a/intern/itasc/WSDLSSolver.cpp
+++ b/intern/itasc/WSDLSSolver.cpp
@@ -1,5 +1,5 @@
/** \file itasc/WSDLSSolver.cpp
- * \ingroup itasc
+ * \ingroup intern_itasc
*/
/*
* WDLSSolver.hpp.cpp
diff --git a/intern/itasc/WorldObject.cpp b/intern/itasc/WorldObject.cpp
index 998b180b73b..34641478ea0 100644
--- a/intern/itasc/WorldObject.cpp
+++ b/intern/itasc/WorldObject.cpp
@@ -1,5 +1,5 @@
/** \file itasc/WorldObject.cpp
- * \ingroup itasc
+ * \ingroup intern_itasc
*/
/*
* WorldObject.cpp
diff --git a/intern/itasc/eigen_types.cpp b/intern/itasc/eigen_types.cpp
index e8ae3d878ab..a1c0525766e 100644
--- a/intern/itasc/eigen_types.cpp
+++ b/intern/itasc/eigen_types.cpp
@@ -1,5 +1,5 @@
/** \file itasc/eigen_types.cpp
- * \ingroup itasc
+ * \ingroup intern_itasc
*/
/*
* eigen_types.cpp
diff --git a/intern/itasc/kdl/chain.cpp b/intern/itasc/kdl/chain.cpp
index 1ab8ee3e648..8137ade1847 100644
--- a/intern/itasc/kdl/chain.cpp
+++ b/intern/itasc/kdl/chain.cpp
@@ -1,5 +1,5 @@
/** \file itasc/kdl/chain.cpp
- * \ingroup itasc
+ * \ingroup intern_itasc
*/
// Copyright (C) 2007 Ruben Smits <ruben dot smits at mech dot kuleuven dot be>
diff --git a/intern/itasc/kdl/chainfksolverpos_recursive.cpp b/intern/itasc/kdl/chainfksolverpos_recursive.cpp
index a0d7262f427..d5149256c0d 100644
--- a/intern/itasc/kdl/chainfksolverpos_recursive.cpp
+++ b/intern/itasc/kdl/chainfksolverpos_recursive.cpp
@@ -1,5 +1,5 @@
/** \file itasc/kdl/chainfksolverpos_recursive.cpp
- * \ingroup itasc
+ * \ingroup intern_itasc
*/
// Copyright (C) 2007 Francois Cauwe <francois at cauwe dot org>
// Copyright (C) 2007 Ruben Smits <ruben dot smits at mech dot kuleuven dot be>
diff --git a/intern/itasc/kdl/chainjnttojacsolver.cpp b/intern/itasc/kdl/chainjnttojacsolver.cpp
index eb84a5d863e..ea183fac4fb 100644
--- a/intern/itasc/kdl/chainjnttojacsolver.cpp
+++ b/intern/itasc/kdl/chainjnttojacsolver.cpp
@@ -1,5 +1,5 @@
/** \file itasc/kdl/chainjnttojacsolver.cpp
- * \ingroup itasc
+ * \ingroup intern_itasc
*/
// Copyright (C) 2007 Ruben Smits <ruben dot smits at mech dot kuleuven dot be>
diff --git a/intern/itasc/kdl/frameacc.cpp b/intern/itasc/kdl/frameacc.cpp
index f145d4de074..7c294aeb268 100644
--- a/intern/itasc/kdl/frameacc.cpp
+++ b/intern/itasc/kdl/frameacc.cpp
@@ -1,5 +1,5 @@
/** \file itasc/kdl/frameacc.cpp
- * \ingroup itasc
+ * \ingroup intern_itasc
*/
/*****************************************************************************
* Erwin Aertbelien, Div. PMA, Dep. of Mech. Eng., K.U.Leuven
diff --git a/intern/itasc/kdl/frames.cpp b/intern/itasc/kdl/frames.cpp
index 517176babb2..747a54909e9 100644
--- a/intern/itasc/kdl/frames.cpp
+++ b/intern/itasc/kdl/frames.cpp
@@ -1,5 +1,5 @@
/** \file itasc/kdl/frames.cpp
- * \ingroup itasc
+ * \ingroup intern_itasc
*/
/***************************************************************************
frames.cxx - description
diff --git a/intern/itasc/kdl/frames_io.cpp b/intern/itasc/kdl/frames_io.cpp
index a35de29da18..782524ce77c 100644
--- a/intern/itasc/kdl/frames_io.cpp
+++ b/intern/itasc/kdl/frames_io.cpp
@@ -1,5 +1,5 @@
/** \file itasc/kdl/frames_io.cpp
- * \ingroup itasc
+ * \ingroup intern_itasc
*/
/***************************************************************************
diff --git a/intern/itasc/kdl/framevel.cpp b/intern/itasc/kdl/framevel.cpp
index 8ccefee999e..d86d9ad2ef6 100644
--- a/intern/itasc/kdl/framevel.cpp
+++ b/intern/itasc/kdl/framevel.cpp
@@ -1,5 +1,5 @@
/** \file itasc/kdl/framevel.cpp
- * \ingroup itasc
+ * \ingroup intern_itasc
*/
/*****************************************************************************
* Erwin Aertbelien, Div. PMA, Dep. of Mech. Eng., K.U.Leuven
diff --git a/intern/itasc/kdl/inertia.cpp b/intern/itasc/kdl/inertia.cpp
index 1a1dc4629ed..651666cf7b9 100644
--- a/intern/itasc/kdl/inertia.cpp
+++ b/intern/itasc/kdl/inertia.cpp
@@ -1,5 +1,5 @@
/** \file itasc/kdl/inertia.cpp
- * \ingroup itasc
+ * \ingroup intern_itasc
*/
// Copyright (C) 2007 Ruben Smits <ruben dot smits at mech dot kuleuven dot be>
diff --git a/intern/itasc/kdl/jacobian.cpp b/intern/itasc/kdl/jacobian.cpp
index e02ab8cbb8b..e15eeac286c 100644
--- a/intern/itasc/kdl/jacobian.cpp
+++ b/intern/itasc/kdl/jacobian.cpp
@@ -1,5 +1,5 @@
/** \file itasc/kdl/jacobian.cpp
- * \ingroup itasc
+ * \ingroup intern_itasc
*/
// Copyright (C) 2007 Ruben Smits <ruben dot smits at mech dot kuleuven dot be>
diff --git a/intern/itasc/kdl/jntarray.cpp b/intern/itasc/kdl/jntarray.cpp
index e427239e69a..40a1a8449aa 100644
--- a/intern/itasc/kdl/jntarray.cpp
+++ b/intern/itasc/kdl/jntarray.cpp
@@ -1,5 +1,5 @@
/** \file itasc/kdl/jntarray.cpp
- * \ingroup itasc
+ * \ingroup intern_itasc
*/
// Copyright (C) 2007 Ruben Smits <ruben dot smits at mech dot kuleuven dot be>
diff --git a/intern/itasc/kdl/jntarrayacc.cpp b/intern/itasc/kdl/jntarrayacc.cpp
index b6bbd541c1d..51e14e56f6f 100644
--- a/intern/itasc/kdl/jntarrayacc.cpp
+++ b/intern/itasc/kdl/jntarrayacc.cpp
@@ -1,5 +1,5 @@
/** \file itasc/kdl/jntarrayacc.cpp
- * \ingroup itasc
+ * \ingroup intern_itasc
*/
// Copyright (C) 2007 Ruben Smits <ruben dot smits at mech dot kuleuven dot be>
diff --git a/intern/itasc/kdl/jntarrayvel.cpp b/intern/itasc/kdl/jntarrayvel.cpp
index 5e00aabc413..9f9328e88c4 100644
--- a/intern/itasc/kdl/jntarrayvel.cpp
+++ b/intern/itasc/kdl/jntarrayvel.cpp
@@ -1,5 +1,5 @@
/** \file itasc/kdl/jntarrayvel.cpp
- * \ingroup itasc
+ * \ingroup intern_itasc
*/
// Copyright (C) 2007 Ruben Smits <ruben dot smits at mech dot kuleuven dot be>
diff --git a/intern/itasc/kdl/joint.cpp b/intern/itasc/kdl/joint.cpp
index 388539ecb02..2ec71066c66 100644
--- a/intern/itasc/kdl/joint.cpp
+++ b/intern/itasc/kdl/joint.cpp
@@ -1,5 +1,5 @@
/** \file itasc/kdl/joint.cpp
- * \ingroup itasc
+ * \ingroup intern_itasc
*/
// Copyright (C) 2007 Ruben Smits <ruben dot smits at mech dot kuleuven dot be>
diff --git a/intern/itasc/kdl/kinfam_io.cpp b/intern/itasc/kdl/kinfam_io.cpp
index 006c3c797f0..5ae62648c2b 100644
--- a/intern/itasc/kdl/kinfam_io.cpp
+++ b/intern/itasc/kdl/kinfam_io.cpp
@@ -1,5 +1,5 @@
/** \file itasc/kdl/kinfam_io.cpp
- * \ingroup itasc
+ * \ingroup intern_itasc
*/
// Copyright (C) 2007 Ruben Smits <ruben dot smits at mech dot kuleuven dot be>
diff --git a/intern/itasc/kdl/segment.cpp b/intern/itasc/kdl/segment.cpp
index dfdcad5df2d..b116095c8b2 100644
--- a/intern/itasc/kdl/segment.cpp
+++ b/intern/itasc/kdl/segment.cpp
@@ -1,5 +1,5 @@
/** \file itasc/kdl/segment.cpp
- * \ingroup itasc
+ * \ingroup intern_itasc
*/
// Version: 1.0
// Author: Ruben Smits <ruben dot smits at mech dot kuleuven dot be>
diff --git a/intern/itasc/kdl/tree.cpp b/intern/itasc/kdl/tree.cpp
index e266c4d2d50..39c7f58d433 100644
--- a/intern/itasc/kdl/tree.cpp
+++ b/intern/itasc/kdl/tree.cpp
@@ -1,5 +1,5 @@
/** \file itasc/kdl/tree.cpp
- * \ingroup itasc
+ * \ingroup intern_itasc
*/
// Copyright (C) 2007 Ruben Smits <ruben dot smits at mech dot kuleuven dot be>
diff --git a/intern/itasc/kdl/treefksolverpos_recursive.cpp b/intern/itasc/kdl/treefksolverpos_recursive.cpp
index e084296648c..f465e13a84c 100644
--- a/intern/itasc/kdl/treefksolverpos_recursive.cpp
+++ b/intern/itasc/kdl/treefksolverpos_recursive.cpp
@@ -1,5 +1,5 @@
/** \file itasc/kdl/treefksolverpos_recursive.cpp
- * \ingroup itasc
+ * \ingroup intern_itasc
*/
// Copyright (C) 2007 Ruben Smits <ruben dot smits at mech dot kuleuven dot be>
// Copyright (C) 2008 Julia Jesse
diff --git a/intern/itasc/kdl/treejnttojacsolver.cpp b/intern/itasc/kdl/treejnttojacsolver.cpp
index 0db14541bb6..94ecad7aec5 100644
--- a/intern/itasc/kdl/treejnttojacsolver.cpp
+++ b/intern/itasc/kdl/treejnttojacsolver.cpp
@@ -1,5 +1,5 @@
/** \file itasc/kdl/treejnttojacsolver.cpp
- * \ingroup itasc
+ * \ingroup intern_itasc
*/
/*
* TreeJntToJacSolver.cpp
diff --git a/intern/itasc/kdl/utilities/error_stack.cpp b/intern/itasc/kdl/utilities/error_stack.cpp
index a8585681266..a409effb193 100644
--- a/intern/itasc/kdl/utilities/error_stack.cpp
+++ b/intern/itasc/kdl/utilities/error_stack.cpp
@@ -1,5 +1,5 @@
/** \file itasc/kdl/utilities/error_stack.cpp
- * \ingroup itasc
+ * \ingroup intern_itasc
*/
/*****************************************************************************
* Erwin Aertbelien, Div. PMA, Dep. of Mech. Eng., K.U.Leuven
diff --git a/intern/itasc/kdl/utilities/kdl-config.h b/intern/itasc/kdl/utilities/kdl-config.h
index ecdf73612d7..b49ddf91058 100644
--- a/intern/itasc/kdl/utilities/kdl-config.h
+++ b/intern/itasc/kdl/utilities/kdl-config.h
@@ -1,5 +1,5 @@
/** \file itasc/kdl/utilities/kdl-config.h
- * \ingroup itasc
+ * \ingroup intern_itasc
*/
/* Copyright (C) 2007 Ruben Smits <ruben dot smits at mech dot kuleuven dot be> */
diff --git a/intern/itasc/kdl/utilities/traits.h b/intern/itasc/kdl/utilities/traits.h
index 7b0b5f1b30f..32cc2eaa2e3 100644
--- a/intern/itasc/kdl/utilities/traits.h
+++ b/intern/itasc/kdl/utilities/traits.h
@@ -1,5 +1,5 @@
/** \file itasc/kdl/utilities/traits.h
- * \ingroup itasc
+ * \ingroup intern_itasc
*/
#ifndef KDLPV_TRAITS_H
#define KDLPV_TRAITS_H
diff --git a/intern/itasc/kdl/utilities/utility.cpp b/intern/itasc/kdl/utilities/utility.cpp
index 5fc8403bdb7..fa8f89fde63 100644
--- a/intern/itasc/kdl/utilities/utility.cpp
+++ b/intern/itasc/kdl/utilities/utility.cpp
@@ -1,5 +1,5 @@
/** \file itasc/kdl/utilities/utility.cpp
- * \ingroup itasc
+ * \ingroup intern_itasc
*/
/** @file utility.cpp
* @author Erwin Aertbelien, Div. PMA, Dep. of Mech. Eng., K.U.Leuven
diff --git a/intern/itasc/kdl/utilities/utility_io.cpp b/intern/itasc/kdl/utilities/utility_io.cpp
index 8d289dbfa50..de9511b9efb 100644
--- a/intern/itasc/kdl/utilities/utility_io.cpp
+++ b/intern/itasc/kdl/utilities/utility_io.cpp
@@ -1,5 +1,5 @@
/** \file itasc/kdl/utilities/utility_io.cpp
- * \ingroup itasc
+ * \ingroup intern_itasc
*/
/*****************************************************************************
* Erwin Aertbelien, Div. PMA, Dep. of Mech. Eng., K.U.Leuven
diff --git a/intern/libc_compat/libc_compat.c b/intern/libc_compat/libc_compat.c
index 78e387e3117..0bf22879422 100644
--- a/intern/libc_compat/libc_compat.c
+++ b/intern/libc_compat/libc_compat.c
@@ -21,6 +21,10 @@
* incompatible with the system libraries that Blender is built on. To solve
* this we add a few -ffast-math symbols that can be missing. */
+/** \file
+ * \ingroup intern_libc_compat
+ */
+
#ifdef __linux__
# include <features.h>
# include <math.h>
diff --git a/intern/libmv/libmv/multiview/fundamental.cc b/intern/libmv/libmv/multiview/fundamental.cc
index c8c94ecd7bb..2ad78369761 100644
--- a/intern/libmv/libmv/multiview/fundamental.cc
+++ b/intern/libmv/libmv/multiview/fundamental.cc
@@ -411,7 +411,7 @@ void FundamentalToEssential(const Mat3& F, Mat3* E) {
// Default settings for fundamental estimation which should be suitable
// for a wide range of use cases.
-EstimateFundamentalOptions::EstimateFundamentalOptions(void)
+EstimateFundamentalOptions::EstimateFundamentalOptions()
: max_num_iterations(50), expected_average_symmetric_distance(1e-16) {
}
diff --git a/intern/libmv/libmv/multiview/homography.cc b/intern/libmv/libmv/multiview/homography.cc
index 2db2c0cd3d5..30b8d982b86 100644
--- a/intern/libmv/libmv/multiview/homography.cc
+++ b/intern/libmv/libmv/multiview/homography.cc
@@ -157,7 +157,7 @@ bool Homography2DFromCorrespondencesLinear(const Mat& x1,
// Default settings for homography estimation which should be suitable
// for a wide range of use cases.
-EstimateHomographyOptions::EstimateHomographyOptions(void)
+EstimateHomographyOptions::EstimateHomographyOptions()
: use_normalization(true),
max_num_iterations(50),
expected_average_symmetric_distance(1e-16) {
diff --git a/intern/locale/boost_locale_wrapper.cpp b/intern/locale/boost_locale_wrapper.cpp
index 444b51b5e04..873ebca6873 100644
--- a/intern/locale/boost_locale_wrapper.cpp
+++ b/intern/locale/boost_locale_wrapper.cpp
@@ -17,6 +17,10 @@
* All rights reserved.
*/
+/** \file
+ * \ingroup intern_locale
+ */
+
#include <boost/locale.hpp>
#include <stdio.h>
diff --git a/intern/locale/boost_locale_wrapper.h b/intern/locale/boost_locale_wrapper.h
index deb552e4871..8eb51735fe5 100644
--- a/intern/locale/boost_locale_wrapper.h
+++ b/intern/locale/boost_locale_wrapper.h
@@ -18,8 +18,8 @@
*/
/** \file
- * \ingroup locale
- * A thin C wrapper around boost::locale...
+ * \ingroup intern_locale
+ * A thin C wrapper around `boost::locale`.
*/
#ifndef __BOOST_LOCALE_WRAPPER_H__
diff --git a/intern/locale/osx_user_locale.mm b/intern/locale/osx_user_locale.mm
index ce694b5fc1e..8776c658b52 100644
--- a/intern/locale/osx_user_locale.mm
+++ b/intern/locale/osx_user_locale.mm
@@ -1,5 +1,9 @@
#include "boost_locale_wrapper.h"
+/** \file
+ * \ingroup intern_locale
+ */
+
#import <Cocoa/Cocoa.h>
#include <cstdlib>
diff --git a/intern/mantaflow/extern/manta_fluid_API.h b/intern/mantaflow/extern/manta_fluid_API.h
index e4ad4c66d8a..d59a7bde426 100644
--- a/intern/mantaflow/extern/manta_fluid_API.h
+++ b/intern/mantaflow/extern/manta_fluid_API.h
@@ -18,7 +18,7 @@
*/
/** \file
- * \ingroup mantaflow
+ * \ingroup intern_mantaflow
*/
#ifndef MANTA_API_H
diff --git a/intern/mantaflow/extern/manta_python_API.h b/intern/mantaflow/extern/manta_python_API.h
index 02d96d2e5f2..1d66725946b 100644
--- a/intern/mantaflow/extern/manta_python_API.h
+++ b/intern/mantaflow/extern/manta_python_API.h
@@ -18,7 +18,7 @@
*/
/** \file
- * \ingroup mantaflow
+ * \ingroup intern_mantaflow
*/
#ifndef MANTA_PYTHON_API_H
diff --git a/intern/mantaflow/intern/MANTA_main.cpp b/intern/mantaflow/intern/MANTA_main.cpp
index 6c8e45ceeb4..858e17443d3 100644
--- a/intern/mantaflow/intern/MANTA_main.cpp
+++ b/intern/mantaflow/intern/MANTA_main.cpp
@@ -18,7 +18,7 @@
*/
/** \file
- * \ingroup mantaflow
+ * \ingroup intern_mantaflow
*/
#include <fstream>
diff --git a/intern/mantaflow/intern/MANTA_main.h b/intern/mantaflow/intern/MANTA_main.h
index 7129a545243..5514b1c651a 100644
--- a/intern/mantaflow/intern/MANTA_main.h
+++ b/intern/mantaflow/intern/MANTA_main.h
@@ -18,7 +18,7 @@
*/
/** \file
- * \ingroup mantaflow
+ * \ingroup intern_mantaflow
*/
#ifndef MANTA_A_H
diff --git a/intern/mantaflow/intern/manta_fluid_API.cpp b/intern/mantaflow/intern/manta_fluid_API.cpp
index 5b27bd91d91..4a096afa9c8 100644
--- a/intern/mantaflow/intern/manta_fluid_API.cpp
+++ b/intern/mantaflow/intern/manta_fluid_API.cpp
@@ -18,7 +18,7 @@
*/
/** \file
- * \ingroup mantaflow
+ * \ingroup intern_mantaflow
*/
#include <cmath>
diff --git a/intern/mantaflow/intern/manta_python_API.cpp b/intern/mantaflow/intern/manta_python_API.cpp
index a905e045fd3..977a5b6b7c4 100644
--- a/intern/mantaflow/intern/manta_python_API.cpp
+++ b/intern/mantaflow/intern/manta_python_API.cpp
@@ -18,7 +18,7 @@
*/
/** \file
- * \ingroup mantaflow
+ * \ingroup intern_mantaflow
*/
#include "manta_python_API.h"
diff --git a/intern/mantaflow/intern/strings/fluid_script.h b/intern/mantaflow/intern/strings/fluid_script.h
index 3bf8e66c110..f3a72e69cd3 100644
--- a/intern/mantaflow/intern/strings/fluid_script.h
+++ b/intern/mantaflow/intern/strings/fluid_script.h
@@ -18,7 +18,7 @@
*/
/** \file
- * \ingroup mantaflow
+ * \ingroup intern_mantaflow
*/
#include <string>
diff --git a/intern/mantaflow/intern/strings/liquid_script.h b/intern/mantaflow/intern/strings/liquid_script.h
index c44727bd47e..94450653703 100644
--- a/intern/mantaflow/intern/strings/liquid_script.h
+++ b/intern/mantaflow/intern/strings/liquid_script.h
@@ -18,7 +18,7 @@
*/
/** \file
- * \ingroup mantaflow
+ * \ingroup intern_mantaflow
*/
#include <string>
diff --git a/intern/mantaflow/intern/strings/smoke_script.h b/intern/mantaflow/intern/strings/smoke_script.h
index 157cfff1a27..9a6f6c0a0e0 100644
--- a/intern/mantaflow/intern/strings/smoke_script.h
+++ b/intern/mantaflow/intern/strings/smoke_script.h
@@ -18,7 +18,7 @@
*/
/** \file
- * \ingroup mantaflow
+ * \ingroup intern_mantaflow
*/
#include <string>
diff --git a/intern/memutil/MEM_Allocator.h b/intern/memutil/MEM_Allocator.h
index 1dbb2d5a9f7..2afe66023ac 100644
--- a/intern/memutil/MEM_Allocator.h
+++ b/intern/memutil/MEM_Allocator.h
@@ -15,7 +15,7 @@
*/
/** \file
- * \ingroup memutil
+ * \ingroup intern_memutil
*/
#ifndef __MEM_ALLOCATOR_H__
diff --git a/intern/memutil/MEM_CacheLimiter.h b/intern/memutil/MEM_CacheLimiter.h
index a8706454de8..d0e52f8540c 100644
--- a/intern/memutil/MEM_CacheLimiter.h
+++ b/intern/memutil/MEM_CacheLimiter.h
@@ -15,7 +15,7 @@
*/
/** \file
- * \ingroup memutil
+ * \ingroup intern_memutil
*/
#ifndef __MEM_CACHELIMITER_H__
diff --git a/intern/memutil/MEM_CacheLimiterC-Api.h b/intern/memutil/MEM_CacheLimiterC-Api.h
index 2bbbfb75555..9a2e404d9da 100644
--- a/intern/memutil/MEM_CacheLimiterC-Api.h
+++ b/intern/memutil/MEM_CacheLimiterC-Api.h
@@ -15,7 +15,7 @@
*/
/** \file
- * \ingroup memutil
+ * \ingroup intern_memutil
*/
#ifndef __MEM_CACHELIMITERC_API_H__
diff --git a/intern/memutil/MEM_RefCounted.h b/intern/memutil/MEM_RefCounted.h
index 06828fc32c3..319effdebaf 100644
--- a/intern/memutil/MEM_RefCounted.h
+++ b/intern/memutil/MEM_RefCounted.h
@@ -18,7 +18,7 @@
*/
/** \file
- * \ingroup memutil
+ * \ingroup intern_memutil
*
* Declaration of MEM_RefCounted class.
*/
diff --git a/intern/memutil/MEM_RefCountedC-Api.h b/intern/memutil/MEM_RefCountedC-Api.h
index 2a132f3c173..0e5dd5e0ae3 100644
--- a/intern/memutil/MEM_RefCountedC-Api.h
+++ b/intern/memutil/MEM_RefCountedC-Api.h
@@ -18,7 +18,7 @@
*/
/** \file
- * \ingroup memutil
+ * \ingroup intern_memutil
*
* Interface for C access to functionality relating to shared objects in the foundation library.
*/
diff --git a/intern/memutil/intern/MEM_CacheLimiterC-Api.cpp b/intern/memutil/intern/MEM_CacheLimiterC-Api.cpp
index 9f583c948ee..099c89f2dfe 100644
--- a/intern/memutil/intern/MEM_CacheLimiterC-Api.cpp
+++ b/intern/memutil/intern/MEM_CacheLimiterC-Api.cpp
@@ -15,7 +15,7 @@
*/
/** \file
- * \ingroup memutil
+ * \ingroup intern_memutil
*/
#include <cstddef>
diff --git a/intern/memutil/intern/MEM_RefCountedC-Api.cpp b/intern/memutil/intern/MEM_RefCountedC-Api.cpp
index c319d6321f4..8a0eebcd5e4 100644
--- a/intern/memutil/intern/MEM_RefCountedC-Api.cpp
+++ b/intern/memutil/intern/MEM_RefCountedC-Api.cpp
@@ -18,7 +18,7 @@
*/
/** \file
- * \ingroup memutil
+ * \ingroup intern_memutil
*/
#include "MEM_RefCountedC-Api.h"
diff --git a/intern/numaapi/include/numaapi.h b/intern/numaapi/include/numaapi.h
index ce7139a9cfb..11e916019ef 100644
--- a/intern/numaapi/include/numaapi.h
+++ b/intern/numaapi/include/numaapi.h
@@ -20,6 +20,10 @@
//
// Author: Sergey Sharybin <sergey.vfx@gmail.com>
+/** \file
+ * \ingroup intern_numaapi
+ */
+
#ifndef __LIBNUMAAPI_H__
#define __LIBNUMAAPI_H__
diff --git a/intern/numaapi/source/build_config.h b/intern/numaapi/source/build_config.h
index 49d82aa3e87..e7c332483b5 100644
--- a/intern/numaapi/source/build_config.h
+++ b/intern/numaapi/source/build_config.h
@@ -20,6 +20,10 @@
//
// Author: Sergey Sharybin <sergey.vfx@gmail.com>
+/** \file
+ * \ingroup intern_numaapi
+ */
+
#ifndef __BUILD_CONFIG_H__
#define __BUILD_CONFIG_H__
diff --git a/intern/numaapi/source/numaapi.c b/intern/numaapi/source/numaapi.c
index c482fc556bb..ef3f5b19dac 100644
--- a/intern/numaapi/source/numaapi.c
+++ b/intern/numaapi/source/numaapi.c
@@ -20,6 +20,10 @@
//
// Author: Sergey Sharybin <sergey.vfx@gmail.com>
+/** \file
+ * \ingroup intern_numaapi
+ */
+
#include "numaapi.h"
#include <assert.h>
diff --git a/intern/numaapi/source/numaapi_linux.c b/intern/numaapi/source/numaapi_linux.c
index 853aeeb34ba..ed5ae1bd35d 100644
--- a/intern/numaapi/source/numaapi_linux.c
+++ b/intern/numaapi/source/numaapi_linux.c
@@ -20,6 +20,10 @@
//
// Author: Sergey Sharybin <sergey.vfx@gmail.com>
+/** \file
+ * \ingroup intern_numaapi
+ */
+
#include "build_config.h"
#if OS_LINUX
diff --git a/intern/numaapi/source/numaapi_stub.c b/intern/numaapi/source/numaapi_stub.c
index a364eb9135a..85a4fab0a86 100644
--- a/intern/numaapi/source/numaapi_stub.c
+++ b/intern/numaapi/source/numaapi_stub.c
@@ -20,6 +20,10 @@
//
// Author: Sergey Sharybin <sergey.vfx@gmail.com>
+/** \file
+ * \ingroup intern_numaapi
+ */
+
#include "numaapi.h"
#include "build_config.h"
diff --git a/intern/numaapi/source/numaapi_win32.c b/intern/numaapi/source/numaapi_win32.c
index 93064ff48b7..1a3634539ce 100644
--- a/intern/numaapi/source/numaapi_win32.c
+++ b/intern/numaapi/source/numaapi_win32.c
@@ -20,6 +20,10 @@
//
// Author: Sergey Sharybin <sergey.vfx@gmail.com>
+/** \file
+ * \ingroup intern_numaapi
+ */
+
#include "build_config.h"
#if OS_WIN
diff --git a/intern/opencolorio/fallback_impl.cc b/intern/opencolorio/fallback_impl.cc
index 9bbc9843e9d..42a2b5bf3b6 100644
--- a/intern/opencolorio/fallback_impl.cc
+++ b/intern/opencolorio/fallback_impl.cc
@@ -123,7 +123,7 @@ struct FallbackProcessor {
MEM_CXX_CLASS_ALLOC_FUNCS("FallbackProcessor");
};
-OCIO_ConstConfigRcPtr *FallbackImpl::getCurrentConfig(void)
+OCIO_ConstConfigRcPtr *FallbackImpl::getCurrentConfig()
{
return CONFIG_DEFAULT;
}
@@ -132,7 +132,7 @@ void FallbackImpl::setCurrentConfig(const OCIO_ConstConfigRcPtr * /*config*/)
{
}
-OCIO_ConstConfigRcPtr *FallbackImpl::configCreateFromEnv(void)
+OCIO_ConstConfigRcPtr *FallbackImpl::configCreateFromEnv()
{
return NULL;
}
@@ -502,12 +502,12 @@ void FallbackImpl::OCIO_PackedImageDescRelease(OCIO_PackedImageDesc *id)
MEM_freeN(id);
}
-const char *FallbackImpl::getVersionString(void)
+const char *FallbackImpl::getVersionString()
{
return "fallback";
}
-int FallbackImpl::getVersionHex(void)
+int FallbackImpl::getVersionHex()
{
return 0;
}
diff --git a/intern/opencolorio/ocio_capi.cc b/intern/opencolorio/ocio_capi.cc
index 49231dee501..f4071edf6e5 100644
--- a/intern/opencolorio/ocio_capi.cc
+++ b/intern/opencolorio/ocio_capi.cc
@@ -23,7 +23,7 @@
static IOCIOImpl *impl = NULL;
-void OCIO_init(void)
+void OCIO_init()
{
#ifdef WITH_OCIO
impl = new OCIOImpl();
@@ -32,18 +32,18 @@ void OCIO_init(void)
#endif
}
-void OCIO_exit(void)
+void OCIO_exit()
{
delete impl;
impl = NULL;
}
-OCIO_ConstConfigRcPtr *OCIO_getCurrentConfig(void)
+OCIO_ConstConfigRcPtr *OCIO_getCurrentConfig()
{
return impl->getCurrentConfig();
}
-OCIO_ConstConfigRcPtr *OCIO_configCreateFallback(void)
+OCIO_ConstConfigRcPtr *OCIO_configCreateFallback()
{
delete impl;
impl = new FallbackImpl();
@@ -56,7 +56,7 @@ void OCIO_setCurrentConfig(const OCIO_ConstConfigRcPtr *config)
impl->setCurrentConfig(config);
}
-OCIO_ConstConfigRcPtr *OCIO_configCreateFromEnv(void)
+OCIO_ConstConfigRcPtr *OCIO_configCreateFromEnv()
{
return impl->configCreateFromEnv();
}
@@ -308,22 +308,22 @@ bool OCIO_gpuDisplayShaderBind(OCIO_ConstConfigRcPtr *config,
use_overlay);
}
-void OCIO_gpuDisplayShaderUnbind(void)
+void OCIO_gpuDisplayShaderUnbind()
{
impl->gpuDisplayShaderUnbind();
}
-void OCIO_gpuCacheFree(void)
+void OCIO_gpuCacheFree()
{
impl->gpuCacheFree();
}
-const char *OCIO_getVersionString(void)
+const char *OCIO_getVersionString()
{
return impl->getVersionString();
}
-int OCIO_getVersionHex(void)
+int OCIO_getVersionHex()
{
return impl->getVersionHex();
}
diff --git a/intern/opencolorio/ocio_impl.cc b/intern/opencolorio/ocio_impl.cc
index 146d5d1a5a7..058b8f51dd6 100644
--- a/intern/opencolorio/ocio_impl.cc
+++ b/intern/opencolorio/ocio_impl.cc
@@ -580,8 +580,8 @@ void OCIOImpl::cpuProcessorApply_predivide(OCIO_ConstCPUProcessorRcPtr *cpu_proc
assert(img->isFloat());
float *pixels = (float *)img->getData();
- int width = img->getWidth();
- int height = img->getHeight();
+ size_t width = img->getWidth();
+ size_t height = img->getHeight();
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
diff --git a/intern/opensubdiv/internal/base/opensubdiv_capi.cc b/intern/opensubdiv/internal/base/opensubdiv_capi.cc
index 430acfd4497..85f8120c76b 100644
--- a/intern/opensubdiv/internal/base/opensubdiv_capi.cc
+++ b/intern/opensubdiv/internal/base/opensubdiv_capi.cc
@@ -33,17 +33,17 @@ using blender::opensubdiv::GLSLTransformFeedbackDeviceContext;
using blender::opensubdiv::OpenCLDeviceContext;
using blender::opensubdiv::OpenMPDeviceContext;
-void openSubdiv_init(void)
+void openSubdiv_init()
{
// Ensure all OpenGL strings are cached.
openSubdiv_getAvailableEvaluators();
}
-void openSubdiv_cleanup(void)
+void openSubdiv_cleanup()
{
}
-int openSubdiv_getAvailableEvaluators(void)
+int openSubdiv_getAvailableEvaluators()
{
int flags = OPENSUBDIV_EVALUATOR_CPU;
@@ -70,7 +70,7 @@ int openSubdiv_getAvailableEvaluators(void)
return flags;
}
-int openSubdiv_getVersionHex(void)
+int openSubdiv_getVersionHex()
{
#if defined(OPENSUBDIV_VERSION_NUMBER)
return OPENSUBDIV_VERSION_NUMBER;
diff --git a/intern/opensubdiv/internal/evaluator/evaluator_impl.h b/intern/opensubdiv/internal/evaluator/evaluator_impl.h
index 6a3682efa62..e7ccc9b376a 100644
--- a/intern/opensubdiv/internal/evaluator/evaluator_impl.h
+++ b/intern/opensubdiv/internal/evaluator/evaluator_impl.h
@@ -37,7 +37,7 @@ namespace opensubdiv {
// Anonymous forward declaration of actual evaluator implementation.
class CpuEvalOutput;
-// Wrapper around implementaiton, which defines API which we are capable to
+// Wrapper around implementation, which defines API which we are capable to
// provide over the implementation.
//
// TODO(sergey): It is almost the same as C-API object, so ideally need to
diff --git a/intern/opensubdiv/stub/opensubdiv_stub.cc b/intern/opensubdiv/stub/opensubdiv_stub.cc
index 8c0b204d41a..24bdcbc79ff 100644
--- a/intern/opensubdiv/stub/opensubdiv_stub.cc
+++ b/intern/opensubdiv/stub/opensubdiv_stub.cc
@@ -20,20 +20,20 @@
#include <cstddef>
-void openSubdiv_init(void)
+void openSubdiv_init()
{
}
-void openSubdiv_cleanup(void)
+void openSubdiv_cleanup()
{
}
-int openSubdiv_getAvailableEvaluators(void)
+int openSubdiv_getAvailableEvaluators()
{
return 0;
}
-int openSubdiv_getVersionHex(void)
+int openSubdiv_getVersionHex()
{
return 0;
}
diff --git a/intern/rigidbody/RBI_api.h b/intern/rigidbody/RBI_api.h
index f13f321a2c6..c37d4bc6619 100644
--- a/intern/rigidbody/RBI_api.h
+++ b/intern/rigidbody/RBI_api.h
@@ -18,7 +18,7 @@
*/
/** \file
- * \ingroup RigidBody
+ * \ingroup intern_rigidbody
* \brief Rigid Body API for interfacing with external Physics Engines
*/
diff --git a/intern/rigidbody/RBI_hull_api.h b/intern/rigidbody/RBI_hull_api.h
index 3bd216b92cb..01c98f4772e 100644
--- a/intern/rigidbody/RBI_hull_api.h
+++ b/intern/rigidbody/RBI_hull_api.h
@@ -17,6 +17,10 @@
* All rights reserved.
*/
+/** \file
+ * \ingroup intern_rigidbody
+ */
+
#ifndef __RB_HULL_API_H__
#define __RB_HULL_API_H__
diff --git a/intern/rigidbody/rb_bullet_api.cpp b/intern/rigidbody/rb_bullet_api.cpp
index daa377a7b55..57d55939218 100644
--- a/intern/rigidbody/rb_bullet_api.cpp
+++ b/intern/rigidbody/rb_bullet_api.cpp
@@ -18,7 +18,7 @@
*/
/** \file
- * \ingroup RigidBody
+ * \ingroup intern_rigidbody
* \brief Rigid Body API implementation for Bullet
*/
diff --git a/intern/rigidbody/rb_convex_hull_api.cpp b/intern/rigidbody/rb_convex_hull_api.cpp
index 03e7580a12b..3b80dfdeae9 100644
--- a/intern/rigidbody/rb_convex_hull_api.cpp
+++ b/intern/rigidbody/rb_convex_hull_api.cpp
@@ -17,6 +17,10 @@
* All rights reserved.
*/
+/** \file
+ * \ingroup intern_rigidbody
+ */
+
#include "LinearMath/btConvexHullComputer.h"
#include "RBI_hull_api.h"
diff --git a/intern/sky/include/sky_model.h b/intern/sky/include/sky_model.h
index 752b5c13785..38a479ade0f 100644
--- a/intern/sky/include/sky_model.h
+++ b/intern/sky/include/sky_model.h
@@ -298,6 +298,10 @@ HINT #1: if you want to model the sky of an earth-like planet that orbits
previous paragraph.
*/
+/** \file
+ * \ingroup intern_sky_modal
+ */
+
#ifndef __SKY_MODEL_H__
#define __SKY_MODEL_H__
diff --git a/intern/sky/source/sky_float3.h b/intern/sky/source/sky_float3.h
index 2a9b9c89623..8370d8127ed 100644
--- a/intern/sky/source/sky_float3.h
+++ b/intern/sky/source/sky_float3.h
@@ -14,6 +14,10 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+/** \file
+ * \ingroup intern_sky_modal
+ */
+
#ifndef __SKY_FLOAT3_H__
#define __SKY_FLOAT3_H__
diff --git a/intern/sky/source/sky_model.cpp b/intern/sky/source/sky_model.cpp
index 165444003d3..b5bf415da26 100644
--- a/intern/sky/source/sky_model.cpp
+++ b/intern/sky/source/sky_model.cpp
@@ -97,6 +97,10 @@ All instructions on how to use this code are in the accompanying header file.
*/
+/** \file
+ * \ingroup intern_sky_modal
+ */
+
#include "sky_model.h"
#include "sky_model_data.h"
diff --git a/intern/sky/source/sky_model_data.h b/intern/sky/source/sky_model_data.h
index 8d98f84cdae..4f7bcb7cc48 100644
--- a/intern/sky/source/sky_model_data.h
+++ b/intern/sky/source/sky_model_data.h
@@ -98,6 +98,10 @@ the model.
*/
+/** \file
+ * \ingroup intern_sky_modal
+ */
+
// Uses Sep 9 pattern / Aug 23 mean dataset
static const double datasetXYZ1[] = {
diff --git a/intern/sky/source/sky_nishita.cpp b/intern/sky/source/sky_nishita.cpp
index e3b6ca021fe..615755390c7 100644
--- a/intern/sky/source/sky_nishita.cpp
+++ b/intern/sky/source/sky_nishita.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+/** \file
+ * \ingroup intern_sky_modal
+ */
+
#include "sky_float3.h"
#include "sky_model.h"
@@ -26,7 +30,6 @@ static const float sqr_G = mie_G * mie_G; // squared aerosols anisotropy
static const float earth_radius = 6360e3f; // radius of Earth (m)
static const float atmosphere_radius = 6420e3f; // radius of atmosphere (m)
static const int steps = 32; // segments of primary ray
-static const int steps_light = 16; // segments of sun connection ray
static const int num_wavelengths = 21; // number of wavelengths
static const int min_wavelength = 380; // lowest sampled wavelength (nm)
static const int max_wavelength = 780; // highest sampled wavelength (nm)
@@ -82,6 +85,34 @@ static const float cmf_xyz[][3] = {{0.00136800000f, 0.00003900000f, 0.0064500010
{0.00016615050f, 0.00006000000f, 0.00000000000f},
{0.00004150994f, 0.00001499000f, 0.00000000000f}};
+/* Parameters for optical depth quadrature.
+ * See the comment in ray_optical_depth for more detail.
+ * Computed using sympy and following Python code:
+ * # from sympy.integrals.quadrature import gauss_laguerre
+ * # from sympy import exp
+ * # x, w = gauss_laguerre(8, 50)
+ * # xend = 25
+ * # print([(xi / xend).evalf(10) for xi in x])
+ * # print([(wi * exp(xi) / xend).evalf(10) for xi, wi in zip(x, w)])
+ */
+static const int quadrature_steps = 8;
+static const float quadrature_nodes[] = {0.006811185292f,
+ 0.03614807107f,
+ 0.09004346519f,
+ 0.1706680068f,
+ 0.2818362161f,
+ 0.4303406404f,
+ 0.6296271457f,
+ 0.9145252695f};
+static const float quadrature_weights[] = {0.01750893642f,
+ 0.04135477391f,
+ 0.06678839063f,
+ 0.09507698807f,
+ 0.1283416365f,
+ 0.1707430204f,
+ 0.2327233347f,
+ 0.3562490486f};
+
static float3 geographical_to_direction(float lat, float lon)
{
return make_float3(cosf(lat) * cosf(lon), cosf(lat) * sinf(lon), sinf(lat));
@@ -157,14 +188,19 @@ static float3 atmosphere_intersection(float3 pos, float3 dir)
static float3 ray_optical_depth(float3 ray_origin, float3 ray_dir)
{
- /* this code computes the optical depth along a ray through the atmosphere */
+ /* This function computes the optical depth along a ray.
+ * Instead of using classic ray marching, the code is based on Gauss-Laguerre quadrature,
+ * which is designed to compute the integral of f(x)*exp(-x) from 0 to infinity.
+ * This works well here, since the optical depth along the ray tends to decrease exponentially.
+ * By setting f(x) = g(x) exp(x), the exponentials cancel out and we get the integral of g(x).
+ * The nodes and weights used here are the standard n=6 Gauss-Laguerre values, except that
+ * the exp(x) scaling factor is already included in the weights.
+ * The parametrization along the ray is scaled so that the last quadrature node is still within
+ * the atmosphere. */
float3 ray_end = atmosphere_intersection(ray_origin, ray_dir);
float ray_length = distance(ray_origin, ray_end);
- /* to compute the optical depth, we step along the ray in segments and
- * accumulate the optical depth along each segment */
- float segment_length = ray_length / steps_light;
- float3 segment = segment_length * ray_dir;
+ float3 segment = ray_length * ray_dir;
/* instead of tracking the transmission spectrum across all wavelengths directly,
* we use the fact that the density always has the same spectrum for each type of
@@ -172,23 +208,18 @@ static float3 ray_optical_depth(float3 ray_origin, float3 ray_dir)
* only track the factors */
float3 optical_depth = make_float3(0.0f, 0.0f, 0.0f);
- /* the density of each segment is evaluated at its middle */
- float3 P = ray_origin + 0.5f * segment;
+ for (int i = 0; i < quadrature_steps; i++) {
+ float3 P = ray_origin + quadrature_nodes[i] * segment;
- for (int i = 0; i < steps_light; i++) {
/* height above sea level */
float height = len(P) - earth_radius;
- /* accumulate optical depth of this segment (density is assumed to be constant along it) */
float3 density = make_float3(
density_rayleigh(height), density_mie(height), density_ozone(height));
- optical_depth += density;
-
- /* advance along ray */
- P += segment;
+ optical_depth += density * quadrature_weights[i];
}
- return optical_depth * segment_length;
+ return optical_depth * ray_length;
}
static void single_scattering(float3 ray_dir,
diff --git a/intern/utfconv/utf_winfunc.c b/intern/utfconv/utf_winfunc.c
index 615379d454a..9de2bcab3fc 100644
--- a/intern/utfconv/utf_winfunc.c
+++ b/intern/utfconv/utf_winfunc.c
@@ -17,6 +17,10 @@
* All rights reserved.
*/
+/** \file
+ * \ingroup intern_utf_conv
+ */
+
#ifndef _WIN32_IE
# define _WIN32_IE 0x0501
#endif
diff --git a/intern/utfconv/utf_winfunc.h b/intern/utfconv/utf_winfunc.h
index 596109cac0e..b6f2ccad219 100644
--- a/intern/utfconv/utf_winfunc.h
+++ b/intern/utfconv/utf_winfunc.h
@@ -15,7 +15,10 @@
*
* The Original Code is Copyright (C) 2012 Blender Foundation.
* All rights reserved.
- *
+ */
+
+/** \file
+ * \ingroup intern_utf_conv
*/
#ifndef __UTF_WINFUNC_H__
diff --git a/intern/utfconv/utfconv.c b/intern/utfconv/utfconv.c
index 26fb1d44d28..00094b84042 100644
--- a/intern/utfconv/utfconv.c
+++ b/intern/utfconv/utfconv.c
@@ -15,7 +15,10 @@
*
* The Original Code is Copyright (C) 2012 Blender Foundation.
* All rights reserved.
- *
+ */
+
+/** \file
+ * \ingroup intern_utf_conv
*/
#include "utfconv.h"
diff --git a/intern/utfconv/utfconv.h b/intern/utfconv/utfconv.h
index b4addd72c75..d3f62dfc1a4 100644
--- a/intern/utfconv/utfconv.h
+++ b/intern/utfconv/utfconv.h
@@ -15,7 +15,10 @@
*
* The Original Code is Copyright (C) 2012 Blender Foundation.
* All rights reserved.
- *
+ */
+
+/** \file
+ * \ingroup intern_utf_conv
*/
#ifndef __UTFCONV_H__
diff --git a/release/datafiles/blender_icons.svg b/release/datafiles/blender_icons.svg
index c87ad40ac0f..63e57a22b9d 100644
--- a/release/datafiles/blender_icons.svg
+++ b/release/datafiles/blender_icons.svg
@@ -8521,26 +8521,6 @@
sodipodi:nodetypes="sssssssssssssss" />
</g>
<g
- transform="matrix(0.92857149,0,0,0.92857137,106.93015,-501.7093)"
- style="display:inline;opacity:0.98999999;fill:#ffffff;stroke-width:1.07692313;enable-background:new"
- id="g8599"
- inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
- <path
- sodipodi:nodetypes="cccccccccccssccsssss"
- inkscape:connector-curvature="0"
- id="path8595"
- transform="matrix(1.076923,0,0,1.0769231,-739.76878,506.92345)"
- d="m 992.67578,105.26367 c -0.19597,-0.18575 -0.45872,-0.28437 -0.72851,-0.27344 -0.89539,0.0396 -1.29072,1.14623 -0.62305,1.74415 L 992.69727,108 H 986 c -1.36099,-0.0279 -1.36099,2.02794 0,2 h 3.0918 c -0.003,0.002 -0.005,0.004 -0.008,0.006 l -4.75,4.24805 c -0.99479,0.88933 0.3392,2.38151 1.33399,1.49218 l 2.33984,-2.09375 C 988.08993,116.60772 990.52575,119 993.5,119 c 3.02565,0 5.49805,-2.47428 5.49805,-5.5 0,-1.56564 -0.66395,-2.97983 -1.72241,-3.98356 z M 993.5,110 c 1.94471,0 3.5,1.5551 3.5,3.5 0,1.94489 -1.55529,3.5 -3.5,3.5 -1.94472,0 -3.5,-1.55511 -3.5,-3.5 0,-1.9449 1.55528,-3.5 3.5,-3.5 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
- <path
- id="path8597"
- d="m 331.99999,629.15424 a 1.86519,1.8457757 0 0 1 -1.86519,1.84577 1.86519,1.8457757 0 0 1 -1.86519,-1.84577 1.86519,1.8457757 0 0 1 1.86519,-1.84578 1.86519,1.8457757 0 0 1 1.86519,1.84578 z"
- style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2.15384626;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
- inkscape:connector-curvature="0" />
- </g>
- <g
id="g12575"
transform="matrix(0.8666665,0,0,0.8666665,-253.07368,16.407198)"
style="display:inline;opacity:1;fill:#ffffff;stroke-width:1.15384638;enable-background:new"
@@ -13730,11 +13710,6 @@
style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new" />
</g>
<path
- inkscape:connector-curvature="0"
- id="path18041"
- d="m 517.0019,53.000264 c -0.47496,-0.0438 -0.94252,0.0803 -1.30468,0.35742 -0.28815,0.22047 -0.55389,0.56737 -0.6211,1.0332 -0.0672,0.46584 0.11485,1.01133 0.57227,1.46876 l 0.14648,0.14648 h -4.29297 c -0.53506,4e-5 -1.03128,0.28661 -1.29883,0.75 -0.26752,0.46339 -0.26752,1.03661 0,1.5 0.26755,0.46339 0.76375,0.75 1.29883,0.75 h 0.79297 l -2.64648,2.64648 c -0.79091,0.79079 -0.84722,1.93194 -0.29297,2.65625 0.22044,0.28814 0.56748,0.55402 1.0332,0.6211 0.46572,0.0671 1.0091,-0.11342 1.4668,-0.57031 l 1.4043,-1.40235 c 0.55515,1.96585 2.10614,3.53021 4.16406,3.94141 2.37442,0.47444 4.78539,-0.66388 5.92773,-2.79883 1.14235,-2.13495 0.75134,-4.77035 -0.96094,-6.48242 a 0.50005,0.50005 0 0 0 -0.002,-0.004 l -4.0332,-3.96094 c -0.39539,-0.39541 -0.87856,-0.60853 -1.35352,-0.65234 z m -0.0957,1.00195 c 0.24304,0.0198 0.50958,0.1248 0.74219,0.35743 a 0.50005,0.50005 0 0 0 0.004,0.002 l 4.03125,3.96289 c 1.40369,1.40351 1.72164,3.55449 0.78516,5.30469 -0.93648,1.7502 -2.90114,2.678 -4.84766,2.28906 -1.9465,-0.38894 -3.40679,-2.00407 -3.60937,-3.97266 a 0.50005,0.50005 0 0 0 -0.85156,-0.30273 l -2.01172,2.00976 c -0.29296,0.29245 -0.47153,0.30809 -0.61719,0.28711 -0.14566,-0.021 -0.29945,-0.12932 -0.38281,-0.23828 -0.21096,-0.27568 -0.25826,-0.87658 0.20703,-1.34179 l 3.5,-3.5 a 0.50005,0.50005 0 0 0 -0.35352,-0.85352 h -2 c -0.17943,0 -0.34387,-0.0946 -0.43359,-0.25 -0.0897,-0.15539 -0.0897,-0.34461 0,-0.5 0.0897,-0.15539 0.25413,-0.24999 0.43359,-0.25 h 5.5 a 0.50005,0.50005 0 0 0 0.35352,-0.85352 l -1,-1 c -0.29258,-0.29257 -0.31008,-0.47147 -0.28906,-0.61718 0.021,-0.14571 0.13127,-0.29945 0.24023,-0.38282 0.13784,-0.10546 0.35657,-0.17021 0.59961,-0.15039 z m 1.5957,5.00391 c -1.37479,0 -2.5,1.12521 -2.5,2.5 0,1.37479 1.12521,2.5 2.5,2.5 1.37479,0 2.5,-1.12521 2.5,-2.5 0,-1.37479 -1.12521,-2.5 -2.5,-2.5 z m 0,1 c 0.83435,0 1.5,0.66565 1.5,1.5 0,0.83435 -0.66565,1.5 -1.5,1.5 -0.83435,0 -1.5,-0.66565 -1.5,-1.5 0,-0.83435 0.66565,-1.5 1.5,-1.5 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.98999999;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
- <path
id="path14479-6"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
d="m 111.51563,74 c -0.27614,2.8e-5 -0.49998,0.223869 -0.5,0.5 v 12 c 2e-5,0.276131 0.22386,0.499972 0.5,0.5 H 114.5 c 0.27613,-2.8e-5 0.49997,-0.223869 0.5,-0.5 v -12 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 z m 0.5,1 H 114 v 2 h -1.98437 z m 0,3 H 114 v 2 h -1.98437 z m 0,3 H 114 v 2 h -1.98437 z m 0,3 H 114 v 2 h -1.98437 z M 124,81.000005 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m 8,-3 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m 8,-3 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z"
@@ -17373,6 +17348,136 @@
d="m 417.92349,304.73964 c -0.7818,-0.0644 -0.86293,1.09626 -0.0796,1.1383 l 0.41758,0.0202 c 0.78182,0.0644 0.86296,-1.09626 0.0796,-1.13831 z m -7.87437,1.29265 c -0.65325,0.42724 0.0163,1.38626 0.65667,0.94062 l 0.34001,-0.23929 c 0.65327,-0.42727 -0.0163,-1.38631 -0.65662,-0.94061 z m 5.26412,-0.10772 c 0.785,-0.0185 0.73895,-1.18175 -0.0451,-1.14009 -0.6811,-0.0652 -1.43225,-0.0213 -2.22341,0.0851 -0.785,0.0185 -0.73896,1.18176 0.0451,1.14011 0.8585,-0.10954 1.60282,-0.14009 2.22342,-0.0852 z m -5.74172,5.34858 c -0.17789,-0.75187 -1.32618,-0.47161 -1.12597,0.27482 -0.008,0.72815 0.18352,1.43475 0.53595,2.12392 0.17789,0.75187 1.32617,0.47159 1.12598,-0.27483 -0.40688,-0.70818 -0.47775,-1.41605 -0.53596,-2.12391 z m 1.14987,4.81425 c 0.55238,0.5479 1.3799,-0.2833 0.81165,-0.81524 l -0.30437,-0.28193 c -0.55238,-0.54789 -1.37991,0.2833 -0.81163,0.81524 z m 2.55883,0.11471 c -0.78112,0.0716 -0.65484,1.22767 0.12391,1.13446 0.79706,0.0708 1.5429,0.0136 2.2124,-0.23372 0.7811,-0.0716 0.65482,-1.22768 -0.12391,-1.13445 -0.66955,0.35373 -1.42049,0.37687 -2.2124,0.23371 z m 4.35036,-1.24066 c 0.39775,-0.66505 -0.63058,-1.23994 -1.00859,-0.56384 l -0.19953,0.36135 c -0.39776,0.66506 0.63057,1.23995 1.00857,0.56383 z m -1.53457,-4.82813 c -0.44444,-0.63566 -1.409,0.0364 -0.94666,0.65956 0.53116,0.53126 0.99257,1.10609 1.28624,1.78569 0.44445,0.63565 1.40902,-0.0364 0.94667,-0.65956 -0.24301,-0.74231 -0.69323,-1.32054 -1.28625,-1.78569 z m -2.73483,-1.49223 c -0.72218,-0.30138 -1.16808,0.7761 -0.43732,1.05681 l 0.39025,0.14758 c 0.7222,0.30141 1.1681,-0.7761 0.43732,-1.0568 z m -7.60223,1.91562 c -0.52109,0.57678 0.37464,1.33651 0.87855,0.74515 l 0.26685,-0.31654 c 0.52111,-0.57679 -0.37465,-1.33654 -0.87854,-0.74516 z m 1.15912,7.09355 c -0.1906,-0.74845 -1.33363,-0.44917 -1.12109,0.29354 l 0.11543,0.39523 c 0.19062,0.74845 1.33365,0.44917 1.12109,-0.29354 z m -0.68592,-4.36328 c -0.0858,-0.76698 -1.25912,-0.62352 -1.15127,0.14077 -0.065,0.75431 -0.008,1.50847 0.28594,2.26232 0.0859,0.76696 1.25912,0.62352 1.15129,-0.14076 -0.28468,-0.81162 -0.29126,-1.53878 -0.28596,-2.26233 z m 1.97398,-4.7241 c -0.77314,0.13162 -0.55483,1.27463 0.21417,1.12135 0.7762,-0.30633 1.5005,-0.42412 2.18687,-0.40397 0.77313,-0.13163 0.55482,-1.27462 -0.21418,-1.12137 -0.74152,0.0229 -1.4733,0.13255 -2.18686,0.40399 z"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.15052;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:2.2;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
id="path4101-2-6-9-1_GP_dotdash" />
+ <g
+ id="g7580"
+ style="display:inline;enable-background:new">
+ <g
+ id="g905">
+ <g
+ transform="matrix(0.6740384,0,0,0.6740384,192.80592,-339.68227)"
+ style="display:inline;opacity:0.99;fill:#ffffff;stroke-width:1.07692;enable-background:new"
+ id="g8599-6-7"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ id="path8597-7-0"
+ d="m 331.87142,629.24052 c 0,0.81936 -0.66423,1.48359 -1.48359,1.48359 -0.81937,0 -1.4836,-0.66422 -1.4836,-1.48359 0,-0.81937 0.66423,-1.4836 1.4836,-1.4836 0.81937,0 1.48359,0.66423 1.48359,1.4836 z"
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.72218;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ </g>
+ <path
+ sodipodi:nodetypes="cccccccccczzcczzzzz"
+ inkscape:connector-curvature="0"
+ id="path8595-5-9"
+ d="m 414.93725,78.999996 c -0.65344,-0.653443 -1.58833,0.255453 -0.88297,0.960812 L 415.18167,81 h -4.6057 c -0.88913,-0.01822 -0.88913,1.018254 0,1 l 2.19337,-0.004 -0.006,0.004 -3.27651,2.873468 c -0.64989,0.580999 0.2216,1.555837 0.87149,0.97484 L 412.00004,84.45 c 0,1.651946 1.15621,3.581251 3.47506,3.550001 C 417.79395,87.968751 419,86.250706 419,84.45 c 0,-1.800705 -1.00462,-2.558141 -1.45954,-3.013074 z M 415.5,82.2 c 1.22478,0 2.25,0.945047 2.25,2.25 0,1.304953 -1.05311,2.25 -2.25,2.25 -1.19689,0 -2.25,-0.960585 -2.25,-2.25 0,-1.289415 1.02522,-2.25 2.25,-2.25 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.3066;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g15543-3-3"
+ transform="translate(21.029034,-20.999943)">
+ <g
+ id="g15520-6-5"
+ transform="translate(231.97182,-397.99995)"
+ style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <g
+ id="g4103-6">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 430.48047,53 c -0.15153,0.004 -0.29304,0.07659 -0.38477,0.197266 l -3.94922,3.949218 C 425.83169,57.461484 426.05468,57.99983 426.5,58 h 4 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 54 h 6 v 2.999953 c -0.01,0.676161 1.00956,0.676161 1,0 V 53.5 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 h -7 c -0.005,-6.2e-5 -0.009,-6.2e-5 -0.0137,0 -6.7e-4,1.8e-5 -0.001,-2.1e-5 -0.002,0 -0.001,4.1e-5 -0.003,-5e-5 -0.004,0 z M 426,59.000004 V 66.5 c 3e-5,0.276131 0.22387,0.499972 0.5,0.5 h 4.49914 c 0.67616,0.0096 0.67616,-1.009563 0,-1 H 427 v -6.999996 z"
+ transform="translate(-273.99999,439.99994)"
+ id="path15514-7-2"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccccccccccccc" />
+ </g>
+ </g>
+ </g>
+ </g>
+ <g
+ transform="translate(499.00086,52.015151)"
+ id="g824"
+ style="display:inline;enable-background:new">
+ <g
+ id="g4207"
+ style="display:inline;enable-background:new"
+ transform="translate(-499.00079,-52.007172)">
+ <g
+ transform="translate(105,-21.000376)"
+ style="display:inline;enable-background:new"
+ id="g7580-6">
+ <g
+ transform="matrix(0.6740384,0,0,0.6740384,192.80592,-339.68227)"
+ style="display:inline;opacity:0.99;fill:#ffffff;stroke-width:1.07692;enable-background:new"
+ id="g8599-6-7-2"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ id="path8597-7-0-9"
+ d="m 331.87142,629.2294 c 0,0.81936 -0.66423,1.48359 -1.48359,1.48359 -0.81937,0 -1.4836,-0.66422 -1.4836,-1.48359 0,-0.81937 0.66423,-1.4836 1.4836,-1.4836 0.81937,0 1.48359,0.66423 1.48359,1.4836 z"
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.72218;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ </g>
+ <path
+ sodipodi:nodetypes="cccccccccczzcczzzzz"
+ inkscape:connector-curvature="0"
+ id="path8595-5-9-1"
+ d="m 414.93725,78.992499 c -0.65344,-0.653443 -1.58833,0.255453 -0.88297,0.960812 l 1.12739,1.039192 h -4.6057 c -0.88913,-0.01822 -0.88913,1.018254 0,1 l 2.19337,-0.004 -0.006,0.004 -3.27651,2.873468 c -0.64989,0.580999 0.2216,1.555837 0.87149,0.97484 l 1.64161,-1.398308 c 0,1.651946 1.15632,3.581251 3.47517,3.550001 2.31885,-0.03125 3.5249,-1.749295 3.5249,-3.550001 0,-1.800705 -1.00462,-2.558141 -1.45954,-3.013074 z M 415.5,82.192503 c 1.22478,0 2.25,0.945047 2.25,2.25 0,1.304953 -1.05311,2.25 -2.25,2.25 -1.19689,0 -2.25,-0.960585 -2.25,-2.25 0,-1.289415 1.02522,-2.25 2.25,-2.25 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.3066;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ transform="translate(19.000003)"
+ id="g28228-3-3"
+ style="display:inline;opacity:0.6;stroke:#ffffff;enable-background:new"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <g
+ id="g28217-6-6"
+ transform="translate(338.99999,-439.99995)"
+ style="display:inline;opacity:0.99;stroke:#ffffff;enable-background:new">
+ <path
+ inkscape:connector-curvature="0"
+ id="path28215-0"
+ transform="translate(-337.99999,439.99995)"
+ d="m 501.49219,52.992188 c -0.27615,0.0043 -0.49651,0.223792 -0.49219,0.499938 v 1 c -0.01,0.676161 1.00956,0.676161 1,0 v -1 c 0.004,-0.282265 -0.22554,-0.504353 -0.50781,-0.499938 z m -7.00781,0.0067 c -0.12718,0.004 -0.248,0.0564 -0.3379,0.146484 l -4,4.001116 c -0.10126,0.101337 -0.1304,0.223491 -0.13086,0.345704 L 490,57.507812 v 1.984314 c -0.01,0.676161 1.00956,0.676161 1,0 v -1.5 h 3.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3.5 h 1.5 c 0.67616,0.0096 0.67616,-1.002805 0,-0.993242 h -2 v 0.002 c -0.005,-5e-6 -0.0101,-0.0021 -0.0156,-0.002 z m 4.01562,-0.0068 c -0.67616,-0.0096 -0.67616,1.009563 0,1 h 1 c 0.67616,0.0096 0.67616,-1.009563 0,-1 z m 2.99219,3.000062 c -0.27615,0.0043 -0.49651,0.223792 -0.49219,0.499938 v 1 c -0.01,0.676161 1.00956,0.676161 1,0 v -1 c 0.004,-0.282265 -0.22554,-0.504353 -0.50781,-0.499938 z m -11,5 c -0.27615,0.0043 -0.49651,0.223792 -0.49219,0.499938 v 1 c -0.01,0.676161 1.00956,0.676161 1,0 v -1 c 0.004,-0.282265 -0.22554,-0.504353 -0.50781,-0.499938 z m 0,3 c -0.27615,0.0043 -0.49651,0.223792 -0.49219,0.499938 v 1 c -0.01,0.676161 1.00956,0.676161 1,0 v -1 c 0.004,-0.282265 -0.22554,-0.504353 -0.50781,-0.499938 z M 492.5,65.992126 c -0.67616,-0.0096 -0.67616,1.009563 0,1 h 1 c 0.67616,0.0096 0.67616,-1.009563 0,-1 z m 3,0 c -0.67616,-0.0096 -0.67616,1.009563 0,1 h 1 c 0.67616,0.0096 0.67616,-1.009563 0,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccccccccccccccccccccc" />
+ </g>
+ </g>
+ </g>
+ </g>
+ <g
+ transform="translate(-0.999993)"
+ id="g4126"
+ style="display:inline;enable-background:new">
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ transform="matrix(0.65914281,0,0,0.65914281,248.47102,-214.89549)"
+ id="g12839-3-5">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 352.97527,473.19666 c -0.49613,-0.0451 -1.03862,0.15972 -1.49219,0.61328 l -0.41128,0.47153 c -0.19519,0.19527 -0.19519,0.51177 0,0.70704 l 3,3 c 0.19527,0.19519 0.51177,0.19519 0.70704,0 l 0.41128,-0.47153 c 0.45356,-0.45357 0.65838,-0.99606 0.61328,-1.49219 -0.0451,-0.49613 -0.30436,-0.90592 -0.61328,-1.21485 l -1,-1 c -0.30893,-0.30892 -0.71872,-0.56817 -1.21485,-0.61328 z m -3.39644,2.7168 c -0.12989,0.002 -0.25387,0.0546 -0.34571,0.14648 l -6.22807,6.22726 c -0.0639,0.0642 -0.10909,0.14453 -0.13086,0.23243 l -1,4 c -0.0904,0.36537 0.2401,0.69582 0.60547,0.60547 l 4,-1 c 0.0879,-0.0218 0.16823,-0.067 0.23243,-0.13086 0,0 6.17898,-6.1737 6.22807,-6.22726 0.19519,-0.19527 0.19519,-0.51177 0,-0.70704 l -3,-3 c -0.0957,-0.0957 -0.22605,-0.14856 -0.36137,-0.14648 z"
+ id="path12837-6-3"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccscccccccccccccccc" />
+ </g>
+ <path
+ sodipodi:nodetypes="csscccccccccccssscccc"
+ style="opacity:0.6;fill:#ffffff"
+ inkscape:connector-curvature="0"
+ id="path2-6"
+ d="m 469,101 v 7.5 c 0,0.276 0.224,0.5 0.5,0.5 h 11 c 0.30423,0 0.5,-0.22782 0.5,-0.5 v -4 c 0,-0.65459 -1,-0.65682 -1,0 v 3.5 h -10 v -7 z m 4.48081,-6 c -0.151,0.004 -0.293,0.077 -0.384,0.197 l -3.95,3.949 c -0.314,0.315 -0.091,0.854 0.354,0.854 h 4 c 0.276,0 0.5,-0.224 0.5,-0.5 V 96 H 480.5 c 0.68512,0 0.64092,-1 0,-1 z" />
+ </g>
</g>
<g
inkscape:groupmode="layer"
diff --git a/release/datafiles/blender_icons16/icon16_current_file.dat b/release/datafiles/blender_icons16/icon16_current_file.dat
new file mode 100644
index 00000000000..cc381ac5cfa
--- /dev/null
+++ b/release/datafiles/blender_icons16/icon16_current_file.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_file_backup.dat b/release/datafiles/blender_icons16/icon16_file_backup.dat
index 790364b2d95..c4d99c1bc75 100644
--- a/release/datafiles/blender_icons16/icon16_file_backup.dat
+++ b/release/datafiles/blender_icons16/icon16_file_backup.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_file_blend.dat b/release/datafiles/blender_icons16/icon16_file_blend.dat
index 2dbab9886cf..85a70be080c 100644
--- a/release/datafiles/blender_icons16/icon16_file_blend.dat
+++ b/release/datafiles/blender_icons16/icon16_file_blend.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_current_file.dat b/release/datafiles/blender_icons32/icon32_current_file.dat
new file mode 100644
index 00000000000..6709a64f29c
--- /dev/null
+++ b/release/datafiles/blender_icons32/icon32_current_file.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_file_backup.dat b/release/datafiles/blender_icons32/icon32_file_backup.dat
index e697ce58a33..5aa455c442b 100644
--- a/release/datafiles/blender_icons32/icon32_file_backup.dat
+++ b/release/datafiles/blender_icons32/icon32_file_backup.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_file_blend.dat b/release/datafiles/blender_icons32/icon32_file_blend.dat
index 92b54eea1d8..25903bc87ee 100644
--- a/release/datafiles/blender_icons32/icon32_file_blend.dat
+++ b/release/datafiles/blender_icons32/icon32_file_blend.dat
Binary files differ
diff --git a/release/datafiles/locale b/release/datafiles/locale
-Subproject 8ee2942570f08d10484bb2328d0d1b0aaaa0367
+Subproject 9d270fd007f628b23ccbcbd87caa2dc35286b26
diff --git a/release/datafiles/preview.blend b/release/datafiles/preview.blend
index e342cb85158..e7a678bca7a 100644
--- a/release/datafiles/preview.blend
+++ b/release/datafiles/preview.blend
Binary files differ
diff --git a/release/datafiles/splash.png b/release/datafiles/splash.png
index 7189380bbd9..eb1250cf5a5 100644
--- a/release/datafiles/splash.png
+++ b/release/datafiles/splash.png
Binary files differ
diff --git a/release/freedesktop/org.blender.Blender.appdata.xml b/release/freedesktop/org.blender.Blender.appdata.xml
index 7a5a252e4ca..4b413f6b38d 100644
--- a/release/freedesktop/org.blender.Blender.appdata.xml
+++ b/release/freedesktop/org.blender.Blender.appdata.xml
@@ -40,6 +40,29 @@
</screenshot>
</screenshots>
<releases>
+ <release version="3.0" date="2021-12-03">
+ <description>
+ <p>New features:</p>
+ <ul>
+ <li>Asset browser</li>
+ <li>Geometry nodes fields</li>
+ <li>Video editor thumbnail previews</li>
+ <li>Transformation tools for video strips</li>
+ <li>Virtual reality navigation</li>
+ <li>Quicker save and better compression</li>
+ </ul>
+ <p>Enhancements:</p>
+ <ul>
+ <li>Cycles performance and quality improvements</li>
+ <li>About 100 new geometry nodes</li>
+ <li>EEVEE attribute support</li>
+ <li>User Interface updates</li>
+ <li>OpenImageDenoise upgraded to 1.4</li>
+ <li>Shadow terminator geometry offset</li>
+ <li>Shadow catcher indirect and environment light support</li>
+ </ul>
+ </description>
+ </release>
<release version="2.93" date="2021-06-02">
<description>
<p>New features:</p>
@@ -51,7 +74,7 @@
</ul>
<p>Enhancements:</p>
<ul>
- <li>Geometry nodes 22 new nodes and imrpoved attribute search</li>
+ <li>Geometry nodes 22 new nodes and improved attribute search</li>
<li>Mask loops, textures and patterns for sculpting</li>
<li>Grease pencil interpolate refactored and SVG and PDF support</li>
<li>Persistent Data rendering settings for Cycles</li>
diff --git a/release/license/THIRD-PARTY-LICENSES.txt b/release/license/THIRD-PARTY-LICENSES.txt
index 3116635ba29..2bd4ac23d6d 100644
--- a/release/license/THIRD-PARTY-LICENSES.txt
+++ b/release/license/THIRD-PARTY-LICENSES.txt
@@ -24,11 +24,12 @@ PERFORMANCE OF THIS SOFTWARE.
** Draco; version 1.3.6 -- https://google.github.io/draco/
** Embree; version 3.10 -- https://github.com/embree/embree
** Mantaflow; version 0.13 -- http://mantaflow.com/
-** oneAPI Threading Building Block; version 2019_U9 --
+** oneAPI Threading Building Block; version 2020_U2 --
https://software.intel.com/en-us/oneapi/onetbb
** OpenCL Wrangler; version 27a6867 -- https://github.com/OpenCLWrangler/clew
-** OpenImageDenoise; version 1.2.3 -- https://www.openimagedenoise.org/
-** OpenXR SDK; version 1.0.8 -- https://khronos.org/openxr
+** OpenImageDenoise; version 1.4.1 -- https://www.openimagedenoise.org/
+** OpenSSL; version 1.1.1 -- https://www.openssl.org/
+** OpenXR SDK; version 1.0.17 -- https://khronos.org/openxr
** RangeTree; version 40ebed8aa209 -- https://github.com/ideasman42/rangetree-c
** SDL Extension Wrangler; version 15edf8e --
https://github.com/SDLWrangler/sdlew
@@ -249,6 +250,9 @@ limitations under the License.
Written by George van Venrooij
* For OpenImageDenoise see also this required NOTICE:
Copyright 2009-2020 Intel Corporation
+* For OpenSSL see also this required NOTICE:
+ Copyright (c) 1998-2021 The OpenSSL Project
+ Copyright (c) 1995-1998 Eric A. Young, Tim J. Hudson
* For OpenXR SDK see also this required NOTICE:
Copyright (c) 2017-2020 The Khronos Group Inc.
Copyright (c) 2017-2019 Valve Corporation
@@ -261,6 +265,8 @@ limitations under the License.
------
+** NASM; version 2.15.02 -- https://www.nasm.us/
+Contributions since 2008-12-15 are Copyright Intel Corporation.
** OpenJPEG; version 2.3.1 -- https://github.com/uclouvain/openjpeg
Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium
Copyright (c) 2002-2014, Professor Benoit Macq
@@ -310,16 +316,20 @@ All rights reserved.
** Google Logging; version 4.4.0 -- https://github.com/google/glog
Copyright (c) 2006, Google Inc.
All rights reserved.
-** Open Shading Language; version 1.10.10 --
+** ISPC; version 1.16.0 -- https://github.com/ispc/ispc
+Copyright Intel Corporation
+** NumPy; version 1.21.2 -- https://numpy.org/
+Copyright (c) 2005-2021, NumPy Developers.
+** Open Shading Language; version 1.11.14.1 --
https://github.com/imageworks/OpenShadingLanguage
Copyright Contributors to the Open Shading Language project.
-** OpenColorIO; version 1.1.1 --
+** OpenColorIO; version 2.0.0 --
https://github.com/AcademySoftwareFoundation/OpenColorIO
Copyright Contributors to the OpenColorIO Project.
-** OpenEXR; version 2.4.0 --
+** OpenEXR; version 2.5.5 --
https://github.com/AcademySoftwareFoundation/openexr
Copyright Contributors to the OpenEXR Project. All rights reserved.
-** OpenImageIO; version 2.1.15.0 -- http://www.openimageio.org
+** OpenImageIO; version 2.2.15.1 -- http://www.openimageio.org
Copyright (c) 2008-present by Contributors to the OpenImageIO project. All
Rights Reserved.
@@ -353,7 +363,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
** AutoPackage; version 1.0 -- http://autopackage.org
BinReloc - a library for creating relocatable executables
Written by: Hongli Lai <h.lai@chello.nl>
-** LZMA SDK; version 4.65 -- https://www.7-zip.org/sdk.html
+** LZMA SDK; version 5.2.5 -- https://www.7-zip.org/sdk.html
LZMA SDK: Public Domain
Creative Commons Legal Code
@@ -1146,6 +1156,9 @@ License.
------
+** libx264; version 33f9e1474613f59392be5ab6a7e7abf60fa63622 --
+https://code.videolan.org/videolan/x264
+Copyright (C) 2003-2021 x264 project
** miniLZO; version 2.08 -- http://www.oberhumer.com/opensource/lzo/
LZO and miniLZO are Copyright (C) 1996-2014 Markus Franz Xaver Oberhumer
All Rights Reserved.
@@ -1156,6 +1169,13 @@ Copyright (C) 1996-2020 by David Turner, Robert Wilhelm, and Werner Lemberg.
https://freedesktop.org/wiki/Specifications/XDND/
xdnd.c, xdnd.h - C program library for handling the Xdnd protocol
Copyright (C) 1996-2000 Paul Sheer
+** Xvid Mpeg-4 Video Codec; version 1.3.7 -- https://www.xvid.com/
+Project initiators:
+Christoph Lampert <gruel@web.de>
+Michael Militzer <isibaar@xvid.org>
+Peter Ross <pross@xvid.org>
+** Zstandard; version 1.5.0 -- https://github.com/facebook/zstd
+Copyright (c) 2016-present, Facebook, Inc. All rights reserved.
GNU GENERAL PUBLIC LICENSE
@@ -2145,7 +2165,7 @@ of this License. But first, please read <http s ://www.gnu.org/ licenses
------
-** FFmpeg; version 4.2.3 -- http://ffmpeg.org/
+** FFmpeg; version 4.4 -- http://ffmpeg.org/
-
GNU LESSER GENERAL PUBLIC LICENSE
@@ -2936,9 +2956,14 @@ December 9, 2010
------
+** Expat; version 2.2.10 -- https://github.com/libexpat/libexpat/
+Copyright (c) 1998-2000 Thai Open Source Software Center Ltd and Clark Cooper
+Copyright (c) 2001-2019 Expat maintainers
+** JSON for Modern C++; version 3.10.2 -- https://github.com/nlohmann/json/
+Copyright (c) 2013-2021 Niels Lohmann
** Libxml2; version 2.9.10 -- http://xmlsoft.org/
Copyright (C) 1998-2012 Daniel Veillard. All Rights Reserved.
-** Mesa 3D; version 18.3.1 -- https://www.mesa3d.org/
+** Mesa 3D; version 21.1.5 -- https://www.mesa3d.org/
Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
** OPENCollada; version 1.6.68 -- https://github.com/KhronosGroup/OpenCOLLADA
Copyright (c) 2008-2009 NetAllied Systems GmbH
@@ -2947,6 +2972,21 @@ Copyright (c) 2006-2020 Arseny Kapoulkine
** QuadriFlow; version 27a6867 -- https://github.com/hjwdzh/QuadriFlow
Copyright (c) 2018 Jingwei Huang, Yichao Zhou, Matthias Niessner,
Jonathan Shewchuk and Leonidas Guibas. All rights reserved.
+** sse2neon; version fe5ff00bb8d19b327714a3c290f3e2ce81ba3525 --
+https://github.com/DLTcollab/sse2neon
+Copyright sse2neon contributors
+** TinyGLTF; version 2.5.0 -- https://github.com/syoyo/tinygltf
+Copyright (c) 2017 Syoyo Fujita, Aurélien Chatelain and many contributors
+** Wayland protocols; version 1.21 --
+https://gitlab.freedesktop.org/wayland/wayland-protocols
+Copyright © 2008-2013 Kristian Høgsberg
+Copyright © 2010-2013 Intel Corporation
+Copyright © 2013 Rafael Antognolli
+Copyright © 2013 Jasper St. Pierre
+Copyright © 2014 Jonas Ådahl
+Copyright © 2014 Jason Ekstrand
+Copyright © 2014-2015 Collabora, Ltd.
+Copyright © 2015 Red Hat Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -2968,10 +3008,10 @@ SOFTWARE.
------
-** NanoVDB; version e62f7a0bf1e27397223c61ddeaaf57edf111b77f --
+** NanoVDB; version dc37d8a631922e7bef46712947dc19b755f3e841 --
https://github.com/AcademySoftwareFoundation/openvdb
Copyright Contributors to the OpenVDB Project
-** OpenVDB; version 7.0.0 -- http://www.openvdb.org/
+** OpenVDB; version 8.0.1 -- http://www.openvdb.org/
Copyright Contributors to the OpenVDB Project
Mozilla Public License Version 2.0
@@ -3314,6 +3354,11 @@ the Mozilla Public License, v. 2.0.
http://continuousphysics.com/Bullet/
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
+** Haru; version 2.3.0 -- http://libharu.org/
+Copyright 2000-2006 (c) Takeshi Kanno
+Copyright 2007-2009 (c) Antony Dovgal et al.
+** NanoSVG; version 3cdd4a9d788 -- https://github.com/memononen/nanosvg
+Copyright (c) 2013-14 Mikko Mononen memon@inside.org
** SDL; version 2.0.12 -- https://www.libsdl.org
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
** zlib; version 1.2.11 -- https://zlib.net
@@ -3369,7 +3414,7 @@ IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
------
-** The LLVM Compiler Infrastructure; version 9.0.1 --
+** The LLVM Compiler Infrastructure; version 12.0.0 --
https://github.com/llvm/llvm-project/
University of Illinois/NCSA
Open Source License
@@ -3397,7 +3442,7 @@ Software.
** OpenSubdiv; version 3.4.3 -- http://graphics.pixar.com/opensubdiv
Copyright 2013 Pixar
-** Universal Scene Description; version 20.05 -- http://www.openusd.org/
+** Universal Scene Description; version 21.02 -- http://www.openusd.org/
Copyright 2016 Pixar
Licensed under the Apache License, Version 2.0 (the "Apache License") with the
@@ -3442,7 +3487,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
------
-** Boost C++ Libraries; version 1.70.0 -- https://www.boost.org/
+** Boost C++ Libraries; version 1.73.0 -- https://www.boost.org/
-
Boost Software License - Version 1.0 - August 17th, 2003
@@ -3471,7 +3516,7 @@ DEALINGS IN THE SOFTWARE.
------
-** Alembic; version 1.7.12 -- https://github.com/alembic/alembic
+** Alembic; version 1.7.16 -- https://github.com/alembic/alembic
TM & © 2009-2015 Lucasfilm Entertainment Company Ltd. or Lucasfilm Ltd.
All rights reserved.
@@ -3582,8 +3627,8 @@ disclaims all warranties with regard to this software.
------
-** Python; version 3.7.7 -- https://www.python.org
-Copyright (c) 2001-2020 Python Software Foundation. All rights reserved.
+** Python; version 3.9.7 -- https://www.python.org
+Copyright (c) 2001-2021 Python Software Foundation. All rights reserved.
A. HISTORY OF THE SOFTWARE
==========================
@@ -3869,6 +3914,48 @@ PERFORMANCE OF THIS SOFTWARE.
------
+** Flex; version 2.6.4 -- https://github.com/westes/flex
+Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The Flex Project.
+
+Copyright (c) 1990, 1997 The Regents of the University of California.
+All rights reserved.
+
+This code is derived from software contributed to Berkeley by
+Vern Paxson.
+
+The United States Government has rights in this work pursuant
+to contract no. DE-AC03-76SF00098 between the United States
+Department of Energy and the University of California.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+Neither the name of the University nor the names of its contributors
+may be used to endorse or promote products derived from this software
+without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.
+
+This basically says "do whatever you please with this software except
+remove this notice or take advantage of the University's (or the flex
+authors') name".
+
+Note that the "flex.skl" scanner skeleton carries no copyright notice.
+You are free to do whatever you please with scanners generated using flex;
+for them, you are not even bound by the above copyright.
+
+------
+
** Jemalloc; version 5.2.1 -- https://github.com/jemalloc/jemalloc
Copyright (C) 2002-present Jason Evans <jasone@canonware.com>.
All rights reserved.
diff --git a/release/scripts/addons b/release/scripts/addons
-Subproject f2a08d80ccd3c13af304525778df3905f95bd44
+Subproject b3c179b2869d86c44a4b29e2c638ce2a596a820
diff --git a/release/scripts/freestyle/modules/parameter_editor.py b/release/scripts/freestyle/modules/parameter_editor.py
index 65eee93c871..ed5b57af689 100644
--- a/release/scripts/freestyle/modules/parameter_editor.py
+++ b/release/scripts/freestyle/modules/parameter_editor.py
@@ -166,7 +166,7 @@ class ScalarBlendModifier(StrokeShader):
v1 = facm * v1 + fac * v1 / v2 if v2 != 0.0 else v1
elif self.blend_type == 'DIFFERENCE':
v1 = facm * v1 + fac * abs(v1 - v2)
- elif self.blend_type == 'MININUM':
+ elif self.blend_type == 'MINIMUM':
v1 = min(fac * v2, v1)
elif self.blend_type == 'MAXIMUM':
v1 = max(fac * v2, v1)
diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
index dbc93cb6caa..543742709ef 100644
--- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py
+++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
@@ -2147,7 +2147,7 @@ def km_file_browser(params):
("file.next", {"type": 'RIGHT_ARROW', "value": 'PRESS', "alt": True}, None),
# The two refresh operators have polls excluding each other (so only one is available depending on context).
("file.refresh", {"type": 'R', "value": 'PRESS'}, None),
- ("file.asset_library_refresh", {"type": 'R', "value": 'PRESS'}, None),
+ ("asset.library_refresh", {"type": 'R', "value": 'PRESS'}, None),
("file.parent", {"type": 'P', "value": 'PRESS'}, None),
("file.previous", {"type": 'BACK_SPACE', "value": 'PRESS'}, None),
("file.next", {"type": 'BACK_SPACE', "value": 'PRESS', "shift": True}, None),
@@ -7557,7 +7557,7 @@ def km_sequencer_editor_tool_generic_select(params, *, fallback):
params, "sequencer.select", "sequencer.cursor_set", extend="toggle")),
*([] if (not params.use_fallback_tool_rmb) else _template_sequencer_preview_select(
- type=params.select_mouse, value=params.select_mouse_value_fallback, legacy=params.legacy)),
+ type=params.select_mouse, value=params.select_mouse_value, legacy=params.legacy)),
# Ignored for preview.
*_template_items_change_frame(params),
]},
diff --git a/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py b/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
index 37cd554e872..3019322d340 100644
--- a/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
+++ b/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
@@ -1229,7 +1229,7 @@ def km_file_browser(params):
("file.next", {"type": 'RIGHT_ARROW', "value": 'PRESS', "ctrl": True}, None),
# The two refresh operators have polls excluding each other (so only one is available depending on context).
("file.refresh", {"type": 'R', "value": 'PRESS', "ctrl": True}, None),
- ("file.asset_library_refresh", {"type": 'R', "value": 'PRESS', "ctrl": True}, None),
+ ("asset.library_refresh", {"type": 'R', "value": 'PRESS', "ctrl": True}, None),
("file.previous", {"type": 'BACK_SPACE', "value": 'PRESS'}, None),
("file.next", {"type": 'BACK_SPACE', "value": 'PRESS', "shift": True}, None),
("wm.context_toggle", {"type": 'H', "value": 'PRESS'},
@@ -1276,7 +1276,7 @@ def km_file_browser_main(params):
("file.mouse_execute", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'}, None),
# The two refresh operators have polls excluding each other (so only one is available depending on context).
("file.refresh", {"type": 'R', "value": 'PRESS', "ctrl": True}, None),
- ("file.asset_library_refresh", {"type": 'R', "value": 'PRESS', "ctrl": True}, None),
+ ("asset.library_refresh", {"type": 'R', "value": 'PRESS', "ctrl": True}, None),
("file.select", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'}, None),
("file.select", {"type": 'LEFTMOUSE', "value": 'CLICK'},
{"properties": [("open", False), ("deselect_all", True)]}),
diff --git a/release/scripts/startup/bl_operators/assets.py b/release/scripts/startup/bl_operators/assets.py
index 58f02201905..32e63f77b23 100644
--- a/release/scripts/startup/bl_operators/assets.py
+++ b/release/scripts/startup/bl_operators/assets.py
@@ -142,14 +142,8 @@ class ASSET_OT_open_containing_blend_file(Operator):
if returncode:
self.report({'WARNING'}, "Blender sub-process exited with error code %d" % returncode)
- # TODO(Sybren): Replace this with a generic "reload assets" operator
- # that can run outside of the Asset Browser context.
- if bpy.ops.file.refresh.poll():
- bpy.ops.file.refresh()
- if bpy.ops.asset.list_refresh.poll():
- bpy.ops.asset.list_refresh()
- if bpy.ops.file.asset_library_refresh.poll():
- bpy.ops.file.asset_library_refresh()
+ if bpy.ops.asset.library_refresh.poll():
+ bpy.ops.asset.library_refresh()
self.cancel(context)
return {'FINISHED'}
diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py
index d9ea991f976..a2f482d1a55 100644
--- a/release/scripts/startup/bl_operators/wm.py
+++ b/release/scripts/startup/bl_operators/wm.py
@@ -2970,7 +2970,7 @@ class WM_MT_splash_quick_setup(Menu):
sub = row.row()
old_version = bpy.types.PREFERENCES_OT_copy_prev.previous_version()
if bpy.types.PREFERENCES_OT_copy_prev.poll(context) and old_version:
- sub.operator("preferences.copy_prev", text="Load %d.%d Settings" % old_version)
+ sub.operator("preferences.copy_prev", text=iface_("Load %d.%d Settings", "Operator") % old_version)
sub.operator("wm.save_userpref", text="Save New Settings")
else:
sub.label()
diff --git a/release/scripts/startup/bl_ui/properties_data_camera.py b/release/scripts/startup/bl_ui/properties_data_camera.py
index b56182bb637..edd0623d8fe 100644
--- a/release/scripts/startup/bl_ui/properties_data_camera.py
+++ b/release/scripts/startup/bl_ui/properties_data_camera.py
@@ -110,6 +110,14 @@ class DATA_PT_lens(CameraButtonsPanel, Panel):
sub = col.column(align=True)
sub.prop(ccam, "longitude_min", text="Longitude Min")
sub.prop(ccam, "longitude_max", text="Max")
+ elif ccam.panorama_type == 'FISHEYE_LENS_POLYNOMIAL':
+ col.prop(ccam, "fisheye_fov")
+ col.prop(ccam, "fisheye_polynomial_k0", text="K0")
+ col.prop(ccam, "fisheye_polynomial_k1", text="K1")
+ col.prop(ccam, "fisheye_polynomial_k2", text="K2")
+ col.prop(ccam, "fisheye_polynomial_k3", text="K3")
+ col.prop(ccam, "fisheye_polynomial_k4", text="K4")
+
elif engine in {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}:
if cam.lens_unit == 'MILLIMETERS':
col.prop(cam, "lens")
diff --git a/release/scripts/startup/bl_ui/space_dopesheet.py b/release/scripts/startup/bl_ui/space_dopesheet.py
index 9b8f1cfeb0d..3c90e0c96cc 100644
--- a/release/scripts/startup/bl_ui/space_dopesheet.py
+++ b/release/scripts/startup/bl_ui/space_dopesheet.py
@@ -539,6 +539,39 @@ class DOPESHEET_MT_key_transform(Menu):
layout.operator("transform.transform", text="Scale").mode = 'TIME_SCALE'
+class DopesheetActionPanelBase:
+ bl_region_type = 'UI'
+ bl_label = "Action"
+
+ @classmethod
+ def draw_generic_panel(cls, context, layout, action):
+ layout.label(text=action.name, icon='ACTION')
+
+ layout.prop(action, "use_frame_range")
+
+ col = layout.column()
+ col.active = action.use_frame_range
+
+ row = col.row(align=True)
+ row.prop(action, "frame_start", text="Start")
+ row.prop(action, "frame_end", text="End")
+
+ col.prop(action, "use_cyclic")
+
+
+class DOPESHEET_PT_action(DopesheetActionPanelBase, Panel):
+ bl_space_type = 'DOPESHEET_EDITOR'
+ bl_category = "Item"
+
+ @classmethod
+ def poll(cls, context):
+ return bool(context.selected_visible_actions)
+
+ def draw(self, context):
+ action = context.selected_visible_actions[0]
+ self.draw_generic_panel(context, self.layout, action)
+
+
#######################################
# Grease Pencil Editing
@@ -792,6 +825,7 @@ classes = (
DOPESHEET_MT_snap_pie,
DOPESHEET_MT_view_pie,
DOPESHEET_PT_filters,
+ DOPESHEET_PT_action,
DOPESHEET_PT_gpencil_mode,
DOPESHEET_PT_gpencil_layer_masks,
DOPESHEET_PT_gpencil_layer_transform,
diff --git a/release/scripts/startup/bl_ui/space_filebrowser.py b/release/scripts/startup/bl_ui/space_filebrowser.py
index f601c795660..e33cf8d6cfb 100644
--- a/release/scripts/startup/bl_ui/space_filebrowser.py
+++ b/release/scripts/startup/bl_ui/space_filebrowser.py
@@ -404,7 +404,13 @@ class FILEBROWSER_PT_advanced_filter(Panel):
def is_option_region_visible(context, space):
- if not space.active_operator:
+ from bpy_extras.asset_utils import SpaceAssetInfo
+
+ if SpaceAssetInfo.is_asset_browser(space):
+ pass
+ # For the File Browser, there must be an operator for there to be options
+ # (irrelevant for the Asset Browser).
+ elif not space.active_operator:
return False
for region in context.area.regions:
@@ -701,7 +707,7 @@ class ASSETBROWSER_PT_metadata(asset_utils.AssetBrowserPanel, Panel):
asset_file_handle = context.asset_file_handle
if asset_file_handle is None:
- layout.label(text="No asset selected", icon='INFO')
+ layout.label(text="No active asset", icon='INFO')
return
asset_library_ref = context.asset_library_ref
@@ -793,7 +799,7 @@ class ASSETBROWSER_MT_context_menu(AssetBrowserMenu, Menu):
st = context.space_data
params = st.params
- layout.operator("file.asset_library_refresh")
+ layout.operator("asset.library_refresh")
layout.separator()
diff --git a/release/scripts/startup/bl_ui/space_nla.py b/release/scripts/startup/bl_ui/space_nla.py
index 9507d8296a9..62c02799a9f 100644
--- a/release/scripts/startup/bl_ui/space_nla.py
+++ b/release/scripts/startup/bl_ui/space_nla.py
@@ -22,6 +22,7 @@ from bpy.types import Header, Menu, Panel
from bpy.app.translations import contexts as i18n_contexts
from bl_ui.space_dopesheet import (
DopesheetFilterPopoverBase,
+ DopesheetActionPanelBase,
dopesheet_filter,
)
@@ -66,6 +67,21 @@ class NLA_PT_filters(DopesheetFilterPopoverBase, Panel):
DopesheetFilterPopoverBase.draw_standard_filters(context, layout)
+class NLA_PT_action(DopesheetActionPanelBase, Panel):
+ bl_space_type = 'NLA_EDITOR'
+ bl_category = "Strip"
+ bl_options = {'DEFAULT_CLOSED'}
+
+ @classmethod
+ def poll(cls, context):
+ strip = context.active_nla_strip
+ return strip and strip.type == 'CLIP' and strip.action
+
+ def draw(self, context):
+ action = context.active_nla_strip.action
+ self.draw_generic_panel(context, self.layout, action)
+
+
class NLA_MT_editor_menus(Menu):
bl_idname = "NLA_MT_editor_menus"
bl_label = ""
@@ -316,6 +332,7 @@ classes = (
NLA_MT_context_menu,
NLA_MT_channel_context_menu,
NLA_PT_filters,
+ NLA_PT_action,
)
if __name__ == "__main__": # only for live edit.
diff --git a/release/scripts/startup/bl_ui/space_node.py b/release/scripts/startup/bl_ui/space_node.py
index 2b3f0cfbf7c..9bf812e036d 100644
--- a/release/scripts/startup/bl_ui/space_node.py
+++ b/release/scripts/startup/bl_ui/space_node.py
@@ -719,8 +719,13 @@ class NODE_PT_overlay(Panel):
col.separator()
+ col.prop(overlay, "show_context_path", text="Context Path")
col.prop(snode, "show_annotation", text="Annotations")
+ if snode.tree_type == 'GeometryNodeTree':
+ col.separator()
+ col.prop(overlay, "show_timing", text="Timings")
+
class NODE_UL_interface_sockets(bpy.types.UIList):
def draw_item(self, context, layout, _data, item, icon, _active_data, _active_propname, _index):
diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py
index 401ff9b64c2..a2ec5075a4d 100644
--- a/release/scripts/startup/bl_ui/space_sequencer.py
+++ b/release/scripts/startup/bl_ui/space_sequencer.py
@@ -41,7 +41,7 @@ def _space_view_types(st):
view_type = st.view_type
return (
view_type in {'SEQUENCER', 'SEQUENCER_PREVIEW'},
- view_type in {'PREVIEW', 'SEQUENCER_PREVIEW'},
+ view_type == 'PREVIEW',
)
@@ -196,10 +196,6 @@ class SEQUENCER_HT_header(Header):
row = layout.row(align=True)
row.prop(sequencer_tool_settings, "overlap_mode", text="")
- if st.view_type == 'SEQUENCER_PREVIEW':
- row = layout.row(align=True)
- row.prop(sequencer_tool_settings, "pivot_point", text="", icon_only=True)
-
if st.view_type in {'SEQUENCER', 'SEQUENCER_PREVIEW'}:
row = layout.row(align=True)
row.prop(tool_settings, "use_snap_sequencer", text="")
@@ -248,7 +244,8 @@ class SEQUENCER_MT_editor_menus(Menu):
layout.menu("SEQUENCER_MT_strip")
- layout.menu("SEQUENCER_MT_image")
+ if st.view_type in {'SEQUENCER', 'PREVIEW'}:
+ layout.menu("SEQUENCER_MT_image")
class SEQUENCER_PT_gizmo_display(Panel):
@@ -576,10 +573,6 @@ class SEQUENCER_MT_select(Menu):
st = context.space_data
has_sequencer, has_preview = _space_view_types(st)
- # FIXME: this doesn't work for both preview + window region.
- if has_preview:
- layout.operator_context = 'INVOKE_REGION_PREVIEW'
-
layout.operator("sequencer.select_all", text="All").action = 'SELECT'
layout.operator("sequencer.select_all", text="None").action = 'DESELECT'
layout.operator("sequencer.select_all", text="Invert").action = 'INVERT'
@@ -821,7 +814,6 @@ class SEQUENCER_MT_strip_transform(Menu):
else:
layout.operator_context = 'INVOKE_REGION_WIN'
- # FIXME: mixed preview/sequencer views.
if has_preview:
layout.operator("transform.translate", text="Move")
layout.operator("transform.rotate", text="Rotate")
@@ -917,12 +909,6 @@ class SEQUENCER_MT_strip(Menu):
st = context.space_data
has_sequencer, has_preview = _space_view_types(st)
- # FIXME: this doesn't work for both preview + window region.
- if has_preview:
- layout.operator_context = 'INVOKE_REGION_PREVIEW'
- else:
- layout.operator_context = 'INVOKE_REGION_WIN'
-
layout.menu("SEQUENCER_MT_strip_transform")
layout.separator()
diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
index 2253dfa5f5d..889155f1858 100644
--- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
@@ -3153,14 +3153,7 @@ class SEQUENCER_PT_tools_active(ToolSelectPanelHelper, Panel):
],
'SEQUENCER_PREVIEW': [
*_tools_select,
- _defs_sequencer_generic.cursor,
None,
- _defs_sequencer_generic.translate,
- _defs_sequencer_generic.rotate,
- _defs_sequencer_generic.scale,
- _defs_sequencer_generic.transform,
- None,
- _defs_sequencer_generic.sample,
*_tools_annotate,
None,
_defs_sequencer_generic.blade,
diff --git a/release/scripts/startup/bl_ui/space_topbar.py b/release/scripts/startup/bl_ui/space_topbar.py
index 518979a5ef3..3137ac43549 100644
--- a/release/scripts/startup/bl_ui/space_topbar.py
+++ b/release/scripts/startup/bl_ui/space_topbar.py
@@ -588,7 +588,7 @@ class TOPBAR_MT_edit(Menu):
layout.separator()
- layout.operator("ed.undo_history", text="Undo History...")
+ layout.menu("TOPBAR_MT_undo_history")
layout.separator()
diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py
index 5032256e4d1..6dbb964e771 100644
--- a/release/scripts/startup/bl_ui/space_userpref.py
+++ b/release/scripts/startup/bl_ui/space_userpref.py
@@ -596,9 +596,11 @@ class USERPREF_PT_system_cycles_devices(SystemPanel, CenterAlignMixIn, Panel):
@classmethod
def poll(cls, _context):
- # No GPU rendering on macOS currently.
+ # No GPU rendering on macOS x86_64 currently.
+ import platform
import sys
- return bpy.app.build_options.cycles and sys.platform != "darwin"
+ return bpy.app.build_options.cycles and \
+ (sys.platform != "darwin" or platform.machine() == "arm64")
def draw_centered(self, context, layout):
prefs = context.preferences
@@ -1818,7 +1820,7 @@ class USERPREF_PT_addons(AddOnPanel, Panel):
bl_options = {'HIDE_HEADER'}
_support_icon_mapping = {
- 'OFFICIAL': 'FILE_BLEND',
+ 'OFFICIAL': 'BLENDER',
'COMMUNITY': 'COMMUNITY',
'TESTING': 'EXPERIMENTAL',
}
@@ -1868,11 +1870,6 @@ class USERPREF_PT_addons(AddOnPanel, Panel):
if p
)
- # Development option for 2.8x, don't show users bundled addons
- # unless they have been updated for 2.8x.
- # Developers can turn them on with '--debug'
- show_official_27x_addons = bpy.app.debug
-
# collect the categories that can be filtered on
addons = [
(mod, addon_utils.module_bl_info(mod))
@@ -1949,15 +1946,6 @@ class USERPREF_PT_addons(AddOnPanel, Panel):
):
continue
- # Skip 2.7x add-ons included with Blender, unless in debug mode.
- is_addon_27x = info.get("blender", (0,)) < (2, 80)
- if (
- is_addon_27x and
- (not show_official_27x_addons) and
- (not mod.__file__.startswith(addon_user_dirs))
- ):
- continue
-
# Addon UI Code
col_box = col.column()
box = col_box.box()
@@ -1980,13 +1968,7 @@ class USERPREF_PT_addons(AddOnPanel, Panel):
sub.active = is_enabled
sub.label(text="%s: %s" % (info["category"], info["name"]))
- # WARNING: 2.8x exception, may be removed
- # use disabled state for old add-ons, chances are they are broken.
- if is_addon_27x:
- sub.label(text="Upgrade to 2.8x required")
- sub.label(icon='ERROR')
- # Remove code above after 2.8x migration is complete.
- elif info["warning"]:
+ if info["warning"]:
sub.label(icon='ERROR')
# icon showing support level.
diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
index acc3d933b85..01850676519 100644
--- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
@@ -689,7 +689,9 @@ class VIEW3D_PT_tools_brush_stroke_smooth_stroke(Panel, View3DPaintPanel, Smooth
class VIEW3D_PT_tools_weight_gradient(Panel, View3DPaintPanel):
- bl_context = ".weightpaint" # dot on purpose (access from topbar)
+ # dont give context on purpose to not show this in the generic header toolsettings
+ # this is added only in the gradient tool's ToolDef
+ #bl_context = ".weightpaint" # dot on purpose (access from topbar)
bl_label = "Falloff"
bl_options = {'DEFAULT_CLOSED'}
diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index 34f447a7108..c8ddd86a195 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -111,13 +111,13 @@ def curve_node_items(context):
yield NodeItem("GeometryNodeTrimCurve")
yield NodeItemCustom(draw=lambda self, layout, context: layout.separator())
yield NodeItem("GeometryNodeInputCurveHandlePositions")
- yield NodeItem("GeometryNodeCurveParameter")
yield NodeItem("GeometryNodeInputTangent")
yield NodeItem("GeometryNodeInputCurveTilt")
yield NodeItem("GeometryNodeCurveEndpointSelection")
yield NodeItem("GeometryNodeCurveHandleTypeSelection")
yield NodeItem("GeometryNodeInputSplineCyclic")
yield NodeItem("GeometryNodeSplineLength")
+ yield NodeItem("GeometryNodeSplineParameter")
yield NodeItem("GeometryNodeInputSplineResolution")
yield NodeItemCustom(draw=lambda self, layout, context: layout.separator())
yield NodeItem("GeometryNodeSetCurveRadius")
@@ -141,6 +141,7 @@ def mesh_node_items(context):
yield NodeItem("GeometryNodeLegacySubdivisionSurface", poll=geometry_nodes_legacy_poll)
yield NodeItemCustom(draw=lambda self, layout, context: layout.separator())
+ yield NodeItem("GeometryNodeDualMesh")
yield NodeItem("GeometryNodeMeshBoolean")
yield NodeItem("GeometryNodeMeshToCurve")
yield NodeItem("GeometryNodeMeshToPoints")
@@ -149,7 +150,13 @@ def mesh_node_items(context):
yield NodeItem("GeometryNodeSubdivisionSurface")
yield NodeItem("GeometryNodeTriangulate")
yield NodeItemCustom(draw=lambda self, layout, context: layout.separator())
+ yield NodeItem("GeometryNodeInputMeshEdgeNeighbors")
+ yield NodeItem("GeometryNodeInputMeshEdgeVertices")
+ yield NodeItem("GeometryNodeInputMeshFaceArea")
+ yield NodeItem("GeometryNodeInputMeshFaceNeighbors")
+ yield NodeItem("GeometryNodeInputMeshIsland")
yield NodeItem("GeometryNodeInputShadeSmooth")
+ yield NodeItem("GeometryNodeInputMeshVertexNeighbors")
yield NodeItemCustom(draw=lambda self, layout, context: layout.separator())
yield NodeItem("GeometryNodeSetShadeSmooth")
@@ -169,6 +176,7 @@ def geometry_node_items(context):
yield NodeItem("GeometryNodeBoundBox")
yield NodeItem("GeometryNodeConvexHull")
yield NodeItem("GeometryNodeDeleteGeometry")
+ yield NodeItem("GeometryNodeGeometryToInstance")
yield NodeItem("GeometryNodeProximity")
yield NodeItem("GeometryNodeJoinGeometry")
yield NodeItem("GeometryNodeRaycast")
@@ -207,6 +215,7 @@ def geometry_input_node_items(context):
yield NodeItem("GeometryNodeInputNormal")
yield NodeItem("GeometryNodeInputPosition")
yield NodeItem("GeometryNodeInputRadius")
+ yield NodeItem("GeometryNodeInputSceneTime")
# Custom Menu for Material Nodes
def geometry_material_node_items(context):
@@ -675,6 +684,7 @@ geometry_node_categories = [
NodeItem("GeometryNodeAttributeRemove", poll=geometry_nodes_legacy_poll),
NodeItem("GeometryNodeCaptureAttribute"),
+ NodeItem("GeometryNodeAttributeDomainSize"),
NodeItem("GeometryNodeAttributeStatistic"),
NodeItem("GeometryNodeAttributeTransfer"),
]),
@@ -749,7 +759,7 @@ geometry_node_categories = [
NodeItem("ShaderNodeMath"),
NodeItem("FunctionNodeBooleanMath"),
NodeItem("FunctionNodeRotateEuler"),
- NodeItem("FunctionNodeCompareFloats"),
+ NodeItem("FunctionNodeCompare"),
NodeItem("FunctionNodeFloatToInt"),
NodeItem("GeometryNodeSwitch"),
NodeItem("FunctionNodeRandomValue"),
diff --git a/release/windows/msix/AppxManifest.xml.template b/release/windows/msix/AppxManifest.xml.template
index 9289a67efef..e1b267472a3 100644
--- a/release/windows/msix/AppxManifest.xml.template
+++ b/release/windows/msix/AppxManifest.xml.template
@@ -5,7 +5,7 @@
<DisplayName>Blender[LTSORNOT]</DisplayName>
<PublisherDisplayName>Blender Foundation</PublisherDisplayName>
<Description>Blender [VERSION] is the Free and Open Source 3D creation suite</Description>
- <Logo>Assets\StoreLogo.png</Logo>
+ <Logo>Assets\StoreLogo.scale-100.png</Logo>
</Properties>
<Resources>
<Resource Language="en-us" />
diff --git a/source/blender/blendthumb/src/blendthumb.hh b/source/blender/blendthumb/src/blendthumb.hh
index c029a1766d6..0bcb160519e 100644
--- a/source/blender/blendthumb/src/blendthumb.hh
+++ b/source/blender/blendthumb/src/blendthumb.hh
@@ -53,6 +53,10 @@ enum eThumbStatus {
std::optional<blender::Vector<uint8_t>> blendthumb_create_png_data_from_thumb(
const Thumbnail *thumb);
+/**
+ * This function extracts the thumbnail from the .blend file into thumb.
+ * Returns #BT_OK for success and the relevant error code otherwise.
+ */
eThumbStatus blendthumb_create_thumb_from_file(struct FileReader *rawfile, Thumbnail *thumb);
/* INTEGER CODES */
diff --git a/source/blender/blendthumb/src/blendthumb_extract.cc b/source/blender/blendthumb/src/blendthumb_extract.cc
index f1c5567bab5..2d14a88c904 100644
--- a/source/blender/blendthumb/src/blendthumb_extract.cc
+++ b/source/blender/blendthumb/src/blendthumb_extract.cc
@@ -179,10 +179,6 @@ static eThumbStatus blendthumb_extract_from_file_impl(FileReader *file,
return BT_INVALID_THUMB;
}
-/**
- * This function extracts the thumbnail from the .blend file into thumb.
- * Returns #BT_OK for success and the relevant error code otherwise.
- */
eThumbStatus blendthumb_create_thumb_from_file(FileReader *rawfile, Thumbnail *thumb)
{
/* Read header in order to identify file type. */
diff --git a/source/blender/blenfont/BLF_api.h b/source/blender/blenfont/BLF_api.h
index fa8e764139d..bd1fa4ce4e5 100644
--- a/source/blender/blenfont/BLF_api.h
+++ b/source/blender/blenfont/BLF_api.h
@@ -43,9 +43,14 @@ void BLF_exit(void);
void BLF_cache_clear(void);
+/**
+ * Optional cache flushing function, called before #blf_batch_draw.
+ */
void BLF_cache_flush_set_fn(void (*cache_flush_fn)(void));
-/* Loads a font, or returns an already loaded font and increments its reference count. */
+/**
+ * Loads a font, or returns an already loaded font and increments its reference count.
+ */
int BLF_load(const char *name) ATTR_NONNULL();
int BLF_load_mem(const char *name, const unsigned char *mem, int mem_size) ATTR_NONNULL();
@@ -57,17 +62,22 @@ void BLF_unload_id(int fontid);
char *BLF_display_name_from_file(const char *filename);
-/* Check if font supports a particular glyph. */
+/**
+ * Check if font supports a particular glyph.
+ */
bool BLF_has_glyph(int fontid, unsigned int unicode);
-/* Attach a file with metrics information from memory. */
+/**
+ * Attach a file with metrics information from memory.
+ */
void BLF_metrics_attach(int fontid, unsigned char *mem, int mem_size);
void BLF_aspect(int fontid, float x, float y, float z);
void BLF_position(int fontid, float x, float y, float z);
void BLF_size(int fontid, float size, int dpi);
-/* goal: small but useful color API */
+/* Goal: small but useful color API. */
+
void BLF_color4ubv(int fontid, const unsigned char rgba[4]);
void BLF_color3ubv(int fontid, const unsigned char rgb[3]);
void BLF_color3ubv_alpha(int fontid, const unsigned char rgb[3], unsigned char alpha);
@@ -80,26 +90,32 @@ void BLF_color3f(int fontid, float r, float g, float b);
void BLF_color3fv_alpha(int fontid, const float rgb[3], float alpha);
/* Also available: `UI_FontThemeColor(fontid, colorid)`. */
-/* Set a 4x4 matrix to be multiplied before draw the text.
+/**
+ * Set a 4x4 matrix to be multiplied before draw the text.
* Remember that you need call BLF_enable(BLF_MATRIX)
* to enable this.
*
* The order of the matrix is like GL:
- *
+ * \code{.unparsed}
* | m[0] m[4] m[8] m[12] |
* | m[1] m[5] m[9] m[13] |
* | m[2] m[6] m[10] m[14] |
* | m[3] m[7] m[11] m[15] |
+ * \endcode
*/
void BLF_matrix(int fontid, const float m[16]);
-/* Batch draw-calls together as long as
- * the model-view matrix and the font remain unchanged. */
+/**
+ * Batch draw-calls together as long as
+ * the model-view matrix and the font remain unchanged.
+ */
void BLF_batch_draw_begin(void);
void BLF_batch_draw_flush(void);
void BLF_batch_draw_end(void);
-/* Draw the string using the current font. */
+/**
+ * Draw the string using the current font.
+ */
void BLF_draw_ex(int fontid, const char *str, size_t str_len, struct ResultBLF *r_info)
ATTR_NONNULL(2);
void BLF_draw(int fontid, const char *str, size_t str_len) ATTR_NONNULL(2);
@@ -113,6 +129,14 @@ typedef bool (*BLF_GlyphBoundsFn)(const char *str,
const int glyph_bearing[2],
void *user_data);
+/**
+ * Run \a user_fn for each character, with the bound-box that would be used for drawing.
+ *
+ * \param user_fn: Callback that runs on each glyph, returning false early exits.
+ * \param user_data: User argument passed to \a user_fn.
+ *
+ * \note The font position, clipping, matrix and rotation are not applied.
+ */
void BLF_boundbox_foreach_glyph_ex(int fontid,
const char *str,
size_t str_len,
@@ -125,14 +149,19 @@ void BLF_boundbox_foreach_glyph(int fontid,
BLF_GlyphBoundsFn user_fn,
void *user_data) ATTR_NONNULL(2);
-/* Get the string byte offset that fits within a given width */
+/**
+ * Get the string byte offset that fits within a given width.
+ */
size_t BLF_width_to_strlen(
int fontid, const char *str, size_t str_len, float width, float *r_width) ATTR_NONNULL(2);
-/* Same as BLF_width_to_strlen but search from the string end */
+/**
+ * Same as BLF_width_to_strlen but search from the string end.
+ */
size_t BLF_width_to_rstrlen(
int fontid, const char *str, size_t str_len, float width, float *r_width) ATTR_NONNULL(2);
-/* This function return the bounding box of the string
+/**
+ * This function return the bounding box of the string
* and are not multiplied by the aspect.
*/
void BLF_boundbox_ex(int fontid,
@@ -142,7 +171,8 @@ void BLF_boundbox_ex(int fontid,
struct ResultBLF *r_info) ATTR_NONNULL(2);
void BLF_boundbox(int fontid, const char *str, size_t str_len, struct rctf *box) ATTR_NONNULL();
-/* The next both function return the width and height
+/**
+ * The next both function return the width and height
* of the string, using the current font and both value
* are multiplied by the aspect of the font.
*/
@@ -155,24 +185,29 @@ float BLF_height_ex(int fontid, const char *str, size_t str_len, struct ResultBL
float BLF_height(int fontid, const char *str, size_t str_len) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
-/* Return dimensions of the font without any sample text. */
+/**
+ * Return dimensions of the font without any sample text.
+ */
int BLF_height_max(int fontid) ATTR_WARN_UNUSED_RESULT;
float BLF_width_max(int fontid) ATTR_WARN_UNUSED_RESULT;
float BLF_descender(int fontid) ATTR_WARN_UNUSED_RESULT;
float BLF_ascender(int fontid) ATTR_WARN_UNUSED_RESULT;
-/* The following function return the width and height of the string, but
+/**
+ * The following function return the width and height of the string, but
* just in one call, so avoid extra freetype2 stuff.
*/
void BLF_width_and_height(
int fontid, const char *str, size_t str_len, float *r_width, float *r_height) ATTR_NONNULL();
-/* For fixed width fonts only, returns the width of a
+/**
+ * For fixed width fonts only, returns the width of a
* character.
*/
float BLF_fixed_width(int fontid) ATTR_WARN_UNUSED_RESULT;
-/* By default, rotation and clipping are disable and
+/**
+ * By default, rotation and clipping are disable and
* have to be enable/disable using BLF_enable/disable.
*/
void BLF_rotation(int fontid, float angle);
@@ -186,27 +221,31 @@ void BLF_blur(int fontid, int size);
void BLF_enable(int fontid, int option);
void BLF_disable(int fontid, int option);
-/* Shadow options, level is the blur level, can be 3, 5 or 0 and
- * the other argument are the rgba color.
- * Take care that shadow need to be enable using BLF_enable!!!
+/**
+ * Shadow options, level is the blur level, can be 3, 5 or 0 and
+ * the other argument are the RGBA color.
+ * Take care that shadow need to be enable using #BLF_enable!
*/
void BLF_shadow(int fontid, int level, const float rgba[4]) ATTR_NONNULL(3);
-/* Set the offset for shadow text, this is the current cursor
+/**
+ * Set the offset for shadow text, this is the current cursor
* position plus this offset, don't need call BLF_position before
* this function, the current position is calculate only on
* BLF_draw, so it's safe call this whenever you like.
*/
void BLF_shadow_offset(int fontid, int x, int y);
-/* Set the buffer, size and number of channels to draw, one thing to take care is call
+/**
+ * Set the buffer, size and number of channels to draw, one thing to take care is call
* this function with NULL pointer when we finish, for example:
+ * \code{.c}
+ * BLF_buffer(my_fbuf, my_cbuf, 100, 100, 4, true, NULL);
*
- * BLF_buffer(my_fbuf, my_cbuf, 100, 100, 4, true, NULL);
+ * ... set color, position and draw ...
*
- * ... set color, position and draw ...
- *
- * BLF_buffer(NULL, NULL, NULL, 0, 0, false, NULL);
+ * BLF_buffer(NULL, NULL, NULL, 0, 0, false, NULL);
+ * \endcode
*/
void BLF_buffer(int fontid,
float *fbuf,
@@ -216,29 +255,46 @@ void BLF_buffer(int fontid,
int nch,
struct ColorManagedDisplay *display);
-/* Set the color to be used for text. */
+/**
+ * Set the color to be used for text.
+ */
void BLF_buffer_col(int fontid, const float rgba[4]) ATTR_NONNULL(2);
-/* Draw the string into the buffer, this function draw in both buffer,
+/**
+ * Draw the string into the buffer, this function draw in both buffer,
* float and unsigned char _BUT_ it's not necessary set both buffer, NULL is valid here.
*/
void BLF_draw_buffer_ex(int fontid, const char *str, size_t str_len, struct ResultBLF *r_info)
ATTR_NONNULL(2);
void BLF_draw_buffer(int fontid, const char *str, size_t str_len) ATTR_NONNULL(2);
-/* Add a path to the font dir paths. */
+/**
+ * Add a path to the font dir paths.
+ */
void BLF_dir_add(const char *path) ATTR_NONNULL();
-/* Remove a path from the font dir paths. */
+/**
+ * Remove a path from the font dir paths.
+ */
void BLF_dir_rem(const char *path) ATTR_NONNULL();
-/* Return an array with all the font dir (this can be used for filesel) */
+/**
+ * Return an array with all the font dir (this can be used for file-selector).
+ */
char **BLF_dir_get(int *ndir) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-/* Free the data return by BLF_dir_get. */
+/**
+ * Free the data return by #BLF_dir_get.
+ */
void BLF_dir_free(char **dirs, int count) ATTR_NONNULL();
/* blf_thumbs.c */
+
+/**
+ * This function is used for generating thumbnail previews.
+ *
+ * \note called from a thread, so it bypasses the normal BLF_* api (which isn't thread-safe).
+ */
void BLF_thumb_preview(const char *filename,
const char **draw_str,
const char **i18n_draw_str,
@@ -251,16 +307,25 @@ void BLF_thumb_preview(const char *filename,
int channels) ATTR_NONNULL();
/* blf_default.c */
+
void BLF_default_dpi(int dpi);
void BLF_default_size(int size);
void BLF_default_set(int fontid);
-int BLF_default(void); /* get default font ID so we can pass it to other functions */
-/* Draw the string using the default font, size and dpi. */
+/**
+ * Get default font ID so we can pass it to other functions.
+ */
+int BLF_default(void);
+/**
+ * Draw the string using the default font, size and DPI.
+ */
void BLF_draw_default(float x, float y, float z, const char *str, size_t str_len) ATTR_NONNULL();
-/* Set size and DPI, and return default font ID. */
+/**
+ * Set size and DPI, and return default font ID.
+ */
int BLF_set_default(void);
/* blf_font_default.c */
+
int BLF_load_default(const bool unique);
int BLF_load_mono_default(const bool unique);
diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c
index d6773916abd..c69a0b1eb73 100644
--- a/source/blender/blenfont/intern/blf.c
+++ b/source/blender/blenfont/intern/blf.c
@@ -66,7 +66,8 @@
/* Font array. */
static FontBLF *global_font[BLF_MAX_FONT] = {NULL};
-/* XXX, should these be made into global_font_'s too? */
+/* XXX: should these be made into global_font_'s too? */
+
int blf_mono_font = -1;
int blf_mono_font_render = -1;
@@ -568,14 +569,6 @@ int BLF_draw_mono(int fontid, const char *str, const size_t str_len, int cwidth)
return columns;
}
-/**
- * Run \a user_fn for each character, with the bound-box that would be used for drawing.
- *
- * \param user_fn: Callback that runs on each glyph, returning false early exits.
- * \param user_data: User argument passed to \a user_fn.
- *
- * \note The font position, clipping, matrix and rotation are not applied.
- */
void BLF_boundbox_foreach_glyph_ex(int fontid,
const char *str,
size_t str_len,
diff --git a/source/blender/blenfont/intern/blf_dir.c b/source/blender/blenfont/intern/blf_dir.c
index f4a20faf109..8eb148a8a9a 100644
--- a/source/blender/blenfont/intern/blf_dir.c
+++ b/source/blender/blenfont/intern/blf_dir.c
@@ -148,10 +148,6 @@ char *blf_dir_search(const char *file)
return s;
}
-/**
- * Some font have additional file with metrics information,
- * in general, the extension of the file is: `.afm` or `.pfm`
- */
char *blf_dir_metrics_search(const char *filename)
{
char *mfile;
diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c
index c81d18ba7de..14d3a208f69 100644
--- a/source/blender/blenfont/intern/blf_font.c
+++ b/source/blender/blenfont/intern/blf_font.c
@@ -63,6 +63,7 @@
#endif
/* Batching buffer for drawing. */
+
BatchBLF g_batch;
/* freetype2 handle ONLY for this file! */
@@ -394,7 +395,6 @@ void blf_font_draw(FontBLF *font, const char *str, const size_t str_len, struct
blf_glyph_cache_release(font);
}
-/* use fixed column width, but an utf8 character may occupy multiple columns */
int blf_font_draw_mono(FontBLF *font, const char *str, const size_t str_len, int cwidth)
{
GlyphBLF *g;
@@ -1168,9 +1168,6 @@ void blf_font_exit(void)
blf_batch_draw_exit();
}
-/**
- * Optional cache flushing function, called before #blf_batch_draw.
- */
void BLF_cache_flush_set_fn(void (*cache_flush_fn)(void))
{
blf_draw_cache_flush = cache_flush_fn;
diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c
index 5f14ef433e9..4f25f99b65c 100644
--- a/source/blender/blenfont/intern/blf_glyph.c
+++ b/source/blender/blenfont/intern/blf_glyph.c
@@ -73,9 +73,6 @@ static FT_Fixed to_16dot16(double val)
/** \name Glyph Cache
* \{ */
-/**
- * Find a glyph cache that matches a size, DPI & styles.
- */
GlyphCacheBLF *blf_glyph_cache_find(FontBLF *font, float size, unsigned int dpi)
{
GlyphCacheBLF *gc = (GlyphCacheBLF *)font->cache.first;
@@ -89,9 +86,6 @@ GlyphCacheBLF *blf_glyph_cache_find(FontBLF *font, float size, unsigned int dpi)
return NULL;
}
-/**
- * Create a new glyph cache for the current size, DPI & styles.
- */
GlyphCacheBLF *blf_glyph_cache_new(FontBLF *font)
{
GlyphCacheBLF *gc = (GlyphCacheBLF *)MEM_callocN(sizeof(GlyphCacheBLF), "blf_glyph_cache_new");
@@ -451,9 +445,6 @@ static FT_GlyphSlot blf_glyph_render(FontBLF *settings_font,
return NULL;
}
-/**
- * Create (or load from cache) a fully-rendered bitmap glyph.
- */
GlyphBLF *blf_glyph_ensure(FontBLF *font, GlyphCacheBLF *gc, uint charcode)
{
GlyphBLF *g = blf_glyph_cache_find_glyph(gc, charcode);
diff --git a/source/blender/blenfont/intern/blf_internal.h b/source/blender/blenfont/intern/blf_internal.h
index cec20995dc6..02e4a896a31 100644
--- a/source/blender/blenfont/intern/blf_internal.h
+++ b/source/blender/blenfont/intern/blf_internal.h
@@ -37,6 +37,10 @@ unsigned int blf_next_p2(unsigned int x);
unsigned int blf_hash(unsigned int val);
char *blf_dir_search(const char *file);
+/**
+ * Some font have additional file with metrics information,
+ * in general, the extension of the file is: `.afm` or `.pfm`
+ */
char *blf_dir_metrics_search(const char *filename);
/* int blf_dir_split(const char *str, char *file, int *size); */ /* UNUSED */
@@ -65,6 +69,9 @@ void blf_font_draw_ascii(struct FontBLF *font,
const char *str,
size_t str_len,
struct ResultBLF *r_info);
+/**
+ * Use fixed column width, but an utf8 character may occupy multiple columns.
+ */
int blf_font_draw_mono(struct FontBLF *font, const char *str, size_t str_len, int cwidth);
void blf_font_draw_buffer(struct FontBLF *font,
const char *str,
@@ -130,13 +137,22 @@ int blf_font_count_missing_chars(struct FontBLF *font,
void blf_font_free(struct FontBLF *font);
+/**
+ * Find a glyph cache that matches a size, DPI & styles.
+ */
struct GlyphCacheBLF *blf_glyph_cache_find(struct FontBLF *font, float size, unsigned int dpi);
+/**
+ * Create a new glyph cache for the current size, DPI & styles.
+ */
struct GlyphCacheBLF *blf_glyph_cache_new(struct FontBLF *font);
struct GlyphCacheBLF *blf_glyph_cache_acquire(struct FontBLF *font);
void blf_glyph_cache_release(struct FontBLF *font);
void blf_glyph_cache_clear(struct FontBLF *font);
void blf_glyph_cache_free(struct GlyphCacheBLF *gc);
+/**
+ * Create (or load from cache) a fully-rendered bitmap glyph.
+ */
struct GlyphBLF *blf_glyph_ensure(struct FontBLF *font, struct GlyphCacheBLF *gc, uint charcode);
void blf_glyph_free(struct GlyphBLF *g);
diff --git a/source/blender/blenfont/intern/blf_thumbs.c b/source/blender/blenfont/intern/blf_thumbs.c
index bbdb26a61b6..06bbd0cf521 100644
--- a/source/blender/blenfont/intern/blf_thumbs.c
+++ b/source/blender/blenfont/intern/blf_thumbs.c
@@ -43,11 +43,6 @@
#include "BLI_strict_flags.h"
-/**
- * This function is used for generating thumbnail previews.
- *
- * \note called from a thread, so it bypasses the normal BLF_* api (which isn't thread-safe).
- */
void BLF_thumb_preview(const char *filename,
const char **draw_str,
const char **i18n_draw_str,
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h
index c95190d2c83..0fff6d27031 100644
--- a/source/blender/blenkernel/BKE_DerivedMesh.h
+++ b/source/blender/blenkernel/BKE_DerivedMesh.h
@@ -242,8 +242,17 @@ struct DerivedMesh {
void (*release)(DerivedMesh *dm);
};
+/**
+ * Utility function to initialize a #DerivedMesh's function pointers to
+ * the default implementation (for those functions which have a default).
+ */
void DM_init_funcs(DerivedMesh *dm);
+/**
+ * Utility function to initialize a #DerivedMesh for the desired number
+ * of vertices, edges and faces (doesn't allocate memory for them, just
+ * sets up the custom data layers)>
+ */
void DM_init(DerivedMesh *dm,
DerivedMeshType type,
int numVerts,
@@ -252,6 +261,10 @@ void DM_init(DerivedMesh *dm,
int numLoops,
int numPolys);
+/**
+ * Utility function to initialize a DerivedMesh for the desired number
+ * of vertices, edges and faces, with a layer setup copied from source
+ */
void DM_from_template_ex(DerivedMesh *dm,
DerivedMesh *source,
DerivedMeshType type,
@@ -276,43 +289,59 @@ void DM_from_template(DerivedMesh *dm,
*/
bool DM_release(DerivedMesh *dm);
+/**
+ * set the #CD_FLAG_NOCOPY flag in custom data layers where the mask is
+ * zero for the layer type, so only layer types specified by the mask
+ * will be copied
+ */
void DM_set_only_copy(DerivedMesh *dm, const struct CustomData_MeshMasks *mask);
-/* adds a vertex/edge/face custom data layer to a DerivedMesh, optionally
+/* Adds a vertex/edge/face custom data layer to a DerivedMesh, optionally
* backed by an external data array
* alloctype defines how the layer is allocated or copied, and how it is
- * freed, see BKE_customdata.h for the different options
- */
+ * freed, see BKE_customdata.h for the different options. */
+
void DM_add_vert_layer(struct DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer);
void DM_add_edge_layer(struct DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer);
void DM_add_tessface_layer(struct DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer);
void DM_add_loop_layer(DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer);
void DM_add_poly_layer(struct DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer);
-/* custom data access functions
- * return pointer to data from first layer which matches type
- * if they return NULL for valid indices, data doesn't exist
- * note these return pointers - any change modifies the internals of the mesh
- */
+/* -------------------------------------------------------------------- */
+/** \name Custom Data Access Functions
+ *
+ * \return pointer to data from first layer which matches type
+ * if they return NULL for valid indices, data doesn't exist.
+ * \note these return pointers - any change modifies the internals of the mesh.
+ * \{ */
+
void *DM_get_vert_data(struct DerivedMesh *dm, int index, int type);
void *DM_get_edge_data(struct DerivedMesh *dm, int index, int type);
void *DM_get_tessface_data(struct DerivedMesh *dm, int index, int type);
void *DM_get_poly_data(struct DerivedMesh *dm, int index, int type);
-/* custom data layer access functions
- * return pointer to first data layer which matches type (a flat array)
- * if they return NULL, data doesn't exist
- * note these return pointers - any change modifies the internals of the mesh
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Custom Data Layer Access Functions
+ *
+ * \return pointer to first data layer which matches type (a flat array)
+ * if they return NULL, data doesn't exist.
+ * \note these return pointers - any change modifies the internals of the mesh.
+ * \{ */
+
void *DM_get_vert_data_layer(struct DerivedMesh *dm, int type);
void *DM_get_edge_data_layer(struct DerivedMesh *dm, int type);
void *DM_get_tessface_data_layer(struct DerivedMesh *dm, int type);
void *DM_get_poly_data_layer(struct DerivedMesh *dm, int type);
void *DM_get_loop_data_layer(struct DerivedMesh *dm, int type);
-/* custom data copy functions
+/** \} */
+
+/**
+ * Custom data copy functions
* copy count elements from source_index in source to dest_index in dest
- * these copy all layers for which the CD_FLAG_NOCOPY flag is not set
+ * these copy all layers for which the CD_FLAG_NOCOPY flag is not set.
*/
void DM_copy_vert_data(struct DerivedMesh *source,
struct DerivedMesh *dest,
@@ -320,13 +349,26 @@ void DM_copy_vert_data(struct DerivedMesh *source,
int dest_index,
int count);
-/* Sets up mpolys for a DM based on face iterators in source. */
+/**
+ * Sets up mpolys for a DM based on face iterators in source.
+ */
void DM_DupPolys(DerivedMesh *source, DerivedMesh *target);
void DM_ensure_normals(DerivedMesh *dm);
+/**
+ * Ensure the array is large enough.
+ *
+ * \note This function must always be thread-protected by caller.
+ * It should only be used by internal code.
+ */
void DM_ensure_looptri_data(DerivedMesh *dm);
+/**
+ * Interpolates vertex data from the vertices indexed by `src_indices` in the
+ * source mesh using the given weights and stores the result in the vertex
+ * indexed by `dest_index` in the `dest` mesh.
+ */
void DM_interp_vert_data(struct DerivedMesh *source,
struct DerivedMesh *dest,
int *src_indices,
@@ -336,7 +378,9 @@ void DM_interp_vert_data(struct DerivedMesh *source,
void mesh_get_mapped_verts_coords(struct Mesh *me_eval, float (*r_cos)[3], const int totcos);
-/* same as above but won't use render settings */
+/**
+ * Same as above but won't use render settings.
+ */
struct Mesh *editbmesh_get_eval_cage(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *,
diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h
index 763e540fdd9..ea8ee3f93b1 100644
--- a/source/blender/blenkernel/BKE_action.h
+++ b/source/blender/blenkernel/BKE_action.h
@@ -79,50 +79,86 @@ typedef enum eAction_TransformFlags {
ACT_TRANS_ALL = (ACT_TRANS_ONLY | ACT_TRANS_PROP),
} eAction_TransformFlags;
-/* Return flags indicating which transforms the given object/posechannel has
+/**
+ * Return flags indicating which transforms the given object/posechannel has
* - if 'curves' is provided, a list of links to these curves are also returned
- * whose nodes WILL NEED FREEING
+ * whose nodes WILL NEED FREEING.
*/
short action_get_item_transforms(struct bAction *act,
struct Object *ob,
struct bPoseChannel *pchan,
ListBase *curves);
-/* Some kind of bounding box operation on the action */
+/**
+ * Calculate the extents of given action.
+ */
void calc_action_range(const struct bAction *act, float *start, float *end, short incl_modifiers);
-/* Does action have any motion data at all? */
+/* Retrieve the intended playback frame range, using the manually set range if available,
+ * or falling back to scanning F-Curves for their first & last frames otherwise. */
+void BKE_action_get_frame_range(const struct bAction *act, float *r_start, float *r_end);
+
+/**
+ * Check if the given action has any keyframes.
+ */
bool action_has_motion(const struct bAction *act);
+/**
+ * Is the action configured as cyclic.
+ */
+bool BKE_action_is_cyclic(const struct bAction *act);
+
/* Action Groups API ----------------- */
-/* Get the active action-group for an Action */
+/**
+ * Get the active action-group for an Action.
+ */
struct bActionGroup *get_active_actiongroup(struct bAction *act);
-/* Make the given Action Group the active one */
+/**
+ * Make the given Action-Group the active one.
+ */
void set_active_action_group(struct bAction *act, struct bActionGroup *agrp, short select);
-/* Sync colors used for action/bone group with theme settings */
+/**
+ * Sync colors used for action/bone group with theme settings.
+ */
void action_group_colors_sync(struct bActionGroup *grp, const struct bActionGroup *ref_grp);
-/* Add a new action group with the given name to the action */
+/**
+ * Add a new action group with the given name to the action>
+ */
struct bActionGroup *action_groups_add_new(struct bAction *act, const char name[]);
-/* Add given channel into (active) group */
+/**
+ * Add given channel into (active) group
+ * - assumes that channel is not linked to anything anymore
+ * - always adds at the end of the group
+ */
void action_groups_add_channel(struct bAction *act,
struct bActionGroup *agrp,
struct FCurve *fcurve);
-/* Remove the given channel from all groups */
+/**
+ * Remove the given channel from all groups.
+ */
void action_groups_remove_channel(struct bAction *act, struct FCurve *fcu);
-/* Reconstruct group channel pointers. */
+/**
+ * Reconstruct group channel pointers.
+ * Assumes that the groups referred to by the FCurves are already in act->groups.
+ * Reorders the main channel list to match group order.
+ */
void BKE_action_groups_reconstruct(struct bAction *act);
-/* Find a group with the given name */
+/**
+ * Find a group with the given name.
+ */
struct bActionGroup *BKE_action_group_find_name(struct bAction *act, const char name[]);
-/* Clear all 'temp' flags on all groups */
+/**
+ * Clear all 'temp' flags on all groups.
+ */
void action_groups_clear_tempflags(struct bAction *act);
/**
@@ -139,21 +175,47 @@ bool BKE_action_has_single_frame(const struct bAction *act);
/* Pose API ----------------- */
void BKE_pose_channel_free(struct bPoseChannel *pchan);
+/**
+ * Deallocates a pose channel.
+ * Does not free the pose channel itself.
+ */
void BKE_pose_channel_free_ex(struct bPoseChannel *pchan, bool do_id_user);
+/**
+ * Clears the runtime cache of a pose channel without free.
+ */
void BKE_pose_channel_runtime_reset(struct bPoseChannel_Runtime *runtime);
+/**
+ * Reset all non-persistent fields.
+ */
void BKE_pose_channel_runtime_reset_on_copy(struct bPoseChannel_Runtime *runtime);
+/**
+ * Deallocates runtime cache of a pose channel
+ */
void BKE_pose_channel_runtime_free(struct bPoseChannel_Runtime *runtime);
+/**
+ * Deallocates runtime cache of a pose channel's B-Bone shape.
+ */
void BKE_pose_channel_free_bbone_cache(struct bPoseChannel_Runtime *runtime);
void BKE_pose_channels_free(struct bPose *pose);
+/**
+ * Removes and deallocates all channels from a pose.
+ * Does not free the pose itself.
+ */
void BKE_pose_channels_free_ex(struct bPose *pose, bool do_id_user);
+/**
+ * Removes the hash for quick lookup of channels, must be done when adding/removing channels.
+ */
void BKE_pose_channels_hash_ensure(struct bPose *pose);
void BKE_pose_channels_hash_free(struct bPose *pose);
+/**
+ * Selectively remove pose channels.
+ */
void BKE_pose_channels_remove(struct Object *ob,
bool (*filter_fn)(const char *bone_name, void *user_data),
void *user_data);
@@ -161,18 +223,63 @@ void BKE_pose_channels_remove(struct Object *ob,
void BKE_pose_free_data_ex(struct bPose *pose, bool do_id_user);
void BKE_pose_free_data(struct bPose *pose);
void BKE_pose_free(struct bPose *pose);
+/**
+ * Removes and deallocates all data from a pose, and also frees the pose.
+ */
void BKE_pose_free_ex(struct bPose *pose, bool do_id_user);
+/**
+ * Allocate a new pose on the heap, and copy the src pose and its channels
+ * into the new pose. *dst is set to the newly allocated structure, and assumed to be NULL.
+ *
+ * \param dst: Should be freed already, makes entire duplicate.
+ */
void BKE_pose_copy_data_ex(struct bPose **dst,
const struct bPose *src,
const int flag,
const bool copy_constraints);
void BKE_pose_copy_data(struct bPose **dst, const struct bPose *src, const bool copy_constraints);
+/**
+ * Copy the internal members of each pose channel including constraints
+ * and ID-Props, used when duplicating bones in edit-mode.
+ * (unlike copy_pose_channel_data which only does posing-related stuff).
+ *
+ * \note use when copying bones in edit-mode (on returned value from #BKE_pose_channel_ensure)
+ */
void BKE_pose_channel_copy_data(struct bPoseChannel *pchan, const struct bPoseChannel *pchan_from);
void BKE_pose_channel_session_uuid_generate(struct bPoseChannel *pchan);
+/**
+ * Return a pointer to the pose channel of the given name
+ * from this pose.
+ */
struct bPoseChannel *BKE_pose_channel_find_name(const struct bPose *pose, const char *name);
+/**
+ * Find the active pose-channel for an object
+ * (we can't just use pose, as layer info is in armature)
+ *
+ * \note #Object, not #bPose is used here, as we need layer info from Armature.
+ */
struct bPoseChannel *BKE_pose_channel_active(struct Object *ob);
+/**
+ * Use this when detecting the "other selected bone",
+ * when we have multiple armatures in pose mode.
+ *
+ * In this case the active-selected is an obvious choice when finding the target for a
+ * constraint for eg. however from the users perspective the active pose bone of the
+ * active object is the _real_ active bone, so any other non-active selected bone
+ * is a candidate for being the other selected bone, see: T58447.
+ */
struct bPoseChannel *BKE_pose_channel_active_or_first_selected(struct Object *ob);
+/**
+ * Looks to see if the channel with the given name already exists
+ * in this pose - if not a new one is allocated and initialized.
+ *
+ * \note Use with care, not on Armature poses but for temporal ones.
+ * \note (currently used for action constraints and in rebuild_pose).
+ */
struct bPoseChannel *BKE_pose_channel_ensure(struct bPose *pose, const char *name);
+/**
+ * \see #ED_armature_ebone_get_mirrored (edit-mode, matching function)
+ */
struct bPoseChannel *BKE_pose_channel_get_mirrored(const struct bPose *pose, const char *name);
void BKE_pose_check_uuids_unique_and_report(const struct bPose *pose);
@@ -181,37 +288,60 @@ void BKE_pose_check_uuids_unique_and_report(const struct bPose *pose);
bool BKE_pose_channels_is_valid(const struct bPose *pose);
#endif
-/* sets constraint flags */
+/**
+ * Checks for IK constraint, Spline IK, and also for Follow-Path constraint.
+ * can do more constraints flags later. pose should be entirely OK.
+ */
void BKE_pose_update_constraint_flags(struct bPose *pose);
-/* tag constraint flags for update */
+/**
+ * Tag constraint flags for update.
+ */
void BKE_pose_tag_update_constraint_flags(struct bPose *pose);
-/* return the name of structure pointed by pose->ikparam */
+/**
+ * Return the name of structure pointed by `pose->ikparam`.
+ */
const char *BKE_pose_ikparam_get_name(struct bPose *pose);
-/* allocate and initialize pose->ikparam according to pose->iksolver */
+/**
+ * Allocate and initialize `pose->ikparam` according to `pose->iksolver`.
+ */
void BKE_pose_ikparam_init(struct bPose *pose);
-/* initialize a bItasc structure with default value */
+/**
+ * Initialize a #bItasc structure with default value.
+ */
void BKE_pose_itasc_init(struct bItasc *itasc);
-/* Checks if a bone is part of an IK chain or not */
+/**
+ * Checks if a bone is part of an IK chain or not.
+ */
bool BKE_pose_channel_in_IK_chain(struct Object *ob, struct bPoseChannel *pchan);
/* Bone Groups API --------------------- */
-/* Adds a new bone-group */
+/**
+ * Adds a new bone-group (name may be NULL).
+ */
struct bActionGroup *BKE_pose_add_group(struct bPose *pose, const char *name);
-/* Remove a bone-group */
+/**
+ * Remove the given bone-group (expects 'virtual' index (+1 one, used by active_group etc.))
+ * index might be invalid ( < 1), in which case it will be find from grp.
+ */
void BKE_pose_remove_group(struct bPose *pose, struct bActionGroup *grp, const int index);
-/* Remove the matching bone-group from its index */
+/**
+ * Remove the indexed bone-group (expects 'virtual' index (+1 one, used by active_group etc.)).
+ */
void BKE_pose_remove_group_index(struct bPose *pose, const int index);
/* Assorted Evaluation ----------------- */
-/* Used for the Action Constraint */
+/**
+ * For the calculation of the effects of an Action at the given frame on an object
+ * This is currently only used for the Action Constraint
+ */
void what_does_obaction(struct Object *ob,
struct Object *workob,
struct bPose *pose,
@@ -222,11 +352,18 @@ void what_does_obaction(struct Object *ob,
/* for proxy */
void BKE_pose_copy_pchan_result(struct bPoseChannel *pchanto,
const struct bPoseChannel *pchanfrom);
+/**
+ * Both poses should be in sync.
+ */
bool BKE_pose_copy_result(struct bPose *to, struct bPose *from);
-/* Clear transforms. */
+/**
+ * Zero the pose transforms for the entire pose or only for selected bones.
+ */
void BKE_pose_rest(struct bPose *pose, bool selected_bones_only);
-/* Tag pose for recalc. Also tag all related data to be recalc. */
+/**
+ * Tag pose for recalculation. Also tag all related data to be recalculated.
+ */
void BKE_pose_tag_recalc(struct Main *bmain, struct bPose *pose);
void BKE_pose_blend_write(struct BlendWriter *writer, struct bPose *pose, struct bArmature *arm);
diff --git a/source/blender/blenkernel/BKE_anim_data.h b/source/blender/blenkernel/BKE_anim_data.h
index 14ab9f21424..a65efbd707c 100644
--- a/source/blender/blenkernel/BKE_anim_data.h
+++ b/source/blender/blenkernel/BKE_anim_data.h
@@ -43,43 +43,81 @@ struct bAction;
/* ************************************* */
/* AnimData API */
-/* Check if the given ID-block can have AnimData */
+/**
+ * Check if the given ID-block can have AnimData.
+ */
bool id_type_can_have_animdata(const short id_type);
bool id_can_have_animdata(const struct ID *id);
-/* Get AnimData from the given ID-block */
+/**
+ * Get #AnimData from the given ID-block.
+ */
struct AnimData *BKE_animdata_from_id(struct ID *id);
-/* Ensure AnimData is present in the ID-block (when supported). */
+/**
+ * Ensure #AnimData exists in the given ID-block (when supported).
+ */
struct AnimData *BKE_animdata_ensure_id(struct ID *id);
-/* Set active action used by AnimData from the given ID-block */
+/**
+ * Set active action used by AnimData from the given ID-block.
+ *
+ * Called when user tries to change the active action of an #AnimData block
+ * (via RNA, Outliner, etc.)
+ *
+ * \param reports: Can be NULL.
+ * \param id: The owner of the animation data
+ * \param act: The Action to set, or NULL to clear.
+ *
+ * \return true when the action was successfully updated, false otherwise.
+ */
bool BKE_animdata_set_action(struct ReportList *reports, struct ID *id, struct bAction *act);
bool BKE_animdata_action_editable(const struct AnimData *adt);
-/* Ensure that the action's idroot is set correctly given the ID type of the owner.
- * Return true if it is, false if it was already set to an incompatible type. */
+/**
+ * Ensure that the action's idroot is set correctly given the ID type of the owner.
+ * Return true if it is, false if it was already set to an incompatible type.
+ */
bool BKE_animdata_action_ensure_idroot(const struct ID *owner, struct bAction *action);
-/* Free AnimData */
+/**
+ * Free AnimData used by the nominated ID-block, and clear ID-block's AnimData pointer.
+ */
void BKE_animdata_free(struct ID *id, const bool do_id_user);
-/* Return true if the ID-block has non-empty AnimData. */
+/**
+ * Return true if the ID-block has non-empty AnimData.
+ */
bool BKE_animdata_id_is_animated(const struct ID *id);
+/**
+ * Callback used by lib_query to walk over all ID usages
+ * (mimics `foreach_id` callback of #IDTypeInfo structure).
+ */
void BKE_animdata_foreach_id(struct AnimData *adt, struct LibraryForeachIDData *data);
-/* Copy AnimData */
+/**
+ * Make a copy of the given AnimData - to be used when copying data-blocks.
+ * \param flag: Control ID pointers management,
+ * see LIB_ID_CREATE_.../LIB_ID_COPY_... flags in BKE_lib_id.h
+ * \return The copied animdata.
+ */
struct AnimData *BKE_animdata_copy(struct Main *bmain, struct AnimData *adt, const int flag);
-/* Copy AnimData */
+/**
+ * \param flag: Control ID pointers management,
+ * see LIB_ID_CREATE_.../LIB_ID_COPY_... flags in BKE_lib_id.h
+ * \return true is successfully copied.
+ */
bool BKE_animdata_copy_id(struct Main *bmain,
struct ID *id_to,
struct ID *id_from,
const int flag);
-/* Copy AnimData Actions */
+/**
+ * Copy AnimData Actions.
+ */
void BKE_animdata_copy_id_action(struct Main *bmain, struct ID *id);
void BKE_animdata_duplicate_id_action(struct Main *bmain,
@@ -98,6 +136,9 @@ typedef enum eAnimData_MergeCopy_Modes {
ADT_MERGECOPY_SRC_REF = 2,
} eAnimData_MergeCopy_Modes;
+/**
+ * Merge copies of the data from the src AnimData into the destination AnimData.
+ */
void BKE_animdata_merge_copy(struct Main *bmain,
struct ID *dst_id,
struct ID *src_id,
diff --git a/source/blender/blenkernel/BKE_anim_path.h b/source/blender/blenkernel/BKE_anim_path.h
index 9db63080fd9..6bc09eb35ed 100644
--- a/source/blender/blenkernel/BKE_anim_path.h
+++ b/source/blender/blenkernel/BKE_anim_path.h
@@ -35,12 +35,21 @@ struct Object;
int BKE_anim_path_get_array_size(const struct CurveCache *curve_cache);
float BKE_anim_path_get_length(const struct CurveCache *curve_cache);
-/* This function populates the 'ob->runtime.curve_cache->anim_path_accum_length' data.
+/**
+ * This function populates the 'ob->runtime.curve_cache->anim_path_accum_length' data.
* You should never have to call this manually as it should already have been called by
* 'BKE_displist_make_curveTypes'. Do not call this manually unless you know what you are doing.
*/
void BKE_anim_path_calc_data(struct Object *ob);
+/**
+ * Calculate the deformation implied by the curve path at a given parametric position,
+ * and returns whether this operation succeeded.
+ *
+ * \param ctime: Time is normalized range <0-1>.
+ *
+ * \return success.
+ */
bool BKE_where_on_path(const struct Object *ob,
float ctime,
float r_vec[4],
diff --git a/source/blender/blenkernel/BKE_anim_visualization.h b/source/blender/blenkernel/BKE_anim_visualization.h
index 4e86abeed8d..3b8c91b7fd2 100644
--- a/source/blender/blenkernel/BKE_anim_visualization.h
+++ b/source/blender/blenkernel/BKE_anim_visualization.h
@@ -38,13 +38,34 @@ struct bPoseChannel;
/* ---------------------------------------------------- */
/* Animation Visualization */
+/**
+ * Initialize the default settings for animation visualization.
+ */
void animviz_settings_init(struct bAnimVizSettings *avs);
+/**
+ * Make a copy of motion-path data, so that viewing with copy on write works.
+ */
struct bMotionPath *animviz_copy_motionpath(const struct bMotionPath *mpath_src);
+/**
+ * Free the given motion path's cache.
+ */
void animviz_free_motionpath_cache(struct bMotionPath *mpath);
+/**
+ * Free the given motion path instance and its data.
+ * \note this frees the motion path given!
+ */
void animviz_free_motionpath(struct bMotionPath *mpath);
+/**
+ * Setup motion paths for the given data.
+ * \note Only used when explicitly calculating paths on bones which may/may not be consider already
+ *
+ * \param scene: Current scene (for frame ranges, etc.)
+ * \param ob: Object to add paths for (must be provided)
+ * \param pchan: Posechannel to add paths for (optional; if not provided, object-paths are assumed)
+ */
struct bMotionPath *animviz_verify_motionpaths(struct ReportList *reports,
struct Scene *scene,
struct Object *ob,
diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h
index 07da9d75e59..6197cb93c95 100644
--- a/source/blender/blenkernel/BKE_animsys.h
+++ b/source/blender/blenkernel/BKE_animsys.h
@@ -69,12 +69,17 @@ AnimationEvalContext BKE_animsys_eval_context_construct_at(
/* ************************************* */
/* KeyingSets API */
-/* Used to create a new 'custom' KeyingSet for the user,
- * that will be automatically added to the stack */
+/**
+ * Used to create a new 'custom' KeyingSet for the user,
+ * that will be automatically added to the stack.
+ */
struct KeyingSet *BKE_keyingset_add(
struct ListBase *list, const char idname[], const char name[], short flag, short keyingflag);
-/* Add a path to a KeyingSet */
+/**
+ * Add a path to a KeyingSet. Nothing is returned for now.
+ * Checks are performed to ensure that destination is appropriate for the KeyingSet in question
+ */
struct KS_Path *BKE_keyingset_add_path(struct KeyingSet *ks,
struct ID *id,
const char group_name[],
@@ -83,7 +88,10 @@ struct KS_Path *BKE_keyingset_add_path(struct KeyingSet *ks,
short flag,
short groupmode);
-/* Find the destination matching the criteria given */
+/**
+ * Find the destination matching the criteria given.
+ * TODO: do we want some method to perform partial matches too?
+ */
struct KS_Path *BKE_keyingset_find_path(struct KeyingSet *ks,
struct ID *id,
const char group_name[],
@@ -208,11 +216,32 @@ void BKE_fcurves_id_cb(struct ID *id, ID_FCurve_Edit_Callback func, void *user_d
typedef struct NlaKeyframingContext NlaKeyframingContext;
+/**
+ * Prepare data necessary to compute correct keyframe values for NLA strips
+ * with non-Replace mode or influence different from 1.
+ *
+ * \param cache: List used to cache contexts for reuse when keying
+ * multiple channels in one operation.
+ * \param ptr: RNA pointer to the Object with the animation.
+ * \return Keyframing context, or NULL if not necessary.
+ */
struct NlaKeyframingContext *BKE_animsys_get_nla_keyframing_context(
struct ListBase *cache,
struct PointerRNA *ptr,
struct AnimData *adt,
const struct AnimationEvalContext *anim_eval_context);
+/**
+ * Apply correction from the NLA context to the values about to be keyframed.
+ *
+ * \param context: Context to use (may be NULL).
+ * \param prop_ptr: Property about to be keyframed.
+ * \param[in,out] values: Array of property values to adjust.
+ * \param count: Number of values in the array.
+ * \param index: Index of the element about to be updated, or -1.
+ * \param[out] r_force_all: Set to true if all channels must be inserted. May be NULL.
+ * \return False if correction fails due to a division by zero,
+ * or null r_force_all when all channels are required.
+ */
bool BKE_animsys_nla_remap_keyframe_values(struct NlaKeyframingContext *context,
struct PointerRNA *prop_ptr,
struct PropertyRNA *prop,
@@ -220,6 +249,9 @@ bool BKE_animsys_nla_remap_keyframe_values(struct NlaKeyframingContext *context,
int count,
int index,
bool *r_force_all);
+/**
+ * Free all cached contexts from the list.
+ */
void BKE_animsys_free_nla_keyframing_context_cache(struct ListBase *cache);
/* ************************************* */
@@ -240,16 +272,32 @@ bool BKE_animsys_rna_path_resolve(struct PointerRNA *ptr,
const int array_index,
struct PathResolvedRNA *r_result);
bool BKE_animsys_read_from_rna_path(struct PathResolvedRNA *anim_rna, float *r_value);
+/**
+ * Write the given value to a setting using RNA, and return success.
+ */
bool BKE_animsys_write_to_rna_path(struct PathResolvedRNA *anim_rna, const float value);
-/* Evaluation loop for evaluating animation data. */
+/**
+ * Evaluation loop for evaluation animation data
+ *
+ * This assumes that the animation-data provided belongs to the ID block in question,
+ * and that the flags for which parts of the animation-data settings need to be recalculated
+ * have been set already by the depsgraph. Now, we use the recalculate.
+ */
void BKE_animsys_evaluate_animdata(struct ID *id,
struct AnimData *adt,
const struct AnimationEvalContext *anim_eval_context,
eAnimData_Recalc recalc,
const bool flush_to_original);
-/* Evaluation of all ID-blocks with Animation Data blocks - Animation Data Only */
+/**
+ * Evaluation of all ID-blocks with Animation Data blocks - Animation Data Only
+ *
+ * This will evaluate only the animation info available in the animation data-blocks
+ * encountered. In order to enforce the system by which some settings controlled by a
+ * 'local' (i.e. belonging in the nearest ID-block that setting is related to, not a
+ * standard 'root') block are overridden by a larger 'user'
+ */
void BKE_animsys_evaluate_all_animation(struct Main *main,
struct Depsgraph *depsgraph,
float ctime);
diff --git a/source/blender/blenkernel/BKE_appdir.h b/source/blender/blenkernel/BKE_appdir.h
index 65485058dd7..dd589282bdd 100644
--- a/source/blender/blenkernel/BKE_appdir.h
+++ b/source/blender/blenkernel/BKE_appdir.h
@@ -17,6 +17,9 @@
/** \file
* \ingroup bke
+ *
+ * \note on naming: typical _get() suffix is omitted here,
+ * since its the main purpose of the API.
*/
#include <stddef.h>
@@ -29,54 +32,139 @@ extern "C" {
struct ListBase;
+/**
+ * Sanity check to ensure correct API use in debug mode.
+ *
+ * Run this once the first level of arguments has been passed so we can be sure
+ * `--env-system-datafiles`, and other `--env-*` arguments has been passed.
+ *
+ * Without this any callers to this module that run early on,
+ * will miss out on changes from parsing arguments.
+ */
void BKE_appdir_init(void);
void BKE_appdir_exit(void);
-/* note on naming: typical _get() suffix is omitted here,
- * since its the main purpose of the API. */
+/**
+ * Get the folder that's the "natural" starting point for browsing files on an OS.
+ * - Unix: `$HOME`
+ * - Windows: `%userprofile%/Documents`
+ *
+ * \note On Windows `Users/{MyUserName}/Documents` is used as it's the default location to save
+ * documents.
+ */
const char *BKE_appdir_folder_default(void) ATTR_WARN_UNUSED_RESULT;
const char *BKE_appdir_folder_root(void) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL;
const char *BKE_appdir_folder_default_or_root(void) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL;
+/**
+ * Get the user's home directory, i.e.
+ * - Unix: `$HOME`
+ * - Windows: `%userprofile%`
+ */
const char *BKE_appdir_folder_home(void);
+/**
+ * Get the user's document directory, i.e.
+ * - Linux: `$HOME/Documents`
+ * - Windows: `%userprofile%/Documents`
+ *
+ * If this can't be found using OS queries (via Ghost), try manually finding it.
+ *
+ * \returns True if the path is valid and points to an existing directory.
+ */
bool BKE_appdir_folder_documents(char *dir);
+/**
+ * Get the user's cache directory, i.e.
+ * - Linux: `$HOME/.cache/blender/`
+ * - Windows: `%USERPROFILE%\AppData\Local\Blender Foundation\Blender\`
+ * - MacOS: `/Library/Caches/Blender`
+ *
+ * \returns True if the path is valid. It doesn't create or checks format
+ * if the `blender` folder exists. It does check if the parent of the path exists.
+ */
bool BKE_appdir_folder_caches(char *r_path, size_t path_len);
+/**
+ * Get a folder out of the \a folder_id presets for paths.
+ *
+ * \param subfolder: The name of a directory to check for,
+ * this may contain path separators but must resolve to a directory, checked with #BLI_is_dir.
+ * \return The path if found, NULL string if not.
+ */
bool BKE_appdir_folder_id_ex(const int folder_id,
const char *subfolder,
char *path,
size_t path_len);
const char *BKE_appdir_folder_id(const int folder_id, const char *subfolder);
+/**
+ * Returns the path to a folder in the user area, creating it if it doesn't exist.
+ */
const char *BKE_appdir_folder_id_create(const int folder_id, const char *subfolder);
+/**
+ * Returns the path to a folder in the user area without checking that it actually exists first.
+ */
const char *BKE_appdir_folder_id_user_notest(const int folder_id, const char *subfolder);
+/**
+ * Returns the path of the top-level version-specific local, user or system directory.
+ * If check_is_dir, then the result will be NULL if the directory doesn't exist.
+ */
const char *BKE_appdir_folder_id_version(const int folder_id,
const int version,
const bool check_is_dir);
+/**
+ * Check if this is an install with user files kept together
+ * with the Blender executable and its installation files.
+ */
bool BKE_appdir_app_is_portable_install(void);
+/**
+ * Return true if templates exist
+ */
bool BKE_appdir_app_template_any(void);
bool BKE_appdir_app_template_id_search(const char *app_template, char *path, size_t path_len);
bool BKE_appdir_app_template_has_userpref(const char *app_template);
void BKE_appdir_app_templates(struct ListBase *templates);
-/* Initialize path to program executable */
+/**
+ * Initialize path to program executable.
+ */
void BKE_appdir_program_path_init(const char *argv0);
+/**
+ * Path to executable
+ */
const char *BKE_appdir_program_path(void);
+/**
+ * Path to directory of executable
+ */
const char *BKE_appdir_program_dir(void);
-/* Return OS fonts directory. */
+/**
+ * Gets a good default directory for fonts.
+ */
bool BKE_appdir_font_folder_default(char *dir);
-/* find python executable */
+/**
+ * Find Python executable.
+ */
bool BKE_appdir_program_python_search(char *fullpath,
const size_t fullpath_len,
const int version_major,
const int version_minor);
-/* Initialize path to temporary directory. */
+/**
+ * Initialize path to temporary directory.
+ */
void BKE_tempdir_init(const char *userdir);
+/**
+ * Path to persistent temporary directory (with trailing slash)
+ */
const char *BKE_tempdir_base(void);
+/**
+ * Path to temporary directory (with trailing slash)
+ */
const char *BKE_tempdir_session(void);
+/**
+ * Delete content of this instance's temp dir.
+ */
void BKE_tempdir_session_purge(void);
/* folder_id */
diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h
index e13475fd78c..fcba7d9d365 100644
--- a/source/blender/blenkernel/BKE_armature.h
+++ b/source/blender/blenkernel/BKE_armature.h
@@ -166,8 +166,20 @@ struct BoundBox *BKE_armature_boundbox_get(struct Object *ob);
bool BKE_pose_minmax(
struct Object *ob, float r_min[3], float r_max[3], bool use_hidden, bool use_select);
+/**
+ * Finds the best possible extension to the name on a particular axis.
+ * (For renaming, check for unique names afterwards)
+ * \param strip_number: removes number extensions (TODO: not used).
+ * \param axis: The axis to name on.
+ * \param head: The head co-ordinate of the bone on the specified axis.
+ * \param tail: The tail co-ordinate of the bone on the specified axis.
+ */
bool bone_autoside_name(char name[64], int strip_number, short axis, float head, float tail);
+/**
+ * Walk the list until the bone is found (slow!),
+ * use #BKE_armature_bone_from_name_map for multiple lookups.
+ */
struct Bone *BKE_armature_find_bone_name(struct bArmature *arm, const char *name);
void BKE_armature_bone_hash_make(struct bArmature *arm);
@@ -177,40 +189,87 @@ bool BKE_armature_bone_flag_test_recursive(const struct Bone *bone, int flag);
void BKE_armature_refresh_layer_used(struct Depsgraph *depsgraph, struct bArmature *arm);
+/**
+ * Using `vec` with dist to bone `b1 - b2`.
+ */
float distfactor_to_bone(
const float vec[3], const float b1[3], const float b2[3], float rad1, float rad2, float rdist);
+/**
+ * Updates vectors and matrices on rest-position level, only needed
+ * after editing armature itself, now only on reading file.
+ */
void BKE_armature_where_is(struct bArmature *arm);
+/**
+ * Recursive part, calculates rest-position of entire tree of children.
+ * \note Used when exiting edit-mode too.
+ */
void BKE_armature_where_is_bone(struct Bone *bone,
const struct Bone *bone_parent,
const bool use_recursion);
+/**
+ * Clear pointers of object's pose
+ * (needed in remap case, since we cannot always wait for a complete pose rebuild).
+ */
void BKE_pose_clear_pointers(struct bPose *pose);
void BKE_pose_remap_bone_pointers(struct bArmature *armature, struct bPose *pose);
+/**
+ * Update the links for the B-Bone handles from Bone data.
+ */
void BKE_pchan_rebuild_bbone_handles(struct bPose *pose, struct bPoseChannel *pchan);
void BKE_pose_channels_clear_with_null_bone(struct bPose *pose, const bool do_id_user);
+/**
+ * Only after leave edit-mode, duplicating, validating older files, library syncing.
+ *
+ * \note pose->flag is set for it.
+ *
+ * \param bmain: May be NULL, only used to tag depsgraph as being dirty.
+ */
void BKE_pose_rebuild(struct Main *bmain,
struct Object *ob,
struct bArmature *arm,
const bool do_id_user);
+/**
+ * Ensures object's pose is rebuilt if needed.
+ *
+ * \param bmain: May be NULL, only used to tag depsgraph as being dirty.
+ */
void BKE_pose_ensure(struct Main *bmain,
struct Object *ob,
struct bArmature *arm,
const bool do_id_user);
+/**
+ * \note This is the only function adding poses.
+ * \note This only reads anim data from channels, and writes to channels.
+ */
void BKE_pose_where_is(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob);
+/**
+ * The main armature solver, does all constraints excluding IK.
+ *
+ * \param pchan: pose-channel - validated, as having bone and parent pointer.
+ * \param do_extra: when zero skips loc/size/rot, constraints and strip modifiers.
+ */
void BKE_pose_where_is_bone(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
struct bPoseChannel *pchan,
float ctime,
bool do_extra);
+/**
+ * Calculate tail of pose-channel.
+ */
void BKE_pose_where_is_bone_tail(struct bPoseChannel *pchan);
-/* Evaluate the action and apply it to the pose. If any pose bones are selected, only FCurves that
- * relate to those bones are evaluated. */
+/**
+ * Evaluate the action and apply it to the pose. If any pose bones are selected, only FCurves that
+ * relate to those bones are evaluated.
+ */
void BKE_pose_apply_action_selected_bones(struct Object *ob,
struct bAction *action,
struct AnimationEvalContext *anim_eval_context);
-/* Evaluate the action and apply it to the pose. Ignore selection state of the bones. */
+/**
+ * Evaluate the action and apply it to the pose. Ignore selection state of the bones.
+ */
void BKE_pose_apply_action_all_bones(struct Object *ob,
struct bAction *action,
struct AnimationEvalContext *anim_eval_context);
@@ -221,24 +280,63 @@ void BKE_pose_apply_action_blend(struct Object *ob,
float blend_factor);
void vec_roll_to_mat3(const float vec[3], const float roll, float r_mat[3][3]);
+
+/**
+ * Calculates the rest matrix of a bone based on its vector and a roll around that vector.
+ */
void vec_roll_to_mat3_normalized(const float nor[3], const float roll, float r_mat[3][3]);
+/**
+ * Computes vector and roll based on a rotation.
+ * "mat" must contain only a rotation, and no scaling.
+ */
void mat3_to_vec_roll(const float mat[3][3], float r_vec[3], float *r_roll);
+/**
+ * Computes roll around the vector that best approximates the matrix.
+ * If `vec` is the Y vector from purely rotational `mat`, result should be exact.
+ */
void mat3_vec_to_roll(const float mat[3][3], const float vec[3], float *r_roll);
/* Common Conversions Between Co-ordinate Spaces */
+
+/**
+ * Convert World-Space Matrix to Pose-Space Matrix.
+ */
void BKE_armature_mat_world_to_pose(struct Object *ob,
const float inmat[4][4],
float outmat[4][4]);
+/**
+ * Convert World-Space Location to Pose-Space Location
+ * \note this cannot be used to convert to pose-space location of the supplied
+ * pose-channel into its local space (i.e. 'visual'-keyframing).
+ */
void BKE_armature_loc_world_to_pose(struct Object *ob, const float inloc[3], float outloc[3]);
+/**
+ * Convert Pose-Space Matrix to Bone-Space Matrix.
+ * \note this cannot be used to convert to pose-space transforms of the supplied
+ * pose-channel into its local space (i.e. 'visual'-keyframing).
+ */
void BKE_armature_mat_pose_to_bone(struct bPoseChannel *pchan,
const float inmat[4][4],
float outmat[4][4]);
+/**
+ * Convert Pose-Space Location to Bone-Space Location
+ * \note this cannot be used to convert to pose-space location of the supplied
+ * pose-channel into its local space (i.e. 'visual'-keyframing).
+ */
void BKE_armature_loc_pose_to_bone(struct bPoseChannel *pchan,
const float inloc[3],
float outloc[3]);
+/**
+ * Convert Bone-Space Matrix to Pose-Space Matrix.
+ */
void BKE_armature_mat_bone_to_pose(struct bPoseChannel *pchan,
const float inmat[4][4],
float outmat[4][4]);
+/**
+ * Remove rest-position effects from pose-transform for obtaining
+ * 'visual' transformation of pose-channel.
+ * (used by the Visual-Keyframing stuff).
+ */
void BKE_armature_mat_pose_to_delta(float delta_mat[4][4],
float pose_mat[4][4],
float arm_mat[4][4]);
@@ -249,13 +347,34 @@ void BKE_armature_mat_pose_to_bone_ex(struct Depsgraph *depsgraph,
const float inmat[4][4],
float outmat[4][4]);
+/**
+ * Same as #BKE_object_mat3_to_rot().
+ */
void BKE_pchan_mat3_to_rot(struct bPoseChannel *pchan, const float mat[3][3], bool use_compat);
+/**
+ * Same as #BKE_object_rot_to_mat3().
+ */
void BKE_pchan_rot_to_mat3(const struct bPoseChannel *pchan, float r_mat[3][3]);
+/**
+ * Apply a 4x4 matrix to the pose bone,
+ * similar to #BKE_object_apply_mat4().
+ */
void BKE_pchan_apply_mat4(struct bPoseChannel *pchan, const float mat[4][4], bool use_compat);
+/**
+ * Convert the loc/rot/size to \a r_chanmat (typically #bPoseChannel.chan_mat).
+ */
void BKE_pchan_to_mat4(const struct bPoseChannel *pchan, float r_chanmat[4][4]);
+
+/**
+ * Convert the loc/rot/size to mat4 (`pchan.chan_mat`),
+ * used in `constraint.c` too.
+ */
void BKE_pchan_calc_mat(struct bPoseChannel *pchan);
-/* Simple helper, computes the offset bone matrix. */
+/**
+ * Simple helper, computes the offset bone matrix:
+ * `offs_bone = yoffs(b-1) + root(b) + bonemat(b)`.
+ */
void BKE_bone_offset_matrix_get(const struct Bone *bone, float offs_bone[4][4]);
/* Transformation inherited from the parent bone. These matrices apply the effects of
@@ -277,9 +396,38 @@ void BKE_bone_parent_transform_apply(const struct BoneParentTransform *bpt,
const float inmat[4][4],
float outmat[4][4]);
-/* Get the current parent transformation for the given pose bone. */
+/**
+ * Get the current parent transformation for the given pose bone.
+ *
+ * Construct the matrices (rot/scale and loc)
+ * to apply the PoseChannels into the armature (object) space.
+ * I.e. (roughly) the `pose_mat(b-1) * yoffs(b-1) * d_root(b) * bone_mat(b)` in the
+ * `pose_mat(b)= pose_mat(b-1) * yoffs(b-1) * d_root(b) * bone_mat(b) * chan_mat(b)`
+ * ...function.
+ *
+ * This allows to get the transformations of a bone in its object space,
+ * *before* constraints (and IK) get applied (used by pose evaluation code).
+ * And reverse: to find pchan transformations needed to place a bone at a given loc/rot/scale
+ * in object space (used by interactive transform, and snapping code).
+ *
+ * Note that, with the HINGE/NO_SCALE/NO_LOCAL_LOCATION options, the location matrix
+ * will differ from the rotation/scale matrix...
+ *
+ * \note This cannot be used to convert to pose-space transforms of the supplied
+ * pose-channel into its local space (i.e. 'visual'-keyframing).
+ * (NOTE(@mont29): I don't understand that, so I keep it :p).
+ */
void BKE_bone_parent_transform_calc_from_pchan(const struct bPoseChannel *pchan,
struct BoneParentTransform *r_bpt);
+/**
+ * Compute the parent transform using data decoupled from specific data structures.
+ *
+ * \param bone_flag: #Bone.flag containing settings.
+ * \param offs_bone: delta from parent to current arm_mat (or just arm_mat if no parent).
+ * \param parent_arm_mat: arm_mat of parent, or NULL.
+ * \param parent_pose_mat: pose_mat of parent, or NULL.
+ * \param r_bpt: OUTPUT parent transform.
+ */
void BKE_bone_parent_transform_calc_from_matrices(int bone_flag,
int inherit_scale_mode,
const float offs_bone[4][4],
@@ -287,7 +435,13 @@ void BKE_bone_parent_transform_calc_from_matrices(int bone_flag,
const float parent_pose_mat[4][4],
struct BoneParentTransform *r_bpt);
-/* Rotation Mode Conversions - Used for PoseChannels + Objects... */
+/**
+ * Rotation Mode Conversions - Used for Pose-Channels + Objects.
+ *
+ * Called from RNA when rotation mode changes
+ * - the result should be that the rotations given in the provided pointers have had conversions
+ * applied (as appropriate), such that the rotation of the element hasn't 'visually' changed.
+ */
void BKE_rotMode_change_values(
float quat[4], float eul[3], float axis[3], float *angle, short oldMode, short newMode);
@@ -320,18 +474,31 @@ typedef struct BBoneSplineParameters {
float curve_in_x, curve_in_z, curve_out_x, curve_out_z;
} BBoneSplineParameters;
+/**
+ * Get "next" and "prev" bones - these are used for handle calculations.
+ */
void BKE_pchan_bbone_handles_get(struct bPoseChannel *pchan,
struct bPoseChannel **r_prev,
struct bPoseChannel **r_next);
+/**
+ * Compute B-Bone spline parameters for the given channel.
+ */
void BKE_pchan_bbone_spline_params_get(struct bPoseChannel *pchan,
const bool rest,
struct BBoneSplineParameters *r_param);
+/**
+ * Fills the array with the desired amount of bone->segments elements.
+ * This calculation is done within unit bone space.
+ */
void BKE_pchan_bbone_spline_setup(struct bPoseChannel *pchan,
const bool rest,
const bool for_deform,
Mat4 *result_array);
+/**
+ * Computes the bezier handle vectors and rolls coming from custom handles.
+ */
void BKE_pchan_bbone_handles_compute(const BBoneSplineParameters *param,
float h1[3],
float *r_roll1,
@@ -339,14 +506,28 @@ void BKE_pchan_bbone_handles_compute(const BBoneSplineParameters *param,
float *r_roll2,
bool ease,
bool offsets);
+/**
+ * Fills the array with the desired amount of `bone->segments` elements.
+ * This calculation is done within unit bone space.
+ */
int BKE_pchan_bbone_spline_compute(struct BBoneSplineParameters *param,
const bool for_deform,
Mat4 *result_array);
+/**
+ * Compute and cache the B-Bone shape in the channel runtime struct.
+ */
void BKE_pchan_bbone_segments_cache_compute(struct bPoseChannel *pchan);
+/**
+ * Copy cached B-Bone segments from one channel to another.
+ */
void BKE_pchan_bbone_segments_cache_copy(struct bPoseChannel *pchan,
struct bPoseChannel *pchan_from);
+/**
+ * Calculate index and blend factor for the two B-Bone segment nodes
+ * affecting the point at 0 <= pos <= 1.
+ */
void BKE_pchan_bbone_deform_segment_index(const struct bPoseChannel *pchan,
float pos,
int *r_index,
diff --git a/source/blender/blenkernel/BKE_asset.h b/source/blender/blenkernel/BKE_asset.h
index 722d142b56c..58c50fb736f 100644
--- a/source/blender/blenkernel/BKE_asset.h
+++ b/source/blender/blenkernel/BKE_asset.h
@@ -57,6 +57,9 @@ struct AssetTagEnsureResult {
};
struct AssetTag *BKE_asset_metadata_tag_add(struct AssetMetaData *asset_data, const char *name);
+/**
+ * Make sure there is a tag with name \a name, create one if needed.
+ */
struct AssetTagEnsureResult BKE_asset_metadata_tag_ensure(struct AssetMetaData *asset_data,
const char *name);
void BKE_asset_metadata_tag_remove(struct AssetMetaData *asset_data, struct AssetTag *tag);
diff --git a/source/blender/blenkernel/BKE_asset_catalog.hh b/source/blender/blenkernel/BKE_asset_catalog.hh
index 3478eebbeb4..ecc839050b7 100644
--- a/source/blender/blenkernel/BKE_asset_catalog.hh
+++ b/source/blender/blenkernel/BKE_asset_catalog.hh
@@ -98,6 +98,15 @@ class AssetCatalogService {
bool write_to_disk(const CatalogFilePath &blend_file_path);
/**
+ * Ensure that the next call to #on_blend_save_post() will choose a new location for the CDF
+ * suitable for the location of the blend file (regardless of where the current catalogs come
+ * from), and that catalogs will be merged with already-existing ones in that location.
+ *
+ * Use this for a "Save as..." that has to write the catalogs to the new blend file location,
+ * instead of updating the previously read CDF. */
+ void prepare_to_merge_on_write();
+
+ /**
* Merge on-disk changes into the in-memory asset catalogs.
* This should be called before writing the asset catalogs to disk.
*
@@ -238,6 +247,11 @@ class AssetCatalogService {
*/
void create_missing_catalogs();
+ /**
+ * For every catalog, mark it as "dirty".
+ */
+ void tag_all_catalogs_as_unsaved_changes();
+
/* For access by subclasses, as those will not be marked as friend by #AssetCatalogCollection. */
AssetCatalogDefinitionFile *get_catalog_definition_file();
OwningAssetCatalogMap &get_catalogs();
@@ -363,6 +377,9 @@ class AssetCatalogDefinitionFile {
/* For now this is the only version of the catalog definition files that is supported.
* Later versioning code may be added to handle older files. */
const static int SUPPORTED_VERSION;
+ /* String that's matched in the catalog definition file to know that the line is the version
+ * declaration. It has to start with a space to ensure it won't match any hypothetical future
+ * field that starts with "VERSION". */
const static std::string VERSION_MARKER;
const static std::string HEADER;
diff --git a/source/blender/blenkernel/BKE_attribute_access.hh b/source/blender/blenkernel/BKE_attribute_access.hh
index 47f62b52a0f..fd30813a506 100644
--- a/source/blender/blenkernel/BKE_attribute_access.hh
+++ b/source/blender/blenkernel/BKE_attribute_access.hh
@@ -155,6 +155,10 @@ using fn::GVMutableArray;
const CPPType *custom_data_type_to_cpp_type(const CustomDataType type);
CustomDataType cpp_type_to_custom_data_type(const CPPType &type);
CustomDataType attribute_data_type_highest_complexity(Span<CustomDataType> data_types);
+/**
+ * Domains with a higher "information density" have a higher priority,
+ * in order to choose a domain that will not lose data through domain conversion.
+ */
AttributeDomain attribute_domain_highest_priority(Span<AttributeDomain> domains);
/**
@@ -345,8 +349,15 @@ class CustomDataAttributes {
void reallocate(const int size);
+ void clear();
+
std::optional<blender::fn::GSpan> get_for_read(const AttributeIDRef &attribute_id) const;
+ /**
+ * Return a virtual array for a stored attribute, or a single value virtual array with the
+ * default value if the attribute doesn't exist. If no default value is provided, the default
+ * value for the type will be used.
+ */
blender::fn::GVArray get_for_read(const AttributeIDRef &attribute_id,
const CustomDataType data_type,
const void *default_value) const;
@@ -514,19 +525,3 @@ template<typename T> inline MutableSpan<T> OutputAttribute::as_span()
/** \} */
} // namespace blender::bke
-
-/* -------------------------------------------------------------------- */
-/** \name External Template Instantiations
- *
- * Defined in `intern/extern_implementations.cc`.
- * \{ */
-
-namespace blender::bke {
-extern template class OutputAttribute_Typed<float>;
-extern template class OutputAttribute_Typed<int>;
-extern template class OutputAttribute_Typed<float3>;
-extern template class OutputAttribute_Typed<bool>;
-extern template class OutputAttribute_Typed<ColorGeometry4f>;
-} // namespace blender::bke
-
-/** \} */
diff --git a/source/blender/blenkernel/BKE_autoexec.h b/source/blender/blenkernel/BKE_autoexec.h
index 84d83ae5d30..55bb3e8877f 100644
--- a/source/blender/blenkernel/BKE_autoexec.h
+++ b/source/blender/blenkernel/BKE_autoexec.h
@@ -23,6 +23,10 @@
extern "C" {
#endif
+/**
+ * \param path: The path to check against.
+ * \return Success
+ */
bool BKE_autoexec_match(const char *path);
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h
index 813472715fa..8c0512edb1d 100644
--- a/source/blender/blenkernel/BKE_blender.h
+++ b/source/blender/blenkernel/BKE_blender.h
@@ -29,6 +29,9 @@ extern "C" {
struct UserDef;
+/**
+ * Only to be called on exit Blender.
+ */
void BKE_blender_free(void);
void BKE_blender_globals_init(void);
@@ -38,11 +41,19 @@ void BKE_blender_userdef_data_swap(struct UserDef *userdef_a, struct UserDef *us
void BKE_blender_userdef_data_set(struct UserDef *userdef);
void BKE_blender_userdef_data_set_and_free(struct UserDef *userdef);
+/**
+ * Write U from userdef.
+ * This function defines which settings a template will override for the user preferences.
+ */
void BKE_blender_userdef_app_template_data_swap(struct UserDef *userdef_a,
struct UserDef *userdef_b);
void BKE_blender_userdef_app_template_data_set(struct UserDef *userdef);
void BKE_blender_userdef_app_template_data_set_and_free(struct UserDef *userdef);
+/**
+ * When loading a new userdef from file,
+ * or when exiting Blender.
+ */
void BKE_blender_userdef_data_free(struct UserDef *userdef, bool clear_fonts);
/* Blenders' own atexit (avoids leaking) */
diff --git a/source/blender/blenkernel/BKE_blender_copybuffer.h b/source/blender/blenkernel/BKE_blender_copybuffer.h
index 4dd7145e66d..abfb37ef959 100644
--- a/source/blender/blenkernel/BKE_blender_copybuffer.h
+++ b/source/blender/blenkernel/BKE_blender_copybuffer.h
@@ -30,16 +30,54 @@ struct Main;
struct ReportList;
struct bContext;
-/* copybuffer (wrapper for BKE_blendfile_write_partial) */
+/* Copy-buffer (wrapper for BKE_blendfile_write_partial). */
+
+/**
+ * Initialize a copy operation.
+ */
void BKE_copybuffer_copy_begin(struct Main *bmain_src);
+/**
+ * Mark an ID to be copied. Should only be called after a call to #BKE_copybuffer_copy_begin.
+ */
void BKE_copybuffer_copy_tag_ID(struct ID *id);
+/**
+ * Finalize a copy operation into given .blend file 'buffer'.
+ *
+ * \param filename: Full path to the .blend file used as copy/paste buffer.
+ *
+ * \return true on success, false otherwise.
+ */
bool BKE_copybuffer_copy_end(struct Main *bmain_src,
const char *filename,
struct ReportList *reports);
+/**
+ * Paste data-blocks from the given .blend file 'buffer' (i.e. append them).
+ *
+ * Unlike #BKE_copybuffer_paste, it does not perform any instantiation of collections/objects/etc.
+ *
+ * \param libname: Full path to the .blend file used as copy/paste buffer.
+ * \param id_types_mask: Only directly link IDs of those types from the given .blend file buffer.
+ *
+ * \return true on success, false otherwise.
+ */
bool BKE_copybuffer_read(struct Main *bmain_dst,
const char *libname,
struct ReportList *reports,
const uint64_t id_types_mask);
+/**
+ * Paste data-blocks from the given .blend file 'buffer' (i.e. append them).
+ *
+ * Similar to #BKE_copybuffer_read, but also handles instantiation of collections/objects/etc.
+ *
+ * \param libname: Full path to the .blend file used as copy/paste buffer.
+ * \param flag: A combination of #eBLOLibLinkFlags and ##eFileSel_Params_Flag to control
+ * link/append behavior.
+ * \note Ignores #FILE_LINK flag, since it always appends IDs.
+ * \param id_types_mask: Only directly link IDs of those types from the given .blend file buffer.
+ *
+ * \return Number of IDs directly pasted from the buffer
+ * (does not includes indirectly linked ones).
+ */
int BKE_copybuffer_paste(struct bContext *C,
const char *libname,
const int flag,
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 966d6c95421..d0ab8be9a29 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -39,7 +39,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
-#define BLENDER_FILE_SUBVERSION 3
+#define BLENDER_FILE_SUBVERSION 5
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and show a warning if the file
diff --git a/source/blender/blenkernel/BKE_blendfile.h b/source/blender/blenkernel/BKE_blendfile.h
index 3e0a343a766..b3211b1dbbc 100644
--- a/source/blender/blenkernel/BKE_blendfile.h
+++ b/source/blender/blenkernel/BKE_blendfile.h
@@ -33,6 +33,14 @@ struct ReportList;
struct UserDef;
struct bContext;
+/**
+ * Shared setup function that makes the data from `bfd` into the current blend file,
+ * replacing the contents of #G.main.
+ * This uses the bfd #BKE_blendfile_read and similarly named functions.
+ *
+ * This is done in a separate step so the caller may perform actions after it is known the file
+ * loaded correctly but before the file replaces the existing blend file contents.
+ */
void BKE_blendfile_read_setup_ex(struct bContext *C,
struct BlendFileData *bfd,
const struct BlendFileReadParams *params,
@@ -46,28 +54,56 @@ void BKE_blendfile_read_setup(struct bContext *C,
const struct BlendFileReadParams *params,
struct BlendFileReadReport *reports);
+/**
+ * \return Blend file data, this must be passed to #BKE_blendfile_read_setup when non-NULL.
+ */
struct BlendFileData *BKE_blendfile_read(const char *filepath,
const struct BlendFileReadParams *params,
struct BlendFileReadReport *reports);
+/**
+ * \return Blend file data, this must be passed to #BKE_blendfile_read_setup when non-NULL.
+ */
struct BlendFileData *BKE_blendfile_read_from_memory(const void *filebuf,
int filelength,
const struct BlendFileReadParams *params,
struct ReportList *reports);
+/**
+ * \return Blend file data, this must be passed to #BKE_blendfile_read_setup when non-NULL.
+ * \note `memfile` is the undo buffer.
+ */
struct BlendFileData *BKE_blendfile_read_from_memfile(struct Main *bmain,
struct MemFile *memfile,
const struct BlendFileReadParams *params,
struct ReportList *reports);
+/**
+ * Utility to make a file 'empty' used for startup to optionally give an empty file.
+ * Handy for tests.
+ */
void BKE_blendfile_read_make_empty(struct bContext *C);
+/**
+ * Only read the #UserDef from a .blend.
+ */
struct UserDef *BKE_blendfile_userdef_read(const char *filepath, struct ReportList *reports);
struct UserDef *BKE_blendfile_userdef_read_from_memory(const void *filebuf,
int filelength,
struct ReportList *reports);
struct UserDef *BKE_blendfile_userdef_from_defaults(void);
+/**
+ * Only write the #UserDef in a `.blend`.
+ * \return success.
+ */
bool BKE_blendfile_userdef_write(const char *filepath, struct ReportList *reports);
+/**
+ * Only write the #UserDef in a `.blend`, merging with the existing blend file.
+ * \return success.
+ *
+ * \note In the future we should re-evaluate user preferences,
+ * possibly splitting out system/hardware specific preferences.
+ */
bool BKE_blendfile_userdef_write_app_template(const char *filepath, struct ReportList *reports);
bool BKE_blendfile_userdef_write_all(struct ReportList *reports);
@@ -81,9 +117,14 @@ bool BKE_blendfile_workspace_config_write(struct Main *bmain,
struct ReportList *reports);
void BKE_blendfile_workspace_config_data_free(struct WorkspaceConfigFileData *workspace_config);
-/* partial blend file writing */
+/* Partial blend file writing. */
+
void BKE_blendfile_write_partial_tag_ID(struct ID *id, bool set);
void BKE_blendfile_write_partial_begin(struct Main *bmain_src);
+/**
+ * \param remap_mode: Choose the kind of path remapping or none #eBLO_WritePathRemap.
+ * \return Success.
+ */
bool BKE_blendfile_write_partial(struct Main *bmain_src,
const char *filepath,
const int write_flags,
diff --git a/source/blender/blenkernel/BKE_blendfile_link_append.h b/source/blender/blenkernel/BKE_blendfile_link_append.h
new file mode 100644
index 00000000000..aaa31352316
--- /dev/null
+++ b/source/blender/blenkernel/BKE_blendfile_link_append.h
@@ -0,0 +1,222 @@
+/*
+ * 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.
+ */
+#pragma once
+
+/** \file
+ * \ingroup bke
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct BlendHandle;
+struct ID;
+struct Library;
+struct LibraryLink_Params;
+struct Main;
+struct ReportList;
+struct Scene;
+struct ViewLayer;
+struct View3D;
+
+typedef struct BlendfileLinkAppendContext BlendfileLinkAppendContext;
+typedef struct BlendfileLinkAppendContextItem BlendfileLinkAppendContextItem;
+
+/**
+ * Allocate and initialize a new context to link/append data-blocks.
+ */
+BlendfileLinkAppendContext *BKE_blendfile_link_append_context_new(
+ struct LibraryLink_Params *params);
+/**
+ * Free a link/append context.
+ */
+void BKE_blendfile_link_append_context_free(struct BlendfileLinkAppendContext *lapp_context);
+/**
+ * Set or clear flags in given \a lapp_context.
+ *
+ * \param flag: A combination of:
+ * - #eFileSel_Params_Flag from `DNA_space_types.h` &
+ * - #eBLOLibLinkFlags * from `BLO_readfile.h`.
+ * \param do_set: Set the given \a flag if true, clear it otherwise.
+ */
+void BKE_blendfile_link_append_context_flag_set(struct BlendfileLinkAppendContext *lapp_context,
+ const int flag,
+ const bool do_set);
+
+/**
+ * Store reference to a Blender's embedded memfile into the context.
+ *
+ * \note This is required since embedded startup blender file is handled in `ED` module, which
+ * cannot be linked in BKE code.
+ */
+void BKE_blendfile_link_append_context_embedded_blendfile_set(
+ struct BlendfileLinkAppendContext *lapp_context,
+ const void *blendfile_mem,
+ int blendfile_memsize);
+/** Clear reference to Blender's embedded startup file into the context. */
+void BKE_blendfile_link_append_context_embedded_blendfile_clear(
+ struct BlendfileLinkAppendContext *lapp_context);
+
+/**
+ * Add a new source library to search for items to be linked to the given link/append context.
+ *
+ * \param libname: the absolute path to the library blend file.
+ * \param blo_handle: the blend file handle of the library, NULL is not available. Note that this
+ * is only borrowed for linking purpose, no releasing or other management will
+ * be performed by #BKE_blendfile_link_append code on it.
+ *
+ * \note *Never* call #BKE_blendfile_link_append_context_library_add()
+ * after having added some items.
+ */
+void BKE_blendfile_link_append_context_library_add(struct BlendfileLinkAppendContext *lapp_context,
+ const char *libname,
+ struct BlendHandle *blo_handle);
+/**
+ * Add a new item (data-block name and `idcode`) to be searched and linked/appended from libraries
+ * associated to the given context.
+ *
+ * \param userdata: an opaque user-data pointer stored in generated link/append item.
+ *
+ * TODO: Add a more friendly version of this that combines it with the call to
+ * #BKE_blendfile_link_append_context_item_library_index_enable to enable the added item for all
+ * added library sources.
+ */
+struct BlendfileLinkAppendContextItem *BKE_blendfile_link_append_context_item_add(
+ struct BlendfileLinkAppendContext *lapp_context,
+ const char *idname,
+ const short idcode,
+ void *userdata);
+
+#define BLENDFILE_LINK_APPEND_INVALID -1
+/**
+ * Search for all ID matching given `id_types_filter` in given `library_index`, and add them to
+ * the list of items to process.
+ *
+ * \note #BKE_blendfile_link_append_context_library_add should never be called on the same
+ *`lapp_context` after this function.
+ *
+ * \param id_types_filter: A set of `FILTER_ID` bitflags, the types of IDs to add to the items
+ * list.
+ * \param library_index: The index of the library to look into, in given `lapp_context`.
+ *
+ * \return The number of items found and added to the list, or `BLENDFILE_LINK_APPEND_INVALID` if
+ * it could not open the .blend file.
+ */
+int BKE_blendfile_link_append_context_item_idtypes_from_library_add(
+ struct BlendfileLinkAppendContext *lapp_context,
+ struct ReportList *reports,
+ const uint64_t id_types_filter,
+ const int library_index);
+
+/**
+ * Enable search of the given \a item into the library stored at given index in the link/append
+ * context.
+ */
+void BKE_blendfile_link_append_context_item_library_index_enable(
+ struct BlendfileLinkAppendContext *lapp_context,
+ struct BlendfileLinkAppendContextItem *item,
+ const int library_index);
+/**
+ * Check if given link/append context is empty (has no items to process) or not.
+ */
+bool BKE_blendfile_link_append_context_is_empty(struct BlendfileLinkAppendContext *lapp_context);
+
+void *BKE_blendfile_link_append_context_item_userdata_get(
+ struct BlendfileLinkAppendContext *lapp_context, struct BlendfileLinkAppendContextItem *item);
+struct ID *BKE_blendfile_link_append_context_item_newid_get(
+ struct BlendfileLinkAppendContext *lapp_context, struct BlendfileLinkAppendContextItem *item);
+short BKE_blendfile_link_append_context_item_idcode_get(
+ struct BlendfileLinkAppendContext *lapp_context, struct BlendfileLinkAppendContextItem *item);
+
+typedef enum eBlendfileLinkAppendForeachItemFlag {
+ /** Loop over directly linked items (i.e. those explicitly defined by user code). */
+ BKE_BLENDFILE_LINK_APPEND_FOREACH_ITEM_FLAG_DO_DIRECT = 1 << 0,
+ /** Loop over indirectly linked items (i.e. those defined by internal code, as dependencies of
+ * direct ones).
+ *
+ * IMPORTANT: Those 'indirect' items currently may not cover **all** indirectly linked data.
+ * See comments in #foreach_libblock_link_append_callback. */
+ BKE_BLENDFILE_LINK_APPEND_FOREACH_ITEM_FLAG_DO_INDIRECT = 1 << 0,
+} eBlendfileLinkAppendForeachItemFlag;
+/**
+ * Callback called by #BKE_blendfile_link_append_context_item_foreach over each (or a subset of
+ * each) of the items in given #BlendfileLinkAppendContext.
+ *
+ * \param userdata: An opaque void pointer passed to the `callback_function`.
+ *
+ * \return `true` if iteration should continue, `false` otherwise.
+ */
+typedef bool (*BKE_BlendfileLinkAppendContexteItemFunction)(
+ struct BlendfileLinkAppendContext *lapp_context,
+ struct BlendfileLinkAppendContextItem *item,
+ void *userdata);
+/**
+ * Iterate over all (or a subset) of the items listed in given #BlendfileLinkAppendContext,
+ * and call the `callback_function` on them.
+ *
+ * \param flag: Control which type of items to process (see
+ * #eBlendfileLinkAppendForeachItemFlag enum flags).
+ * \param userdata: An opaque void pointer passed to the `callback_function`.
+ */
+void BKE_blendfile_link_append_context_item_foreach(
+ struct BlendfileLinkAppendContext *lapp_context,
+ BKE_BlendfileLinkAppendContexteItemFunction callback_function,
+ const eBlendfileLinkAppendForeachItemFlag flag,
+ void *userdata);
+
+/**
+ * Perform append operation, using modern ID usage looper to detect which ID should be kept
+ * linked, made local, duplicated as local, re-used from local etc.
+ *
+ * The IDs processed by this functions are the one that have been linked by a previous call to
+ * #BKE_blendfile_link on the same `lapp_context`.
+ */
+void BKE_blendfile_append(struct BlendfileLinkAppendContext *lapp_context,
+ struct ReportList *reports);
+/**
+ * Perform linking operation on all items added to given `lapp_context`.
+ */
+void BKE_blendfile_link(struct BlendfileLinkAppendContext *lapp_context,
+ struct ReportList *reports);
+
+/**
+ * Try to relocate all linked IDs added to `lapp_context`, belonging to the given `library`.
+ *
+ * This function searches for matching IDs (type and name) in all libraries added to the given
+ * `lapp_context`.
+ *
+ * Typical usages include:
+ * - Relocating a library:
+ * - Add the new target library path to `lapp_context`.
+ * - Add all IDs from the library to relocate to `lapp_context`
+ * - Mark the new target library to be considered for each ID.
+ * - Call this function.
+ *
+ * - Searching for (e.g.missing) linked IDs in a set or sub-set of libraries:
+ * - Add all potential library sources paths to `lapp_context`.
+ * - Add all IDs to search for to `lapp_context`.
+ * - Mark which libraries should be considered for each ID.
+ * - Call this function.
+ */
+void BKE_blendfile_library_relocate(struct BlendfileLinkAppendContext *lapp_context,
+ struct ReportList *reports,
+ struct Library *library,
+ const bool do_reload);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/blenkernel/BKE_boids.h b/source/blender/blenkernel/BKE_boids.h
index 71a4d35767f..a9c8ad6422f 100644
--- a/source/blender/blenkernel/BKE_boids.h
+++ b/source/blender/blenkernel/BKE_boids.h
@@ -51,7 +51,13 @@ typedef struct BoidBrainData {
} BoidBrainData;
void boids_precalc_rules(struct ParticleSettings *part, float cfra);
+/**
+ * Determines the velocity the boid wants to have.
+ */
void boid_brain(BoidBrainData *bbd, int p, struct ParticleData *pa);
+/**
+ * Tries to realize the wanted velocity taking all constraints into account.
+ */
void boid_body(BoidBrainData *bbd, struct ParticleData *pa);
void boid_default_settings(struct BoidSettings *boids);
struct BoidRule *boid_new_rule(int type);
diff --git a/source/blender/blenkernel/BKE_bpath.h b/source/blender/blenkernel/BKE_bpath.h
index 3ec5409ca7f..bae151f6a72 100644
--- a/source/blender/blenkernel/BKE_bpath.h
+++ b/source/blender/blenkernel/BKE_bpath.h
@@ -16,10 +16,14 @@
/** \file
* \ingroup bke
- * \attention Based on ghash, difference is ghash is not a fixed size,
- * so for BPath we don't need to malloc
+ *
+ * \warning All paths manipulated by this API are assumed to be either constant char buffers of
+ * `FILE_MAX` size, or allocated char buffers not bigger than `FILE_MAX`.
*/
+/* TODO: Make this module handle a bit more safely string length, instead of assuming buffers are
+ * FILE_MAX length etc. */
+
#pragma once
#ifdef __cplusplus
@@ -31,66 +35,181 @@ struct ListBase;
struct Main;
struct ReportList;
-/* Function that does something with an ID's file path. Should return 1 if the
- * path has changed, and in that case, should write the result to pathOut. */
-typedef bool (*BPathVisitor)(void *userdata, char *path_dst, const char *path_src);
-/* Executes 'visit' for each path associated with 'id'. */
-void BKE_bpath_traverse_id(struct Main *bmain,
- struct ID *id,
- BPathVisitor visit_cb,
- const int flag,
- void *bpath_user_data);
-void BKE_bpath_traverse_id_list(struct Main *bmain,
- struct ListBase *lb,
- BPathVisitor visit_cb,
- const int flag,
- void *bpath_user_data);
-void BKE_bpath_traverse_main(struct Main *bmain,
- BPathVisitor visit_cb,
- const int flag,
- void *bpath_user_data);
-bool BKE_bpath_relocate_visitor(void *oldbasepath, char *path_dst, const char *path_src);
-
-/* Functions for temp backup/restore of paths, path count must NOT change */
-void *BKE_bpath_list_backup(struct Main *bmain, const int flag);
-void BKE_bpath_list_restore(struct Main *bmain, const int flag, void *ls_handle);
-void BKE_bpath_list_free(void *ls_handle);
-
-enum {
- /* convert paths to absolute */
- BKE_BPATH_TRAVERSE_ABS = (1 << 0),
- /* skip library paths */
- BKE_BPATH_TRAVERSE_SKIP_LIBRARY = (1 << 1),
- /* skip packed data */
- BKE_BPATH_TRAVERSE_SKIP_PACKED = (1 << 2),
- /* skip paths where a single dir is used with an array of files, eg.
- * sequence strip images and pointcache. in this case only use the first
- * file, this is needed for directory manipulation functions which might
- * otherwise modify the same directory multiple times */
- BKE_BPATH_TRAVERSE_SKIP_MULTIFILE = (1 << 3),
- /* reload data (when the path is edited) */
- BKE_BPATH_TRAVERSE_RELOAD_EDITED = (1 << 4),
-};
-
-/* high level funcs */
-
-/* creates a text file with missing files if there are any */
+/** \name Core `foreach_path` API.
+ * \{ */
+
+typedef enum eBPathForeachFlag {
+ /** Flags controlling the behavior of the generic BPath API. */
+
+ /** Ensures the `absolute_base_path` member of #BPathForeachPathData is initialized properly with
+ * the path of the current .blend file. This can be used by the callbacks to convert relative
+ * paths to absolute ones. */
+ BKE_BPATH_FOREACH_PATH_ABSOLUTE = (1 << 0),
+ /** Skip paths of linked IDs. */
+ BKE_BPATH_FOREACH_PATH_SKIP_LINKED = (1 << 1),
+ /** Skip paths when their matching data is packed. */
+ BKE_BPATH_FOREACH_PATH_SKIP_PACKED = (1 << 2),
+ /* Skip weak reference paths. Those paths are typically 'nice to have' extra information, but are
+ * not used as actual source of data by the current .blend file.
+ *
+ * NOTE: Currently this only concerns the weak reference to a library file stored in
+ * `ID::library_weak_reference`. */
+ BKE_BPATH_TRAVERSE_SKIP_WEAK_REFERENCES = (1 << 5),
+
+ /** Flags not affecting the generic BPath API. Those may be used by specific IDTypeInfo
+ * `foreach_path` implementations and/or callbacks to implement specific behaviors. */
+
+ /** Skip paths where a single dir is used with an array of files, eg. sequence strip images or
+ * point-caches. In this case only use the first file path is processed.
+ *
+ * This is needed for directory manipulation callbacks which might otherwise modify the same
+ * directory multiple times. */
+ BKE_BPATH_FOREACH_PATH_SKIP_MULTIFILE = (1 << 8),
+ /** Reload data (when the path is edited).
+ * \note Only used by Image IDType currently. */
+ BKE_BPATH_FOREACH_PATH_RELOAD_EDITED = (1 << 9),
+} eBPathForeachFlag;
+
+struct BPathForeachPathData;
+
+/** Callback used to iterate over an ID's file paths.
+ *
+ * \note `path`s parameters should be considered as having a maximal `FILE_MAX` string length.
+ *
+ * \return `true` if the path has been changed, and in that case, result should be written into
+ * `r_path_dst`. */
+typedef bool (*BPathForeachPathFunctionCallback)(struct BPathForeachPathData *bpath_data,
+ char *r_path_dst,
+ const char *path_src);
+
+/** Storage for common data needed across the BPath 'foreach_path' code. */
+typedef struct BPathForeachPathData {
+ struct Main *bmain;
+
+ BPathForeachPathFunctionCallback callback_function;
+ eBPathForeachFlag flag;
+
+ void *user_data;
+
+ /* 'Private' data, caller don't need to set those. */
+
+ /** The root to use as base for relative paths. Only set if `BKE_BPATH_FOREACH_PATH_ABSOLUTE`
+ * flag is set, NULL otherwise. */
+ const char *absolute_base_path;
+} BPathForeachPathData;
+
+/** Run `bpath_data.callback_function` on all paths contained in `id`. */
+void BKE_bpath_foreach_path_id(BPathForeachPathData *bpath_data, struct ID *id);
+
+/** Run `bpath_data.callback_function` on all paths of all IDs in `bmain`. */
+void BKE_bpath_foreach_path_main(BPathForeachPathData *bpath_data);
+
+/** \} */
+
+/** \name Helpers to handle common cases from `IDTypeInfo`'s `foreach_path` functions.
+ * \{ */
+
+/* TODO: Investigate using macros around those calls to check a bit better about actual
+ * strings/buffers length (e,g, with static asserts). */
+
+/**
+ * Run the callback on a path, replacing the content of the string as needed.
+ *
+ * \param path: A fixed, FILE_MAX-sized char buffer.
+ *
+ * \return true is \a path was modified, false otherwise.
+ */
+bool BKE_bpath_foreach_path_fixed_process(struct BPathForeachPathData *bpath_data, char *path);
+
+/**
+ * Run the callback on a (directory + file) path, replacing the content of the two strings as
+ * needed.
+ *
+ * \param path_dir: A fixed, FILE_MAXDIR-sized char buffer.
+ * \param path_file: A fixed, FILE_MAXFILE-sized char buffer.
+ *
+ * \return true is \a path_dir and/or \a path_file were modified, false otherwise.
+ */
+bool BKE_bpath_foreach_path_dirfile_fixed_process(struct BPathForeachPathData *bpath_data,
+ char *path_dir,
+ char *path_file);
+
+/**
+ * Run the callback on a path, replacing the content of the string as needed.
+ *
+ * \param path: A pointer to a MEM-allocated string. If modified, it will be freed and replaced by
+ * a new allocated string.
+ * \note path is expected to be FILE_MAX size or smaller.
+ *
+ * \return true is \a path was modified and re-allocated, false otherwise.
+ */
+bool BKE_bpath_foreach_path_allocated_process(struct BPathForeachPathData *bpath_data,
+ char **path);
+
+/** \} */
+
+/** \name High level features.
+ * \{ */
+
+/** Check for missing files. */
void BKE_bpath_missing_files_check(struct Main *bmain, struct ReportList *reports);
+
+/** Recursively search into given search directory, for all file paths of all IDs in given \a
+ * bmain, and replace existing paths as needed.
+ *
+ * \note The search will happen into the whole search directory tree recursively (with a limit of
+ * MAX_DIR_RECURSE), if several files are found matching a searched filename, the biggest one will
+ * be used. This is so that things like thumbnails don't get selected instead of the actual image
+ * e.g.
+ *
+ * \param searchpath: The root directory in which the new filepaths should be searched for.
+ * \param find_all: If `true`, also search for files which current path is still valid, if `false`
+ * skip those still valid paths.
+ * */
void BKE_bpath_missing_files_find(struct Main *bmain,
const char *searchpath,
struct ReportList *reports,
const bool find_all);
+
+/** Rebase all relative file paths in given \a bmain from \a basedir_src to \a basedir_dst. */
void BKE_bpath_relative_rebase(struct Main *bmain,
const char *basedir_src,
const char *basedir_dst,
struct ReportList *reports);
+
+/** Make all absolute file paths in given \a bmain relative to given \a basedir. */
void BKE_bpath_relative_convert(struct Main *bmain,
const char *basedir,
struct ReportList *reports);
+
+/** Make all relative file paths in given \a bmain absolute, using given \a basedir as root. */
void BKE_bpath_absolute_convert(struct Main *bmain,
const char *basedir,
struct ReportList *reports);
+/** Temp backup of paths from all IDs in given \a bmain.
+ *
+ * \return An opaque handle to pass to #BKE_bpath_list_restore and #BKE_bpath_list_free.
+ */
+void *BKE_bpath_list_backup(struct Main *bmain, const eBPathForeachFlag flag);
+
+/** Restore the temp backup of paths from \a path_list_handle into all IDs in given \a bmain.
+ *
+ * \note This function assumes that the data in given Main did not change (no
+ * addition/deletion/re-ordering of IDs, or their file paths) since the call to
+ * #BKE_bpath_list_backup that generated the given \a path_list_handle. */
+void BKE_bpath_list_restore(struct Main *bmain,
+ const eBPathForeachFlag flag,
+ void *path_list_handle);
+
+/** Free the temp backup of paths in \a path_list_handle.
+ *
+ * \note This function assumes that the path list has already been restored with a call to
+ * #BKE_bpath_list_restore, and is therefore empty. */
+void BKE_bpath_list_free(void *path_list_handle);
+
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h
index 452a08bc9c8..a0f3733588a 100644
--- a/source/blender/blenkernel/BKE_brush.h
+++ b/source/blender/blenkernel/BKE_brush.h
@@ -39,49 +39,93 @@ struct UnifiedPaintSettings;
// enum eCurveMappingPreset;
-/* globals for brush execution */
+/* Globals for brush execution. */
+
void BKE_brush_system_init(void);
void BKE_brush_system_exit(void);
-/* datablock functions */
+/* Data-block functions. */
+
+/**
+ * \note Resulting brush will have two users: one as a fake user,
+ * another is assumed to be used by the caller.
+ */
struct Brush *BKE_brush_add(struct Main *bmain, const char *name, const eObjectMode ob_mode);
+/**
+ * Add a new gp-brush.
+ */
struct Brush *BKE_brush_add_gpencil(struct Main *bmain,
struct ToolSettings *ts,
const char *name,
eObjectMode mode);
+/**
+ * Delete a Brush.
+ */
bool BKE_brush_delete(struct Main *bmain, struct Brush *brush);
+/**
+ * Add grease pencil settings.
+ */
void BKE_brush_init_gpencil_settings(struct Brush *brush);
struct Brush *BKE_brush_first_search(struct Main *bmain, const eObjectMode ob_mode);
void BKE_brush_sculpt_reset(struct Brush *brush);
+/**
+ * Create a set of grease pencil Drawing presets.
+ */
void BKE_brush_gpencil_paint_presets(struct Main *bmain,
struct ToolSettings *ts,
const bool reset);
+/**
+ * Create a set of grease pencil Vertex Paint presets.
+ */
void BKE_brush_gpencil_vertex_presets(struct Main *bmain,
struct ToolSettings *ts,
const bool reset);
+/**
+ * Create a set of grease pencil Sculpt Paint presets.
+ */
void BKE_brush_gpencil_sculpt_presets(struct Main *bmain,
struct ToolSettings *ts,
const bool reset);
+/**
+ * Create a set of grease pencil Weight Paint presets.
+ */
void BKE_brush_gpencil_weight_presets(struct Main *bmain,
struct ToolSettings *ts,
const bool reset);
void BKE_gpencil_brush_preset_set(struct Main *bmain, struct Brush *brush, const short type);
-/* jitter */
void BKE_brush_jitter_pos(const struct Scene *scene,
struct Brush *brush,
const float pos[2],
float jitterpos[2]);
void BKE_brush_randomize_texture_coords(struct UnifiedPaintSettings *ups, bool mask);
-/* brush curve */
+/* Brush curve. */
+
+/**
+ * Library Operations
+ */
void BKE_brush_curve_preset(struct Brush *b, enum eCurveMappingPreset preset);
-float BKE_brush_curve_strength_clamped(struct Brush *br, float p, const float len);
+/**
+ * Uses the brush curve control to find a strength value between 0 and 1.
+ */
+float BKE_brush_curve_strength_clamped(const struct Brush *br, float p, const float len);
+/**
+ * Uses the brush curve control to find a strength value.
+ */
float BKE_brush_curve_strength(const struct Brush *br, float p, const float len);
-/* sampling */
+/* Sampling. */
+
+/**
+ * Generic texture sampler for 3D painting systems.
+ * point has to be either in region space mouse coordinates,
+ * or 3d world coordinates for 3D mapping.
+ *
+ * RGBA outputs straight alpha.
+ */
float BKE_brush_sample_tex_3d(const struct Scene *scene,
const struct Brush *br,
const float point[3],
@@ -94,15 +138,18 @@ float BKE_brush_sample_masktex(const struct Scene *scene,
const int thread,
struct ImagePool *pool);
-/* texture */
+/* Texture. */
+
unsigned int *BKE_brush_gen_texture_cache(struct Brush *br, int half_side, bool use_secondary);
-/* radial control */
+/**
+ * Radial control.
+ */
struct ImBuf *BKE_brush_gen_radial_control_imbuf(struct Brush *br,
bool secondary,
bool display_gradient);
-/* unified strength size and color */
+/* Unified strength size and color. */
const float *BKE_brush_color_get(const struct Scene *scene, const struct Brush *brush);
const float *BKE_brush_secondary_color_get(const struct Scene *scene, const struct Brush *brush);
@@ -127,12 +174,16 @@ bool BKE_brush_use_size_pressure(const struct Brush *brush);
bool BKE_brush_sculpt_has_secondary_color(const struct Brush *brush);
-/* scale unprojected radius to reflect a change in the brush's 2D size */
+/**
+ * Scale unprojected radius to reflect a change in the brush's 2D size.
+ */
void BKE_brush_scale_unprojected_radius(float *unprojected_radius,
int new_brush_size,
int old_brush_size);
-/* scale brush size to reflect a change in the brush's unprojected radius */
+/**
+ * Scale brush size to reflect a change in the brush's unprojected radius.
+ */
void BKE_brush_scale_size(int *r_brush_size,
float new_unprojected_radius,
float old_unprojected_radius);
diff --git a/source/blender/blenkernel/BKE_bvhutils.h b/source/blender/blenkernel/BKE_bvhutils.h
index bb95985ef4c..45c3a8ec159 100644
--- a/source/blender/blenkernel/BKE_bvhutils.h
+++ b/source/blender/blenkernel/BKE_bvhutils.h
@@ -48,7 +48,7 @@ struct BVHCache;
typedef struct BVHTreeFromEditMesh {
struct BVHTree *tree;
- /** Default callbacks to bvh nearest and ray-cast. */
+ /** Default callbacks to BVH nearest and ray-cast. */
BVHTree_NearestPointCallback nearest_callback;
BVHTree_RayCastCallback raycast_callback;
@@ -65,7 +65,7 @@ typedef struct BVHTreeFromEditMesh {
typedef struct BVHTreeFromMesh {
struct BVHTree *tree;
- /** Default callbacks to bvh nearest and ray-cast. */
+ /** Default callbacks to BVH nearest and ray-cast. */
BVHTree_NearestPointCallback nearest_callback;
BVHTree_RayCastCallback raycast_callback;
@@ -105,7 +105,7 @@ typedef enum BVHCacheType {
} BVHCacheType;
/**
- * Builds a bvh tree where nodes are the relevant elements of the given mesh.
+ * Builds a BVH tree where nodes are the relevant elements of the given mesh.
* Configures #BVHTreeFromMesh.
*
* The tree is build in mesh space coordinates, this means special care must be made on queries
@@ -113,11 +113,14 @@ typedef enum BVHCacheType {
* Reason for this is that bvh_from_mesh_* can use a cache in some cases and so it
* becomes possible to reuse a #BVHTree.
*
- * free_bvhtree_from_mesh should be called when the tree is no longer needed.
+ * #free_bvhtree_from_mesh should be called when the tree is no longer needed.
*/
BVHTree *bvhtree_from_editmesh_verts(
BVHTreeFromEditMesh *data, struct BMEditMesh *em, float epsilon, int tree_type, int axis);
+/**
+ * Builds a BVH-tree where nodes are the vertices of the given `em`.
+ */
BVHTree *bvhtree_from_editmesh_verts_ex(BVHTreeFromEditMesh *data,
struct BMEditMesh *em,
const BLI_bitmap *mask,
@@ -129,11 +132,18 @@ BVHTree *bvhtree_from_editmesh_verts_ex(BVHTreeFromEditMesh *data,
struct BVHCache **bvh_cache_p,
ThreadMutex *mesh_eval_mutex);
+/**
+ * Builds a BVH-tree where nodes are the given vertices (NOTE: does not copy given `vert`!).
+ * \param vert_allocated: if true, vert freeing will be done when freeing data.
+ * \param verts_mask: if not null, true elements give which vert to add to BVH-tree.
+ * \param verts_num_active: if >= 0, number of active verts to add to BVH-tree
+ * (else will be computed from mask).
+ */
BVHTree *bvhtree_from_mesh_verts_ex(struct BVHTreeFromMesh *data,
const struct MVert *vert,
const int verts_num,
const bool vert_allocated,
- const BLI_bitmap *mask,
+ const BLI_bitmap *verts_mask,
int verts_num_active,
float epsilon,
int tree_type,
@@ -145,6 +155,9 @@ BVHTree *bvhtree_from_mesh_verts_ex(struct BVHTreeFromMesh *data,
BVHTree *bvhtree_from_editmesh_edges(
BVHTreeFromEditMesh *data, struct BMEditMesh *em, float epsilon, int tree_type, int axis);
+/**
+ * Builds a BVH-tree where nodes are the edges of the given `em`.
+ */
BVHTree *bvhtree_from_editmesh_edges_ex(BVHTreeFromEditMesh *data,
struct BMEditMesh *em,
const BLI_bitmap *edges_mask,
@@ -156,6 +169,14 @@ BVHTree *bvhtree_from_editmesh_edges_ex(BVHTreeFromEditMesh *data,
struct BVHCache **bvh_cache_p,
ThreadMutex *mesh_eval_mutex);
+/**
+ * Builds a BVH-tree where nodes are the given edges.
+ * \param vert, vert_allocated: if true, elem freeing will be done when freeing data.
+ * \param edge, edge_allocated: if true, elem freeing will be done when freeing data.
+ * \param edges_mask: if not null, true elements give which vert to add to BVH-tree.
+ * \param edges_num_active: if >= 0, number of active edges to add to BVH-tree
+ * (else will be computed from mask).
+ */
BVHTree *bvhtree_from_mesh_edges_ex(struct BVHTreeFromMesh *data,
const struct MVert *vert,
const bool vert_allocated,
@@ -171,13 +192,22 @@ BVHTree *bvhtree_from_mesh_edges_ex(struct BVHTreeFromMesh *data,
struct BVHCache **bvh_cache_p,
ThreadMutex *mesh_eval_mutex);
+/**
+ * Builds a BVH-tree where nodes are the given tessellated faces
+ * (NOTE: does not copy given mfaces!).
+ * \param vert_allocated: if true, vert freeing will be done when freeing data.
+ * \param face_allocated: if true, face freeing will be done when freeing data.
+ * \param faces_mask: if not null, true elements give which faces to add to BVH-tree.
+ * \param faces_num_active: if >= 0, number of active faces to add to BVH-tree
+ * (else will be computed from mask).
+ */
BVHTree *bvhtree_from_mesh_faces_ex(struct BVHTreeFromMesh *data,
const struct MVert *vert,
const bool vert_allocated,
const struct MFace *face,
const int numFaces,
const bool face_allocated,
- const BLI_bitmap *mask,
+ const BLI_bitmap *faces_mask,
int faces_num_active,
float epsilon,
int tree_type,
@@ -189,6 +219,9 @@ BVHTree *bvhtree_from_mesh_faces_ex(struct BVHTreeFromMesh *data,
BVHTree *bvhtree_from_editmesh_looptri(
BVHTreeFromEditMesh *data, struct BMEditMesh *em, float epsilon, int tree_type, int axis);
+/**
+ * Builds a BVH-tree where nodes are the `looptri` faces of the given `bm`.
+ */
BVHTree *bvhtree_from_editmesh_looptri_ex(BVHTreeFromEditMesh *data,
struct BMEditMesh *em,
const BLI_bitmap *mask,
@@ -200,6 +233,11 @@ BVHTree *bvhtree_from_editmesh_looptri_ex(BVHTreeFromEditMesh *data,
struct BVHCache **bvh_cache_p,
ThreadMutex *mesh_eval_mutex);
+/**
+ * Builds a BVH-tree where nodes are the looptri faces of the given mesh.
+ *
+ * \note for edit-mesh this is currently a duplicate of #bvhtree_from_mesh_faces_ex
+ */
BVHTree *bvhtree_from_mesh_looptri_ex(struct BVHTreeFromMesh *data,
const struct MVert *vert,
const bool vert_allocated,
@@ -217,11 +255,20 @@ BVHTree *bvhtree_from_mesh_looptri_ex(struct BVHTreeFromMesh *data,
struct BVHCache **bvh_cache_p,
ThreadMutex *mesh_eval_mutex);
+/**
+ * Builds or queries a BVH-cache for the cache BVH-tree of the request type.
+ *
+ * \note This function only fills a cache, and therefore the mesh argument can
+ * be considered logically const. Concurrent access is protected by a mutex.
+ */
BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
const struct Mesh *mesh,
const BVHCacheType bvh_cache_type,
const int tree_type);
+/**
+ * Builds or queries a BVH-cache for the cache BVH-tree of the request type.
+ */
BVHTree *BKE_bvhtree_from_editmesh_get(BVHTreeFromEditMesh *data,
struct BMEditMesh *em,
const int tree_type,
@@ -230,9 +277,12 @@ BVHTree *BKE_bvhtree_from_editmesh_get(BVHTreeFromEditMesh *data,
ThreadMutex *mesh_eval_mutex);
/**
- * Frees data allocated by a call to bvhtree_from_mesh_*.
+ * Frees data allocated by a call to `bvhtree_from_editmesh_*`.
*/
void free_bvhtree_from_editmesh(struct BVHTreeFromEditMesh *data);
+/**
+ * Frees data allocated by a call to `bvhtree_from_mesh_*`.
+ */
void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data);
/**
@@ -272,6 +322,9 @@ void free_bvhtree_from_pointcloud(struct BVHTreeFromPointCloud *data);
bool bvhcache_has_tree(const struct BVHCache *bvh_cache, const BVHTree *tree);
struct BVHCache *bvhcache_init(void);
+/**
+ * Frees a BVH-cache.
+ */
void bvhcache_free(struct BVHCache *bvh_cache);
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_cachefile.h b/source/blender/blenkernel/BKE_cachefile.h
index 836597f95da..ac621bfdcb9 100644
--- a/source/blender/blenkernel/BKE_cachefile.h
+++ b/source/blender/blenkernel/BKE_cachefile.h
@@ -61,6 +61,12 @@ void BKE_cachefile_reader_open(struct CacheFile *cache_file,
const char *object_path);
void BKE_cachefile_reader_free(struct CacheFile *cache_file, struct CacheReader **reader);
+/**
+ * Determine whether the #CacheFile should use a render engine procedural. If so, data is not read
+ * from the file and bounding boxes are used to represent the objects in the Scene.
+ * Render engines will receive the bounding box as a placeholder but can instead
+ * load the data directly if they support it.
+ */
bool BKE_cache_file_uses_render_procedural(const struct CacheFile *cache_file,
struct Scene *scene,
const int dag_eval_mode);
diff --git a/source/blender/blenkernel/BKE_callbacks.h b/source/blender/blenkernel/BKE_callbacks.h
index 7c518f33c89..c125b081b49 100644
--- a/source/blender/blenkernel/BKE_callbacks.h
+++ b/source/blender/blenkernel/BKE_callbacks.h
@@ -133,6 +133,9 @@ void BKE_callback_add(bCallbackFuncStore *funcstore, eCbEvent evt);
void BKE_callback_remove(bCallbackFuncStore *funcstore, eCbEvent evt);
void BKE_callback_global_init(void);
+/**
+ * Call on application exit.
+ */
void BKE_callback_global_finalize(void);
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_camera.h b/source/blender/blenkernel/BKE_camera.h
index b42fcbe7808..45bfef82302 100644
--- a/source/blender/blenkernel/BKE_camera.h
+++ b/source/blender/blenkernel/BKE_camera.h
@@ -37,22 +37,26 @@ struct Scene;
struct View3D;
struct rctf;
-/* Camera Datablock */
+/* Camera Data-block */
void *BKE_camera_add(struct Main *bmain, const char *name);
/* Camera Usage */
+/**
+ * Get the camera's DOF value, takes the DOF object into account.
+ */
float BKE_camera_object_dof_distance(struct Object *ob);
int BKE_camera_sensor_fit(int sensor_fit, float sizex, float sizey);
float BKE_camera_sensor_size(int sensor_fit, float sensor_x, float sensor_y);
-/* Camera Parameters:
+/**
+ * Camera Parameters:
*
* Intermediate struct for storing camera parameters from various sources,
- * to unify computation of viewplane, window matrix, ... */
-
+ * to unify computation of view-plane, window matrix, ... etc.
+ */
typedef struct CameraParams {
/* lens */
bool is_ortho;
@@ -84,7 +88,7 @@ typedef struct CameraParams {
float winmat[4][4];
} CameraParams;
-/* values for CameraParams.zoom, need to be taken into account for some operations */
+/* Values for CameraParams.zoom, need to be taken into account for some operations. */
#define CAMERA_PARAM_ZOOM_INIT_CAMOB 1.0f
#define CAMERA_PARAM_ZOOM_INIT_PERSP 2.0f
@@ -97,6 +101,9 @@ void BKE_camera_params_from_view3d(CameraParams *params,
void BKE_camera_params_compute_viewplane(
CameraParams *params, int winx, int winy, float aspx, float aspy);
+/**
+ * View-plane is assumed to be already computed.
+ */
void BKE_camera_params_compute_matrix(CameraParams *params);
/* Camera View Frame */
@@ -114,6 +121,11 @@ void BKE_camera_view_frame(const struct Scene *scene,
const struct Camera *camera,
float r_vec[4][3]);
+/**
+ * \param r_scale: only valid/useful for orthographic cameras.
+ *
+ * \note Don't move the camera, just yield the fit location.
+ */
bool BKE_camera_view_frame_fit_to_scene(struct Depsgraph *depsgraph,
const struct Scene *scene,
struct Object *camera_ob,
@@ -128,9 +140,15 @@ bool BKE_camera_view_frame_fit_to_coords(const struct Depsgraph *depsgraph,
/* Camera multi-view API */
+/**
+ * Returns the camera to be used for render.
+ */
struct Object *BKE_camera_multiview_render(const struct Scene *scene,
struct Object *camera,
const char *viewname);
+/**
+ * The view matrix is used by the viewport drawing, it is basically the inverted model matrix.
+ */
void BKE_camera_multiview_view_matrix(const struct RenderData *rd,
const struct Object *camera,
const bool is_left,
@@ -158,6 +176,7 @@ bool BKE_camera_multiview_spherical_stereo(const struct RenderData *rd,
const struct Object *camera);
/* Camera background image API */
+
struct CameraBGImage *BKE_camera_background_image_new(struct Camera *cam);
void BKE_camera_background_image_remove(struct Camera *cam, struct CameraBGImage *bgpic);
void BKE_camera_background_image_clear(struct Camera *cam);
diff --git a/source/blender/blenkernel/BKE_cloth.h b/source/blender/blenkernel/BKE_cloth.h
index dbf285feb92..ee73b926886 100644
--- a/source/blender/blenkernel/BKE_cloth.h
+++ b/source/blender/blenkernel/BKE_cloth.h
@@ -235,7 +235,9 @@ int cloth_bvh_collision(struct Depsgraph *depsgraph,
/* cloth.c */
/* Needed for modifier.c */
+/** Frees all. */
void cloth_free_modifier_extern(struct ClothModifierData *clmd);
+/** Frees all. */
void cloth_free_modifier(struct ClothModifierData *clmd);
void clothModifier_do(struct ClothModifierData *clmd,
struct Depsgraph *depsgraph,
diff --git a/source/blender/blenkernel/BKE_collection.h b/source/blender/blenkernel/BKE_collection.h
index 2c7143be60e..46c1fe0d33d 100644
--- a/source/blender/blenkernel/BKE_collection.h
+++ b/source/blender/blenkernel/BKE_collection.h
@@ -54,20 +54,51 @@ typedef struct CollectionParent {
/* Collections */
+/**
+ * Add a collection to a collection ListBase and synchronize all render layers
+ * The ListBase is NULL when the collection is to be added to the master collection
+ */
struct Collection *BKE_collection_add(struct Main *bmain,
struct Collection *parent,
const char *name);
+/**
+ * Add \a collection_dst to all scene collections that reference object \a ob_src is in.
+ * Used to replace an instance object with a collection (library override operator).
+ *
+ * Logic is very similar to #BKE_collection_object_add_from().
+ */
void BKE_collection_add_from_object(struct Main *bmain,
struct Scene *scene,
const struct Object *ob_src,
struct Collection *collection_dst);
+/**
+ * Add \a collection_dst to all scene collections that reference collection \a collection_src is
+ * in.
+ *
+ * Logic is very similar to #BKE_collection_object_add_from().
+ */
void BKE_collection_add_from_collection(struct Main *bmain,
struct Scene *scene,
struct Collection *collection_src,
struct Collection *collection_dst);
+/**
+ * Free (or release) any data used by this collection (does not free the collection itself).
+ */
void BKE_collection_free_data(struct Collection *collection);
+/**
+ * Remove a collection, optionally removing its child objects or moving
+ * them to parent collections.
+ */
bool BKE_collection_delete(struct Main *bmain, struct Collection *collection, bool hierarchy);
+/**
+ * Make a deep copy (aka duplicate) of the given collection and all of its children, recursively.
+ *
+ * \warning This functions will clear all \a bmain #ID.idnew pointers, unless \a
+ * #LIB_ID_DUPLICATE_IS_SUBPROCESS duplicate option is passed on, in which case caller is
+ * responsible to reconstruct collection dependencies information's
+ * (i.e. call #BKE_main_collection_sync).
+ */
struct Collection *BKE_collection_duplicate(struct Main *bmain,
struct Collection *parent,
struct Collection *collection,
@@ -91,28 +122,60 @@ struct Collection *BKE_collection_object_find(struct Main *bmain,
struct Object *ob);
bool BKE_collection_is_empty(const struct Collection *collection);
+/**
+ * Add object to collection
+ */
bool BKE_collection_object_add(struct Main *bmain,
struct Collection *collection,
struct Object *ob);
+/**
+ * Add \a ob_dst to all scene collections that reference object \a ob_src is in.
+ * Used for copying objects.
+ *
+ * Logic is very similar to #BKE_collection_add_from_object()
+ */
void BKE_collection_object_add_from(struct Main *bmain,
struct Scene *scene,
struct Object *ob_src,
struct Object *ob_dst);
+/**
+ * Remove object from collection.
+ */
bool BKE_collection_object_remove(struct Main *bmain,
struct Collection *collection,
struct Object *object,
const bool free_us);
+/**
+ * Move object from a collection into another
+ *
+ * If source collection is NULL move it from all the existing collections.
+ */
void BKE_collection_object_move(struct Main *bmain,
struct Scene *scene,
struct Collection *collection_dst,
struct Collection *collection_src,
struct Object *ob);
+/**
+ * Remove object from all collections of scene
+ */
bool BKE_scene_collections_object_remove(struct Main *bmain,
struct Scene *scene,
struct Object *object,
const bool free_us);
void BKE_collections_object_remove_nulls(struct Main *bmain);
+/**
+ * Remove all NULL children from parent collections of changed \a collection.
+ * This is used for library remapping, where these pointers have been set to NULL.
+ * Otherwise this should never happen.
+ *
+ * \note caller must ensure #BKE_main_collection_sync_remap() is called afterwards!
+ *
+ * \param parent_collection: The collection owning the pointers that were remapped. May be \a NULL,
+ * in which case whole \a bmain database of collections is checked.
+ * \param child_collection: The collection that was remapped to another pointer. May be \a NULL,
+ * in which case whole \a bmain database of collections is checked.
+ */
void BKE_collections_child_remove_nulls(struct Main *bmain,
struct Collection *parent_collection,
struct Collection *child_collection);
@@ -136,9 +199,24 @@ struct Base *BKE_collection_or_layer_objects(const struct ViewLayer *view_layer,
/* Editing. */
+/**
+ * Return Scene Collection for a given index.
+ *
+ * The index is calculated from top to bottom counting the children before the siblings.
+ */
struct Collection *BKE_collection_from_index(struct Scene *scene, const int index);
+/**
+ * The automatic/fallback name of a new collection.
+ */
void BKE_collection_new_name_get(struct Collection *collection_parent, char *rname);
+/**
+ * The name to show in the interface.
+ */
const char *BKE_collection_ui_name_get(struct Collection *collection);
+/**
+ * Select all the objects in this Collection (and its nested collections) for this ViewLayer.
+ * Return true if any object was selected.
+ */
bool BKE_collection_objects_select(struct ViewLayer *view_layer,
struct Collection *collection,
bool deselect);
@@ -162,13 +240,36 @@ bool BKE_collection_move(struct Main *bmain,
bool relative_after,
struct Collection *collection);
+/**
+ * Find potential cycles in collections.
+ *
+ * \param new_ancestor: the potential new owner of given \a collection,
+ * or the collection to check if the later is NULL.
+ * \param collection: the collection we want to add to \a new_ancestor,
+ * may be NULL if we just want to ensure \a new_ancestor does not already have cycles.
+ * \return true if a cycle is found.
+ */
bool BKE_collection_cycle_find(struct Collection *new_ancestor, struct Collection *collection);
+/**
+ * Find and fix potential cycles in collections.
+ *
+ * \param collection: The collection to check for existing cycles.
+ * \return true if cycles are found and fixed.
+ */
bool BKE_collection_cycles_fix(struct Main *bmain, struct Collection *collection);
bool BKE_collection_has_collection(const struct Collection *parent,
const struct Collection *collection);
+/**
+ * Rebuild parent relationships from child ones, for all children of given \a collection.
+ *
+ * \note Given collection is assumed to already have valid parents.
+ */
void BKE_collection_parent_relations_rebuild(struct Collection *collection);
+/**
+ * Rebuild parent relationships from child ones, for all collections in given \a bmain.
+ */
void BKE_main_collections_parent_relations_rebuild(struct Main *bmain);
/* .blend file I/O */
@@ -224,6 +325,10 @@ typedef void (*BKE_scene_collections_Cb)(struct Collection *ob, void *data);
/* Iteration over collections in scene. */
+/**
+ * Only use this in non-performance critical situations
+ * (it iterates over all scene collections twice)
+ */
void BKE_scene_collections_iterator_begin(struct BLI_Iterator *iter, void *data_in);
void BKE_scene_collections_iterator_next(struct BLI_Iterator *iter);
void BKE_scene_collections_iterator_end(struct BLI_Iterator *iter);
@@ -232,6 +337,13 @@ void BKE_scene_objects_iterator_begin(struct BLI_Iterator *iter, void *data_in);
void BKE_scene_objects_iterator_next(struct BLI_Iterator *iter);
void BKE_scene_objects_iterator_end(struct BLI_Iterator *iter);
+/**
+ * Generate a new #GSet (or extend given `objects_gset` if not NULL) with all objects referenced by
+ * all collections of given `scene`.
+ *
+ * \note This will include objects without a base currently
+ * (because they would belong to excluded collections only e.g.).
+ */
struct GSet *BKE_scene_objects_as_gset(struct Scene *scene, struct GSet *objects_gset);
#define FOREACH_SCENE_COLLECTION_BEGIN(scene, _instance) \
diff --git a/source/blender/blenkernel/BKE_collision.h b/source/blender/blenkernel/BKE_collision.h
index 2c21b7355d6..71929d1797c 100644
--- a/source/blender/blenkernel/BKE_collision.h
+++ b/source/blender/blenkernel/BKE_collision.h
@@ -116,8 +116,11 @@ void bvhtree_update_from_mvert(struct BVHTree *bvhtree,
/////////////////////////////////////////////////
-/* move Collision modifier object inter-frame with step = [0,1]
- * defined in collisions.c */
+/**
+ * Move Collision modifier object inter-frame with step = [0,1]
+ *
+ * \param step: is limited from 0 (frame start position) to 1 (frame end position).
+ */
void collision_move_object(struct CollisionModifierData *collmd,
const float step,
const float prevstep,
@@ -135,6 +138,11 @@ typedef struct CollisionRelation {
struct Object *ob;
} CollisionRelation;
+/**
+ * Create list of collision relations in the collection or entire scene.
+ * This is used by the depsgraph to build relations, as well as faster
+ * lookup of colliders during evaluation.
+ */
struct ListBase *BKE_collision_relations_create(struct Depsgraph *depsgraph,
struct Collection *collection,
unsigned int modifier_type);
@@ -142,6 +150,10 @@ void BKE_collision_relations_free(struct ListBase *relations);
/* Collision object lists for physics simulation evaluation. */
+/**
+ * Create effective list of colliders from relations built beforehand.
+ * Self will be excluded.
+ */
struct Object **BKE_collision_objects_create(struct Depsgraph *depsgraph,
struct Object *self,
struct Collection *collection,
@@ -155,6 +167,10 @@ typedef struct ColliderCache {
struct CollisionModifierData *collmd;
} ColliderCache;
+/**
+ * Create effective list of colliders from relations built beforehand.
+ * Self will be excluded.
+ */
struct ListBase *BKE_collider_cache_create(struct Depsgraph *depsgraph,
struct Object *self,
struct Collection *collection);
diff --git a/source/blender/blenkernel/BKE_colortools.h b/source/blender/blenkernel/BKE_colortools.h
index 109947cece4..17fb48cdd27 100644
--- a/source/blender/blenkernel/BKE_colortools.h
+++ b/source/blender/blenkernel/BKE_colortools.h
@@ -59,40 +59,85 @@ enum {
CURVEMAP_SLOPE_POS_NEG = 2,
};
+/**
+ * Reset the view for current curve.
+ */
void BKE_curvemapping_reset_view(struct CurveMapping *cumap);
void BKE_curvemap_reset(struct CurveMap *cuma, const struct rctf *clipr, int preset, int slope);
+/**
+ * Removes with flag set.
+ */
void BKE_curvemap_remove(struct CurveMap *cuma, const short flag);
+/**
+ * Remove specified point.
+ */
bool BKE_curvemap_remove_point(struct CurveMap *cuma, struct CurveMapPoint *cmp);
struct CurveMapPoint *BKE_curvemap_insert(struct CurveMap *cuma, float x, float y);
+/**
+ * \param type: #eBezTriple_Handle
+ */
void BKE_curvemap_handle_set(struct CurveMap *cuma, int type);
+/**
+ * \note only does current curvemap!.
+ */
void BKE_curvemapping_changed(struct CurveMapping *cumap, const bool rem_doubles);
void BKE_curvemapping_changed_all(struct CurveMapping *cumap);
-/* call before _all_ evaluation functions */
+/**
+ * Call before _all_ evaluation functions.
+ */
void BKE_curvemapping_init(struct CurveMapping *cumap);
-/* keep these (const CurveMap) - to help with thread safety */
-/* single curve, no table check */
+/**
+ * Keep these `const CurveMap` - to help with thread safety.
+ * \note Single curve, no table check.
+ * \note Table should be verified.
+ */
float BKE_curvemap_evaluateF(const struct CurveMapping *cumap,
const struct CurveMap *cuma,
float value);
-/* single curve, with table check */
+/**
+ * Single curve, with table check.
+ * Works with curve 'cur'.
+ */
float BKE_curvemapping_evaluateF(const struct CurveMapping *cumap, int cur, float value);
+/**
+ * Vector case.
+ */
void BKE_curvemapping_evaluate3F(const struct CurveMapping *cumap,
float vecout[3],
const float vecin[3]);
+/**
+ * RGB case, no black/white points, no pre-multiply.
+ */
void BKE_curvemapping_evaluateRGBF(const struct CurveMapping *cumap,
float vecout[3],
const float vecin[3]);
+/**
+ * Byte version of #BKE_curvemapping_evaluateRGBF.
+ */
void BKE_curvemapping_evaluate_premulRGB(const struct CurveMapping *cumap,
unsigned char vecout_byte[3],
const unsigned char vecin_byte[3]);
+/**
+ * Same as #BKE_curvemapping_evaluate_premulRGBF
+ * but black/bwmul are passed as args for the compositor
+ * where they can change per pixel.
+ *
+ * Use in conjunction with #BKE_curvemapping_set_black_white_ex
+ *
+ * \param black: Use instead of cumap->black
+ * \param bwmul: Use instead of cumap->bwmul
+ */
void BKE_curvemapping_evaluate_premulRGBF_ex(const struct CurveMapping *cumap,
float vecout[3],
const float vecin[3],
const float black[3],
const float bwmul[3]);
+/**
+ * RGB with black/white points and pre-multiply. tables are checked.
+ */
void BKE_curvemapping_evaluate_premulRGBF(const struct CurveMapping *cumap,
float vecout[3],
const float vecin[3]);
@@ -100,12 +145,18 @@ bool BKE_curvemapping_RGBA_does_something(const struct CurveMapping *cumap);
void BKE_curvemapping_table_F(const struct CurveMapping *cumap, float **array, int *size);
void BKE_curvemapping_table_RGBA(const struct CurveMapping *cumap, float **array, int *size);
-/* non-const, these modify the curve */
-void BKE_curvemapping_premultiply(struct CurveMapping *cumap, int restore);
+/**
+ * Call when you do images etc, needs restore too. also verifies tables.
+ * non-const (these modify the curve).
+ */
+void BKE_curvemapping_premultiply(struct CurveMapping *cumap, bool restore);
void BKE_curvemapping_blend_write(struct BlendWriter *writer, const struct CurveMapping *cumap);
void BKE_curvemapping_curves_blend_write(struct BlendWriter *writer,
const struct CurveMapping *cumap);
+/**
+ * \note `cumap` itself has been read already.
+ */
void BKE_curvemapping_blend_read(struct BlendDataReader *reader, struct CurveMapping *cumap);
void BKE_histogram_update_sample_line(struct Histogram *hist,
@@ -123,16 +174,20 @@ void BKE_color_managed_display_settings_init(struct ColorManagedDisplaySettings
void BKE_color_managed_display_settings_copy(struct ColorManagedDisplaySettings *new_settings,
const struct ColorManagedDisplaySettings *settings);
-/* Initialize view settings to be best suitable for render type of viewing.
+/**
+ * Initialize view settings to be best suitable for render type of viewing.
* This will use default view transform from the OCIO configuration if none
- * is specified. */
+ * is specified.
+ */
void BKE_color_managed_view_settings_init_render(
struct ColorManagedViewSettings *settings,
const struct ColorManagedDisplaySettings *display_settings,
const char *view_transform);
-/* Initialize view settings which are best suitable for viewing non-render
- * images. For example,s movie clips while tracking. */
+/**
+ * Initialize view settings which are best suitable for viewing non-render images.
+ * For example,s movie clips while tracking.
+ */
void BKE_color_managed_view_settings_init_default(
struct ColorManagedViewSettings *settings,
const struct ColorManagedDisplaySettings *display_settings);
diff --git a/source/blender/blenkernel/BKE_constraint.h b/source/blender/blenkernel/BKE_constraint.h
index 784b395dfa5..1f59efbb0f3 100644
--- a/source/blender/blenkernel/BKE_constraint.h
+++ b/source/blender/blenkernel/BKE_constraint.h
@@ -45,7 +45,7 @@ extern "C" {
typedef struct bConstraintOb {
/** to get evaluated armature. */
struct Depsgraph *depsgraph;
- /** for system time, part of deglobalization, code nicer later with local time (ton) */
+ /** for system time, part of de-globalization, code nicer later with local time (ton) */
struct Scene *scene;
/** if pchan, then armature that it comes from, otherwise constraint owner */
struct Object *ob;
@@ -61,7 +61,7 @@ typedef struct bConstraintOb {
/** type of owner. */
short type;
- /** rotation order for constraint owner (as defined in eEulerRotationOrders in BLI_math.h) */
+ /** rotation order for constraint owner (as defined in #eEulerRotationOrders in BLI_math.h) */
short rotOrder;
} bConstraintOb;
@@ -76,7 +76,7 @@ typedef void (*ConstraintIDFunc)(struct bConstraint *con,
/* ....... */
/**
- * Constraint Type-Info (shorthand in code = cti):
+ * Constraint Type-Info (shorthand in code = `cti`):
* This struct provides function pointers for runtime, so that functions can be
* written more generally (with fewer/no special exceptions for various constraints).
*
@@ -138,49 +138,107 @@ typedef struct bConstraintTypeInfo {
} bConstraintTypeInfo;
/* Function Prototypes for bConstraintTypeInfo's */
+
+/**
+ * This function should always be used to get the appropriate type-info, as it
+ * has checks which prevent segfaults in some weird cases.
+ */
const bConstraintTypeInfo *BKE_constraint_typeinfo_get(struct bConstraint *con);
+/**
+ * This function should be used for getting the appropriate type-info when only
+ * a constraint type is known.
+ */
const bConstraintTypeInfo *BKE_constraint_typeinfo_from_type(int type);
/* ---------------------------------------------------------------------------- */
/* Constraint function prototypes */
+
+/**
+ * Find the first available, non-duplicate name for a given constraint.
+ */
void BKE_constraint_unique_name(struct bConstraint *con, struct ListBase *list);
+/**
+ * Allocate and duplicate a single constraint, outside of any object/pose context.
+ */
struct bConstraint *BKE_constraint_duplicate_ex(struct bConstraint *src,
const int flag,
const bool do_extern);
+/**
+ * Add a copy of the given constraint for the given bone.
+ */
struct bConstraint *BKE_constraint_copy_for_pose(struct Object *ob,
struct bPoseChannel *pchan,
struct bConstraint *src);
+/**
+ * Add a copy of the given constraint for the given object.
+ */
struct bConstraint *BKE_constraint_copy_for_object(struct Object *ob, struct bConstraint *src);
void BKE_constraints_free(struct ListBase *list);
+/**
+ * Free all constraints from a constraint-stack.
+ */
void BKE_constraints_free_ex(struct ListBase *list, bool do_id_user);
void BKE_constraints_copy(struct ListBase *dst, const struct ListBase *src, bool do_extern);
+/**
+ * Duplicate all of the constraints in a constraint stack.
+ */
void BKE_constraints_copy_ex(struct ListBase *dst,
const struct ListBase *src,
const int flag,
bool do_extern);
+/**
+ * Run the given callback on all ID-blocks in list of constraints.
+ */
void BKE_constraints_id_loop(struct ListBase *list, ConstraintIDFunc func, void *userdata);
void BKE_constraint_free_data(struct bConstraint *con);
+/**
+ * Free data of a specific constraint if it has any info.
+ * Be sure to run #BIK_clear_data() when freeing an IK constraint,
+ * unless #DAG_relations_tag_update is called.
+ */
void BKE_constraint_free_data_ex(struct bConstraint *con, bool do_id_user);
bool BKE_constraint_target_uses_bbone(struct bConstraint *con, struct bConstraintTarget *ct);
/* Constraint API function prototypes */
+
+/**
+ * Finds the 'active' constraint in a constraint stack.
+ */
struct bConstraint *BKE_constraints_active_get(struct ListBase *list);
+/**
+ * Set the given constraint as the active one (clearing all the others).
+ */
void BKE_constraints_active_set(ListBase *list, struct bConstraint *con);
struct bConstraint *BKE_constraints_find_name(struct ListBase *list, const char *name);
+/**
+ * Finds the constraint that owns the given target within the object.
+ */
struct bConstraint *BKE_constraint_find_from_target(struct Object *ob,
struct bConstraintTarget *tgt,
struct bPoseChannel **r_pchan);
+/**
+ * Check whether given constraint is not local (i.e. from linked data) when the object is a library
+ * override.
+ *
+ * \param con: May be NULL, in which case we consider it as a non-local constraint case.
+ */
bool BKE_constraint_is_nonlocal_in_liboverride(const struct Object *ob,
const struct bConstraint *con);
+/**
+ * Add new constraint for the given object.
+ */
struct bConstraint *BKE_constraint_add_for_object(struct Object *ob, const char *name, short type);
+/**
+ * Add new constraint for the given bone.
+ */
struct bConstraint *BKE_constraint_add_for_pose(struct Object *ob,
struct bPoseChannel *pchan,
const char *name,
@@ -190,8 +248,14 @@ bool BKE_constraint_remove_ex(ListBase *list,
struct Object *ob,
struct bConstraint *con,
bool clear_dep);
+/**
+ * Remove the specified constraint from the given constraint stack.
+ */
bool BKE_constraint_remove(ListBase *list, struct bConstraint *con);
+/**
+ * Apply the specified constraint in the given constraint stack.
+ */
bool BKE_constraint_apply_for_object(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
@@ -217,17 +281,38 @@ bool BKE_constraint_apply_and_remove_for_pose(struct Depsgraph *depsgraph,
void BKE_constraint_panel_expand(struct bConstraint *con);
/* Constraints + Proxies function prototypes */
+
+/**
+ * Rescue all constraints tagged as being #CONSTRAINT_PROXY_LOCAL
+ * (i.e. added to bone that's proxy-synced in this file).
+ */
void BKE_constraints_proxylocal_extract(struct ListBase *dst, struct ListBase *src);
+/**
+ * Returns if the owner of the constraint is proxy-protected.
+ */
bool BKE_constraints_proxylocked_owner(struct Object *ob, struct bPoseChannel *pchan);
/* Constraint Evaluation function prototypes */
+
+/**
+ * This function MEM_calloc's a #bConstraintOb struct,
+ * that will need to be freed after evaluation.
+ */
struct bConstraintOb *BKE_constraints_make_evalob(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
void *subdata,
short datatype);
+/**
+ * Cleanup after constraint evaluation.
+ */
void BKE_constraints_clear_evalob(struct bConstraintOb *cob);
+/**
+ * This function is responsible for the correct transformations/conversions
+ * of a matrix from one space to another for constraint evaluation.
+ * For now, this is only implemented for objects and pose-channels.
+ */
void BKE_constraint_mat_convertspace(struct Object *ob,
struct bPoseChannel *pchan,
struct bConstraintOb *cob,
@@ -236,6 +321,14 @@ void BKE_constraint_mat_convertspace(struct Object *ob,
short to,
const bool keep_scale);
+/**
+ * This function is a relic from the prior implementations of the constraints system, when all
+ * constraints either had one or no targets. It used to be called during the main constraint
+ * solving loop, but is now only used for the remaining cases for a few constraints.
+ *
+ * None of the actual calculations of the matrices should be done here! Also, this function is
+ * not to be used by any new constraints, particularly any that have multiple targets.
+ */
void BKE_constraint_target_matrix_get(struct Depsgraph *depsgraph,
struct Scene *scene,
struct bConstraint *con,
@@ -244,12 +337,22 @@ void BKE_constraint_target_matrix_get(struct Depsgraph *depsgraph,
void *ownerdata,
float mat[4][4],
float ctime);
+/**
+ * Get the list of targets required for solving a constraint.
+ */
void BKE_constraint_targets_for_solving_get(struct Depsgraph *depsgraph,
struct bConstraint *con,
struct bConstraintOb *ob,
struct ListBase *targets,
float ctime);
void BKE_constraint_custom_object_space_get(float r_mat[4][4], struct bConstraint *con);
+/**
+ * This function is called whenever constraints need to be evaluated. Currently, all
+ * constraints that can be evaluated are every time this gets run.
+ *
+ * #BKE_constraints_make_evalob and #BKE_constraints_clear_evalob should be called before and
+ * after running this function, to sort out cob.
+ */
void BKE_constraints_solve(struct Depsgraph *depsgraph,
struct ListBase *conlist,
struct bConstraintOb *cob,
diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h
index b0705ff411f..ac864c7f82c 100644
--- a/source/blender/blenkernel/BKE_context.h
+++ b/source/blender/blenkernel/BKE_context.h
@@ -247,6 +247,12 @@ PointerRNA CTX_data_pointer_get_type_silent(const bContext *C,
const char *member,
StructRNA *type);
ListBase CTX_data_collection_get(const bContext *C, const char *member);
+/**
+ * \param C: Context.
+ * \param use_store: Use 'C->wm.store'.
+ * \param use_rna: Use Include the properties from 'RNA_Context'.
+ * \param use_all: Don't skip values (currently only "scene").
+ */
ListBase CTX_data_dir_get_ex(const bContext *C,
const bool use_store,
const bool use_rna,
@@ -297,6 +303,13 @@ int ctx_data_list_count(const bContext *C, int (*func)(const bContext *, ListBas
struct Main *CTX_data_main(const bContext *C);
struct Scene *CTX_data_scene(const bContext *C);
+/**
+ * This is tricky. Sometimes the user overrides the render_layer
+ * but not the scene_collection. In this case what to do?
+ *
+ * If the scene_collection is linked to the #ViewLayer we use it.
+ * Otherwise we fallback to the active one of the #ViewLayer.
+ */
struct LayerCollection *CTX_data_layer_collection(const bContext *C);
struct Collection *CTX_data_collection(const bContext *C);
struct ViewLayer *CTX_data_view_layer(const bContext *C);
@@ -367,28 +380,34 @@ struct AssetHandle CTX_wm_asset_handle(const bContext *C, bool *r_is_valid);
bool CTX_wm_interface_locked(const bContext *C);
-/* Gets pointer to the dependency graph.
+/**
+ * Gets pointer to the dependency graph.
* If it doesn't exist yet, it will be allocated.
*
* The result dependency graph is NOT guaranteed to be up-to-date neither from relation nor from
* evaluated data points of view.
*
- * NOTE: Can not be used if access to a fully evaluated datablock is needed. */
+ * \note Can not be used if access to a fully evaluated data-block is needed.
+ */
struct Depsgraph *CTX_data_depsgraph_pointer(const bContext *C);
-/* Get dependency graph which is expected to be fully evaluated.
+/**
+ * Get dependency graph which is expected to be fully evaluated.
*
* In the release builds it is the same as CTX_data_depsgraph_pointer(). In the debug builds extra
* sanity checks are done. Additionally, this provides more semantic meaning to what is exactly
- * expected to happen. */
+ * expected to happen.
+ */
struct Depsgraph *CTX_data_expect_evaluated_depsgraph(const bContext *C);
-/* Gets fully updated and evaluated dependency graph.
+/**
+ * Gets fully updated and evaluated dependency graph.
*
* All the relations and evaluated objects are guaranteed to be up to date.
*
- * NOTE: Will be expensive if there are relations or objects tagged for update.
- * NOTE: If there are pending updates depsgraph hooks will be invoked. */
+ * \note Will be expensive if there are relations or objects tagged for update.
+ * \note If there are pending updates depsgraph hooks will be invoked.
+ */
struct Depsgraph *CTX_data_ensure_evaluated_depsgraph(const bContext *C);
/* Will Return NULL if depsgraph is not allocated yet.
diff --git a/source/blender/blenkernel/BKE_crazyspace.h b/source/blender/blenkernel/BKE_crazyspace.h
index b95be70379f..f5266ed7a10 100644
--- a/source/blender/blenkernel/BKE_crazyspace.h
+++ b/source/blender/blenkernel/BKE_crazyspace.h
@@ -33,6 +33,10 @@ struct Object;
struct Scene;
/* crazyspace.c */
+
+/**
+ * Disable subdivision-surface temporal, get mapped coordinates, and enable it.
+ */
float (*BKE_crazyspace_get_mapped_editverts(struct Depsgraph *depsgraph,
struct Object *obedit))[3];
void BKE_crazyspace_set_quats_editmesh(struct BMEditMesh *em,
@@ -44,6 +48,10 @@ void BKE_crazyspace_set_quats_mesh(struct Mesh *me,
float (*origcos)[3],
float (*mappedcos)[3],
float (*quats)[4]);
+/**
+ * Returns an array of deform matrices for crazy-space correction,
+ * and the number of modifiers left.
+ */
int BKE_crazyspace_get_first_deform_matrices_editbmesh(struct Depsgraph *depsgraph,
struct Scene *,
struct Object *,
diff --git a/source/blender/blenkernel/BKE_cryptomatte.h b/source/blender/blenkernel/BKE_cryptomatte.h
index e98a9b2b1fd..329046ad494 100644
--- a/source/blender/blenkernel/BKE_cryptomatte.h
+++ b/source/blender/blenkernel/BKE_cryptomatte.h
@@ -55,6 +55,9 @@ uint32_t BKE_cryptomatte_asset_hash(struct CryptomatteSession *session,
const char *layer_name,
const struct Object *object);
float BKE_cryptomatte_hash_to_float(uint32_t cryptomatte_hash);
+/**
+ * Find an ID in the given main that matches the given encoded float.
+ */
bool BKE_cryptomatte_find_name(const struct CryptomatteSession *session,
const float encoded_hash,
char *r_name,
diff --git a/source/blender/blenkernel/BKE_cryptomatte.hh b/source/blender/blenkernel/BKE_cryptomatte.hh
index 9e205d01765..08536ecccbd 100644
--- a/source/blender/blenkernel/BKE_cryptomatte.hh
+++ b/source/blender/blenkernel/BKE_cryptomatte.hh
@@ -37,7 +37,8 @@ struct ID;
namespace blender::bke::cryptomatte {
-/* Format to a cryptomatte meta data key.
+/**
+ * Format to a cryptomatte meta data key.
*
* Cryptomatte stores meta data. The keys are formatted containing a hash that
* is generated from its layer name.
@@ -48,7 +49,8 @@ namespace blender::bke::cryptomatte {
std::string BKE_cryptomatte_meta_data_key(const StringRef layer_name,
const StringRefNull key_name);
-/* Extract the cryptomatte layer name from the given `render_pass_name`.
+/**
+ * Extract the cryptomatte layer name from the given `render_pass_name`.
*
* Cryptomatte passes are formatted with a trailing number for storing multiple samples that belong
* to the same cryptomatte layer. This function would remove the trailing numbers to determine the
@@ -59,7 +61,7 @@ std::string BKE_cryptomatte_meta_data_key(const StringRef layer_name,
* A render_pass_name could be 'View Layer.CryptoMaterial02'. The cryptomatte layer would be 'View
* Layer.CryptoMaterial'.
*
- * NOTE: The return type is a sub-string of `render_pass_name` and therefore cannot outlive the
+ * \note The return type is a sub-string of `render_pass_name` and therefore cannot outlive the
* `render_pass_name` internal data.
*/
StringRef BKE_cryptomatte_extract_layer_name(const StringRef render_pass_name);
@@ -72,6 +74,18 @@ struct CryptomatteHash {
static CryptomatteHash from_hex_encoded(blender::StringRef hex_encoded);
std::string hex_encoded() const;
+ /**
+ Convert a cryptomatte hash to a float.
+ *
+ * Cryptomatte hashes are stored in float textures and images. The conversion is taken from the
+ * cryptomatte specification. See Floating point conversion section in
+ * https://github.com/Psyop/Cryptomatte/blob/master/specification/cryptomatte_specification.pdf.
+ *
+ * The conversion uses as many 32 bit floating point values as possible to minimize hash
+ * collisions. Unfortunately not all 32 bits can be used as NaN and Inf can be problematic.
+ *
+ * Note that this conversion assumes to be running on a L-endian system.
+ */
float float_encoded() const;
};
diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h
index 5e474c0c5ac..713ee8cac01 100644
--- a/source/blender/blenkernel/BKE_curve.h
+++ b/source/blender/blenkernel/BKE_curve.h
@@ -75,8 +75,8 @@ typedef struct CVKeyIndex {
#define SEGMENTSV(nu) (((nu)->flagv & CU_NURB_CYCLIC) ? (nu)->pntsv : (nu)->pntsv - 1)
#define CU_DO_RADIUS(cu, nu) \
- ((((cu)->flag & (CU_PATH_RADIUS | CU_3D)) || (cu)->bevobj || (cu)->ext1 != 0.0f || \
- (cu)->ext2 != 0.0f) ? \
+ ((((cu)->flag & (CU_PATH_RADIUS | CU_3D)) || (cu)->bevobj || (cu)->extrude != 0.0f || \
+ (cu)->bevel_radius != 0.0f) ? \
1 : \
0)
@@ -86,6 +86,9 @@ typedef struct CVKeyIndex {
#define CU_DO_2DFILL(cu) (CU_IS_2D(cu) && (((cu)->flag & (CU_FRONT | CU_BACK)) != 0))
/* ** Curve ** */
+/**
+ * Frees edit-curve entirely.
+ */
void BKE_curve_editfont_free(struct Curve *cu);
void BKE_curve_init(struct Curve *cu, const short curve_type);
struct Curve *BKE_curve_add(struct Main *bmain, const char *name, int type);
@@ -98,6 +101,8 @@ struct BoundBox *BKE_curve_boundbox_get(struct Object *ob);
void BKE_curve_texspace_calc(struct Curve *cu);
void BKE_curve_texspace_ensure(struct Curve *cu);
+/* Basic vertex data functions. */
+
bool BKE_curve_minmax(struct Curve *cu, bool use_radius, float min[3], float max[3]);
bool BKE_curve_center_median(struct Curve *cu, float cent[3]);
bool BKE_curve_center_bounds(struct Curve *cu, float cent[3]);
@@ -119,14 +124,26 @@ void BKE_curve_material_remap(struct Curve *cu, const unsigned int *remap, unsig
void BKE_curve_smooth_flag_set(struct Curve *cu, const bool use_smooth);
+/**
+ * \return edit-nurbs or normal nurbs list.
+ */
ListBase *BKE_curve_nurbs_get(struct Curve *cu);
const ListBase *BKE_curve_nurbs_get_for_read(const struct Curve *cu);
int BKE_curve_nurb_vert_index_get(const struct Nurb *nu, const void *vert);
void BKE_curve_nurb_active_set(struct Curve *cu, const struct Nurb *nu);
struct Nurb *BKE_curve_nurb_active_get(struct Curve *cu);
+/**
+ * Get active vert for curve.
+ */
void *BKE_curve_vert_active_get(struct Curve *cu);
+/**
+ * Set active nurb and active vert for curve.
+ */
void BKE_curve_nurb_vert_active_set(struct Curve *cu, const struct Nurb *nu, const void *vert);
+/**
+ * Get points to the active nurb and active vert for curve.
+ */
bool BKE_curve_nurb_vert_active_get(struct Curve *cu, struct Nurb **r_nu, void **r_vert);
void BKE_curve_nurb_vert_active_validate(struct Curve *cu);
@@ -152,6 +169,9 @@ void BKE_curve_nurbs_key_vert_tilts_apply(struct ListBase *lb, const float *key)
void BKE_curve_editNurb_keyIndex_delCV(struct GHash *keyindex, const void *cv);
void BKE_curve_editNurb_keyIndex_free(struct GHash **keyindex);
void BKE_curve_editNurb_free(struct Curve *cu);
+/**
+ * Get list of nurbs from edit-nurbs structure.
+ */
struct ListBase *BKE_curve_editNurbs_get(struct Curve *cu);
const struct ListBase *BKE_curve_editNurbs_get_for_read(const struct Curve *cu);
@@ -159,8 +179,14 @@ void BKE_curve_bevelList_free(struct ListBase *bev);
void BKE_curve_bevelList_make(struct Object *ob, const struct ListBase *nurbs, bool for_render);
ListBase BKE_curve_bevel_make(const struct Curve *curve);
+/**
+ * Forward differencing method for bezier curve.
+ */
void BKE_curve_forward_diff_bezier(
float q0, float q1, float q2, float q3, float *p, int it, int stride);
+/**
+ * Forward differencing method for first derivative of cubic bezier curve.
+ */
void BKE_curve_forward_diff_tangent_bezier(
float q0, float q1, float q2, float q3, float *p, int it, int stride);
@@ -168,6 +194,10 @@ void BKE_curve_rect_from_textbox(const struct Curve *cu,
const struct TextBox *tb,
struct rctf *r_rect);
+/**
+ * This function is almost the same as #BKE_fcurve_correct_bezpart,
+ * but doesn't allow as large a tangent.
+ */
void BKE_curve_correct_bezpart(const float v1[2], float v2[2], float v3[2], const float v4[2]);
/* ** Nurbs ** */
@@ -179,6 +209,15 @@ int BKE_nurbList_verts_count_without_handles(const struct ListBase *nurb);
void BKE_nurbList_free(struct ListBase *lb);
void BKE_nurbList_duplicate(struct ListBase *lb1, const struct ListBase *lb2);
+/**
+ * \param code:
+ * - 1 (#HD_AUTO): set auto-handle.
+ * - 2 (#HD_VECT): set vector-handle.
+ * - 3 (#HD_ALIGN) it toggle, vector-handles become #HD_FREE.
+ *
+ * - 5: Set align, like 3 but no toggle.
+ * - 6: Clear align (setting #HD_FREE), like 3 but no toggle.
+ */
void BKE_nurbList_handles_set(struct ListBase *editnurb, const char code);
void BKE_nurbList_handles_recalculate(struct ListBase *editnurb,
const bool calc_length,
@@ -186,18 +225,36 @@ void BKE_nurbList_handles_recalculate(struct ListBase *editnurb,
void BKE_nurbList_handles_autocalc(ListBase *editnurb, uint8_t flag);
void BKE_nurbList_flag_set(ListBase *editnurb, uint8_t flag, bool set);
+/**
+ * Set \a flag for every point that already has \a from_flag set.
+ */
bool BKE_nurbList_flag_set_from_flag(ListBase *editnurb, uint8_t from_flag, uint8_t flag);
void BKE_nurb_free(struct Nurb *nu);
struct Nurb *BKE_nurb_duplicate(const struct Nurb *nu);
+/**
+ * Copy the nurb but allow for different number of points (to be copied after this).
+ */
struct Nurb *BKE_nurb_copy(struct Nurb *src, int pntsu, int pntsv);
void BKE_nurb_project_2d(struct Nurb *nu);
+/**
+ * if use_radius is truth, minmax will take points' radius into account,
+ * which will make bound-box closer to beveled curve.
+ */
void BKE_nurb_minmax(const struct Nurb *nu, bool use_radius, float min[3], float max[3]);
float BKE_nurb_calc_length(const struct Nurb *nu, int resolution);
+/**
+ * \param coord_array: has to be `(3 * 4 * resolu * resolv)` in size, and zero-ed.
+ */
void BKE_nurb_makeFaces(
const struct Nurb *nu, float *coord_array, int rowstride, int resolu, int resolv);
+/**
+ * \param coord_array: Has to be `(3 * 4 * pntsu * resolu)` in size and zero-ed
+ * \param tilt_array: set when non-NULL
+ * \param radius_array: set when non-NULL
+ */
void BKE_nurb_makeCurve(const struct Nurb *nu,
float *coord_array,
float *tilt_array,
@@ -206,10 +263,19 @@ void BKE_nurb_makeCurve(const struct Nurb *nu,
int resolu,
int stride);
+/**
+ * Calculate the length for arrays filled in by #BKE_curve_calc_coords_axis.
+ */
unsigned int BKE_curve_calc_coords_axis_len(const unsigned int bezt_array_len,
const unsigned int resolu,
const bool is_cyclic,
const bool use_cyclic_duplicate_endpoint);
+/**
+ * Calculate an array for the entire curve (cyclic or non-cyclic).
+ * \note Call for each axis.
+ *
+ * \param use_cyclic_duplicate_endpoint: Duplicate values at the beginning & end of the array.
+ */
void BKE_curve_calc_coords_axis(const struct BezTriple *bezt_array,
const unsigned int bezt_array_len,
const unsigned int resolu,
@@ -232,11 +298,17 @@ bool BKE_nurb_order_clamp_u(struct Nurb *nu);
bool BKE_nurb_order_clamp_v(struct Nurb *nu);
void BKE_nurb_direction_switch(struct Nurb *nu);
+/**
+ * \note caller must ensure active vertex remains valid.
+ */
bool BKE_nurb_type_convert(struct Nurb *nu,
const short type,
const bool use_handles,
const char **r_err_msg);
+/**
+ * Be sure to call #BKE_nurb_knot_calc_u / #BKE_nurb_knot_calc_v after this.
+ */
void BKE_nurb_points_add(struct Nurb *nu, int number);
void BKE_nurb_bezierPoints_add(struct Nurb *nu, int number);
@@ -254,17 +326,31 @@ void BKE_nurb_bezt_calc_plane(struct Nurb *nu, struct BezTriple *bezt, float r_p
void BKE_nurb_bpoint_calc_normal(struct Nurb *nu, struct BPoint *bp, float r_normal[3]);
void BKE_nurb_bpoint_calc_plane(struct Nurb *nu, struct BPoint *bp, float r_plane[3]);
+/**
+ * Recalculate the handles of a nurb bezier-triple. Acts based on handle selection with `SELECT`
+ * flag. To use a different flag, use #BKE_nurb_handle_calc_ex().
+ */
void BKE_nurb_handle_calc(struct BezTriple *bezt,
struct BezTriple *prev,
struct BezTriple *next,
const bool is_fcurve,
const char smoothing);
+/**
+ * Variant of #BKE_nurb_handle_calc() that allows calculating based on a different select flag.
+ *
+ * \param handle_sel_flag: The flag (bezt.f1/2/3) value to use to determine selection.
+ * Usually #SELECT, but may want to use a different one at times
+ * (if caller does not operate on selection).
+ */
void BKE_nurb_handle_calc_ex(struct BezTriple *bezt,
struct BezTriple *prev,
struct BezTriple *next,
const eBezTriple_Flag__Alias handle_sel_flag,
const bool is_fcurve,
const char smoothing);
+/**
+ * Similar to #BKE_nurb_handle_calc but for curves and figures out the previous and next for us.
+ */
void BKE_nurb_handle_calc_simple(struct Nurb *nu, struct BezTriple *bezt);
void BKE_nurb_handle_calc_simple_auto(struct Nurb *nu, struct BezTriple *bezt);
@@ -272,6 +358,18 @@ void BKE_nurb_handle_smooth_fcurve(struct BezTriple *bezt, int total, bool cycli
void BKE_nurb_handles_calc(struct Nurb *nu);
void BKE_nurb_handles_autocalc(struct Nurb *nu, uint8_t flag);
+/**
+ * Update selected handle types to ensure valid state, e.g. deduce "Auto" types to concrete ones.
+ * Thereby \a sel_flag defines what qualifies as selected.
+ * Use when something has changed handle positions.
+ *
+ * The caller needs to recalculate handles.
+ *
+ * \param sel_flag: The flag (bezt.f1/2/3) value to use to determine selection. Usually `SELECT`,
+ * but may want to use a different one at times (if caller does not operate on * selection).
+ * \param use_handle: Check selection state of individual handles, otherwise always update both
+ * handles if the key is selected.
+ */
void BKE_nurb_bezt_handle_test(struct BezTriple *bezt,
const eBezTriple_Flag__Alias sel_flag,
const bool use_handle,
@@ -337,6 +435,12 @@ void BKE_curve_deform_coords_with_editmesh(const struct Object *ob_curve,
const short defaxis,
struct BMEditMesh *em_target);
+/**
+ * \param orco: Input vec and orco = local coord in curve space
+ * orco is original not-animated or deformed reference point.
+ *
+ * The result written to `vec` and `r_mat`.
+ */
void BKE_curve_deform_co(const struct Object *ob_curve,
const struct Object *ob_target,
const float orco[3],
diff --git a/source/blender/blenkernel/BKE_curve_to_mesh.hh b/source/blender/blenkernel/BKE_curve_to_mesh.hh
index fb077425336..cf5c8b87ede 100644
--- a/source/blender/blenkernel/BKE_curve_to_mesh.hh
+++ b/source/blender/blenkernel/BKE_curve_to_mesh.hh
@@ -25,7 +25,21 @@ struct CurveEval;
namespace blender::bke {
+/**
+ * Extrude all splines in the profile curve along the path of every spline in the curve input.
+ * Transfer curve attributes to the mesh.
+ *
+ * \note Normal calculation is by far the slowest part of calculations relating to the result mesh.
+ * Although it would be a sensible decision to use the better topology information available while
+ * generating the mesh to also generate the normals, that work may wasted if the output mesh is
+ * changed anyway in a way that affects the normals. So currently this code uses the safer /
+ * simpler solution of deferring normal calculation to the rest of Blender.
+ */
Mesh *curve_to_mesh_sweep(const CurveEval &curve, const CurveEval &profile, bool fill_caps);
+/**
+ * Create a loose-edge mesh based on the evaluated path of the curve's splines.
+ * Transfer curve attributes to the mesh.
+ */
Mesh *curve_to_wire_mesh(const CurveEval &curve);
} // namespace blender::bke
diff --git a/source/blender/blenkernel/BKE_curveprofile.h b/source/blender/blenkernel/BKE_curveprofile.h
index 5a948f0d844..ee8bf99a216 100644
--- a/source/blender/blenkernel/BKE_curveprofile.h
+++ b/source/blender/blenkernel/BKE_curveprofile.h
@@ -34,8 +34,15 @@ struct BlendWriter;
struct CurveProfile;
struct CurveProfilePoint;
+/**
+ * Sets the default settings and clip range for the profile widget.
+ * Does not generate either table.
+ */
void BKE_curveprofile_set_defaults(struct CurveProfile *profile);
+/**
+ * Returns a pointer to a newly allocated curve profile, using the given preset.
+ */
struct CurveProfile *BKE_curveprofile_add(eCurveProfilePresets preset);
void BKE_curveprofile_free_data(struct CurveProfile *profile);
@@ -46,32 +53,90 @@ void BKE_curveprofile_copy_data(struct CurveProfile *target, const struct CurveP
struct CurveProfile *BKE_curveprofile_copy(const struct CurveProfile *profile);
+/**
+ * Move a point's handle, accounting for the alignment of handles with the #HD_ALIGN type.
+ *
+ * \param handle_1: Whether to move the 1st or 2nd control point.
+ * \param delta: The *relative* change in the handle's position.
+ * \note Requires #BKE_curveprofile_update call after.
+ * \return Whether the handle moved from its start position.
+ */
bool BKE_curveprofile_move_handle(struct CurveProfilePoint *point,
const bool handle_1,
const bool snap,
const float delta[2]);
+/**
+ * Moves a control point, accounting for clipping and snapping, and moving free handles.
+ *
+ * \param snap: Whether to snap the point to the grid
+ * \param delta: The *relative* change of the point's location.
+ * \return Whether the point moved from its start position.
+ * \note Requires #BKE_curveprofile_update call after.
+ */
bool BKE_curveprofile_move_point(struct CurveProfile *profile,
struct CurveProfilePoint *point,
const bool snap,
const float delta[2]);
+/**
+ * Removes a specific point from the path of control points.
+ * \note Requires #BKE_curveprofile_update call after.
+ */
bool BKE_curveprofile_remove_point(struct CurveProfile *profile, struct CurveProfilePoint *point);
+/**
+ * Removes every point in the widget with the supplied flag set, except for the first and last.
+ *
+ * \param flag: #CurveProfilePoint.flag.
+ *
+ * \note Requires #BKE_curveprofile_update call after.
+ */
void BKE_curveprofile_remove_by_flag(struct CurveProfile *profile, const short flag);
+/**
+ * Adds a new point at the specified location. The choice for which points to place the new vertex
+ * between is made by checking which control point line segment is closest to the new point and
+ * placing the new vertex in between that segment's points.
+ *
+ * \note Requires #BKE_curveprofile_update call after.
+ */
struct CurveProfilePoint *BKE_curveprofile_insert(struct CurveProfile *profile, float x, float y);
+/**
+ * Sets the handle type of the selected control points.
+ * \param type_1, type_2: Handle type for the first handle. HD_VECT, HD_AUTO, HD_FREE, or HD_ALIGN.
+ * \note Requires #BKE_curveprofile_update call after.
+ */
void BKE_curveprofile_selected_handle_set(struct CurveProfile *profile, int type_1, int type_2);
+/**
+ * Flips the profile across the diagonal so that its orientation is reversed.
+ *
+ * \note Requires #BKE_curveprofile_update call after.
+ */
void BKE_curveprofile_reverse(struct CurveProfile *profile);
+/**
+ * Reset the view to the clipping rectangle.
+ */
void BKE_curveprofile_reset_view(struct CurveProfile *profile);
+/**
+ * Resets the profile to the current preset.
+ *
+ * \note Requires #BKE_curveprofile_update call after.
+ */
void BKE_curveprofile_reset(struct CurveProfile *profile);
int BKE_curveprofile_table_size(const struct CurveProfile *profile);
+/**
+ * Refreshes the higher resolution table sampled from the input points. A call to this or
+ * #BKE_curveprofile_update is needed before evaluation functions that use the table.
+ * Also sets the number of segments used for the display preview of the locations
+ * of the sampled points.
+ */
void BKE_curveprofile_init(struct CurveProfile *profile, short segments_len);
/* Called for a complete update of the widget after modifications */
@@ -80,15 +145,31 @@ enum {
PROF_UPDATE_REMOVE_DOUBLES = (1 << 0),
PROF_UPDATE_CLIP = (1 << 1),
};
+/**
+ * Should be called after the widget is changed. Does profile and remove double checks and more
+ * importantly, recreates the display / evaluation and segments tables.
+ * \param update_flags: Bit-field with fields defined in header file.
+ * Controls removing doubles and clipping.
+ */
void BKE_curveprofile_update(struct CurveProfile *profile, const int update_flags);
-/* Length portion is the fraction of the total path length where we want the location */
+/**
+ * Does a single evaluation along the profile's path.
+ * Travels down (length_portion * path) length and returns the position at that point.
+ * Where length portion is the fraction of the total path length where we want the location.
+ *
+ * \param length_portion: The portion (0 to 1) of the path's full length to sample at.
+ * \note Requires #BKE_curveprofile_init or #BKE_curveprofile_update call before to fill table.
+ */
void BKE_curveprofile_evaluate_length_portion(const struct CurveProfile *profile,
float length_portion,
float *x_out,
float *y_out);
void BKE_curveprofile_blend_write(struct BlendWriter *writer, const struct CurveProfile *profile);
+/**
+ * Expects that the curve profile itself has been read already.
+ */
void BKE_curveprofile_blend_read(struct BlendDataReader *reader, struct CurveProfile *profile);
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h
index 0732f1e5190..68d29235469 100644
--- a/source/blender/blenkernel/BKE_customdata.h
+++ b/source/blender/blenkernel/BKE_customdata.h
@@ -86,8 +86,14 @@ typedef void (*cd_interp)(
typedef void (*cd_copy)(const void *source, void *dest, int count);
typedef bool (*cd_validate)(void *item, const uint totitems, const bool do_fixes);
+/**
+ * Update mask_dst with layers defined in mask_src (equivalent to a bit-wise OR).
+ */
void CustomData_MeshMasks_update(CustomData_MeshMasks *mask_dst,
const CustomData_MeshMasks *mask_src);
+/**
+ * Return True if all layers set in \a mask_required are also set in \a mask_ref
+ */
bool CustomData_MeshMasks_are_matching(const CustomData_MeshMasks *mask_ref,
const CustomData_MeshMasks *mask_required);
@@ -99,39 +105,50 @@ bool CustomData_layer_has_math(const struct CustomData *data, int layer_n);
bool CustomData_layer_has_interp(const struct CustomData *data, int layer_n);
/**
- * Checks if any of the customdata layers has math.
+ * Checks if any of the custom-data layers has math.
*/
bool CustomData_has_math(const struct CustomData *data);
bool CustomData_has_interp(const struct CustomData *data);
+/**
+ * A non bmesh version would have to check `layer->data`.
+ */
bool CustomData_bmesh_has_free(const struct CustomData *data);
/**
- * Checks if any of the customdata layers is referenced.
+ * Checks if any of the custom-data layers is referenced.
*/
bool CustomData_has_referenced(const struct CustomData *data);
-/* Copies the "value" (e.g. mloopuv uv or mloopcol colors) from one block to
+/**
+ * Copies the "value" (e.g. mloopuv uv or mloopcol colors) from one block to
* another, while not overwriting anything else (e.g. flags). probably only
- * implemented for mloopuv/mloopcol, for now. */
+ * implemented for mloopuv/mloopcol, for now.
+ */
void CustomData_data_copy_value(int type, const void *source, void *dest);
-/* Same as above, but doing advanced mixing.
- * Only available for a few types of data (like colors...). */
+/**
+ * Mixes the "value" (e.g. mloopuv uv or mloopcol colors) from one block into
+ * another, while not overwriting anything else (e.g. flags).
+ */
void CustomData_data_mix_value(
int type, const void *source, void *dest, const int mixmode, const float mixfactor);
-/* compares if data1 is equal to data2. type is a valid CustomData type
- * enum (e.g. CD_MLOOPUV). the layer type's equal function is used to compare
- * the data, if it exists, otherwise memcmp is used. */
+/**
+ * Compares if data1 is equal to data2. type is a valid CustomData type
+ * enum (e.g. #CD_MLOOPUV). the layer type's equal function is used to compare
+ * the data, if it exists, otherwise #memcmp is used.
+ */
bool CustomData_data_equals(int type, const void *data1, const void *data2);
void CustomData_data_initminmax(int type, void *min, void *max);
void CustomData_data_dominmax(int type, const void *data, void *min, void *max);
void CustomData_data_multiply(int type, void *data, float fac);
void CustomData_data_add(int type, void *data1, const void *data2);
-/* initializes a CustomData object with the same layer setup as source.
- * mask is a bitfield where (mask & (1 << (layer type))) indicates
- * if a layer should be copied or not. alloctype must be one of the above. */
+/**
+ * Initializes a CustomData object with the same layer setup as source.
+ * mask is a bitfield where `(mask & (1 << (layer type)))` indicates
+ * if a layer should be copied or not. alloctype must be one of the above.
+ */
void CustomData_copy(const struct CustomData *source,
struct CustomData *dest,
CustomDataMask mask,
@@ -141,25 +158,30 @@ void CustomData_copy(const struct CustomData *source,
/* BMESH_TODO, not really a public function but readfile.c needs it */
void CustomData_update_typemap(struct CustomData *data);
-/* same as the above, except that this will preserve existing layers, and only
- * add the layers that were not there yet */
+/**
+ * Same as the above, except that this will preserve existing layers, and only
+ * add the layers that were not there yet.
+ */
bool CustomData_merge(const struct CustomData *source,
struct CustomData *dest,
CustomDataMask mask,
eCDAllocType alloctype,
int totelem);
-/* Reallocate custom data to a new element count.
+/**
+ * Reallocate custom data to a new element count.
* Only affects on data layers which are owned by the CustomData itself,
* referenced data is kept unchanged,
*
- * NOTE: Take care of referenced layers by yourself!
+ * \note Take care of referenced layers by yourself!
*/
void CustomData_realloc(struct CustomData *data, int totelem);
-/* bmesh version of CustomData_merge; merges the layouts of source and dest,
- * then goes through the mesh and makes sure all the customdata blocks are
- * consistent with the new layout. */
+/**
+ * BMesh version of CustomData_merge; merges the layouts of source and `dest`,
+ * then goes through the mesh and makes sure all the custom-data blocks are
+ * consistent with the new layout.
+ */
bool CustomData_bmesh_merge(const struct CustomData *source,
struct CustomData *dest,
CustomDataMask mask,
@@ -167,7 +189,9 @@ bool CustomData_bmesh_merge(const struct CustomData *source,
struct BMesh *bm,
const char htype);
-/** NULL's all members and resets the typemap. */
+/**
+ * NULL's all members and resets the #CustomData.typemap.
+ */
void CustomData_reset(struct CustomData *data);
/**
@@ -175,19 +199,26 @@ void CustomData_reset(struct CustomData *data);
*/
void CustomData_free(struct CustomData *data, int totelem);
-/* same as above, but only frees layers which matches the given mask. */
+/**
+ * Same as above, but only frees layers which matches the given mask.
+ */
void CustomData_free_typemask(struct CustomData *data, int totelem, CustomDataMask mask);
-/* frees all layers with CD_FLAG_TEMPORARY */
+/**
+ * Frees all layers with #CD_FLAG_TEMPORARY.
+ */
void CustomData_free_temporary(struct CustomData *data, int totelem);
-/* adds a data layer of the given type to the CustomData object, optionally
+/**
+ * Adds a data layer of the given type to the #CustomData object, optionally
* backed by an external data array. the different allocation types are
* defined above. returns the data of the layer.
*/
void *CustomData_add_layer(
struct CustomData *data, int type, eCDAllocType alloctype, void *layer, int totelem);
-/* Same as above but accepts a name. */
+/**
+ * Same as above but accepts a name.
+ */
void *CustomData_add_layer_named(struct CustomData *data,
int type,
eCDAllocType alloctype,
@@ -201,32 +232,42 @@ void *CustomData_add_layer_anonymous(struct CustomData *data,
int totelem,
const struct AnonymousAttributeID *anonymous_id);
-/* frees the active or first data layer with the give type.
+/**
+ * Frees the active or first data layer with the give type.
* returns 1 on success, 0 if no layer with the given type is found
*
- * in editmode, use EDBM_data_layer_free instead of this function
+ * In edit-mode, use #EDBM_data_layer_free instead of this function.
*/
bool CustomData_free_layer(struct CustomData *data, int type, int totelem, int index);
-/* frees the layer index with the give type.
- * returns 1 on success, 0 if no layer with the given type is found
+/**
+ * Frees the layer index with the give type.
+ * returns 1 on success, 0 if no layer with the given type is found.
*
- * in editmode, use EDBM_data_layer_free instead of this function
+ * In edit-mode, use #EDBM_data_layer_free instead of this function.
*/
bool CustomData_free_layer_active(struct CustomData *data, int type, int totelem);
-/* same as above, but free all layers with type */
+/**
+ * Same as above, but free all layers with type.
+ */
void CustomData_free_layers(struct CustomData *data, int type, int totelem);
-/* returns 1 if a layer with the specified type exists */
+/**
+ * Returns true if a layer with the specified type exists.
+ */
bool CustomData_has_layer(const struct CustomData *data, int type);
-/* returns the number of layers with this type */
+/**
+ * Returns the number of layers with this type.
+ */
int CustomData_number_of_layers(const struct CustomData *data, int type);
int CustomData_number_of_layers_typemask(const struct CustomData *data, CustomDataMask mask);
-/* duplicate data of a layer with flag NOFREE, and remove that flag.
- * returns the layer data */
+/**
+ * Duplicate data of a layer with flag NOFREE, and remove that flag.
+ * \return the layer data.
+ */
void *CustomData_duplicate_referenced_layer(struct CustomData *data,
const int type,
const int totelem);
@@ -245,19 +286,21 @@ void *CustomData_duplicate_referenced_layer_anonymous(
const int totelem);
bool CustomData_is_referenced_layer(struct CustomData *data, int type);
-/* Duplicate all the layers with flag NOFREE, and remove the flag from duplicated layers. */
+/**
+ * Duplicate all the layers with flag NOFREE, and remove the flag from duplicated layers.
+ */
void CustomData_duplicate_referenced_layers(CustomData *data, int totelem);
-/* set the CD_FLAG_NOCOPY flag in custom data layers where the mask is
- * zero for the layer type, so only layer types specified by the mask
- * will be copied
+/**
+ * Set the #CD_FLAG_NOCOPY flag in custom data layers where the mask is
+ * zero for the layer type, so only layer types specified by the mask will be copied
*/
void CustomData_set_only_copy(const struct CustomData *data, CustomDataMask mask);
-/* copies data from one CustomData object to another
+/**
+ * Copies data from one CustomData object to another
* objects need not be compatible, each source layer is copied to the
- * first dest layer of correct type (if there is none, the layer is skipped)
- * return 1 on success, 0 on failure
+ * first dest layer of correct type (if there is none, the layer is skipped).
*/
void CustomData_copy_data(const struct CustomData *source,
struct CustomData *dest,
@@ -287,7 +330,9 @@ void CustomData_bmesh_copy_data_exclude_by_type(const struct CustomData *source,
void **dest_block,
const CustomDataMask mask_exclude);
-/* Copies data of a single layer of a given type. */
+/**
+ * Copies data of a single layer of a given type.
+ */
void CustomData_copy_layer_type_data(const struct CustomData *source,
struct CustomData *destination,
int type,
@@ -295,22 +340,22 @@ void CustomData_copy_layer_type_data(const struct CustomData *source,
int destination_index,
int count);
-/* frees data in a CustomData object
- * return 1 on success, 0 on failure
+/**
+ * Frees data in a #CustomData object.
*/
void CustomData_free_elem(struct CustomData *data, int index, int count);
-/* interpolates data from one CustomData object to another
- * objects need not be compatible, each source layer is interpolated to the
- * first dest layer of correct type (if there is none, the layer is skipped)
- * if weights == NULL or sub_weights == NULL, they default to all 1's
+/**
+ * Interpolate given custom data source items into a single destination one.
*
- * src_indices gives the source elements to interpolate from
- * weights gives the weight for each source element
- * sub_weights is an array of matrices of weights for sub-elements (matrices
- * should be source->subElems * source->subElems in size)
- * count gives the number of source elements to interpolate from
- * dest_index gives the dest element to write the interpolated value to
+ * \param src_indices: Indices of every source items to interpolate into the destination one.
+ * \param weights: The weight to apply to each source value individually. If NULL, they will be
+ * averaged.
+ * \param sub_weights: The weights of sub-items, only used to affect each corners of a
+ * tessellated face data (should always be and array of four values).
+ * \param count: The number of source items to interpolate.
+ * \param dest_index: Index of the destination item, in which to put the result of the
+ * interpolation.
*/
void CustomData_interp(const struct CustomData *source,
struct CustomData *dest,
@@ -319,6 +364,10 @@ void CustomData_interp(const struct CustomData *source,
const float *sub_weights,
int count,
int dest_index);
+/**
+ * \note src_blocks_ofs & dst_block_ofs
+ * must be pointers to the data, offset by layer->offset already.
+ */
void CustomData_bmesh_interp_n(struct CustomData *data,
const void **src_blocks,
const float *weights,
@@ -333,30 +382,45 @@ void CustomData_bmesh_interp(struct CustomData *data,
int count,
void *dst_block);
-/* swaps the data in the element corners, to new corners with indices as
- * specified in corner_indices. for edges this is an array of length 2, for
- * faces an array of length 4 */
+/**
+ * Swap data inside each item, for all layers.
+ * This only applies to item types that may store several sub-item data
+ * (e.g. corner data [UVs, VCol, ...] of tessellated faces).
+ *
+ * \param corner_indices: A mapping 'new_index -> old_index' of sub-item data.
+ */
void CustomData_swap_corners(struct CustomData *data, int index, const int *corner_indices);
+/**
+ * Swap two items of given custom data, in all available layers.
+ */
void CustomData_swap(struct CustomData *data, const int index_a, const int index_b);
-/* gets a pointer to the data element at index from the first layer of type
- * returns NULL if there is no layer of type
+/**
+ * Gets a pointer to the data element at index from the first layer of type.
+ * \return NULL if there is no layer of type.
*/
void *CustomData_get(const struct CustomData *data, int index, int type);
void *CustomData_get_n(const struct CustomData *data, int type, int index, int n);
+
+/* BMesh Custom Data Functions.
+ * Should replace edit-mesh ones with these as well, due to more efficient memory alloc. */
+
void *CustomData_bmesh_get(const struct CustomData *data, void *block, int type);
void *CustomData_bmesh_get_n(const struct CustomData *data, void *block, int type, int n);
-/* gets the layer at physical index n, with no type checking.
+/**
+ * Gets from the layer at physical index `n`,
+ * \note doesn't check type.
*/
void *CustomData_bmesh_get_layer_n(const struct CustomData *data, void *block, int n);
bool CustomData_set_layer_name(const struct CustomData *data, int type, int n, const char *name);
const char *CustomData_get_layer_name(const struct CustomData *data, int type, int n);
-/* gets a pointer to the active or first layer of type
- * returns NULL if there is no layer of type
+/**
+ * Gets a pointer to the active or first layer of type.
+ * \return NULL if there is no layer of type.
*/
void *CustomData_get_layer(const struct CustomData *data, int type);
void *CustomData_get_layer_n(const struct CustomData *data, int type, int n);
@@ -377,9 +441,9 @@ int CustomData_get_render_layer(const struct CustomData *data, int type);
int CustomData_get_clone_layer(const struct CustomData *data, int type);
int CustomData_get_stencil_layer(const struct CustomData *data, int type);
-/* copies the data from source to the data element at index in the first
- * layer of type
- * no effect if there is no layer of type
+/**
+ * Copies the data from source to the data element at index in the first layer of type
+ * no effect if there is no layer of type.
*/
void CustomData_set(const struct CustomData *data, int index, int type, const void *source);
@@ -390,42 +454,63 @@ void CustomData_bmesh_set(const struct CustomData *data,
void CustomData_bmesh_set_n(
struct CustomData *data, void *block, int type, int n, const void *source);
-/* sets the data of the block at physical layer n. no real type checking
- * is performed.
+/**
+ * Sets the data of the block at physical layer n.
+ * no real type checking is performed.
*/
void CustomData_bmesh_set_layer_n(struct CustomData *data, void *block, int n, const void *source);
-/* set the pointer of to the first layer of type. the old data is not freed.
- * returns the value of ptr if the layer is found, NULL otherwise
+/**
+ * Set the pointer of to the first layer of type. the old data is not freed.
+ * returns the value of `ptr` if the layer is found, NULL otherwise.
*/
void *CustomData_set_layer(const struct CustomData *data, int type, void *ptr);
void *CustomData_set_layer_n(const struct CustomData *data, int type, int n, void *ptr);
-/* sets the nth layer of type as active */
+/**
+ * Sets the nth layer of type as active.
+ */
void CustomData_set_layer_active(struct CustomData *data, int type, int n);
void CustomData_set_layer_render(struct CustomData *data, int type, int n);
void CustomData_set_layer_clone(struct CustomData *data, int type, int n);
void CustomData_set_layer_stencil(struct CustomData *data, int type, int n);
-/* same as above but works with an index from CustomData_get_layer_index */
+/**
+ * For using with an index from #CustomData_get_active_layer_index and
+ * #CustomData_get_render_layer_index.
+ */
void CustomData_set_layer_active_index(struct CustomData *data, int type, int n);
void CustomData_set_layer_render_index(struct CustomData *data, int type, int n);
void CustomData_set_layer_clone_index(struct CustomData *data, int type, int n);
void CustomData_set_layer_stencil_index(struct CustomData *data, int type, int n);
-/* adds flag to the layer flags */
+/**
+ * Adds flag to the layer flags.
+ */
void CustomData_set_layer_flag(struct CustomData *data, int type, int flag);
void CustomData_clear_layer_flag(struct CustomData *data, int type, int flag);
void CustomData_bmesh_set_default(struct CustomData *data, void **block);
void CustomData_bmesh_free_block(struct CustomData *data, void **block);
+/**
+ * Same as #CustomData_bmesh_free_block but zero the memory rather than freeing.
+ */
void CustomData_bmesh_free_block_data(struct CustomData *data, void *block);
+/**
+ * A selective version of #CustomData_bmesh_free_block_data.
+ */
void CustomData_bmesh_free_block_data_exclude_by_type(struct CustomData *data,
void *block,
const CustomDataMask mask_exclude);
-/* copy custom data to/from layers as in mesh/derivedmesh, to editmesh
- * blocks of data. the CustomData's must not be compatible */
+/**
+ * Copy custom data to/from layers as in mesh/derived-mesh, to edit-mesh
+ * blocks of data. the CustomData's must not be compatible.
+ *
+ * \param use_default_init: initializes data which can't be copied,
+ * typically you'll want to use this if the BM_xxx create function
+ * is called with BM_CREATE_SKIP_CD flag
+ */
void CustomData_to_bmesh_block(const struct CustomData *source,
struct CustomData *dest,
int src_index,
@@ -436,17 +521,34 @@ void CustomData_from_bmesh_block(const struct CustomData *source,
void *src_block,
int dest_index);
-/* query info over types */
+/**
+ * Query info over types.
+ */
void CustomData_file_write_info(int type, const char **r_struct_name, int *r_struct_num);
int CustomData_sizeof(int type);
-/* get the name of a layer type */
+/**
+ * Get the name of a layer type.
+ */
const char *CustomData_layertype_name(int type);
+/**
+ * Can only ever be one of these.
+ */
bool CustomData_layertype_is_singleton(int type);
+/**
+ * Has dynamically allocated members.
+ * This is useful to know if operations such as #memcmp are
+ * valid when comparing data from two layers.
+ */
bool CustomData_layertype_is_dynamic(int type);
+/**
+ * \return Maximum number of layers of given \a type, -1 means 'no limit'.
+ */
int CustomData_layertype_layers_max(const int type);
-/* make sure the name of layer at index is unique */
+/**
+ * Make sure the name of layer at index is unique.
+ */
void CustomData_set_layer_unique_name(struct CustomData *data, int index);
void CustomData_validate_layer_name(const struct CustomData *data,
@@ -454,23 +556,45 @@ void CustomData_validate_layer_name(const struct CustomData *data,
const char *name,
char *outname);
-/* for file reading compatibility, returns false if the layer was freed,
- * only after this test passes, layer->data should be assigned */
+/**
+ * For file reading compatibility, returns false if the layer was freed,
+ * only after this test passes, `layer->data` should be assigned.
+ */
bool CustomData_verify_versions(struct CustomData *data, int index);
-/* BMesh specific custom-data stuff. */
+/* BMesh specific custom-data stuff.
+ *
+ * Needed to convert to/from different face representation (for versioning). */
+
void CustomData_to_bmeshpoly(struct CustomData *fdata, struct CustomData *ldata, int totloop);
void CustomData_from_bmeshpoly(struct CustomData *fdata, struct CustomData *ldata, int total);
void CustomData_bmesh_update_active_layers(struct CustomData *fdata, struct CustomData *ldata);
+/**
+ * Update active indices for active/render/clone/stencil custom data layers
+ * based on indices from fdata layers
+ * used by do_versions in `readfile.c` when creating pdata and ldata for pre-bmesh
+ * meshes and needed to preserve active/render/clone/stencil flags set in pre-bmesh files.
+ */
void CustomData_bmesh_do_versions_update_active_layers(struct CustomData *fdata,
struct CustomData *ldata);
void CustomData_bmesh_init_pool(struct CustomData *data, int totelem, const char htype);
#ifndef NDEBUG
+/**
+ * Debug check, used to assert when we expect layers to be in/out of sync.
+ *
+ * \param fallback: Use when there are no layers to handle,
+ * since callers may expect success or failure.
+ */
bool CustomData_from_bmeshpoly_test(CustomData *fdata, CustomData *ldata, bool fallback);
#endif
-/* Layer data validation. */
+/**
+ * Validate and fix data of \a layer,
+ * if possible (needs relevant callback in layer's type to be defined).
+ *
+ * \return True if some errors were found.
+ */
bool CustomData_layer_validate(struct CustomDataLayer *layer,
const uint totitems,
const bool do_fixes);
@@ -587,16 +711,41 @@ typedef struct CustomDataTransferLayerMap {
cd_datatransfer_interp interp;
} CustomDataTransferLayerMap;
-/* Those functions assume src_n and dst_n layers of given type exist in resp. src and dst. */
+/**
+ * Those functions assume src_n and dst_n layers of given type exist in resp. src and dst.
+ */
void CustomData_data_transfer(const struct MeshPairRemap *me_remap,
const CustomDataTransferLayerMap *laymap);
/* .blend file I/O */
+
+/**
+ * Prepare given custom data for file writing.
+ *
+ * \param data: the custom-data to tweak for .blend file writing (modified in place).
+ * \param r_write_layers: contains a reduced set of layers to be written to file,
+ * use it with #writestruct_at_address()
+ * (caller must free it if != \a write_layers_buff).
+ *
+ * \param write_layers_buff: An optional buffer for r_write_layers (to avoid allocating it).
+ * \param write_layers_size: The size of pre-allocated \a write_layer_buff.
+ *
+ * \warning After this funcion has ran, given custom data is no more valid from Blender POV
+ * (its `totlayer` is invalid). This function shall always be called with localized data
+ * (as it is in write_meshes()).
+ *
+ * \note `data->typemap` is not updated here, since it is always rebuilt on file read anyway.
+ * This means written `typemap` does not match written layers (as returned by \a r_write_layers).
+ * Trivial to fix is ever needed.
+ */
void CustomData_blend_write_prepare(struct CustomData *data,
struct CustomDataLayer **r_write_layers,
struct CustomDataLayer *write_layers_buff,
size_t write_layers_size);
+/**
+ * \param layers: The layers argument assigned by #CustomData_blend_write_prepare.
+ */
void CustomData_blend_write(struct BlendWriter *writer,
struct CustomData *data,
CustomDataLayer *layers,
diff --git a/source/blender/blenkernel/BKE_data_transfer.h b/source/blender/blenkernel/BKE_data_transfer.h
index a2544e43c3d..a4218ec564b 100644
--- a/source/blender/blenkernel/BKE_data_transfer.h
+++ b/source/blender/blenkernel/BKE_data_transfer.h
@@ -65,6 +65,10 @@ enum {
void BKE_object_data_transfer_dttypes_to_cdmask(const int dtdata_types,
struct CustomData_MeshMasks *r_data_masks);
+/**
+ * Check what can do each layer type
+ * (if it is actually handled by transfer-data, if it supports advanced mixing.
+ */
bool BKE_object_data_transfer_get_dttypes_capacity(const int dtdata_types,
bool *r_advanced_mixing,
bool *r_threshold);
@@ -122,6 +126,12 @@ enum {
#endif
};
+/**
+ * Transfer data *layout* of selected types from source to destination object.
+ * By default, it only creates new data layers if needed on \a ob_dst.
+ * If \a use_delete is true, it will also delete data layers on \a ob_dst that do not match those
+ * from \a ob_src, to get (as much as possible) exact copy of source data layout.
+ */
void BKE_object_data_transfer_layout(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob_src,
diff --git a/source/blender/blenkernel/BKE_deform.h b/source/blender/blenkernel/BKE_deform.h
index f4221d57428..9870d43b5c2 100644
--- a/source/blender/blenkernel/BKE_deform.h
+++ b/source/blender/blenkernel/BKE_deform.h
@@ -44,20 +44,36 @@ const struct ListBase *BKE_object_defgroup_list(const struct Object *ob);
struct ListBase *BKE_object_defgroup_list_mutable(struct Object *ob);
int BKE_object_defgroup_count(const struct Object *ob);
+/**
+ * \note For historical reasons, the index starts at 1 rather than 0.
+ */
int BKE_object_defgroup_active_index_get(const struct Object *ob);
+/**
+ * \note For historical reasons, the index starts at 1 rather than 0.
+ */
void BKE_object_defgroup_active_index_set(struct Object *ob, const int new_index);
const struct ListBase *BKE_id_defgroup_list_get(const struct ID *id);
struct ListBase *BKE_id_defgroup_list_get_mutable(struct ID *id);
int BKE_id_defgroup_name_index(const struct ID *id, const char *name);
+bool BKE_id_defgroup_name_find(const struct ID *id,
+ const char *name,
+ int *r_index,
+ struct bDeformGroup **r_group);
struct bDeformGroup *BKE_object_defgroup_new(struct Object *ob, const char *name);
void BKE_defgroup_copy_list(struct ListBase *outbase, const struct ListBase *inbase);
struct bDeformGroup *BKE_defgroup_duplicate(const struct bDeformGroup *ingroup);
struct bDeformGroup *BKE_object_defgroup_find_name(const struct Object *ob, const char *name);
+/**
+ * \note caller must free.
+ */
int *BKE_object_defgroup_flip_map(const struct Object *ob,
int *flip_map_len,
const bool use_default);
+/**
+ * \note caller must free.
+ */
int *BKE_object_defgroup_flip_map_single(const struct Object *ob,
int *flip_map_len,
const bool use_default,
@@ -67,11 +83,33 @@ int BKE_object_defgroup_name_index(const struct Object *ob, const char *name);
void BKE_object_defgroup_unique_name(struct bDeformGroup *dg, struct Object *ob);
struct MDeformWeight *BKE_defvert_find_index(const struct MDeformVert *dv, const int defgroup);
+/**
+ * Ensures that `dv` has a deform weight entry for the specified defweight group.
+ *
+ * \note this function is mirrored in editmesh_tools.c, for use for edit-vertices.
+ */
struct MDeformWeight *BKE_defvert_ensure_index(struct MDeformVert *dv, const int defgroup);
+/**
+ * Adds the given vertex to the specified vertex group, with given weight.
+ *
+ * \warning this does NOT check for existing, assume caller already knows its not there.
+ */
void BKE_defvert_add_index_notest(struct MDeformVert *dv, int defgroup, const float weight);
+/**
+ * Removes the given vertex from the vertex group.
+ *
+ * \warning This function frees the given #MDeformWeight, do not use it afterward!
+ */
void BKE_defvert_remove_group(struct MDeformVert *dvert, struct MDeformWeight *dw);
void BKE_defvert_clear(struct MDeformVert *dvert);
+/**
+ * \return The first group index shared by both deform verts
+ * or -1 if none are found.
+ */
int BKE_defvert_find_shared(const struct MDeformVert *dvert_a, const struct MDeformVert *dvert_b);
+/**
+ * \return true if has no weights.
+ */
bool BKE_defvert_is_weight_zero(const struct MDeformVert *dvert, const int defgroup_tot);
void BKE_defvert_array_free_elems(struct MDeformVert *dvert, int totvert);
@@ -79,14 +117,32 @@ void BKE_defvert_array_free(struct MDeformVert *dvert, int totvert);
void BKE_defvert_array_copy(struct MDeformVert *dst, const struct MDeformVert *src, int totvert);
float BKE_defvert_find_weight(const struct MDeformVert *dvert, const int defgroup);
+/**
+ * Take care with this the rationale is:
+ * - if the object has no vertex group. act like vertex group isn't set and return 1.0.
+ * - if the vertex group exists but the 'defgroup' isn't found on this vertex, _still_ return 0.0.
+ *
+ * This is a bit confusing, just saves some checks from the caller.
+ */
float BKE_defvert_array_find_weight_safe(const struct MDeformVert *dvert,
const int index,
const int defgroup);
+/**
+ * \return The total weight in all groups marked in the selection mask.
+ */
float BKE_defvert_total_selected_weight(const struct MDeformVert *dv,
int defbase_tot,
const bool *defbase_sel);
+/**
+ * \return The representative weight of a multi-paint group, used for
+ * viewport colors and actual painting.
+ *
+ * Result equal to sum of weights with auto normalize, and average otherwise.
+ * Value is not clamped, since painting relies on multiplication being always
+ * commutative with the collective weight function.
+ */
float BKE_defvert_multipaint_collective_weight(const struct MDeformVert *dv,
int defbase_tot,
const bool *defbase_sel,
@@ -96,9 +152,19 @@ float BKE_defvert_multipaint_collective_weight(const struct MDeformVert *dv,
/* This much unlocked weight is considered equivalent to none. */
#define VERTEX_WEIGHT_LOCK_EPSILON 1e-6f
+/**
+ * Computes the display weight for the lock relative weight paint mode.
+ *
+ * \return weight divided by 1-locked_weight with division by zero check
+ */
float BKE_defvert_calc_lock_relative_weight(float weight,
float locked_weight,
float unlocked_weight);
+/**
+ * Computes the display weight for the lock relative weight paint mode, using weight data.
+ *
+ * \return weight divided by unlocked, or 1-locked_weight with division by zero check.
+ */
float BKE_defvert_lock_relative_weight(float weight,
const struct MDeformVert *dv,
int defbase_tot,
@@ -106,41 +172,75 @@ float BKE_defvert_lock_relative_weight(float weight,
const bool *defbase_unlocked);
void BKE_defvert_copy(struct MDeformVert *dvert_dst, const struct MDeformVert *dvert_src);
+/**
+ * Overwrite weights filtered by vgroup_subset.
+ * - do nothing if neither are set.
+ * - add destination weight if needed
+ */
void BKE_defvert_copy_subset(struct MDeformVert *dvert_dst,
const struct MDeformVert *dvert_src,
const bool *vgroup_subset,
const int vgroup_tot);
+/**
+ * Overwrite weights filtered by vgroup_subset and with mirroring specified by the flip map
+ * - do nothing if neither are set.
+ * - add destination weight if needed
+ */
void BKE_defvert_mirror_subset(struct MDeformVert *dvert_dst,
const struct MDeformVert *dvert_src,
const bool *vgroup_subset,
const int vgroup_tot,
const int *flip_map,
const int flip_map_len);
+/**
+ * Copy an index from one #MDeformVert to another.
+ * - do nothing if neither are set.
+ * - add destination weight if needed.
+ */
void BKE_defvert_copy_index(struct MDeformVert *dvert_dst,
const int defgroup_dst,
const struct MDeformVert *dvert_src,
const int defgroup_src);
+/**
+ * Only sync over matching weights, don't add or remove groups
+ * warning, loop within loop.
+ */
void BKE_defvert_sync(struct MDeformVert *dvert_dst,
const struct MDeformVert *dvert_src,
const bool use_ensure);
+/**
+ * be sure all flip_map values are valid
+ */
void BKE_defvert_sync_mapped(struct MDeformVert *dvert_dst,
const struct MDeformVert *dvert_src,
const int *flip_map,
const int flip_map_len,
const bool use_ensure);
+/**
+ * be sure all flip_map values are valid
+ */
void BKE_defvert_remap(struct MDeformVert *dvert, const int *map, const int map_len);
void BKE_defvert_flip(struct MDeformVert *dvert, const int *flip_map, const int flip_map_len);
void BKE_defvert_flip_merged(struct MDeformVert *dvert,
const int *flip_map,
const int flip_map_len);
void BKE_defvert_normalize(struct MDeformVert *dvert);
+/**
+ * Same as #BKE_defvert_normalize but takes a bool array.
+ */
void BKE_defvert_normalize_subset(struct MDeformVert *dvert,
const bool *vgroup_subset,
const int vgroup_tot);
+/**
+ * Same as BKE_defvert_normalize() if the locked vgroup is not a member of the subset
+ */
void BKE_defvert_normalize_lock_single(struct MDeformVert *dvert,
const bool *vgroup_subset,
const int vgroup_tot,
const uint def_nr_lock);
+/**
+ * Same as BKE_defvert_normalize() if no locked vgroup is a member of the subset
+ */
void BKE_defvert_normalize_lock_map(struct MDeformVert *dvert,
const bool *vgroup_subset,
const int vgroup_tot,
@@ -149,11 +249,16 @@ void BKE_defvert_normalize_lock_map(struct MDeformVert *dvert,
/* Utilities to 'extract' a given vgroup into a simple float array,
* for verts, but also edges/polys/loops. */
+
void BKE_defvert_extract_vgroup_to_vertweights(struct MDeformVert *dvert,
const int defgroup,
const int num_verts,
float *r_weights,
const bool invert_vgroup);
+/**
+ * The following three make basic interpolation,
+ * using temp vert_weights array to avoid looking up same weight several times.
+ */
void BKE_defvert_extract_vgroup_to_edgeweights(struct MDeformVert *dvert,
const int defgroup,
const int num_verts,
diff --git a/source/blender/blenkernel/BKE_displist.h b/source/blender/blenkernel/BKE_displist.h
index 8fb596a8096..db1217465d7 100644
--- a/source/blender/blenkernel/BKE_displist.h
+++ b/source/blender/blenkernel/BKE_displist.h
@@ -98,6 +98,12 @@ void BKE_curve_calc_modifiers_pre(struct Depsgraph *depsgraph,
bool BKE_displist_surfindex_get(
const struct DispList *dl, int a, int *b, int *p1, int *p2, int *p3, int *p4);
+/**
+ * \param normal_proj: Optional normal that's used to project the scan-fill verts into 2D coords.
+ * Pass this along if known since it saves time calculating the normal.
+ * This is also used to initialize #DispList.nors (one normal per display list).
+ * \param flip_normal: Flip the normal (same as passing \a normal_proj negated).
+ */
void BKE_displist_fill(const struct ListBase *dispbase,
struct ListBase *to,
const float normal_proj[3],
diff --git a/source/blender/blenkernel/BKE_duplilist.h b/source/blender/blenkernel/BKE_duplilist.h
index 989b68f4ccb..5eff84b8c9e 100644
--- a/source/blender/blenkernel/BKE_duplilist.h
+++ b/source/blender/blenkernel/BKE_duplilist.h
@@ -36,6 +36,9 @@ struct ID;
/* ---------------------------------------------------- */
/* Dupli-Geometry */
+/**
+ * \return a #ListBase of #DupliObject.
+ */
struct ListBase *object_duplilist(struct Depsgraph *depsgraph,
struct Scene *sce,
struct Object *ob);
diff --git a/source/blender/blenkernel/BKE_dynamicpaint.h b/source/blender/blenkernel/BKE_dynamicpaint.h
index 31f48be2c27..4b34a9490c4 100644
--- a/source/blender/blenkernel/BKE_dynamicpaint.h
+++ b/source/blender/blenkernel/BKE_dynamicpaint.h
@@ -64,41 +64,79 @@ typedef struct PaintWavePoint {
short state;
} PaintWavePoint;
+/**
+ * Modifier call. Processes dynamic paint modifier step.
+ */
struct Mesh *dynamicPaint_Modifier_do(struct DynamicPaintModifierData *pmd,
struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
struct Mesh *me);
+/**
+ * Free whole dynamic-paint modifier.
+ */
void dynamicPaint_Modifier_free(struct DynamicPaintModifierData *pmd);
void dynamicPaint_Modifier_free_runtime(struct DynamicPaintRuntime *runtime);
void dynamicPaint_Modifier_copy(const struct DynamicPaintModifierData *pmd,
struct DynamicPaintModifierData *tpmd,
int flag);
+/**
+ * Initialize modifier data.
+ */
bool dynamicPaint_createType(struct DynamicPaintModifierData *pmd, int type, struct Scene *scene);
+/**
+ * Creates a new surface and adds it to the list
+ * If scene is null, frame range of 1-250 is used
+ * A pointer to this surface is returned.
+ */
struct DynamicPaintSurface *dynamicPaint_createNewSurface(
struct DynamicPaintCanvasSettings *canvas, struct Scene *scene);
+/**
+ * Clears surface data back to zero.
+ */
void dynamicPaint_clearSurface(const struct Scene *scene, struct DynamicPaintSurface *surface);
+/**
+ * Completely (re)initializes surface (only for point cache types).
+ */
bool dynamicPaint_resetSurface(const struct Scene *scene, struct DynamicPaintSurface *surface);
void dynamicPaint_freeSurface(const struct DynamicPaintModifierData *pmd,
struct DynamicPaintSurface *surface);
+/**
+ * Free canvas data.
+ */
void dynamicPaint_freeCanvas(struct DynamicPaintModifierData *pmd);
+/* Free brush data */
void dynamicPaint_freeBrush(struct DynamicPaintModifierData *pmd);
void dynamicPaint_freeSurfaceData(struct DynamicPaintSurface *surface);
+/**
+ * Update cache frame range.
+ */
void dynamicPaint_cacheUpdateFrames(struct DynamicPaintSurface *surface);
bool dynamicPaint_outputLayerExists(struct DynamicPaintSurface *surface,
struct Object *ob,
int output);
+/**
+ * Change surface data to defaults on new type.
+ */
void dynamicPaintSurface_updateType(struct DynamicPaintSurface *surface);
void dynamicPaintSurface_setUniqueName(struct DynamicPaintSurface *surface, const char *basename);
+/**
+ * Get currently active surface (in user interface).
+ */
struct DynamicPaintSurface *get_activeSurface(struct DynamicPaintCanvasSettings *canvas);
-/* image sequence baking */
+/**
+ * Image sequence baking.
+ */
int dynamicPaint_createUVSurface(struct Scene *scene,
struct DynamicPaintSurface *surface,
float *progress,
short *do_update);
+/**
+ * Calculate a single frame and included sub-frames for surface.
+ */
int dynamicPaint_calculateFrame(struct DynamicPaintSurface *surface,
struct Depsgraph *depsgraph,
struct Scene *scene,
diff --git a/source/blender/blenkernel/BKE_editmesh.h b/source/blender/blenkernel/BKE_editmesh.h
index 2c24b1a5487..32cc5961e4a 100644
--- a/source/blender/blenkernel/BKE_editmesh.h
+++ b/source/blender/blenkernel/BKE_editmesh.h
@@ -102,12 +102,29 @@ void BKE_editmesh_looptri_calc_with_partial(BMEditMesh *em, struct BMPartialUpda
void BKE_editmesh_looptri_and_normals_calc_with_partial(BMEditMesh *em,
struct BMPartialUpdate *bmpinfo);
+/**
+ * Performing the face normal calculation at the same time as tessellation
+ * gives a reasonable performance boost (approx ~20% faster).
+ */
void BKE_editmesh_looptri_and_normals_calc(BMEditMesh *em);
+/**
+ * \note The caller is responsible for ensuring triangulation data,
+ * typically by calling #BKE_editmesh_looptri_calc.
+ */
BMEditMesh *BKE_editmesh_create(BMesh *bm);
BMEditMesh *BKE_editmesh_copy(BMEditMesh *em);
+/**
+ * \brief Return the #BMEditMesh for a given object
+ *
+ * \note this function assumes this is a mesh object,
+ * don't add NULL data check here. caller must do that
+ */
BMEditMesh *BKE_editmesh_from_object(struct Object *ob);
void BKE_editmesh_free_derived_caches(BMEditMesh *em);
+/**
+ * \note Does not free the #BMEditMesh struct itself.
+ */
void BKE_editmesh_free_data(BMEditMesh *em);
float (*BKE_editmesh_vert_coords_alloc(struct Depsgraph *depsgraph,
@@ -124,6 +141,9 @@ const float (*BKE_editmesh_vert_coords_when_deformed(struct Depsgraph *depsgraph
bool *r_is_alloc))[3];
void BKE_editmesh_lnorspace_update(BMEditMesh *em, struct Mesh *me);
+/**
+ * If auto-smooth not already set, set it.
+ */
void BKE_editmesh_ensure_autosmooth(BMEditMesh *em, struct Mesh *me);
struct BoundBox *BKE_editmesh_cage_boundbox_get(BMEditMesh *em);
diff --git a/source/blender/blenkernel/BKE_editmesh_bvh.h b/source/blender/blenkernel/BKE_editmesh_bvh.h
index 69d1b4819f8..fc274b4ffd1 100644
--- a/source/blender/blenkernel/BKE_editmesh_bvh.h
+++ b/source/blender/blenkernel/BKE_editmesh_bvh.h
@@ -78,7 +78,9 @@ struct BMFace *BKE_bmbvh_ray_cast_filter(BMBVHTree *tree,
BMBVHTree_FaceFilter filter_cb,
void *filter_userdata);
-/* find a vert closest to co in a sphere of radius dist_max */
+/**
+ * Find a vert closest to co in a sphere of radius dist_max.
+ */
struct BMVert *BKE_bmbvh_find_vert_closest(BMBVHTree *tree,
const float co[3],
const float dist_max);
@@ -86,10 +88,16 @@ struct BMFace *BKE_bmbvh_find_face_closest(BMBVHTree *tree,
const float co[3],
const float dist_max);
+/**
+ * Overlap indices reference the looptri's.
+ */
struct BVHTreeOverlap *BKE_bmbvh_overlap(const BMBVHTree *bmtree_a,
const BMBVHTree *bmtree_b,
unsigned int *r_overlap_tot);
+/**
+ * Overlap indices reference the looptri's.
+ */
struct BVHTreeOverlap *BKE_bmbvh_overlap_self(const BMBVHTree *bmtree,
unsigned int *r_overlap_tot);
diff --git a/source/blender/blenkernel/BKE_editmesh_tangent.h b/source/blender/blenkernel/BKE_editmesh_tangent.h
index 0e3f063ae44..b76db11348e 100644
--- a/source/blender/blenkernel/BKE_editmesh_tangent.h
+++ b/source/blender/blenkernel/BKE_editmesh_tangent.h
@@ -24,6 +24,13 @@
extern "C" {
#endif
+/**
+ * \see #BKE_mesh_calc_loop_tangent, same logic but used arrays instead of #BMesh data.
+ *
+ * \note This function is not so normal, its using #BMesh.ldata as input,
+ * but output's to #Mesh.ldata.
+ * This is done because #CD_TANGENT is cache data used only for drawing.
+ */
void BKE_editmesh_loop_tangent_calc(BMEditMesh *em,
bool calc_active_tangent,
const char (*tangent_names)[MAX_NAME],
diff --git a/source/blender/blenkernel/BKE_effect.h b/source/blender/blenkernel/BKE_effect.h
index 3a964ddb1aa..f33ca2f03d1 100644
--- a/source/blender/blenkernel/BKE_effect.h
+++ b/source/blender/blenkernel/BKE_effect.h
@@ -113,16 +113,27 @@ struct PartDeflect *BKE_partdeflect_new(int type);
struct PartDeflect *BKE_partdeflect_copy(const struct PartDeflect *pd_src);
void BKE_partdeflect_free(struct PartDeflect *pd);
+/**
+ * Create list of effector relations in the collection or entire scene.
+ * This is used by the depsgraph to build relations, as well as faster
+ * lookup of effectors during evaluation.
+ */
struct ListBase *BKE_effector_relations_create(struct Depsgraph *depsgraph,
struct ViewLayer *view_layer,
struct Collection *collection);
void BKE_effector_relations_free(struct ListBase *lb);
+/**
+ * Create effective list of effectors from relations built beforehand.
+ */
struct ListBase *BKE_effectors_create(struct Depsgraph *depsgraph,
struct Object *ob_src,
struct ParticleSystem *psys_src,
struct EffectorWeights *weights,
bool use_rotation);
+/**
+ * Generic force/speed system, now used for particles, soft-bodies & dynamic-paint.
+ */
void BKE_effectors_apply(struct ListBase *effectors,
struct ListBase *colliders,
struct EffectorWeights *weights,
@@ -146,15 +157,15 @@ float effector_falloff(struct EffectorCache *eff,
struct EffectorData *efd,
struct EffectedPoint *point,
struct EffectorWeights *weights);
-int closest_point_on_surface(struct SurfaceModifierData *surmd,
- const float co[3],
- float surface_co[3],
- float surface_nor[3],
- float surface_vel[3]);
-int get_effector_data(struct EffectorCache *eff,
- struct EffectorData *efd,
- struct EffectedPoint *point,
- int real_velocity);
+bool closest_point_on_surface(struct SurfaceModifierData *surmd,
+ const float co[3],
+ float surface_co[3],
+ float surface_nor[3],
+ float surface_vel[3]);
+bool get_effector_data(struct EffectorCache *eff,
+ struct EffectorData *efd,
+ struct EffectedPoint *point,
+ int real_velocity);
/* required for particle_system.c */
#if 0
diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h
index f494c2e30cc..1537d14ab01 100644
--- a/source/blender/blenkernel/BKE_fcurve.h
+++ b/source/blender/blenkernel/BKE_fcurve.h
@@ -133,20 +133,56 @@ typedef enum eFMI_Requirement_Flags {
} eFMI_Requirement_Flags;
/* Function Prototypes for FModifierTypeInfo's */
+
+/**
+ * This function should always be used to get the appropriate type-info,
+ * as it has checks which prevent segfaults in some weird cases.
+ */
const FModifierTypeInfo *fmodifier_get_typeinfo(const struct FModifier *fcm);
+/**
+ * This function should be used for getting the appropriate type-info when only
+ * a F-Curve modifier type is known.
+ */
const FModifierTypeInfo *get_fmodifier_typeinfo(const int type);
/* ---------------------- */
+/**
+ * Add a new F-Curve Modifier to the given F-Curve of a certain type.
+ */
struct FModifier *add_fmodifier(ListBase *modifiers, int type, struct FCurve *owner_fcu);
+/**
+ * Make a copy of the specified F-Modifier.
+ */
struct FModifier *copy_fmodifier(const struct FModifier *src);
+/**
+ * Duplicate all of the F-Modifiers in the Modifier stacks.
+ */
void copy_fmodifiers(ListBase *dst, const ListBase *src);
+/**
+ * Remove and free the given F-Modifier from the given stack.
+ */
bool remove_fmodifier(ListBase *modifiers, struct FModifier *fcm);
+/**
+ * Remove all of a given F-Curve's modifiers.
+ */
void free_fmodifiers(ListBase *modifiers);
+/**
+ * Find the active F-Modifier.
+ */
struct FModifier *find_active_fmodifier(ListBase *modifiers);
+/**
+ * Set the active F-Modifier.
+ */
void set_active_fmodifier(ListBase *modifiers, struct FModifier *fcm);
+/**
+ * Do we have any modifiers which match certain criteria.
+ *
+ * \param mtype: Type of modifier (if 0, doesn't matter).
+ * \param acttype: Type of action to perform (if -1, doesn't matter).
+ */
bool list_has_suitable_fmodifier(ListBase *modifiers, int mtype, short acttype);
typedef struct FModifiersStackStorage {
@@ -156,17 +192,38 @@ typedef struct FModifiersStackStorage {
} FModifiersStackStorage;
uint evaluate_fmodifiers_storage_size_per_modifier(ListBase *modifiers);
+/**
+ * Evaluate time modifications imposed by some F-Curve Modifiers.
+ *
+ * - This step acts as an optimization to prevent the F-Curve stack being evaluated
+ * several times by modifiers requesting the time be modified, as the final result
+ * would have required using the modified time
+ * - Modifiers only ever receive the unmodified time, as subsequent modifiers should be
+ * working on the 'global' result of the modified curve, not some localized segment,
+ * so \a evaltime gets set to whatever the last time-modifying modifier likes.
+ * - We start from the end of the stack, as only the last one matters for now.
+ *
+ * \param fcu: Can be NULL.
+ */
float evaluate_time_fmodifiers(FModifiersStackStorage *storage,
ListBase *modifiers,
struct FCurve *fcu,
float cvalue,
float evaltime);
+/**
+ * Evaluates the given set of F-Curve Modifiers using the given data
+ * Should only be called after evaluate_time_fmodifiers() has been called.
+ */
void evaluate_value_fmodifiers(FModifiersStackStorage *storage,
ListBase *modifiers,
struct FCurve *fcu,
float *cvalue,
float evaltime);
+/**
+ * Bake modifiers for given F-Curve to curve sample data, in the frame range defined
+ * by start and end (inclusive).
+ */
void fcurve_bake_modifiers(struct FCurve *fcu, int start, int end);
int BKE_fcm_envelope_find_index(struct FCM_EnvelopeData *array,
@@ -182,30 +239,64 @@ int BKE_fcm_envelope_find_index(struct FCM_EnvelopeData *array,
/* -------- Data Management -------- */
struct FCurve *BKE_fcurve_create(void);
+/**
+ * Frees the F-Curve itself too, so make sure #BLI_remlink is called before calling this.
+ */
void BKE_fcurve_free(struct FCurve *fcu);
+/**
+ * Duplicate a F-Curve.
+ */
struct FCurve *BKE_fcurve_copy(const struct FCurve *fcu);
-
+/**
+ * Frees a list of F-Curves.
+ */
void BKE_fcurves_free(ListBase *list);
+/**
+ * Duplicate a list of F-Curves.
+ */
void BKE_fcurves_copy(ListBase *dst, ListBase *src);
+/**
+ * Callback used by lib_query to walk over all ID usages
+ * (mimics `foreach_id` callback of #IDTypeInfo structure).
+ */
void BKE_fcurve_foreach_id(struct FCurve *fcu, struct LibraryForeachIDData *data);
-/* find matching F-Curve in the given list of F-Curves */
+/**
+ * Find the F-Curve affecting the given RNA-access path + index,
+ * in the list of F-Curves provided.
+ */
struct FCurve *BKE_fcurve_find(ListBase *list, const char rna_path[], const int array_index);
+/**
+ * Quick way to loop over all f-curves of a given 'path'.
+ */
struct FCurve *BKE_fcurve_iter_step(struct FCurve *fcu_iter, const char rna_path[]);
-/* high level function to get an fcurve from C without having the rna */
+/**
+ * High level function to get an f-curve from C without having the RNA.
+ */
struct FCurve *id_data_find_fcurve(
ID *id, void *data, struct StructRNA *type, const char *prop_name, int index, bool *r_driven);
-/* Get list of LinkData's containing pointers to the F-Curves which control the types of data
- * indicated
- * e.g. numMatches = BKE_fcurves_filter(matches, &act->curves, "pose.bones[", "MyFancyBone");
+/**
+ * Get list of LinkData's containing pointers to the F-curves
+ * which control the types of data indicated.
+ * e.g. `numMatches = BKE_fcurves_filter(matches, &act->curves, "pose.bones[", "MyFancyBone");`
+ *
+ * Lists:
+ * \param dst: list of LinkData's matching the criteria returned.
+ * List must be freed after use, and is assumed to be empty when passed.
+ * \param src: list of F-Curves to search through
+ * Filters:
+ * \param dataPrefix: i.e. `pose.bones[` or `nodes[`.
+ * \param dataName: name of entity within "" immediately following the prefix.
*/
int BKE_fcurves_filter(ListBase *dst, ListBase *src, const char *dataPrefix, const char *dataName);
-/* Find an f-curve based on an rna property. */
+/**
+ * Find an f-curve based on an rna property.
+ */
struct FCurve *BKE_fcurve_find_by_rna(struct PointerRNA *ptr,
struct PropertyRNA *prop,
int rnaindex,
@@ -213,8 +304,10 @@ struct FCurve *BKE_fcurve_find_by_rna(struct PointerRNA *ptr,
struct bAction **r_action,
bool *r_driven,
bool *r_special);
-/* Same as above, but takes a context data,
- * temp hack needed for complex paths like texture ones. */
+/**
+ * Same as above, but takes a context data,
+ * temp hack needed for complex paths like texture ones.
+ */
struct FCurve *BKE_fcurve_find_by_rna_context_ui(struct bContext *C,
struct PointerRNA *ptr,
struct PropertyRNA *prop,
@@ -224,7 +317,8 @@ struct FCurve *BKE_fcurve_find_by_rna_context_ui(struct bContext *C,
bool *r_driven,
bool *r_special);
-/* Binary search algorithm for finding where to 'insert' BezTriple with given frame number.
+/**
+ * Binary search algorithm for finding where to 'insert' #BezTriple with given frame number.
* Returns the index to insert at (data already at that index will be offset if replace is 0)
*/
int BKE_fcurve_bezt_binarysearch_index(const struct BezTriple array[],
@@ -233,23 +327,35 @@ int BKE_fcurve_bezt_binarysearch_index(const struct BezTriple array[],
bool *r_replace);
/* fcurve_cache.c */
-/* Cached f-curve look-ups, use when this needs to be done many times. */
+
+/**
+ * Cached f-curve look-ups, use when this needs to be done many times.
+ */
struct FCurvePathCache;
struct FCurvePathCache *BKE_fcurve_pathcache_create(ListBase *list);
void BKE_fcurve_pathcache_destroy(struct FCurvePathCache *fcache);
struct FCurve *BKE_fcurve_pathcache_find(struct FCurvePathCache *fcache,
const char rna_path[],
const int array_index);
+/**
+ * Fill in an array of F-Curve, leave NULL when not found.
+ *
+ * \return The number of F-Curves found.
+ */
int BKE_fcurve_pathcache_find_array(struct FCurvePathCache *fcache,
const char *rna_path,
struct FCurve **fcurve_result,
int fcurve_result_len);
-/* get the time extents for F-Curve */
+/**
+ * Calculate the extents of F-Curve's keyframes.
+ */
bool BKE_fcurve_calc_range(
struct FCurve *fcu, float *min, float *max, const bool do_sel_only, const bool do_min_length);
-/* get the bounding-box extents for F-Curve */
+/**
+ * Calculate the extents of F-Curve's data.
+ */
bool BKE_fcurve_calc_bounds(struct FCurve *fcu,
float *xmin,
float *xmax,
@@ -258,6 +364,14 @@ bool BKE_fcurve_calc_bounds(struct FCurve *fcu,
const bool do_sel_only,
const bool include_handles);
+/**
+ * Return an array of keyed frames, rounded to `interval`.
+ *
+ * \param interval: Set to 1.0 to round to whole keyframes, 0.5 for in-between key-frames, etc.
+ *
+ * \note An interval of zero could be supported (this implies no rounding at all),
+ * however this risks very small differences in float values being treated as separate keyframes.
+ */
float *BKE_fcurves_calc_keyed_frames_ex(struct FCurve **fcurve_array,
const int fcurve_array_len,
const float interval,
@@ -266,23 +380,42 @@ float *BKE_fcurves_calc_keyed_frames(struct FCurve **fcurve_array,
const int fcurve_array_len,
int *r_frames_len);
+/**
+ * Set the index that stores the FCurve's active keyframe, assuming that \a active_bezt
+ * is already part of `fcu->bezt`. If NULL, set active keyframe index to "none."
+ */
void BKE_fcurve_active_keyframe_set(struct FCurve *fcu, const struct BezTriple *active_bezt);
+/**
+ * Get the active keyframe index, with sanity checks for point bounds.
+ */
int BKE_fcurve_active_keyframe_index(const struct FCurve *fcu);
-/* Move the indexed keyframe to the given value, and move the handles with it to ensure the slope
- * remains the same. */
+/**
+ * Move the indexed keyframe to the given value,
+ * and move the handles with it to ensure the slope remains the same.
+ */
void BKE_fcurve_keyframe_move_value_with_handles(struct BezTriple *keyframe, float new_value);
/* .............. */
-/* Are keyframes on F-Curve of any use (to final result, and to show in editors)? */
+/**
+ * Are keyframes on F-Curve of any use (to final result, and to show in editors)?
+ * Usability of keyframes refers to whether they should be displayed,
+ * and also whether they will have any influence on the final result.
+ */
bool BKE_fcurve_are_keyframes_usable(struct FCurve *fcu);
-/* Can keyframes be added to F-Curve? */
+/**
+ * Can keyframes be added to F-Curve?
+ * Keyframes can only be added if they are already visible.
+ */
bool BKE_fcurve_is_keyframable(struct FCurve *fcu);
bool BKE_fcurve_is_protected(struct FCurve *fcu);
-/* The curve is an infinite cycle via Cycles modifier */
+/**
+ * Checks if the F-Curve has a Cycles modifier with simple settings
+ * that warrant transition smoothing.
+ */
bool BKE_fcurve_is_cyclic(struct FCurve *fcu);
/* Type of infinite cycle for a curve. */
@@ -294,9 +427,19 @@ typedef enum eFCU_Cycle_Type {
FCU_CYCLE_OFFSET,
} eFCU_Cycle_Type;
+/**
+ * Checks if the F-Curve has a Cycles modifier, and returns the type of the cycle behavior.
+ */
eFCU_Cycle_Type BKE_fcurve_get_cycle_type(struct FCurve *fcu);
-/* Recompute handles to neatly subdivide the prev-next range at bezt. */
+/**
+ * Recompute bezier handles of all three given BezTriples, so that `bezt` can be inserted between
+ * `prev` and `next` without changing the resulting curve shape.
+ *
+ * \param r_pdelta: return Y difference between `bezt` and the original curve value at its X
+ * position.
+ * \return Whether the split was successful.
+ */
bool BKE_fcurve_bezt_subdivide_handles(struct BezTriple *bezt,
struct BezTriple *prev,
struct BezTriple *next,
@@ -304,12 +447,50 @@ bool BKE_fcurve_bezt_subdivide_handles(struct BezTriple *bezt,
/* -------- Curve Sanity -------- */
+/**
+ * This function recalculates the handles of an F-Curve. Acts based on selection with `SELECT`
+ * flag. To use a different flag, use #calchandles_fcurve_ex().
+ *
+ * If the BezTriples have been rearranged, sort them first before using this.
+ */
void calchandles_fcurve(struct FCurve *fcu);
+/**
+ * Variant of #calchandles_fcurve() that allows calculating based on a different select flag.
+ *
+ * \param handle_sel_flag: The flag (bezt.f1/2/3) value to use to determine selection.
+ * Usually `SELECT`, but may want to use a different one at times
+ * (if caller does not operate on selection).
+ */
void calchandles_fcurve_ex(struct FCurve *fcu, eBezTriple_Flag handle_sel_flag);
+/**
+ * Update handles, making sure the handle-types are valid (e.g. correctly deduced from an "Auto"
+ * type), and recalculating their position vectors.
+ * Use when something has changed handle positions.
+ *
+ * \param sel_flag: The flag (bezt.f1/2/3) value to use to determine selection. Usually `SELECT`,
+ * but may want to use a different one at times (if caller does not operate on selection).
+ * \param use_handle: Check selection state of individual handles, otherwise always update both
+ * handles if the key is selected.
+ */
void testhandles_fcurve(struct FCurve *fcu, eBezTriple_Flag sel_flag, const bool use_handle);
+/**
+ * This function sorts BezTriples so that they are arranged in chronological order,
+ * as tools working on F-Curves expect that the BezTriples are in order.
+ */
void sort_time_fcurve(struct FCurve *fcu);
+/**
+ * This function tests if any BezTriples are out of order, thus requiring a sort.
+ */
bool test_time_fcurve(struct FCurve *fcu);
+/**
+ * The length of each handle is not allowed to be more
+ * than the horizontal distance between (v1-v4).
+ * This is to prevent curve loops.
+ *
+ * This function is very similar to BKE_curve_correct_bezpart(), but allows a steeper tangent for
+ * more snappy animations. This is not desired for other areas in which curves are used, though.
+ */
void BKE_fcurve_correct_bezpart(const float v1[2], float v2[2], float v3[2], const float v4[2]);
/* -------- Evaluation -------- */
@@ -321,8 +502,14 @@ float evaluate_fcurve_driver(struct PathResolvedRNA *anim_rna,
struct FCurve *fcu,
struct ChannelDriver *driver_orig,
const struct AnimationEvalContext *anim_eval_context);
+/**
+ * Checks if the curve has valid keys, drivers or modifiers that produce an actual curve.
+ */
bool BKE_fcurve_is_empty(struct FCurve *fcu);
-/* evaluate fcurve and store value */
+/**
+ * Calculate the value of the given F-Curve at the given frame,
+ * and store it's value in #FCurve.curval.
+ */
float calculate_fcurve(struct PathResolvedRNA *anim_rna,
struct FCurve *fcu,
const struct AnimationEvalContext *anim_eval_context);
@@ -331,26 +518,34 @@ float calculate_fcurve(struct PathResolvedRNA *anim_rna,
/* -------- Defines -------- */
-/* Basic signature for F-Curve sample-creation function
- * - fcu: the F-Curve being operated on
- * - data: pointer to some specific data that may be used by one of the callbacks
+/**
+ * Basic signature for F-Curve sample-creation function.
+ *
+ * \param fcu: the F-Curve being operated on.
+ * \param data: pointer to some specific data that may be used by one of the callbacks.
*/
typedef float (*FcuSampleFunc)(struct FCurve *fcu, void *data, float evaltime);
/* ----- Sampling Callbacks ------ */
-/* Basic sampling callback which acts as a wrapper for evaluate_fcurve() */
+/**
+ * Basic sampling callback which acts as a wrapper for #evaluate_fcurve()
+ * 'data' arg here is unneeded here.
+ */
float fcurve_samplingcb_evalcurve(struct FCurve *fcu, void *data, float evaltime);
/* -------- Main Methods -------- */
-/* Main API function for creating a set of sampled curve data, given some callback function
+/**
+ * Main API function for creating a set of sampled curve data, given some callback function
* used to retrieve the values to store.
*/
void fcurve_store_samples(
struct FCurve *fcu, void *data, int start, int end, FcuSampleFunc sample_cb);
-/* Convert baked/sampled fcurves into bezt/regular fcurves. */
+/**
+ * Convert baked/sampled f-curves into bezt/regular f-curves.
+ */
void fcurve_samples_to_keyframes(struct FCurve *fcu, const int start, const int end);
/* ************* F-Curve .blend file API ******************** */
diff --git a/source/blender/blenkernel/BKE_fcurve_driver.h b/source/blender/blenkernel/BKE_fcurve_driver.h
index 5b4da4a78a4..18676dfcb38 100644
--- a/source/blender/blenkernel/BKE_fcurve_driver.h
+++ b/source/blender/blenkernel/BKE_fcurve_driver.h
@@ -66,34 +66,85 @@ struct PropertyRNA;
/* ---------------------- */
+/**
+ * This frees the driver itself.
+ */
void fcurve_free_driver(struct FCurve *fcu);
+/**
+ * This makes a copy of the given driver.
+ */
struct ChannelDriver *fcurve_copy_driver(const struct ChannelDriver *driver);
+/**
+ * Copy driver variables from src_vars list to dst_vars list.
+ */
void driver_variables_copy(struct ListBase *dst_vars, const struct ListBase *src_vars);
+/**
+ * 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]);
+/**
+ * Perform actual freeing driver variable and remove it from the given list.
+ */
void driver_free_variable(struct ListBase *variables, struct DriverVar *dvar);
+/**
+ * Free the driver variable and do extra updates.
+ */
void driver_free_variable_ex(struct ChannelDriver *driver, struct DriverVar *dvar);
+/**
+ * Change the type of driver variable.
+ */
void driver_change_variable_type(struct DriverVar *dvar, int type);
+/**
+ * Validate driver variable name (after being renamed).
+ *
+ */
void driver_variable_name_validate(struct DriverVar *dvar);
+/**
+ * Add a new driver variable.
+ */
struct DriverVar *driver_add_new_variable(struct ChannelDriver *driver);
+/**
+ * Evaluate a Driver Variable to get a value that contributes to the final.
+ */
float driver_get_variable_value(struct ChannelDriver *driver, struct DriverVar *dvar);
+/**
+ * Same as 'dtar_get_prop_val'. but get the RNA property.
+ */
bool driver_get_variable_property(struct ChannelDriver *driver,
struct DriverTarget *dtar,
struct PointerRNA *r_ptr,
struct PropertyRNA **r_prop,
int *r_index);
+/**
+ * Check if the expression in the driver conforms to the simple subset.
+ */
bool BKE_driver_has_simple_expression(struct ChannelDriver *driver);
+/**
+ * Check if the expression in the driver may depend on the current frame.
+ */
bool BKE_driver_expression_depends_on_time(struct ChannelDriver *driver);
+/**
+ * Reset cached compiled expression data.
+ */
void BKE_driver_invalidate_expression(struct ChannelDriver *driver,
bool expr_changed,
bool varname_changed);
+/**
+ * Evaluate an Channel-Driver to get a 'time' value to use
+ * instead of `anim_eval_context->eval_time`.
+ *
+ * - `anim_eval_context->eval_time` is the frame at which F-Curve is being evaluated.
+ * - Has to return a float value.
+ * - \a driver_orig is where we cache Python expressions, in case of COW
+ */
float evaluate_driver(struct PathResolvedRNA *anim_rna,
struct ChannelDriver *driver,
struct ChannelDriver *driver_orig,
diff --git a/source/blender/blenkernel/BKE_fluid.h b/source/blender/blenkernel/BKE_fluid.h
index 33ff6943514..7bafcf00ce8 100644
--- a/source/blender/blenkernel/BKE_fluid.h
+++ b/source/blender/blenkernel/BKE_fluid.h
@@ -64,6 +64,10 @@ void BKE_fluid_cache_free_all(struct FluidDomainSettings *fds, struct Object *ob
void BKE_fluid_cache_free(struct FluidDomainSettings *fds, struct Object *ob, int cache_map);
void BKE_fluid_cache_new_name_for_current_session(int maxlen, char *r_name);
+/**
+ * Get fluid velocity and density at given coordinates.
+ * \returns fluid density or -1.0f if outside domain.
+ */
float BKE_fluid_get_velocity_at(struct Object *ob, float position[3], float velocity[3]);
int BKE_fluid_get_data_flags(struct FluidDomainSettings *fds);
diff --git a/source/blender/blenkernel/BKE_freestyle.h b/source/blender/blenkernel/BKE_freestyle.h
index 5e29665d728..ee3517f5b43 100644
--- a/source/blender/blenkernel/BKE_freestyle.h
+++ b/source/blender/blenkernel/BKE_freestyle.h
@@ -47,6 +47,10 @@ void BKE_freestyle_config_copy(struct FreestyleConfig *new_config,
struct FreestyleModuleConfig *BKE_freestyle_module_add(struct FreestyleConfig *config);
bool BKE_freestyle_module_delete(struct FreestyleConfig *config,
struct FreestyleModuleConfig *module_conf);
+/**
+ * Reinsert \a module_conf offset by \a direction from current position.
+ * \return if position of \a module_conf changed.
+ */
bool BKE_freestyle_module_move(struct FreestyleConfig *config,
struct FreestyleModuleConfig *module_conf,
int direction);
diff --git a/source/blender/blenkernel/BKE_geometry_set.h b/source/blender/blenkernel/BKE_geometry_set.h
index 17cdb9d6a42..2d6218f1036 100644
--- a/source/blender/blenkernel/BKE_geometry_set.h
+++ b/source/blender/blenkernel/BKE_geometry_set.h
@@ -39,6 +39,8 @@ typedef enum GeometryComponentType {
GEO_COMPONENT_TYPE_CURVE = 4,
} GeometryComponentType;
+#define GEO_COMPONENT_TYPE_ENUM_SIZE 5
+
void BKE_geometry_set_free(struct GeometrySet *geometry_set);
bool BKE_object_has_geometry_set_instances(const struct Object *ob);
diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh
index 35e66908d54..79f29e0954e 100644
--- a/source/blender/blenkernel/BKE_geometry_set.hh
+++ b/source/blender/blenkernel/BKE_geometry_set.hh
@@ -62,7 +62,9 @@ class ComponentAttributeProviders;
class GeometryComponent;
/**
- * This is the base class for specialized geometry component types.
+ * This is the base class for specialized geometry component types. A geometry component handles
+ * a user count to allow avoiding duplication when it is wrapped with #UserCounter. It also handles
+ * the attribute API, which generalizes storing and modifying generic information on a geometry.
*/
class GeometryComponent {
private:
@@ -150,6 +152,10 @@ class GeometryComponent {
const AttributeInit &initializer);
blender::Set<blender::bke::AttributeIDRef> attribute_ids() const;
+ /**
+ * \return False if the callback explicitly returned false at any point, otherwise true,
+ * meaning the callback made it all the way through.
+ */
bool attribute_foreach(const AttributeForeachCallback callback) const;
virtual bool is_empty() const;
@@ -252,19 +258,33 @@ template<typename T>
inline constexpr bool is_geometry_component_v = std::is_base_of_v<GeometryComponent, T>;
/**
- * A geometry set contains zero or more geometry components. There is at most one component of each
- * type. Individual components might be shared between multiple geometries. Shared components are
- * copied automatically when write access is requested.
+ * A geometry set is a container for multiple kinds of geometry. It does not own geometry directly
+ * itself, instead geometry is owned by multiple #GeometryComponents, and the geometry set
+ * increases the user count of each component, so they avoid losing the data. This means
+ * individual components might be shared between multiple geometries and other code. Shared
+ * components are copied automatically when write access is requested.
+ *
+ * The components usually do not store data directly, but keep a reference to a data
+ * structure defined elsewhere. There is at most one component of each type:
+ * - #MeshComponent
+ * - #CurveComponent
+ * - #PointCloudComponent
+ * - #InstancesComponent
+ * - #VolumeComponent
*
* Copying a geometry set is a relatively cheap operation, because it does not copy the referenced
- * geometry components.
+ * geometry components, so #GeometrySet can often be passed or moved by value.
*/
struct GeometrySet {
private:
using GeometryComponentPtr = blender::UserCounter<class GeometryComponent>;
- blender::Map<GeometryComponentType, GeometryComponentPtr> components_;
+ /* Indexed by #GeometryComponentType. */
+ std::array<GeometryComponentPtr, GEO_COMPONENT_TYPE_ENUM_SIZE> components_;
public:
+ /**
+ * The methods are defaulted here so that they are not instantiated in every translation unit.
+ */
GeometrySet();
GeometrySet(const GeometrySet &other);
GeometrySet(GeometrySet &&other);
@@ -272,6 +292,10 @@ struct GeometrySet {
GeometrySet &operator=(const GeometrySet &other);
GeometrySet &operator=(GeometrySet &&other);
+ /**
+ * This method can only be used when the geometry set is mutable. It returns a mutable geometry
+ * component of the given type.
+ */
GeometryComponent &get_component_for_write(GeometryComponentType component_type);
template<typename Component> Component &get_component_for_write()
{
@@ -279,6 +303,9 @@ struct GeometrySet {
return static_cast<Component &>(this->get_component_for_write(Component::static_type));
}
+ /**
+ * Get the component of the given type. Might return null if the component does not exist yet.
+ */
const GeometryComponent *get_component_for_read(GeometryComponentType component_type) const;
template<typename Component> const Component *get_component_for_read() const
{
@@ -300,19 +327,33 @@ struct GeometrySet {
return this->remove(Component::static_type);
}
+ /**
+ * Remove all geometry components with types that are not in the provided list.
+ */
void keep_only(const blender::Span<GeometryComponentType> component_types);
void add(const GeometryComponent &component);
+ /**
+ * Get all geometry components in this geometry set for read-only access.
+ */
blender::Vector<const GeometryComponent *> get_components_for_read() const;
void compute_boundbox_without_instances(blender::float3 *r_min, blender::float3 *r_max) const;
friend std::ostream &operator<<(std::ostream &stream, const GeometrySet &geometry_set);
+ /**
+ * Remove all geometry components from the geometry set.
+ */
void clear();
bool owns_direct_data() const;
+ /**
+ * Make sure that the geometry can be cached. This does not ensure ownership of object/collection
+ * instances. This is necessary because sometimes components only have read-only or editing
+ * access to their data, which might be freed later if this geometry set outlasts the data.
+ */
void ensure_owns_direct_data();
using AttributeForeachCallback =
@@ -335,46 +376,119 @@ struct GeometrySet {
using ForeachSubGeometryCallback = blender::FunctionRef<void(GeometrySet &geometry_set)>;
+ /**
+ * Modify every (recursive) instance separately. This is often more efficient than realizing all
+ * instances just to change the same thing on all of them.
+ */
void modify_geometry_sets(ForeachSubGeometryCallback callback);
/* Utility methods for creation. */
+ /**
+ * Create a new geometry set that only contains the given mesh.
+ */
static GeometrySet create_with_mesh(
Mesh *mesh, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
+ /**
+ * Create a new geometry set that only contains the given point cloud.
+ */
static GeometrySet create_with_pointcloud(
PointCloud *pointcloud, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
+ /**
+ * Create a new geometry set that only contains the given curve.
+ */
static GeometrySet create_with_curve(
CurveEval *curve, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
/* Utility methods for access. */
+ /**
+ * Returns true when the geometry set has a mesh component that has a mesh.
+ */
bool has_mesh() const;
+ /**
+ * Returns true when the geometry set has a point cloud component that has a point cloud.
+ */
bool has_pointcloud() const;
+ /**
+ * Returns true when the geometry set has an instances component that has at least one instance.
+ */
bool has_instances() const;
+ /**
+ * Returns true when the geometry set has a volume component that has a volume.
+ */
bool has_volume() const;
+ /**
+ * Returns true when the geometry set has a curve component that has a curve.
+ */
bool has_curve() const;
+ /**
+ * Returns true when the geometry set has any data that is not an instance.
+ */
bool has_realized_data() const;
+ /**
+ * Return true if the geometry set has any component that isn't empty.
+ */
bool is_empty() const;
+ /**
+ * Returns a read-only mesh or null.
+ */
const Mesh *get_mesh_for_read() const;
+ /**
+ * Returns a read-only point cloud of null.
+ */
const PointCloud *get_pointcloud_for_read() const;
+ /**
+ * Returns a read-only volume or null.
+ */
const Volume *get_volume_for_read() const;
+ /**
+ * Returns a read-only curve or null.
+ */
const CurveEval *get_curve_for_read() const;
+ /**
+ * Returns a mutable mesh or null. No ownership is transferred.
+ */
Mesh *get_mesh_for_write();
+ /**
+ * Returns a mutable point cloud or null. No ownership is transferred.
+ */
PointCloud *get_pointcloud_for_write();
+ /**
+ * Returns a mutable volume or null. No ownership is transferred.
+ */
Volume *get_volume_for_write();
+ /**
+ * Returns a mutable curve or null. No ownership is transferred.
+ */
CurveEval *get_curve_for_write();
/* Utility methods for replacement. */
+ /**
+ * Clear the existing mesh and replace it with the given one.
+ */
void replace_mesh(Mesh *mesh, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
+ /**
+ * Clear the existing point cloud and replace with the given one.
+ */
void replace_pointcloud(PointCloud *pointcloud,
GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
+ /**
+ * Clear the existing volume and replace with the given one.
+ */
void replace_volume(Volume *volume,
GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
+ /**
+ * Clear the existing curve and replace it with the given one.
+ */
void replace_curve(CurveEval *curve,
GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
private:
- /* Utility to retrieve a mutable component without creating it. */
+ /**
+ * Retrieve the pointer to a component without creating it if it does not exist,
+ * unlike #get_component_for_write.
+ */
GeometryComponent *get_component_ptr(GeometryComponentType type);
template<typename Component> Component *get_component_ptr()
{
@@ -383,7 +497,13 @@ struct GeometrySet {
}
};
-/** A geometry component that can store a mesh. */
+/**
+ * A geometry component that can store a mesh, storing the #Mesh data structure.
+ *
+ * Attributes are stored in the mesh itself, on any of the four attribute domains. Generic
+ * attributes are stored in contiguous arrays, but often built-in attributes are stored in an
+ * array of structs fashion for historical reasons, requiring more complex attribute access.
+ */
class MeshComponent : public GeometryComponent {
private:
Mesh *mesh_ = nullptr;
@@ -396,10 +516,25 @@ class MeshComponent : public GeometryComponent {
void clear();
bool has_mesh() const;
+ /**
+ * Clear the component and replace it with the new mesh.
+ */
void replace(Mesh *mesh, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
+ /**
+ * Return the mesh and clear the component. The caller takes over responsibility for freeing the
+ * mesh (if the component was responsible before).
+ */
Mesh *release();
+ /**
+ * Get the mesh from this component. This method can be used by multiple threads at the same
+ * time. Therefore, the returned mesh should not be modified. No ownership is transferred.
+ */
const Mesh *get_for_read() const;
+ /**
+ * Get the mesh from this component. This method can only be used when the component is mutable,
+ * i.e. it is not shared. The returned mesh can be modified. No ownership is transferred.
+ */
Mesh *get_for_write();
int attribute_domain_size(const AttributeDomain domain) const final;
@@ -420,7 +555,16 @@ class MeshComponent : public GeometryComponent {
const AttributeDomain to_domain) const final;
};
-/** A geometry component that stores a point cloud. */
+/**
+ * A geometry component that stores a point cloud, corresponding to the #PointCloud data structure.
+ * While a point cloud is technically a subset of a mesh in some respects, it is useful because of
+ * its simplicity, partly on a conceptual level for the user, but also in the code, though partly
+ * for historical reasons. Point clouds can also be rendered in special ways, based on the built-in
+ * `radius` attribute.
+ *
+ * Attributes on point clouds are all stored in contiguous arrays in its #CustomData,
+ * which makes them efficient to process, relative to some legacy built-in mesh attributes.
+ */
class PointCloudComponent : public GeometryComponent {
private:
PointCloud *pointcloud_ = nullptr;
@@ -433,11 +577,28 @@ class PointCloudComponent : public GeometryComponent {
void clear();
bool has_pointcloud() const;
+ /**
+ * Clear the component and replace it with the new point cloud.
+ */
void replace(PointCloud *pointcloud,
GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
+ /**
+ * Return the point cloud and clear the component. The caller takes over responsibility for
+ * freeing the point cloud (if the component was responsible before).
+ */
PointCloud *release();
+ /**
+ * Get the point cloud from this component. This method can be used by multiple threads at the
+ * same time. Therefore, the returned point cloud should not be modified. No ownership is
+ * transferred.
+ */
const PointCloud *get_for_read() const;
+ /**
+ * Get the point cloud from this component. This method can only be used when the component is
+ * mutable, i.e. it is not shared. The returned point cloud can be modified. No ownership is
+ * transferred.
+ */
PointCloud *get_for_write();
int attribute_domain_size(const AttributeDomain domain) const final;
@@ -453,7 +614,13 @@ class PointCloudComponent : public GeometryComponent {
const blender::bke::ComponentAttributeProviders *get_attribute_providers() const final;
};
-/** A geometry component that stores curve data, in other words, a group of splines. */
+/**
+ * A geometry component that stores curve data, in other words, a group of splines.
+ * Curves are stored differently than other geometry components, because the data structure used
+ * here does not correspond exactly to the #Curve DNA data structure. A #CurveEval is stored here
+ * instead, though the component does give access to a #Curve for interfacing with render engines
+ * and other areas of Blender that expect to use a data-block with an #ID.
+ */
class CurveComponent : public GeometryComponent {
private:
CurveEval *curve_ = nullptr;
@@ -475,6 +642,9 @@ class CurveComponent : public GeometryComponent {
void clear();
bool has_curve() const;
+ /**
+ * Clear the component and replace it with the new curve.
+ */
void replace(CurveEval *curve, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
CurveEval *release();
@@ -488,6 +658,10 @@ class CurveComponent : public GeometryComponent {
bool owns_direct_data() const override;
void ensure_owns_direct_data() override;
+ /**
+ * Create empty curve data used for rendering the spline's wire edges.
+ * \note See comment on #curve_for_render_ for further explanation.
+ */
const Curve *get_curve_for_render() const;
static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_CURVE;
@@ -501,6 +675,10 @@ class CurveComponent : public GeometryComponent {
const AttributeDomain to_domain) const final;
};
+/**
+ * Holds a reference to conceptually unique geometry or a pointer to object/collection data
+ * that is is instanced with a transform in #InstancesComponent.
+ */
class InstanceReference {
public:
enum class Type {
@@ -623,7 +801,19 @@ class InstanceReference {
}
};
-/** A geometry component that stores instances. */
+/**
+ * A geometry component that stores instances. The instance data can be any type described by
+ * #InstanceReference. Geometry instances can even contain instances themselves, for nested
+ * instancing. Each instance has an index into an array of unique instance data, and a transform.
+ * The component can also store generic attributes for each instance.
+ *
+ * The component works differently from other geometry components in that it stores
+ * data about instancing directly, rather than owning a pointer to a separate data structure.
+ *
+ * This component is not responsible for handling the interface to a render engine, or other
+ * areas that work with all visible geometry, that is handled by the dependency graph iterator
+ * (see `DEG_depsgraph_query.h`).
+ */
class InstancesComponent : public GeometryComponent {
private:
/**
@@ -636,18 +826,11 @@ class InstancesComponent : public GeometryComponent {
blender::Vector<int> instance_reference_handles_;
/** Transformation of the instances. */
blender::Vector<blender::float4x4> instance_transforms_;
- /**
- * IDs of the instances. They are used for consistency over multiple frames for things like
- * motion blur. Proper stable ID data that actually helps when rendering can only be generated
- * in some situations, so this vector is allowed to be empty, in which case the index of each
- * instance will be used for the final ID.
- */
- blender::Vector<int> instance_ids_;
- /* These almost unique ids are generated based on `ids_`, which might not contain unique ids at
- * all. They are *almost* unique, because under certain very unlikely circumstances, they are not
- * unique. Code using these ids should not crash when they are not unique but can generally
- * expect them to be unique. */
+ /* These almost unique ids are generated based on the `id` attribute, which might not contain
+ * unique ids at all. They are *almost* unique, because under certain very unlikely
+ * circumstances, they are not unique. Code using these ids should not crash when they are not
+ * unique but can generally expect them to be unique. */
mutable std::mutex almost_unique_ids_mutex_;
mutable blender::Array<int> almost_unique_ids_;
@@ -661,26 +844,47 @@ class InstancesComponent : public GeometryComponent {
void clear();
void reserve(int min_capacity);
+ /**
+ * Resize the transform, handles, and attributes to the specified capacity.
+ *
+ * \note This function should be used carefully, only when it's guaranteed
+ * that the data will be filled.
+ */
void resize(int capacity);
+ /**
+ * Returns a handle for the given reference.
+ * If the reference exists already, the handle of the existing reference is returned.
+ * Otherwise a new handle is added.
+ */
int add_reference(const InstanceReference &reference);
+ /**
+ * Add a reference to the instance reference with an index specified by the #instance_handle
+ * argument. For adding many instances, using #resize and accessing the transform array directly
+ * is preferred.
+ */
void add_instance(int instance_handle, const blender::float4x4 &transform);
blender::Span<InstanceReference> references() const;
void remove_unused_references();
+ /**
+ * If references have a collection or object type, convert them into geometry instances
+ * recursively. After that, the geometry sets can be edited. There may still be instances of
+ * other types of they can't be converted to geometry sets.
+ */
void ensure_geometry_instances();
+ /**
+ * With write access to the instances component, the data in the instanced geometry sets can be
+ * changed. This is a function on the component rather than each reference to ensure `const`
+ * correctness for that reason.
+ */
GeometrySet &geometry_set_from_reference(const int reference_index);
blender::Span<int> instance_reference_handles() const;
blender::MutableSpan<int> instance_reference_handles();
blender::MutableSpan<blender::float4x4> instance_transforms();
blender::Span<blender::float4x4> instance_transforms() const;
- blender::MutableSpan<int> instance_ids();
- blender::Span<int> instance_ids() const;
-
- blender::MutableSpan<int> instance_ids_ensure();
- void instance_ids_clear();
int instances_amount() const;
int references_amount() const;
@@ -706,7 +910,11 @@ class InstancesComponent : public GeometryComponent {
const blender::bke::ComponentAttributeProviders *get_attribute_providers() const final;
};
-/** A geometry component that stores volume grids. */
+/**
+ * A geometry component that stores volume grids, corresponding to the #Volume data structure.
+ * This component does not implement an attribute API, partly because storage of sparse volume
+ * information in grids is much more complicated than it is for other types
+ */
class VolumeComponent : public GeometryComponent {
private:
Volume *volume_ = nullptr;
@@ -719,10 +927,26 @@ class VolumeComponent : public GeometryComponent {
void clear();
bool has_volume() const;
+ /**
+ * Clear the component and replace it with the new volume.
+ */
void replace(Volume *volume, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
+ /**
+ * Return the volume and clear the component. The caller takes over responsibility for freeing
+ * the volume (if the component was responsible before).
+ */
Volume *release();
+ /**
+ * Get the volume from this component. This method can be used by multiple threads at the same
+ * time. Therefore, the returned volume should not be modified. No ownership is transferred.
+ */
const Volume *get_for_read() const;
+ /**
+ * Get the volume from this component. This method can only be used when the component is
+ * mutable, i.e. it is not shared. The returned volume can be modified. No ownership is
+ * transferred.
+ */
Volume *get_for_write();
bool owns_direct_data() const override;
@@ -755,13 +979,26 @@ class GeometryComponentFieldContext : public fn::FieldContext {
}
};
-class AttributeFieldInput : public fn::FieldInput {
+class GeometryFieldInput : public fn::FieldInput {
+ public:
+ using fn::FieldInput::FieldInput;
+
+ GVArray get_varray_for_context(const fn::FieldContext &context,
+ IndexMask mask,
+ ResourceScope &scope) const override;
+
+ virtual GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask mask) const = 0;
+};
+
+class AttributeFieldInput : public GeometryFieldInput {
private:
std::string name_;
public:
AttributeFieldInput(std::string name, const CPPType &type)
- : fn::FieldInput(type, name), name_(std::move(name))
+ : GeometryFieldInput(type, name), name_(std::move(name))
{
category_ = Category::NamedAttribute;
}
@@ -778,9 +1015,9 @@ class AttributeFieldInput : public fn::FieldInput {
return name_;
}
- GVArray get_varray_for_context(const fn::FieldContext &context,
- IndexMask mask,
- ResourceScope &scope) const override;
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask mask) const override;
std::string socket_inspection_name() const override;
@@ -788,16 +1025,16 @@ class AttributeFieldInput : public fn::FieldInput {
bool is_equal_to(const fn::FieldNode &other) const override;
};
-class IDAttributeFieldInput : public fn::FieldInput {
+class IDAttributeFieldInput : public GeometryFieldInput {
public:
- IDAttributeFieldInput() : fn::FieldInput(CPPType::get<int>())
+ IDAttributeFieldInput() : GeometryFieldInput(CPPType::get<int>())
{
category_ = Category::Generated;
}
- GVArray get_varray_for_context(const fn::FieldContext &context,
- IndexMask mask,
- ResourceScope &scope) const override;
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask mask) const override;
std::string socket_inspection_name() const override;
@@ -805,7 +1042,7 @@ class IDAttributeFieldInput : public fn::FieldInput {
bool is_equal_to(const fn::FieldNode &other) const override;
};
-class AnonymousAttributeFieldInput : public fn::FieldInput {
+class AnonymousAttributeFieldInput : public GeometryFieldInput {
private:
/**
* A strong reference is required to make sure that the referenced attribute is not removed
@@ -818,7 +1055,7 @@ class AnonymousAttributeFieldInput : public fn::FieldInput {
AnonymousAttributeFieldInput(StrongAnonymousAttributeID anonymous_id,
const CPPType &type,
std::string producer_name)
- : fn::FieldInput(type, anonymous_id.debug_name()),
+ : GeometryFieldInput(type, anonymous_id.debug_name()),
anonymous_id_(std::move(anonymous_id)),
producer_name_(producer_name)
{
@@ -834,9 +1071,9 @@ class AnonymousAttributeFieldInput : public fn::FieldInput {
return fn::Field<T>{field_input};
}
- GVArray get_varray_for_context(const fn::FieldContext &context,
- IndexMask mask,
- ResourceScope &scope) const override;
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask mask) const override;
std::string socket_inspection_name() const override;
diff --git a/source/blender/blenkernel/BKE_geometry_set_instances.hh b/source/blender/blenkernel/BKE_geometry_set_instances.hh
index e5b28e4fbab..98120b07f2d 100644
--- a/source/blender/blenkernel/BKE_geometry_set_instances.hh
+++ b/source/blender/blenkernel/BKE_geometry_set_instances.hh
@@ -20,6 +20,9 @@
namespace blender::bke {
+/**
+ * \note This doesn't extract instances from the "dupli" system for non-geometry-nodes instances.
+ */
GeometrySet object_get_evaluated_geometry_set(const Object &object);
/**
@@ -41,11 +44,19 @@ struct GeometryInstanceGroup {
Vector<float4x4> transforms;
};
+/**
+ * Return flattened vector of the geometry component's recursive instances. I.e. all collection
+ * instances and object instances will be expanded into the instances of their geometry components.
+ * Even the instances in those geometry components' will be included.
+ *
+ * \note For convenience (to avoid duplication in the caller), the returned vector also contains
+ * the argument geometry set.
+ *
+ * \note This doesn't extract instances from the "dupli" system for non-geometry-nodes instances.
+ */
void geometry_set_gather_instances(const GeometrySet &geometry_set,
Vector<GeometryInstanceGroup> &r_instance_groups);
-GeometrySet geometry_set_realize_instances(const GeometrySet &geometry_set);
-
/**
* Add information about all the attributes on every component of the type. The resulting info
* will contain the highest complexity data type and the highest priority domain among every
diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h
index d6cabbc1236..ecf2e1f32a0 100644
--- a/source/blender/blenkernel/BKE_global.h
+++ b/source/blender/blenkernel/BKE_global.h
@@ -37,35 +37,61 @@ struct Main;
typedef struct Global {
- /** Active pointers. */
+ /**
+ * Data for the current active blend file.
+ *
+ * Note that `CTX_data_main(C)` should be used where possible.
+ * Otherwise access via #G_MAIN.
+ */
struct Main *main;
- /** Strings: last saved */
- char ima[1024], lib[1024]; /* 1024 = FILE_MAX */
-
- /** When set: `G_MAIN->name` contains valid relative base path. */
- bool relbase_valid;
- bool save_over;
+ /** Last saved location for images. */
+ char ima[1024]; /* 1024 = FILE_MAX */
+ /** Last used location for library link/append. */
+ char lib[1024];
- /** Strings of recent opened files. */
+ /**
+ * Strings of recently opened files to show in the file menu.
+ * A list of #RecentFile read from #BLENDER_HISTORY_FILE.
+ */
struct ListBase recent_files;
- /** Has escape been pressed or Ctrl+C pressed in background mode, used for render quit. */
+ /**
+ * Set when Escape been pressed or `Ctrl-C` pressed in background mode.
+ * Used for render quit and some other background tasks such as baking.
+ */
bool is_break;
+ /**
+ * Blender is running without any Windows or OpenGLES context.
+ * Typically set by the `--background` command-line argument.
+ *
+ * Also enabled when build defines `WITH_PYTHON_MODULE` or `WITH_HEADLESS` are set
+ * (which use background mode by definition).
+ */
bool background;
+
+ /**
+ * Skip reading the startup file and user preferences.
+ * Also disable saving the preferences on exit (see #G_FLAG_USERPREF_NO_SAVE_ON_EXIT),
+ * see via the command line argument: `--factory-startup`.
+ */
bool factory_startup;
+ /**
+ * Set when the user is interactively moving (transforming) content.
+ * see: #G_TRANSFORM_OBJ and related flags.
+ */
short moving;
- /** To indicate render is busy, prevent render-window events etc. */
+ /** To indicate render is busy, prevent render-window events, animation playback etc. */
bool is_rendering;
/**
* Debug value, can be set from the UI and python, used for testing nonstandard features.
* DO NOT abuse it with generic checks like `if (G.debug_value > 0)`. Do not use it as bitflags.
* Only precise specific values should be checked for, to avoid unpredictable side-effects.
- * Please document here the value(s) you are using (or a range of values reserved to some area).
+ * Please document here the value(s) you are using (or a range of values reserved to some area):
* * -16384 and below: Reserved for python (add-ons) usage.
* * -1: Disable faster motion paths computation (since 08/2018).
* * 1 - 30: EEVEE debug/stats values (01/2018).
@@ -82,24 +108,50 @@ typedef struct Global {
*/
short debug_value;
- /** Saved to the blend file as #FileGlobal.globalf,
- * however this is now only used for runtime options. */
+ /**
+ * Saved to the blend file as #FileGlobal.globalf
+ *
+ * \note Currently this is only used for runtime options, adding flags to #G_FLAG_ALL_READFILE
+ * will cause them to be written and read to files.
+ */
int f;
struct {
- /** Logging vars (different loggers may use). */
+ /**
+ * Logging vars (different loggers may use).
+ * Set via `--log-level` command line argument.
+ */
int level;
- /** FILE handle or use stderr (we own this so close when done). */
+ /**
+ * FILE handle or use `stderr` (we own this so close when done).
+ * Set via `--log-file` command line argument.
+ */
void *file;
} log;
- /** debug flag, #G_DEBUG, #G_DEBUG_PYTHON & friends, set python or command line args */
+ /**
+ * Debug flag, #G_DEBUG, #G_DEBUG_PYTHON & friends, set via:
+ * - Command line arguments: `--debug`, `--debug-memory` ... etc.
+ * - Python API: `bpy.app.debug`, `bpy.app.debug_memory` ... etc.
+ */
int debug;
- /** This variable is written to / read from #FileGlobal.fileflags */
+ /**
+ * Control behavior of file reading/writing.
+ *
+ * This variable is written to / read from #FileGlobal.fileflags.
+ * See: #G_FILE_COMPRESS and related flags.
+ */
int fileflags;
- /** Message to use when auto execution fails. */
+ /**
+ * Message to show when loading a `.blend` file attempts to execute
+ * a Python script or driver-expression when doing so is disallowed.
+ *
+ * Set when `(G.f & G_FLAG_SCRIPT_AUTOEXEC_FAIL) == 0`,
+ * so users can be alerted to the reason why the file may not be behaving as expected.
+ * Typically Python drivers.
+ */
char autoexec_fail[200];
} Global;
diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h
index b58317f4815..a483d482bd5 100644
--- a/source/blender/blenkernel/BKE_gpencil.h
+++ b/source/blender/blenkernel/BKE_gpencil.h
@@ -86,65 +86,185 @@ struct bGPdata;
/* ------------ Grease-Pencil API ------------------ */
+/* clean vertex groups weights */
void BKE_gpencil_free_point_weights(struct MDeformVert *dvert);
void BKE_gpencil_free_stroke_weights(struct bGPDstroke *gps);
void BKE_gpencil_free_stroke_editcurve(struct bGPDstroke *gps);
+/* free stroke, doesn't unlink from any listbase */
void BKE_gpencil_free_stroke(struct bGPDstroke *gps);
+/* Free strokes belonging to a gp-frame */
bool BKE_gpencil_free_strokes(struct bGPDframe *gpf);
+/* Free all of a gp-layer's frames */
void BKE_gpencil_free_frames(struct bGPDlayer *gpl);
+/* Free all of the gp-layers for a viewport (list should be &gpd->layers or so) */
void BKE_gpencil_free_layers(struct ListBase *list);
+/** Free (or release) any data used by this grease pencil (does not free the gpencil itself). */
void BKE_gpencil_free_data(struct bGPdata *gpd, bool free_all);
+/**
+ * Delete grease pencil evaluated data
+ * \param gpd_eval: Grease pencil data-block
+ */
void BKE_gpencil_eval_delete(struct bGPdata *gpd_eval);
void BKE_gpencil_free_layer_masks(struct bGPDlayer *gpl);
+/**
+ * Tag data-block for depsgraph update.
+ * Wrapper to avoid include Depsgraph tag functions in other modules.
+ * \param gpd: Grease pencil data-block.
+ */
void BKE_gpencil_tag(struct bGPdata *gpd);
void BKE_gpencil_batch_cache_dirty_tag(struct bGPdata *gpd);
void BKE_gpencil_batch_cache_free(struct bGPdata *gpd);
+/**
+ * Ensure selection status of stroke is in sync with its points.
+ * \param gps: Grease pencil stroke
+ */
void BKE_gpencil_stroke_sync_selection(struct bGPdata *gpd, struct bGPDstroke *gps);
void BKE_gpencil_curve_sync_selection(struct bGPdata *gpd, struct bGPDstroke *gps);
+/* Assign unique stroke ID for selection. */
void BKE_gpencil_stroke_select_index_set(struct bGPdata *gpd, struct bGPDstroke *gps);
+/* Reset unique stroke ID for selection. */
void BKE_gpencil_stroke_select_index_reset(struct bGPDstroke *gps);
+/**
+ * Add a new gp-frame to the given layer.
+ * \param gpl: Grease pencil layer
+ * \param cframe: Frame number
+ * \return Pointer to new frame
+ */
struct bGPDframe *BKE_gpencil_frame_addnew(struct bGPDlayer *gpl, int cframe);
+/**
+ * Add a copy of the active gp-frame to the given layer.
+ * \param gpl: Grease pencil layer
+ * \param cframe: Frame number
+ * \return Pointer to new frame
+ */
struct bGPDframe *BKE_gpencil_frame_addcopy(struct bGPDlayer *gpl, int cframe);
+/**
+ * Add a new gp-layer and make it the active layer.
+ * \param gpd: Grease pencil data-block
+ * \param name: Name of the layer
+ * \param setactive: Set as active
+ * \param add_to_header: Used to force the layer added at header
+ * \return Pointer to new layer
+ */
struct bGPDlayer *BKE_gpencil_layer_addnew(struct bGPdata *gpd,
const char *name,
const bool setactive,
const bool add_to_header);
+/**
+ * Add a new grease pencil data-block.
+ * \param bmain: Main pointer
+ * \param name: Name of the datablock
+ * \return Pointer to new data-block
+ */
struct bGPdata *BKE_gpencil_data_addnew(struct Main *bmain, const char name[]);
+/**
+ * Make a copy of a given gpencil frame.
+ * \param gpf_src: Source grease pencil frame
+ * \return Pointer to new frame
+ */
struct bGPDframe *BKE_gpencil_frame_duplicate(const struct bGPDframe *gpf_src,
const bool dup_strokes);
+/**
+ * Make a copy of a given gpencil layer.
+ * \param gpl_src: Source grease pencil layer
+ * \return Pointer to new layer
+ */
struct bGPDlayer *BKE_gpencil_layer_duplicate(const struct bGPDlayer *gpl_src,
const bool dup_frames,
const bool dup_strokes);
+/**
+ * Make a copy of a given gpencil layer settings.
+ */
void BKE_gpencil_layer_copy_settings(const struct bGPDlayer *gpl_src, struct bGPDlayer *gpl_dst);
+/**
+ * Make a copy of strokes between gpencil frames.
+ * \param gpf_src: Source grease pencil frame
+ * \param gpf_dst: Destination grease pencil frame
+ */
void BKE_gpencil_frame_copy_strokes(struct bGPDframe *gpf_src, struct bGPDframe *gpf_dst);
+/* Create a hash with the list of selected frame number. */
void BKE_gpencil_frame_selected_hash(struct bGPdata *gpd, struct GHash *r_list);
+/* Make a copy of a given gpencil stroke editcurve */
struct bGPDcurve *BKE_gpencil_stroke_curve_duplicate(struct bGPDcurve *gpc_src);
+/**
+ * Make a copy of a given grease-pencil stroke.
+ * \param gps_src: Source grease pencil strokes.
+ * \param dup_points: Duplicate points data.
+ * \param dup_curve: Duplicate curve data.
+ * \return Pointer to new stroke.
+ */
struct bGPDstroke *BKE_gpencil_stroke_duplicate(struct bGPDstroke *gps_src,
const bool dup_points,
const bool dup_curve);
+/**
+ * Make a copy of a given gpencil data-block.
+ *
+ * XXX: Should this be deprecated?
+ */
struct bGPdata *BKE_gpencil_data_duplicate(struct Main *bmain,
const struct bGPdata *gpd,
bool internal_copy);
+/**
+ * Delete the last stroke of the given frame.
+ * \param gpl: Grease pencil layer
+ * \param gpf: Grease pencil frame
+ */
void BKE_gpencil_frame_delete_laststroke(struct bGPDlayer *gpl, struct bGPDframe *gpf);
/* materials */
+/**
+ * Reassign strokes using a material.
+ * \param gpd: Grease pencil data-block
+ * \param totcol: Total materials
+ * \param index: Index of the material
+ */
void BKE_gpencil_material_index_reassign(struct bGPdata *gpd, int totcol, int index);
+/**
+ * Remove strokes using a material.
+ * \param gpd: Grease pencil data-block
+ * \param index: Index of the material
+ * \return True if removed
+ */
bool BKE_gpencil_material_index_used(struct bGPdata *gpd, int index);
+/**
+ * Remap material
+ * \param gpd: Grease pencil data-block
+ * \param remap: Remap index
+ * \param remap_len: Remap length
+ */
void BKE_gpencil_material_remap(struct bGPdata *gpd,
const unsigned int *remap,
unsigned int remap_len);
+/**
+ * Load a table with material conversion index for merged materials.
+ * \param ob: Grease pencil object.
+ * \param hue_threshold: Threshold for Hue.
+ * \param sat_threshold: Threshold for Saturation.
+ * \param val_threshold: Threshold for Value.
+ * \param r_mat_table: return material table.
+ * \return True if done.
+ */
bool BKE_gpencil_merge_materials_table_get(struct Object *ob,
const float hue_threshold,
const float sat_threshold,
const float val_threshold,
struct GHash *r_mat_table);
+/**
+ * Merge similar materials
+ * \param ob: Grease pencil object
+ * \param hue_threshold: Threshold for Hue
+ * \param sat_threshold: Threshold for Saturation
+ * \param val_threshold: Threshold for Value
+ * \param r_removed: Number of materials removed
+ * \return True if done
+ */
bool BKE_gpencil_merge_materials(struct Object *ob,
const float hue_threshold,
const float sat_threshold,
@@ -152,12 +272,42 @@ bool BKE_gpencil_merge_materials(struct Object *ob,
int *r_removed);
/* statistics functions */
+/**
+ * Calc grease pencil statistics functions.
+ * \param gpd: Grease pencil data-block
+ */
void BKE_gpencil_stats_update(struct bGPdata *gpd);
+/**
+ * Create a new stroke, with pre-allocated data buffers.
+ * \param mat_idx: Index of the material
+ * \param totpoints: Total points
+ * \param thickness: Stroke thickness
+ * \return Pointer to new stroke
+ */
struct bGPDstroke *BKE_gpencil_stroke_new(int mat_idx, int totpoints, short thickness);
+/**
+ * Create a new stroke and add to frame.
+ * \param gpf: Grease pencil frame
+ * \param mat_idx: Material index
+ * \param totpoints: Total points
+ * \param thickness: Stroke thickness
+ * \param insert_at_head: Add to the head of the strokes list
+ * \return Pointer to new stroke
+ */
struct bGPDstroke *BKE_gpencil_stroke_add(
struct bGPDframe *gpf, int mat_idx, int totpoints, short thickness, const bool insert_at_head);
+/**
+ * Add a stroke and copy the temporary drawing color value
+ * from one of the existing stroke.
+ * \param gpf: Grease pencil frame
+ * \param existing: Stroke with the style to copy
+ * \param mat_idx: Material index
+ * \param totpoints: Total points
+ * \param thickness: Stroke thickness
+ * \return Pointer to new stroke
+ */
struct bGPDstroke *BKE_gpencil_stroke_add_existing_style(struct bGPDframe *gpf,
struct bGPDstroke *existing,
int mat_idx,
@@ -170,6 +320,11 @@ struct bGPDcurve *BKE_gpencil_stroke_editcurve_new(const int tot_curve_points);
#define GPENCIL_ALPHA_OPACITY_THRESH 0.001f
#define GPENCIL_STRENGTH_MIN 0.003f
+/**
+ * Check if the given layer is able to be edited or not.
+ * \param gpl: Grease pencil layer
+ * \return True if layer is editable
+ */
bool BKE_gpencil_layer_is_editable(const struct bGPDlayer *gpl);
/* How gpencil_layer_getframe() should behave when there
@@ -185,28 +340,121 @@ typedef enum eGP_GetFrame_Mode {
GP_GETFRAME_ADD_COPY = 2,
} eGP_GetFrame_Mode;
+/**
+ * Get the appropriate gp-frame from a given layer
+ * - this sets the layer's actframe var (if allowed to)
+ * - extension beyond range (if first gp-frame is after all frame in interest and cannot add)
+ *
+ * \param gpl: Grease pencil layer
+ * \param cframe: Frame number
+ * \param addnew: Add option
+ * \return Pointer to new frame
+ */
struct bGPDframe *BKE_gpencil_layer_frame_get(struct bGPDlayer *gpl,
int cframe,
eGP_GetFrame_Mode addnew);
+/**
+ * Look up the gp-frame on the requested frame number, but don't add a new one.
+ * \param gpl: Grease pencil layer
+ * \param cframe: Frame number
+ * \return Pointer to frame
+ */
struct bGPDframe *BKE_gpencil_layer_frame_find(struct bGPDlayer *gpl, int cframe);
+/**
+ * Delete the given frame from a layer.
+ * \param gpl: Grease pencil layer
+ * \param gpf: Grease pencil frame
+ * \return True if delete was done
+ */
bool BKE_gpencil_layer_frame_delete(struct bGPDlayer *gpl, struct bGPDframe *gpf);
+/**
+ * Get layer by name
+ * \param gpd: Grease pencil data-block
+ * \param name: Layer name
+ * \return Pointer to layer
+ */
struct bGPDlayer *BKE_gpencil_layer_named_get(struct bGPdata *gpd, const char *name);
+/**
+ * Get the active grease pencil layer for editing.
+ * \param gpd: Grease pencil data-block
+ * \return Pointer to layer
+ */
struct bGPDlayer *BKE_gpencil_layer_active_get(struct bGPdata *gpd);
+/**
+ * Set active grease pencil layer.
+ * \param gpd: Grease pencil data-block
+ * \param active: Grease pencil layer to set as active
+ */
void BKE_gpencil_layer_active_set(struct bGPdata *gpd, struct bGPDlayer *active);
+/**
+ * Delete grease pencil layer.
+ * \param gpd: Grease pencil data-block
+ * \param gpl: Grease pencil layer
+ */
void BKE_gpencil_layer_delete(struct bGPdata *gpd, struct bGPDlayer *gpl);
+/**
+ * Set locked layers for autolock mode.
+ * \param gpd: Grease pencil data-block
+ * \param unlock: Unlock flag
+ */
void BKE_gpencil_layer_autolock_set(struct bGPdata *gpd, const bool unlock);
+/**
+ * Add grease pencil mask layer.
+ * \param gpl: Grease pencil layer
+ * \param name: Name of the mask
+ * \return Pointer to new mask layer
+ */
struct bGPDlayer_Mask *BKE_gpencil_layer_mask_add(struct bGPDlayer *gpl, const char *name);
+/**
+ * Remove grease pencil mask layer.
+ * \param gpl: Grease pencil layer
+ * \param mask: Grease pencil mask layer
+ */
void BKE_gpencil_layer_mask_remove(struct bGPDlayer *gpl, struct bGPDlayer_Mask *mask);
+/**
+ * Remove any reference to mask layer.
+ * \param gpd: Grease pencil data-block
+ * \param name: Name of the mask layer
+ */
void BKE_gpencil_layer_mask_remove_ref(struct bGPdata *gpd, const char *name);
+/**
+ * Get mask layer by name.
+ * \param gpl: Grease pencil layer
+ * \param name: Mask name
+ * \return Pointer to mask layer
+ */
struct bGPDlayer_Mask *BKE_gpencil_layer_mask_named_get(struct bGPDlayer *gpl, const char *name);
+/**
+ * Sort grease pencil mask layers.
+ * \param gpd: Grease pencil data-block
+ * \param gpl: Grease pencil layer
+ */
void BKE_gpencil_layer_mask_sort(struct bGPdata *gpd, struct bGPDlayer *gpl);
+/**
+ * Sort all grease pencil mask layer.
+ * \param gpd: Grease pencil data-block
+ */
void BKE_gpencil_layer_mask_sort_all(struct bGPdata *gpd);
+/**
+ * Make a copy of a given gpencil mask layers.
+ */
void BKE_gpencil_layer_mask_copy(const struct bGPDlayer *gpl_src, struct bGPDlayer *gpl_dst);
+/**
+ * Clean any invalid mask layer.
+ */
void BKE_gpencil_layer_mask_cleanup(struct bGPdata *gpd, struct bGPDlayer *gpl);
+/**
+ * Clean any invalid mask layer for all layers.
+ */
void BKE_gpencil_layer_mask_cleanup_all_layers(struct bGPdata *gpd);
+/**
+ * Sort grease pencil frames.
+ * \param gpl: Grease pencil layer
+ * \param r_has_duplicate_frames: Duplicated frames flag
+ */
void BKE_gpencil_layer_frames_sort(struct bGPDlayer *gpl, bool *r_has_duplicate_frames);
struct bGPDlayer *BKE_gpencil_layer_get_by_name(struct bGPdata *gpd,
@@ -214,14 +462,43 @@ struct bGPDlayer *BKE_gpencil_layer_get_by_name(struct bGPdata *gpd,
int first_if_not_found);
/* Brush */
+/**
+ * Get grease pencil material from brush.
+ * \param brush: Brush
+ * \return Pointer to material
+ */
struct Material *BKE_gpencil_brush_material_get(struct Brush *brush);
+/**
+ * Set grease pencil brush material.
+ * \param brush: Brush
+ * \param material: Material
+ */
void BKE_gpencil_brush_material_set(struct Brush *brush, struct Material *material);
/* Object */
+/**
+ * Get active color, and add all default settings if we don't find anything.
+ * \param ob: Grease pencil object
+ * \return Material pointer
+ */
struct Material *BKE_gpencil_object_material_ensure_active(struct Object *ob);
+/**
+ * Adds the pinned material to the object if necessary.
+ * \param bmain: Main pointer
+ * \param ob: Grease pencil object
+ * \param brush: Brush
+ * \return Pointer to material
+ */
struct Material *BKE_gpencil_object_material_ensure_from_brush(struct Main *bmain,
struct Object *ob,
struct Brush *brush);
+/**
+ * Assigns the material to object (if not already present) and returns its index (mat_nr).
+ * \param bmain: Main pointer
+ * \param ob: Grease pencil object
+ * \param material: Material
+ * \return Index of the material
+ */
int BKE_gpencil_object_material_ensure(struct Main *bmain,
struct Object *ob,
struct Material *material);
@@ -230,41 +507,140 @@ struct Material *BKE_gpencil_object_material_ensure_by_name(struct Main *bmain,
const char *name,
int *r_index);
+/**
+ * Creates a new grease-pencil material and assigns it to object.
+ * \param bmain: Main pointer
+ * \param ob: Grease pencil object
+ * \param name: Material name
+ * \param r_index: value is set to zero based index of the new material if \a r_index is not NULL.
+ * \return Material pointer.
+ */
struct Material *BKE_gpencil_object_material_new(struct Main *bmain,
struct Object *ob,
const char *name,
int *r_index);
+/**
+ * Get material index (0-based like mat_nr not actcol).
+ * \param ob: Grease pencil object
+ * \param ma: Material
+ * \return Index of the material
+ */
int BKE_gpencil_object_material_index_get(struct Object *ob, struct Material *ma);
int BKE_gpencil_object_material_index_get_by_name(struct Object *ob, const char *name);
+/**
+ * Returns the material for a brush with respect to its pinned state.
+ * \param ob: Grease pencil object
+ * \param brush: Brush
+ * \return Material pointer
+ */
struct Material *BKE_gpencil_object_material_from_brush_get(struct Object *ob,
struct Brush *brush);
+/**
+ * Returns the material index for a brush with respect to its pinned state.
+ * \param ob: Grease pencil object
+ * \param brush: Brush
+ * \return Material index.
+ */
int BKE_gpencil_object_material_get_index_from_brush(struct Object *ob, struct Brush *brush);
+/**
+ * Guaranteed to return a material assigned to object. Returns never NULL.
+ * \param bmain: Main pointer
+ * \param ob: Grease pencil object
+ * \return Material pointer.
+ */
struct Material *BKE_gpencil_object_material_ensure_from_active_input_toolsettings(
struct Main *bmain, struct Object *ob, struct ToolSettings *ts);
+/**
+ * Guaranteed to return a material assigned to object. Returns never NULL.
+ * \param bmain: Main pointer
+ * \param ob: Grease pencil object.
+ * \param brush: Brush
+ * \return Material pointer
+ */
struct Material *BKE_gpencil_object_material_ensure_from_active_input_brush(struct Main *bmain,
struct Object *ob,
struct Brush *brush);
+/**
+ * Guaranteed to return a material assigned to object. Returns never NULL.
+ * Only use this for materials unrelated to user input.
+ * \param ob: Grease pencil object
+ * \return Material pointer
+ */
struct Material *BKE_gpencil_object_material_ensure_from_active_input_material(struct Object *ob);
+/**
+ * Check if stroke has any point selected
+ * \param gps: Grease pencil stroke
+ * \return True if selected
+ */
bool BKE_gpencil_stroke_select_check(const struct bGPDstroke *gps);
/* vertex groups */
+/**
+ * Ensure stroke has vertex group.
+ * \param gps: Grease pencil stroke
+ */
void BKE_gpencil_dvert_ensure(struct bGPDstroke *gps);
+/**
+ * Remove a vertex group.
+ * \param ob: Grease pencil object
+ * \param defgroup: deform group
+ */
void BKE_gpencil_vgroup_remove(struct Object *ob, struct bDeformGroup *defgroup);
+/**
+ * Make a copy of a given gpencil weights.
+ * \param gps_src: Source grease pencil stroke
+ * \param gps_dst: Destination grease pencil stroke
+ */
void BKE_gpencil_stroke_weights_duplicate(struct bGPDstroke *gps_src, struct bGPDstroke *gps_dst);
/* Set active frame by layer. */
+/**
+ * Set current grease pencil active frame.
+ * \param depsgraph: Current depsgraph
+ * \param gpd: Grease pencil data-block.
+ */
void BKE_gpencil_frame_active_set(struct Depsgraph *depsgraph, struct bGPdata *gpd);
+/**
+ * Get range of selected frames in layer.
+ * Always the active frame is considered as selected, so if no more selected the range
+ * will be equal to the current active frame.
+ * \param gpl: Layer.
+ * \param r_initframe: Number of first selected frame.
+ * \param r_endframe: Number of last selected frame.
+ */
void BKE_gpencil_frame_range_selected(struct bGPDlayer *gpl, int *r_initframe, int *r_endframe);
+/**
+ * Get Falloff factor base on frame range
+ * \param gpf: Frame.
+ * \param actnum: Number of active frame in layer.
+ * \param f_init: Number of first selected frame.
+ * \param f_end: Number of last selected frame.
+ * \param cur_falloff: Curve with falloff factors.
+ */
float BKE_gpencil_multiframe_falloff_calc(
struct bGPDframe *gpf, int actnum, int f_init, int f_end, struct CurveMapping *cur_falloff);
+/**
+ * Create a default palette.
+ * \param bmain: Main pointer
+ * \param scene: Scene
+ */
void BKE_gpencil_palette_ensure(struct Main *bmain, struct Scene *scene);
+/**
+ * Create grease pencil strokes from image
+ * \param sima: Image
+ * \param gpd: Grease pencil data-block
+ * \param gpf: Grease pencil frame
+ * \param size: Size
+ * \param mask: Mask
+ * \return True if done
+ */
bool BKE_gpencil_from_image(struct SpaceImage *sima,
struct bGPdata *gpd,
struct bGPDframe *gpf,
@@ -272,7 +648,9 @@ bool BKE_gpencil_from_image(struct SpaceImage *sima,
const bool mask);
/* Iterators */
-/* frame & stroke are NULL if it is a layer callback. */
+/**
+ * Frame & stroke are NULL if it is a layer callback.
+ */
typedef void (*gpIterCb)(struct bGPDlayer *layer,
struct bGPDframe *frame,
struct bGPDstroke *stroke,
@@ -294,17 +672,45 @@ void BKE_gpencil_visible_stroke_advanced_iter(struct ViewLayer *view_layer,
extern void (*BKE_gpencil_batch_cache_dirty_tag_cb)(struct bGPdata *gpd);
extern void (*BKE_gpencil_batch_cache_free_cb)(struct bGPdata *gpd);
+/**
+ * Update original pointers in evaluated frame.
+ * \param gpf_orig: Original grease-pencil frame.
+ * \param gpf_eval: Evaluated grease pencil frame.
+ */
void BKE_gpencil_frame_original_pointers_update(const struct bGPDframe *gpf_orig,
const struct bGPDframe *gpf_eval);
+/**
+ * Update pointers of eval data to original data to keep references.
+ * \param ob_orig: Original grease pencil object
+ * \param ob_eval: Evaluated grease pencil object
+ */
void BKE_gpencil_update_orig_pointers(const struct Object *ob_orig, const struct Object *ob_eval);
+/**
+ * Get parent matrix, including layer parenting.
+ * \param depsgraph: Depsgraph
+ * \param obact: Grease pencil object
+ * \param gpl: Grease pencil layer
+ * \param diff_mat: Result parent matrix
+ */
void BKE_gpencil_layer_transform_matrix_get(const struct Depsgraph *depsgraph,
struct Object *obact,
struct bGPDlayer *gpl,
float diff_mat[4][4]);
+/**
+ * Update parent matrix and local transforms.
+ * \param depsgraph: Depsgraph
+ * \param ob: Grease pencil object
+ */
void BKE_gpencil_update_layer_transforms(const struct Depsgraph *depsgraph, struct Object *ob);
+/**
+ * Find material by name prefix.
+ * \param ob: Object pointer
+ * \param name_prefix: Prefix name of the material
+ * \return Index
+ */
int BKE_gpencil_material_find_index_by_name_prefix(struct Object *ob, const char *name_prefix);
void BKE_gpencil_blend_read_data(struct BlendDataReader *reader, struct bGPdata *gpd);
diff --git a/source/blender/blenkernel/BKE_gpencil_curve.h b/source/blender/blenkernel/BKE_gpencil_curve.h
index 9cbe67af9c1..044e2ff2336 100644
--- a/source/blender/blenkernel/BKE_gpencil_curve.h
+++ b/source/blender/blenkernel/BKE_gpencil_curve.h
@@ -35,6 +35,17 @@ struct bGPDlayer;
struct bGPDstroke;
struct bGPdata;
+/**
+ * Convert a curve object to grease pencil stroke.
+ *
+ * \param bmain: Main thread pointer
+ * \param scene: Original scene.
+ * \param ob_gp: Grease pencil object to add strokes.
+ * \param ob_cu: Curve to convert.
+ * \param use_collections: Create layers using collection names.
+ * \param scale_thickness: Scale thickness factor.
+ * \param sample: Sample distance, zero to disable.
+ */
void BKE_gpencil_convert_curve(struct Main *bmain,
struct Scene *scene,
struct Object *ob_gp,
@@ -43,24 +54,42 @@ void BKE_gpencil_convert_curve(struct Main *bmain,
const float scale_thickness,
const float sample);
+/**
+ * Creates a bGPDcurve by doing a cubic curve fitting on the grease pencil stroke points.
+ */
struct bGPDcurve *BKE_gpencil_stroke_editcurve_generate(struct bGPDstroke *gps,
const float error_threshold,
const float corner_angle,
const float stroke_radius);
+/**
+ * Updates the edit-curve for a stroke. Frees the old curve if one exists and generates a new one.
+ */
void BKE_gpencil_stroke_editcurve_update(struct bGPdata *gpd,
struct bGPDlayer *gpl,
struct bGPDstroke *gps);
+/**
+ * Sync the selection from stroke to edit-curve.
+ */
void BKE_gpencil_editcurve_stroke_sync_selection(struct bGPdata *gpd,
struct bGPDstroke *gps,
struct bGPDcurve *gpc);
+/**
+ * Sync the selection from edit-curve to stroke.
+ */
void BKE_gpencil_stroke_editcurve_sync_selection(struct bGPdata *gpd,
struct bGPDstroke *gps,
struct bGPDcurve *gpc);
void BKE_gpencil_strokes_selected_update_editcurve(struct bGPdata *gpd);
void BKE_gpencil_strokes_selected_sync_selection_editcurve(struct bGPdata *gpd);
+/**
+ * Recalculate stroke points with the edit-curve of the stroke.
+ */
void BKE_gpencil_stroke_update_geometry_from_editcurve(struct bGPDstroke *gps,
const uint resolution,
const bool is_adaptive);
+/**
+ * Recalculate the handles of the edit curve of a grease pencil stroke.
+ */
void BKE_gpencil_editcurve_recalculate_handles(struct bGPDstroke *gps);
void BKE_gpencil_editcurve_subdivide(struct bGPDstroke *gps, const int cuts);
diff --git a/source/blender/blenkernel/BKE_gpencil_geom.h b/source/blender/blenkernel/BKE_gpencil_geom.h
index 41b1bba10ba..4b9671c7881 100644
--- a/source/blender/blenkernel/BKE_gpencil_geom.h
+++ b/source/blender/blenkernel/BKE_gpencil_geom.h
@@ -38,38 +38,130 @@ struct bGPDspoint;
struct bGPDstroke;
struct bGPdata;
-/* Object boundbox. */
+/* Object bound-box. */
+
+/**
+ * Get min/max bounds of all strokes in grease pencil data-block.
+ * \param gpd: Grease pencil data-block
+ * \param r_min: Result minimum coordinates
+ * \param r_max: Result maximum coordinates
+ * \return True if it was possible to calculate
+ */
bool BKE_gpencil_data_minmax(const struct bGPdata *gpd, float r_min[3], float r_max[3]);
+/**
+ * Get min/max coordinate bounds for single stroke.
+ * \param gps: Grease pencil stroke
+ * \param use_select: Include only selected points
+ * \param r_min: Result minimum coordinates
+ * \param r_max: Result maximum coordinates
+ * \return True if it was possible to calculate
+ */
bool BKE_gpencil_stroke_minmax(const struct bGPDstroke *gps,
const bool use_select,
float r_min[3],
float r_max[3]);
+/**
+ * Get grease pencil object bounding box.
+ * \param ob: Grease pencil object
+ * \return Bounding box
+ */
struct BoundBox *BKE_gpencil_boundbox_get(struct Object *ob);
+/**
+ * Compute center of bounding box.
+ * \param gpd: Grease pencil data-block
+ * \param r_centroid: Location of the center
+ */
void BKE_gpencil_centroid_3d(struct bGPdata *gpd, float r_centroid[3]);
+/**
+ * Compute stroke bounding box.
+ * \param gps: Grease pencil Stroke
+ */
void BKE_gpencil_stroke_boundingbox_calc(struct bGPDstroke *gps);
-/* stroke geometry utilities */
+/* Stroke geometry utilities. */
+
+/**
+ * Calculate stroke normals.
+ * \param gps: Grease pencil stroke
+ * \param r_normal: Return Normal vector normalized
+ */
void BKE_gpencil_stroke_normal(const struct bGPDstroke *gps, float r_normal[3]);
+/**
+ * Reduce a series of points to a simplified version,
+ * but maintains the general shape of the series.
+ *
+ * Ramer - Douglas - Peucker algorithm
+ * by http://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm
+ * \param gpd: Grease pencil data-block
+ * \param gps: Grease pencil stroke
+ * \param epsilon: Epsilon value to define precision of the algorithm
+ */
void BKE_gpencil_stroke_simplify_adaptive(struct bGPdata *gpd,
struct bGPDstroke *gps,
float epsilon);
+/**
+ * Simplify alternate vertex of stroke except extremes.
+ * \param gpd: Grease pencil data-block
+ * \param gps: Grease pencil stroke
+ */
void BKE_gpencil_stroke_simplify_fixed(struct bGPdata *gpd, struct bGPDstroke *gps);
+/**
+ * Subdivide a stroke
+ * \param gpd: Grease pencil data-block
+ * \param gps: Stroke
+ * \param level: Level of subdivision
+ * \param type: Type of subdivision
+ */
void BKE_gpencil_stroke_subdivide(struct bGPdata *gpd,
struct bGPDstroke *gps,
int level,
int type);
+/**
+ * Trim stroke to the first intersection or loop.
+ * \param gps: Stroke data
+ */
bool BKE_gpencil_stroke_trim(struct bGPdata *gpd, struct bGPDstroke *gps);
+/**
+ * Reduce a series of points when the distance is below a threshold.
+ * Special case for first and last points (both are kept) for other points,
+ * the merge point always is at first point.
+ *
+ * \param gpd: Grease pencil data-block.
+ * \param gpf: Grease Pencil frame.
+ * \param gps: Grease Pencil stroke.
+ * \param threshold: Distance between points.
+ * \param use_unselected: Set to true to analyze all stroke and not only selected points.
+ */
void BKE_gpencil_stroke_merge_distance(struct bGPdata *gpd,
struct bGPDframe *gpf,
struct bGPDstroke *gps,
const float threshold,
const bool use_unselected);
+/**
+ * Get points of stroke always flat to view not affected
+ * by camera view or view position.
+ * \param points: Array of grease pencil points (3D)
+ * \param totpoints: Total of points
+ * \param points2d: Result array of 2D points
+ * \param r_direction: Return Concave (-1), Convex (1), or Auto-detect (0)
+ */
void BKE_gpencil_stroke_2d_flat(const struct bGPDspoint *points,
int totpoints,
float (*points2d)[2],
int *r_direction);
+/**
+ * Get points of stroke always flat to view not affected by camera view or view position
+ * using another stroke as reference.
+ * \param ref_points: Array of reference points (3D)
+ * \param ref_totpoints: Total reference points
+ * \param points: Array of points to flat (3D)
+ * \param totpoints: Total points
+ * \param points2d: Result array of 2D points
+ * \param scale: Scale factor
+ * \param r_direction: Return Concave (-1), Convex (1), or Auto-detect (0)
+ */
void BKE_gpencil_stroke_2d_flat_ref(const struct bGPDspoint *ref_points,
int ref_totpoints,
const struct bGPDspoint *points,
@@ -77,10 +169,28 @@ void BKE_gpencil_stroke_2d_flat_ref(const struct bGPDspoint *ref_points,
float (*points2d)[2],
const float scale,
int *r_direction);
+/**
+ * Triangulate stroke to generate data for filling areas.
+ * \param gps: Grease pencil stroke
+ */
void BKE_gpencil_stroke_fill_triangulate(struct bGPDstroke *gps);
+/**
+ * Recalc all internal geometry data for the stroke
+ * \param gpd: Grease pencil data-block
+ * \param gps: Grease pencil stroke
+ */
void BKE_gpencil_stroke_geometry_update(struct bGPdata *gpd, struct bGPDstroke *gps);
+/**
+ * Update Stroke UV data.
+ * \param gps: Grease pencil stroke
+ */
void BKE_gpencil_stroke_uv_update(struct bGPDstroke *gps);
+/**
+ * Apply grease pencil Transforms.
+ * \param gpd: Grease pencil data-block
+ * \param mat: Transformation matrix
+ */
void BKE_gpencil_transform(struct bGPdata *gpd, const float mat[4][4]);
typedef struct GPencilPointCoordinates {
@@ -90,27 +200,93 @@ typedef struct GPencilPointCoordinates {
float pressure;
} GPencilPointCoordinates;
+/**
+ * \note Used for "move only origins" in object_data_transform.c.
+ */
int BKE_gpencil_stroke_point_count(const struct bGPdata *gpd);
+/**
+ * \note Used for "move only origins" in object_data_transform.c.
+ */
void BKE_gpencil_point_coords_get(struct bGPdata *gpd, GPencilPointCoordinates *elem_data);
+/**
+ * \note Used for "move only origins" in object_data_transform.c.
+ */
void BKE_gpencil_point_coords_apply(struct bGPdata *gpd, const GPencilPointCoordinates *elem_data);
+/**
+ * \note Used for "move only origins" in object_data_transform.c.
+ */
void BKE_gpencil_point_coords_apply_with_mat4(struct bGPdata *gpd,
const GPencilPointCoordinates *elem_data,
const float mat[4][4]);
+/**
+ * Resample a stroke
+ * \param gpd: Grease pencil data-block
+ * \param gps: Stroke to sample
+ * \param dist: Distance of one segment
+ */
bool BKE_gpencil_stroke_sample(struct bGPdata *gpd,
struct bGPDstroke *gps,
const float dist,
const bool select);
-bool BKE_gpencil_stroke_smooth_point(struct bGPDstroke *gps, int i, float inf);
+/**
+ * Apply smooth position to stroke point.
+ * \param gps: Stroke to smooth
+ * \param i: Point index
+ * \param inf: Amount of smoothing to apply
+ * \param smooth_caps: Apply smooth to stroke extremes
+ */
+bool BKE_gpencil_stroke_smooth_point(struct bGPDstroke *gps,
+ int i,
+ float inf,
+ const bool smooth_caps);
+/**
+ * Apply smooth strength to stroke point.
+ * \param gps: Stroke to smooth
+ * \param point_index: Point index
+ * \param influence: Amount of smoothing to apply
+ */
bool BKE_gpencil_stroke_smooth_strength(struct bGPDstroke *gps, int point_index, float influence);
+/**
+ * Apply smooth for thickness to stroke point (use pressure).
+ * \param gps: Stroke to smooth
+ * \param point_index: Point index
+ * \param influence: Amount of smoothing to apply
+ */
bool BKE_gpencil_stroke_smooth_thickness(struct bGPDstroke *gps, int point_index, float influence);
+/**
+ * Apply smooth for UV rotation to stroke point (use pressure).
+ * \param gps: Stroke to smooth
+ * \param point_index: Point index
+ * \param influence: Amount of smoothing to apply
+ */
bool BKE_gpencil_stroke_smooth_uv(struct bGPDstroke *gps, int point_index, float influence);
+/**
+ * Close grease pencil stroke.
+ * \param gps: Stroke to close
+ */
bool BKE_gpencil_stroke_close(struct bGPDstroke *gps);
+/**
+ * Dissolve points in stroke.
+ * \param gpd: Grease pencil data-block
+ * \param gpf: Grease pencil frame
+ * \param gps: Grease pencil stroke
+ * \param tag: Type of tag for point
+ */
void BKE_gpencil_dissolve_points(struct bGPdata *gpd,
struct bGPDframe *gpf,
struct bGPDstroke *gps,
const short tag);
+/**
+ * Backbone stretch similar to Freestyle.
+ * \param gps: Stroke to sample.
+ * \param dist: Length of the added section.
+ * \param overshoot_fac: Relative length of the curve which is used to determine the extension.
+ * \param mode: Affect to Start, End or Both extremes (0->Both, 1->Start, 2->End).
+ * \param follow_curvature: True for approximating curvature of given overshoot.
+ * \param extra_point_count: When follow_curvature is true, use this amount of extra points.
+ */
bool BKE_gpencil_stroke_stretch(struct bGPDstroke *gps,
const float dist,
const float overshoot_fac,
@@ -120,9 +296,20 @@ bool BKE_gpencil_stroke_stretch(struct bGPDstroke *gps,
const float segment_influence,
const float max_angle,
const bool invert_curvature);
+/**
+ * Trim stroke to needed segments.
+ * \param gps: Target stroke.
+ * \param index_from: the index of the first point to be used in the trimmed result.
+ * \param index_to: the index of the last point to be used in the trimmed result.
+ */
bool BKE_gpencil_stroke_trim_points(struct bGPDstroke *gps,
const int index_from,
const int index_to);
+/**
+ * Split the given stroke into several new strokes, partitioning
+ * it based on whether the stroke points have a particular flag
+ * is set (e.g. #GP_SPOINT_SELECT in most cases, but not always).
+ */
struct bGPDstroke *BKE_gpencil_stroke_delete_tagged_points(struct bGPdata *gpd,
struct bGPDframe *gpf,
struct bGPDstroke *gps,
@@ -138,33 +325,84 @@ void BKE_gpencil_curve_delete_tagged_points(struct bGPdata *gpd,
struct bGPDcurve *gpc,
int tag_flags);
+/**
+ * Flip stroke.
+ */
void BKE_gpencil_stroke_flip(struct bGPDstroke *gps);
+/**
+ * Split stroke.
+ * \param gpd: Grease pencil data-block.
+ * \param gpf: Grease pencil frame.
+ * \param gps: Grease pencil original stroke.
+ * \param before_index: Position of the point to split.
+ * \param remaining_gps: Secondary stroke after split.
+ * \return True if the split was done
+ */
bool BKE_gpencil_stroke_split(struct bGPdata *gpd,
struct bGPDframe *gpf,
struct bGPDstroke *gps,
const int before_index,
struct bGPDstroke **remaining_gps);
+/**
+ * Shrink the stroke by length.
+ * \param gps: Stroke to shrink
+ * \param dist: delta length
+ * \param mode: 1->Start, 2->End
+ */
bool BKE_gpencil_stroke_shrink(struct bGPDstroke *gps, const float dist, const short mode);
+/**
+ * Calculate grease pencil stroke length.
+ * \param gps: Grease pencil stroke.
+ * \param use_3d: Set to true to use 3D points.
+ * \return Length of the stroke.
+ */
float BKE_gpencil_stroke_length(const struct bGPDstroke *gps, bool use_3d);
+/** Calculate grease pencil stroke length between points. */
float BKE_gpencil_stroke_segment_length(const struct bGPDstroke *gps,
const int start_index,
const int end_index,
bool use_3d);
+/**
+ * Set a random color to stroke using vertex color.
+ * \param gps: Stroke
+ */
void BKE_gpencil_stroke_set_random_color(struct bGPDstroke *gps);
+/**
+ * Join two strokes using the shortest distance (reorder stroke if necessary).
+ */
void BKE_gpencil_stroke_join(struct bGPDstroke *gps_a,
struct bGPDstroke *gps_b,
const bool leave_gaps,
const bool fit_thickness,
const bool smooth);
+/**
+ * Copy the stroke of the frame to all frames selected (except current).
+ */
void BKE_gpencil_stroke_copy_to_keyframes(struct bGPdata *gpd,
struct bGPDlayer *gpl,
struct bGPDframe *gpf,
struct bGPDstroke *gps,
const bool tail);
+/**
+ * Convert a mesh object to grease pencil stroke.
+ *
+ * \param bmain: Main thread pointer.
+ * \param depsgraph: Original depsgraph.
+ * \param scene: Original scene.
+ * \param ob_gp: Grease pencil object to add strokes.
+ * \param ob_mesh: Mesh to convert.
+ * \param angle: Limit angle to consider a edge-loop ends.
+ * \param thickness: Thickness of the strokes.
+ * \param offset: Offset along the normals.
+ * \param matrix: Transformation matrix.
+ * \param frame_offset: Destination frame number offset.
+ * \param use_seams: Only export seam edges.
+ * \param use_faces: Export faces as filled strokes.
+ */
bool BKE_gpencil_convert_mesh(struct Main *bmain,
struct Depsgraph *depsgraph,
struct Scene *scene,
@@ -179,24 +417,56 @@ bool BKE_gpencil_convert_mesh(struct Main *bmain,
const bool use_faces,
const bool use_vgroups);
+/**
+ * Subdivide the grease pencil stroke so the number of points is target_number.
+ * Does not change the shape of the stroke. The new points will be distributed as
+ * uniformly as possible by repeatedly subdividing the current longest edge.
+ *
+ * \param gps: The stroke to be up-sampled.
+ * \param target_number: The number of points the up-sampled stroke should have.
+ * \param select: Select/Deselect the stroke.
+ */
void BKE_gpencil_stroke_uniform_subdivide(struct bGPdata *gpd,
struct bGPDstroke *gps,
const uint32_t target_number,
const bool select);
+/**
+ * Stroke to view space
+ * Transforms a stroke to view space.
+ * This allows for manipulations in 2D but also easy conversion back to 3D.
+ * \note also takes care of parent space transform.
+ */
void BKE_gpencil_stroke_to_view_space(struct RegionView3D *rv3d,
struct bGPDstroke *gps,
const float diff_mat[4][4]);
+/**
+ * Stroke from view space
+ * Transforms a stroke from view space back to world space.
+ * Inverse of #BKE_gpencil_stroke_to_view_space
+ * \note also takes care of parent space transform.
+ */
void BKE_gpencil_stroke_from_view_space(struct RegionView3D *rv3d,
struct bGPDstroke *gps,
const float diff_mat[4][4]);
+/**
+ * Calculates the perimeter of a stroke projected from the view and returns it as a new stroke.
+ * \param subdivisions: Number of subdivisions for the start and end caps.
+ * \return: bGPDstroke pointer to stroke perimeter.
+ */
struct bGPDstroke *BKE_gpencil_stroke_perimeter_from_view(struct RegionView3D *rv3d,
struct bGPdata *gpd,
const struct bGPDlayer *gpl,
struct bGPDstroke *gps,
const int subdivisions,
const float diff_mat[4][4]);
+/**
+ * Get average pressure.
+ */
float BKE_gpencil_stroke_average_pressure_get(struct bGPDstroke *gps);
+/**
+ * Check if the thickness of the stroke is constant.
+ */
bool BKE_gpencil_stroke_is_pressure_constant(struct bGPDstroke *gps);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_gpencil_modifier.h b/source/blender/blenkernel/BKE_gpencil_modifier.h
index 33524e47473..5fc0abf6a2c 100644
--- a/source/blender/blenkernel/BKE_gpencil_modifier.h
+++ b/source/blender/blenkernel/BKE_gpencil_modifier.h
@@ -249,36 +249,114 @@ typedef struct GpencilModifierTypeInfo {
#define GPENCIL_MODIFIER_TYPE_PANEL_PREFIX "MOD_PT_gpencil_"
-/* Initialize modifier's global data (type info and some common global storage). */
+/**
+ * Initialize modifier's global data (type info and some common global storage).
+ */
void BKE_gpencil_modifier_init(void);
+/**
+ * Get the idname of the modifier type's panel, which was defined in the #panelRegister callback.
+ *
+ * \param type: Type of modifier.
+ * \param r_idname: ID name.
+ */
void BKE_gpencil_modifierType_panel_id(GpencilModifierType type, char *r_idname);
void BKE_gpencil_modifier_panel_expand(struct GpencilModifierData *md);
+/**
+ * Get grease pencil modifier information.
+ * \param type: Type of modifier.
+ * \return Pointer to type
+ */
const GpencilModifierTypeInfo *BKE_gpencil_modifier_get_info(GpencilModifierType type);
+/**
+ * Create new grease pencil modifier.
+ * \param type: Type of modifier.
+ * \return New modifier pointer.
+ */
struct GpencilModifierData *BKE_gpencil_modifier_new(int type);
+/**
+ * Free grease pencil modifier data
+ * \param md: Modifier data.
+ * \param flag: Flags.
+ */
void BKE_gpencil_modifier_free_ex(struct GpencilModifierData *md, const int flag);
+/**
+ * Free grease pencil modifier data
+ * \param md: Modifier data.
+ */
void BKE_gpencil_modifier_free(struct GpencilModifierData *md);
+/* check unique name */
bool BKE_gpencil_modifier_unique_name(struct ListBase *modifiers, struct GpencilModifierData *gmd);
+/**
+ * Check if grease pencil modifier depends on time.
+ * \param md: Modifier data.
+ * \return True if depends on time.
+ */
bool BKE_gpencil_modifier_depends_ontime(struct GpencilModifierData *md);
struct GpencilModifierData *BKE_gpencil_modifiers_findby_type(struct Object *ob,
GpencilModifierType type);
+/**
+ * Find grease pencil modifier by name.
+ * \param ob: Grease pencil object.
+ * \param name: Name to find.
+ * \return Pointer to modifier.
+ */
struct GpencilModifierData *BKE_gpencil_modifiers_findby_name(struct Object *ob, const char *name);
+/**
+ * Generic grease pencil modifier copy data.
+ * \param md_src: Source modifier data.
+ * \param md_dst: Target modifier data.
+ */
void BKE_gpencil_modifier_copydata_generic(const struct GpencilModifierData *md_src,
struct GpencilModifierData *md_dst);
+/**
+ * Copy grease pencil modifier data.
+ * \param md: Source modifier data.
+ * \param target: Target modifier data.
+ */
void BKE_gpencil_modifier_copydata(struct GpencilModifierData *md,
struct GpencilModifierData *target);
+/**
+ * Copy grease pencil modifier data.
+ * \param md: Source modifier data.
+ * \param target: Target modifier data.
+ * \param flag: Flags.
+ */
void BKE_gpencil_modifier_copydata_ex(struct GpencilModifierData *md,
struct GpencilModifierData *target,
const int flag);
+/**
+ * Set grease pencil modifier error.
+ * \param md: Modifier data.
+ * \param format: Format.
+ */
void BKE_gpencil_modifier_set_error(struct GpencilModifierData *md, const char *format, ...)
ATTR_PRINTF_FORMAT(2, 3);
+/**
+ * Link grease pencil modifier related IDs.
+ * \param ob: Grease pencil object.
+ * \param walk: Walk option.
+ * \param userData: User data.
+ */
void BKE_gpencil_modifiers_foreach_ID_link(struct Object *ob,
GreasePencilIDWalkFunc walk,
void *userData);
+/**
+ * Link grease pencil modifier related Texts.
+ * \param ob: Grease pencil object.
+ * \param walk: Walk option.
+ * \param userData: User data.
+ */
void BKE_gpencil_modifiers_foreach_tex_link(struct Object *ob,
GreasePencilTexWalkFunc walk,
void *userData);
+/**
+ * Check whether given modifier is not local (i.e. from linked data) when the object is a library
+ * override.
+ *
+ * \param gmd: May be NULL, in which case we consider it as a non-local modifier case.
+ */
bool BKE_gpencil_modifier_is_nonlocal_in_liboverride(const struct Object *ob,
const struct GpencilModifierData *gmd);
@@ -287,11 +365,30 @@ typedef struct GpencilVirtualModifierData {
LatticeGpencilModifierData lmd;
} GpencilVirtualModifierData;
+/**
+ * This is to include things that are not modifiers in the evaluation of the modifier stack,
+ * for example parenting to an armature or lattice without having a real modifier.
+ */
struct GpencilModifierData *BKE_gpencil_modifiers_get_virtual_modifierlist(
const struct Object *ob, struct GpencilVirtualModifierData *data);
+/**
+ * Check if object has grease pencil Geometry modifiers.
+ * \param ob: Grease pencil object.
+ * \return True if exist.
+ */
bool BKE_gpencil_has_geometry_modifiers(struct Object *ob);
+/**
+ * Check if object has grease pencil Time modifiers.
+ * \param ob: Grease pencil object.
+ * \return True if exist.
+ */
bool BKE_gpencil_has_time_modifiers(struct Object *ob);
+/**
+ * Check if object has grease pencil transform stroke modifiers.
+ * \param ob: Grease pencil object.
+ * \return True if exist.
+ */
bool BKE_gpencil_has_transform_modifiers(struct Object *ob);
/* Stores the maximum calculation range in the whole modifier stack for line art so the cache can
@@ -310,21 +407,44 @@ void BKE_gpencil_set_lineart_modifier_limits(struct GpencilModifierData *md,
bool BKE_gpencil_is_first_lineart_in_stack(const struct Object *ob,
const struct GpencilModifierData *md);
-void BKE_gpencil_lattice_init(struct Object *ob);
-void BKE_gpencil_lattice_clear(struct Object *ob);
+void BKE_gpencil_cache_data_init(struct Depsgraph *depsgraph, struct Object *ob);
+void BKE_gpencil_cache_data_clear(struct Object *ob);
+/**
+ * Calculate grease-pencil modifiers.
+ * \param depsgraph: Current depsgraph.
+ * \param scene: Current scene.
+ * \param ob: Grease pencil object.
+ */
void BKE_gpencil_modifiers_calc(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob);
+/**
+ * Prepare grease pencil eval data for modifiers
+ * \param depsgraph: Current depsgraph.
+ * \param scene: Current scene.
+ * \param ob: Grease pencil object.
+ */
void BKE_gpencil_prepare_eval_data(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob);
+/**
+ * Get the current frame re-timed with time modifiers.
+ * \param depsgraph: Current depsgraph.
+ * \param scene: Current scene.
+ * \param ob: Grease pencil object.
+ * \param gpl: Grease pencil layer.
+ * \return New frame number.
+ */
struct bGPDframe *BKE_gpencil_frame_retime_get(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
struct bGPDlayer *gpl);
+/**
+ * Get Time modifier frame number.
+ */
int BKE_gpencil_time_modifier_cfra(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
diff --git a/source/blender/blenkernel/BKE_icons.h b/source/blender/blenkernel/BKE_icons.h
index 28a6f837f61..c96a37e0d09 100644
--- a/source/blender/blenkernel/BKE_icons.h
+++ b/source/blender/blenkernel/BKE_icons.h
@@ -97,76 +97,135 @@ enum eIconSizes;
void BKE_icons_init(int first_dyn_id);
-/* return icon id for library object or create new icon if not found */
+/**
+ * Return icon id for library object or create new icon if not found.
+ */
int BKE_icon_id_ensure(struct ID *id);
-/* return icon id for Grease Pencil layer (color preview) or create new icon if not found */
+/**
+ * Return icon id for Grease Pencil layer (color preview) or create new icon if not found.
+ */
int BKE_icon_gplayer_color_ensure(struct bGPDlayer *gpl);
+/**
+ * Return icon id of given preview, or create new icon if not found.
+ */
int BKE_icon_preview_ensure(struct ID *id, struct PreviewImage *preview);
+/**
+ * Create an icon as owner or \a ibuf. The icon-ID is not stored in \a ibuf,
+ * it needs to be stored separately.
+ * \note Transforms ownership of \a ibuf to the newly created icon.
+ */
int BKE_icon_imbuf_create(struct ImBuf *ibuf) ATTR_WARN_UNUSED_RESULT;
struct ImBuf *BKE_icon_imbuf_get_buffer(int icon_id) ATTR_WARN_UNUSED_RESULT;
-/* retrieve icon for id */
+/**
+ * Retrieve icon for id.
+ */
struct Icon *BKE_icon_get(const int icon_id);
-/* set icon for id if not already defined */
-/* used for inserting the internal icons */
+/**
+ * Set icon for id if not already defined.
+ * Used for inserting the internal icons.
+ */
void BKE_icon_set(const int icon_id, struct Icon *icon);
-/* remove icon and free data if library object becomes invalid */
+/**
+ * Remove icon and free data if library object becomes invalid.
+ */
void BKE_icon_id_delete(struct ID *id);
+/**
+ * Remove icon and free data.
+ */
bool BKE_icon_delete(const int icon_id);
bool BKE_icon_delete_unmanaged(const int icon_id);
-/* report changes - icon needs to be recalculated */
+/**
+ * Report changes - icon needs to be recalculated.
+ */
void BKE_icon_changed(const int icon_id);
-/* free all icons */
+/**
+ * Free all icons.
+ */
void BKE_icons_free(void);
-/* free all icons marked for deferred deletion */
+/**
+ * Free all icons marked for deferred deletion.
+ */
void BKE_icons_deferred_free(void);
-/* free the preview image for use in list */
+/**
+ * Free the preview image for use in list.
+ */
void BKE_previewimg_freefunc(void *link);
-/* free the preview image */
+/**
+ * Free the preview image.
+ */
void BKE_previewimg_free(struct PreviewImage **prv);
-/* clear the preview image or icon, but does not free it */
+/**
+ * Clear the preview image or icon, but does not free it.
+ */
void BKE_previewimg_clear(struct PreviewImage *prv);
-/* clear the preview image or icon at a specific size */
+/**
+ * Clear the preview image or icon at a specific size.
+ */
void BKE_previewimg_clear_single(struct PreviewImage *prv, enum eIconSizes size);
-/* get the preview from any pointer */
+/**
+ * Get the preview from any pointer.
+ */
struct PreviewImage **BKE_previewimg_id_get_p(const struct ID *id);
struct PreviewImage *BKE_previewimg_id_get(const struct ID *id);
bool BKE_previewimg_id_supports_jobs(const struct ID *id);
-/* Trigger deferred loading of a custom image file into the preview buffer. */
+/**
+ * Trigger deferred loading of a custom image file into the preview buffer.
+ */
void BKE_previewimg_id_custom_set(struct ID *id, const char *path);
-/* free the preview image belonging to the id */
+/**
+ * Free the preview image belonging to the id.
+ */
void BKE_previewimg_id_free(struct ID *id);
-/* create a new preview image */
+/**
+ * Create a new preview image.
+ */
struct PreviewImage *BKE_previewimg_create(void);
-/* create a copy of the preview image */
+/**
+ * Create a copy of the preview image.
+ */
struct PreviewImage *BKE_previewimg_copy(const struct PreviewImage *prv);
+/**
+ * Duplicate preview image from \a id and clear icon_id,
+ * to be used by data-block copy functions.
+ */
void BKE_previewimg_id_copy(struct ID *new_id, const struct ID *old_id);
-/* retrieve existing or create new preview image */
+/**
+ * Retrieve existing or create new preview image.
+ */
struct PreviewImage *BKE_previewimg_id_ensure(struct ID *id);
+/**
+ * Handle deferred (lazy) loading/generation of preview image, if needed.
+ * For now, only used with file thumbnails.
+ */
void BKE_previewimg_ensure(struct PreviewImage *prv, const int size);
+/**
+ * Create an #ImBuf holding a copy of the preview image buffer in \a prv.
+ * \note The returned image buffer has to be free'd (#IMB_freeImBuf()).
+ */
struct ImBuf *BKE_previewimg_to_imbuf(struct PreviewImage *prv, const int size);
void BKE_previewimg_finish(struct PreviewImage *prv, const int size);
@@ -174,8 +233,15 @@ bool BKE_previewimg_is_finished(const struct PreviewImage *prv, const int size);
struct PreviewImage *BKE_previewimg_cached_get(const char *name);
+/**
+ * Generate an empty #PreviewImage, if not yet existing.
+ */
struct PreviewImage *BKE_previewimg_cached_ensure(const char *name);
+/**
+ * Generate a #PreviewImage from given file path, using thumbnails management, if not yet existing.
+ * Does not actually generate the preview, #BKE_previewimg_ensure() must be called for that.
+ */
struct PreviewImage *BKE_previewimg_cached_thumbnail_read(const char *name,
const char *path,
const int source,
diff --git a/source/blender/blenkernel/BKE_idprop.h b/source/blender/blenkernel/BKE_idprop.h
index c28ac63388b..1fb3636e9fd 100644
--- a/source/blender/blenkernel/BKE_idprop.h
+++ b/source/blender/blenkernel/BKE_idprop.h
@@ -56,11 +56,17 @@ typedef union IDPropertyTemplate {
/* ----------- Property Array Type ---------- */
+/**
+ * \note as a start to move away from the stupid #IDP_New function,
+ * this type has its own allocation function.
+ */
struct IDProperty *IDP_NewIDPArray(const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
struct IDProperty *IDP_CopyIDPArray(const struct IDProperty *array,
const int flag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-/* shallow copies item */
+/**
+ * Shallow copies item.
+ */
void IDP_SetIndexArray(struct IDProperty *prop, int index, struct IDProperty *item) ATTR_NONNULL();
struct IDProperty *IDP_GetIndexArray(struct IDProperty *prop, int index) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
@@ -68,11 +74,20 @@ void IDP_AppendArray(struct IDProperty *prop, struct IDProperty *item);
void IDP_ResizeIDPArray(struct IDProperty *prop, int len);
/* ----------- Numeric Array Type ----------- */
-/* This function works for strings too! */
+
+/**
+ * This function works for strings too!
+ */
void IDP_ResizeArray(struct IDProperty *prop, int newlen);
void IDP_FreeArray(struct IDProperty *prop);
/* ---------- String Type ------------ */
+/**
+ * \param st: The string to assign.
+ * \param name: The property name.
+ * \param maxlen: The size of the new string (including the \0 terminator).
+ * \return The new string property.
+ */
struct IDProperty *IDP_NewString(const char *st,
const char *name,
int maxlen) ATTR_WARN_UNUSED_RESULT
@@ -91,38 +106,90 @@ void IDP_AssignID(struct IDProperty *prop, struct ID *id, const int flag);
/*-------- Group Functions -------*/
-/** Sync values from one group to another, only where they match */
+/**
+ * Sync values from one group to another when values name and types match,
+ * copy the values, else ignore.
+ *
+ * \note Use for syncing proxies.
+ */
void IDP_SyncGroupValues(struct IDProperty *dest, const struct IDProperty *src) ATTR_NONNULL();
void IDP_SyncGroupTypes(struct IDProperty *dest,
const struct IDProperty *src,
const bool do_arraylen) ATTR_NONNULL();
+/**
+ * Replaces all properties with the same name in a destination group from a source group.
+ */
void IDP_ReplaceGroupInGroup(struct IDProperty *dest, const struct IDProperty *src) ATTR_NONNULL();
void IDP_ReplaceInGroup(struct IDProperty *group, struct IDProperty *prop) ATTR_NONNULL();
+/**
+ * Checks if a property with the same name as prop exists, and if so replaces it.
+ * Use this to preserve order!
+ */
void IDP_ReplaceInGroup_ex(struct IDProperty *group,
struct IDProperty *prop,
struct IDProperty *prop_exist);
+/**
+ * If a property is missing in \a dest, add it.
+ * Do it recursively.
+ */
void IDP_MergeGroup(struct IDProperty *dest, const struct IDProperty *src, const bool do_overwrite)
ATTR_NONNULL();
+/**
+ * If a property is missing in \a dest, add it.
+ * Do it recursively.
+ */
void IDP_MergeGroup_ex(struct IDProperty *dest,
const struct IDProperty *src,
const bool do_overwrite,
const int flag) ATTR_NONNULL();
+/**
+ * This function has a sanity check to make sure ID properties with the same name don't
+ * get added to the group.
+ *
+ * The sanity check just means the property is not added to the group if another property
+ * exists with the same name; the client code using ID properties then needs to detect this
+ * (the function that adds new properties to groups, #IDP_AddToGroup,
+ * returns false if a property can't be added to the group, and true if it can)
+ * and free the property.
+ */
bool IDP_AddToGroup(struct IDProperty *group, struct IDProperty *prop) ATTR_NONNULL();
+/**
+ * This is the same as IDP_AddToGroup, only you pass an item
+ * in the group list to be inserted after.
+ */
bool IDP_InsertToGroup(struct IDProperty *group,
struct IDProperty *previous,
struct IDProperty *pnew) ATTR_NONNULL(1 /* group */, 3 /* pnew */);
+/**
+ * \note this does not free the property!
+ *
+ * To free the property, you have to do:
+ * #IDP_FreeProperty(prop);
+ */
void IDP_RemoveFromGroup(struct IDProperty *group, struct IDProperty *prop) ATTR_NONNULL();
+/**
+ * Removes the property from the group and frees it.
+ */
void IDP_FreeFromGroup(struct IDProperty *group, struct IDProperty *prop) ATTR_NONNULL();
struct IDProperty *IDP_GetPropertyFromGroup(const struct IDProperty *prop,
const char *name) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Same as above but ensure type match.
+ */
struct IDProperty *IDP_GetPropertyTypeFromGroup(const struct IDProperty *prop,
const char *name,
const char type) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
/*-------- Main Functions --------*/
+/**
+ * Get the Group property that contains the id properties for ID id.
+ *
+ * \param create_if_needed: Set to create the group property and attach it to id if it doesn't
+ * exist; otherwise the function will return NULL if there's no Group property attached to the ID.
+ */
struct IDProperty *IDP_GetProperties(struct ID *id,
const bool create_if_needed) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
@@ -130,8 +197,15 @@ struct IDProperty *IDP_CopyProperty(const struct IDProperty *prop) ATTR_WARN_UNU
ATTR_NONNULL();
struct IDProperty *IDP_CopyProperty_ex(const struct IDProperty *prop,
const int flag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Copy content from source #IDProperty into destination one,
+ * freeing destination property's content first.
+ */
void IDP_CopyPropertyContent(struct IDProperty *dst, struct IDProperty *src) ATTR_NONNULL();
+/**
+ * \param is_strict: When false treat missing items as a match.
+ */
bool IDP_EqualsProperties_ex(struct IDProperty *prop1,
struct IDProperty *prop2,
const bool is_strict) ATTR_WARN_UNUSED_RESULT;
@@ -139,10 +213,41 @@ bool IDP_EqualsProperties_ex(struct IDProperty *prop1,
bool IDP_EqualsProperties(struct IDProperty *prop1,
struct IDProperty *prop2) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Allocate a new ID.
+ *
+ * This function takes three arguments: the ID property type, a union which defines
+ * its initial value, and a name.
+ *
+ * The union is simple to use; see the top of BKE_idprop.h for its definition.
+ * An example of using this function:
+ *
+ * \code{.c}
+ * IDPropertyTemplate val;
+ * IDProperty *group, *idgroup, *color;
+ * group = IDP_New(IDP_GROUP, val, "group1"); // groups don't need a template.
+ *
+ * val.array.len = 4
+ * val.array.type = IDP_FLOAT;
+ * color = IDP_New(IDP_ARRAY, val, "color1");
+ *
+ * idgroup = IDP_GetProperties(some_id, 1);
+ * IDP_AddToGroup(idgroup, color);
+ * IDP_AddToGroup(idgroup, group);
+ * \endcode
+ *
+ * Note that you MUST either attach the id property to an id property group with
+ * IDP_AddToGroup or MEM_freeN the property, doing anything else might result in
+ * a memory leak.
+ */
struct IDProperty *IDP_New(const char type,
const IDPropertyTemplate *val,
const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * \note This will free allocated data, all child properties of arrays and groups, and unlink IDs!
+ * But it does not free the actual #IDProperty struct itself.
+ */
void IDP_FreePropertyContent_ex(struct IDProperty *prop, const bool do_id_user);
void IDP_FreePropertyContent(struct IDProperty *prop);
void IDP_FreeProperty_ex(struct IDProperty *prop, const bool do_id_user);
@@ -184,16 +289,35 @@ void IDP_Reset(struct IDProperty *prop, const struct IDProperty *reference);
# define IDP_Id(prop) ((ID *)(prop)->data.pointer)
#endif
+/**
+ * Return an int from an #IDProperty with a compatible type. This should be avoided, but
+ * it's sometimes necessary, for example when legacy files have incorrect property types.
+ */
int IDP_coerce_to_int_or_zero(const struct IDProperty *prop);
+/**
+ * Return a float from an #IDProperty with a compatible type. This should be avoided, but
+ * it's sometimes necessary, for example when legacy files have incorrect property types.
+ */
float IDP_coerce_to_float_or_zero(const struct IDProperty *prop);
+/**
+ * Return a double from an #IDProperty with a compatible type. This should be avoided, but
+ * it's sometimes necessary, for example when legacy files have incorrect property types.
+ */
double IDP_coerce_to_double_or_zero(const struct IDProperty *prop);
/**
- * Call a callback for each idproperty in the hierarchy under given root one (included).
- *
+ * Call a callback for each #IDproperty in the hierarchy under given root one (included).
*/
typedef void (*IDPForeachPropertyCallback)(struct IDProperty *id_property, void *user_data);
+/**
+ * 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(struct IDProperty *id_property_root,
const int type_filter,
IDPForeachPropertyCallback callback,
@@ -230,6 +354,11 @@ typedef enum eIDPropertyUIDataType {
bool IDP_ui_data_supported(const struct IDProperty *prop);
eIDPropertyUIDataType IDP_ui_data_type(const struct IDProperty *prop);
void IDP_ui_data_free(struct IDProperty *prop);
+/**
+ * Free allocated pointers in the UI data that isn't shared with the UI data in the `other`
+ * argument. Useful for returning early on failure when updating UI data in place, or when
+ * replacing a subset of the UI data's allocated pointers.
+ */
void IDP_ui_data_free_unique_contents(struct IDPropertyUIData *ui_data,
eIDPropertyUIDataType type,
const struct IDPropertyUIData *other);
diff --git a/source/blender/blenkernel/BKE_idtype.h b/source/blender/blenkernel/BKE_idtype.h
index d33c24f2c75..8cd5d2a2361 100644
--- a/source/blender/blenkernel/BKE_idtype.h
+++ b/source/blender/blenkernel/BKE_idtype.h
@@ -35,6 +35,7 @@ struct BlendDataReader;
struct BlendExpander;
struct BlendLibReader;
struct BlendWriter;
+struct BPathForeachPathData;
struct ID;
struct LibraryForeachIDData;
struct Main;
@@ -81,7 +82,7 @@ typedef void (*IDTypeCopyDataFunction)(struct Main *bmain,
typedef void (*IDTypeFreeDataFunction)(struct ID *id);
-/** \param flag: See BKE_lib_id.h's LIB_ID_MAKELOCAL_... flags. */
+/** \param flags: See BKE_lib_id.h's LIB_ID_MAKELOCAL_... flags. */
typedef void (*IDTypeMakeLocalFunction)(struct Main *bmain, struct ID *id, const int flags);
typedef void (*IDTypeForeachIDFunction)(struct ID *id, struct LibraryForeachIDData *data);
@@ -100,6 +101,8 @@ typedef void (*IDTypeForeachCacheFunction)(struct ID *id,
IDTypeForeachCacheFunctionCallback function_callback,
void *user_data);
+typedef void (*IDTypeForeachPathFunction)(struct ID *id, struct BPathForeachPathData *bpath_data);
+
typedef struct ID *(*IDTypeEmbeddedOwnerGetFunction)(struct Main *bmain, struct ID *id);
typedef void (*IDTypeBlendWriteFunction)(struct BlendWriter *writer,
@@ -149,11 +152,12 @@ typedef struct IDTypeInfo {
/** Generic info flags about that data-block type. */
uint32_t flags;
- /* ********** ID management callbacks ********** */
+ /**
+ * Information and callbacks for assets, based on the type of asset.
+ */
+ struct AssetTypeInfo *asset_type_info;
- /* TODO: Note about callbacks: Ideally we could also handle here `BKE_lib_query`'s behavior, as
- * well as read/write of files. However, this is a bit more involved than basic ID management
- * callbacks, so we'll check on this later. */
+ /* ********** ID management callbacks ********** */
/**
* Initialize a new, empty calloc'ed data-block. May be NULL if there is nothing to do.
@@ -189,6 +193,11 @@ typedef struct IDTypeInfo {
IDTypeForeachCacheFunction foreach_cache;
/**
+ * Iterator over all file paths of given ID.
+ */
+ IDTypeForeachPathFunction foreach_path;
+
+ /**
* For embedded IDs, return their owner ID.
*/
IDTypeEmbeddedOwnerGetFunction owner_get;
@@ -228,11 +237,6 @@ typedef struct IDTypeInfo {
* \note Currently needed for some update operation on point caches.
*/
IDTypeLibOverrideApplyPost lib_override_apply_post;
-
- /**
- * Callbacks for assets, based on the type of asset.
- */
- struct AssetTypeInfo *asset_type_info;
} IDTypeInfo;
/* ********** Declaration of each IDTypeInfo. ********** */
@@ -279,6 +283,7 @@ extern IDTypeInfo IDType_ID_PT;
extern IDTypeInfo IDType_ID_VO;
extern IDTypeInfo IDType_ID_SIM;
+/** Empty shell mostly, but needed for read code. */
extern IDTypeInfo IDType_ID_LINK_PLACEHOLDER;
/* ********** Helpers/Utils API. ********** */
@@ -290,32 +295,101 @@ void BKE_idtype_init(void);
const struct IDTypeInfo *BKE_idtype_get_info_from_idcode(const short id_code);
const struct IDTypeInfo *BKE_idtype_get_info_from_id(const struct ID *id);
+/**
+ * Convert an \a idcode into a name.
+ *
+ * \param idcode: The code to convert.
+ * \return A static string representing the name of the code.
+ */
const char *BKE_idtype_idcode_to_name(const short idcode);
+/**
+ * Convert an \a idcode into a name (plural).
+ *
+ * \param idcode: The code to convert.
+ * \return A static string representing the name of the code.
+ */
const char *BKE_idtype_idcode_to_name_plural(const short idcode);
+/**
+ * Convert an \a idcode into its translations' context.
+ *
+ * \param idcode: The code to convert.
+ * \return A static string representing the i18n context of the code.
+ */
const char *BKE_idtype_idcode_to_translation_context(const short idcode);
+/**
+ * Return if the ID code is a valid ID code.
+ *
+ * \param idcode: The code to check.
+ * \return Boolean, 0 when invalid.
+ */
bool BKE_idtype_idcode_is_valid(const short idcode);
+/**
+ * Check if an ID type is linkable.
+ *
+ * \param idcode: The IDType code to check.
+ * \return Boolean, false when non linkable, true otherwise.
+ */
bool BKE_idtype_idcode_is_linkable(const short idcode);
+/**
+ * Check if an ID type is only appendable.
+ *
+ * \param idcode: The IDType code to check.
+ * \return Boolean, false when also linkable, true when only appendable.
+ */
bool BKE_idtype_idcode_is_only_appendable(const short idcode);
+/**
+ * Check if an ID type can try to reuse and existing matching local one when being appended again.
+ *
+ * \param idcode: The IDType code to check.
+ * \return Boolean, false when it cannot be re-used, true otherwise.
+ */
bool BKE_idtype_idcode_append_is_reusable(const short idcode);
/* Macro currently, since any linkable IDtype should be localizable. */
#define BKE_idtype_idcode_is_localizable BKE_idtype_idcode_is_linkable
+/**
+ * Convert an ID-type name into an \a idcode (ie. #ID_SCE)
+ *
+ * \param idtype_name: The ID-type's "user visible name" to convert.
+ * \return The \a idcode for the name, or 0 if invalid.
+ */
short BKE_idtype_idcode_from_name(const char *idtype_name);
+/**
+ * Convert an \a idcode into an \a idfilter (e.g. #ID_OB -> #FILTER_ID_OB).
+ */
uint64_t BKE_idtype_idcode_to_idfilter(const short idcode);
+/**
+ * Convert an \a idfilter into an \a idcode (e.g. #FILTER_ID_OB -> #ID_OB).
+ */
short BKE_idtype_idcode_from_idfilter(const uint64_t idfilter);
+/**
+ * Convert an \a idcode into an index (e.g. #ID_OB -> #INDEX_ID_OB).
+ */
int BKE_idtype_idcode_to_index(const short idcode);
+/**
+ * Get an \a idcode from an index (e.g. #INDEX_ID_OB -> #ID_OB).
+ */
short BKE_idtype_idcode_from_index(const int index);
+/**
+ * Return an ID code and steps the index forward 1.
+ *
+ * \param index: start as 0.
+ * \return the code, 0 when all codes have been returned.
+ */
short BKE_idtype_idcode_iter_step(int *index);
/* Some helpers/wrappers around callbacks defined in #IDTypeInfo, dealing e.g. with embedded IDs.
* XXX Ideally those would rather belong to #BKE_lib_id, but using callback function pointers makes
* this hard to do properly if we want to avoid headers includes in headers. */
+/**
+ * Wrapper around #IDTypeInfo foreach_cache that also handles embedded IDs.
+ */
void BKE_idtype_id_foreach_cache(struct ID *id,
IDTypeForeachCacheFunctionCallback function_callback,
void *user_data);
diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h
index 77f1d197844..4db6da4b3ea 100644
--- a/source/blender/blenkernel/BKE_image.h
+++ b/source/blender/blenkernel/BKE_image.h
@@ -50,9 +50,16 @@ struct anim;
void BKE_image_free_packedfiles(struct Image *image);
void BKE_image_free_views(struct Image *image);
void BKE_image_free_buffers(struct Image *image);
+/**
+ * Simply free the image data from memory,
+ * on display the image can load again (except for render buffers).
+ */
void BKE_image_free_buffers_ex(struct Image *image, bool do_lock);
void BKE_image_free_gputextures(struct Image *ima);
-/* call from library */
+/**
+ * Free (or release) any data used by this image (does not free the image itself).
+ * \note Call from library.
+ */
void BKE_image_free_data(struct Image *image);
typedef void(StampCallback)(void *data, const char *propname, char *propvalue, int len);
@@ -66,6 +73,9 @@ void BKE_render_result_stamp_info(struct Scene *scene,
* The caller is responsible for freeing the allocated memory.
*/
struct StampData *BKE_stamp_info_from_scene_static(const struct Scene *scene);
+/**
+ * Check whether the given metadata field name translates to a known field of a stamp.
+ */
bool BKE_stamp_is_known_field(const char *field_name);
void BKE_imbuf_stamp_info(struct RenderResult *rr, struct ImBuf *ibuf);
void BKE_stamp_info_from_imbuf(struct RenderResult *rr, struct ImBuf *ibuf);
@@ -90,8 +100,15 @@ int BKE_imbuf_write_stamp(struct Scene *scene,
struct ImBuf *ibuf,
const char *name,
const struct ImageFormatData *imf);
+/**
+ * \note imf->planes is ignored here, its assumed the image channels are already set.
+ */
void BKE_imbuf_write_prepare(struct ImBuf *ibuf, const struct ImageFormatData *imf);
int BKE_imbuf_write(struct ImBuf *ibuf, const char *name, const struct ImageFormatData *imf);
+/**
+ * Same as #BKE_imbuf_write() but crappy workaround not to permanently modify _some_,
+ * values in the imbuf.
+ */
int BKE_imbuf_write_as(struct ImBuf *ibuf,
const char *name,
struct ImageFormatData *imf,
@@ -125,11 +142,18 @@ bool BKE_imtype_requires_linear_float(const char imtype);
char BKE_imtype_valid_channels(const char imtype, bool write_file);
char BKE_imtype_valid_depths(const char imtype);
+/**
+ * String is from command line `--render-format` argument,
+ * keep in sync with `creator_args.c` help info.
+ */
char BKE_imtype_from_arg(const char *arg);
void BKE_imformat_defaults(struct ImageFormatData *im_format);
void BKE_imbuf_to_image_format(struct ImageFormatData *im_format, const struct ImBuf *imbuf);
+/**
+ * Used by sequencer too.
+ */
struct anim *openanim(const char *name,
int flags,
int streamindex,
@@ -164,11 +188,18 @@ struct RenderResult;
#define IMA_CHAN_FLAG_RGB 2
#define IMA_CHAN_FLAG_ALPHA 4
-/* checks whether there's an image buffer for given image and user */
+/**
+ * Checks whether there's an image buffer for given image and user.
+ */
bool BKE_image_has_ibuf(struct Image *ima, struct ImageUser *iuser);
-/* same as above, but can be used to retrieve images being rendered in
- * a thread safe way, always call both acquire and release */
+/**
+ * Return image buffer for given image and user:
+ * - will lock render result if image type is render result and lock is not NULL
+ * - will return NULL if image is NULL or image type is render or composite result and lock is NULL
+ *
+ * References the result, #BKE_image_release_ibuf should be used to de-reference.
+ */
struct ImBuf *BKE_image_acquire_ibuf(struct Image *ima, struct ImageUser *iuser, void **r_lock);
void BKE_image_release_ibuf(struct Image *ima, struct ImBuf *ibuf, void *lock);
@@ -179,17 +210,28 @@ struct ImBuf *BKE_image_pool_acquire_ibuf(struct Image *ima,
struct ImagePool *pool);
void BKE_image_pool_release_ibuf(struct Image *ima, struct ImBuf *ibuf, struct ImagePool *pool);
-/* set an alpha mode based on file extension */
+/**
+ * Set an alpha mode based on file extension.
+ */
char BKE_image_alpha_mode_from_extension_ex(const char *filepath);
void BKE_image_alpha_mode_from_extension(struct Image *image);
-/* returns a new image or NULL if it can't load */
+/**
+ * Returns a new image or NULL if it can't load.
+ */
struct Image *BKE_image_load(struct Main *bmain, const char *filepath);
-/* returns existing Image when filename/type is same (frame optional) */
+/**
+ * Returns existing Image when filename/type is same.
+ *
+ * Checks if image was already loaded, then returns same image otherwise creates new
+ * (does not load ibuf itself).
+ */
struct Image *BKE_image_load_exists_ex(struct Main *bmain, const char *filepath, bool *r_exists);
struct Image *BKE_image_load_exists(struct Main *bmain, const char *filepath);
-/* adds image, adds ibuf, generates color or pattern */
+/**
+ * Adds new image block, creates ImBuf and initializes color.
+ */
struct Image *BKE_image_add_generated(struct Main *bmain,
unsigned int width,
unsigned int height,
@@ -201,10 +243,15 @@ struct Image *BKE_image_add_generated(struct Main *bmain,
const bool stereo3d,
const bool is_data,
const bool tiled);
-/* adds image from imbuf, owns imbuf */
+/**
+ * Create an image from ibuf. The reference-count of ibuf is increased,
+ * caller should take care to drop its reference by calling #IMB_freeImBuf if needed.
+ */
struct Image *BKE_image_add_from_imbuf(struct Main *bmain, struct ImBuf *ibuf, const char *name);
-/* for reload, refresh, pack */
+/**
+ * For reload, refresh, pack.
+ */
void BKE_imageuser_default(struct ImageUser *iuser);
void BKE_image_init_imageuser(struct Image *ima, struct ImageUser *iuser);
void BKE_image_signal(struct Main *bmain, struct Image *ima, struct ImageUser *iuser, int signal);
@@ -216,61 +263,100 @@ void BKE_image_walk_all_users(const struct Main *mainp,
struct ImageUser *iuser,
void *customdata));
-/* ensures an Image exists for viewing nodes or render */
+/**
+ * Ensures an Image exists for viewing nodes or render
+ * forces existence of 1 Image for render-output or nodes, returns Image.
+ *
+ * \param name: Only for default, when making new one.
+ */
struct Image *BKE_image_ensure_viewer(struct Main *bmain, int type, const char *name);
-/* ensures the view node cache is compatible with the scene views */
+/**
+ * Ensures the view node cache is compatible with the scene views.
+ * Reset the image cache and views when the Viewer Nodes views don't match the scene views.
+ */
void BKE_image_ensure_viewer_views(const struct RenderData *rd,
struct Image *ima,
struct ImageUser *iuser);
-/* called on frame change or before render */
+/**
+ * Called on frame change or before render.
+ */
void BKE_image_user_frame_calc(struct Image *ima, struct ImageUser *iuser, int cfra);
int BKE_image_user_frame_get(const struct ImageUser *iuser, int cfra, bool *r_is_in_range);
void BKE_image_user_file_path(struct ImageUser *iuser, struct Image *ima, char *path);
void BKE_image_editors_update_frame(const struct Main *bmain, int cfra);
-/* dependency graph update for image user users */
+/**
+ * Dependency graph update for image user users.
+ */
bool BKE_image_user_id_has_animation(struct ID *id);
void BKE_image_user_id_eval_animation(struct Depsgraph *depsgraph, struct ID *id);
-/* sets index offset for multilayer files */
+/**
+ * Sets index offset for multi-layer files and because rendered results use fake layer/passes,
+ * don't correct for wrong indices here.
+ */
struct RenderPass *BKE_image_multilayer_index(struct RenderResult *rr, struct ImageUser *iuser);
-/* sets index offset for multiview files */
+/**
+ * Sets index offset for multi-view files.
+ */
void BKE_image_multiview_index(struct Image *ima, struct ImageUser *iuser);
-/* for multilayer images as well as for render-viewer */
+/**
+ * For multi-layer images as well as for render-viewer
+ * and because rendered results use fake layer/passes, don't correct for wrong indices here.
+ */
bool BKE_image_is_multilayer(struct Image *ima);
bool BKE_image_is_multiview(struct Image *ima);
bool BKE_image_is_stereo(struct Image *ima);
struct RenderResult *BKE_image_acquire_renderresult(struct Scene *scene, struct Image *ima);
void BKE_image_release_renderresult(struct Scene *scene, struct Image *ima);
-/* For multi-layer images as well as for single-layer. */
+/**
+ * For multi-layer images as well as for single-layer.
+ */
bool BKE_image_is_openexr(struct Image *ima);
-/* For multiple slot render, call this before render. */
+/**
+ * For multiple slot render, call this before render.
+ */
void BKE_image_backup_render(struct Scene *scene, struct Image *ima, bool free_current_slot);
-/* For single-layer OpenEXR saving */
+/**
+ * For single-layer OpenEXR saving.
+ */
bool BKE_image_save_openexr_multiview(struct Image *ima,
struct ImBuf *ibuf,
const char *filepath,
const int flags);
-/* goes over all textures that use images */
+/**
+ * Goes over all textures that use images.
+ */
void BKE_image_free_all_textures(struct Main *bmain);
-/* does one image! */
+/**
+ * Operates on one image only!
+ * \param except_frame: This is weak, only works for sequences without offset.
+ */
void BKE_image_free_anim_ibufs(struct Image *ima, int except_frame);
-/* does all images with type MOVIE or SEQUENCE */
+/**
+ * Does all images with type MOVIE or SEQUENCE.
+ */
void BKE_image_all_free_anim_ibufs(struct Main *bmain, int cfra);
void BKE_image_free_all_gputextures(struct Main *bmain);
+/**
+ * Same as above but only free animated images.
+ */
void BKE_image_free_anim_gputextures(struct Main *bmain);
void BKE_image_free_old_gputextures(struct Main *bmain);
+/**
+ * Pack image to memory.
+ */
bool BKE_image_memorypack(struct Image *ima);
void BKE_image_packfiles(struct ReportList *reports, struct Image *ima, const char *basepath);
void BKE_image_packfiles_from_mem(struct ReportList *reports,
@@ -278,22 +364,34 @@ void BKE_image_packfiles_from_mem(struct ReportList *reports,
char *data,
const size_t data_len);
-/* Prints memory statistics for images. */
+/**
+ * Prints memory statistics for images.
+ */
void BKE_image_print_memlist(struct Main *bmain);
-/* Merge source into dest, and free source. */
+/**
+ * Merge source into `dest`, and free `source`.
+ */
void BKE_image_merge(struct Main *bmain, struct Image *dest, struct Image *source);
-/* Scale the image. */
+/**
+ * Scale the image.
+ */
bool BKE_image_scale(struct Image *image, int width, int height);
-/* Check if texture has alpha (depth=32). */
+/**
+ * Check if texture has alpha (depth=32).
+ */
bool BKE_image_has_alpha(struct Image *image);
-/* Check if texture has GPU texture code. */
+/**
+ * Check if texture has GPU texture code.
+ */
bool BKE_image_has_opengl_texture(struct Image *ima);
-/* Get tile index for tiled images. */
+/**
+ * Get tile index for tiled images.
+ */
void BKE_image_get_tile_label(struct Image *ima,
struct ImageTile *tile,
char *label,
@@ -320,6 +418,9 @@ int BKE_image_get_tile_from_pos(struct Image *ima,
const float uv[2],
float r_uv[2],
float r_ofs[2]);
+/**
+ * Return the tile_number for the closest UDIM tile.
+ */
int BKE_image_find_nearest_tile(const struct Image *image, const float co[2]);
void BKE_image_get_size(struct Image *image, struct ImageUser *iuser, int *r_width, int *r_height);
@@ -327,6 +428,7 @@ void BKE_image_get_size_fl(struct Image *image, struct ImageUser *iuser, float r
void BKE_image_get_aspect(struct Image *image, float *r_aspx, float *r_aspy);
/* image_gen.c */
+
void BKE_image_buf_fill_color(
unsigned char *rect, float *rect_float, int width, int height, const float color[4]);
void BKE_image_buf_fill_checker(unsigned char *rect, float *rect_float, int width, int height);
@@ -336,36 +438,64 @@ void BKE_image_buf_fill_checker_color(unsigned char *rect,
int height);
/* Cycles hookup */
+
unsigned char *BKE_image_get_pixels_for_frame(struct Image *image, int frame, int tile);
float *BKE_image_get_float_pixels_for_frame(struct Image *image, int frame, int tile);
/* Image modifications */
+
bool BKE_image_is_dirty(struct Image *image);
void BKE_image_mark_dirty(struct Image *image, struct ImBuf *ibuf);
bool BKE_image_buffer_format_writable(struct ImBuf *ibuf);
+
bool BKE_image_is_dirty_writable(struct Image *image, bool *is_format_writable);
-/* Guess offset for the first frame in the sequence */
+/**
+ * Guess offset for the first frame in the sequence.
+ */
int BKE_image_sequence_guess_offset(struct Image *image);
bool BKE_image_has_anim(struct Image *image);
bool BKE_image_has_packedfile(const struct Image *image);
bool BKE_image_has_filepath(struct Image *ima);
+/**
+ * Checks the image buffer changes with time (not keyframed values).
+ */
bool BKE_image_is_animated(struct Image *image);
+/**
+ * Checks whether the image consists of multiple buffers.
+ */
bool BKE_image_has_multiple_ibufs(struct Image *image);
void BKE_image_file_format_set(struct Image *image,
int ftype,
const struct ImbFormatOptions *options);
bool BKE_image_has_loaded_ibuf(struct Image *image);
+/**
+ * References the result, #BKE_image_release_ibuf is to be called to de-reference.
+ * Use lock=NULL when calling #BKE_image_release_ibuf().
+ */
struct ImBuf *BKE_image_get_ibuf_with_name(struct Image *image, const char *name);
+/**
+ * References the result, #BKE_image_release_ibuf is to be called to de-reference.
+ * Use lock=NULL when calling #BKE_image_release_ibuf().
+ *
+ * TODO(sergey): This is actually "get first item from the cache", which is
+ * not so much predictable. But using first loaded image buffer
+ * was also malicious logic and all the areas which uses this
+ * function are to be re-considered.
+ */
struct ImBuf *BKE_image_get_first_ibuf(struct Image *image);
-/* Not to be use directly. */
+/**
+ * Not to be use directly.
+ */
struct GPUTexture *BKE_image_create_gpu_texture_from_ibuf(struct Image *image, struct ImBuf *ibuf);
-/* Get the #GPUTexture for a given `Image`.
+/**
+ * Get the #GPUTexture for a given `Image`.
*
* `iuser` and `ibuf` are mutual exclusive parameters. The caller can pass the `ibuf` when already
- * available. It is also required when requesting the #GPUTexture for a render result. */
+ * available. It is also required when requesting the #GPUTexture for a render result.
+ */
struct GPUTexture *BKE_image_get_gpu_texture(struct Image *image,
struct ImageUser *iuser,
struct ImBuf *ibuf);
@@ -375,14 +505,33 @@ struct GPUTexture *BKE_image_get_gpu_tiles(struct Image *image,
struct GPUTexture *BKE_image_get_gpu_tilemap(struct Image *image,
struct ImageUser *iuser,
struct ImBuf *ibuf);
+/**
+ * Is the alpha of the `GPUTexture` for a given image/ibuf premultiplied.
+ */
bool BKE_image_has_gpu_texture_premultiplied_alpha(struct Image *image, struct ImBuf *ibuf);
+/**
+ * Partial update of texture for texture painting.
+ * This is often much quicker than fully updating the texture for high resolution images.
+ */
void BKE_image_update_gputexture(
struct Image *ima, struct ImageUser *iuser, int x, int y, int w, int h);
+/**
+ * Mark areas on the #GPUTexture that needs to be updated. The areas are marked in chunks.
+ * The next time the #GPUTexture is used these tiles will be refreshes. This saves time
+ * when writing to the same place multiple times This happens for during foreground rendering.
+ */
void BKE_image_update_gputexture_delayed(
struct Image *ima, struct ImBuf *ibuf, int x, int y, int w, int h);
+/**
+ * Called on entering and exiting texture paint mode,
+ * temporary disabling/enabling mipmapping on all images for quick texture
+ * updates with glTexSubImage2D. images that didn't change don't have to be re-uploaded to OpenGL.
+ */
void BKE_image_paint_set_mipmap(struct Main *bmain, bool mipmap);
-/* Delayed free of OpenGL buffers by main thread */
+/**
+ * Delayed free of OpenGL buffers by main thread.
+ */
void BKE_image_free_unused_gpu_textures(void);
struct RenderSlot *BKE_image_add_renderslot(struct Image *ima, const char *name);
diff --git a/source/blender/blenkernel/BKE_ipo.h b/source/blender/blenkernel/BKE_ipo.h
index f4871c83caf..5899db6c6ce 100644
--- a/source/blender/blenkernel/BKE_ipo.h
+++ b/source/blender/blenkernel/BKE_ipo.h
@@ -28,6 +28,19 @@ extern "C" {
struct Main;
+/**
+ * Called from #do_versions() in `readfile.c` to convert the old 'IPO/adrcode' system
+ * to the new 'Animato/RNA' system.
+ *
+ * The basic method used here, is to loop over data-blocks which have IPO-data,
+ * and add those IPO's to new AnimData blocks as Actions.
+ * Action/NLA data only works well for Objects, so these only need to be checked for there.
+ *
+ * Data that has been converted should be freed immediately, which means that it is immediately
+ * clear which data-blocks have yet to be converted, and also prevent freeing errors when we exit.
+ *
+ * \note Currently done after all file reading.
+ */
void do_versions_ipos_to_animato(struct Main *main);
/* --------------------- xxx stuff ------------------------ */
diff --git a/source/blender/blenkernel/BKE_key.h b/source/blender/blenkernel/BKE_key.h
index cb4fc607703..de069d6236f 100644
--- a/source/blender/blenkernel/BKE_key.h
+++ b/source/blender/blenkernel/BKE_key.h
@@ -36,21 +36,44 @@ struct Object;
extern "C" {
#endif
+/**
+ * Free (or release) any data used by this shapekey (does not free the key itself).
+ */
void BKE_key_free_data(struct Key *key);
void BKE_key_free_nolib(struct Key *key);
struct Key *BKE_key_add(struct Main *bmain, struct ID *id);
+/**
+ * Sort shape keys after a change.
+ * This assumes that at most one key was moved,
+ * which is a valid assumption for the places it's currently being called.
+ */
void BKE_key_sort(struct Key *key);
void key_curve_position_weights(float t, float data[4], int type);
+/**
+ * First derivative.
+ */
void key_curve_tangent_weights(float t, float data[4], int type);
+/**
+ * Second derivative.
+ */
void key_curve_normal_weights(float t, float data[4], int type);
+/**
+ * Returns key coordinates (+ tilt) when key applied, NULL otherwise.
+ */
float *BKE_key_evaluate_object_ex(struct Object *ob, int *r_totelem, float *arr, size_t arr_size);
float *BKE_key_evaluate_object(struct Object *ob, int *r_totelem);
+/**
+ * \param shape_index: The index to use or all (when -1).
+ */
int BKE_keyblock_element_count_from_shape(const struct Key *key, const int shape_index);
int BKE_keyblock_element_count(const struct Key *key);
+/**
+ * \param shape_index: The index to use or all (when -1).
+ */
size_t BKE_keyblock_element_calc_size_from_shape(const struct Key *key, const int shape_index);
size_t BKE_keyblock_element_calc_size(const struct Key *key);
@@ -60,18 +83,43 @@ struct Key **BKE_key_from_id_p(struct ID *id);
struct Key *BKE_key_from_id(struct ID *id);
struct Key **BKE_key_from_object_p(const struct Object *ob);
struct Key *BKE_key_from_object(const struct Object *ob);
+/**
+ * Only the active key-block.
+ */
struct KeyBlock *BKE_keyblock_from_object(struct Object *ob);
struct KeyBlock *BKE_keyblock_from_object_reference(struct Object *ob);
struct KeyBlock *BKE_keyblock_add(struct Key *key, const char *name);
+/**
+ * \note sorting is a problematic side effect in some cases,
+ * better only do this explicitly by having its own function,
+ *
+ * \param key: The key datablock to add to.
+ * \param name: Optional name for the new keyblock.
+ * \param do_force: always use ctime even for relative keys.
+ */
struct KeyBlock *BKE_keyblock_add_ctime(struct Key *key, const char *name, const bool do_force);
+/**
+ * Get the appropriate #KeyBlock given an index.
+ */
struct KeyBlock *BKE_keyblock_from_key(struct Key *key, int index);
+/**
+ * Get the appropriate #KeyBlock given a name to search for.
+ */
struct KeyBlock *BKE_keyblock_find_name(struct Key *key, const char name[]);
+/**
+ * \brief copy shape-key attributes, but not key data or name/UID.
+ */
void BKE_keyblock_copy_settings(struct KeyBlock *kb_dst, const struct KeyBlock *kb_src);
+/**
+ * Get RNA-Path for 'value' setting of the given shape-key.
+ * \note the user needs to free the returned string once they're finish with it.
+ */
char *BKE_keyblock_curval_rnapath_get(struct Key *key, struct KeyBlock *kb);
/* conversion functions */
/* NOTE: 'update_from' versions do not (re)allocate mem in kb, while 'convert_from' do. */
+
void BKE_keyblock_update_from_lattice(struct Lattice *lt, struct KeyBlock *kb);
void BKE_keyblock_convert_from_lattice(struct Lattice *lt, struct KeyBlock *kb);
void BKE_keyblock_convert_to_lattice(struct KeyBlock *kb, struct Lattice *lt);
@@ -88,6 +136,15 @@ void BKE_keyblock_convert_to_curve(struct KeyBlock *kb, struct Curve *cu, struct
void BKE_keyblock_update_from_mesh(struct Mesh *me, struct KeyBlock *kb);
void BKE_keyblock_convert_from_mesh(struct Mesh *me, struct Key *key, struct KeyBlock *kb);
void BKE_keyblock_convert_to_mesh(struct KeyBlock *kb, struct Mesh *me);
+/**
+ * Computes normals (vertices, polygons and/or loops ones) of given mesh for given shape key.
+ *
+ * \param kb: the KeyBlock to use to compute normals.
+ * \param mesh: the Mesh to apply key-block to.
+ * \param r_vertnors: if non-NULL, an array of vectors, same length as number of vertices.
+ * \param r_polynors: if non-NULL, an array of vectors, same length as number of polygons.
+ * \param r_loopnors: if non-NULL, an array of vectors, same length as number of loops.
+ */
void BKE_keyblock_mesh_calc_normals(struct KeyBlock *kb,
struct Mesh *mesh,
float (*r_vertnors)[3],
@@ -107,28 +164,54 @@ void BKE_keyblock_update_from_offset(struct Object *ob,
const float (*ofs)[3]);
/* other management */
+
+/**
+ * Move shape key from org_index to new_index. Safe, clamps index to valid range,
+ * updates reference keys, the object's active shape index,
+ * the 'frame' value in case of absolute keys, etc.
+ * Note indices are expected in real values (not 'fake' shapenr +1 ones).
+ *
+ * \param org_index: if < 0, current object's active shape will be used as skey to move.
+ * \return true if something was done, else false.
+ */
bool BKE_keyblock_move(struct Object *ob, int org_index, int new_index);
+/**
+ * Check if given key-block (as index) is used as basis by others in given key.
+ */
bool BKE_keyblock_is_basis(struct Key *key, const int index);
/* -------------------------------------------------------------------- */
/** \name Key-Block Data Access
* \{ */
+/**
+ * \param shape_index: The index to use or all (when -1).
+ */
void BKE_keyblock_data_get_from_shape(const struct Key *key,
float (*arr)[3],
const int shape_index);
void BKE_keyblock_data_get(const struct Key *key, float (*arr)[3]);
+/**
+ * Set the data to all key-blocks (or shape_index if != -1).
+ */
void BKE_keyblock_data_set_with_mat4(struct Key *key,
const int shape_index,
const float (*coords)[3],
const float mat[4][4]);
+/**
+ * Set the data for all key-blocks (or shape_index if != -1),
+ * transforming by \a mat.
+ */
void BKE_keyblock_curve_data_set_with_mat4(struct Key *key,
const struct ListBase *nurb,
const int shape_index,
const void *data,
const float mat[4][4]);
+/**
+ * Set the data for all key-blocks (or shape_index if != -1).
+ */
void BKE_keyblock_data_set(struct Key *key, const int shape_index, const void *data);
/** \} */
diff --git a/source/blender/blenkernel/BKE_keyconfig.h b/source/blender/blenkernel/BKE_keyconfig.h
index 1cacbf61976..132994ede3a 100644
--- a/source/blender/blenkernel/BKE_keyconfig.h
+++ b/source/blender/blenkernel/BKE_keyconfig.h
@@ -43,10 +43,12 @@ typedef struct wmKeyConfigPrefType_Runtime {
typedef struct wmKeyConfigPrefType_Runtime wmKeyConfigPrefType_Runtime;
#endif
-/* KeyConfig preferences (UserDef). */
+/* KeyConfig preferences (#UserDef). */
+
struct wmKeyConfigPref *BKE_keyconfig_pref_ensure(struct UserDef *userdef, const char *kc_idname);
/* KeyConfig preferences (RNA). */
+
struct wmKeyConfigPrefType_Runtime *BKE_keyconfig_pref_type_find(const char *idname, bool quiet);
void BKE_keyconfig_pref_type_add(struct wmKeyConfigPrefType_Runtime *kpt_rt);
void BKE_keyconfig_pref_type_remove(const struct wmKeyConfigPrefType_Runtime *kpt_rt);
@@ -55,6 +57,10 @@ void BKE_keyconfig_pref_type_init(void);
void BKE_keyconfig_pref_type_free(void);
/* Versioning. */
+
+/**
+ * Set select mouse, for versioning code.
+ */
void BKE_keyconfig_pref_set_select_mouse(struct UserDef *userdef, int value, bool override);
struct wmKeyConfigFilterItemParams {
@@ -67,6 +73,10 @@ void BKE_keyconfig_keymap_filter_item(struct wmKeyMap *keymap,
const struct wmKeyConfigFilterItemParams *params,
bool (*filter_fn)(struct wmKeyMapItem *kmi, void *user_data),
void *user_data);
+/**
+ * Filter & optionally remove key-map items,
+ * intended for versioning, but may be used in other situations too.
+ */
void BKE_keyconfig_pref_filter_items(struct UserDef *userdef,
const struct wmKeyConfigFilterItemParams *params,
bool (*filter_fn)(struct wmKeyMapItem *kmi, void *user_data),
diff --git a/source/blender/blenkernel/BKE_lattice.h b/source/blender/blenkernel/BKE_lattice.h
index 02fa8b306d3..bf03e99bbc3 100644
--- a/source/blender/blenkernel/BKE_lattice.h
+++ b/source/blender/blenkernel/BKE_lattice.h
@@ -132,6 +132,7 @@ void BKE_lattice_deform_coords_with_editmesh(const struct Object *ob_lattice,
const char *defgrp_name,
const float fac,
struct BMEditMesh *em_target);
+
/** \} */
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_layer.h b/source/blender/blenkernel/BKE_layer.h
index 08b44959096..b2fa464aedc 100644
--- a/source/blender/blenkernel/BKE_layer.h
+++ b/source/blender/blenkernel/BKE_layer.h
@@ -52,23 +52,57 @@ typedef enum eViewLayerCopyMethod {
VIEWLAYER_ADD_COPY = 2,
} eViewLayerCopyMethod;
+/**
+ * Returns the default view layer to view in work-spaces if there is
+ * none linked to the workspace yet.
+ */
struct ViewLayer *BKE_view_layer_default_view(const struct Scene *scene);
+/**
+ * Returns the default view layer to render if we need to render just one.
+ */
struct ViewLayer *BKE_view_layer_default_render(const struct Scene *scene);
+/**
+ * Returns view layer with matching name, or NULL if not found.
+ */
struct ViewLayer *BKE_view_layer_find(const struct Scene *scene, const char *layer_name);
+/**
+ * Add a new view layer by default, a view layer has the master collection.
+ */
struct ViewLayer *BKE_view_layer_add(struct Scene *scene,
const char *name,
struct ViewLayer *view_layer_source,
const int type);
/* DEPRECATED */
+/**
+ * This is a placeholder to know which areas of the code need to be addressed
+ * for the Workspace changes. Never use this, you should typically get the
+ * active layer from the context or window.
+ */
struct ViewLayer *BKE_view_layer_context_active_PLACEHOLDER(const struct Scene *scene);
void BKE_view_layer_free(struct ViewLayer *view_layer);
+/**
+ * Free (or release) any data used by this #ViewLayer.
+ */
void BKE_view_layer_free_ex(struct ViewLayer *view_layer, const bool do_id_user);
+/**
+ * Tag all the selected objects of a render-layer.
+ */
void BKE_view_layer_selected_objects_tag(struct ViewLayer *view_layer, const int tag);
+/**
+ * Fallback for when a Scene has no camera to use.
+ *
+ * \param view_layer: in general you want to use the same #ViewLayer that is used for depsgraph.
+ * If rendering you pass the scene active layer, when viewing in the viewport
+ * you want to get #ViewLayer from context.
+ */
struct Object *BKE_view_layer_camera_find(struct ViewLayer *view_layer);
+/**
+ * Find the #ViewLayer a #LayerCollection belongs to.
+ */
struct ViewLayer *BKE_view_layer_find_from_collection(const struct Scene *scene,
struct LayerCollection *lc);
struct Base *BKE_view_layer_base_find(struct ViewLayer *view_layer, struct Object *ob);
@@ -76,6 +110,11 @@ void BKE_view_layer_base_deselect_all(struct ViewLayer *view_layer);
void BKE_view_layer_base_select_and_set_active(struct ViewLayer *view_layer, struct Base *selbase);
+/**
+ * Only copy internal data of #ViewLayer from source to already allocated/initialized destination.
+ *
+ * \param flag: Copying options (see BKE_lib_id.h's LIB_ID_COPY_... flags for more).
+ */
void BKE_view_layer_copy_data(struct Scene *scene_dst,
const struct Scene *scene_src,
struct ViewLayer *view_layer_dst,
@@ -87,15 +126,33 @@ void BKE_view_layer_rename(struct Main *bmain,
struct ViewLayer *view_layer,
const char *name);
+/**
+ * Get the active collection
+ */
struct LayerCollection *BKE_layer_collection_get_active(struct ViewLayer *view_layer);
+/**
+ * Activate collection
+ */
bool BKE_layer_collection_activate(struct ViewLayer *view_layer, struct LayerCollection *lc);
+/**
+ * Activate first parent collection.
+ */
struct LayerCollection *BKE_layer_collection_activate_parent(struct ViewLayer *view_layer,
struct LayerCollection *lc);
+/**
+ * Get the total number of collections (including all the nested collections)
+ */
int BKE_layer_collection_count(const struct ViewLayer *view_layer);
+/**
+ * Get the collection for a given index.
+ */
struct LayerCollection *BKE_layer_collection_from_index(struct ViewLayer *view_layer,
const int index);
+/**
+ * \return -1 if not found.
+ */
int BKE_layer_collection_findindex(struct ViewLayer *view_layer, const struct LayerCollection *lc);
void BKE_layer_collection_resync_forbid(void);
@@ -103,20 +160,43 @@ void BKE_layer_collection_resync_allow(void);
void BKE_main_collection_sync(const struct Main *bmain);
void BKE_scene_collection_sync(const struct Scene *scene);
+/**
+ * Update view layer collection tree from collections used in the scene.
+ * This is used when collections are removed or added, both while editing
+ * and on file loaded in case linked data changed or went missing.
+ */
void BKE_layer_collection_sync(const struct Scene *scene, struct ViewLayer *view_layer);
void BKE_layer_collection_local_sync(struct ViewLayer *view_layer, const struct View3D *v3d);
+/**
+ * Sync the local collection for all the 3D Viewports.
+ */
void BKE_layer_collection_local_sync_all(const struct Main *bmain);
void BKE_main_collection_sync_remap(const struct Main *bmain);
+/**
+ * Return the first matching #LayerCollection in the #ViewLayer for the Collection.
+ */
struct LayerCollection *BKE_layer_collection_first_from_scene_collection(
const struct ViewLayer *view_layer, const struct Collection *collection);
+/**
+ * See if view layer has the scene collection linked directly, or indirectly (nested).
+ */
bool BKE_view_layer_has_collection(const struct ViewLayer *view_layer,
const struct Collection *collection);
+/**
+ * See if the object is in any of the scene layers of the scene.
+ */
bool BKE_scene_has_object(struct Scene *scene, struct Object *ob);
-/* selection and hiding */
+/* Selection and hiding. */
+/**
+ * Select all the objects of this layer collection
+ *
+ * It also select the objects that are in nested collections.
+ * \note Recursive.
+ */
bool BKE_layer_collection_objects_select(struct ViewLayer *view_layer,
struct LayerCollection *lc,
bool deselect);
@@ -125,28 +205,54 @@ bool BKE_layer_collection_has_selected_objects(struct ViewLayer *view_layer,
bool BKE_layer_collection_has_layer_collection(struct LayerCollection *lc_parent,
struct LayerCollection *lc_child);
+/**
+ * Update after toggling visibility of an object base.
+ */
void BKE_base_set_visible(struct Scene *scene,
struct ViewLayer *view_layer,
struct Base *base,
bool extend);
bool BKE_base_is_visible(const struct View3D *v3d, const struct Base *base);
bool BKE_object_is_visible_in_viewport(const struct View3D *v3d, const struct Object *ob);
+/**
+ * Isolate the collection - hide all other collections but this one.
+ * Make sure to show all the direct parents and all children of the layer collection as well.
+ * When extending we simply show the collections and its direct family.
+ *
+ * If the collection or any of its parents is disabled, make it enabled.
+ * Don't change the children disable state though.
+ */
void BKE_layer_collection_isolate_global(struct Scene *scene,
struct ViewLayer *view_layer,
struct LayerCollection *lc,
bool extend);
+/**
+ * Isolate the collection locally
+ *
+ * Same as #BKE_layer_collection_isolate_local but for a viewport
+ */
void BKE_layer_collection_isolate_local(struct ViewLayer *view_layer,
const struct View3D *v3d,
struct LayerCollection *lc,
bool extend);
+/**
+ * Hide/show all the elements of a collection.
+ * Don't change the collection children enable/disable state,
+ * but it may change it for the collection itself.
+ */
void BKE_layer_collection_set_visible(struct ViewLayer *view_layer,
struct LayerCollection *lc,
const bool visible,
const bool hierarchy);
void BKE_layer_collection_set_flag(struct LayerCollection *lc, const int flag, const bool value);
-/* evaluation */
+/* Evaluation. */
+/**
+ * Applies object's restrict flags on top of flags coming from the collection
+ * and stores those in `base->flag`. #BASE_VISIBLE_DEPSGRAPH ignores viewport flags visibility
+ * (i.e., restriction and local collection).
+ */
void BKE_base_eval_flags(struct Base *base);
void BKE_layer_eval_view_layer_indexed(struct Depsgraph *depsgraph,
@@ -380,6 +486,13 @@ struct Object **BKE_view_layer_array_selected_objects_params(
uint *r_len,
const struct ObjectsInViewLayerParams *params);
+/**
+ * Use this in rare cases we need to detect a pair of objects (active, selected).
+ * This returns the other non-active selected object.
+ *
+ * Returns NULL with it finds multiple other selected objects
+ * as behavior in this case would be random from the user perspective.
+ */
struct Object *BKE_view_layer_non_active_selected_object(struct ViewLayer *view_layer,
const struct View3D *v3d);
@@ -451,9 +564,20 @@ bool BKE_view_layer_filter_edit_mesh_has_edges(const struct Object *ob, void *us
struct ViewLayerAOV *BKE_view_layer_add_aov(struct ViewLayer *view_layer);
void BKE_view_layer_remove_aov(struct ViewLayer *view_layer, struct ViewLayerAOV *aov);
void BKE_view_layer_set_active_aov(struct ViewLayer *view_layer, struct ViewLayerAOV *aov);
+/**
+ * Update the naming and conflicts of the AOVs.
+ *
+ * Name must be unique between all AOVs.
+ * Conflicts with render passes will show a conflict icon. Reason is that switching a render
+ * engine or activating a render pass could lead to other conflicts that wouldn't be that clear
+ * for the user.
+ */
void BKE_view_layer_verify_aov(struct RenderEngine *engine,
struct Scene *scene,
struct ViewLayer *view_layer);
+/**
+ * Check if the given view layer has at least one valid AOV.
+ */
bool BKE_view_layer_has_valid_aov(struct ViewLayer *view_layer);
struct ViewLayer *BKE_view_layer_find_with_aov(struct Scene *scene,
struct ViewLayerAOV *view_layer_aov);
diff --git a/source/blender/blenkernel/BKE_lib_id.h b/source/blender/blenkernel/BKE_lib_id.h
index 359fb72534a..34339c4ff9f 100644
--- a/source/blender/blenkernel/BKE_lib_id.h
+++ b/source/blender/blenkernel/BKE_lib_id.h
@@ -62,21 +62,65 @@ struct PointerRNA;
struct PropertyRNA;
struct bContext;
+/**
+ * Get allocation size of a given data-block type and optionally allocation name.
+ */
size_t BKE_libblock_get_alloc_info(short type, const char **name);
+/**
+ * Allocates and returns memory of the right size for the specified block type,
+ * initialized to zero.
+ */
void *BKE_libblock_alloc_notest(short type) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Allocates and returns a block of the specified type, with the specified name
+ * (adjusted as necessary to ensure uniqueness), and appended to the specified list.
+ * The user count is set to 1, all other content (apart from name and links) being
+ * initialized to zero.
+ */
void *BKE_libblock_alloc(struct Main *bmain, short type, const char *name, const int flag)
ATTR_WARN_UNUSED_RESULT;
+/**
+ * Initialize an ID of given type, such that it has valid 'empty' data.
+ * ID is assumed to be just calloc'ed.
+ */
void BKE_libblock_init_empty(struct ID *id) ATTR_NONNULL(1);
/* *** ID's session_uuid management. *** */
-/* When an ID's uuid is of that value, it is unset/invalid (e.g. for runtime IDs, etc.). */
+/**
+ * When an ID's uuid is of that value, it is unset/invalid (e.g. for runtime IDs, etc.).
+ */
#define MAIN_ID_SESSION_UUID_UNSET 0
+/**
+ * Generate a session-wise uuid for the given \a id.
+ *
+ * \note "session-wise" here means while editing a given .blend file. Once a new .blend file is
+ * loaded or created, undo history is cleared/reset, and so is the uuid counter.
+ */
void BKE_lib_libblock_session_uuid_ensure(struct ID *id);
+/**
+ * Re-generate a new session-wise uuid for the given \a id.
+ *
+ * \warning This has a few very specific use-cases, no other usage is expected currently:
+ * - To handle UI-related data-blocks that are kept across new file reading, when we do keep
+ * existing UI.
+ * - For IDs that are made local without needing any copying.
+ */
void BKE_lib_libblock_session_uuid_renew(struct ID *id);
+/**
+ * Generic helper to create a new empty data-block of given type in given \a bmain database.
+ *
+ * \param name: can be NULL, in which case we get default name for this ID type.
+ */
void *BKE_id_new(struct Main *bmain, const short type, const char *name);
+/**
+ * Generic helper to create a new temporary empty data-block of given type,
+ * *outside* of any Main database.
+ *
+ * \param name: can be NULL, in which case we get default name for this ID type.
+ */
void *BKE_id_new_nomain(const short type, const char *name);
/**
@@ -159,10 +203,20 @@ void BKE_libblock_copy_ex(struct Main *bmain,
const struct ID *id,
struct ID **r_newid,
const int orig_flag);
+/**
+ * Used everywhere in blenkernel.
+ */
void *BKE_libblock_copy(struct Main *bmain, const struct ID *id) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Sets the name of a block to name, suitably adjusted for uniqueness.
+ */
void BKE_libblock_rename(struct Main *bmain, struct ID *id, const char *name) ATTR_NONNULL();
+/**
+ * Use after setting the ID's name
+ * When name exists: call 'new_id'
+ */
void BLI_libblock_ensure_unique_name(struct Main *bmain, const char *name) ATTR_NONNULL();
struct ID *BKE_libblock_find_name(struct Main *bmain,
@@ -216,17 +270,70 @@ enum {
void BKE_libblock_free_datablock(struct ID *id, const int flag) ATTR_NONNULL();
void BKE_libblock_free_data(struct ID *id, const bool do_id_user) ATTR_NONNULL();
+/**
+ * In most cases #BKE_id_free_ex handles this, when lower level functions are called directly
+ * this function will need to be called too, if Python has access to the data.
+ *
+ * ID data-blocks such as #Material.nodetree are not stored in #Main.
+ */
void BKE_libblock_free_data_py(struct ID *id);
+/**
+ * Complete ID freeing, extended version for corner cases.
+ * Can override default (and safe!) freeing process, to gain some speed up.
+ *
+ * At that point, given id is assumed to not be used by any other data-block already
+ * (might not be actually true, in case e.g. several inter-related IDs get freed together...).
+ * However, they might still be using (referencing) other IDs, this code takes care of it if
+ * #LIB_TAG_NO_USER_REFCOUNT is not defined.
+ *
+ * \param bmain: #Main database containing the freed #ID,
+ * can be NULL in case it's a temp ID outside of any #Main.
+ * \param idv: Pointer to ID to be freed.
+ * \param flag: Set of \a LIB_ID_FREE_... flags controlling/overriding usual freeing process,
+ * 0 to get default safe behavior.
+ * \param use_flag_from_idtag: Still use freeing info flags from given #ID datablock,
+ * even if some overriding ones are passed in \a flag parameter.
+ */
void BKE_id_free_ex(struct Main *bmain, void *idv, int flag, const bool use_flag_from_idtag);
+/**
+ * Complete ID freeing, should be usable in most cases (even for out-of-Main IDs).
+ *
+ * See #BKE_id_free_ex description for full details.
+ *
+ * \param bmain: Main database containing the freed ID,
+ * can be NULL in case it's a temp ID outside of any Main.
+ * \param idv: Pointer to ID to be freed.
+ */
void BKE_id_free(struct Main *bmain, void *idv);
+/**
+ * Not really a freeing function by itself,
+ * it decrements usercount of given id, and only frees it if it reaches 0.
+ */
void BKE_id_free_us(struct Main *bmain, void *idv) ATTR_NONNULL();
+/**
+ * Properly delete a single ID from given \a bmain database.
+ */
void BKE_id_delete(struct Main *bmain, void *idv) ATTR_NONNULL();
+/**
+ * Properly delete all IDs tagged with \a LIB_TAG_DOIT, in given \a bmain database.
+ *
+ * This is more efficient than calling #BKE_id_delete repetitively on a large set of IDs
+ * (several times faster when deleting most of the IDs at once).
+ *
+ * \warning Considered experimental for now, seems to be working OK but this is
+ * risky code in a complicated area.
+ * \return Number of deleted datablocks.
+ */
size_t BKE_id_multi_tagged_delete(struct Main *bmain) ATTR_NONNULL();
+/**
+ * Add a 'NO_MAIN' data-block to given main (also sets usercounts of its IDs if needed).
+ */
void BKE_libblock_management_main_add(struct Main *bmain, void *idv);
+/** Remove a data-block from given main (set it to 'NO_MAIN' status). */
void BKE_libblock_management_main_remove(struct Main *bmain, void *idv);
void BKE_libblock_management_usercounts_set(struct Main *bmain, void *idv);
@@ -234,10 +341,23 @@ void BKE_libblock_management_usercounts_clear(struct Main *bmain, void *idv);
void id_lib_extern(struct ID *id);
void id_lib_indirect_weak_link(struct ID *id);
+/**
+ * Ensure we have a real user
+ *
+ * \note Now that we have flags, we could get rid of the 'fake_user' special case,
+ * flags are enough to ensure we always have a real user.
+ * However, #ID_REAL_USERS is used in several places outside of core lib.c,
+ * so think we can wait later to make this change.
+ */
void id_us_ensure_real(struct ID *id);
void id_us_clear_real(struct ID *id);
+/**
+ * Same as \a id_us_plus, but does not handle lib indirect -> extern.
+ * Only used by readfile.c so far, but simpler/safer to keep it here nonetheless.
+ */
void id_us_plus_no_lib(struct ID *id);
void id_us_plus(struct ID *id);
+/* decrements the user count for *id. */
void id_us_min(struct ID *id);
void id_fake_user_set(struct ID *id);
void id_fake_user_clear(struct ID *id);
@@ -262,66 +382,212 @@ enum {
LIB_ID_MAKELOCAL_OBJECT_NO_PROXY_CLEARING = 1 << 16,
};
+/**
+ * Generic 'make local' function, works for most of data-block types.
+ */
void BKE_lib_id_make_local_generic(struct Main *bmain, struct ID *id, const int flags);
+/**
+ * Calls the appropriate make_local method for the block, unless test is set.
+ *
+ * \note Always set #ID.newid pointer in case it gets duplicated.
+ *
+ * \param flags: Special flag used when making a whole library's content local,
+ * it needs specific handling.
+ * \return true is the ID has successfully been made local.
+ */
bool BKE_lib_id_make_local(struct Main *bmain, struct ID *id, const int flags);
+/**
+ * \note Does *not* set #ID.newid pointer.
+ */
bool id_single_user(struct bContext *C,
struct ID *id,
struct PointerRNA *ptr,
struct PropertyRNA *prop);
bool BKE_id_copy_is_allowed(const struct ID *id);
+/**
+ * Invokes the appropriate copy method for the block and returns the result in
+ * #ID.newid, unless test. Returns true if the block can be copied.
+ */
struct ID *BKE_id_copy(struct Main *bmain, const struct ID *id);
+/**
+ * Generic entry point for copying a data-block (new API).
+ *
+ * \note Copy is generally only affecting the given data-block
+ * (no ID used by copied one will be affected, besides user-count).
+ *
+ * There are exceptions though:
+ * - Embedded IDs (root node trees and master collections) are always copied with their owner.
+ * - If #LIB_ID_COPY_ACTIONS is defined, actions used by animdata will be duplicated.
+ * - If #LIB_ID_COPY_SHAPEKEY is defined, shape-keys will be duplicated.
+ * - If #LIB_ID_CREATE_LOCAL is defined, root node trees will be deep-duplicated recursively.
+ *
+ * \note User-count of new copy is always set to 1.
+ *
+ * \param bmain: Main database, may be NULL only if LIB_ID_CREATE_NO_MAIN is specified.
+ * \param id: Source data-block.
+ * \param r_newid: Pointer to new (copied) ID pointer, may be NULL.
+ * Used to allow copying into already allocated memory.
+ * \param flag: Set of copy options, see `DNA_ID.h` enum for details
+ * (leave to zero for default, full copy).
+ * \return NULL when copying that ID type is not supported, the new copy otherwise.
+ */
struct ID *BKE_id_copy_ex(struct Main *bmain,
const struct ID *id,
struct ID **r_newid,
const int flag);
+/**
+ * Invokes the appropriate copy method for the block and returns the result in
+ * newid, unless test. Returns true if the block can be copied.
+ */
struct ID *BKE_id_copy_for_duplicate(struct Main *bmain,
struct ID *id,
const uint duplicate_flags,
const int copy_flags);
+/**
+ * Does a mere memory swap over the whole IDs data (including type-specific memory).
+ * \note Most internal ID data itself is not swapped (only IDProperties are).
+ *
+ * \param bmain: May be NULL, in which case there will be no remapping of internal pointers to
+ * itself.
+ */
void BKE_lib_id_swap(struct Main *bmain, struct ID *id_a, struct ID *id_b);
+/**
+ * Does a mere memory swap over the whole IDs data (including type-specific memory).
+ * \note All internal ID data itself is also swapped.
+ *
+ * \param bmain: May be NULL, in which case there will be no remapping of internal pointers to
+ * itself.
+ */
void BKE_lib_id_swap_full(struct Main *bmain, struct ID *id_a, struct ID *id_b);
+/**
+ * Sort given \a id into given \a lb list, using case-insensitive comparison of the id names.
+ *
+ * \note All other IDs beside given one are assumed already properly sorted in the list.
+ *
+ * \param id_sorting_hint: Ignored if NULL. Otherwise, used to check if we can insert \a id
+ * immediately before or after that pointer. It must always be into given \a lb list.
+ */
void id_sort_by_name(struct ListBase *lb, struct ID *id, struct ID *id_sorting_hint);
+/**
+ * Expand ID usages of given id as 'extern' (and no more indirect) linked data.
+ * Used by ID copy/make_local functions.
+ */
void BKE_lib_id_expand_local(struct Main *bmain, struct ID *id, const int flags);
+/**
+ * Ensures given ID has a unique name in given listbase.
+ *
+ * Only for local IDs (linked ones already have a unique ID in their library).
+ *
+ * \param do_linked_data: if true, also ensure a unique name in case the given \a id is linked
+ * (otherwise, just ensure that it is properly sorted).
+ *
+ * \return true if a new name had to be created.
+ */
bool BKE_id_new_name_validate(struct ListBase *lb,
struct ID *id,
const char *name,
const bool do_linked_data) ATTR_NONNULL(1, 2);
+/**
+ * Pull an ID out of a library (make it local). Only call this for IDs that
+ * don't have other library users.
+ *
+ * \param flags: Same set of `LIB_ID_MAKELOCAL_` flags as passed to #BKE_lib_id_make_local.
+ */
void BKE_lib_id_clear_library_data(struct Main *bmain, struct ID *id, const int flags);
-/* Affect whole Main database. */
+/**
+ * Clear or set given tags for all ids of given type in `bmain` (runtime tags).
+ *
+ * \note Affect whole Main database.
+ */
void BKE_main_id_tag_idcode(struct Main *mainvar,
const short type,
const int tag,
const bool value);
+/**
+ * Clear or set given tags for all ids in listbase (runtime tags).
+ */
void BKE_main_id_tag_listbase(struct ListBase *lb, const int tag, const bool value);
+/**
+ * Clear or set given tags for all ids in bmain (runtime tags).
+ */
void BKE_main_id_tag_all(struct Main *mainvar, const int tag, const bool value);
+/**
+ * Clear or set given flags for all ids in listbase (persistent flags).
+ */
void BKE_main_id_flag_listbase(struct ListBase *lb, const int flag, const bool value);
+/**
+ * Clear or set given flags for all ids in bmain (persistent flags).
+ */
void BKE_main_id_flag_all(struct Main *bmain, const int flag, const bool value);
+/**
+ * Next to indirect usage in `readfile.c/writefile.c` also in `editobject.c`, `scene.c`.
+ */
void BKE_main_id_newptr_and_tag_clear(struct Main *bmain);
void BKE_main_id_refcount_recompute(struct Main *bmain, const bool do_linked_only);
void BKE_main_lib_objects_recalc_all(struct Main *bmain);
-/* Only for repairing files via versioning, avoid for general use. */
+/**
+ * Only for repairing files via versioning, avoid for general use.
+ */
void BKE_main_id_repair_duplicate_names_listbase(struct ListBase *lb);
#define MAX_ID_FULL_NAME (64 + 64 + 3 + 1) /* 64 is MAX_ID_NAME - 2 */
#define MAX_ID_FULL_NAME_UI (MAX_ID_FULL_NAME + 3) /* Adds 'keycode' two letters at beginning. */
+/**
+ * Generate full name of the data-block (without ID code, but with library if any).
+ *
+ * \note Result is unique to a given ID type in a given Main database.
+ *
+ * \param name: An allocated string of minimal length #MAX_ID_FULL_NAME,
+ * will be filled with generated string.
+ * \param separator_char: Character to use for separating name and library name.
+ * Can be 0 to use default (' ').
+ */
void BKE_id_full_name_get(char name[MAX_ID_FULL_NAME], const struct ID *id, char separator_char);
+/**
+ * Generate full name of the data-block (without ID code, but with library if any),
+ * with a 2 to 3 character prefix prepended indicating whether it comes from a library,
+ * is overriding, has a fake or no user, etc.
+ *
+ * \note Result is unique to a given ID type in a given Main database.
+ *
+ * \param name: An allocated string of minimal length #MAX_ID_FULL_NAME_UI,
+ * will be filled with generated string.
+ * \param separator_char: Character to use for separating name and library name.
+ * Can be 0 to use default (' ').
+ * \param r_prefix_len: The length of the prefix added.
+ */
void BKE_id_full_name_ui_prefix_get(char name[MAX_ID_FULL_NAME_UI],
const struct ID *id,
const bool add_lib_hint,
char separator_char,
int *r_prefix_len);
+/**
+ * Generate a concatenation of ID name (including two-chars type code) and its lib name, if any.
+ *
+ * \return A unique allocated string key for any ID in the whole Main database.
+ */
char *BKE_id_to_unique_string_key(const struct ID *id);
+/**
+ * Make linked data-blocks local.
+ *
+ * \param bmain: Almost certainly global main.
+ * \param lib: If not NULL, only make local data-blocks from this library.
+ * \param untagged_only: If true, only make local data-blocks not tagged with
+ * #LIB_TAG_PRE_EXISTING.
+ * \param set_fake: If true, set fake user on all localized data-blocks
+ * (except group and objects ones).
+ */
void BKE_library_make_local(struct Main *bmain,
const struct Library *lib,
struct GHash *old_to_new_ids,
@@ -331,11 +597,22 @@ void BKE_library_make_local(struct Main *bmain,
void BKE_id_tag_set_atomic(struct ID *id, int tag);
void BKE_id_tag_clear_atomic(struct ID *id, int tag);
+/**
+ * Check that given ID pointer actually is in G_MAIN.
+ * Main intended use is for debug asserts in places we cannot easily get rid of #G_Main.
+ */
bool BKE_id_is_in_global_main(struct ID *id);
bool BKE_id_can_be_asset(const struct ID *id);
+/**
+ * Returns ordered list of data-blocks for display in the UI.
+ * Result is list of #LinkData of IDs that must be freed.
+ */
void BKE_id_ordered_list(struct ListBase *ordered_lb, const struct ListBase *lb);
+/**
+ * Reorder ID in the list, before or after the "relative" ID.
+ */
void BKE_id_reorder(const struct ListBase *lb, struct ID *id, struct ID *relative, bool after);
void BKE_id_blend_write(struct BlendWriter *writer, struct ID *id);
@@ -343,6 +620,12 @@ void BKE_id_blend_write(struct BlendWriter *writer, struct ID *id);
#define IS_TAGGED(_id) ((_id) && (((ID *)_id)->tag & LIB_TAG_DOIT))
/* lib_id_eval.c */
+
+/**
+ * Copy relatives parameters, from `id` to `id_cow`.
+ * Use handle the #ID_RECALC_PARAMETERS tag.
+ * \note Keep in sync with #ID_TYPE_SUPPORTS_PARAMS_WITHOUT_COW.
+ */
void BKE_id_eval_properties_copy(struct ID *id_cow, struct ID *id);
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_lib_override.h b/source/blender/blenkernel/BKE_lib_override.h
index b94a1b33606..1c30db7a714 100644
--- a/source/blender/blenkernel/BKE_lib_override.h
+++ b/source/blender/blenkernel/BKE_lib_override.h
@@ -57,35 +57,117 @@ struct ReportList;
struct Scene;
struct ViewLayer;
+/**
+ * Initialize empty overriding of \a reference_id by \a local_id.
+ */
struct IDOverrideLibrary *BKE_lib_override_library_init(struct ID *local_id,
struct ID *reference_id);
+/**
+ * Shallow or deep copy of a whole override from \a src_id to \a dst_id.
+ */
void BKE_lib_override_library_copy(struct ID *dst_id,
const struct ID *src_id,
const bool do_full_copy);
+/**
+ * Clear any overriding data from given \a override.
+ */
void BKE_lib_override_library_clear(struct IDOverrideLibrary *override, const bool do_id_user);
+/**
+ * Free given \a override.
+ */
void BKE_lib_override_library_free(struct IDOverrideLibrary **override, const bool do_id_user);
+/**
+ * Check if given ID has some override rules that actually indicate the user edited it.
+ */
bool BKE_lib_override_library_is_user_edited(struct ID *id);
+/**
+ * Create an overridden local copy of linked reference.
+ */
struct ID *BKE_lib_override_library_create_from_id(struct Main *bmain,
struct ID *reference_id,
const bool do_tagged_remap);
+/**
+ * Create overridden local copies of all tagged data-blocks in given Main.
+ *
+ * \note Set `id->newid` of overridden libs with newly created overrides,
+ * caller is responsible to clean those pointers before/after usage as needed.
+ *
+ * \note By default, it will only remap newly created local overriding data-blocks between
+ * themselves, to avoid 'enforcing' those overrides into all other usages of the linked data in
+ * main. You can add more local IDs to be remapped to use new overriding ones by setting their
+ * LIB_TAG_DOIT tag.
+ *
+ * \param reference_library: the library from which the linked data being overridden come from
+ * (i.e. the library of the linked reference ID).
+ *
+ * \param do_no_main: Create the new override data outside of Main database.
+ * Used for resyncing of linked overrides.
+ *
+ * \return \a true on success, \a false otherwise.
+ */
bool BKE_lib_override_library_create_from_tag(struct Main *bmain,
const struct Library *reference_library,
const bool do_no_main);
+/**
+ * Advanced 'smart' function to create fully functional overrides.
+ *
+ * \note Currently it only does special things if given \a id_root is an object or collection, more
+ * specific behaviors may be added in the future for other ID types.
+ *
+ * \note It will override all IDs tagged with \a LIB_TAG_DOIT, and it does not clear that tag at
+ * its beginning, so caller code can add extra data-blocks to be overridden as well.
+ *
+ * \param view_layer: the active view layer to search instantiated collections in, can be NULL (in
+ * which case \a scene's master collection children hierarchy is used instead).
+ * \param id_root: The root ID to create an override from.
+ * \param id_reference: Some reference ID used to do some post-processing after overrides have been
+ * created, may be NULL. Typically, the Empty object instantiating the linked collection we
+ * override, currently.
+ * \param r_id_root_override: if not NULL, the override generated for the given \a id_root.
+ * \return true if override was successfully created.
+ */
bool BKE_lib_override_library_create(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,
struct ID *id_root,
struct ID *id_reference,
struct ID **r_id_root_override);
+/**
+ * Create a library override template.
+ */
bool BKE_lib_override_library_template_create(struct ID *id);
+/**
+ * Convert a given proxy object into a library override.
+ *
+ * \note This is a thin wrapper around \a BKE_lib_override_library_create, only extra work is to
+ * actually convert the proxy itself into an override first.
+ *
+ * \param view_layer: the active view layer to search instantiated collections in, can be NULL (in
+ * which case \a scene's master collection children hierarchy is used instead).
+ * \return true if override was successfully created.
+ */
bool BKE_lib_override_library_proxy_convert(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,
struct Object *ob_proxy);
+/**
+ * Convert all proxy objects into library overrides.
+ *
+ * \note Only affects local proxies, linked ones are not affected.
+ */
void BKE_lib_override_library_main_proxy_convert(struct Main *bmain,
struct BlendFileReadReport *reports);
+/**
+ * Advanced 'smart' function to resync, re-create fully functional overrides up-to-date with linked
+ * data, from an existing override hierarchy.
+ *
+ * \param id_root: The root liboverride ID to resync from.
+ * \param view_layer: the active view layer to search instantiated collections in, can be NULL (in
+ * which case \a scene's master collection children hierarchy is used instead).
+ * \return true if override was successfully resynced.
+ */
bool BKE_lib_override_library_resync(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,
@@ -94,26 +176,76 @@ bool BKE_lib_override_library_resync(struct Main *bmain,
const bool do_hierarchy_enforce,
const bool do_post_process,
struct BlendFileReadReport *reports);
+/**
+ * Detect and handle required resync of overrides data, when relations between reference linked IDs
+ * have changed.
+ *
+ * This is a fairly complex and costly operation, typically it should be called after
+ * #BKE_lib_override_library_main_update, which would already detect and tag a lot of cases.
+ *
+ * This function will first detect the remaining cases requiring a resync (namely, either when an
+ * existing linked ID that did not require to be overridden before now would be, or when new IDs
+ * are added to the hierarchy).
+ *
+ * Then it will handle the resync of necessary IDs (through calls to
+ * #BKE_lib_override_library_resync).
+ *
+ * \param view_layer: the active view layer to search instantiated collections in, can be NULL (in
+ * which case \a scene's master collection children hierarchy is used instead).
+ */
void BKE_lib_override_library_main_resync(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,
struct BlendFileReadReport *reports);
+/**
+ * Advanced 'smart' function to delete library overrides (including their existing override
+ * hierarchy) and remap their usages to their linked reference IDs.
+ *
+ * \note All IDs tagged with #LIB_TAG_DOIT will be deleted.
+ *
+ * \param id_root: The root liboverride ID to delete.
+ */
void BKE_lib_override_library_delete(struct Main *bmain, struct ID *id_root);
+/**
+ * Make given ID fully local.
+ *
+ * \note Only differs from lower-level #BKE_lib_override_library_free in infamous embedded ID
+ * cases.
+ */
void BKE_lib_override_library_make_local(struct ID *id);
+/**
+ * Find override property from given RNA path, if it exists.
+ */
struct IDOverrideLibraryProperty *BKE_lib_override_library_property_find(
struct IDOverrideLibrary *override, const char *rna_path);
+/**
+ * Find override property from given RNA path, or create it if it does not exist.
+ */
struct IDOverrideLibraryProperty *BKE_lib_override_library_property_get(
struct IDOverrideLibrary *override, const char *rna_path, bool *r_created);
+/**
+ * Remove and free given \a override_property from given ID \a override.
+ */
void BKE_lib_override_library_property_delete(struct IDOverrideLibrary *override,
struct IDOverrideLibraryProperty *override_property);
+/**
+ * Get the RNA-property matching the \a library_prop override property. Used for UI to query
+ * additional data about the overridden property (e.g. UI name).
+ *
+ * \param idpoin: Pointer to the override ID.
+ * \param library_prop: The library override property to find the matching RNA property for.
+ */
bool BKE_lib_override_rna_property_find(struct PointerRNA *idpoin,
const struct IDOverrideLibraryProperty *library_prop,
struct PointerRNA *r_override_poin,
struct PropertyRNA **r_override_prop);
+/**
+ * Find override property operation from given sub-item(s), if it exists.
+ */
struct IDOverrideLibraryPropertyOperation *BKE_lib_override_library_property_operation_find(
struct IDOverrideLibraryProperty *override_property,
const char *subitem_refname,
@@ -122,6 +254,9 @@ struct IDOverrideLibraryPropertyOperation *BKE_lib_override_library_property_ope
const int subitem_locindex,
const bool strict,
bool *r_strict);
+/**
+ * Find override property operation from given sub-item(s), or create it if it does not exist.
+ */
struct IDOverrideLibraryPropertyOperation *BKE_lib_override_library_property_operation_get(
struct IDOverrideLibraryProperty *override_property,
const short operation,
@@ -132,10 +267,16 @@ struct IDOverrideLibraryPropertyOperation *BKE_lib_override_library_property_ope
const bool strict,
bool *r_strict,
bool *r_created);
+/**
+ * Remove and free given \a override_property_operation from given ID \a override_property.
+ */
void BKE_lib_override_library_property_operation_delete(
struct IDOverrideLibraryProperty *override_property,
struct IDOverrideLibraryPropertyOperation *override_property_operation);
+/**
+ * Validate that required data for a given operation are available.
+ */
bool BKE_lib_override_library_property_operation_operands_validate(
struct IDOverrideLibraryPropertyOperation *override_property_operation,
struct PointerRNA *ptr_dst,
@@ -145,34 +286,107 @@ bool BKE_lib_override_library_property_operation_operands_validate(
struct PropertyRNA *prop_src,
struct PropertyRNA *prop_storage);
+/**
+ * Check against potential \a bmain.
+ */
void BKE_lib_override_library_validate(struct Main *bmain,
struct ID *id,
struct ReportList *reports);
+/**
+ * Check against potential \a bmain.
+ */
void BKE_lib_override_library_main_validate(struct Main *bmain, struct ReportList *reports);
+/**
+ * Check that status of local data-block is still valid against current reference one.
+ *
+ * It means that all overridable, but not overridden, properties' local values must be equal to
+ * reference ones. Clears #LIB_TAG_OVERRIDE_OK if they do not.
+ *
+ * This is typically used to detect whether some property has been changed in local and a new
+ * #IDOverrideProperty (of #IDOverridePropertyOperation) has to be added.
+ *
+ * \return true if status is OK, false otherwise. */
bool BKE_lib_override_library_status_check_local(struct Main *bmain, struct ID *local);
+/**
+ * Check that status of reference data-block is still valid against current local one.
+ *
+ * It means that all non-overridden properties' local values must be equal to reference ones.
+ * Clears LIB_TAG_OVERRIDE_OK if they do not.
+ *
+ * This is typically used to detect whether some reference has changed and local
+ * needs to be updated against it.
+ *
+ * \return true if status is OK, false otherwise. */
bool BKE_lib_override_library_status_check_reference(struct Main *bmain, struct ID *local);
+/**
+ * Compare local and reference data-blocks and create new override operations as needed,
+ * or reset to reference values if overriding is not allowed.
+ *
+ * \note Defining override operations is only mandatory before saving a `.blend` file on disk
+ * (not for undo!).
+ * Knowing that info at runtime is only useful for UI/UX feedback.
+ *
+ * \note This is by far the biggest operation (the more time-consuming) of the three so far,
+ * since it has to go over all properties in depth (all overridable ones at least).
+ * Generating differential values and applying overrides are much cheaper.
+ *
+ * \return true if any library operation was created.
+ */
bool BKE_lib_override_library_operations_create(struct Main *bmain, struct ID *local);
+/**
+ * Check all overrides from given \a bmain and create/update overriding operations as needed.
+ */
bool BKE_lib_override_library_main_operations_create(struct Main *bmain, const bool force_auto);
+/**
+ * Reset all overrides in given \a id_root, while preserving ID relations.
+ */
void BKE_lib_override_library_id_reset(struct Main *bmain, struct ID *id_root);
+/**
+ * Reset all overrides in given \a id_root and its dependencies, while preserving ID relations.
+ */
void BKE_lib_override_library_id_hierarchy_reset(struct Main *bmain, struct ID *id_root);
+/**
+ * Set or clear given tag in all operations in that override property data.
+ */
void BKE_lib_override_library_operations_tag(struct IDOverrideLibraryProperty *override_property,
const short tag,
const bool do_set);
+/**
+ * Set or clear given tag in all properties and operations in that override data.
+ */
void BKE_lib_override_library_properties_tag(struct IDOverrideLibrary *override,
const short tag,
const bool do_set);
+/**
+ * Set or clear given tag in all properties and operations in that Main's ID override data.
+ */
void BKE_lib_override_library_main_tag(struct Main *bmain, const short tag, const bool do_set);
+/**
+ * Remove all tagged-as-unused properties and operations from that ID override data.
+ */
void BKE_lib_override_library_id_unused_cleanup(struct ID *local);
+/**
+ * Remove all tagged-as-unused properties and operations from that Main's ID override data.
+ */
void BKE_lib_override_library_main_unused_cleanup(struct Main *bmain);
+/**
+ * Update given override from its reference (re-applying overridden properties).
+ */
void BKE_lib_override_library_update(struct Main *bmain, struct ID *local);
+/**
+ * Update all overrides from given \a bmain.
+ */
void BKE_lib_override_library_main_update(struct Main *bmain);
+/**
+ * In case an ID is used by another liboverride ID, user may not be allowed to delete it.
+ */
bool BKE_lib_override_library_id_is_user_deletable(struct Main *bmain, struct ID *id);
/* Storage (.blend file writing) part. */
@@ -180,9 +394,22 @@ bool BKE_lib_override_library_id_is_user_deletable(struct Main *bmain, struct ID
/* For now, we just use a temp main list. */
typedef struct Main OverrideLibraryStorage;
+/**
+ * Initialize an override storage.
+ */
OverrideLibraryStorage *BKE_lib_override_library_operations_store_init(void);
+/**
+ * Generate suitable 'write' data (this only affects differential override operations).
+ *
+ * Note that \a local ID is no more modified by this call,
+ * all extra data are stored in its temp \a storage_id copy.
+ */
struct ID *BKE_lib_override_library_operations_store_start(
struct Main *bmain, OverrideLibraryStorage *override_storage, struct ID *local);
+/**
+ * Restore given ID modified by #BKE_lib_override_library_operations_store_start, to its
+ * original state.
+ */
void BKE_lib_override_library_operations_store_end(OverrideLibraryStorage *override_storage,
struct ID *local);
void BKE_lib_override_library_operations_store_finalize(OverrideLibraryStorage *override_storage);
diff --git a/source/blender/blenkernel/BKE_lib_query.h b/source/blender/blenkernel/BKE_lib_query.h
index 30c742e3af6..91f72cc0762 100644
--- a/source/blender/blenkernel/BKE_lib_query.h
+++ b/source/blender/blenkernel/BKE_lib_query.h
@@ -143,6 +143,10 @@ enum {
typedef struct LibraryForeachIDData LibraryForeachIDData;
+/**
+ * Check whether current iteration over ID usages should be stopped or not.
+ * \return true if the iteration should be stopped, false otherwise.
+ */
bool BKE_lib_query_foreachid_iter_stop(struct LibraryForeachIDData *data);
void BKE_lib_query_foreachid_process(struct LibraryForeachIDData *data,
struct ID **id_pp,
@@ -181,25 +185,77 @@ int BKE_lib_query_foreachid_process_callback_flag_override(struct LibraryForeach
} \
((void)0)
+/**
+ * Process embedded ID pointers (root node-trees, master collections, ...).
+ *
+ * Those require specific care, since they are technically sub-data of their owner, yet in some
+ * cases they still behave as regular IDs.
+ */
void BKE_library_foreach_ID_embedded(struct LibraryForeachIDData *data, struct ID **id_pp);
void BKE_lib_query_idpropertiesForeachIDLink_callback(struct IDProperty *id_prop, void *user_data);
-/* Loop over all of the ID's this datablock links to. */
+/**
+ * Loop over all of the ID's this data-block links to.
+ */
void BKE_library_foreach_ID_link(
struct Main *bmain, struct ID *id, LibraryIDLinkCallback callback, void *user_data, int flag);
+/**
+ * Re-usable function, use when replacing ID's.
+ */
void BKE_library_update_ID_link_user(struct ID *id_dst, struct ID *id_src, const int cb_flag);
+/**
+ * Return the number of times given \a id_user uses/references \a id_used.
+ *
+ * \note This only checks for pointer references of an ID, shallow usages
+ * (like e.g. by RNA paths, as done for FCurves) are not detected at all.
+ *
+ * \param id_user: the ID which is supposed to use (reference) \a id_used.
+ * \param id_used: the ID which is supposed to be used (referenced) by \a id_user.
+ * \return the number of direct usages/references of \a id_used by \a id_user.
+ */
int BKE_library_ID_use_ID(struct ID *id_user, struct ID *id_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.
+ */
bool BKE_library_id_can_use_idtype(struct ID *id_owner, const short id_type_used);
+/**
+ * Check whether given ID is used locally (i.e. by another non-linked ID).
+ */
bool BKE_library_ID_is_locally_used(struct Main *bmain, void *idv);
+/**
+ * Check whether given ID is used indirectly (i.e. by another linked ID).
+ */
bool BKE_library_ID_is_indirectly_used(struct Main *bmain, void *idv);
+/**
+ * Combine #BKE_library_ID_is_locally_used() and #BKE_library_ID_is_indirectly_used()
+ * in a single call.
+ */
void BKE_library_ID_test_usages(struct Main *bmain,
void *idv,
bool *is_used_local,
bool *is_used_linked);
+/**
+ * Tag all unused IDs (a.k.a 'orphaned').
+ *
+ * By default only tag IDs with `0` user count.
+ * If `do_tag_recursive` is set, it will check dependencies to detect all IDs that are not actually
+ * used in current file, including 'archipelagos` (i.e. set of IDs referencing each other in
+ * loops, but without any 'external' valid usages.
+ *
+ * Valid usages here are defined as ref-counting usages, which are not towards embedded or
+ * loop-back data.
+ *
+ * \param r_num_tagged: If non-NULL, must be a zero-initialized array of #INDEX_ID_MAX integers.
+ * Number of tagged-as-unused IDs is then set for each type, and as total in
+ * #INDEX_ID_NULL item.
+ */
void BKE_lib_query_unused_ids_tag(struct Main *bmain,
const int tag,
const bool do_local_ids,
@@ -207,7 +263,24 @@ void BKE_lib_query_unused_ids_tag(struct Main *bmain,
const bool do_tag_recursive,
int *r_num_tagged);
+/**
+ * Detect orphaned linked data blocks (i.e. linked data not used (directly or indirectly)
+ * in any way by any local data), including complex cases like 'linked archipelagoes', i.e.
+ * linked data-blocks that use each other in loops,
+ * which prevents their deletion by 'basic' usage checks.
+ *
+ * \param do_init_tag: if \a true, all linked data are checked, if \a false,
+ * only linked data-blocks already tagged with #LIB_TAG_DOIT are checked.
+ */
void BKE_library_unused_linked_data_set_tag(struct Main *bmain, const bool do_init_tag);
+/**
+ * Untag linked data blocks used by other untagged linked data-blocks.
+ * Used to detect data-blocks that we can forcefully make local
+ * (instead of copying them to later get rid of original):
+ * All data-blocks we want to make local are tagged by caller,
+ * after this function has ran caller knows data-blocks still tagged can directly be made local,
+ * since they are only used by other data-blocks that will also be made fully local.
+ */
void BKE_library_indirectly_used_data_tag_clear(struct Main *bmain);
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_lib_remap.h b/source/blender/blenkernel/BKE_lib_remap.h
index 5e154459a6c..9c8caa0266b 100644
--- a/source/blender/blenkernel/BKE_lib_remap.h
+++ b/source/blender/blenkernel/BKE_lib_remap.h
@@ -97,8 +97,13 @@ enum {
ID_REMAP_FORCE_OBDATA_IN_EDITMODE = 1 << 9,
};
-/* NOTE: Requiring new_id to be non-null, this *may* not be the case ultimately,
- * but makes things simpler for now. */
+/**
+ * Replace all references in given Main to \a old_id by \a new_id
+ * (if \a new_id is NULL, it unlinks \a old_id).
+ *
+ * \note Requiring new_id to be non-null, this *may* not be the case ultimately,
+ * but makes things simpler for now.
+ */
void BKE_libblock_remap_locked(struct Main *bmain,
void *old_idv,
void *new_idv,
@@ -106,17 +111,39 @@ void BKE_libblock_remap_locked(struct Main *bmain,
void BKE_libblock_remap(struct Main *bmain, void *old_idv, void *new_idv, const short remap_flags)
ATTR_NONNULL(1, 2);
+/**
+ * Unlink given \a id from given \a bmain
+ * (does not touch to indirect, i.e. library, usages of the ID).
+ *
+ * \param do_flag_never_null: If true, all IDs using \a idv in a 'non-NULL' way are flagged by
+ * #LIB_TAG_DOIT flag (quite obviously, 'non-NULL' usages can never be unlinked by this function).
+ */
void BKE_libblock_unlink(struct Main *bmain,
void *idv,
const bool do_flag_never_null,
const bool do_skip_indirect) ATTR_NONNULL();
+/**
+ * Similar to libblock_remap, but only affects IDs used by given \a idv ID.
+ *
+ * \param old_idv: Unlike BKE_libblock_remap, can be NULL,
+ * in which case all ID usages by given \a idv will be cleared.
+ */
void BKE_libblock_relink_ex(struct Main *bmain,
void *idv,
void *old_idv,
void *new_idv,
const short remap_flags) ATTR_NONNULL(1, 2);
+/**
+ * Remaps ID usages of given ID to their `id->newid` pointer if not None, and proceeds recursively
+ * in the dependency tree of IDs for all data-blocks tagged with `LIB_TAG_NEW`.
+ *
+ * \note `LIB_TAG_NEW` is cleared.
+ *
+ * Very specific usage, not sure we'll keep it on the long run,
+ * currently only used in Object/Collection duplication code.
+ */
void BKE_libblock_relink_to_newid(struct Main *bmain, struct ID *id, const int remap_flag)
ATTR_NONNULL();
diff --git a/source/blender/blenkernel/BKE_linestyle.h b/source/blender/blenkernel/BKE_linestyle.h
index 1236a96c8d9..eb17ff78688 100644
--- a/source/blender/blenkernel/BKE_linestyle.h
+++ b/source/blender/blenkernel/BKE_linestyle.h
@@ -80,6 +80,10 @@ int BKE_linestyle_thickness_modifier_remove(FreestyleLineStyle *linestyle,
int BKE_linestyle_geometry_modifier_remove(FreestyleLineStyle *linestyle,
LineStyleModifier *modifier);
+/**
+ * Reinsert \a modifier in modifier list with an offset of \a direction.
+ * \return if position of \a modifier has changed.
+ */
bool BKE_linestyle_color_modifier_move(FreestyleLineStyle *linestyle,
LineStyleModifier *modifier,
int direction);
diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h
index 9ded97e0003..41ef5e3f5ba 100644
--- a/source/blender/blenkernel/BKE_main.h
+++ b/source/blender/blenkernel/BKE_main.h
@@ -116,12 +116,14 @@ enum {
typedef struct Main {
struct Main *next, *prev;
- char name[1024]; /* 1024 = FILE_MAX */
+ /** The file-path of this blend file, an empty string indicates an unsaved file. */
+ char filepath[1024]; /* 1024 = FILE_MAX */
short versionfile, subversionfile; /* see BLENDER_FILE_VERSION, BLENDER_FILE_SUBVERSION */
short minversionfile, minsubversionfile;
uint64_t build_commit_timestamp; /* commit's timestamp from buildinfo */
char build_hash[16]; /* hash from buildinfo */
- char recovered; /* indicate the main->name (file) is the recovered one */
+ /** Indicate the #Main.filepath (file) is the recovered one. */
+ char recovered;
/** All current ID's exist in the last memfile undo step. */
char is_memfile_undo_written;
/**
@@ -201,40 +203,99 @@ typedef struct Main {
struct Main *BKE_main_new(void);
void BKE_main_free(struct Main *mainvar);
+/**
+ * Check whether given `bmain` is empty or contains some IDs.
+ */
bool BKE_main_is_empty(struct Main *bmain);
void BKE_main_lock(struct Main *bmain);
void BKE_main_unlock(struct Main *bmain);
+/** Generate the mappings between used IDs and their users, and vice-versa. */
void BKE_main_relations_create(struct Main *bmain, const short flag);
void BKE_main_relations_free(struct Main *bmain);
+/** Set or clear given `tag` in all relation entries of given `bmain`. */
void BKE_main_relations_tag_set(struct Main *bmain,
const eMainIDRelationsEntryTags tag,
const bool value);
+/**
+ * Create a #GSet storing all IDs present in given \a bmain, by their pointers.
+ *
+ * \param gset: If not NULL, given GSet will be extended with IDs from given \a bmain,
+ * instead of creating a new one.
+ */
struct GSet *BKE_main_gset_create(struct Main *bmain, struct GSet *gset);
-/*
- * Temporary runtime API to allow re-using local (already appended) IDs instead of appending a new
- * copy again.
- */
+/* Temporary runtime API to allow re-using local (already appended)
+ * IDs instead of appending a new copy again. */
+/**
+ * Generate a mapping between 'library path' of an ID
+ * (as a pair (relative blend file path, id name)), and a current local ID, if any.
+ *
+ * This uses the information stored in `ID.library_weak_reference`.
+ */
struct GHash *BKE_main_library_weak_reference_create(struct Main *bmain) ATTR_NONNULL();
+/**
+ * Destroy the data generated by #BKE_main_library_weak_reference_create.
+ */
void BKE_main_library_weak_reference_destroy(struct GHash *library_weak_reference_mapping)
ATTR_NONNULL();
+/**
+ * Search for a local ID matching the given linked ID reference.
+ *
+ * \param library_weak_reference_mapping: the mapping data generated by
+ * #BKE_main_library_weak_reference_create.
+ * \param library_filepath: the path of a blend file library (relative to current working one).
+ * \param library_id_name: the full ID name, including the leading two chars encoding the ID
+ * type.
+ */
struct ID *BKE_main_library_weak_reference_search_item(
struct GHash *library_weak_reference_mapping,
const char *library_filepath,
const char *library_id_name) ATTR_NONNULL();
+/**
+ * Add the given ID weak library reference to given local ID and the runtime mapping.
+ *
+ * \param library_weak_reference_mapping: the mapping data generated by
+ * #BKE_main_library_weak_reference_create.
+ * \param library_filepath: the path of a blend file library (relative to current working one).
+ * \param library_id_name: the full ID name, including the leading two chars encoding the ID type.
+ * \param new_id: New local ID matching given weak reference.
+ */
void BKE_main_library_weak_reference_add_item(struct GHash *library_weak_reference_mapping,
const char *library_filepath,
const char *library_id_name,
struct ID *new_id) ATTR_NONNULL();
+/**
+ * Update the status of the given ID weak library reference in current local IDs and the runtime
+ * mapping.
+ *
+ * This effectively transfers the 'ownership' of the given weak reference from `old_id` to
+ * `new_id`.
+ *
+ * \param library_weak_reference_mapping: the mapping data generated by
+ * #BKE_main_library_weak_reference_create.
+ * \param library_filepath: the path of a blend file library (relative to current working one).
+ * \param library_id_name: the full ID name, including the leading two chars encoding the ID type.
+ * \param old_id: Existing local ID matching given weak reference.
+ * \param new_id: New local ID matching given weak reference.
+ */
void BKE_main_library_weak_reference_update_item(struct GHash *library_weak_reference_mapping,
const char *library_filepath,
const char *library_id_name,
struct ID *old_id,
struct ID *new_id) ATTR_NONNULL();
+/**
+ * Remove the given ID weak library reference from the given local ID and the runtime mapping.
+ *
+ * \param library_weak_reference_mapping: the mapping data generated by
+ * #BKE_main_library_weak_reference_create.
+ * \param library_filepath: the path of a blend file library (relative to current working one).
+ * \param library_id_name: the full ID name, including the leading two chars encoding the ID type.
+ * \param old_id: Existing local ID matching given weak reference.
+ */
void BKE_main_library_weak_reference_remove_item(struct GHash *library_weak_reference_mapping,
const char *library_filepath,
const char *library_id_name,
@@ -286,16 +347,57 @@ void BKE_main_library_weak_reference_remove_item(struct GHash *library_weak_refe
} \
((void)0)
+/**
+ * Generates a raw .blend file thumbnail data from given image.
+ *
+ * \param bmain: If not NULL, also store generated data in this Main.
+ * \param img: ImBuf image to generate thumbnail data from.
+ * \return The generated .blend file raw thumbnail data.
+ */
struct BlendThumbnail *BKE_main_thumbnail_from_imbuf(struct Main *bmain, struct ImBuf *img);
+/**
+ * Generates an image from raw .blend file thumbnail \a data.
+ *
+ * \param bmain: Use this bmain->blen_thumb data if given \a data is NULL.
+ * \param data: Raw .blend file thumbnail data.
+ * \return An ImBuf from given data, or NULL if invalid.
+ */
struct ImBuf *BKE_main_thumbnail_to_imbuf(struct Main *bmain, struct BlendThumbnail *data);
+/**
+ * Generates an empty (black) thumbnail for given Main.
+ */
void BKE_main_thumbnail_create(struct Main *bmain);
+/**
+ * Return file-path of given \a main.
+ */
const char *BKE_main_blendfile_path(const struct Main *bmain) ATTR_NONNULL();
+/**
+ * Return file-path of global main #G_MAIN.
+ *
+ * \warning Usage is not recommended,
+ * you should always try to get a valid Main pointer from context.
+ */
const char *BKE_main_blendfile_path_from_global(void);
+/**
+ * \return A pointer to the \a ListBase of given \a bmain for requested \a type ID type.
+ */
struct ListBase *which_libbase(struct Main *bmain, short type);
//#define INDEX_ID_MAX 41
+/**
+ * Put the pointers to all the #ListBase structs in given `bmain` into the `*lb[INDEX_ID_MAX]`
+ * array, and return the number of those for convenience.
+ *
+ * This is useful for generic traversal of all the blocks in a #Main (by traversing all the lists
+ * in turn), without worrying about block types.
+ *
+ * \param lb: Array of lists #INDEX_ID_MAX in length.
+ *
+ * \note The order of each ID type #ListBase in the array is determined by the `INDEX_ID_<IDTYPE>`
+ * enum definitions in `DNA_ID.h`. See also the #FOREACH_MAIN_ID_BEGIN macro in `BKE_main.h`
+ */
int set_listbasepointers(struct Main *main, struct ListBase *lb[]);
#define MAIN_VERSION_ATLEAST(main, ver, subver) \
diff --git a/source/blender/blenkernel/BKE_main_idmap.h b/source/blender/blenkernel/BKE_main_idmap.h
index ff69883f0fb..13ddcaa93ba 100644
--- a/source/blender/blenkernel/BKE_main_idmap.h
+++ b/source/blender/blenkernel/BKE_main_idmap.h
@@ -44,6 +44,17 @@ enum {
MAIN_IDMAP_TYPE_UUID = 1 << 1,
};
+/**
+ * Generate mapping from ID type/name to ID pointer for given \a bmain.
+ *
+ * \note When used during undo/redo, there is no guaranty that ID pointers from UI area are not
+ * pointing to freed memory (when some IDs have been deleted). To avoid crashes in those cases, one
+ * can provide the 'old' (aka current) Main database as reference. #BKE_main_idmap_lookup_id will
+ * then check that given ID does exist in \a old_bmain before trying to use it.
+ *
+ * \param create_valid_ids_set: If \a true, generate a reference to prevent freed memory accesses.
+ * \param old_bmain: If not NULL, its IDs will be added the valid references set.
+ */
struct IDNameLib_Map *BKE_main_idmap_create(struct Main *bmain,
const bool create_valid_ids_set,
struct Main *old_bmain,
diff --git a/source/blender/blenkernel/BKE_mask.h b/source/blender/blenkernel/BKE_mask.h
index 8e2f6e6f10c..2a2b080217c 100644
--- a/source/blender/blenkernel/BKE_mask.h
+++ b/source/blender/blenkernel/BKE_mask.h
@@ -56,16 +56,20 @@ typedef enum {
MASK_HANDLE_MODE_INDIVIDUAL_HANDLES = 2,
} eMaskhandleMode;
-struct MaskSplinePoint *BKE_mask_spline_point_array(struct MaskSpline *spline);
-struct MaskSplinePoint *BKE_mask_spline_point_array_from_point(
- struct MaskSpline *spline, const struct MaskSplinePoint *point_ref);
+/* -------------------------------------------------------------------- */
+/** \name Mask Layers
+ * \{ */
-/* mask layers */
struct MaskLayer *BKE_mask_layer_new(struct Mask *mask, const char *name);
+/**
+ * \note The returned mask-layer may be hidden, caller needs to check.
+ */
struct MaskLayer *BKE_mask_layer_active(struct Mask *mask);
void BKE_mask_layer_active_set(struct Mask *mask, struct MaskLayer *masklay);
void BKE_mask_layer_remove(struct Mask *mask, struct MaskLayer *masklay);
+/** \brief Free all animation keys for a mask layer.
+ */
void BKE_mask_layer_free_shapes(struct MaskLayer *masklay);
void BKE_mask_layer_free(struct MaskLayer *masklay);
void BKE_mask_layer_free_list(struct ListBase *masklayers);
@@ -83,7 +87,16 @@ void BKE_mask_layer_rename(struct Mask *mask,
struct MaskLayer *BKE_mask_layer_copy(const struct MaskLayer *masklay);
void BKE_mask_layer_copy_list(struct ListBase *masklayers_new, const struct ListBase *masklayers);
-/* splines */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Splines
+ * \{ */
+
+struct MaskSplinePoint *BKE_mask_spline_point_array(struct MaskSpline *spline);
+struct MaskSplinePoint *BKE_mask_spline_point_array_from_point(
+ struct MaskSpline *spline, const struct MaskSplinePoint *point_ref);
+
struct MaskSpline *BKE_mask_spline_add(struct MaskLayer *masklay);
bool BKE_mask_spline_remove(struct MaskLayer *mask_layer, struct MaskSpline *spline);
void BKE_mask_point_direction_switch(struct MaskSplinePoint *point);
@@ -104,7 +117,12 @@ float BKE_mask_spline_project_co(struct MaskSpline *spline,
const float co[2],
const eMaskSign sign);
-/* point */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Point
+ * \{ */
+
eMaskhandleMode BKE_mask_point_handles_mode_get(const struct MaskSplinePoint *point);
void BKE_mask_point_handle(const struct MaskSplinePoint *point,
eMaskWhichHandle which_handle,
@@ -139,7 +157,12 @@ void BKE_mask_point_select_set_handle(struct MaskSplinePoint *point,
const eMaskWhichHandle which_handle,
const bool do_select);
-/* general */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name General
+ * \{ */
+
struct Mask *BKE_mask_new(struct Main *bmain, const char *name);
void BKE_mask_coord_from_frame(float r_co[2], const float co[2], const float frame_size[2]);
@@ -151,6 +174,9 @@ void BKE_mask_coord_from_image(struct Image *image,
struct ImageUser *iuser,
float r_co[2],
const float co[2]);
+/**
+ * Inverse of #BKE_mask_coord_from_image.
+ */
void BKE_mask_coord_to_frame(float r_co[2], const float co[2], const float frame_size[2]);
void BKE_mask_coord_to_movieclip(struct MovieClip *clip,
struct MovieClipUser *user,
@@ -161,7 +187,11 @@ void BKE_mask_coord_to_image(struct Image *image,
float r_co[2],
const float co[2]);
-/* parenting */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Parenting
+ * \{ */
void BKE_mask_evaluate(struct Mask *mask, const float ctime, const bool do_newframe);
void BKE_mask_layer_evaluate(struct MaskLayer *masklay, const float ctime, const bool do_newframe);
@@ -169,10 +199,19 @@ void BKE_mask_parent_init(struct MaskParent *parent);
void BKE_mask_calc_handle_adjacent_interp(struct MaskSpline *spline,
struct MaskSplinePoint *point,
const float u);
+/**
+ * Calculates the tangent of a point by its previous and next
+ * (ignoring handles - as if its a poly line).
+ */
void BKE_mask_calc_tangent_polyline(struct MaskSpline *spline,
struct MaskSplinePoint *point,
float t[2]);
void BKE_mask_calc_handle_point(struct MaskSpline *spline, struct MaskSplinePoint *point);
+/**
+ * \brief Resets auto handles even for non-auto bezier points
+ *
+ * Useful for giving sane defaults.
+ */
void BKE_mask_calc_handle_point_auto(struct MaskSpline *spline,
struct MaskSplinePoint *point,
const bool do_recalc_length);
@@ -186,20 +225,40 @@ void BKE_mask_point_parent_matrix_get(struct MaskSplinePoint *point,
float ctime,
float parent_matrix[3][3]);
-/* animation */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Animation
+ * \{ */
+
int BKE_mask_layer_shape_totvert(struct MaskLayer *masklay);
+/**
+ * Inverse of #BKE_mask_layer_shape_to_mask
+ */
void BKE_mask_layer_shape_from_mask(struct MaskLayer *masklay,
struct MaskLayerShape *masklay_shape);
+/**
+ * Inverse of #BKE_mask_layer_shape_from_mask
+ */
void BKE_mask_layer_shape_to_mask(struct MaskLayer *masklay, struct MaskLayerShape *masklay_shape);
+/**
+ * \note Linear interpolation only.
+ */
void BKE_mask_layer_shape_to_mask_interp(struct MaskLayer *masklay,
struct MaskLayerShape *masklay_shape_a,
struct MaskLayerShape *masklay_shape_b,
const float fac);
struct MaskLayerShape *BKE_mask_layer_shape_find_frame(struct MaskLayer *masklay, const int frame);
+/**
+ * When returning 2 - the frame isn't found but before/after frames are.
+ */
int BKE_mask_layer_shape_find_frame_range(struct MaskLayer *masklay,
const float frame,
struct MaskLayerShape **r_masklay_shape_a,
struct MaskLayerShape **r_masklay_shape_b);
+/**
+ * \note Does *not* add to the list.
+ */
struct MaskLayerShape *BKE_mask_layer_shape_alloc(struct MaskLayer *masklay, const int frame);
void BKE_mask_layer_shape_free(struct MaskLayerShape *masklay_shape);
struct MaskLayerShape *BKE_mask_layer_shape_verify_frame(struct MaskLayer *masklay,
@@ -214,19 +273,42 @@ bool BKE_mask_layer_shape_spline_from_index(struct MaskLayer *masklay,
int *r_index);
int BKE_mask_layer_shape_spline_to_index(struct MaskLayer *masklay, struct MaskSpline *spline);
+/**
+ * When a new points added, resizing all shape-key arrays.
+ */
void BKE_mask_layer_shape_changed_add(struct MaskLayer *masklay,
int index,
bool do_init,
bool do_init_interpolate);
+/**
+ * Move array elements to account for removed point.
+ */
void BKE_mask_layer_shape_changed_remove(struct MaskLayer *masklay, int index, int count);
int BKE_mask_get_duration(struct Mask *mask);
-/* clipboard */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Clipboard
+ * \{ */
+
+/**
+ * Free the clipboard.
+ */
void BKE_mask_clipboard_free(void);
+/**
+ * Copy selected visible splines from the given layer to clipboard.
+ */
void BKE_mask_clipboard_copy_from_layer(struct MaskLayer *mask_layer);
+/**
+ * Check clipboard is empty.
+ */
bool BKE_mask_clipboard_is_empty(void);
+/**
+ * Paste the contents of clipboard to given mask layer.
+ */
void BKE_mask_clipboard_paste_to_layer(struct Main *bmain, struct MaskLayer *mask_layer);
#define MASKPOINT_ISSEL_ANY(p) ((((p)->bezt.f1 | (p)->bezt.f2 | (p)->bezt.f3) & SELECT) != 0)
@@ -260,9 +342,16 @@ void BKE_mask_clipboard_paste_to_layer(struct Main *bmain, struct MaskLayer *mas
} \
(void)0
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Evaluation
+ * \{ */
+
#define MASK_RESOL_MAX 128
/* mask_evaluate.c */
+
unsigned int BKE_mask_spline_resolution(struct MaskSpline *spline, int width, int height);
unsigned int BKE_mask_spline_feather_resolution(struct MaskSpline *spline, int width, int height);
int BKE_mask_spline_differentiate_calc_total(const struct MaskSpline *spline,
@@ -276,6 +365,10 @@ void BKE_mask_spline_feather_collapse_inner_loops(struct MaskSpline *spline,
const unsigned int tot_feather_point);
float (*BKE_mask_spline_differentiate(
struct MaskSpline *spline, int width, int height, unsigned int *r_tot_diff_point))[2];
+/**
+ * values align with #BKE_mask_spline_differentiate_with_resolution
+ * when \a resol arguments match.
+ */
float (*BKE_mask_spline_feather_differentiated_points_with_resolution(
struct MaskSpline *spline,
const unsigned int resol,
@@ -283,6 +376,7 @@ float (*BKE_mask_spline_feather_differentiated_points_with_resolution(
unsigned int *r_tot_feather_point))[2];
/* *** mask point functions which involve evaluation *** */
+
float (*BKE_mask_spline_feather_points(struct MaskSpline *spline, int *tot_feather_point))[2];
float *BKE_mask_point_segment_diff(struct MaskSpline *spline,
@@ -291,6 +385,8 @@ float *BKE_mask_point_segment_diff(struct MaskSpline *spline,
int height,
unsigned int *r_tot_diff_point);
+/* *** mask point functions which involve evaluation *** */
+
float *BKE_mask_point_segment_feather_diff(struct MaskSpline *spline,
struct MaskSplinePoint *point,
int width,
@@ -303,7 +399,14 @@ void BKE_mask_layer_evaluate_deform(struct MaskLayer *masklay, const float ctime
void BKE_mask_eval_animation(struct Depsgraph *depsgraph, struct Mask *mask);
void BKE_mask_eval_update(struct Depsgraph *depsgraph, struct Mask *mask);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Rasterization
+ * \{ */
+
/* mask_rasterize.c */
+
struct MaskRasterHandle;
typedef struct MaskRasterHandle MaskRasterHandle;
@@ -318,11 +421,16 @@ void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle,
const bool do_feather);
float BKE_maskrasterize_handle_sample(MaskRasterHandle *mr_handle, const float xy[2]);
+/**
+ * \brief Rasterize a buffer from a single mask (threaded execution).
+ */
void BKE_maskrasterize_buffer(MaskRasterHandle *mr_handle,
const unsigned int width,
const unsigned int height,
float *buffer);
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h
index b1eaf7207fa..5f9007c79b0 100644
--- a/source/blender/blenkernel/BKE_material.h
+++ b/source/blender/blenkernel/BKE_material.h
@@ -34,12 +34,18 @@ struct Object;
struct Scene;
struct bNode;
-/* Module */
+/* -------------------------------------------------------------------- */
+/** \name Module
+ * \{ */
void BKE_materials_init(void);
void BKE_materials_exit(void);
-/* Materials */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Materials
+ * \{ */
void BKE_object_materials_test(struct Main *bmain, struct Object *ob, struct ID *id);
void BKE_objects_materials_test_all(struct Main *bmain, struct ID *id);
@@ -48,9 +54,18 @@ void BKE_object_material_resize(struct Main *bmain,
const short totcol,
bool do_id_user);
void BKE_object_material_remap(struct Object *ob, const unsigned int *remap);
+/**
+ * Calculate a material remapping from \a ob_src to \a ob_dst.
+ *
+ * \param remap_src_to_dst: An array the size of `ob_src->totcol`
+ * where index values are filled in which map to \a ob_dst materials.
+ */
void BKE_object_material_remap_calc(struct Object *ob_dst,
struct Object *ob_src,
short *remap_src_to_dst);
+/**
+ * Copy materials from evaluated geometry to the original geometry of an object.
+ */
void BKE_object_material_from_eval_data(struct Main *bmain,
struct Object *ob_orig,
struct ID *data_eval);
@@ -61,10 +76,17 @@ void BKE_gpencil_material_attr_init(struct Material *ma);
/* UNUSED */
// void automatname(struct Material *);
-/* material slots */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Material Slots
+ * \{ */
struct Material ***BKE_object_material_array_p(struct Object *ob);
short *BKE_object_material_len_p(struct Object *ob);
+/**
+ * \note Same as #BKE_object_material_len_p but for ID's.
+ */
struct Material ***BKE_id_material_array_p(struct ID *id); /* same but for ID's */
short *BKE_id_material_len_p(struct ID *id);
@@ -81,6 +103,9 @@ struct Material *BKE_object_material_get(struct Object *ob, short act);
void BKE_id_material_assign(struct Main *bmain, struct ID *id, struct Material *ma, short act);
void BKE_object_material_assign(
struct Main *bmain, struct Object *ob, struct Material *ma, short act, int assign_type);
+/**
+ * \warning this calls many more update calls per object then are needed, could be optimized.
+ */
void BKE_object_material_array_assign(struct Main *bmain,
struct Object *ob,
struct Material ***matar,
@@ -99,7 +124,12 @@ void BKE_texpaint_slot_refresh_cache(struct Scene *scene, struct Material *ma);
void BKE_texpaint_slots_refresh_object(struct Scene *scene, struct Object *ob);
struct bNode *BKE_texpaint_slot_material_find_node(struct Material *ma, short texpaint_slot);
-/* rna api */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name RNA API
+ * \{ */
+
void BKE_id_materials_copy(struct Main *bmain, struct ID *id_src, struct ID *id_dst);
void BKE_id_material_resize(struct Main *bmain, struct ID *id, short totcol, bool do_id_user);
void BKE_id_material_append(struct Main *bmain, struct ID *id, struct Material *ma);
@@ -109,23 +139,57 @@ struct Material *BKE_id_material_pop(struct Main *bmain,
int index);
void BKE_id_material_clear(struct Main *bmain, struct ID *id);
-/* eval api */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Evaluation API
+ * \{ */
+
+/**
+ * On evaluated objects the number of materials on an object and its data might go out of sync.
+ * This is because during evaluation materials can be added/removed on the object data.
+ *
+ * For rendering or exporting we generally use the materials on the object data. However, some
+ * material indices might be overwritten by the object.
+ */
struct Material *BKE_object_material_get_eval(struct Object *ob, short act);
int BKE_object_material_count_eval(struct Object *ob);
void BKE_id_material_eval_assign(struct ID *id, int slot, struct Material *material);
+/**
+ * Add an empty material slot if the id has no material slots. This material slot allows the
+ * material to be overwritten by object-linked materials.
+ */
void BKE_id_material_eval_ensure_default_slot(struct ID *id);
-/* rendering */
+/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Rendering
+ * \{ */
+
+/**
+ * \param r_col: current value.
+ * \param col: new value.
+ * \param fac: Zero for is no change.
+ */
void ramp_blend(int type, float r_col[3], const float fac, const float col[3]);
-/* copy/paste */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Copy/Paste
+ * \{ */
+
void BKE_material_copybuf_clear(void);
void BKE_material_copybuf_free(void);
void BKE_material_copybuf_copy(struct Main *bmain, struct Material *ma);
void BKE_material_copybuf_paste(struct Main *bmain, struct Material *ma);
-/* Default Materials */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Default Materials
+ * \{ */
struct Material *BKE_material_default_empty(void);
struct Material *BKE_material_default_holdout(void);
@@ -135,12 +199,18 @@ struct Material *BKE_material_default_gpencil(void);
void BKE_material_defaults_free_gpu(void);
-/* Dependency graph evaluation. */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Dependency graph evaluation
+ * \{ */
struct Depsgraph;
void BKE_material_eval(struct Depsgraph *depsgraph, struct Material *material);
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_mball.h b/source/blender/blenkernel/BKE_mball.h
index db4dca14535..895fe5a28f9 100644
--- a/source/blender/blenkernel/BKE_mball.h
+++ b/source/blender/blenkernel/BKE_mball.h
@@ -41,13 +41,45 @@ bool BKE_mball_is_any_selected(const struct MetaBall *mb);
bool BKE_mball_is_any_selected_multi(struct Base **bases, int bases_len);
bool BKE_mball_is_any_unselected(const struct MetaBall *mb);
bool BKE_mball_is_basis_for(struct Object *ob1, struct Object *ob2);
+/**
+ * Test, if \a ob is a basis meta-ball.
+ *
+ * It test last character of Object ID name.
+ * If last character is digit it return 0, else it return 1.
+ */
bool BKE_mball_is_basis(struct Object *ob);
+/**
+ * This function finds the basis meta-ball.
+ *
+ * Basis meta-ball doesn't include any number at the end of
+ * its name. All meta-balls with same base of name can be
+ * blended. meta-balls with different basic name can't be blended.
+ *
+ * \warning #BKE_mball_is_basis() can fail on returned object, see function docs for details.
+ */
struct Object *BKE_mball_basis_find(struct Scene *scene, struct Object *ob);
+/**
+ * Compute bounding box of all meta-elements / meta-ball.
+ *
+ * Bounding box is computed from polygonized surface. \a ob is
+ * basic meta-balls (with name `Meta` for example). All other meta-ball objects
+ * (with names `Meta.001`, `Meta.002`, etc) are included in this bounding-box.
+ */
void BKE_mball_texspace_calc(struct Object *ob);
+/**
+ * Return or compute bounding-box for given meta-ball object.
+ */
struct BoundBox *BKE_mball_boundbox_get(struct Object *ob);
float *BKE_mball_make_orco(struct Object *ob, struct ListBase *dispbase);
+/**
+ * Copy some properties from object to other meta-ball object with same base name.
+ *
+ * When some properties (wire-size, threshold, update flags) of meta-ball are changed, then this
+ * properties are copied to all meta-balls in same "group" (meta-balls with same base name:
+ * `MBall`, `MBall.001`, `MBall.002`, etc). The most important is to copy properties to the base
+ * meta-ball, because this meta-ball influence polygonization of meta-balls. */
void BKE_mball_properties_copy(struct Scene *scene, struct Object *active_object);
bool BKE_mball_minmax_ex(const struct MetaBall *mb,
@@ -55,14 +87,24 @@ bool BKE_mball_minmax_ex(const struct MetaBall *mb,
float max[3],
const float obmat[4][4],
const short flag);
+
+/* Basic vertex data functions. */
+
bool BKE_mball_minmax(const struct MetaBall *mb, float min[3], float max[3]);
bool BKE_mball_center_median(const struct MetaBall *mb, float r_cent[3]);
bool BKE_mball_center_bounds(const struct MetaBall *mb, float r_cent[3]);
void BKE_mball_transform(struct MetaBall *mb, const float mat[4][4], const bool do_props);
void BKE_mball_translate(struct MetaBall *mb, const float offset[3]);
+/**
+ * Most simple meta-element adding function.
+ *
+ * \note don't do context manipulation here (rna uses).
+ */
struct MetaElem *BKE_mball_element_add(struct MetaBall *mb, const int type);
+/* *** select funcs *** */
+
int BKE_mball_select_count(const struct MetaBall *mb);
int BKE_mball_select_count_multi(struct Base **bases, int bases_len);
bool BKE_mball_select_all(struct MetaBall *mb);
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index be9b84ccd62..c39583d234a 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -84,21 +84,51 @@ struct Mesh *BKE_mesh_from_bmesh_for_eval_nomain(struct BMesh *bm,
const struct CustomData_MeshMasks *cd_mask_extra,
const struct Mesh *me_settings);
+/**
+ * Find the index of the loop in 'poly' which references vertex,
+ * returns -1 if not found
+ */
int poly_find_loop_from_vert(const struct MPoly *poly, const struct MLoop *loopstart, uint vert);
+/**
+ * Fill \a r_adj with the loop indices in \a poly adjacent to the
+ * vertex. Returns the index of the loop matching vertex, or -1 if the
+ * vertex is not in \a poly
+ */
int poly_get_adj_loops_from_vert(const struct MPoly *poly,
const struct MLoop *mloop,
unsigned int vert,
unsigned int r_adj[2]);
+/**
+ * Return the index of the edge vert that is not equal to \a v. If
+ * neither edge vertex is equal to \a v, returns -1.
+ */
int BKE_mesh_edge_other_vert(const struct MEdge *e, int v);
+/**
+ * Sets each output array element to the edge index if it is a real edge, or -1.
+ */
void BKE_mesh_looptri_get_real_edges(const struct Mesh *mesh,
const struct MLoopTri *looptri,
int r_edges[3]);
+/**
+ * Free (or release) any data used by this mesh (does not free the mesh itself).
+ * Only use for undo, in most cases `BKE_id_free(nullptr, me)` should be used.
+ */
void BKE_mesh_free_data_for_undo(struct Mesh *me);
void BKE_mesh_clear_geometry(struct Mesh *me);
struct Mesh *BKE_mesh_add(struct Main *bmain, const char *name);
+/**
+ * A version of #BKE_mesh_copy_parameters that is intended for evaluated output
+ * (the modifier stack for example).
+ *
+ * \warning User counts are not handled for ID's.
+ */
void BKE_mesh_copy_parameters_for_eval(struct Mesh *me_dst, const struct Mesh *me_src);
+/**
+ * Copy user editable settings that we want to preserve
+ * when a new mesh is based on an existing mesh.
+ */
void BKE_mesh_copy_parameters(struct Mesh *me_dst, const struct Mesh *me_src);
void BKE_mesh_update_customdata_pointers(struct Mesh *me, const bool do_ensure_tess_cd);
void BKE_mesh_ensure_skin_customdata(struct Mesh *me);
@@ -121,12 +151,16 @@ struct Mesh *BKE_mesh_new_nomain_from_template_ex(const struct Mesh *me_src,
void BKE_mesh_eval_delete(struct Mesh *mesh_eval);
-/* Performs copy for use during evaluation,
- * optional referencing original arrays to reduce memory. */
+/**
+ * Performs copy for use during evaluation,
+ * optional referencing original arrays to reduce memory.
+ */
struct Mesh *BKE_mesh_copy_for_eval(const struct Mesh *source, bool reference);
-/* These functions construct a new Mesh,
- * contrary to BKE_mesh_to_curve_nurblist which modifies ob itself. */
+/**
+ * These functions construct a new Mesh,
+ * contrary to #BKE_mesh_to_curve_nurblist which modifies ob itself.
+ */
struct Mesh *BKE_mesh_new_nomain_from_curve(const struct Object *ob);
struct Mesh *BKE_mesh_new_nomain_from_curve_displist(const struct Object *ob,
const struct ListBase *dispbase);
@@ -136,6 +170,16 @@ bool BKE_mesh_clear_facemap_customdata(struct Mesh *me);
float (*BKE_mesh_orco_verts_get(struct Object *ob))[3];
void BKE_mesh_orco_verts_transform(struct Mesh *me, float (*orco)[3], int totvert, int invert);
+
+/**
+ * Add a #CD_ORCO layer to the Mesh if there is none already.
+ */
+void BKE_mesh_orco_ensure(struct Object *ob, struct Mesh *mesh);
+
+/**
+ * Rotates the vertices of a face in case v[2] or v[3] (vertex index) is = 0.
+ * this is necessary to make the if #MFace.v4 check for quads work.
+ */
int BKE_mesh_mface_index_validate(struct MFace *mface,
struct CustomData *mfdata,
int mfindex,
@@ -166,9 +210,17 @@ void BKE_mesh_material_index_clear(struct Mesh *me);
void BKE_mesh_material_remap(struct Mesh *me, const unsigned int *remap, unsigned int remap_len);
void BKE_mesh_smooth_flag_set(struct Mesh *me, const bool use_smooth);
-/* Needed after converting a mesh with subsurf optimal display to mesh. */
+/**
+ * Needed after converting a mesh with subsurf optimal display to mesh.
+ */
void BKE_mesh_edges_set_draw_render(struct Mesh *me);
+/**
+ * Used for unit testing; compares two meshes, checking only
+ * differences we care about. should be usable with leaf's
+ * testing framework I get RNA work done, will use hackish
+ * testing code for now.
+ */
const char *BKE_mesh_cmp(struct Mesh *me1, struct Mesh *me2, float thresh);
struct BoundBox *BKE_mesh_boundbox_get(struct Object *ob);
@@ -177,34 +229,49 @@ void BKE_mesh_texspace_calc(struct Mesh *me);
void BKE_mesh_texspace_ensure(struct Mesh *me);
void BKE_mesh_texspace_get(struct Mesh *me, float r_loc[3], float r_size[3]);
void BKE_mesh_texspace_get_reference(struct Mesh *me,
- short **r_texflag,
+ char **r_texflag,
float **r_loc,
float **r_size);
void BKE_mesh_texspace_copy_from_object(struct Mesh *me, struct Object *ob);
+/**
+ * Split faces based on the edge angle and loop normals.
+ * Matches behavior of face splitting in render engines.
+ *
+ * \note Will leave #CD_NORMAL loop data layer which is used by render engines to set shading up.
+ */
void BKE_mesh_split_faces(struct Mesh *mesh, bool free_loop_normals);
-/* Create new mesh from the given object at its current state.
+/**
+ * Create new mesh from the given object at its current state.
* The owner of this mesh is unknown, it is up to the caller to decide.
*
* If preserve_all_data_layers is truth then the modifier stack is re-evaluated to ensure it
* preserves all possible custom data layers.
*
- * NOTE: Dependency graph argument is required when preserve_all_data_layers is truth, and is
- * ignored otherwise. */
+ * \note Dependency graph argument is required when preserve_all_data_layers is truth, and is
+ * ignored otherwise.
+ */
struct Mesh *BKE_mesh_new_from_object(struct Depsgraph *depsgraph,
struct Object *object,
const bool preserve_all_data_layers,
const bool preserve_origindex);
-/* This is a version of BKE_mesh_new_from_object() which stores mesh in the given main database.
+/**
+ * This is a version of BKE_mesh_new_from_object() which stores mesh in the given main database.
* However, that function enforces object type to be a geometry one, and ensures a mesh is always
- * generated, be it empty. */
+ * generated, be it empty.
+ */
struct Mesh *BKE_mesh_new_from_object_to_bmain(struct Main *bmain,
struct Depsgraph *depsgraph,
struct Object *object,
bool preserve_all_data_layers);
+/**
+ * \param use_virtual_modifiers: When enabled calculate virtual-modifiers before applying `md_eval`
+ * support this since virtual-modifiers are not modifiers from a user perspective,
+ * allowing shape keys to be included with the modifier being applied, see: T91923.
+ */
struct Mesh *BKE_mesh_create_derived_for_modifier(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob_eval,
@@ -212,7 +279,9 @@ struct Mesh *BKE_mesh_create_derived_for_modifier(struct Depsgraph *depsgraph,
const bool use_virtual_modifiers,
const bool build_shapekey_layers);
-/* Copies a nomain-Mesh into an existing Mesh. */
+/**
+ * Copies a nomain-Mesh into an existing Mesh.
+ */
void BKE_mesh_nomain_to_mesh(struct Mesh *mesh_src,
struct Mesh *mesh_dst,
struct Object *ob,
@@ -222,6 +291,7 @@ void BKE_mesh_nomain_to_meshkey(struct Mesh *mesh_src, struct Mesh *mesh_dst, st
/* vertex level transformations & checks (no derived mesh) */
+/* basic vertex data functions */
bool BKE_mesh_minmax(const struct Mesh *me, float r_min[3], float r_max[3]);
void BKE_mesh_transform(struct Mesh *me, const float mat[4][4], bool do_keys);
void BKE_mesh_translate(struct Mesh *me, const float offset[3], const bool do_keys);
@@ -233,7 +303,13 @@ void BKE_mesh_do_versions_cd_flag_init(struct Mesh *mesh);
void BKE_mesh_mselect_clear(struct Mesh *me);
void BKE_mesh_mselect_validate(struct Mesh *me);
+/**
+ * \return the index within `me->mselect`, or -1
+ */
int BKE_mesh_mselect_find(struct Mesh *me, int index, int type);
+/**
+ * \return The index of the active element.
+ */
int BKE_mesh_mselect_active_get(struct Mesh *me, int type);
void BKE_mesh_mselect_active_set(struct Mesh *me, int index, int type);
@@ -250,6 +326,17 @@ void BKE_mesh_vert_normals_apply(struct Mesh *mesh, const short (*vert_normals)[
/* *** mesh_tessellate.c *** */
+/**
+ * Recreate #MFace Tessellation.
+ *
+ * \param do_face_nor_copy: Controls whether the normals from the poly
+ * are copied to the tessellated faces.
+ *
+ * \return number of tessellation faces.
+ *
+ * \note This doesn't use multi-threading like #BKE_mesh_recalc_looptri since
+ * it's not used in many places and #MFace should be phased out.
+ */
int BKE_mesh_tessface_calc_ex(struct CustomData *fdata,
struct CustomData *ldata,
struct CustomData *pdata,
@@ -260,12 +347,23 @@ int BKE_mesh_tessface_calc_ex(struct CustomData *fdata,
const bool do_face_nor_copy);
void BKE_mesh_tessface_calc(struct Mesh *mesh);
+/**
+ * Calculate tessellation into #MLoopTri which exist only for this purpose.
+ */
void BKE_mesh_recalc_looptri(const struct MLoop *mloop,
const struct MPoly *mpoly,
const struct MVert *mvert,
int totloop,
int totpoly,
struct MLoopTri *mlooptri);
+/**
+ * A version of #BKE_mesh_recalc_looptri which takes pre-calculated polygon normals
+ * (used to avoid having to calculate the face normal for NGON tessellation).
+ *
+ * \note Only use this function if normals have already been calculated, there is no need
+ * to calculate normals just to use this function as it will cause the normals for triangles
+ * to be calculated which aren't needed for tessellation.
+ */
void BKE_mesh_recalc_looptri_with_normals(const struct MLoop *mloop,
const struct MPoly *mpoly,
const struct MVert *mvert,
@@ -292,8 +390,15 @@ void BKE_mesh_calc_normals_poly_and_vertex(struct MVert *mvert,
int mpoly_len,
float (*r_poly_normals)[3],
float (*r_vert_normals)[3]);
+/**
+ * \note this does not update the #CD_NORMAL layer,
+ * but does update the normals in the #CD_MVERT layer.
+ */
void BKE_mesh_calc_normals(struct Mesh *me);
void BKE_mesh_ensure_normals(struct Mesh *me);
+/**
+ * Called after calculating all modifiers.
+ */
void BKE_mesh_ensure_normals_for_display(struct Mesh *mesh);
void BKE_mesh_calc_normals_looptri(struct MVert *mverts,
int numVerts,
@@ -311,6 +416,12 @@ void BKE_mesh_loop_manifold_fan_around_vert_next(const struct MLoop *mloops,
int *r_mlfan_vert_index,
int *r_mpfan_curr_index);
+/**
+ * Define sharp edges as needed to mimic 'autosmooth' from angle threshold.
+ *
+ * Used when defining an empty custom loop normals data layer,
+ * to keep same shading as with auto-smooth!
+ */
void BKE_edges_sharp_from_angle_set(const struct MVert *mverts,
const int numVerts,
struct MEdge *medges,
@@ -379,17 +490,42 @@ void BKE_lnor_spacearr_init(MLoopNorSpaceArray *lnors_spacearr,
void BKE_lnor_spacearr_clear(MLoopNorSpaceArray *lnors_spacearr);
void BKE_lnor_spacearr_free(MLoopNorSpaceArray *lnors_spacearr);
+/**
+ * Utility for multi-threaded calculation that ensures
+ * `lnors_spacearr_tls` doesn't share memory with `lnors_spacearr`
+ * that would cause it not to be thread safe.
+ *
+ * \note This works as long as threads never operate on the same loops at once.
+ */
void BKE_lnor_spacearr_tls_init(MLoopNorSpaceArray *lnors_spacearr,
MLoopNorSpaceArray *lnors_spacearr_tls);
+/**
+ * Utility for multi-threaded calculation
+ * that merges `lnors_spacearr_tls` into `lnors_spacearr`.
+ */
void BKE_lnor_spacearr_tls_join(MLoopNorSpaceArray *lnors_spacearr,
MLoopNorSpaceArray *lnors_spacearr_tls);
MLoopNorSpace *BKE_lnor_space_create(MLoopNorSpaceArray *lnors_spacearr);
+/**
+ * Should only be called once.
+ * Beware, this modifies ref_vec and other_vec in place!
+ * In case no valid space can be generated, ref_alpha and ref_beta are set to zero
+ * (which means 'use auto lnors').
+ */
void BKE_lnor_space_define(MLoopNorSpace *lnor_space,
const float lnor[3],
float vec_ref[3],
float vec_other[3],
struct BLI_Stack *edge_vectors);
+/**
+ * Add a new given loop to given lnor_space.
+ * Depending on \a lnor_space->data_type, we expect \a bm_loop to be a pointer to BMLoop struct
+ * (in case of BMLOOP_PTR), or nullptr (in case of LOOP_INDEX), loop index is then stored in
+ * pointer. If \a is_single is set, the BMLoop or loop index is directly stored in \a
+ * lnor_space->loops pointer (since there is only one loop in this fan), else it is added to the
+ * linked list of loops in the fan.
+ */
void BKE_lnor_space_add_loop(MLoopNorSpaceArray *lnors_spacearr,
MLoopNorSpace *lnor_space,
const int ml_index,
@@ -403,6 +539,12 @@ void BKE_lnor_space_custom_normal_to_data(MLoopNorSpace *lnor_space,
short r_clnor_data[2]);
/* Medium-level custom normals functions. */
+
+/**
+ * Compute split normals, i.e. vertex normals associated with each poly (hence 'loop normals').
+ * Useful to materialize sharp edges (or non-smooth faces) without actually modifying the geometry
+ * (splitting edges).
+ */
void BKE_mesh_normals_loop_split(const struct MVert *mverts,
const int numVerts,
struct MEdge *medges,
@@ -442,20 +584,49 @@ void BKE_mesh_normals_loop_custom_from_vertices_set(const struct MVert *mverts,
const int numPolys,
short (*r_clnors_data)[2]);
+/**
+ * Computes average per-vertex normals from given custom loop normals.
+ *
+ * \param clnors: The computed custom loop normals.
+ * \param r_vert_clnors: The (already allocated) array where to store averaged per-vertex normals.
+ */
void BKE_mesh_normals_loop_to_vertex(const int numVerts,
const struct MLoop *mloops,
const int numLoops,
const float (*clnors)[3],
float (*r_vert_clnors)[3]);
-/* High-level custom normals functions. */
+/**
+ * High-level custom normals functions.
+ */
bool BKE_mesh_has_custom_loop_normals(struct Mesh *me);
void BKE_mesh_calc_normals_split(struct Mesh *mesh);
+/**
+ * Compute 'split' (aka loop, or per face corner's) normals.
+ *
+ * \param r_lnors_spacearr: Allows to get computed loop normal space array.
+ * That data, among other things, contains 'smooth fan' info, useful e.g.
+ * to split geometry along sharp edges.
+ */
void BKE_mesh_calc_normals_split_ex(struct Mesh *mesh,
struct MLoopNorSpaceArray *r_lnors_spacearr);
+/**
+ * Higher level functions hiding most of the code needed around call to
+ * #BKE_mesh_normals_loop_custom_set().
+ *
+ * \param r_custom_loopnors: is not const, since code will replace zero_v3 normals there
+ * with automatically computed vectors.
+ */
void BKE_mesh_set_custom_normals(struct Mesh *mesh, float (*r_custom_loopnors)[3]);
+/**
+ * Higher level functions hiding most of the code needed around call to
+ * #BKE_mesh_normals_loop_custom_from_vertices_set().
+ *
+ * \param r_custom_vertnors: is not const, since code will replace zero_v3 normals there
+ * with automatically computed vectors.
+ */
void BKE_mesh_set_custom_normals_from_vertices(struct Mesh *mesh, float (*r_custom_vertnors)[3]);
/* *** mesh_evaluate.cc *** */
@@ -472,6 +643,7 @@ void BKE_mesh_calc_poly_center(const struct MPoly *mpoly,
const struct MLoop *loopstart,
const struct MVert *mvarray,
float r_cent[3]);
+/* NOTE: passing poly-normal is only a speedup so we can skip calculating it. */
float BKE_mesh_calc_poly_area(const struct MPoly *mpoly,
const struct MLoop *loopstart,
const struct MVert *mvarray);
@@ -490,11 +662,25 @@ void BKE_mesh_poly_edgebitmap_insert(unsigned int *edge_bitmap,
const struct MLoop *mloop);
bool BKE_mesh_center_median(const struct Mesh *me, float r_cent[3]);
+/**
+ * Calculate the center from polygons,
+ * use when we want to ignore vertex locations that don't have connected faces.
+ */
bool BKE_mesh_center_median_from_polys(const struct Mesh *me, float r_cent[3]);
bool BKE_mesh_center_bounds(const struct Mesh *me, float r_cent[3]);
bool BKE_mesh_center_of_surface(const struct Mesh *me, float r_cent[3]);
+/**
+ * \note Mesh must be manifold with consistent face-winding,
+ * see #mesh_calc_poly_volume_centroid for details.
+ */
bool BKE_mesh_center_of_volume(const struct Mesh *me, float r_cent[3]);
+/**
+ * Calculate the volume and center.
+ *
+ * \param r_volume: Volume (unsigned).
+ * \param r_center: Center of mass.
+ */
void BKE_mesh_calc_volume(const struct MVert *mverts,
const int mverts_num,
const struct MLoopTri *mlooptri,
@@ -505,6 +691,19 @@ void BKE_mesh_calc_volume(const struct MVert *mverts,
/* tessface */
void BKE_mesh_convert_mfaces_to_mpolys(struct Mesh *mesh);
+/**
+ * The same as #BKE_mesh_convert_mfaces_to_mpolys
+ * but oriented to be used in #do_versions from `readfile.c`
+ * the difference is how active/render/clone/stencil indices are handled here.
+ *
+ * normally they're being set from `pdata` which totally makes sense for meshes which are already
+ * converted to #BMesh structures, but when loading older files indices shall be updated in other
+ * way around, so newly added `pdata` and `ldata` would have this indices set
+ * based on `fdata` layer.
+ *
+ * this is normally only needed when reading older files,
+ * in all other cases #BKE_mesh_convert_mfaces_to_mpolys shall be always used.
+ */
void BKE_mesh_do_versions_convert_mfaces_to_mpolys(struct Mesh *mesh);
void BKE_mesh_convert_mfaces_to_mpolys_ex(struct ID *id,
struct CustomData *fdata,
@@ -521,8 +720,20 @@ void BKE_mesh_convert_mfaces_to_mpolys_ex(struct ID *id,
struct MLoop **r_mloop,
struct MPoly **r_mpoly);
+/**
+ * Flip a single MLoop's #MDisps structure,
+ * low level function to be called from face-flipping code which re-arranged the mdisps themselves.
+ */
void BKE_mesh_mdisp_flip(struct MDisps *md, const bool use_loop_mdisp_flip);
+/**
+ * Flip (invert winding of) the given \a mpoly, i.e. reverse order of its loops
+ * (keeping the same vertex as 'start point').
+ *
+ * \param mpoly: the polygon to flip.
+ * \param mloop: the full loops array.
+ * \param ldata: the loops custom data.
+ */
void BKE_mesh_polygon_flip_ex(struct MPoly *mpoly,
struct MLoop *mloop,
struct CustomData *ldata,
@@ -530,6 +741,11 @@ void BKE_mesh_polygon_flip_ex(struct MPoly *mpoly,
struct MDisps *mdisp,
const bool use_loop_mdisp_flip);
void BKE_mesh_polygon_flip(struct MPoly *mpoly, struct MLoop *mloop, struct CustomData *ldata);
+/**
+ * Flip (invert winding of) all polygons (used to inverse their normals).
+ *
+ * \note Invalidates tessellation, caller must handle that.
+ */
void BKE_mesh_polygons_flip(struct MPoly *mpoly,
struct MLoop *mloop,
struct CustomData *ldata,
@@ -542,12 +758,48 @@ enum {
MESH_MERGE_VERTS_DUMP_IF_MAPPED,
MESH_MERGE_VERTS_DUMP_IF_EQUAL,
};
+/**
+ * Merge Verts
+ *
+ * This frees the given mesh and returns a new mesh.
+ *
+ * \param vtargetmap: The table that maps vertices to target vertices. a value of -1
+ * indicates a vertex is a target, and is to be kept.
+ * This array is aligned with 'mesh->totvert'
+ * \warning \a vtargetmap must **not** contain any chained mapping (v1 -> v2 -> v3 etc.),
+ * this is not supported and will likely generate corrupted geometry.
+ *
+ * \param tot_vtargetmap: The number of non '-1' values in vtargetmap. (not the size)
+ *
+ * \param merge_mode: enum with two modes.
+ * - #MESH_MERGE_VERTS_DUMP_IF_MAPPED
+ * When called by the Mirror Modifier,
+ * In this mode it skips any faces that have all vertices merged (to avoid creating pairs
+ * of faces sharing the same set of vertices)
+ * - #MESH_MERGE_VERTS_DUMP_IF_EQUAL
+ * When called by the Array Modifier,
+ * In this mode, faces where all vertices are merged are double-checked,
+ * to see whether all target vertices actually make up a poly already.
+ * Indeed it could be that all of a poly's vertices are merged,
+ * but merged to vertices that do not make up a single poly,
+ * in which case the original poly should not be dumped.
+ * Actually this later behavior could apply to the Mirror Modifier as well,
+ * but the additional checks are costly and not necessary in the case of mirror,
+ * because each vertex is only merged to its own mirror.
+ *
+ * \note #BKE_mesh_tessface_calc_ex has to run on the returned DM
+ * if you want to access tess-faces.
+ */
struct Mesh *BKE_mesh_merge_verts(struct Mesh *mesh,
const int *vtargetmap,
const int tot_vtargetmap,
const int merge_mode);
-/* flush flags */
+/* Flush flags. */
+
+/**
+ * Update the hide flag for edges and faces from the corresponding flag in verts.
+ */
void BKE_mesh_flush_hidden_from_verts_ex(const struct MVert *mvert,
const struct MLoop *mloop,
struct MEdge *medge,
@@ -562,6 +814,9 @@ void BKE_mesh_flush_hidden_from_polys_ex(struct MVert *mvert,
const struct MPoly *mpoly,
const int totpoly);
void BKE_mesh_flush_hidden_from_polys(struct Mesh *me);
+/**
+ * simple poly -> vert/edge selection.
+ */
void BKE_mesh_flush_select_from_polys_ex(struct MVert *mvert,
const int totvert,
const struct MLoop *mloop,
@@ -580,6 +835,17 @@ void BKE_mesh_flush_select_from_verts_ex(const struct MVert *mvert,
void BKE_mesh_flush_select_from_verts(struct Mesh *me);
/* spatial evaluation */
+/**
+ * This function takes the difference between 2 vertex-coord-arrays
+ * (\a vert_cos_src, \a vert_cos_dst),
+ * and applies the difference to \a vert_cos_new relative to \a vert_cos_org.
+ *
+ * \param vert_cos_src: reference deform source.
+ * \param vert_cos_dst: reference deform destination.
+ *
+ * \param vert_cos_org: reference for the output location.
+ * \param vert_cos_new: resulting coords.
+ */
void BKE_mesh_calc_relative_deform(const struct MPoly *mpoly,
const int totpoly,
const struct MLoop *mloop,
@@ -593,10 +859,41 @@ void BKE_mesh_calc_relative_deform(const struct MPoly *mpoly,
/* *** mesh_validate.c *** */
+/**
+ * Validates and corrects a Mesh.
+ *
+ * \returns true if a change is made.
+ */
bool BKE_mesh_validate(struct Mesh *me, const bool do_verbose, const bool cddata_check_mask);
+/**
+ * Checks if a Mesh is valid without any modification. This is always verbose.
+ *
+ * \see #DM_is_valid to call on derived meshes
+ *
+ * \returns is_valid.
+ */
bool BKE_mesh_is_valid(struct Mesh *me);
+/**
+ * Check all material indices of polygons are valid, invalid ones are set to 0.
+ * \returns is_valid.
+ */
bool BKE_mesh_validate_material_indices(struct Mesh *me);
+/**
+ * Validate the mesh, \a do_fixes requires \a mesh to be non-null.
+ *
+ * \return false if no changes needed to be made.
+ *
+ * Vertex Normals
+ * ==============
+ *
+ * While zeroed normals are checked, these checks aren't comprehensive.
+ * Technically, to detect errors here a normal recalculation and comparison is necessary.
+ * However this function is mainly to prevent severe errors in geometry
+ * (invalid data that will crash Blender, or cause some features to behave incorrectly),
+ * not to detect subtle differences in the resulting normals which could be caused
+ * by importers that load normals (for example).
+ */
bool BKE_mesh_validate_arrays(struct Mesh *me,
struct MVert *mverts,
unsigned int totvert,
@@ -613,6 +910,9 @@ bool BKE_mesh_validate_arrays(struct Mesh *me,
const bool do_fixes,
bool *r_change);
+/**
+ * \returns is_valid.
+ */
bool BKE_mesh_validate_all_customdata(struct CustomData *vdata,
const uint totvert,
struct CustomData *edata,
@@ -627,12 +927,31 @@ bool BKE_mesh_validate_all_customdata(struct CustomData *vdata,
bool *r_change);
void BKE_mesh_strip_loose_faces(struct Mesh *me);
+/**
+ * Works on both loops and polys!
+ *
+ * \note It won't try to guess which loops of an invalid poly to remove!
+ * this is the work of the caller, to mark those loops.
+ * See e.g. #BKE_mesh_validate_arrays().
+ */
void BKE_mesh_strip_loose_polysloops(struct Mesh *me);
void BKE_mesh_strip_loose_edges(struct Mesh *me);
+/**
+ * If the mesh is from a very old blender version,
+ * convert mface->edcode to edge drawflags
+ */
void BKE_mesh_calc_edges_legacy(struct Mesh *me, const bool use_old);
void BKE_mesh_calc_edges_loose(struct Mesh *mesh);
+/**
+ * Calculate edges from polygons.
+ */
void BKE_mesh_calc_edges(struct Mesh *mesh, bool keep_existing_edges, const bool select_new_edges);
+/**
+ * Calculate/create edges from tessface data
+ *
+ * \param mesh: The mesh to add edges into
+ */
void BKE_mesh_calc_edges_tessface(struct Mesh *mesh);
/* In DerivedMesh.cc */
diff --git a/source/blender/blenkernel/BKE_mesh_boolean_convert.hh b/source/blender/blenkernel/BKE_mesh_boolean_convert.hh
index 59f6e75183e..a7a7529f217 100644
--- a/source/blender/blenkernel/BKE_mesh_boolean_convert.hh
+++ b/source/blender/blenkernel/BKE_mesh_boolean_convert.hh
@@ -32,6 +32,16 @@ struct Mesh;
namespace blender::meshintersect {
+/**
+ * Do a mesh boolean operation directly on meshes (without going back and forth to BMesh).
+ * \param meshes: An array of Mesh pointers.
+ * \param obmats: An array of pointers to the obmat matrices that transform local
+ * coordinates to global ones. It is allowed for the pointers to be null, meaning the
+ * transformation is the identity.
+ * \param material_remaps: An array of pointers to arrays of maps from material slot numbers in the
+ * corresponding mesh to the material slot in the first mesh. It is OK for material_remaps or any
+ * of its constituent arrays to be empty.
+ */
Mesh *direct_mesh_boolean(blender::Span<const Mesh *> meshes,
blender::Span<const float4x4 *> obmats,
const float4x4 &target_transform,
diff --git a/source/blender/blenkernel/BKE_mesh_iterators.h b/source/blender/blenkernel/BKE_mesh_iterators.h
index a65f25ee182..83f0228dc76 100644
--- a/source/blender/blenkernel/BKE_mesh_iterators.h
+++ b/source/blender/blenkernel/BKE_mesh_iterators.h
@@ -39,6 +39,11 @@ void BKE_mesh_foreach_mapped_vert(struct Mesh *mesh,
const short no_s[3]),
void *userData,
MeshForeachFlag flag);
+/**
+ * Copied from #cdDM_foreachMappedEdge.
+ * \param tot_edges: Number of original edges. Used to avoid calling the callback with invalid
+ * edge indices.
+ */
void BKE_mesh_foreach_mapped_edge(
struct Mesh *mesh,
int tot_edges,
diff --git a/source/blender/blenkernel/BKE_mesh_mapping.h b/source/blender/blenkernel/BKE_mesh_mapping.h
index 0518f303744..acc1628de1d 100644
--- a/source/blender/blenkernel/BKE_mesh_mapping.h
+++ b/source/blender/blenkernel/BKE_mesh_mapping.h
@@ -105,6 +105,11 @@ UvVertMap *BKE_mesh_uv_vert_map_create(const struct MPoly *mpoly,
UvMapVert *BKE_mesh_uv_vert_map_get_vert(UvVertMap *vmap, unsigned int v);
void BKE_mesh_uv_vert_map_free(UvVertMap *vmap);
+/**
+ * Generates a map where the key is the vertex and the value
+ * is a list of polys that use that vertex as a corner.
+ * The lists are allocated from one memory pool.
+ */
void BKE_mesh_vert_poly_map_create(MeshElemMap **r_map,
int **r_mem,
const struct MPoly *mpoly,
@@ -112,6 +117,11 @@ void BKE_mesh_vert_poly_map_create(MeshElemMap **r_map,
int totvert,
int totpoly,
int totloop);
+/**
+ * Generates a map where the key is the vertex and the value
+ * is a list of loops that use that vertex as a corner.
+ * The lists are allocated from one memory pool.
+ */
void BKE_mesh_vert_loop_map_create(MeshElemMap **r_map,
int **r_mem,
const struct MPoly *mpoly,
@@ -119,6 +129,11 @@ void BKE_mesh_vert_loop_map_create(MeshElemMap **r_map,
int totvert,
int totpoly,
int totloop);
+/**
+ * Generates a map where the key is the edge and the value
+ * is a list of looptris that use that edge.
+ * The lists are allocated from one memory pool.
+ */
void BKE_mesh_vert_looptri_map_create(MeshElemMap **r_map,
int **r_mem,
const struct MVert *mvert,
@@ -127,10 +142,24 @@ void BKE_mesh_vert_looptri_map_create(MeshElemMap **r_map,
const int totlooptri,
const struct MLoop *mloop,
const int totloop);
+/**
+ * Generates a map where the key is the vertex and the value
+ * is a list of edges that use that vertex as an endpoint.
+ * The lists are allocated from one memory pool.
+ */
void BKE_mesh_vert_edge_map_create(
MeshElemMap **r_map, int **r_mem, const struct MEdge *medge, int totvert, int totedge);
+/**
+ * A version of #BKE_mesh_vert_edge_map_create that references connected vertices directly
+ * (not their edges).
+ */
void BKE_mesh_vert_edge_vert_map_create(
MeshElemMap **r_map, int **r_mem, const struct MEdge *medge, int totvert, int totedge);
+/**
+ * Generates a map where the key is the edge and the value is a list of loops that use that edge.
+ * Loops indices of a same poly are contiguous and in winding order.
+ * The lists are allocated from one memory pool.
+ */
void BKE_mesh_edge_loop_map_create(MeshElemMap **r_map,
int **r_mem,
const struct MEdge *medge,
@@ -139,6 +168,11 @@ void BKE_mesh_edge_loop_map_create(MeshElemMap **r_map,
const int totpoly,
const struct MLoop *mloop,
const int totloop);
+/**
+ * Generates a map where the key is the edge and the value
+ * is a list of polygons that use that edge.
+ * The lists are allocated from one memory pool.
+ */
void BKE_mesh_edge_poly_map_create(MeshElemMap **r_map,
int **r_mem,
const struct MEdge *medge,
@@ -147,11 +181,29 @@ void BKE_mesh_edge_poly_map_create(MeshElemMap **r_map,
const int totpoly,
const struct MLoop *mloop,
const int totloop);
+/**
+ * This function creates a map so the source-data (vert/edge/loop/poly)
+ * can loop over the destination data (using the destination arrays origindex).
+ *
+ * This has the advantage that it can operate on any data-types.
+ *
+ * \param totsource: The total number of elements that \a final_origindex points to.
+ * \param totfinal: The size of \a final_origindex
+ * \param final_origindex: The size of the final array.
+ *
+ * \note `totsource` could be `totpoly`,
+ * `totfinal` could be `tottessface` and `final_origindex` its ORIGINDEX custom-data.
+ * This would allow an MPoly to loop over its tessfaces.
+ */
void BKE_mesh_origindex_map_create(MeshElemMap **r_map,
int **r_mem,
const int totsource,
const int *final_origindex,
const int totfinal);
+/**
+ * A version of #BKE_mesh_origindex_map_create that takes a looptri array.
+ * Making a poly -> looptri map.
+ */
void BKE_mesh_origindex_map_create_looptri(MeshElemMap **r_map,
int **r_mem,
const struct MPoly *mpoly,
@@ -212,7 +264,11 @@ typedef bool (*MeshRemapIslandsCalc)(struct MVert *verts,
struct MeshIslandStore *r_island_store);
/* Above vert/UV mapping stuff does not do what we need here, but does things we do not need here.
- * So better keep them separated for now, I think.
+ * So better keep them separated for now, I think. */
+
+/**
+ * Calculate 'generic' UV islands, i.e. based only on actual geometry data (edge seams),
+ * not some UV layers coordinates.
*/
bool BKE_mesh_calc_islands_loop_poly_edgeseam(struct MVert *verts,
const int totvert,
@@ -224,6 +280,19 @@ bool BKE_mesh_calc_islands_loop_poly_edgeseam(struct MVert *verts,
const int totloop,
MeshIslandStore *r_island_store);
+/**
+ * Calculate UV islands.
+ *
+ * \note If no MLoopUV layer is passed, we only consider edges tagged as seams as UV boundaries.
+ * This has the advantages of simplicity, and being valid/common to all UV maps.
+ * However, it means actual UV islands without matching UV seams will not be handled correctly.
+ * If a valid UV layer is passed as \a luvs parameter,
+ * UV coordinates are also used to detect islands boundaries.
+ *
+ * \note All this could be optimized.
+ * Not sure it would be worth the more complex code, though,
+ * those loops are supposed to be really quick to do.
+ */
bool BKE_mesh_calc_islands_loop_poly_uvmap(struct MVert *verts,
const int totvert,
struct MEdge *edges,
@@ -235,6 +304,14 @@ bool BKE_mesh_calc_islands_loop_poly_uvmap(struct MVert *verts,
const struct MLoopUV *luvs,
MeshIslandStore *r_island_store);
+/**
+ * Calculate smooth groups from sharp edges.
+ *
+ * \param r_totgroup: The total number of groups, 1 or more.
+ * \return Polygon aligned array of group index values (bitflags if use_bitflags is true),
+ * starting at 1 (0 being used as 'invalid' flag).
+ * Note it's callers's responsibility to MEM_freeN returned array.
+ */
int *BKE_mesh_calc_smoothgroups(const struct MEdge *medge,
const int totedge,
const struct MPoly *mpoly,
diff --git a/source/blender/blenkernel/BKE_mesh_mirror.h b/source/blender/blenkernel/BKE_mesh_mirror.h
index 7b230b04410..abb8e4d3e44 100644
--- a/source/blender/blenkernel/BKE_mesh_mirror.h
+++ b/source/blender/blenkernel/BKE_mesh_mirror.h
@@ -43,10 +43,16 @@ void BKE_mesh_mirror_apply_mirror_on_axis(struct Main *bmain,
const int axis,
const float dist);
-struct Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(struct MirrorModifierData *mmd,
- struct Object *ob,
- const struct Mesh *mesh,
- const int axis);
+/**
+ * \warning This should _not_ be used to modify original meshes since
+ * it doesn't handle shape-keys, use #BKE_mesh_mirror_apply_mirror_on_axis instead.
+ */
+struct Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(
+ struct MirrorModifierData *mmd,
+ struct Object *ob,
+ const struct Mesh *mesh,
+ const int axis,
+ const bool use_correct_order_on_merge);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_mesh_remap.h b/source/blender/blenkernel/BKE_mesh_remap.h
index 7f8f028c26b..c33b3800aa4 100644
--- a/source/blender/blenkernel/BKE_mesh_remap.h
+++ b/source/blender/blenkernel/BKE_mesh_remap.h
@@ -161,11 +161,24 @@ void BKE_mesh_remap_calc_source_cddata_masks_from_map_modes(
const int poly_mode,
struct CustomData_MeshMasks *cddata_mask);
+/**
+ * Compute a value of the difference between both given meshes.
+ * The smaller the result, the better the match.
+ *
+ * We return the inverse of the average of the inversed
+ * shortest distance from each dst vertex to src ones.
+ * In other words, beyond a certain (relatively small) distance, all differences have more or less
+ * the same weight in final result, which allows to reduce influence of a few high differences,
+ * in favor of a global good matching.
+ */
float BKE_mesh_remap_calc_difference_from_mesh(const struct SpaceTransform *space_transform,
const struct MVert *verts_dst,
const int numverts_dst,
struct Mesh *me_src);
+/**
+ * Set r_space_transform so that best bbox of dst matches best bbox of src.
+ */
void BKE_mesh_remap_find_best_match_from_mesh(const struct MVert *verts_dst,
const int numverts_dst,
struct Mesh *me_src,
diff --git a/source/blender/blenkernel/BKE_mesh_runtime.h b/source/blender/blenkernel/BKE_mesh_runtime.h
index df111360bcd..764241e7f92 100644
--- a/source/blender/blenkernel/BKE_mesh_runtime.h
+++ b/source/blender/blenkernel/BKE_mesh_runtime.h
@@ -41,18 +41,42 @@ struct Mesh;
struct Object;
struct Scene;
+/**
+ * \brief Initialize the runtime of the given mesh.
+ *
+ * Function expects that the runtime is already cleared.
+ */
void BKE_mesh_runtime_init_data(struct Mesh *mesh);
+/**
+ * \brief Free all data (and mutexes) inside the runtime of the given mesh.
+ */
void BKE_mesh_runtime_free_data(struct Mesh *mesh);
+/**
+ * Clear all pointers which we don't want to be shared on copying the datablock.
+ * However, keep all the flags which defines what the mesh is (for example, that
+ * it's deformed only, or that its custom data layers are out of date.)
+ */
void BKE_mesh_runtime_reset_on_copy(struct Mesh *mesh, const int flag);
int BKE_mesh_runtime_looptri_len(const struct Mesh *mesh);
void BKE_mesh_runtime_looptri_recalc(struct Mesh *mesh);
+/**
+ * \note This function only fills a cache, and therefore the mesh argument can
+ * be considered logically const. Concurrent access is protected by a mutex.
+ * \note This is a ported copy of dm_getLoopTriArray(dm).
+ */
const struct MLoopTri *BKE_mesh_runtime_looptri_ensure(const struct Mesh *mesh);
bool BKE_mesh_runtime_ensure_edit_data(struct Mesh *mesh);
bool BKE_mesh_runtime_clear_edit_data(struct Mesh *mesh);
bool BKE_mesh_runtime_reset_edit_data(struct Mesh *mesh);
void BKE_mesh_runtime_clear_geometry(struct Mesh *mesh);
+/**
+ * \brief This function clears runtime cache of the given mesh.
+ *
+ * Call this function to recalculate runtime data when used.
+ */
void BKE_mesh_runtime_clear_cache(struct Mesh *mesh);
+/* This is a copy of DM_verttri_from_looptri(). */
void BKE_mesh_runtime_verttri_from_looptri(struct MVertTri *r_verttri,
const struct MLoop *mloop,
const struct MLoopTri *looptri,
@@ -62,6 +86,7 @@ void BKE_mesh_runtime_verttri_from_looptri(struct MVertTri *r_verttri,
* to a more suitable location when that file is removed.
* They should also be renamed to use conventions from BKE, not old DerivedMesh.cc.
* For now keep the names similar to avoid confusion. */
+
struct Mesh *mesh_get_eval_final(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
@@ -99,6 +124,7 @@ void BKE_mesh_runtime_eval_to_meshkey(struct Mesh *me_deformed,
#ifndef NDEBUG
char *BKE_mesh_runtime_debug_info(struct Mesh *me_eval);
void BKE_mesh_runtime_debug_print(struct Mesh *me_eval);
+/* XXX Should go in customdata file? */
void BKE_mesh_runtime_debug_print_cdlayers(struct CustomData *data);
bool BKE_mesh_runtime_is_valid(struct Mesh *me_eval);
#endif /* NDEBUG */
diff --git a/source/blender/blenkernel/BKE_mesh_tangent.h b/source/blender/blenkernel/BKE_mesh_tangent.h
index 96eaa23ce71..39d4072085c 100644
--- a/source/blender/blenkernel/BKE_mesh_tangent.h
+++ b/source/blender/blenkernel/BKE_mesh_tangent.h
@@ -25,6 +25,12 @@ extern "C" {
struct ReportList;
+/**
+ * Compute simplified tangent space normals, i.e.
+ * tangent vector + sign of bi-tangent one, which combined with
+ * split normals can be used to recreate the full tangent space.
+ * NOTE: * The mesh should be made of only tris and quads!
+ */
void BKE_mesh_calc_loop_tangent_single_ex(const struct MVert *mverts,
const int numVerts,
const struct MLoop *mloops,
@@ -35,11 +41,20 @@ void BKE_mesh_calc_loop_tangent_single_ex(const struct MVert *mverts,
const struct MPoly *mpolys,
const int numPolys,
struct ReportList *reports);
+/**
+ * Wrapper around BKE_mesh_calc_loop_tangent_single_ex, which takes care of most boiling code.
+ * \note
+ * - There must be a valid loop's CD_NORMALS available.
+ * - The mesh should be made of only tris and quads!
+ */
void BKE_mesh_calc_loop_tangent_single(struct Mesh *mesh,
const char *uvmap,
float (*r_looptangents)[4],
struct ReportList *reports);
+/**
+ * See: #BKE_editmesh_loop_tangent_calc (matching logic).
+ */
void BKE_mesh_calc_loop_tangent_ex(const struct MVert *mvert,
const struct MPoly *mpoly,
const uint mpoly_len,
@@ -71,6 +86,12 @@ void BKE_mesh_add_loop_tangent_named_layer_for_uv(struct CustomData *uv_data,
const char *layer_name);
#define DM_TANGENT_MASK_ORCO (1 << 9)
+/**
+ * Here we get some useful information such as active uv layer name and
+ * search if it is already in tangent_names.
+ * Also, we calculate tangent_mask that works as a descriptor of tangents state.
+ * If tangent_mask has changed, then recalculate tangents.
+ */
void BKE_mesh_calc_loop_tangent_step_0(const struct CustomData *loopData,
bool calc_active_tangent,
const char (*tangent_names)[64],
diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h
index 8be563e4c96..278189633a6 100644
--- a/source/blender/blenkernel/BKE_modifier.h
+++ b/source/blender/blenkernel/BKE_modifier.h
@@ -98,7 +98,7 @@ typedef enum {
eModifierTypeFlag_RequiresOriginalData = (1 << 5),
/**
- * For modifiers that support pointcache,
+ * For modifiers that support point-cache,
* so we can check to see if it has files we need to deal with.
*/
eModifierTypeFlag_UsesPointCache = (1 << 6),
@@ -403,6 +403,10 @@ void BKE_modifier_init(void);
const ModifierTypeInfo *BKE_modifier_get_info(ModifierType type);
/* For modifier UI panels. */
+
+/**
+ * Get the idname of the modifier type's panel, which was defined in the #panelRegister callback.
+ */
void BKE_modifier_type_panel_id(ModifierType type, char *r_idname);
void BKE_modifier_panel_expand(struct ModifierData *md);
@@ -413,6 +417,9 @@ struct ModifierData *BKE_modifier_new(int type);
void BKE_modifier_free_ex(struct ModifierData *md, const int flag);
void BKE_modifier_free(struct ModifierData *md);
+/**
+ * Use instead of `BLI_remlink` when the object's active modifier should change.
+ */
void BKE_modifier_remove_from_list(struct Object *ob, struct ModifierData *md);
/* Generate new UUID for the given modifier. */
@@ -420,6 +427,9 @@ void BKE_modifier_session_uuid_generate(struct ModifierData *md);
bool BKE_modifier_unique_name(struct ListBase *modifiers, struct ModifierData *md);
+/**
+ * Callback's can use this to avoid copying every member.
+ */
void BKE_modifier_copydata_generic(const struct ModifierData *md,
struct ModifierData *md_dst,
const int flag);
@@ -434,9 +444,21 @@ bool BKE_modifier_couldbe_cage(struct Scene *scene, struct ModifierData *md);
bool BKE_modifier_is_correctable_deformed(struct ModifierData *md);
bool BKE_modifier_is_same_topology(ModifierData *md);
bool BKE_modifier_is_non_geometrical(ModifierData *md);
+/**
+ * Check whether is enabled.
+ *
+ * \param scene: Current scene, may be NULL,
+ * in which case `isDisabled` callback of the modifier is never called.
+ */
bool BKE_modifier_is_enabled(const struct Scene *scene,
struct ModifierData *md,
int required_mode);
+/**
+ * Check whether given modifier is not local (i.e. from linked data) when the object is a library
+ * override.
+ *
+ * \param md: May be NULL, in which case we consider it as a non-local modifier case.
+ */
bool BKE_modifier_is_nonlocal_in_liboverride(const struct Object *ob,
const struct ModifierData *md);
void BKE_modifier_set_error(const struct Object *ob,
@@ -451,6 +473,12 @@ void BKE_modifiers_foreach_tex_link(struct Object *ob, TexWalkFunc walk, void *u
struct ModifierData *BKE_modifiers_findby_type(const struct Object *ob, ModifierType type);
struct ModifierData *BKE_modifiers_findby_name(const struct Object *ob, const char *name);
void BKE_modifiers_clear_errors(struct Object *ob);
+/**
+ * used for buttons, to find out if the 'draw deformed in edit-mode option is there.
+ *
+ * Also used in transform_conversion.c, to detect crazy-space (2nd arg then is NULL).
+ * Also used for some mesh tools to give warnings.
+ */
int BKE_modifiers_get_cage_index(const struct Scene *scene,
struct Object *ob,
int *r_lastPossibleCageIndex,
@@ -461,9 +489,21 @@ bool BKE_modifiers_is_softbody_enabled(struct Object *ob);
bool BKE_modifiers_is_cloth_enabled(struct Object *ob);
bool BKE_modifiers_is_particle_enabled(struct Object *ob);
+/**
+ * Takes an object and returns its first selected armature, else just its armature.
+ * This should work for multiple armatures per object.
+ */
struct Object *BKE_modifiers_is_deformed_by_armature(struct Object *ob);
struct Object *BKE_modifiers_is_deformed_by_meshdeform(struct Object *ob);
+/**
+ * Takes an object and returns its first selected lattice, else just its lattice.
+ * This should work for multiple lattices per object.
+ */
struct Object *BKE_modifiers_is_deformed_by_lattice(struct Object *ob);
+/**
+ * Takes an object and returns its first selected curve, else just its curve.
+ * This should work for multiple curves per object.
+ */
struct Object *BKE_modifiers_is_deformed_by_curve(struct Object *ob);
bool BKE_modifiers_uses_multires(struct Object *ob);
bool BKE_modifiers_uses_armature(struct Object *ob, struct bArmature *arm);
@@ -500,23 +540,36 @@ typedef struct VirtualModifierData {
ShapeKeyModifierData smd;
} VirtualModifierData;
+/**
+ * This is to include things that are not modifiers in the evaluation of the modifier stack,
+ * for example parenting to an armature.
+ */
struct ModifierData *BKE_modifiers_get_virtual_modifierlist(const struct Object *ob,
struct VirtualModifierData *data);
-/** Ensure modifier correctness when changing ob->data. */
+/**
+ * Ensure modifier correctness when changing `ob->data`.
+ */
void BKE_modifiers_test_object(struct Object *ob);
-/* here for do_versions */
+/**
+ * Here for #do_versions.
+ */
void BKE_modifier_mdef_compact_influences(struct ModifierData *md);
+/**
+ * Initializes `path` with either the blend file or temporary directory.
+ */
void BKE_modifier_path_init(char *path, int path_maxlen, const char *name);
const char *BKE_modifier_path_relbase(struct Main *bmain, struct Object *ob);
const char *BKE_modifier_path_relbase_from_global(struct Object *ob);
/* Accessors of original/evaluated modifiers. */
-/* For a given modifier data, get corresponding original one.
- * If the modifier data is already original, return it as-is. */
+/**
+ * For a given modifier data, get corresponding original one.
+ * If the modifier data is already original, return it as-is.
+ */
struct ModifierData *BKE_modifier_get_original(struct ModifierData *md);
struct ModifierData *BKE_modifier_get_evaluated(struct Depsgraph *depsgraph,
struct Object *object,
@@ -541,6 +594,15 @@ void BKE_modifier_deform_vertsEM(ModifierData *md,
float (*vertexCos)[3],
int numVerts);
+/**
+ * Get evaluated mesh for other evaluated object, which is used as an operand for the modifier,
+ * e.g. second operand for boolean modifier.
+ * Note that modifiers in stack always get fully evaluated COW ID pointers,
+ * never original ones. Makes things simpler.
+ *
+ * \param get_cage_mesh: Return evaluated mesh with only deforming modifiers applied
+ * (i.e. mesh topology remains the same as original one, a.k.a. 'cage' mesh).
+ */
struct Mesh *BKE_modifier_get_evaluated_mesh_from_evaluated_object(struct Object *ob_eval,
const bool get_cage_mesh);
diff --git a/source/blender/blenkernel/BKE_movieclip.h b/source/blender/blenkernel/BKE_movieclip.h
index 73c7494b8fa..9148d5b760f 100644
--- a/source/blender/blenkernel/BKE_movieclip.h
+++ b/source/blender/blenkernel/BKE_movieclip.h
@@ -35,6 +35,10 @@ struct MovieClipScopes;
struct MovieClipUser;
struct MovieDistortion;
+/**
+ * Checks if image was already loaded, then returns same image otherwise creates new.
+ * does not load ibuf itself pass on optional frame for #name images.
+ */
struct MovieClip *BKE_movieclip_file_add(struct Main *bmain, const char *name);
struct MovieClip *BKE_movieclip_file_add_exists_ex(struct Main *bmain,
const char *filepath,
@@ -44,6 +48,11 @@ void BKE_movieclip_reload(struct Main *bmain, struct MovieClip *clip);
void BKE_movieclip_clear_cache(struct MovieClip *clip);
void BKE_movieclip_clear_proxy_cache(struct MovieClip *clip);
+/**
+ * Will try to make image buffer usable when originating from the multi-layer source.
+ * Internally finds a first combined pass and uses that as a buffer.
+ * Not ideal, but is better than a complete empty buffer.
+ */
void BKE_movieclip_convert_multilayer_ibuf(struct ImBuf *ibuf);
struct ImBuf *BKE_movieclip_get_ibuf(struct MovieClip *clip, struct MovieClipUser *user);
@@ -75,11 +84,18 @@ void BKE_movieclip_update_scopes(struct MovieClip *clip,
struct MovieClipUser *user,
struct MovieClipScopes *scopes);
+/**
+ * Get segments of cached frames. useful for debugging cache policies.
+ */
void BKE_movieclip_get_cache_segments(struct MovieClip *clip,
struct MovieClipUser *user,
int *r_totseg,
int **r_points);
+/**
+ * \note currently used by proxy job for movies, threading happens within single frame
+ * (meaning scaling shall be threaded).
+ */
void BKE_movieclip_build_proxy_frame(struct MovieClip *clip,
int clip_flag,
struct MovieDistortion *distortion,
@@ -88,6 +104,10 @@ void BKE_movieclip_build_proxy_frame(struct MovieClip *clip,
int build_count,
bool undistorted);
+/**
+ * \note currently used by proxy job for sequences, threading happens within sequence
+ * (different threads handles different frames, no threading within frame is needed)
+ */
void BKE_movieclip_build_proxy_frame_for_ibuf(struct MovieClip *clip,
struct ImBuf *ibuf,
struct MovieDistortion *distortion,
@@ -104,8 +124,10 @@ void BKE_movieclip_filename_for_frame(struct MovieClip *clip,
struct MovieClipUser *user,
char *name);
-/* Read image buffer from the given movie clip without acquiring the `LOCK_MOVIECLIP` lock.
- * Used by a prefetch job which takes care of creating a local copy of the clip. */
+/**
+ * Read image buffer from the given movie clip without acquiring the #LOCK_MOVIECLIP lock.
+ * Used by a prefetch job which takes care of creating a local copy of the clip.
+ */
struct ImBuf *BKE_movieclip_anim_ibuf_for_frame_no_lock(struct MovieClip *clip,
struct MovieClipUser *user);
@@ -126,10 +148,10 @@ void BKE_movieclip_eval_update(struct Depsgraph *depsgraph,
struct MovieClip *clip);
void BKE_movieclip_eval_selection_update(struct Depsgraph *depsgraph, struct MovieClip *clip);
-/* caching flags */
+/** Caching flags. */
#define MOVIECLIP_CACHE_SKIP (1 << 0)
-/* postprocessing flags */
+/** Post-processing flags. */
#define MOVIECLIP_DISABLE_RED (1 << 0)
#define MOVIECLIP_DISABLE_GREEN (1 << 1)
#define MOVIECLIP_DISABLE_BLUE (1 << 2)
diff --git a/source/blender/blenkernel/BKE_multires.h b/source/blender/blenkernel/BKE_multires.h
index 11bfc4b2b3a..c83022c4658 100644
--- a/source/blender/blenkernel/BKE_multires.h
+++ b/source/blender/blenkernel/BKE_multires.h
@@ -45,7 +45,9 @@ struct MLoopTri;
struct MPoly;
struct MVert;
-/* Delete mesh mdisps and grid paint masks */
+/**
+ * Delete mesh mdisps and grid paint masks.
+ */
void multires_customdata_delete(struct Mesh *me);
void multires_set_tot_level(struct Object *ob, struct MultiresModifierData *mmd, int lvl);
@@ -62,6 +64,9 @@ void multires_force_external_reload(struct Object *object);
void multires_modifier_update_mdisps(struct DerivedMesh *dm, struct Scene *scene);
void multires_modifier_update_hidden(struct DerivedMesh *dm);
+/**
+ * Reset the multi-res levels to match the number of mdisps.
+ */
void multiresModifier_set_levels_from_disps(struct MultiresModifierData *mmd, struct Object *ob);
typedef enum {
@@ -79,6 +84,10 @@ struct DerivedMesh *multires_make_derived_from_derived(struct DerivedMesh *dm,
struct MultiresModifierData *find_multires_modifier_before(struct Scene *scene,
struct ModifierData *lastmd);
+/**
+ * used for applying scale on mdisps layer and syncing subdivide levels when joining objects.
+ * \param use_first: return first multi-res modifier if all multi-res'es are disabled.
+ */
struct MultiresModifierData *get_multires_modifier(struct Scene *scene,
struct Object *ob,
bool use_first);
@@ -88,18 +97,25 @@ int multires_get_level(const struct Scene *scene,
bool render,
bool ignore_simplify);
-/* Creates mesh with multires modifier applied on current object's deform mesh. */
+/**
+ * Creates mesh with multi-res modifier applied on current object's deform mesh.
+ */
struct Mesh *BKE_multires_create_mesh(struct Depsgraph *depsgraph,
struct Object *object,
struct MultiresModifierData *mmd);
-/* Get coordinates of a deformed base mesh which is an input to the given multires modifier.
- * NOTE: The modifiers will be re-evaluated. */
+/**
+ * Get coordinates of a deformed base mesh which is an input to the given multi-res modifier.
+ * \note The modifiers will be re-evaluated.
+ */
float (*BKE_multires_create_deformed_base_mesh_vert_coords(struct Depsgraph *depsgraph,
struct Object *object,
struct MultiresModifierData *mmd,
int *r_num_deformed_verts))[3];
+/**
+ * \param direction: 1 for delete higher, 0 for lower (not implemented yet).
+ */
void multiresModifier_del_levels(struct MultiresModifierData *mmd,
struct Scene *scene,
struct Object *object,
@@ -112,6 +128,10 @@ int multiresModifier_rebuild_subdiv(struct Depsgraph *depsgraph,
struct MultiresModifierData *mmd,
int rebuild_limit,
bool switch_view_to_lower_level);
+/**
+ * If `ob_src` and `ob_dst` both have multi-res modifiers,
+ * synchronize them such that `ob_dst` has the same total number of levels as `ob_src`.
+ */
void multiresModifier_sync_levels_ex(struct Object *ob_dst,
struct MultiresModifierData *mmd_src,
struct MultiresModifierData *mmd_dst);
@@ -128,15 +148,29 @@ void multiresModifier_prepare_join(struct Depsgraph *depsgraph,
int multires_mdisp_corners(struct MDisps *s);
-/* update multires data after topology changing */
+/**
+ * Update multi-res data after topology changing.
+ */
void multires_topology_changed(struct Mesh *me);
+/**
+ * Makes sure data from an external file is fully read.
+ *
+ * Since the multi-res data files only contain displacement vectors without knowledge about
+ * subdivision level some extra work is needed. Namely make is to all displacement grids have
+ * proper level and number of displacement vectors set.
+ */
void multires_ensure_external_read(struct Mesh *mesh, int top_level);
void multiresModifier_ensure_external_read(struct Mesh *mesh,
const struct MultiresModifierData *mmd);
/**** interpolation stuff ****/
+/* Adapted from `sculptmode.c` */
+
void old_mdisps_bilinear(float out[3], float (*disps)[3], const int st, float u, float v);
+/**
+ * Find per-corner coordinate with given per-face UV coord.
+ */
int mdisp_rot_face_to_crn(struct MVert *mvert,
struct MPoly *mpoly,
struct MLoop *mloop,
@@ -154,6 +188,12 @@ bool multiresModifier_reshapeFromVertcos(struct Depsgraph *depsgraph,
struct MultiresModifierData *mmd,
const float (*vert_coords)[3],
const int num_vert_coords);
+/**
+ * Returns truth on success, false otherwise.
+ *
+ * This function might fail in cases like source and destination not having
+ * matched amount of vertices.
+ */
bool multiresModifier_reshapeFromObject(struct Depsgraph *depsgraph,
struct MultiresModifierData *mmd,
struct Object *dst,
@@ -166,7 +206,7 @@ bool multiresModifier_reshapeFromCCG(const int tot_level,
struct Mesh *coarse_mesh,
struct SubdivCCG *subdiv_ccg);
-/* Subdivide multires displacement once. */
+/* Subdivide multi-res displacement once. */
typedef enum eMultiresSubdivideModeType {
MULTIRES_SUBDIVIDE_CATMULL_CLARK,
@@ -180,8 +220,10 @@ void multiresModifier_subdivide(struct Object *object,
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. */
+/**
+ * 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,
@@ -206,12 +248,12 @@ void BKE_multires_subdiv_mesh_settings_init(struct SubdivToMeshSettings *mesh_se
/* General helpers. */
-/* For a given partial derivatives of a ptex face get tangent matrix for
- * displacement.
+/**
+ * For a given partial derivatives of a PTEX face get tangent matrix for displacement.
*
* Corner needs to be known to properly "rotate" partial derivatives when the
- * matrix is being constructed for quad. For non-quad the corner is to be set
- * to 0. */
+ * matrix is being constructed for quad. For non-quad the corner is to be set to 0.
+ */
BLI_INLINE void BKE_multires_construct_tangent_matrix(float tangent_matrix[3][3],
const float dPdu[3],
const float dPdv[3],
@@ -219,8 +261,10 @@ BLI_INLINE void BKE_multires_construct_tangent_matrix(float tangent_matrix[3][3]
/* Versioning. */
-/* Convert displacement which is stored for simply-subdivided mesh to a Catmull-Clark
- * subdivided mesh. */
+/**
+ * Convert displacement which is stored for simply-subdivided mesh to a Catmull-Clark
+ * subdivided mesh.
+ */
void multires_do_versions_simple_to_catmull_clark(struct Object *object,
struct MultiresModifierData *mmd);
diff --git a/source/blender/blenkernel/BKE_nla.h b/source/blender/blenkernel/BKE_nla.h
index cf8848fe607..b297851ad90 100644
--- a/source/blender/blenkernel/BKE_nla.h
+++ b/source/blender/blenkernel/BKE_nla.h
@@ -46,106 +46,291 @@ struct PropertyRNA;
/* ----------------------------- */
/* Data Management */
+/**
+ * Remove the given NLA strip from the NLA track it occupies, free the strip's data,
+ * and the strip itself.
+ */
void BKE_nlastrip_free(ListBase *strips, struct NlaStrip *strip, bool do_id_user);
+/**
+ * Remove the given NLA track from the set of NLA tracks, free the track's data,
+ * and the track itself.
+ */
void BKE_nlatrack_free(ListBase *tracks, struct NlaTrack *nlt, bool do_id_user);
+/**
+ * Free the elements of type NLA Tracks provided in the given list, but do not free
+ * the list itself since that is not free-standing
+ */
void BKE_nla_tracks_free(ListBase *tracks, bool do_id_user);
+/**
+ * Copy NLA strip
+ *
+ * \param use_same_action: When true, the existing action is used (instead of being duplicated)
+ * \param flag: Control ID pointers management, see LIB_ID_CREATE_.../LIB_ID_COPY_...
+ * flags in BKE_lib_id.h
+ */
struct NlaStrip *BKE_nlastrip_copy(struct Main *bmain,
struct NlaStrip *strip,
const bool use_same_action,
const int flag);
+/**
+ * Copy a single NLA Track.
+ * \param flag: Control ID pointers management, see LIB_ID_CREATE_.../LIB_ID_COPY_...
+ * flags in BKE_lib_id.h
+ */
struct NlaTrack *BKE_nlatrack_copy(struct Main *bmain,
struct NlaTrack *nlt,
const bool use_same_actions,
const int flag);
+/**
+ * Copy all NLA data.
+ * \param flag: Control ID pointers management, see LIB_ID_CREATE_.../LIB_ID_COPY_...
+ * flags in BKE_lib_id.h
+ */
void BKE_nla_tracks_copy(struct Main *bmain, ListBase *dst, const ListBase *src, const int flag);
-/* Copy NLA tracks from #adt_source to #adt_dest, and update the active track/strip pointers to
- * point at those copies. */
+/**
+ * Copy NLA tracks from #adt_source to #adt_dest, and update the active track/strip pointers to
+ * point at those copies.
+ */
void BKE_nla_tracks_copy_from_adt(struct Main *bmain,
struct AnimData *adt_dest,
const struct AnimData *adt_source,
int flag);
+/**
+ * Add a NLA Track to the given AnimData.
+ * \param prev: NLA-Track to add the new one after.
+ */
struct NlaTrack *BKE_nlatrack_add(struct AnimData *adt,
struct NlaTrack *prev,
bool is_liboverride);
+/**
+ * Create a NLA Strip referencing the given Action.
+ */
struct NlaStrip *BKE_nlastrip_new(struct bAction *act);
+/**
+ * Add new NLA-strip to the top of the NLA stack - i.e.
+ * into the last track if space, or a new one otherwise.
+ */
struct NlaStrip *BKE_nlastack_add_strip(struct AnimData *adt,
struct bAction *act,
const bool is_liboverride);
+/**
+ * Add a NLA Strip referencing the given speaker's sound.
+ */
struct NlaStrip *BKE_nla_add_soundstrip(struct Main *bmain,
struct Scene *scene,
struct Speaker *speaker);
+/**
+ * Callback used by lib_query to walk over all ID usages
+ * (mimics `foreach_id` callback of #IDTypeInfo structure).
+ */
void BKE_nla_strip_foreach_id(struct NlaStrip *strip, struct LibraryForeachIDData *data);
/* ----------------------------- */
/* API */
+/**
+ * Check if there is any space in the given list to add the given strip.
+ */
bool BKE_nlastrips_has_space(ListBase *strips, float start, float end);
+/**
+ * Rearrange the strips in the track so that they are always in order
+ * (usually only needed after a strip has been moved)
+ */
void BKE_nlastrips_sort_strips(ListBase *strips);
+/**
+ * Add the given NLA-Strip to the given list of strips, assuming that it
+ * isn't currently a member of another list
+ */
bool BKE_nlastrips_add_strip(ListBase *strips, struct NlaStrip *strip);
+/**
+ * Convert 'islands' (i.e. continuous string of) selected strips to be
+ * contained within 'Meta-Strips' which act as strips which contain strips.
+ *
+ * \param is_temp: are the meta-strips to be created 'temporary' ones used for transforms?
+ */
void BKE_nlastrips_make_metas(ListBase *strips, bool is_temp);
+/**
+ * Remove meta-strips (i.e. flatten the list of strips) from the top-level of the list of strips.
+ *
+ * \param only_sel: only consider selected meta-strips, otherwise all meta-strips are removed
+ * \param only_temp: only remove the 'temporary' meta-strips used for transforms
+ */
void BKE_nlastrips_clear_metas(ListBase *strips, bool only_sel, bool only_temp);
+/**
+ * Split a meta-strip into a set of normal strips.
+ */
void BKE_nlastrips_clear_metastrip(ListBase *strips, struct NlaStrip *strip);
+/**
+ * Add the given NLA-Strip to the given Meta-Strip, assuming that the
+ * strip isn't attached to any list of strips
+ */
bool BKE_nlameta_add_strip(struct NlaStrip *mstrip, struct NlaStrip *strip);
+/**
+ * Adjust the settings of NLA-Strips contained within a Meta-Strip (recursively),
+ * until the Meta-Strips children all fit within the Meta-Strip's new dimensions
+ */
void BKE_nlameta_flush_transforms(struct NlaStrip *mstrip);
/* ............ */
+/**
+ * Find the active NLA-track for the given stack.
+ */
struct NlaTrack *BKE_nlatrack_find_active(ListBase *tracks);
+/**
+ * Make the given NLA-track the active one for the given stack. If no track is provided,
+ * this function can be used to simply deactivate all the NLA tracks in the given stack too.
+ */
void BKE_nlatrack_set_active(ListBase *tracks, struct NlaTrack *nlt);
+/**
+ * Get the NLA Track that the active action/action strip comes from,
+ * since this info is not stored in AnimData. It also isn't as simple
+ * as just using the active track, since multiple tracks may have been
+ * entered at the same time.
+ */
struct NlaTrack *BKE_nlatrack_find_tweaked(struct AnimData *adt);
+/**
+ * Toggle the 'solo' setting for the given NLA-track, making sure that it is the only one
+ * that has this status in its AnimData block.
+ */
void BKE_nlatrack_solo_toggle(struct AnimData *adt, struct NlaTrack *nlt);
+/**
+ * Check if there is any space in the given track to add a strip of the given length.
+ */
bool BKE_nlatrack_has_space(struct NlaTrack *nlt, float start, float end);
+/**
+ * Rearrange the strips in the track so that they are always in order
+ * (usually only needed after a strip has been moved).
+ */
void BKE_nlatrack_sort_strips(struct NlaTrack *nlt);
+/**
+ * Add the given NLA-Strip to the given NLA-Track, assuming that it
+ * isn't currently attached to another one.
+ */
bool BKE_nlatrack_add_strip(struct NlaTrack *nlt,
struct NlaStrip *strip,
const bool is_liboverride);
+/**
+ * Get the extents of the given NLA-Track including gaps between strips,
+ * returning whether this succeeded or not
+ */
bool BKE_nlatrack_get_bounds(struct NlaTrack *nlt, float bounds[2]);
-
+/**
+ * Check whether given NLA track is not local (i.e. from linked data) when the object is a library
+ * override.
+ *
+ * \param nlt: May be NULL, in which case we consider it as a non-local track case.
+ */
bool BKE_nlatrack_is_nonlocal_in_liboverride(const struct ID *id, const struct NlaTrack *nlt);
/* ............ */
+/**
+ * Find the active NLA-strip within the given track.
+ */
struct NlaStrip *BKE_nlastrip_find_active(struct NlaTrack *nlt);
+/**
+ * Make the given NLA-Strip the active one within the given block.
+ */
void BKE_nlastrip_set_active(struct AnimData *adt, struct NlaStrip *strip);
+/**
+ * Does the given NLA-strip fall within the given bounds (times)?.
+ */
bool BKE_nlastrip_within_bounds(struct NlaStrip *strip, float min, float max);
+/**
+ * Recalculate the start and end frames for the current strip, after changing
+ * the extents of the action or the mapping (repeats or scale factor) info.
+ */
void BKE_nlastrip_recalculate_bounds(struct NlaStrip *strip);
+/**
+ * Recalculate the start and end frames for the strip to match the bounds of its action such that
+ * the overall NLA animation result is unchanged.
+ */
void BKE_nlastrip_recalculate_bounds_sync_action(struct NlaStrip *strip);
+/**
+ * Find (and set) a unique name for a strip from the whole AnimData block
+ * Uses a similar method to the BLI method, but is implemented differently
+ * as we need to ensure that the name is unique over several lists of tracks,
+ * not just a single track.
+ */
void BKE_nlastrip_validate_name(struct AnimData *adt, struct NlaStrip *strip);
/* ............ */
+/**
+ * Check if the given NLA-Track has any strips with own F-Curves.
+ */
bool BKE_nlatrack_has_animated_strips(struct NlaTrack *nlt);
+/**
+ * Check if given NLA-Tracks have any strips with own F-Curves.
+ */
bool BKE_nlatracks_have_animated_strips(ListBase *tracks);
+/**
+ * Validate the NLA-Strips 'control' F-Curves based on the flags set.
+ */
void BKE_nlastrip_validate_fcurves(struct NlaStrip *strip);
+/**
+ * Check if the given RNA pointer + property combo should be handled by
+ * NLA strip curves or not.
+ */
bool BKE_nlastrip_has_curves_for_property(const struct PointerRNA *ptr,
const struct PropertyRNA *prop);
+/**
+ * Ensure that auto-blending and other settings are set correctly.
+ */
void BKE_nla_validate_state(struct AnimData *adt);
/* ............ */
+/**
+ * Check if an action is "stashed" in the NLA already
+ *
+ * The criteria for this are:
+ * 1) The action in question lives in a "stash" track.
+ * 2) We only check first-level strips. That is, we will not check inside meta strips.
+ */
bool BKE_nla_action_is_stashed(struct AnimData *adt, struct bAction *act);
+/**
+ * "Stash" an action (i.e. store it as a track/layer in the NLA, but non-contributing)
+ * to retain it in the file for future uses.
+ */
bool BKE_nla_action_stash(struct AnimData *adt, const bool is_liboverride);
/* ............ */
+/**
+ * For the given AnimData block, add the active action to the NLA
+ * stack (i.e. 'push-down' action). The UI should only allow this
+ * for normal editing only (i.e. not in edit-mode for some strip's action),
+ * so no checks for this are performed.
+ *
+ * TODO: maybe we should have checks for this too.
+ */
void BKE_nla_action_pushdown(struct AnimData *adt, const bool is_liboverride);
+/**
+ * Find the active strip + track combination, and set them up as the tweaking track,
+ * and return if successful or not.
+ */
bool BKE_nla_tweakmode_enter(struct AnimData *adt);
+/**
+ * Exit tweak-mode for this AnimData block.
+ */
void BKE_nla_tweakmode_exit(struct AnimData *adt);
/* ----------------------------- */
@@ -163,6 +348,13 @@ enum eNlaTime_ConvertModes {
NLATIME_CONVERT_MAP,
};
+/**
+ * Non clipped mapping for strip-time <-> global time:
+ * `mode = eNlaTime_ConvertModes -> NLATIME_CONVERT_*`
+ *
+ * Public API method - perform this mapping using the given AnimData block
+ * and perform any necessary sanity checks on the value
+ */
float BKE_nla_tweakedit_remap(struct AnimData *adt, float cframe, short mode);
/* ----------------------------- */
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index bbeb01de0ff..a2959556810 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -34,6 +34,10 @@
#include "RNA_types.h"
#ifdef __cplusplus
+# include "BLI_string_ref.hh"
+#endif
+
+#ifdef __cplusplus
extern "C" {
#endif
@@ -114,6 +118,7 @@ namespace nodes {
class NodeMultiFunctionBuilder;
class GeoNodeExecParams;
class NodeDeclarationBuilder;
+class GatherLinkSearchOpParams;
} // namespace nodes
namespace fn {
class CPPType;
@@ -121,23 +126,28 @@ class MFDataType;
} // namespace fn
} // namespace blender
+using CPPTypeHandle = blender::fn::CPPType;
using NodeMultiFunctionBuildFunction = void (*)(blender::nodes::NodeMultiFunctionBuilder &builder);
using NodeGeometryExecFunction = void (*)(blender::nodes::GeoNodeExecParams params);
using NodeDeclareFunction = void (*)(blender::nodes::NodeDeclarationBuilder &builder);
-using SocketGetCPPTypeFunction = const blender::fn::CPPType *(*)();
using SocketGetCPPValueFunction = void (*)(const struct bNodeSocket &socket, void *r_value);
-using SocketGetGeometryNodesCPPTypeFunction = const blender::fn::CPPType *(*)();
using SocketGetGeometryNodesCPPValueFunction = void (*)(const struct bNodeSocket &socket,
void *r_value);
+/* Adds socket link operations that are specific to this node type. */
+using NodeGatherSocketLinkOperationsFunction =
+ void (*)(blender::nodes::GatherLinkSearchOpParams &params);
+
#else
typedef void *NodeMultiFunctionBuildFunction;
typedef void *NodeGeometryExecFunction;
typedef void *NodeDeclareFunction;
+typedef void *NodeGatherSocketLinkOperationsFunction;
typedef void *SocketGetCPPTypeFunction;
typedef void *SocketGetGeometryNodesCPPTypeFunction;
typedef void *SocketGetGeometryNodesCPPValueFunction;
typedef void *SocketGetCPPValueFunction;
+typedef struct CPPTypeHandle CPPTypeHandle;
#endif
/**
@@ -164,20 +174,20 @@ typedef struct bNodeSocketType {
void (*interface_draw)(struct bContext *C, struct uiLayout *layout, struct PointerRNA *ptr);
void (*interface_draw_color)(struct bContext *C, struct PointerRNA *ptr, float *r_color);
void (*interface_register_properties)(struct bNodeTree *ntree,
- struct bNodeSocket *stemp,
+ struct bNodeSocket *interface_socket,
struct StructRNA *data_srna);
void (*interface_init_socket)(struct bNodeTree *ntree,
- struct bNodeSocket *stemp,
+ const struct bNodeSocket *interface_socket,
struct bNode *node,
struct bNodeSocket *sock,
const char *data_path);
void (*interface_verify_socket)(struct bNodeTree *ntree,
- struct bNodeSocket *stemp,
+ const struct bNodeSocket *interface_socket,
struct bNode *node,
struct bNodeSocket *sock,
const char *data_path);
void (*interface_from_socket)(struct bNodeTree *ntree,
- struct bNodeSocket *stemp,
+ struct bNodeSocket *interface_socket,
struct bNode *node,
struct bNodeSocket *sock);
@@ -197,11 +207,11 @@ typedef struct bNodeSocketType {
void (*free_self)(struct bNodeSocketType *stype);
/* Return the CPPType of this socket. */
- SocketGetCPPTypeFunction get_base_cpp_type;
+ const CPPTypeHandle *base_cpp_type;
/* Get the value of this socket in a generic way. */
SocketGetCPPValueFunction get_base_cpp_value;
/* Get geometry nodes cpp type. */
- SocketGetGeometryNodesCPPTypeFunction get_geometry_nodes_cpp_type;
+ const CPPTypeHandle *geometry_nodes_cpp_type;
/* Get geometry nodes cpp value. */
SocketGetGeometryNodesCPPValueFunction get_geometry_nodes_cpp_value;
} bNodeSocketType;
@@ -229,8 +239,6 @@ typedef int (*NodeGPUExecFunction)(struct GPUMaterial *mat,
* implementing the node behavior.
*/
typedef struct bNodeType {
- void *next, *prev;
-
char idname[64]; /* identifier name */
int type;
@@ -247,18 +255,6 @@ typedef struct bNodeType {
char storagename[64]; /* struct name for DNA */
- /* Main draw function for the node */
- void (*draw_nodetype)(const struct bContext *C,
- struct ARegion *region,
- struct SpaceNode *snode,
- struct bNodeTree *ntree,
- struct bNode *node,
- bNodeInstanceKey key);
- /* Updates the node geometry attributes according to internal state before actual drawing */
- void (*draw_nodetype_prepare)(const struct bContext *C,
- struct bNodeTree *ntree,
- struct bNode *node);
-
/* Draw the option buttons on the node */
void (*draw_buttons)(struct uiLayout *, struct bContext *C, struct PointerRNA *ptr);
/* Additional parameters in the side panel */
@@ -272,13 +268,10 @@ typedef struct bNodeType {
* Optional custom label function for the node header.
* \note Used as a fallback when #bNode.label isn't set.
*/
- void (*labelfunc)(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen);
- /** Optional custom resize handle polling. */
- int (*resize_area_func)(struct bNode *node, int x, int y);
- /** Optional selection area polling. */
- int (*select_area_func)(struct bNode *node, int x, int y);
- /** Optional tweak area polling (for grabbing). */
- int (*tweak_area_func)(struct bNode *node, int x, int y);
+ void (*labelfunc)(const struct bNodeTree *ntree,
+ const struct bNode *node,
+ char *label,
+ int maxlen);
/** Called when the node is updated in the editor. */
void (*updatefunc)(struct bNodeTree *ntree, struct bNode *node);
@@ -301,7 +294,7 @@ typedef struct bNodeType {
/**
* Can this node type be added to a node tree?
- * \param r_disabled_hint: Optional hint to display in the UI when the poll fails.
+ * \param r_disabled_hint: Hint to display in the UI when the poll fails.
* The callback can set this to a static string without having to
* null-check it (or without setting it to null if it's not used).
* The caller must pass a valid `const char **` and null-initialize it
@@ -342,6 +335,13 @@ typedef struct bNodeType {
/* Declaration to be used when it is not dynamic. */
NodeDeclarationHandle *fixed_declaration;
+ /**
+ * Add to the list of search names and operations gathered by node link drag searching.
+ * Usually it isn't necessary to override the default behavior here, but a node type can have
+ * custom behavior here like adding custom search items.
+ */
+ NodeGatherSocketLinkOperationsFunction gather_link_search_ops;
+
/** True when the node cannot be muted. */
bool no_muting;
@@ -379,12 +379,6 @@ typedef struct bNodeType {
#define NODE_CLASS_ATTRIBUTE 42
#define NODE_CLASS_LAYOUT 100
-/* node resize directions */
-#define NODE_RESIZE_TOP 1
-#define NODE_RESIZE_BOTTOM 2
-#define NODE_RESIZE_RIGHT 4
-#define NODE_RESIZE_LEFT 8
-
typedef enum eNodeSizePreset {
NODE_SIZE_DEFAULT,
NODE_SIZE_SMALL,
@@ -425,7 +419,7 @@ typedef struct bNodeTreeType {
/* Tree update. Overrides `nodetype->updatetreefunc` ! */
void (*update)(struct bNodeTree *ntree);
- bool (*validate_link)(struct bNodeTree *ntree, struct bNodeLink *link);
+ bool (*validate_link)(eNodeSocketDatatype from, eNodeSocketDatatype to);
void (*node_add_init)(struct bNodeTree *ntree, struct bNode *bnode);
@@ -462,20 +456,44 @@ struct GHashIterator *ntreeTypeGetIterator(void);
} \
(void)0
+/**
+ * Try to initialize all type-info in a node tree.
+ *
+ * \note In general undefined type-info is a perfectly valid case,
+ * the type may just be registered later.
+ * In that case the update_typeinfo function will set type-info on registration
+ * and do necessary updates.
+ */
void ntreeSetTypes(const struct bContext *C, struct bNodeTree *ntree);
struct bNodeTree *ntreeAddTree(struct Main *bmain, const char *name, const char *idname);
/* copy/free funcs, need to manage ID users */
+
+/**
+ * Free (or release) any data used by this node-tree.
+ * Does not free the node-tree itself and does no ID user counting.
+ */
void ntreeFreeTree(struct bNodeTree *ntree);
-/* Free tree which is embedded into another datablock. */
+/**
+ * Free tree which is embedded into another data-block.
+ */
void ntreeFreeEmbeddedTree(struct bNodeTree *ntree);
struct bNodeTree *ntreeCopyTree_ex(const struct bNodeTree *ntree,
struct Main *bmain,
const bool do_id_user);
struct bNodeTree *ntreeCopyTree(struct Main *bmain, const struct bNodeTree *ntree);
+/**
+ * Get address of potential node-tree pointer of given ID.
+ *
+ * \warning Using this function directly is potentially dangerous, if you don't know or are not
+ * sure, please use `ntreeFromID()` instead.
+ */
struct bNodeTree **BKE_ntree_ptr_from_id(struct ID *id);
+/**
+ * Returns the private NodeTree object of the data-block, if it has one.
+ */
struct bNodeTree *ntreeFromID(struct ID *id);
void ntreeFreeLocalNode(struct bNodeTree *ntree, struct bNode *node);
@@ -485,13 +503,17 @@ bool ntreeHasType(const struct bNodeTree *ntree, int type);
bool ntreeHasTree(const struct bNodeTree *ntree, const struct bNodeTree *lookup);
void ntreeUpdateTree(struct Main *main, struct bNodeTree *ntree);
void ntreeUpdateAllNew(struct Main *main);
+/**
+ * \param tree_update_flag: #eNodeTreeUpdate enum.
+ */
void ntreeUpdateAllUsers(struct Main *main, struct ID *id, int tree_update_flag);
void ntreeGetDependencyList(struct bNodeTree *ntree,
struct bNode ***r_deplist,
int *r_deplist_len);
-/* XXX old trees handle output flags automatically based on special output
+/**
+ * XXX: old trees handle output flags automatically based on special output
* node types and last active selection.
* New tree types have a per-output socket flag to indicate the final output to use explicitly.
*/
@@ -502,11 +524,31 @@ void ntreeFreeCache(struct bNodeTree *ntree);
bool ntreeNodeExists(const struct bNodeTree *ntree, const struct bNode *testnode);
bool ntreeOutputExists(const struct bNode *node, const struct bNodeSocket *testsock);
void ntreeNodeFlagSet(const bNodeTree *ntree, const int flag, const bool enable);
+/**
+ * Returns localized tree for execution in threads.
+ */
struct bNodeTree *ntreeLocalize(struct bNodeTree *ntree);
+/**
+ * Sync local composite with real tree.
+ * The local tree is supposed to be running, be careful moving previews!
+ *
+ * Is called by jobs manager, outside threads, so it doesn't happen during draw.
+ */
void ntreeLocalSync(struct bNodeTree *localtree, struct bNodeTree *ntree);
+/**
+ * Merge local tree results back, and free local tree.
+ *
+ * We have to assume the editor already changed completely.
+ */
void ntreeLocalMerge(struct Main *bmain, struct bNodeTree *localtree, struct bNodeTree *ntree);
+/**
+ * This is only direct data, tree itself should have been written.
+ */
void ntreeBlendWrite(struct BlendWriter *writer, struct bNodeTree *ntree);
+/**
+ * \note `ntree` itself has been read!
+ */
void ntreeBlendReadData(struct BlendDataReader *reader, struct bNodeTree *ntree);
void ntreeBlendReadLib(struct BlendLibReader *reader, struct bNodeTree *ntree);
void ntreeBlendReadExpand(struct BlendExpander *expander, struct bNodeTree *ntree);
@@ -516,6 +558,7 @@ void ntreeBlendReadExpand(struct BlendExpander *expander, struct bNodeTree *ntre
/* -------------------------------------------------------------------- */
/** \name Node Tree Interface
* \{ */
+
struct bNodeSocket *ntreeFindSocketInterface(struct bNodeTree *ntree,
eNodeSocketInOut in_out,
const char *identifier);
@@ -550,7 +593,7 @@ void ntreeInterfaceTypeUpdate(struct bNodeTree *ntree);
struct bNodeType *nodeTypeFind(const char *idname);
void nodeRegisterType(struct bNodeType *ntype);
void nodeUnregisterType(struct bNodeType *ntype);
-bool nodeTypeUndefined(struct bNode *node);
+bool nodeTypeUndefined(const struct bNode *node);
struct GHashIterator *nodeTypeGetIterator(void);
/* Helper macros for iterating over node types. */
@@ -640,27 +683,42 @@ void nodeModifySocketTypeStatic(
struct bNode *nodeAddNode(const struct bContext *C, struct bNodeTree *ntree, const char *idname);
struct bNode *nodeAddStaticNode(const struct bContext *C, struct bNodeTree *ntree, int type);
+/**
+ * \note Goes over entire tree.
+ */
void nodeUnlinkNode(struct bNodeTree *ntree, struct bNode *node);
+/**
+ * Find the first available, non-duplicate name for a given node.
+ */
void nodeUniqueName(struct bNodeTree *ntree, struct bNode *node);
-/* Delete node, associated animation data and ID user count. */
+/**
+ * Delete node, associated animation data and ID user count.
+ */
void nodeRemoveNode(struct Main *bmain,
struct bNodeTree *ntree,
struct bNode *node,
bool do_id_user);
+/**
+ * \param ntree: is the target tree.
+ *
+ * \note keep socket list order identical, for copying links.
+ * \note `unique_name` needs to be true. It's only disabled for speed when doing GPUnodetrees.
+ */
struct bNode *BKE_node_copy_ex(struct bNodeTree *ntree,
const struct bNode *node_src,
const int flag,
const bool unique_name);
-/* Same as BKE_node_copy_ex() but stores pointers to a new node and its sockets in the source
- * node.
+/**
+ * Same as #BKE_node_copy_ex but stores pointers to a new node and its sockets in the source node.
*
* NOTE: DANGER ZONE!
*
* TODO(sergey): Maybe it's better to make BKE_node_copy_ex() return a mapping from old node and
- * sockets to new one. */
+ * sockets to new one.
+ */
struct bNode *BKE_node_copy_store_new_pointers(struct bNodeTree *ntree,
struct bNode *node_src,
const int flag);
@@ -668,6 +726,9 @@ struct bNodeTree *ntreeCopyTree_ex_new_pointers(const struct bNodeTree *ntree,
struct Main *bmain,
const bool do_id_user);
+/**
+ * Also used via RNA API, so we check for proper input output direction.
+ */
struct bNodeLink *nodeAddLink(struct bNodeTree *ntree,
struct bNode *fromnode,
struct bNodeSocket *fromsock,
@@ -691,25 +752,62 @@ void nodePositionRelative(struct bNode *from_node,
struct bNodeSocket *to_sock);
void nodePositionPropagate(struct bNode *node);
+/**
+ * Finds a node based on its name.
+ */
struct bNode *nodeFindNodebyName(struct bNodeTree *ntree, const char *name);
+/**
+ * Finds a node based on given socket and returns true on success.
+ */
bool nodeFindNode(struct bNodeTree *ntree,
struct bNodeSocket *sock,
struct bNode **r_node,
int *r_sockindex);
+/**
+ * \note Recursive.
+ */
struct bNode *nodeFindRootParent(bNode *node);
+/**
+ * \returns true if \a child has \a parent as a parent/grandparent/... etc.
+ * \note Recursive
+ */
bool nodeIsChildOf(const bNode *parent, const bNode *child);
+/**
+ * Iterate over a chain of nodes, starting with \a node_start, executing
+ * \a callback for each node (which can return false to end iterator).
+ *
+ * \param reversed: for backwards iteration
+ * \note Recursive
+ */
void nodeChainIter(const bNodeTree *ntree,
const bNode *node_start,
bool (*callback)(bNode *, bNode *, void *, const bool),
void *userdata,
const bool reversed);
+/**
+ * Iterate over a chain of nodes, starting with \a node_start, executing
+ * \a callback for each node (which can return false to end iterator).
+ *
+ * Faster than nodeChainIter. Iter only once per node.
+ * Can be called recursively (using another nodeChainIterBackwards) by
+ * setting the recursion_lvl accordingly.
+ *
+ * \note Needs updated socket links (ntreeUpdateTree).
+ * \note Recursive
+ */
void nodeChainIterBackwards(const bNodeTree *ntree,
const bNode *node_start,
bool (*callback)(bNode *, bNode *, void *),
void *userdata,
int recursion_lvl);
+/**
+ * Iterate over all parents of \a node, executing \a callback for each parent
+ * (which can return false to end iterator)
+ *
+ * \note Recursive
+ */
void nodeParentsIter(bNode *node, bool (*callback)(bNode *, void *), void *userdata);
struct bNodeLink *nodeFindLink(struct bNodeTree *ntree,
@@ -718,11 +816,20 @@ struct bNodeLink *nodeFindLink(struct bNodeTree *ntree,
int nodeCountSocketLinks(const struct bNodeTree *ntree, const struct bNodeSocket *sock);
void nodeSetSelected(struct bNode *node, bool select);
+/**
+ * Two active flags, ID nodes have special flag for buttons display.
+ */
void nodeSetActive(struct bNodeTree *ntree, struct bNode *node);
struct bNode *nodeGetActive(struct bNodeTree *ntree);
+/**
+ * Two active flags, ID nodes have special flag for buttons display.
+ */
struct bNode *nodeGetActiveID(struct bNodeTree *ntree, short idtype);
bool nodeSetActiveID(struct bNodeTree *ntree, short idtype, struct ID *id);
void nodeClearActive(struct bNodeTree *ntree);
+/**
+ * Two active flags, ID nodes have special flag for buttons display.
+ */
void nodeClearActiveID(struct bNodeTree *ntree, short idtype);
struct bNode *nodeGetActiveTexture(struct bNodeTree *ntree);
@@ -738,14 +845,31 @@ void nodeSetSocketAvailability(struct bNodeTree *ntree,
int nodeSocketLinkLimit(const struct bNodeSocket *sock);
+/**
+ * If the node implements a `declare` function, this function makes sure that `node->declaration`
+ * is up to date. It is expected that the sockets of the node are up to date already.
+ */
bool nodeDeclarationEnsure(struct bNodeTree *ntree, struct bNode *node);
+/**
+ * Just update `node->declaration` if necessary. This can also be called on nodes that may not be
+ * up to date (e.g. because the need versioning or are dynamic).
+ */
bool nodeDeclarationEnsureOnOutdatedNode(struct bNodeTree *ntree, struct bNode *node);
+/**
+ * Update `socket->declaration` for all sockets in the node. This assumes that the node declaration
+ * and sockets are up to date already.
+ */
void nodeSocketDeclarationsUpdate(struct bNode *node);
-/* Node Clipboard */
+/**
+ * Node Clipboard.
+ */
void BKE_node_clipboard_init(const struct bNodeTree *ntree);
void BKE_node_clipboard_clear(void);
void BKE_node_clipboard_free(void);
+/**
+ * Return false when one or more ID's are lost.
+ */
bool BKE_node_clipboard_validate(void);
void BKE_node_clipboard_add_node(struct bNode *node);
void BKE_node_clipboard_add_link(struct bNodeLink *link);
@@ -753,7 +877,9 @@ const struct ListBase *BKE_node_clipboard_get_nodes(void);
const struct ListBase *BKE_node_clipboard_get_links(void);
int BKE_node_clipboard_get_type(void);
-/* Node Instance Hash */
+/**
+ * Node Instance Hash.
+ */
typedef struct bNodeInstanceHash {
/** XXX should be made a direct member, #GHash allocation needs to support it */
GHash *ghash;
@@ -761,6 +887,9 @@ typedef struct bNodeInstanceHash {
typedef void (*bNodeInstanceValueFP)(void *value);
+/**
+ * Magic number for initial hash key.
+ */
extern const bNodeInstanceKey NODE_INSTANCE_KEY_BASE;
extern const bNodeInstanceKey NODE_INSTANCE_KEY_NONE;
@@ -845,6 +974,11 @@ void BKE_node_preview_merge_tree(struct bNodeTree *to_ntree,
struct bNodeTree *from_ntree,
bool remove_old);
+/**
+ * Hack warning! this function is only used for shader previews,
+ * and since it gets called multiple times per pixel for Z-transparency we only add the color once.
+ * Preview gets cleared before it starts render though.
+ */
void BKE_node_preview_set_pixel(
struct bNodePreview *preview, const float col[4], int x, int y, bool do_manage);
@@ -854,14 +988,19 @@ void BKE_node_preview_set_pixel(
/** \name Node Type Access
* \{ */
-void nodeLabel(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen);
+void nodeLabel(const struct bNodeTree *ntree, const struct bNode *node, char *label, int maxlen);
+/**
+ * Get node socket label if it is set.
+ */
const char *nodeSocketLabel(const struct bNodeSocket *sock);
bool nodeGroupPoll(struct bNodeTree *nodetree,
struct bNodeTree *grouptree,
const char **r_disabled_hint);
-/* Init a new node type struct with default values and callbacks */
+/**
+ * Initialize a new node type struct with default values and callbacks.
+ */
void node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass, short flag);
void node_type_base_custom(
struct bNodeType *ntype, const char *idname, const char *name, short nclass, short flag);
@@ -872,15 +1011,16 @@ void node_type_size(struct bNodeType *ntype, int width, int minwidth, int maxwid
void node_type_size_preset(struct bNodeType *ntype, eNodeSizePreset size);
void node_type_init(struct bNodeType *ntype,
void (*initfunc)(struct bNodeTree *ntree, struct bNode *node));
+/**
+ * \warning Nodes defining a storage type _must_ allocate this for new nodes.
+ * Otherwise nodes will reload as undefined (T46619).
+ */
void node_type_storage(struct bNodeType *ntype,
const char *storagename,
void (*freefunc)(struct bNode *node),
void (*copyfunc)(struct bNodeTree *dest_ntree,
struct bNode *dest_node,
const struct bNode *src_node));
-void node_type_label(
- struct bNodeType *ntype,
- void (*labelfunc)(struct bNodeTree *ntree, struct bNode *, char *label, int maxlen));
void node_type_update(struct bNodeType *ntype,
void (*updatefunc)(struct bNodeTree *ntree, struct bNode *node));
void node_type_group_update(struct bNodeType *ntype,
@@ -986,6 +1126,7 @@ bool BKE_node_tree_iter_step(struct NodeTreeIterStore *ntreeiter,
} \
} \
((void)0)
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1121,8 +1262,21 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree,
struct bNodeTreeExec *ntreeShaderBeginExecTree(struct bNodeTree *ntree);
void ntreeShaderEndExecTree(struct bNodeTreeExec *exec);
+/**
+ Find an output node of the shader tree.
+ *
+ * \note it will only return output which is NOT in the group, which isn't how
+ * render engines works but it's how the GPU shader compilation works. This we
+ * can change in the future and make it a generic function, but for now it stays
+ * private here.
+ */
struct bNode *ntreeShaderOutputNode(struct bNodeTree *ntree, int target);
-
+/**
+ * This one needs to work on a local tree.
+ *
+ * TODO: This is *not* part of `blenkernel`, it's defined under "source/blender/nodes/".
+ * This declaration should be moved out of BKE.
+ */
void ntreeGPUMaterialNodes(struct bNodeTree *localtree,
struct GPUMaterial *mat,
bool *has_surface_output,
@@ -1314,7 +1468,25 @@ void ntreeCompositExecTree(struct Scene *scene,
const struct ColorManagedViewSettings *view_settings,
const struct ColorManagedDisplaySettings *display_settings,
const char *view_name);
+
+/**
+ * Called from render pipeline, to tag render input and output.
+ * need to do all scenes, to prevent errors when you re-render 1 scene.
+ */
void ntreeCompositTagRender(struct Scene *scene);
+/**
+ * Update the outputs of the render layer nodes.
+ * Since the outputs depend on the render engine, this part is a bit complex:
+ * - #ntreeCompositUpdateRLayers is called and loops over all render layer nodes.
+ * - Each render layer node calls the update function of the
+ * render engine that's used for its scene.
+ * - The render engine calls RE_engine_register_pass for each pass.
+ * - #RE_engine_register_pass calls #ntreeCompositRegisterPass,
+ * which calls #node_cmp_rlayers_register_pass for every render layer node.
+ *
+ * TODO: This is *not* part of `blenkernel`, it's defined under "source/blender/nodes/".
+ * This declaration should be moved out of BKE.
+ */
void ntreeCompositUpdateRLayers(struct bNodeTree *ntree);
void ntreeCompositRegisterPass(struct bNodeTree *ntree,
struct Scene *scene,
@@ -1355,8 +1527,10 @@ void ntreeCompositCryptomatteLayerPrefix(const Scene *scene,
const bNode *node,
char *r_prefix,
size_t prefix_len);
-/* Update the runtime layer names with the crypto-matte layer names of the references
- * render layer or image. */
+/**
+ * Update the runtime layer names with the crypto-matte layer names of the references render layer
+ * or image.
+ */
void ntreeCompositCryptomatteUpdateLayerNames(const Scene *scene, bNode *node);
struct CryptomatteSession *ntreeCompositCryptomatteSession(const Scene *scene, bNode *node);
@@ -1413,6 +1587,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
int cfra,
int preview,
struct MTex *mtex);
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1507,7 +1682,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
#define GEO_NODE_SAMPLE_CURVE 1085
#define GEO_NODE_INPUT_TANGENT 1086
#define GEO_NODE_STRING_JOIN 1087
-#define GEO_NODE_CURVE_PARAMETER 1088
+#define GEO_NODE_CURVE_SPLINE_PARAMETER 1088
#define GEO_NODE_FILLET_CURVE 1089
#define GEO_NODE_DISTRIBUTE_POINTS_ON_FACES 1090
#define GEO_NODE_STRING_TO_CURVES 1091
@@ -1554,6 +1729,16 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
#define GEO_NODE_VOLUME_TO_MESH 1133
#define GEO_NODE_INPUT_ID 1134
#define GEO_NODE_SET_ID 1135
+#define GEO_NODE_ATTRIBUTE_DOMAIN_SIZE 1136
+#define GEO_NODE_DUAL_MESH 1137
+#define GEO_NODE_INPUT_MESH_EDGE_VERTICES 1138
+#define GEO_NODE_INPUT_MESH_FACE_AREA 1139
+#define GEO_NODE_INPUT_MESH_FACE_NEIGHBORS 1140
+#define GEO_NODE_INPUT_MESH_VERTEX_NEIGHBORS 1141
+#define GEO_NODE_GEOMETRY_TO_INSTANCE 1142
+#define GEO_NODE_INPUT_MESH_EDGE_NEIGHBORS 1143
+#define GEO_NODE_INPUT_MESH_ISLAND 1144
+#define GEO_NODE_INPUT_SCENE_TIME 1145
/** \} */
@@ -1562,7 +1747,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
* \{ */
#define FN_NODE_BOOLEAN_MATH 1200
-#define FN_NODE_COMPARE_FLOATS 1202
+#define FN_NODE_COMPARE 1202
#define FN_NODE_LEGACY_RANDOM_FLOAT 1206
#define FN_NODE_INPUT_VECTOR 1207
#define FN_NODE_INPUT_STRING 1208
@@ -1599,3 +1784,25 @@ extern struct bNodeSocketType NodeSocketTypeUndefined;
#ifdef __cplusplus
}
#endif
+
+#ifdef __cplusplus
+
+namespace blender::bke {
+
+bNodeSocket *node_find_enabled_socket(bNode &node, eNodeSocketInOut in_out, StringRef name);
+bNodeSocket *node_find_enabled_input_socket(bNode &node, StringRef name);
+bNodeSocket *node_find_enabled_output_socket(bNode &node, StringRef name);
+
+} // namespace blender::bke
+
+#endif
+
+#define NODE_STORAGE_FUNCS(StorageT) \
+ [[maybe_unused]] static StorageT &node_storage(bNode &node) \
+ { \
+ return *static_cast<StorageT *>(node.storage); \
+ } \
+ [[maybe_unused]] static const StorageT &node_storage(const bNode &node) \
+ { \
+ return *static_cast<const StorageT *>(node.storage); \
+ }
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index 4e53af5562f..03565bd3bda 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -52,6 +52,14 @@ struct View3D;
struct ViewLayer;
void BKE_object_workob_clear(struct Object *workob);
+/**
+ * For calculation of the inverse parent transform, only used for editor.
+ *
+ * It assumes the object parent is already in the depsgraph.
+ * Otherwise, after changing ob->parent you need to call:
+ * - #DEG_relations_tag_update(bmain);
+ * - #BKE_scene_graph_update_tagged(depsgraph, bmain);
+ */
void BKE_object_workob_calc_parent(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
@@ -67,6 +75,9 @@ void BKE_object_free_particlesystems(struct Object *ob);
void BKE_object_free_softbody(struct Object *ob);
void BKE_object_free_curve_cache(struct Object *ob);
+/**
+ * Free data derived from mesh, called when mesh changes or is freed.
+ */
void BKE_object_free_derived_caches(struct Object *ob);
void BKE_object_free_caches(struct Object *object);
@@ -77,19 +88,55 @@ bool BKE_object_modifier_gpencil_use_time(struct Object *ob, struct GpencilModif
bool BKE_object_shaderfx_use_time(struct Object *ob, struct ShaderFxData *fx);
+/**
+ * \return True if the object's type supports regular modifiers (not grease pencil modifiers).
+ */
bool BKE_object_supports_modifiers(const struct Object *ob);
bool BKE_object_support_modifier_type_check(const struct Object *ob, int modifier_type);
/* Active modifier. */
+
+/**
+ * Set the object's active modifier.
+ *
+ * \param md: If nullptr, only clear the active modifier, otherwise
+ * it must be in the #Object.modifiers list.
+ */
void BKE_object_modifier_set_active(struct Object *ob, struct ModifierData *md);
struct ModifierData *BKE_object_active_modifier(const struct Object *ob);
+/**
+ * Copy a single modifier.
+ *
+ * \note *Do not* use this function to copy a whole modifier stack (see note below too). Use
+ * `BKE_object_modifier_stack_copy` instead.
+ *
+ * \note Complex modifiers relaying on other data (like e.g. dynamic paint or fluid using particle
+ * systems) are not always 100% 'correctly' copied here, since we have to use heuristics to decide
+ * which particle system to use or add in `ob_dst`, and it's placement in the stack, etc. If used
+ * more than once, this function should preferably be called in stack order.
+ */
bool BKE_object_copy_modifier(struct Main *bmain,
struct Scene *scene,
struct Object *ob_dst,
const struct Object *ob_src,
struct ModifierData *md);
+/**
+ * Copy a single GPencil modifier.
+ *
+ * \note *Do not* use this function to copy a whole modifier stack. Use
+ * `BKE_object_modifier_stack_copy` instead.
+ */
bool BKE_object_copy_gpencil_modifier(struct Object *ob_dst, struct GpencilModifierData *gmd_src);
+/**
+ * Copy the whole stack of modifiers from one object into another.
+ *
+ * \warning *Does not* clear modifier stack and related data (particle systems, soft-body,
+ * etc.) in `ob_dst`, if needed calling code must do it.
+ *
+ * \param do_copy_all: If true, even modifiers that should not support copying (like Hook one)
+ * will be duplicated.
+ */
bool BKE_object_modifier_stack_copy(struct Object *ob_dst,
const struct Object *ob_src,
const bool do_copy_all,
@@ -98,6 +145,12 @@ void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_sr
void BKE_object_free_modifiers(struct Object *ob, const int flag);
void BKE_object_free_shaderfx(struct Object *ob, const int flag);
+/**
+ * Proxy rule:
+ * - `lib_object->proxy_from` == the one we borrow from, set temporally while object_update.
+ * - `local_object->proxy` == pointer to library object, saved in files and read.
+ * - `local_object->proxy_group` == pointer to collection dupli-object, saved in files and read.
+ */
void BKE_object_make_proxy(struct Main *bmain,
struct Object *ob,
struct Object *target,
@@ -105,6 +158,9 @@ void BKE_object_make_proxy(struct Main *bmain,
void BKE_object_copy_proxy_drivers(struct Object *ob, struct Object *target);
bool BKE_object_exists_check(struct Main *bmain, const struct Object *obtest);
+/**
+ * Actual check for internal data, not context or flags.
+ */
bool BKE_object_is_in_editmode(const struct Object *ob);
bool BKE_object_is_in_editmode_vgroup(const struct Object *ob);
bool BKE_object_is_in_wpaint_select_vert(const struct Object *ob);
@@ -115,6 +171,9 @@ bool BKE_object_data_is_in_editmode(const struct ID *id);
char *BKE_object_data_editmode_flush_ptr_get(struct ID *id);
+/**
+ * Updates select_id of all objects in the given \a bmain.
+ */
void BKE_object_update_select_id(struct Main *bmain);
typedef enum eObjectVisibilityResult {
@@ -124,14 +183,33 @@ typedef enum eObjectVisibilityResult {
OB_VISIBLE_ALL = (OB_VISIBLE_SELF | OB_VISIBLE_PARTICLES | OB_VISIBLE_INSTANCES),
} eObjectVisibilityResult;
+/**
+ * Return which parts of the object are visible, as evaluated by depsgraph.
+ */
int BKE_object_visibility(const struct Object *ob, const int dag_eval_mode);
+/**
+ * More general add: creates minimum required data, but without vertices etc.
+ */
struct Object *BKE_object_add_only_object(struct Main *bmain, int type, const char *name)
ATTR_NONNULL(1) ATTR_RETURNS_NONNULL;
+/**
+ * General add: to scene, with layer from area and default name.
+ *
+ * Object is added to the active #Collection.
+ * If there is no linked collection to the active #ViewLayer we create a new one.
+ *
+ * \note Creates minimum required data, but without vertices etc.
+ */
struct Object *BKE_object_add(struct Main *bmain,
struct ViewLayer *view_layer,
int type,
const char *name) ATTR_NONNULL(1, 2) ATTR_RETURNS_NONNULL;
+/**
+ * Add a new object, using another one as a reference
+ *
+ * \param ob_src: object to use to determine the collections of the new object.
+ */
struct Object *BKE_object_add_from(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,
@@ -139,6 +217,15 @@ struct Object *BKE_object_add_from(struct Main *bmain,
const char *name,
struct Object *ob_src)
ATTR_NONNULL(1, 2, 3, 6) ATTR_RETURNS_NONNULL;
+/**
+ * Add a new object, but assign the given data-block as the `ob->data`
+ * for the newly created object.
+ *
+ * \param data: The data-block to assign as `ob->data` for the new object.
+ * This is assumed to be of the correct type.
+ * \param do_id_user: If true, #id_us_plus() will be called on data when
+ * assigning it to the object.
+ */
struct Object *BKE_object_add_for_data(struct Main *bmain,
struct ViewLayer *view_layer,
int type,
@@ -147,16 +234,39 @@ struct Object *BKE_object_add_for_data(struct Main *bmain,
bool do_id_user) ATTR_RETURNS_NONNULL;
void *BKE_object_obdata_add_from_type(struct Main *bmain, int type, const char *name)
ATTR_NONNULL(1);
+/**
+ * Return -1 on failure.
+ */
int BKE_object_obdata_to_type(const struct ID *id) ATTR_NONNULL(1);
+/**
+ * Returns true if the Object is from an external blend file (libdata).
+ */
bool BKE_object_is_libdata(const struct Object *ob);
+/**
+ * Returns true if the Object data is from an external blend file (libdata).
+ */
bool BKE_object_obdata_is_libdata(const struct Object *ob);
+/**
+ * Perform deep-copy of object and its 'children' data-blocks (obdata, materials, actions, etc.).
+ *
+ * \param dupflag: Controls which sub-data are also duplicated
+ * (see #eDupli_ID_Flags in DNA_userdef_types.h).
+ *
+ * \note This function does not do any remapping to new IDs, caller must do it
+ * (\a #BKE_libblock_relink_to_newid()).
+ * \note Caller MUST free \a newid pointers itself (#BKE_main_id_newptr_and_tag_clear()) and call
+ * updates of DEG too (#DAG_relations_tag_update()).
+ */
struct Object *BKE_object_duplicate(struct Main *bmain,
struct Object *ob,
uint dupflag,
uint duplicate_options);
+/**
+ * Use with newly created objects to set their size (used to apply scene-scale).
+ */
void BKE_object_obdata_size_init(struct Object *ob, const float size);
void BKE_object_scale_to_mat3(struct Object *ob, float r_mat[3][3]);
@@ -164,15 +274,26 @@ void BKE_object_rot_to_mat3(const struct Object *ob, float r_mat[3][3], bool use
void BKE_object_mat3_to_rot(struct Object *ob, float r_mat[3][3], bool use_compat);
void BKE_object_to_mat3(struct Object *ob, float r_mat[3][3]);
void BKE_object_to_mat4(struct Object *ob, float r_mat[4][4]);
-void BKE_object_apply_mat4(struct Object *ob,
- const float mat[4][4],
- const bool use_compat,
- const bool use_parent);
+/**
+ * Applies the global transformation \a mat to the \a ob using a relative parent space if
+ * supplied.
+ *
+ * \param mat: the global transformation mat that the object should be set object to.
+ * \param parent: the parent space in which this object will be set relative to
+ * (should probably always be parent_eval).
+ * \param use_compat: true to ensure that rotations are set using the
+ * min difference between the old and new orientation.
+ */
void BKE_object_apply_mat4_ex(struct Object *ob,
const float mat[4][4],
struct Object *parent,
const float parentinv[4][4],
const bool use_compat);
+/** See #BKE_object_apply_mat4_ex */
+void BKE_object_apply_mat4(struct Object *ob,
+ const float mat[4][4],
+ const bool use_compat,
+ const bool use_parent);
void BKE_object_matrix_local_get(struct Object *ob, float r_mat[4][4]);
bool BKE_object_pose_context_check(const struct Object *ob);
@@ -181,6 +302,9 @@ struct Object *BKE_object_pose_armature_get_visible(struct Object *ob,
struct ViewLayer *view_layer,
struct View3D *v3d);
+/**
+ * Access pose array with special check to get pose object when in weight paint mode.
+ */
struct Object **BKE_object_pose_array_get_ex(struct ViewLayer *view_layer,
struct View3D *v3d,
unsigned int *r_objects_len,
@@ -205,7 +329,9 @@ struct Base **BKE_object_pose_base_array_get(struct ViewLayer *view_layer,
void BKE_object_get_parent_matrix(struct Object *ob, struct Object *par, float r_parentmat[4][4]);
-/* Compute object world transform and store it in ob->obmat. */
+/**
+ * Compute object world transform and store it in `ob->obmat`.
+ */
void BKE_object_where_is_calc(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob);
void BKE_object_where_is_calc_ex(struct Depsgraph *depsgraph,
struct Scene *scene,
@@ -216,9 +342,16 @@ void BKE_object_where_is_calc_time(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
float ctime);
+/**
+ * Calculate object transformation matrix without recalculating dependencies and
+ * constraints -- assume dependencies are already solved by depsgraph.
+ * No changes to object and its parent would be done.
+ * Used for bundles orientation in 3d space relative to parented blender camera.
+ */
void BKE_object_where_is_calc_mat4(struct Object *ob, float r_obmat[4][4]);
/* Possibly belong in own module? */
+
struct BoundBox *BKE_boundbox_alloc_unit(void);
void BKE_boundbox_init_from_minmax(struct BoundBox *bb, const float min[3], const float max[3]);
void BKE_boundbox_calc_center_aabb(const struct BoundBox *bb, float r_cent[3]);
@@ -230,6 +363,14 @@ void BKE_boundbox_minmax(const struct BoundBox *bb,
struct BoundBox *BKE_object_boundbox_get(struct Object *ob);
void BKE_object_dimensions_get(struct Object *ob, float r_vec[3]);
+/**
+ * The original scale and object matrix can be passed in so any difference
+ * of the objects matrix and the final matrix can be accounted for,
+ * typically this caused by parenting, constraints or delta-scale.
+ *
+ * Re-using these values from the object causes a feedback loop
+ * when multiple values are modified at once in some situations. see: T69536.
+ */
void BKE_object_dimensions_set_ex(struct Object *ob,
const float value[3],
int axis_mask,
@@ -238,8 +379,12 @@ void BKE_object_dimensions_set_ex(struct Object *ob,
void BKE_object_dimensions_set(struct Object *ob, const float value[3], int axis_mask);
void BKE_object_empty_draw_type_set(struct Object *ob, const int value);
+/**
+ * Use this to temporally disable/enable bound-box.
+ */
void BKE_object_boundbox_flag(struct Object *ob, int flag, const bool set);
void BKE_object_boundbox_calc_from_mesh(struct Object *ob, const struct Mesh *me_eval);
+bool BKE_object_boundbox_calc_from_evaluated_geometry(struct Object *ob);
void BKE_object_minmax(struct Object *ob, float r_min[3], float r_max[3], const bool use_hidden);
bool BKE_object_minmax_dupli(struct Depsgraph *depsgraph,
struct Scene *scene,
@@ -248,7 +393,9 @@ bool BKE_object_minmax_dupli(struct Depsgraph *depsgraph,
float r_max[3],
const bool use_hidden);
-/* sometimes min-max isn't enough, we need to loop over each point */
+/**
+ * Sometimes min-max isn't enough, we need to loop over each point.
+ */
void BKE_object_foreach_display_point(struct Object *ob,
const float obmat[4][4],
void (*func_cb)(const float[3], void *),
@@ -279,9 +426,18 @@ void BKE_object_tfm_protected_restore(struct Object *ob,
void BKE_object_tfm_copy(struct Object *object_dst, const struct Object *object_src);
+/**
+ * Restore the object->data to a non-modifier evaluated state.
+ *
+ * Some changes done directly in evaluated object require them to be reset
+ * before being re-evaluated.
+ * For example, we need to call this before #BKE_mesh_new_from_object(),
+ * in case we removed/added modifiers in the evaluated object.
+ */
void BKE_object_eval_reset(struct Object *ob_eval);
/* Dependency graph evaluation callbacks. */
+
void BKE_object_eval_local_transform(struct Depsgraph *depsgraph, struct Object *ob);
void BKE_object_eval_parent(struct Depsgraph *depsgraph, struct Object *ob);
void BKE_object_eval_constraints(struct Depsgraph *depsgraph,
@@ -294,6 +450,9 @@ void BKE_object_eval_uber_transform(struct Depsgraph *depsgraph, struct Object *
void BKE_object_eval_uber_data(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob);
+/**
+ * Assign #Object.data after modifier stack evaluation.
+ */
void BKE_object_eval_assign_data(struct Object *object, struct ID *data, bool is_owned);
void BKE_object_sync_to_original(struct Depsgraph *depsgraph, struct Object *object);
@@ -319,7 +478,27 @@ void BKE_object_eval_eval_base_flags(struct Depsgraph *depsgraph,
void BKE_object_handle_data_update(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob);
+/**
+ * \warning "scene" here may not be the scene object actually resides in.
+ * When dealing with background-sets, "scene" is actually the active scene.
+ * e.g. "scene" <-- set 1 <-- set 2 ("ob" lives here) <-- set 3 <-- ... <-- set n
+ * rigid bodies depend on their world so use #BKE_object_handle_update_ex()
+ * to also pass along the current rigid body world.
+ */
void BKE_object_handle_update(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob);
+/**
+ * Proxy rule:
+ * - lib_object->proxy_from == the one we borrow from, only set temporal and cleared here.
+ * - local_object->proxy == pointer to library object, saved in files and read.
+ *
+ * Function below is polluted with proxy exceptions, cleanup will follow!
+ *
+ * The main object update call, for object matrix, constraints, keys and displist (modifiers)
+ * requires flags to be set!
+ *
+ * Ideally we shouldn't have to pass the rigid body world,
+ * but need bigger restructuring to avoid id.
+ */
void BKE_object_handle_update_ex(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
@@ -329,17 +508,32 @@ void BKE_object_handle_update_ex(struct Depsgraph *depsgraph,
void BKE_object_sculpt_data_create(struct Object *ob);
bool BKE_object_obdata_texspace_get(struct Object *ob,
- short **r_texflag,
+ char **r_texflag,
float **r_loc,
float **r_size);
+/** Get evaluated mesh for given object. */
struct Mesh *BKE_object_get_evaluated_mesh(const struct Object *object);
+/**
+ * Get mesh which is not affected by modifiers:
+ * - For original objects it will be same as `object->data`, and it is a mesh
+ * which is in the corresponding #Main.
+ * - For copied-on-write objects it will give pointer to a copied-on-write
+ * mesh which corresponds to original object's mesh.
+ */
struct Mesh *BKE_object_get_pre_modified_mesh(const struct Object *object);
+/**
+ * Get a mesh which corresponds to the very original mesh from #Main.
+ * - For original objects it will be object->data.
+ * - For evaluated objects it will be same mesh as corresponding original
+ * object uses as data.
+ */
struct Mesh *BKE_object_get_original_mesh(const struct Object *object);
/* Lattice accessors.
* These functions return either the regular lattice, or the edit-mode lattice,
* whichever is currently in use. */
+
struct Lattice *BKE_object_get_lattice(const struct Object *object);
struct Lattice *BKE_object_get_evaluated_lattice(const struct Object *object);
@@ -356,12 +550,38 @@ bool BKE_object_flag_test_recursive(const struct Object *ob, short flag);
bool BKE_object_is_child_recursive(const struct Object *ob_parent, const struct Object *ob_child);
-/* return ModifierMode flag */
+/**
+ * Most important if this is modified it should _always_ return true, in certain
+ * cases false positives are hard to avoid (shape keys for example).
+ *
+ * \return #ModifierMode flag.
+ */
int BKE_object_is_modified(struct Scene *scene, struct Object *ob);
+/**
+ * Test if object is affected by deforming modifiers (for motion blur). again
+ * most important is to avoid false positives, this is to skip computations
+ * and we can still if there was actual deformation afterwards.
+ */
int BKE_object_is_deform_modified(struct Scene *scene, struct Object *ob);
+/**
+ * Check of objects moves in time.
+ *
+ * \note This function is currently optimized for usage in combination
+ * with modifier deformation checks (#eModifierTypeType_OnlyDeform),
+ * so modifiers can quickly check if their target objects moves
+ * (causing deformation motion blur) or not.
+ *
+ * This makes it possible to give some degree of false-positives here,
+ * but it's currently an acceptable tradeoff between complexity and check
+ * speed. In combination with checks of modifier stack and real life usage
+ * percentage of false-positives shouldn't be that high.
+ *
+ * \note This function does not consider physics systems.
+ */
bool BKE_object_moves_in_time(const struct Object *object, bool recurse_parent);
+/** Return the number of scenes using (instantiating) that object in their collections. */
int BKE_object_scenes_users_get(struct Main *bmain, struct Object *ob);
struct MovieClip *BKE_object_movieclip_get(struct Scene *scene,
@@ -369,7 +589,16 @@ struct MovieClip *BKE_object_movieclip_get(struct Scene *scene,
bool use_default);
void BKE_object_runtime_reset(struct Object *object);
+/**
+ * Reset all pointers which we don't want to be shared when copying the object.
+ */
void BKE_object_runtime_reset_on_copy(struct Object *object, const int flag);
+/**
+ * The function frees memory used by the runtime data, but not the runtime field itself.
+ *
+ * All runtime data is cleared to ensure it's not used again,
+ * in keeping with other `_free_data(..)` functions.
+ */
void BKE_object_runtime_free_data(struct Object *object);
void BKE_object_batch_cache_dirty_tag(struct Object *ob);
@@ -393,12 +622,31 @@ typedef enum eObjectSet {
OB_SET_ALL, /* All Objects. */
} eObjectSet;
+/**
+ * Iterates over all objects of the given scene layer.
+ * Depending on the #eObjectSet flag:
+ * collect either #OB_SET_ALL, #OB_SET_VISIBLE or #OB_SET_SELECTED objects.
+ * If #OB_SET_VISIBLE or#OB_SET_SELECTED are collected,
+ * then also add related objects according to the given \a includeFilter.
+ */
struct LinkNode *BKE_object_relational_superset(struct ViewLayer *view_layer,
eObjectSet objectSet,
eObRelationTypes includeFilter);
+/**
+ * \return All groups this object is a part of, caller must free.
+ */
struct LinkNode *BKE_object_groups(struct Main *bmain, struct Scene *scene, struct Object *ob);
void BKE_object_groups_clear(struct Main *bmain, struct Scene *scene, struct Object *object);
+/**
+ * Return a KDTree_3d from the deformed object (in world-space).
+ *
+ * \note Only mesh objects currently support deforming, others are TODO.
+ *
+ * \param ob:
+ * \param r_tot:
+ * \return The KD-tree or nullptr if it can't be created.
+ */
struct KDTree_3d *BKE_object_as_kdtree(struct Object *ob, int *r_tot);
bool BKE_object_modifier_use_time(struct Scene *scene,
@@ -406,6 +654,10 @@ bool BKE_object_modifier_use_time(struct Scene *scene,
struct ModifierData *md,
int dag_eval_mode);
+/**
+ * \note this function should eventually be replaced by depsgraph functionality.
+ * Avoid calling this in new code unless there is a very good reason for it!
+ */
bool BKE_object_modifier_update_subframe(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
@@ -419,7 +671,8 @@ bool BKE_object_empty_image_frame_is_visible_in_view3d(const struct Object *ob,
bool BKE_object_empty_image_data_is_visible_in_view3d(const struct Object *ob,
const struct RegionView3D *rv3d);
-/* This is an utility function for Python's object.to_mesh() (the naming is not very clear though).
+/**
+ * This is an utility function for Python's object.to_mesh() (the naming is not very clear though).
* The result is owned by the object.
*
* The mesh will be freed when object is re-evaluated or is destroyed. It is possible to force to
@@ -436,11 +689,12 @@ struct Mesh *BKE_object_to_mesh(struct Depsgraph *depsgraph,
void BKE_object_to_mesh_clear(struct Object *object);
-/* This is an utility function for Python's object.to_curve().
+/**
+ * This is an utility function for Python's `object.to_curve()`.
* The result is owned by the object.
*
* The curve will be freed when object is re-evaluated or is destroyed. It is possible to force
- * clear memory used by this curve by calling BKE_object_to_curve_clear().
+ * clear memory used by this curve by calling #BKE_object_to_curve_clear().
*
* If apply_modifiers is true and the object is a curve one, then spline deform modifiers are
* applied on the curve control points.
diff --git a/source/blender/blenkernel/BKE_object_deform.h b/source/blender/blenkernel/BKE_object_deform.h
index a10158254c2..ddbf5178ab0 100644
--- a/source/blender/blenkernel/BKE_object_deform.h
+++ b/source/blender/blenkernel/BKE_object_deform.h
@@ -31,24 +31,73 @@ struct MDeformVert;
struct Object;
struct bDeformGroup;
-/* General vgroup operations */
+/* General vgroup operations. */
+
+/**
+ * Update users of vgroups from this object, according to given map.
+ *
+ * Use it when you remove or reorder vgroups in the object.
+ *
+ * \param map: an array mapping old indices to new indices.
+ */
void BKE_object_defgroup_remap_update_users(struct Object *ob, const int *map);
+/**
+ * Get #MDeformVert vgroup data from given object. Should only be used in Object mode.
+ *
+ * \return True if the id type supports weights.
+ */
bool BKE_object_defgroup_array_get(struct ID *id, struct MDeformVert **dvert_arr, int *dvert_tot);
+/**
+ * Add a vgroup of default name to object. *Does not* handle #MDeformVert data at all!
+ */
struct bDeformGroup *BKE_object_defgroup_add(struct Object *ob);
+/**
+ * Add a vgroup of given name to object. *Does not* handle #MDeformVert data at all!
+ */
struct bDeformGroup *BKE_object_defgroup_add_name(struct Object *ob, const char *name);
+/**
+ * Create #MDeformVert data for given ID. Work in Object mode only.
+ */
struct MDeformVert *BKE_object_defgroup_data_create(struct ID *id);
+/**
+ * Remove all verts (or only selected ones) from given vgroup. Work in Object and Edit modes.
+ *
+ * \param use_selection: Only operate on selection.
+ * \return True if any vertex was removed, false otherwise.
+ */
bool BKE_object_defgroup_clear(struct Object *ob,
struct bDeformGroup *dg,
const bool use_selection);
+/**
+ * Remove all verts (or only selected ones) from all vgroups. Work in Object and Edit modes.
+ *
+ * \param use_selection: Only operate on selection.
+ * \return True if any vertex was removed, false otherwise.
+ */
bool BKE_object_defgroup_clear_all(struct Object *ob, const bool use_selection);
+/**
+ * Remove given vgroup from object. Work in Object and Edit modes.
+ */
void BKE_object_defgroup_remove(struct Object *ob, struct bDeformGroup *defgroup);
+/**
+ * Remove all vgroups from object. Work in Object and Edit modes.
+ * When only_unlocked=true, locked vertex groups are not removed.
+ */
void BKE_object_defgroup_remove_all_ex(struct Object *ob, bool only_unlocked);
+/**
+ * Remove all vgroups from object. Work in Object and Edit modes.
+ */
void BKE_object_defgroup_remove_all(struct Object *ob);
+/**
+ * Compute mapping for vertex groups with matching name, -1 is used for no remapping.
+ * Returns null if no remapping is required.
+ * The returned array has to be freed.
+ */
int *BKE_object_defgroup_index_map_create(struct Object *ob_src,
struct Object *ob_dst,
int *r_map_len);
@@ -57,34 +106,69 @@ void BKE_object_defgroup_index_map_apply(struct MDeformVert *dvert,
const int *map,
int map_len);
-/* Select helpers */
+/* Select helpers. */
+
enum eVGroupSelect;
+/**
+ * Return the subset type of the Vertex Group Selection.
+ */
bool *BKE_object_defgroup_subset_from_select_type(struct Object *ob,
enum eVGroupSelect subset_type,
int *r_defgroup_tot,
int *r_subset_count);
+/**
+ * Store indices from the defgroup_validmap (faster lookups in some cases).
+ */
void BKE_object_defgroup_subset_to_index_array(const bool *defgroup_validmap,
const int defgroup_tot,
int *r_defgroup_subset_map);
/* ********** */
+/**
+ * Gets the status of "flag" for each #bDeformGroup
+ * in the object data's vertex group list and returns an array containing them
+ */
bool *BKE_object_defgroup_lock_flags_get(struct Object *ob, const int defbase_tot);
bool *BKE_object_defgroup_validmap_get(struct Object *ob, const int defbase_tot);
+/**
+ * Returns total selected vgroups,
+ * `wpi.defbase_sel` is assumed malloc'd, all values are set.
+ */
bool *BKE_object_defgroup_selected_get(struct Object *ob,
int defbase_tot,
int *r_dg_flags_sel_tot);
+/**
+ * Checks if the lock relative mode is applicable.
+ *
+ * \return true if an unlocked deform group is active.
+ */
bool BKE_object_defgroup_check_lock_relative(const bool *lock_flags,
const bool *validmap,
int index);
+/**
+ * Additional check for whether the lock relative mode is applicable in multi-paint mode.
+ *
+ * \return true if none of the selected groups are locked.
+ */
bool BKE_object_defgroup_check_lock_relative_multi(int defbase_tot,
const bool *lock_flags,
const bool *selected,
int sel_tot);
+/**
+ * Takes a pair of boolean masks of all locked and all deform groups, and computes
+ * a pair of masks for locked deform and unlocked deform groups. Output buffers may
+ * reuse the input ones.
+ */
void BKE_object_defgroup_split_locked_validmap(
int defbase_tot, const bool *locked, const bool *deform, bool *r_locked, bool *r_unlocked);
+/**
+ * Marks mirror vgroups in output and counts them.
+ * Output and counter assumed to be already initialized.
+ * Designed to be usable after BKE_object_defgroup_selected_get to extend selection to mirror.
+ */
void BKE_object_defgroup_mirror_selection(struct Object *ob,
int defbase_tot,
const bool *selection,
diff --git a/source/blender/blenkernel/BKE_ocean.h b/source/blender/blenkernel/BKE_ocean.h
index 186e0ec174b..4388190221d 100644
--- a/source/blender/blenkernel/BKE_ocean.h
+++ b/source/blender/blenkernel/BKE_ocean.h
@@ -74,12 +74,21 @@ struct Ocean *BKE_ocean_add(void);
void BKE_ocean_free_data(struct Ocean *oc);
void BKE_ocean_free(struct Ocean *oc);
bool BKE_ocean_ensure(struct OceanModifierData *omd, const int resolution);
+/**
+ * Return true if the ocean data is valid and can be used.
+ */
bool BKE_ocean_init_from_modifier(struct Ocean *ocean,
struct OceanModifierData const *omd,
const int resolution);
+/**
+ * Return true if the ocean is valid and can be used.
+ */
bool BKE_ocean_is_valid(const struct Ocean *o);
+/**
+ * Return true if the ocean data is valid and can be used.
+ */
bool BKE_ocean_init(struct Ocean *o,
int M,
int N,
@@ -104,15 +113,26 @@ bool BKE_ocean_init(struct Ocean *o,
int seed);
void BKE_ocean_simulate(struct Ocean *o, float t, float scale, float chop_amount);
-/* sampling the ocean surface */
float BKE_ocean_jminus_to_foam(float jminus, float coverage);
+/**
+ * Sampling the ocean surface.
+ */
void BKE_ocean_eval_uv(struct Ocean *oc, struct OceanResult *ocr, float u, float v);
+/**
+ * Use catmullrom interpolation rather than linear.
+ */
void BKE_ocean_eval_uv_catrom(struct Ocean *oc, struct OceanResult *ocr, float u, float v);
void BKE_ocean_eval_xz(struct Ocean *oc, struct OceanResult *ocr, float x, float z);
void BKE_ocean_eval_xz_catrom(struct Ocean *oc, struct OceanResult *ocr, float x, float z);
+/**
+ * Note that this doesn't wrap properly for i, j < 0, but its not really meant for that being
+ * just a way to get the raw data out to save in some image format.
+ */
void BKE_ocean_eval_ij(struct Ocean *oc, struct OceanResult *ocr, int i, int j);
-/* ocean cache handling */
+/**
+ * Ocean cache handling.
+ */
struct OceanCache *BKE_ocean_init_cache(const char *bakepath,
const char *relbase,
int start,
@@ -136,8 +156,26 @@ void BKE_ocean_free_cache(struct OceanCache *och);
void BKE_ocean_free_modifier_cache(struct OceanModifierData *omd);
/* ocean_spectrum.c */
+
+/**
+ * Pierson-Moskowitz model, 1964, assumes waves reach equilibrium with wind.
+ * Model is intended for large area 'fully developed' sea, where winds have been steadily blowing
+ * for days over an area that includes hundreds of wavelengths on a side.
+ */
float BLI_ocean_spectrum_piersonmoskowitz(const struct Ocean *oc, const float kx, const float kz);
+/**
+ * TMA extends the JONSWAP spectrum.
+ * This spectral model is best suited to shallow water.
+ */
float BLI_ocean_spectrum_texelmarsenarsloe(const struct Ocean *oc, const float kx, const float kz);
+/**
+ * Hasselmann et al, 1973. This model extends the Pierson-Moskowitz model with a peak sharpening
+ * function This enhancement is an artificial construct to address the problem that the wave
+ * spectrum is never fully developed.
+ *
+ * The fetch parameter represents the distance from a lee shore,
+ * called the fetch, or the distance over which the wind blows with constant velocity.
+ */
float BLI_ocean_spectrum_jonswap(const struct Ocean *oc, const float kx, const float kz);
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_packedFile.h b/source/blender/blenkernel/BKE_packedFile.h
index 8ddf77e3d49..e3deff9d8fa 100644
--- a/source/blender/blenkernel/BKE_packedFile.h
+++ b/source/blender/blenkernel/BKE_packedFile.h
@@ -57,17 +57,32 @@ enum ePF_FileStatus {
PF_ASK = 10,
};
-/* pack */
+/* Pack. */
+
struct PackedFile *BKE_packedfile_duplicate(const struct PackedFile *pf_src);
struct PackedFile *BKE_packedfile_new(struct ReportList *reports,
const char *filename,
const char *basepath);
struct PackedFile *BKE_packedfile_new_from_memory(void *mem, int memlen);
+/**
+ * No libraries for now.
+ */
void BKE_packedfile_pack_all(struct Main *bmain, struct ReportList *reports, bool verbose);
void BKE_packedfile_pack_all_libraries(struct Main *bmain, struct ReportList *reports);
-/* unpack */
+/* Unpack. */
+
+/**
+ * #BKE_packedfile_unpack_to_file() looks at the existing files (abs_name, local_name)
+ * and a packed file.
+ *
+ * It returns a char *to the existing file name / new file name or NULL when
+ * there was an error or when the user decides to cancel the operation.
+ *
+ * \warning 'abs_name' may be relative still! (use a "//" prefix)
+ * be sure to run #BLI_path_abs on it first.
+ */
char *BKE_packedfile_unpack_to_file(struct ReportList *reports,
const char *ref_file_name,
const char *abs_name,
@@ -107,23 +122,38 @@ int BKE_packedfile_write_to_file(struct ReportList *reports,
struct PackedFile *pf,
const bool guimode);
-/* free */
+/* Free. */
+
void BKE_packedfile_free(struct PackedFile *pf);
-/* info */
+/* Info. */
+
int BKE_packedfile_count_all(struct Main *bmain);
+/**
+ * This function compares a packed file to a 'real' file.
+ * It returns an integer indicating if:
+ *
+ * - #PF_EQUAL: the packed file and original file are identical.
+ * - #PF_DIFFERENT: the packed file and original file differ.
+ * - #PF_NOFILE: the original file doesn't exist.
+ */
enum ePF_FileCompare BKE_packedfile_compare_to_file(const char *ref_file_name,
const char *filename,
struct PackedFile *pf);
-/* read */
+/* Read. */
+
int BKE_packedfile_seek(struct PackedFile *pf, int offset, int whence);
void BKE_packedfile_rewind(struct PackedFile *pf);
int BKE_packedfile_read(struct PackedFile *pf, void *data, int size);
-/* ID should be not NULL, return true if there's a packed file */
+/**
+ * ID should be not NULL, return true if there's a packed file.
+ */
bool BKE_packedfile_id_check(const struct ID *id);
-/* ID should be not NULL, throws error when ID is Library */
+/**
+ * ID should be not NULL, throws error when ID is Library.
+ */
void BKE_packedfile_id_unpack(struct Main *bmain,
struct ID *id,
struct ReportList *reports,
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index 6fc5ef4d870..40e3ab74fac 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -111,10 +111,11 @@ typedef enum ePaintOverlayControlFlags {
(PAINT_OVERLAY_OVERRIDE_SECONDARY | PAINT_OVERLAY_OVERRIDE_PRIMARY | \
PAINT_OVERLAY_OVERRIDE_CURSOR)
-/* Defines 8 areas resulting of splitting the object space by the XYZ axis planes. This is used to
+/**
+ * Defines 8 areas resulting of splitting the object space by the XYZ axis planes. This is used to
* flip or mirror transform values depending on where the vertex is and where the transform
- * operation started to support XYZ symmetry on those operations in a predictable way. */
-
+ * operation started to support XYZ symmetry on those operations in a predictable way.
+ */
#define PAINT_SYMM_AREA_DEFAULT 0
typedef enum ePaintSymmetryAreas {
@@ -136,10 +137,14 @@ ePaintOverlayControlFlags BKE_paint_get_overlay_flags(void);
void BKE_paint_reset_overlay_invalid(ePaintOverlayControlFlags flag);
void BKE_paint_set_overlay_override(enum eOverlayFlags flag);
-/* palettes */
+/* Palettes. */
+
struct Palette *BKE_palette_add(struct Main *bmain, const char *name);
struct PaletteColor *BKE_palette_color_add(struct Palette *palette);
bool BKE_palette_is_empty(const struct Palette *palette);
+/**
+ * Remove color from palette. Must be certain color is inside the palette!
+ */
void BKE_palette_color_remove(struct Palette *palette, struct PaletteColor *color);
void BKE_palette_clear(struct Palette *palette);
@@ -152,12 +157,21 @@ bool BKE_palette_from_hash(struct Main *bmain,
const char *name,
const bool linear);
-/* paint curves */
+/* Paint curves. */
+
struct PaintCurve *BKE_paint_curve_add(struct Main *bmain, const char *name);
+/**
+ * Call when entering each respective paint mode.
+ */
bool BKE_paint_ensure(struct ToolSettings *ts, struct Paint **r_paint);
void BKE_paint_init(struct Main *bmain, struct Scene *sce, ePaintMode mode, const char col[3]);
void BKE_paint_free(struct Paint *p);
+/**
+ * Called when copying scene settings, so even if 'src' and 'tar' are the same still do a
+ * #id_us_plus(), rather than if we were copying between 2 existing scenes where a matching
+ * value should decrease the existing user count as with #paint_brush_set()
+ */
void BKE_paint_copy(struct Paint *src, struct Paint *tar, const int flag);
void BKE_paint_runtime_init(const struct ToolSettings *ts, struct Paint *paint);
@@ -181,26 +195,46 @@ void BKE_paint_palette_set(struct Paint *p, struct Palette *palette);
void BKE_paint_curve_set(struct Brush *br, struct PaintCurve *pc);
void BKE_paint_curve_clamp_endpoint_add_index(struct PaintCurve *pc, const int add_index);
-/* testing face select mode
- * Texture paint could be removed since selected faces are not used
- * however hiding faces is useful */
+/**
+ * Return true when in vertex/weight/texture paint + face-select mode?
+ */
bool BKE_paint_select_face_test(struct Object *ob);
+/**
+ * Return true when in vertex/weight paint + vertex-select mode?
+ */
bool BKE_paint_select_vert_test(struct Object *ob);
+/**
+ * used to check if selection is possible
+ * (when we don't care if its face or vert)
+ */
bool BKE_paint_select_elem_test(struct Object *ob);
-/* partial visibility */
+/* Partial visibility. */
+
+/**
+ * Returns non-zero if any of the face's vertices are hidden, zero otherwise.
+ */
bool paint_is_face_hidden(const struct MLoopTri *lt,
const struct MVert *mvert,
const struct MLoop *mloop);
+/**
+ * Returns non-zero if any of the corners of the grid
+ * face whose inner corner is at (x, y) are hidden, zero otherwise.
+ */
bool paint_is_grid_face_hidden(const unsigned int *grid_hidden, int gridsize, int x, int y);
+/**
+ * Return true if all vertices in the face are visible, false otherwise.
+ */
bool paint_is_bmesh_face_hidden(struct BMFace *f);
-/* paint masks */
+/* Paint masks. */
+
float paint_grid_paint_mask(const struct GridPaintMask *gpm, uint level, uint x, uint y);
void BKE_paint_face_set_overlay_color_get(const int face_set, const int seed, uchar r_color[4]);
-/* stroke related */
+/* Stroke related. */
+
bool paint_calculate_rake_rotation(struct UnifiedPaintSettings *ups,
struct Brush *brush,
const float mouse_pos[2]);
@@ -211,14 +245,20 @@ void paint_update_brush_rake_rotation(struct UnifiedPaintSettings *ups,
void BKE_paint_stroke_get_average(struct Scene *scene, struct Object *ob, float stroke[3]);
/* Tool slot API. */
+
void BKE_paint_toolslots_init_from_main(struct Main *bmain);
void BKE_paint_toolslots_len_ensure(struct Paint *paint, int len);
void BKE_paint_toolslots_brush_update_ex(struct Paint *paint, struct Brush *brush);
void BKE_paint_toolslots_brush_update(struct Paint *paint);
+/**
+ * Run this to ensure brush types are set for each slot on entering modes
+ * (for new scenes for example).
+ */
void BKE_paint_toolslots_brush_validate(struct Main *bmain, struct Paint *paint);
struct Brush *BKE_paint_toolslots_brush_get(struct Paint *paint, int slot_index);
/* .blend I/O */
+
void BKE_paint_blend_write(struct BlendWriter *writer, struct Paint *paint);
void BKE_paint_blend_read_data(struct BlendDataReader *reader,
const struct Scene *scene,
@@ -229,7 +269,7 @@ void BKE_paint_blend_read_lib(struct BlendLibReader *reader,
#define SCULPT_FACE_SET_NONE 0
-/* Used for both vertex color and weight paint */
+/** Used for both vertex color and weight paint. */
struct SculptVertexPaintGeomMap {
int *vert_map_mem;
struct MeshElemMap *vert_to_loop;
@@ -237,7 +277,7 @@ struct SculptVertexPaintGeomMap {
struct MeshElemMap *vert_to_poly;
};
-/* Pose Brush IK Chain */
+/** Pose Brush IK Chain. */
typedef struct SculptPoseIKChainSegment {
float orig[3];
float head[3];
@@ -620,10 +660,15 @@ void BKE_sculptsession_free_vwpaint_data(struct SculptSession *ss);
void BKE_sculptsession_bm_to_me(struct Object *ob, bool reorder);
void BKE_sculptsession_bm_to_me_for_render(struct Object *object);
-/* Create new color layer on object if it doesn't have one and if experimental feature set has
- * sculpt vertex color enabled. Returns truth if new layer has been added, false otherwise. */
+/**
+ * Create new color layer on object if it doesn't have one and if experimental feature set has
+ * sculpt vertex color enabled. Returns truth if new layer has been added, false otherwise.
+ */
void BKE_sculpt_color_layer_create_if_needed(struct Object *object);
+/**
+ * \warning Expects a fully evaluated depsgraph.
+ */
void BKE_sculpt_update_object_for_edit(struct Depsgraph *depsgraph,
struct Object *ob_orig,
bool need_pmap,
@@ -632,6 +677,10 @@ void BKE_sculpt_update_object_for_edit(struct Depsgraph *depsgraph,
void BKE_sculpt_update_object_before_eval(struct Object *ob_eval);
void BKE_sculpt_update_object_after_eval(struct Depsgraph *depsgraph, struct Object *ob_eval);
+/**
+ * Sculpt mode handles multi-res differently from regular meshes, but only if
+ * it's the last modifier on the stack and it is not on the first level.
+ */
struct MultiresModifierData *BKE_sculpt_multires_active(struct Scene *scene, struct Object *ob);
int BKE_sculpt_mask_layers_ensure(struct Object *ob, struct MultiresModifierData *mmd);
void BKE_sculpt_toolsettings_data_ensure(struct Scene *scene);
@@ -640,19 +689,37 @@ struct PBVH *BKE_sculpt_object_pbvh_ensure(struct Depsgraph *depsgraph, struct O
void BKE_sculpt_bvh_update_from_ccg(struct PBVH *pbvh, struct SubdivCCG *subdiv_ccg);
-/* This ensure that all elements in the mesh (both vertices and grids) have their visibility
- * updated according to the face sets. */
+/**
+ * This ensure that all elements in the mesh (both vertices and grids) have their visibility
+ * updated according to the face sets.
+ */
void BKE_sculpt_sync_face_set_visibility(struct Mesh *mesh, struct SubdivCCG *subdiv_ccg);
-/* Individual function to sync the Face Set visibility to mesh and grids. */
+/**
+ * Individual function to sync the Face Set visibility to mesh and grids.
+ */
void BKE_sculpt_sync_face_sets_visibility_to_base_mesh(struct Mesh *mesh);
void BKE_sculpt_sync_face_sets_visibility_to_grids(struct Mesh *mesh,
struct SubdivCCG *subdiv_ccg);
+/**
+ * Ensures that a Face Set data-layers exists. If it does not, it creates one respecting the
+ * visibility stored in the vertices of the mesh. If it does, it copies the visibility from the
+ * mesh to the Face Sets. */
void BKE_sculpt_face_sets_ensure_from_base_mesh_visibility(struct Mesh *mesh);
+/**
+ * Ensures we do have expected mesh data in original mesh for the sculpt mode.
+ *
+ * \note IDs are expected to be original ones here, and calling code should ensure it updates its
+ * depsgraph properly after calling this function if it needs up-to-date evaluated data.
+ */
void BKE_sculpt_ensure_orig_mesh_data(struct Scene *scene, struct Object *object);
+/**
+ * Test if PBVH can be used directly for drawing, which is faster than
+ * drawing the mesh and all updates that come with it.
+ */
bool BKE_sculptsession_use_pbvh_draw(const struct Object *ob, const struct View3D *v3d);
enum {
diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h
index 78a6e47ec48..972cba2d132 100644
--- a/source/blender/blenkernel/BKE_particle.h
+++ b/source/blender/blenkernel/BKE_particle.h
@@ -286,6 +286,9 @@ BLI_INLINE void psys_frand_vec(ParticleSystem *psys, unsigned int seed, float ve
/* ----------- functions needed outside particlesystem ---------------- */
/* particle.c */
+
+/* Few helpers for count-all etc. */
+
int count_particles(struct ParticleSystem *psys);
int count_particles_mod(struct ParticleSystem *psys, int totgr, int cur);
@@ -296,8 +299,13 @@ int psys_get_tot_child(struct Scene *scene,
struct ParticleSystem *psys,
const bool use_render_params);
+/**
+ * Get object's active particle system safely.
+ */
struct ParticleSystem *psys_get_current(struct Object *ob);
-/* for rna */
+
+/* For RNA API. */
+
short psys_get_current_num(struct Object *ob);
void psys_set_current_num(struct Object *ob, int index);
/* UNUSED */
@@ -305,14 +313,17 @@ void psys_set_current_num(struct Object *ob, int index);
struct LatticeDeformData *psys_create_lattice_deform_data(struct ParticleSimulationData *sim);
-/* For a given evaluated particle system get its original.
+/**
+ * For a given evaluated particle system get its original.
*
- * If this input is an original particle system already, the return value is the
- * same as the input. */
+ * If this input is an original particle system already, the return value is the same as the input.
+ */
struct ParticleSystem *psys_orig_get(struct ParticleSystem *psys);
-/* For a given original object and its particle system, get evaluated particle
- * system within a given dependency graph. */
+/**
+ * For a given original object and its particle system,
+ * get evaluated particle system within a given dependency graph.
+ */
struct ParticleSystem *psys_eval_get(struct Depsgraph *depsgraph,
struct Object *object,
struct ParticleSystem *psys);
@@ -328,11 +339,17 @@ void psys_check_group_weights(struct ParticleSettings *part);
int psys_uses_gravity(struct ParticleSimulationData *sim);
void BKE_particlesettings_fluid_default_settings(struct ParticleSettings *part);
-/* free */
+/**
+ * Free cache path.
+ */
void psys_free_path_cache(struct ParticleSystem *psys, struct PTCacheEdit *edit);
+/**
+ * Free everything.
+ */
void psys_free(struct Object *ob, struct ParticleSystem *psys);
-
-/* Copy. */
+/**
+ * Copy.
+ */
void psys_copy_particles(struct ParticleSystem *psys_dst, struct ParticleSystem *psys_src);
bool psys_render_simplify_params(struct ParticleSystem *psys,
@@ -379,6 +396,12 @@ void psys_find_parents(struct ParticleSimulationData *sim, const bool use_render
void psys_unique_name(struct Object *object, struct ParticleSystem *psys, const char *defname);
+/**
+ * Calculates paths ready for drawing/rendering
+ * - Useful for making use of opengl vertex arrays for super fast strand drawing.
+ * - Makes child strands possible and creates them too into the cache.
+ * - Cached path data is also used to determine cut position for the edit-mode tool.
+ */
void psys_cache_paths(struct ParticleSimulationData *sim,
float cfra,
const bool use_render_params);
@@ -409,16 +432,24 @@ float psys_get_child_size(struct ParticleSystem *psys,
struct ChildParticle *cpa,
float cfra,
float *pa_time);
+/**
+ * Gets hair (or keyed) particles state at the "path time" specified in `state->time`.
+ */
void psys_get_particle_on_path(struct ParticleSimulationData *sim,
int pa_num,
struct ParticleKey *state,
const bool vel);
-int psys_get_particle_state(struct ParticleSimulationData *sim,
- int p,
- struct ParticleKey *state,
- int always);
+/**
+ * Gets particle's state at a time.
+ * \return true if particle exists and can be seen and false if not.
+ */
+bool psys_get_particle_state(struct ParticleSimulationData *sim,
+ int p,
+ struct ParticleKey *state,
+ const bool always);
+
+/* Child paths. */
-/* child paths */
void BKE_particlesettings_clump_curve_init(struct ParticleSettings *part);
void BKE_particlesettings_rough_curve_init(struct ParticleSettings *part);
void BKE_particlesettings_twist_curve_init(struct ParticleSettings *part);
@@ -434,9 +465,13 @@ void psys_apply_child_modifiers(struct ParticleThreadContext *ctx,
void psys_sph_init(struct ParticleSimulationData *sim, struct SPHData *sphdata);
void psys_sph_finalize(struct SPHData *sphdata);
+/**
+ * Sample the density field at a point in space.
+ */
void psys_sph_density(struct BVHTree *tree, struct SPHData *data, float co[3], float vars[2]);
-/* for anim.c */
+/* For anim.c */
+
void psys_get_dupli_texture(struct ParticleSystem *psys,
struct ParticleSettings *part,
struct ParticleSystemModifierData *psmd,
@@ -451,6 +486,9 @@ void psys_get_dupli_path_transform(struct ParticleSimulationData *sim,
float mat[4][4],
float *scale);
+/**
+ * Threaded child particle distribution and path caching.
+ */
void psys_thread_context_init(struct ParticleThreadContext *ctx,
struct ParticleSimulationData *sim);
void psys_thread_context_free(struct ParticleThreadContext *ctx);
@@ -467,9 +505,16 @@ void psys_apply_hair_lattice(struct Depsgraph *depsgraph,
struct ParticleSystem *psys);
/* particle_system.c */
+
struct ParticleSystem *psys_get_target_system(struct Object *ob, struct ParticleTarget *pt);
+/**
+ * Counts valid keyed targets.
+ */
void psys_count_keyed_targets(struct ParticleSimulationData *sim);
void psys_update_particle_tree(struct ParticleSystem *psys, float cfra);
+/**
+ * System type has changed so set sensible defaults and clear non applicable flags.
+ */
void psys_changed_type(struct Object *ob, struct ParticleSystem *psys);
void psys_make_temp_pointcache(struct Object *ob, struct ParticleSystem *psys);
@@ -486,13 +531,19 @@ void psys_get_birth_coords(struct ParticleSimulationData *sim,
float dtime,
float cfra);
+/**
+ * Main particle update call, checks that things are ok on the large scale and
+ * then advances in to actual particle calculations depending on particle type.
+ */
void particle_system_update(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
struct ParticleSystem *psys,
const bool use_render_params);
-/* Callback format for performing operations on ID-pointers for particle systems */
+/**
+ * Callback format for performing operations on ID-pointers for particle systems.
+ */
typedef void (*ParticleSystemIDFunc)(struct ParticleSystem *psys,
struct ID **idpoin,
void *userdata,
@@ -502,11 +553,15 @@ void BKE_particlesystem_id_loop(struct ParticleSystem *psys,
ParticleSystemIDFunc func,
void *userdata);
-/* Reset all particle systems in the given object. */
+/**
+ * Reset all particle systems in the given object.
+ */
void BKE_particlesystem_reset_all(struct Object *object);
/* ----------- functions needed only inside particlesystem ------------ */
+
/* particle.c */
+
void psys_disable_all(struct Object *ob);
void psys_enable_all(struct Object *ob);
@@ -544,6 +599,9 @@ void psys_get_texture(struct ParticleSimulationData *sim,
struct ParticleTexture *ptex,
int event,
float cfra);
+/**
+ * Interpolate a location on a face based on face coordinates.
+ */
void psys_interpolate_face(struct MVert *mvert,
struct MFace *mface,
struct MTFace *tface,
@@ -561,11 +619,16 @@ float psys_particle_value_from_verts(struct Mesh *mesh,
void psys_get_from_key(
struct ParticleKey *key, float loc[3], float vel[3], float rot[4], float *time);
-/* BLI_bvhtree_ray_cast callback */
+/**
+ * Callback for #BVHTree near test.
+ */
void BKE_psys_collision_neartest_cb(void *userdata,
int index,
const struct BVHTreeRay *ray,
struct BVHTreeRayHit *hit);
+/**
+ * Interprets particle data to get a point on a mesh in object space.
+ */
void psys_particle_on_dm(struct Mesh *mesh_final,
int from,
int index,
@@ -579,18 +642,37 @@ void psys_particle_on_dm(struct Mesh *mesh_final,
float orco[3]);
/* particle_system.c */
+
void distribute_particles(struct ParticleSimulationData *sim, int from);
+/**
+ * Set particle parameters that don't change during particle's life.
+ */
void init_particle(struct ParticleSimulationData *sim, struct ParticleData *pa);
void psys_calc_dmcache(struct Object *ob,
struct Mesh *mesh_final,
struct Mesh *mesh_original,
struct ParticleSystem *psys);
+/**
+ * Find the final derived mesh tessface for a particle, from its original tessface index.
+ * This is slow and can be optimized but only for many lookups.
+ *
+ * \param mesh_final: Final mesh, it may not have the same topology as original mesh.
+ * \param mesh_original: Original mesh, use for accessing #MPoly to #MFace mapping.
+ * \param findex_orig: The input tessface index.
+ * \param fw: Face weights (position of the particle inside the \a findex_orig tessface).
+ * \param poly_nodes: May be NULL, otherwise an array of linked list,
+ * one for each final \a mesh_final polygon, containing all its tessfaces indices.
+ * \return The \a mesh_final tessface index.
+ */
int psys_particle_dm_face_lookup(struct Mesh *mesh_final,
struct Mesh *mesh_original,
- int findex,
+ int findex_orig,
const float fw[4],
struct LinkNode **poly_nodes);
+/**
+ * Sets particle to the emitter surface with initial velocity & rotation.
+ */
void reset_particle(struct ParticleSimulationData *sim,
struct ParticleData *pa,
float dtime,
@@ -629,6 +711,7 @@ extern void (*BKE_particle_batch_cache_dirty_tag_cb)(struct ParticleSystem *psys
extern void (*BKE_particle_batch_cache_free_cb)(struct ParticleSystem *psys);
/* .blend file I/O */
+
void BKE_particle_partdeflect_blend_read_data(struct BlendDataReader *reader,
struct PartDeflect *pd);
void BKE_particle_partdeflect_blend_read_lib(struct BlendLibReader *reader,
diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h
index 3a0e9d48af7..5e7a9883de6 100644
--- a/source/blender/blenkernel/BKE_pbvh.h
+++ b/source/blender/blenkernel/BKE_pbvh.h
@@ -90,7 +90,9 @@ void BKE_pbvh_get_frustum_planes(PBVH *pbvh, PBVHFrustumPlanes *planes);
/* Callbacks */
-/* returns 1 if the search should continue from this node, 0 otherwise */
+/**
+ * Returns true if the search should continue from this node, false otherwise.
+ */
typedef bool (*BKE_pbvh_SearchCallback)(PBVHNode *node, void *data);
typedef void (*BKE_pbvh_HitCallback)(PBVHNode *node, void *data);
@@ -101,6 +103,12 @@ typedef void (*BKE_pbvh_SearchNearestCallback)(PBVHNode *node, void *data, float
/* Building */
PBVH *BKE_pbvh_new(void);
+/**
+ * Do a full rebuild with on Mesh data structure.
+ *
+ * \note Unlike mpoly/mloop/verts, looptri is *totally owned* by PBVH
+ * (which means it may rewrite it if needed, see #BKE_pbvh_vert_coords_apply().
+ */
void BKE_pbvh_build_mesh(PBVH *pbvh,
const struct Mesh *mesh,
const struct MPoly *mpoly,
@@ -112,6 +120,9 @@ void BKE_pbvh_build_mesh(PBVH *pbvh,
struct CustomData *pdata,
const struct MLoopTri *looptri,
int looptri_num);
+/**
+ * Do a full rebuild with on Grids data structure.
+ */
void BKE_pbvh_build_grids(PBVH *pbvh,
struct CCGElem **grids,
int totgrid,
@@ -119,6 +130,9 @@ void BKE_pbvh_build_grids(PBVH *pbvh,
void **gridfaces,
struct DMFlagMat *flagmats,
unsigned int **grid_hidden);
+/**
+ * Build a PBVH from a BMesh.
+ */
void BKE_pbvh_build_bmesh(PBVH *pbvh,
struct BMesh *bm,
bool smooth_shading,
@@ -170,8 +184,10 @@ bool BKE_pbvh_bmesh_node_raycast_detail(PBVHNode *node,
float *depth,
float *r_edge_length);
-/* for orthographic cameras, project the far away ray segment points to the root node so
- * we can have better precision. */
+/**
+ * For orthographic cameras, project the far away ray segment points to the root node so
+ * we can have better precision.
+ */
void BKE_pbvh_raycast_project_ray_root(
PBVH *pbvh, bool original, float ray_start[3], float ray_end[3], float ray_normal[3]);
@@ -215,12 +231,19 @@ typedef enum {
PBVHType BKE_pbvh_type(const PBVH *pbvh);
bool BKE_pbvh_has_faces(const PBVH *pbvh);
-/* Get the PBVH root's bounding box */
+/**
+ * Get the PBVH root's bounding box.
+ */
void BKE_pbvh_bounding_box(const PBVH *pbvh, float min[3], float max[3]);
-/* multires hidden data, only valid for type == PBVH_GRIDS */
+/**
+ * Multi-res hidden data, only valid for type == PBVH_GRIDS.
+ */
unsigned int **BKE_pbvh_grid_hidden(const PBVH *pbvh);
+/**
+ * Returns the number of visible quads in the nodes' grids.
+ */
int BKE_pbvh_count_grid_quads(BLI_bitmap **grid_hidden,
const int *grid_indices,
int totgrid,
@@ -228,7 +251,9 @@ int BKE_pbvh_count_grid_quads(BLI_bitmap **grid_hidden,
void BKE_pbvh_sync_face_sets_to_grids(PBVH *pbvh);
-/* multires level, only valid for type == PBVH_GRIDS */
+/**
+ * Multi-res level, only valid for type == #PBVH_GRIDS.
+ */
const struct CCGKey *BKE_pbvh_get_grid_key(const PBVH *pbvh);
struct CCGElem **BKE_pbvh_get_grids(const PBVH *pbvh);
@@ -236,7 +261,9 @@ BLI_bitmap **BKE_pbvh_get_grid_visibility(const PBVH *pbvh);
int BKE_pbvh_get_grid_num_vertices(const PBVH *pbvh);
int BKE_pbvh_get_grid_num_faces(const PBVH *pbvh);
-/* Only valid for type == PBVH_BMESH */
+/**
+ * Only valid for type == #PBVH_BMESH.
+ */
struct BMesh *BKE_pbvh_get_bmesh(PBVH *pbvh);
void BKE_pbvh_bmesh_detail_size_set(PBVH *pbvh, float detail_size);
@@ -244,6 +271,9 @@ typedef enum {
PBVH_Subdivide = 1,
PBVH_Collapse = 2,
} PBVHTopologyUpdateMode;
+/**
+ * Collapse short edges, subdivide long edges.
+ */
bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
PBVHTopologyUpdateMode mode,
const float center[3],
@@ -287,18 +317,28 @@ void BKE_pbvh_node_get_original_BB(PBVHNode *node, float bb_min[3], float bb_max
float BKE_pbvh_node_get_tmin(PBVHNode *node);
-/* test if AABB is at least partially inside the PBVHFrustumPlanes volume */
+/**
+ * Test if AABB is at least partially inside the #PBVHFrustumPlanes volume.
+ */
bool BKE_pbvh_node_frustum_contain_AABB(PBVHNode *node, void *frustum);
-/* test if AABB is at least partially outside the PBVHFrustumPlanes volume */
+/**
+ * Test if AABB is at least partially outside the #PBVHFrustumPlanes volume.
+ */
bool BKE_pbvh_node_frustum_exclude_AABB(PBVHNode *node, void *frustum);
struct GSet *BKE_pbvh_bmesh_node_unique_verts(PBVHNode *node);
struct GSet *BKE_pbvh_bmesh_node_other_verts(PBVHNode *node);
struct GSet *BKE_pbvh_bmesh_node_faces(PBVHNode *node);
+/**
+ * In order to perform operations on the original node coordinates
+ * (currently just ray-cast), store the node's triangles and vertices.
+ *
+ * Skips triangles that are hidden.
+ */
void BKE_pbvh_bmesh_node_save_orig(struct BMesh *bm, PBVHNode *node);
void BKE_pbvh_bmesh_after_stroke(PBVH *pbvh);
-/* Update Bounding Box/Redraw and clear flags */
+/* Update Bounding Box/Redraw and clear flags. */
void BKE_pbvh_update_bounds(PBVH *pbvh, int flags);
void BKE_pbvh_update_vertex_data(PBVH *pbvh, int flags);
@@ -318,14 +358,15 @@ void BKE_pbvh_face_sets_color_set(PBVH *pbvh, int seed, int color_default);
void BKE_pbvh_respect_hide_set(PBVH *pbvh, bool respect_hide);
-/* vertex deformer */
+/* Vertex Deformer. */
+
float (*BKE_pbvh_vert_coords_alloc(struct PBVH *pbvh))[3];
void BKE_pbvh_vert_coords_apply(struct PBVH *pbvh, const float (*vertCos)[3], const int totvert);
bool BKE_pbvh_is_deformed(struct PBVH *pbvh);
-/* Vertex Iterator */
+/* Vertex Iterator. */
-/* this iterator has quite a lot of code, but it's designed to:
+/* This iterator has quite a lot of code, but it's designed to:
* - allow the compiler to eliminate dead code and variables
* - spend most of the time in the relatively simple inner loop */
@@ -469,6 +510,11 @@ void BKE_pbvh_node_get_bm_orco_data(PBVHNode *node,
int *r_orco_tris_num,
float (**r_orco_coords)[3]);
+/**
+ * \note doing a full search on all vertices here seems expensive,
+ * however this is important to avoid having to recalculate bound-box & sync the buffers to the
+ * GPU (which is far more expensive!) See: T47232.
+ */
bool BKE_pbvh_node_vert_update_check_any(PBVH *pbvh, PBVHNode *node);
// void BKE_pbvh_node_BB_reset(PBVHNode *node);
@@ -480,7 +526,8 @@ void pbvh_show_mask_set(PBVH *pbvh, bool show_mask);
bool pbvh_has_face_sets(PBVH *pbvh);
void pbvh_show_face_sets_set(PBVH *pbvh, bool show_face_sets);
-/* Parallelization */
+/* Parallelization. */
+
void BKE_pbvh_parallel_range_settings(struct TaskParallelSettings *settings,
bool use_threading,
int totnode);
diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h
index c83fca767a1..47d3d83f8bb 100644
--- a/source/blender/blenkernel/BKE_pointcache.h
+++ b/source/blender/blenkernel/BKE_pointcache.h
@@ -273,19 +273,28 @@ typedef struct PTCacheEdit {
int totpoint, totframes, totcached, edited;
} PTCacheEdit;
-/* Particle functions */
void BKE_ptcache_make_particle_key(struct ParticleKey *key, int index, void **data, float time);
/**************** Creating ID's ****************************/
+
void BKE_ptcache_id_from_softbody(PTCacheID *pid, struct Object *ob, struct SoftBody *sb);
void BKE_ptcache_id_from_particles(PTCacheID *pid, struct Object *ob, struct ParticleSystem *psys);
void BKE_ptcache_id_from_cloth(PTCacheID *pid, struct Object *ob, struct ClothModifierData *clmd);
+/**
+ * The fluid modifier does not actually use this anymore, but some parts of Blender expect that it
+ * still has a point cache currently. For example, the fluid modifier uses
+ * #DEG_add_collision_relations, which internally creates relations with the point cache.
+ */
void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct FluidModifierData *fmd);
void BKE_ptcache_id_from_dynamicpaint(PTCacheID *pid,
struct Object *ob,
struct DynamicPaintSurface *surface);
void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, struct Object *ob, struct RigidBodyWorld *rbw);
+/**
+ * \param ob: Optional, may be NULL.
+ * \param scene: Optional may be NULL.
+ */
PTCacheID BKE_ptcache_id_find(struct Object *ob, struct Scene *scene, struct PointCache *cache);
void BKE_ptcache_ids_from_object(struct ListBase *lb,
struct Object *ob,
@@ -294,12 +303,11 @@ void BKE_ptcache_ids_from_object(struct ListBase *lb,
/****************** Query funcs ****************************/
-/* Check whether object has a point cache. */
+/**
+ * Check whether object has a point cache.
+ */
bool BKE_ptcache_object_has(struct Scene *scene, struct Object *ob, int duplis);
-/***************** Global funcs ****************************/
-void BKE_ptcache_remove(void);
-
/************ ID specific functions ************************/
void BKE_ptcache_id_clear(PTCacheID *id, int mode, unsigned int cfra);
bool BKE_ptcache_id_exist(PTCacheID *id, int cfra);
@@ -316,23 +324,35 @@ void BKE_ptcache_update_info(PTCacheID *pid);
/*********** General cache reading/writing ******************/
-/* Size of cache data type. */
+/**
+ * Size of cache data type.
+ */
int BKE_ptcache_data_size(int data_type);
-/* Is point with index in memory cache */
+/**
+ * Is point with index in memory cache?
+ * Check to see if point number "index" is in `pm` (uses binary search for index data).
+ */
int BKE_ptcache_mem_index_find(struct PTCacheMem *pm, unsigned int index);
/* Memory cache read/write helpers. */
+
void BKE_ptcache_mem_pointers_init(struct PTCacheMem *pm, void *cur[BPHYS_TOT_DATA]);
void BKE_ptcache_mem_pointers_incr(void *cur[BPHYS_TOT_DATA]);
int BKE_ptcache_mem_pointers_seek(int point_index,
struct PTCacheMem *pm,
void *cur[BPHYS_TOT_DATA]);
-/* Main cache reading call. */
+/**
+ * Main cache reading call.
+ * Possible to get old or interpolated result.
+ */
int BKE_ptcache_read(PTCacheID *pid, float cfra, bool no_extrapolate_old);
-/* Main cache writing call. */
+/**
+ * Main cache writing call.
+ * Writes cache to disk or memory.
+ */
int BKE_ptcache_write(PTCacheID *pid, unsigned int cfra);
/******************* Allocate & free ***************/
@@ -340,41 +360,56 @@ struct PointCache *BKE_ptcache_add(struct ListBase *ptcaches);
void BKE_ptcache_free_mem(struct ListBase *mem_cache);
void BKE_ptcache_free(struct PointCache *cache);
void BKE_ptcache_free_list(struct ListBase *ptcaches);
+/* returns first point cache */
struct PointCache *BKE_ptcache_copy_list(struct ListBase *ptcaches_new,
const struct ListBase *ptcaches_old,
const int flag);
/********************** Baking *********************/
-/* Bakes cache with cache_step sized jumps in time, not accurate but very fast. */
+/**
+ * Bakes cache with cache_step sized jumps in time, not accurate but very fast.
+ */
void BKE_ptcache_quick_cache_all(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer);
-/* Bake cache or simulate to current frame with settings defined in the baker. */
+/**
+ * Bake cache or simulate to current frame with settings defined in the baker.
+ * if bake is not given run simulations to current frame.
+ */
void BKE_ptcache_bake(struct PTCacheBaker *baker);
-/* Convert disk cache to memory cache. */
+/**
+ * Convert disk cache to memory cache.
+ */
void BKE_ptcache_disk_to_mem(struct PTCacheID *pid);
-
-/* Convert memory cache to disk cache. */
+/**
+ * Convert memory cache to disk cache.
+ */
void BKE_ptcache_mem_to_disk(struct PTCacheID *pid);
-
-/* Convert disk cache to memory cache and vice versa. Clears the cache that was converted. */
+/**
+ * Convert disk cache to memory cache and vice versa. Clears the cache that was converted.
+ */
void BKE_ptcache_toggle_disk_cache(struct PTCacheID *pid);
-
-/* Rename all disk cache files with a new name. Doesn't touch the actual content of the files. */
+/**
+ * Rename all disk cache files with a new name. Doesn't touch the actual content of the files.
+ */
void BKE_ptcache_disk_cache_rename(struct PTCacheID *pid,
const char *name_src,
const char *name_dst);
-/* Loads simulation from external (disk) cache files. */
+/**
+ * Loads simulation from external (disk) cache files.
+ */
void BKE_ptcache_load_external(struct PTCacheID *pid);
-
-/* Set correct flags after successful simulation step */
+/**
+ * Set correct flags after successful simulation step.
+ */
void BKE_ptcache_validate(struct PointCache *cache, int framenr);
-
-/* Set correct flags after unsuccessful simulation step */
+/**
+ * Set correct flags after unsuccessful simulation step.
+ */
void BKE_ptcache_invalidate(struct PointCache *cache);
/********************** .blend File I/O *********************/
diff --git a/source/blender/blenkernel/BKE_pointcloud.h b/source/blender/blenkernel/BKE_pointcloud.h
index d2d390dc786..af8a6ed293d 100644
--- a/source/blender/blenkernel/BKE_pointcloud.h
+++ b/source/blender/blenkernel/BKE_pointcloud.h
@@ -18,7 +18,7 @@
/** \file
* \ingroup bke
- * \brief General operations for point-clouds.
+ * \brief General operations for point clouds.
*/
#ifdef __cplusplus
extern "C" {
diff --git a/source/blender/blenkernel/BKE_preferences.h b/source/blender/blenkernel/BKE_preferences.h
index e9cb024f117..6d6c58e5c1e 100644
--- a/source/blender/blenkernel/BKE_preferences.h
+++ b/source/blender/blenkernel/BKE_preferences.h
@@ -35,6 +35,10 @@ struct bUserAssetLibrary;
struct bUserAssetLibrary *BKE_preferences_asset_library_add(struct UserDef *userdef,
const char *name,
const char *path) ATTR_NONNULL(1);
+/**
+ * Unlink and free a library preference member.
+ * \note Free's \a library itself.
+ */
void BKE_preferences_asset_library_remove(struct UserDef *userdef,
struct bUserAssetLibrary *library) ATTR_NONNULL();
@@ -42,6 +46,12 @@ void BKE_preferences_asset_library_name_set(struct UserDef *userdef,
struct bUserAssetLibrary *library,
const char *name) ATTR_NONNULL();
+/**
+ * Set the library path, ensuring it is pointing to a directory.
+ * Single blend files can only act as "Current File" library; libraries on disk
+ * should always be directories. If the path does not exist, that's fine; it can
+ * created as directory if necessary later.
+ */
void BKE_preferences_asset_library_path_set(struct bUserAssetLibrary *library, const char *path)
ATTR_NONNULL();
diff --git a/source/blender/blenkernel/BKE_report.h b/source/blender/blenkernel/BKE_report.h
index ec2e8d0f875..8b585fd0167 100644
--- a/source/blender/blenkernel/BKE_report.h
+++ b/source/blender/blenkernel/BKE_report.h
@@ -35,9 +35,14 @@ extern "C" {
* These functions also accept NULL in case no error reporting
* is needed. */
-/* report structures are stored in DNA */
+/* Report structures are stored in DNA. */
void BKE_reports_init(ReportList *reports, int flag);
+/**
+ * Only frees the list \a reports.
+ * To make displayed reports disappear, either remove window-manager reports
+ * (#wmWindowManager.reports, or #CTX_wm_reports()), or use #WM_report_banners_cancel().
+ */
void BKE_reports_clear(ReportList *reports);
void BKE_report(ReportList *reports, eReportType type, const char *message);
diff --git a/source/blender/blenkernel/BKE_rigidbody.h b/source/blender/blenkernel/BKE_rigidbody.h
index e28f668d189..1c9bad7fbe8 100644
--- a/source/blender/blenkernel/BKE_rigidbody.h
+++ b/source/blender/blenkernel/BKE_rigidbody.h
@@ -38,11 +38,21 @@ struct Object;
struct ReportList;
struct Scene;
-/* -------------- */
-/* Memory Management */
+/* -------------------------------------------------------------------- */
+/** \name Memory Management
+ * \{ */
+/**
+ * Free rigid-body world.
+ */
void BKE_rigidbody_free_world(struct Scene *scene);
+/**
+ * Free rigid-body settings and simulation instances.
+ */
void BKE_rigidbody_free_object(struct Object *ob, struct RigidBodyWorld *rbw);
+/**
+ * Free rigid-body constraint and simulation instance.
+ */
void BKE_rigidbody_free_constraint(struct Object *ob);
/* ...... */
@@ -52,7 +62,15 @@ void BKE_rigidbody_object_copy(struct Main *bmain,
const struct Object *ob_src,
const int flag);
-/* Callback format for performing operations on ID-pointers for rigidbody world. */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Iterator
+ * \{ */
+
+/**
+ * Callback format for performing operations on ID-pointers for rigid-body world.
+ */
typedef void (*RigidbodyWorldIDFunc)(struct RigidBodyWorld *rbw,
struct ID **idpoin,
void *userdata,
@@ -62,43 +80,83 @@ void BKE_rigidbody_world_id_loop(struct RigidBodyWorld *rbw,
RigidbodyWorldIDFunc func,
void *userdata);
-/* -------------- */
-/* Setup */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Setup
+ * \{ */
-/* create Blender-side settings data - physics objects not initialized yet */
+/**
+ * Set up RigidBody world.
+ *
+ * Create Blender-side settings data - physics objects not initialized yet.
+ */
struct RigidBodyWorld *BKE_rigidbody_create_world(struct Scene *scene);
+/**
+ * Add rigid body settings to the specified object.
+ */
struct RigidBodyOb *BKE_rigidbody_create_object(struct Scene *scene,
struct Object *ob,
short type);
+/**
+ * Add rigid body constraint to the specified object.
+ */
struct RigidBodyCon *BKE_rigidbody_create_constraint(struct Scene *scene,
struct Object *ob,
short type);
-/* Ensure newly set collections' objects all have required data. */
+/**
+ * Ensure newly set collections' objects all have required data.
+ */
void BKE_rigidbody_objects_collection_validate(struct Scene *scene, struct RigidBodyWorld *rbw);
void BKE_rigidbody_constraints_collection_validate(struct Scene *scene,
struct RigidBodyWorld *rbw);
-/* Ensure object added to collection gets RB data if that collection is a RB one. */
+/**
+ * Ensure object added to collection gets RB data if that collection is a RB one.
+ */
void BKE_rigidbody_main_collection_object_add(struct Main *bmain,
struct Collection *collection,
struct Object *object);
-/* copy */
+/**
+ * Copy.
+ */
struct RigidBodyWorld *BKE_rigidbody_world_copy(struct RigidBodyWorld *rbw, const int flag);
void BKE_rigidbody_world_groups_relink(struct RigidBodyWorld *rbw);
-/* 'validate' (i.e. make new or replace old) Physics-Engine objects */
+/**
+ * 'validate' (i.e. make new or replace old) Physics-Engine objects.
+ */
+/**
+ * Create physics sim world given RigidBody world settings
+ *
+ * \note this does NOT update object references that the scene uses,
+ * in case those aren't ready yet!
+ */
void BKE_rigidbody_validate_sim_world(struct Scene *scene,
struct RigidBodyWorld *rbw,
bool rebuild);
+/**
+ * Helper function to calculate volume of rigid-body object.
+
+ * TODO: allow a parameter to specify method used to calculate this?
+ */
void BKE_rigidbody_calc_volume(struct Object *ob, float *r_vol);
void BKE_rigidbody_calc_center_of_mass(struct Object *ob, float r_center[3]);
-/* -------------- */
-/* Utilities */
+/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Utilities
+ * \{ */
+
+/**
+ * Get RigidBody world for the given scene, creating one if needed
+ *
+ * \param scene: Scene to find active Rigid Body world for.
+ */
struct RigidBodyWorld *BKE_rigidbody_get_world(struct Scene *scene);
bool BKE_rigidbody_add_object(struct Main *bmain,
struct Scene *scene,
@@ -115,41 +173,68 @@ void BKE_rigidbody_remove_constraint(struct Main *bmain,
struct Object *ob,
const bool free_us);
-/* -------------- */
-/* Utility Macros */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Utility Macros
+ * \{ */
-/* get mass of Rigid Body Object to supply to RigidBody simulators */
+/**
+ * Get mass of Rigid Body Object to supply to RigidBody simulators.
+ */
#define RBO_GET_MASS(rbo) \
(((rbo) && (((rbo)->type == RBO_TYPE_PASSIVE) || ((rbo)->flag & RBO_FLAG_KINEMATIC) || \
((rbo)->flag & RBO_FLAG_DISABLED))) ? \
(0.0f) : \
((rbo)->mass))
-/* Get collision margin for Rigid Body Object, triangle mesh and cone shapes cannot embed margin,
- * convex hull always uses custom margin. */
+/**
+ * Get collision margin for Rigid Body Object, triangle mesh and cone shapes cannot embed margin,
+ * convex hull always uses custom margin.
+ */
#define RBO_GET_MARGIN(rbo) \
(((rbo)->flag & RBO_FLAG_USE_MARGIN || (rbo)->shape == RB_SHAPE_CONVEXH || \
(rbo)->shape == RB_SHAPE_TRIMESH || (rbo)->shape == RB_SHAPE_CONE) ? \
((rbo)->margin) : \
(0.04f))
-/* -------------- */
-/* Simulation */
+/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Simulation
+ * \{ */
+
+/**
+ * Used when canceling transforms - return rigidbody and object to initial states.
+ */
void BKE_rigidbody_aftertrans_update(struct Object *ob,
float loc[3],
float rot[3],
float quat[4],
float rotAxis[3],
float rotAngle);
+/**
+ * Sync rigid body and object transformations.
+ */
void BKE_rigidbody_sync_transforms(struct RigidBodyWorld *rbw, struct Object *ob, float ctime);
bool BKE_rigidbody_check_sim_running(struct RigidBodyWorld *rbw, float ctime);
bool BKE_rigidbody_is_affected_by_simulation(struct Object *ob);
void BKE_rigidbody_cache_reset(struct RigidBodyWorld *rbw);
+/**
+ * Rebuild rigid body world.
+ *
+ * NOTE: this needs to be called before frame update to work correctly.
+ */
void BKE_rigidbody_rebuild_world(struct Depsgraph *depsgraph, struct Scene *scene, float ctime);
+/**
+ * Run RigidBody simulation for the specified physics world.
+ */
void BKE_rigidbody_do_simulation(struct Depsgraph *depsgraph, struct Scene *scene, float ctime);
-/* -------------------- */
-/* Depsgraph evaluation */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Depsgraph evaluation
+ * \{ */
void BKE_rigidbody_rebuild_sim(struct Depsgraph *depsgraph, struct Scene *scene);
@@ -159,6 +244,8 @@ void BKE_rigidbody_object_sync_transforms(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob);
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h
index f3edf8e9f64..77cf250471f 100644
--- a/source/blender/blenkernel/BKE_scene.h
+++ b/source/blender/blenkernel/BKE_scene.h
@@ -46,7 +46,7 @@ typedef enum eSceneCopyMethod {
SCE_COPY_FULL = 3,
} eSceneCopyMethod;
-/* Use as the contents of a 'for' loop: for (SETLOOPER(...)) { ... */
+/** Use as the contents of a 'for' loop: `for (SETLOOPER(...)) { ... }`. */
#define SETLOOPER(_sce_basis, _sce_iter, _base) \
_sce_iter = _sce_basis, \
_base = _setlooper_base_step( \
@@ -64,6 +64,12 @@ typedef enum eSceneCopyMethod {
_base; \
_base = _setlooper_base_step(&_sce_iter, NULL, _base)
+/**
+ * Helper function for the #SETLOOPER and #SETLOOPER_VIEW_LAYER macros
+ *
+ * It iterates over the bases of the active layer and then the bases
+ * of the active layer of the background (set) scenes recursively.
+ */
struct Base *_setlooper_base_step(struct Scene **sce_iter,
struct ViewLayer *view_layer,
struct Base *base);
@@ -77,6 +83,9 @@ void BKE_scene_remove_rigidbody_object(struct Main *bmain,
struct Object *ob,
const bool free_us);
+/**
+ * Check if there is any instance of the object in the scene.
+ */
bool BKE_scene_object_find(struct Scene *scene, struct Object *ob);
struct Object *BKE_scene_object_find_by_name(const struct Scene *scene, const char *name);
@@ -91,6 +100,10 @@ typedef struct SceneBaseIter {
int phase;
} SceneBaseIter;
+/**
+ * Used by meta-balls, return *all* objects (including duplis)
+ * existing in the scene (including scene's sets).
+ */
int BKE_scene_base_iter_next(struct Depsgraph *depsgraph,
struct SceneBaseIter *iter,
struct Scene **scene,
@@ -99,11 +112,33 @@ int BKE_scene_base_iter_next(struct Depsgraph *depsgraph,
struct Object **ob);
void BKE_scene_base_flag_to_objects(struct ViewLayer *view_layer);
+/**
+ * Synchronize object base flags
+ *
+ * This is usually handled by the depsgraph.
+ * However, in rare occasions we need to use the latest object flags
+ * before depsgraph is fully updated.
+ *
+ * It should (ideally) only run for copy-on-written objects since this is
+ * runtime data generated per-view-layer.
+ */
void BKE_scene_object_base_flag_sync_from_base(struct Base *base);
+/**
+ * Sets the active scene, mainly used when running in background mode
+ * (`--scene` command line argument).
+ * This is also called to set the scene directly, bypassing windowing code.
+ * Otherwise #WM_window_set_active_scene is used when changing scenes by the user.
+ */
void BKE_scene_set_background(struct Main *bmain, struct Scene *sce);
+/**
+ * Called from `creator_args.c`.
+ */
struct Scene *BKE_scene_set_name(struct Main *bmain, const char *name);
+/**
+ * \param flag: copying options (see BKE_lib_id.h's `LIB_ID_COPY_...` flags for more).
+ */
struct ToolSettings *BKE_toolsettings_copy(struct ToolSettings *toolsettings, const int flag);
void BKE_toolsettings_free(struct ToolSettings *toolsettings);
@@ -122,23 +157,49 @@ struct Object *BKE_scene_camera_switch_find(struct Scene *scene); /* DURIAN_CAME
bool BKE_scene_camera_switch_update(struct Scene *scene);
const char *BKE_scene_find_marker_name(const struct Scene *scene, int frame);
+/**
+ * Return the current marker for this frame,
+ * we can have more than 1 marker per frame, this just returns the first (unfortunately).
+ */
const char *BKE_scene_find_last_marker_name(const struct Scene *scene, int frame);
int BKE_scene_frame_snap_by_seconds(struct Scene *scene, double interval_in_seconds, int frame);
-/* checks for cycle, returns 1 if it's all OK */
+/**
+ * Checks for cycle, returns true if it's all OK.
+ */
bool BKE_scene_validate_setscene(struct Main *bmain, struct Scene *sce);
+/**
+ * Return fractional frame number taking into account sub-frames and time
+ * remapping. This the time value used by animation, modifiers and physics
+ * evaluation. */
float BKE_scene_ctime_get(const struct Scene *scene);
+/**
+ * Convert integer frame number to fractional frame number taking into account
+ * sub-frames and time remapping.
+ */
float BKE_scene_frame_to_ctime(const struct Scene *scene, const int frame);
+/**
+ * Get current fractional frame based on frame and sub-frame.
+ */
float BKE_scene_frame_get(const struct Scene *scene);
+/**
+ * Set current frame and sub-frame based on a fractional frame.
+ */
void BKE_scene_frame_set(struct Scene *scene, float frame);
struct TransformOrientationSlot *BKE_scene_orientation_slot_get_from_flag(struct Scene *scene,
int flag);
struct TransformOrientationSlot *BKE_scene_orientation_slot_get(struct Scene *scene,
int slot_index);
+/**
+ * Activate a transform orientation in a 3D view based on an enum value.
+ *
+ * \param orientation: If this is #V3D_ORIENT_CUSTOM or greater, the custom transform orientation
+ * with index \a orientation - #V3D_ORIENT_CUSTOM gets activated.
+ */
void BKE_scene_orientation_slot_set_index(struct TransformOrientationSlot *orient_slot,
int orientation);
int BKE_scene_orientation_slot_get_index(const struct TransformOrientationSlot *orient_slot);
@@ -154,16 +215,29 @@ void BKE_scene_graph_update_tagged(struct Depsgraph *depsgraph, struct Main *bma
void BKE_scene_graph_evaluated_ensure(struct Depsgraph *depsgraph, struct Main *bmain);
void BKE_scene_graph_update_for_newframe(struct Depsgraph *depsgraph);
+/**
+ * Applies changes right away, does all sets too.
+ */
void BKE_scene_graph_update_for_newframe_ex(struct Depsgraph *depsgraph, const bool clear_recalc);
+/**
+ * Ensures given scene/view_layer pair has a valid, up-to-date depsgraph.
+ *
+ * \warning Sets matching depsgraph as active,
+ * so should only be called from the active editing context (usually, from operators).
+ */
void BKE_scene_view_layer_graph_evaluated_ensure(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer);
+/**
+ * Return default view.
+ */
struct SceneRenderView *BKE_scene_add_render_view(struct Scene *sce, const char *name);
bool BKE_scene_remove_render_view(struct Scene *scene, struct SceneRenderView *srv);
-/* render profile */
+/* Render profile. */
+
int get_render_subsurf_level(const struct RenderData *r, int lvl, bool for_render);
int get_render_child_particle_number(const struct RenderData *r, int num, bool for_render);
@@ -174,8 +248,12 @@ bool BKE_scene_uses_blender_eevee(const struct Scene *scene);
bool BKE_scene_uses_blender_workbench(const struct Scene *scene);
bool BKE_scene_uses_cycles(const struct Scene *scene);
-/* Return whether the Cycles experimental feature is enabled. It is invalid to call without first
- * ensuring that Cycles is the active render engine (e.g. with BKE_scene_uses_cycles). */
+/**
+ * Return whether the Cycles experimental feature is enabled. It is invalid to call without first
+ * ensuring that Cycles is the active render engine (e.g. with #BKE_scene_uses_cycles).
+ *
+ * \note We cannot use `const` as RNA_id_pointer_create is not using a const ID.
+ */
bool BKE_scene_uses_cycles_experimental_features(struct Scene *scene);
void BKE_scene_copy_data_eevee(struct Scene *sce_dst, const struct Scene *sce_src);
@@ -191,13 +269,27 @@ int BKE_render_preview_pixel_size(const struct RenderData *r);
/**********************************/
+/**
+ * Apply the needed correction factor to value, based on unit_type
+ * (only length-related are affected currently) and `unit->scale_length`.
+ */
double BKE_scene_unit_scale(const struct UnitSettings *unit, const int unit_type, double value);
-/* multiview */
+/* Multi-view. */
+
bool BKE_scene_multiview_is_stereo3d(const struct RenderData *rd);
+/**
+ * Return whether to render this #SceneRenderView.
+ */
bool BKE_scene_multiview_is_render_view_active(const struct RenderData *rd,
const struct SceneRenderView *srv);
+/**
+ * \return true if `viewname` is the first or if the name is NULL or not found.
+ */
bool BKE_scene_multiview_is_render_view_first(const struct RenderData *rd, const char *viewname);
+/**
+ * \return true if `viewname` is the last or if the name is NULL or not found.
+ */
bool BKE_scene_multiview_is_render_view_last(const struct RenderData *rd, const char *viewname);
int BKE_scene_multiview_num_views_get(const struct RenderData *rd);
struct SceneRenderView *BKE_scene_multiview_render_view_findindex(const struct RenderData *rd,
@@ -208,6 +300,12 @@ int BKE_scene_multiview_view_id_get(const struct RenderData *rd, const char *vie
void BKE_scene_multiview_filepath_get(struct SceneRenderView *srv,
const char *filepath,
char *r_filepath);
+/**
+ * When multi-view is not used the `filepath` is as usual (e.g., `Image.jpg`).
+ * When multi-view is on, even if only one view is enabled the view is incorporated
+ * into the file name (e.g., `Image_L.jpg`). That allows for the user to re-render
+ * individual views.
+ */
void BKE_scene_multiview_view_filepath_get(const struct RenderData *rd,
const char *filepath,
const char *view,
@@ -231,10 +329,14 @@ void BKE_scene_ensure_depsgraph_hash(struct Scene *scene);
void BKE_scene_free_depsgraph_hash(struct Scene *scene);
void BKE_scene_free_view_layer_depsgraph(struct Scene *scene, struct ViewLayer *view_layer);
-/* Do not allocate new depsgraph. */
+/**
+ * \note Do not allocate new depsgraph.
+ */
struct Depsgraph *BKE_scene_get_depsgraph(const struct Scene *scene,
const struct ViewLayer *view_layer);
-/* Allocate new depsgraph if necessary. */
+/**
+ * \note Allocate new depsgraph if necessary.
+ */
struct Depsgraph *BKE_scene_ensure_depsgraph(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer);
@@ -246,6 +348,10 @@ void BKE_scene_transform_orientation_remove(struct Scene *scene,
struct TransformOrientation *orientation);
struct TransformOrientation *BKE_scene_transform_orientation_find(const struct Scene *scene,
const int index);
+/**
+ * \return the index that \a orientation has within \a scene's transform-orientation list
+ * or -1 if not found.
+ */
int BKE_scene_transform_orientation_get_index(const struct Scene *scene,
const struct TransformOrientation *orientation);
diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h
index 5c913ed851f..fd0682ee8f0 100644
--- a/source/blender/blenkernel/BKE_screen.h
+++ b/source/blender/blenkernel/BKE_screen.h
@@ -396,7 +396,8 @@ typedef struct Menu {
struct uiLayout *layout; /* runtime for drawing */
} Menu;
-/* spacetypes */
+/* Space-types. */
+
struct SpaceType *BKE_spacetype_from_id(int spaceid);
struct ARegionType *BKE_regiontype_from_id_or_first(const struct SpaceType *st, int regionid);
struct ARegionType *BKE_regiontype_from_id(const struct SpaceType *st, int regionid);
@@ -405,11 +406,26 @@ void BKE_spacetype_register(struct SpaceType *st);
bool BKE_spacetype_exists(int spaceid);
void BKE_spacetypes_free(void); /* only for quitting blender */
-/* spacedata */
+/* Space-data. */
+
void BKE_spacedata_freelist(ListBase *lb);
-void BKE_spacedata_copylist(ListBase *lb1, ListBase *lb2);
+/**
+ * \param lb_dst: should be empty (will be cleared).
+ */
+void BKE_spacedata_copylist(ListBase *lb_dst, ListBase *lb_src);
+
+/**
+ * Facility to set locks for drawing to survive (render) threads accessing drawing data.
+ *
+ * \note Lock can become bit-flag too.
+ * \note Should be replaced in future by better local data handling for threads.
+ */
void BKE_spacedata_draw_locks(bool set);
+/**
+ * Version of #BKE_area_find_region_type that also works if \a slink
+ * is not the active space of \a area.
+ */
struct ARegion *BKE_spacedata_find_region_type(const struct SpaceLink *slink,
const struct ScrArea *area,
int region_type) ATTR_WARN_UNUSED_RESULT
@@ -417,21 +433,42 @@ struct ARegion *BKE_spacedata_find_region_type(const struct SpaceLink *slink,
void BKE_spacedata_callback_id_remap_set(void (*func)(
struct ScrArea *area, struct SpaceLink *sl, struct ID *old_id, struct ID *new_id));
+/**
+ * Currently unused!
+ */
void BKE_spacedata_id_unref(struct ScrArea *area, struct SpaceLink *sl, struct ID *id);
-/* area/regions */
+/* Area/regions. */
+
struct ARegion *BKE_area_region_copy(const struct SpaceType *st, const struct ARegion *region);
+/**
+ * Doesn't free the region itself.
+ */
void BKE_area_region_free(struct SpaceType *st, struct ARegion *region);
void BKE_area_region_panels_free(struct ListBase *panels);
+/**
+ * Doesn't free the area itself.
+ */
void BKE_screen_area_free(struct ScrArea *area);
-/* Gizmo-maps of a region need to be freed with the region.
- * Uses callback to avoid low-level call. */
+/**
+ * Gizmo-maps of a region need to be freed with the region.
+ * Uses callback to avoid low-level call.
+ */
void BKE_region_callback_free_gizmomap_set(void (*callback)(struct wmGizmoMap *));
void BKE_region_callback_refresh_tag_gizmomap_set(void (*callback)(struct wmGizmoMap *));
+/**
+ * Find a region of type \a region_type in the currently active space of \a area.
+ *
+ * \note This does _not_ work if the region to look up is not in the active space.
+ * Use #BKE_spacedata_find_region_type if that may be the case.
+ */
struct ARegion *BKE_area_find_region_type(const struct ScrArea *area, int type);
struct ARegion *BKE_area_find_region_active_win(struct ScrArea *area);
struct ARegion *BKE_area_find_region_xy(struct ScrArea *area, const int regiontype, int x, int y);
+/**
+ * \note This is only for screen level regions (typically menus/popups).
+ */
struct ARegion *BKE_screen_find_region_xy(struct bScreen *screen,
const int regiontype,
int x,
@@ -442,9 +479,17 @@ struct ARegion *BKE_screen_find_main_region_at_xy(struct bScreen *screen,
const int x,
const int y);
+/**
+ * \note Ideally we can get the area from the context,
+ * there are a few places however where this isn't practical.
+ */
struct ScrArea *BKE_screen_find_area_from_space(struct bScreen *screen,
struct SpaceLink *sl) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1, 2);
+/**
+ * \note Using this function is generally a last resort, you really want to be
+ * using the context when you can - campbell
+ */
struct ScrArea *BKE_screen_find_big_area(struct bScreen *screen,
const int spacetype,
const short min);
@@ -462,15 +507,24 @@ bool BKE_screen_is_fullscreen_area(const struct bScreen *screen) ATTR_WARN_UNUSE
ATTR_NONNULL();
bool BKE_screen_is_used(const struct bScreen *screen) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-/* zoom factor conversion */
+/* Zoom factor conversion. */
+
float BKE_screen_view3d_zoom_to_fac(float camzoom);
float BKE_screen_view3d_zoom_from_fac(float zoomfac);
void BKE_screen_view3d_shading_init(struct View3DShading *shading);
-/* screen */
+/* Screen. */
+
+/**
+ * Callback used by lib_query to walk over all ID usages
+ * (mimics `foreach_id` callback of #IDTypeInfo structure).
+ */
void BKE_screen_foreach_id_screen_area(struct LibraryForeachIDData *data, struct ScrArea *area);
+/**
+ * Free (or release) any data used by this screen (does not free the screen itself).
+ */
void BKE_screen_free_data(struct bScreen *screen);
void BKE_screen_area_map_free(struct ScrAreaMap *area_map) ATTR_NONNULL();
@@ -486,18 +540,28 @@ void BKE_screen_remove_unused_scrverts(struct bScreen *screen);
void BKE_screen_header_alignment_reset(struct bScreen *screen);
/* .blend file I/O */
+
void BKE_screen_view3d_shading_blend_write(struct BlendWriter *writer,
struct View3DShading *shading);
void BKE_screen_view3d_shading_blend_read_data(struct BlendDataReader *reader,
struct View3DShading *shading);
void BKE_screen_area_map_blend_write(struct BlendWriter *writer, struct ScrAreaMap *area_map);
+/**
+ * \return false on error.
+ */
bool BKE_screen_area_map_blend_read_data(struct BlendDataReader *reader,
struct ScrAreaMap *area_map);
+/**
+ * And as patch for 2.48 and older.
+ */
void BKE_screen_view3d_do_versions_250(struct View3D *v3d, ListBase *regions);
void BKE_screen_area_blend_read_lib(struct BlendLibReader *reader,
struct ID *parent_id,
struct ScrArea *area);
+/**
+ * Cannot use #IDTypeInfo callback yet, because of the return value.
+ */
bool BKE_screen_blend_read_data(struct BlendDataReader *reader, struct bScreen *screen);
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_shader_fx.h b/source/blender/blenkernel/BKE_shader_fx.h
index 8d1fe709355..a82112ff967 100644
--- a/source/blender/blenkernel/BKE_shader_fx.h
+++ b/source/blender/blenkernel/BKE_shader_fx.h
@@ -149,17 +149,34 @@ typedef struct ShaderFxTypeInfo {
#define SHADERFX_TYPE_PANEL_PREFIX "FX_PT_"
-/* Initialize global data (type info and some common global storage). */
+/**
+ * Initialize global data (type info and some common global storage).
+ */
void BKE_shaderfx_init(void);
+/**
+ * Get an effect's panel type, which was defined in the #panelRegister callback.
+ *
+ * \note ShaderFx panel types are assumed to be named with the struct name field concatenated to
+ * the defined prefix.
+ */
void BKE_shaderfxType_panel_id(ShaderFxType type, char *r_idname);
void BKE_shaderfx_panel_expand(struct ShaderFxData *fx);
const ShaderFxTypeInfo *BKE_shaderfx_get_info(ShaderFxType type);
struct ShaderFxData *BKE_shaderfx_new(int type);
void BKE_shaderfx_free_ex(struct ShaderFxData *fx, const int flag);
void BKE_shaderfx_free(struct ShaderFxData *fx);
+/**
+ * Check unique name.
+ */
bool BKE_shaderfx_unique_name(struct ListBase *shaderfx, struct ShaderFxData *fx);
bool BKE_shaderfx_depends_ontime(struct ShaderFxData *fx);
+/**
+ * Check whether given shaderfx is not local (i.e. from linked data) when the object is a library
+ * override.
+ *
+ * \param shaderfx: May be NULL, in which case we consider it as a non-local shaderfx case.
+ */
bool BKE_shaderfx_is_nonlocal_in_liboverride(const struct Object *ob,
const struct ShaderFxData *shaderfx);
struct ShaderFxData *BKE_shaderfx_findby_type(struct Object *ob, ShaderFxType type);
@@ -172,6 +189,9 @@ void BKE_shaderfx_copydata_ex(struct ShaderFxData *fx,
void BKE_shaderfx_copy(struct ListBase *dst, const struct ListBase *src);
void BKE_shaderfx_foreach_ID_link(struct Object *ob, ShaderFxIDWalkFunc walk, void *userData);
+/**
+ * Check if exist grease pencil effects.
+ */
bool BKE_shaderfx_has_gpencil(const struct Object *ob);
void BKE_shaderfx_blend_write(struct BlendWriter *writer, struct ListBase *fxbase);
diff --git a/source/blender/blenkernel/BKE_shrinkwrap.h b/source/blender/blenkernel/BKE_shrinkwrap.h
index 70aeb37d995..088b270bfed 100644
--- a/source/blender/blenkernel/BKE_shrinkwrap.h
+++ b/source/blender/blenkernel/BKE_shrinkwrap.h
@@ -34,11 +34,11 @@ extern "C" {
* Shrinkwrap is composed by a set of functions and options that define the type of shrink.
*
* 3 modes are available:
- * - Nearest vertex
- * - Nearest surface
- * - Normal projection
+ * - Nearest vertex.
+ * - Nearest surface.
+ * - Normal projection.
*
- * ShrinkwrapCalcData encapsulates all needed data for shrinkwrap functions.
+ * #ShrinkwrapCalcData encapsulates all needed data for shrink-wrap functions.
* (So that you don't have to pass an enormous amount of arguments to functions)
*/
@@ -48,6 +48,7 @@ struct Mesh;
struct ModifierEvalContext;
struct Object;
struct ShrinkwrapModifierData;
+struct ShrinkwrapGpencilModifierData;
struct SpaceTransform;
/* Information about boundary edges in the mesh. */
@@ -74,6 +75,9 @@ typedef struct ShrinkwrapBoundaryData {
const ShrinkwrapBoundaryVertData *boundary_verts;
} ShrinkwrapBoundaryData;
+/**
+ * Free boundary data for target project.
+ */
void BKE_shrinkwrap_discard_boundary_data(struct Mesh *mesh);
void BKE_shrinkwrap_compute_boundary_data(struct Mesh *mesh);
@@ -89,20 +93,28 @@ typedef struct ShrinkwrapTreeData {
ShrinkwrapBoundaryData *boundary;
} ShrinkwrapTreeData;
-/* Checks if the modifier needs target normals with these settings. */
+/**
+ * Checks if the modifier needs target normals with these settings.
+ */
bool BKE_shrinkwrap_needs_normals(int shrinkType, int shrinkMode);
-/* Initializes the mesh data structure from the given mesh and settings. */
+/**
+ * Initializes the mesh data structure from the given mesh and settings.
+ */
bool BKE_shrinkwrap_init_tree(struct ShrinkwrapTreeData *data,
Mesh *mesh,
int shrinkType,
int shrinkMode,
bool force_normals);
-/* Frees the tree data if necessary. */
+/**
+ * Frees the tree data if necessary.
+ */
void BKE_shrinkwrap_free_tree(struct ShrinkwrapTreeData *data);
-/* Implementation of the Shrinkwrap modifier */
+/**
+ * Main shrink-wrap function (implementation of the shrink-wrap modifier).
+ */
void shrinkwrapModifier_deform(struct ShrinkwrapModifierData *smd,
const struct ModifierEvalContext *ctx,
struct Scene *scene,
@@ -112,27 +124,44 @@ void shrinkwrapModifier_deform(struct ShrinkwrapModifierData *smd,
const int defgrp_index,
float (*vertexCos)[3],
int numVerts);
-
-/* Used in editmesh_mask_extract.c to shrinkwrap the extracted mesh to the sculpt */
+/* Implementation of the Shrinkwrap Grease Pencil modifier. */
+void shrinkwrapGpencilModifier_deform(struct ShrinkwrapGpencilModifierData *mmd,
+ struct Object *ob,
+ struct MDeformVert *dvert,
+ const int defgrp_index,
+ float (*vertexCos)[3],
+ int numVerts);
+
+/**
+ * Used in `editmesh_mask_extract.c` to shrink-wrap the extracted mesh to the sculpt.
+ */
void BKE_shrinkwrap_mesh_nearest_surface_deform(struct bContext *C,
struct Object *ob_source,
struct Object *ob_target);
-/* Used in object_remesh.cc to preserve the details and volume in the voxel remesher */
+/**
+ * Used in `object_remesh.cc` to preserve the details and volume in the voxel remesher.
+ */
void BKE_shrinkwrap_remesh_target_project(struct Mesh *src_me,
struct Mesh *target_me,
struct Object *ob_target);
-/*
- * This function casts a ray in the given BVHTree.
- * but it takes into consideration the space_transform, that is:
+/**
+ * This function ray-cast a single vertex and updates the hit if the "hit" is considered valid.
*
- * if transf was configured with "SPACE_TRANSFORM_SETUP( &transf, ob1, ob2 )"
- * then the input (vert, dir, BVHTreeRayHit) must be defined in ob1 coordinates space
- * and the BVHTree must be built in ob2 coordinate space.
+ * \param options: Opts control whether an hit is valid or not.
+ * Supported options are:
+ * - #MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE (front faces hits are ignored)
+ * - #MOD_SHRINKWRAP_CULL_TARGET_BACKFACE (back faces hits are ignored)
*
+ * \param transf: Take into consideration the space_transform, that is:
+ * if `transf` was configured with `SPACE_TRANSFORM_SETUP( &transf, ob1, ob2)`
+ * then the input (vert, dir, #BVHTreeRayHit) must be defined in ob1 coordinates space
+ * and the #BVHTree must be built in ob2 coordinate space.
* Thus it provides an easy way to cast the same ray across several trees
- * (where each tree was built on its own coords space)
+ * (where each tree was built on its own coords space).
+ *
+ * \return true if "hit" was updated.
*/
bool BKE_shrinkwrap_project_normal(char options,
const float vert[3],
@@ -142,14 +171,21 @@ bool BKE_shrinkwrap_project_normal(char options,
struct ShrinkwrapTreeData *tree,
BVHTreeRayHit *hit);
-/* Maps the point to the nearest surface, either by simple nearest,
- * or by target normal projection. */
+/**
+ * Maps the point to the nearest surface, either by simple nearest, or by target normal projection.
+ */
void BKE_shrinkwrap_find_nearest_surface(struct ShrinkwrapTreeData *tree,
struct BVHTreeNearest *nearest,
float co[3],
int type);
-/* Computes a smooth normal of the target (if applicable) at the hit location. */
+/**
+ * Compute a smooth normal of the target (if applicable) at the hit location.
+ *
+ * \param tree: information about the mesh.
+ * \param transform: transform from the hit coordinate space to the object space; may be null.
+ * \param r_no: output in hit coordinate space; may be shared with inputs.
+ */
void BKE_shrinkwrap_compute_smooth_normal(const struct ShrinkwrapTreeData *tree,
const struct SpaceTransform *transform,
int looptri_idx,
@@ -157,7 +193,13 @@ void BKE_shrinkwrap_compute_smooth_normal(const struct ShrinkwrapTreeData *tree,
const float hit_no[3],
float r_no[3]);
-/* Apply the shrink to surface modes to the given original coordinates and nearest point. */
+/**
+ * Apply the shrink to surface modes to the given original coordinates and nearest point.
+ *
+ * \param tree: mesh data for smooth normals.
+ * \param transform: transform from the hit coordinate space to the object space; may be null.
+ * \param r_point_co: may be the same memory location as `point_co`, `hit_co`, or `hit_no`.
+ */
void BKE_shrinkwrap_snap_point_to_surface(const struct ShrinkwrapTreeData *tree,
const struct SpaceTransform *transform,
int mode,
diff --git a/source/blender/blenkernel/BKE_softbody.h b/source/blender/blenkernel/BKE_softbody.h
index 58dc90f62dc..5d010fa2155 100644
--- a/source/blender/blenkernel/BKE_softbody.h
+++ b/source/blender/blenkernel/BKE_softbody.h
@@ -46,16 +46,24 @@ typedef struct BodyPoint {
float springweight;
} BodyPoint;
-/* allocates and initializes general main data */
+/**
+ * Allocates and initializes general main data.
+ */
extern struct SoftBody *sbNew(void);
-/* frees internal data and soft-body itself */
+/**
+ * Frees internal data and soft-body itself.
+ */
extern void sbFree(struct Object *ob);
-/* frees simulation data to reset simulation */
+/**
+ * Frees simulation data to reset simulation.
+ */
extern void sbFreeSimulation(struct SoftBody *sb);
-/* do one simul step, reading and writing vertex locs from given array */
+/**
+ * Do one simulation step, reading and writing vertex locs from given array.
+ * */
extern void sbObjectStep(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
@@ -63,13 +71,30 @@ extern void sbObjectStep(struct Depsgraph *depsgraph,
float (*vertexCos)[3],
int numVerts);
-/* makes totally fresh start situation, resets time */
+/**
+ * Makes totally fresh start situation, resets time.
+ */
extern void sbObjectToSoftbody(struct Object *ob);
-/* links the soft-body module to a 'test for Interrupt' function */
-/* pass NULL to unlink again */
+/**
+ * Soft-body global visible functions.
+ * Links the soft-body module to a 'test for Interrupt' function, pass NULL to clear the callback.
+ */
extern void sbSetInterruptCallBack(int (*f)(void));
+/**
+ * A precise position vector denoting the motion of the center of mass give a rotation/scale matrix
+ * using averaging method, that's why estimate and not calculate see: this is kind of reverse
+ * engineering: having to states of a point cloud and recover what happened our advantage here we
+ * know the identity of the vertex there are others methods giving other results.
+ *
+ * \param ob: Any object that can do soft-body e.g. mesh, lattice, curve.
+ * \param lloc: Output of the calculated location (or NULL).
+ * \param lrot: Output of the calculated rotation (or NULL).
+ * \param lscale: Output for the calculated scale (or NULL).
+ *
+ * For velocity & 2nd order stuff see: #vcloud_estimate_transform_v3.
+ */
extern void SB_estimate_transform(Object *ob, float lloc[3], float lrot[3][3], float lscale[3][3]);
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_spline.hh b/source/blender/blenkernel/BKE_spline.hh
index c332e9a8dac..ebdc4a0ca0b 100644
--- a/source/blender/blenkernel/BKE_spline.hh
+++ b/source/blender/blenkernel/BKE_spline.hh
@@ -40,7 +40,8 @@ using SplinePtr = std::unique_ptr<Spline>;
/**
* A spline is an abstraction of a single branch-less curve section, its evaluation methods,
* and data. The spline data itself is just control points and a set of attributes by the set
- * of "evaluated" data is often used instead.
+ * of "evaluated" data is often used instead. Conceptually, the derived vs. original data is
+ * an essential distinction. Derived data is usually calculated lazily and cached on the spline.
*
* Any derived class of Spline has to manage two things:
* 1. Interpolating arbitrary attribute data from the control points to evaluated points.
@@ -106,8 +107,17 @@ class Spline {
copy_base_settings(other, *this);
}
+ /**
+ * Return a new spline with the same data, settings, and attributes.
+ */
SplinePtr copy() const;
+ /**
+ * Return a new spline with the same type and settings like "cyclic", but without any data.
+ */
SplinePtr copy_only_settings() const;
+ /**
+ * The same as #copy, but skips copying dynamic attributes to the new spline.
+ */
SplinePtr copy_without_attributes() const;
static void copy_base_settings(const Spline &src, Spline &dst);
@@ -147,8 +157,22 @@ class Spline {
virtual blender::Span<blender::float3> evaluated_positions() const = 0;
+ /**
+ * Return non-owning access to the cache of accumulated lengths along the spline. Each item is
+ * the length of the subsequent segment, i.e. the first value is the length of the first segment
+ * rather than 0. This calculation is rather trivial, and only depends on the evaluated
+ * positions. However, the results are used often, and it is necessarily single threaded, so it
+ * is cached.
+ */
blender::Span<float> evaluated_lengths() const;
+ /**
+ * Return non-owning access to the direction of the curve at each evaluated point.
+ */
blender::Span<blender::float3> evaluated_tangents() const;
+ /**
+ * Return non-owning access to the direction vectors perpendicular to the tangents at every
+ * evaluated point. The method used to generate the normal vectors depends on Spline.normal_mode.
+ */
blender::Span<blender::float3> evaluated_normals() const;
void bounds_min_max(blender::float3 &min, blender::float3 &max, const bool use_evaluated) const;
@@ -172,12 +196,32 @@ class Spline {
*/
float factor;
};
+ /**
+ * Find the position on the evaluated spline at the given portion of the total length.
+ * The return value is the indices of the two neighboring points at that location and the
+ * factor between them, which can be used to look up any attribute on the evaluated points.
+ * \note This does not support extrapolation.
+ */
LookupResult lookup_evaluated_factor(const float factor) const;
+ /**
+ * The same as #lookup_evaluated_factor, but looks up a length directly instead of
+ * a portion of the total.
+ */
LookupResult lookup_evaluated_length(const float length) const;
+ /**
+ * Return an array of evenly spaced samples along the length of the spline. The samples are
+ * indices and factors to the next index encoded in floats. The logic for converting from the
+ * float values to interpolation data is in #lookup_data_from_index_factor.
+ */
blender::Array<float> sample_uniform_index_factors(const int samples_size) const;
LookupResult lookup_data_from_index_factor(const float index_factor) const;
+ /**
+ * Sample any input data with a value for each evaluated point (already interpolated to evaluated
+ * points) to arbitrary parameters in between the evaluated points. The interpolation is quite
+ * simple, but this handles the cyclic and end point special cases.
+ */
void sample_with_index_factors(const blender::fn::GVArray &src,
blender::Span<float> index_factors,
blender::fn::GMutableSpan dst) const;
@@ -286,6 +330,9 @@ class BezierSpline final : public Spline {
int resolution() const;
void set_resolution(const int value);
+ /**
+ * \warning Call #reallocate on the spline's attributes after adding all points.
+ */
void add_point(const blender::float3 position,
const HandleType handle_type_left,
const blender::float3 handle_position_left,
@@ -321,12 +368,24 @@ class BezierSpline final : public Spline {
* uninitialized memory while auto-generating handles.
*/
blender::MutableSpan<blender::float3> handle_positions_right(bool write_only = false);
+ /**
+ * Recalculate all #Auto and #Vector handles with positions automatically
+ * derived from the neighboring control points.
+ */
void ensure_auto_handles() const;
void translate(const blender::float3 &translation) override;
void transform(const blender::float4x4 &matrix) override;
+ /**
+ * Set positions for the right handle of the control point, ensuring that
+ * aligned handles stay aligned. Has no effect for auto and vector type handles.
+ */
void set_handle_position_right(const int index, const blender::float3 &value);
+ /**
+ * Set positions for the left handle of the control point, ensuring that
+ * aligned handles stay aligned. Has no effect for auto and vector type handles.
+ */
void set_handle_position_left(const int index, const blender::float3 &value);
bool point_is_sharp(const int index) const;
@@ -334,7 +393,22 @@ class BezierSpline final : public Spline {
void mark_cache_invalid() final;
int evaluated_points_size() const final;
+ /**
+ * Returns access to a cache of offsets into the evaluated point array for each control point.
+ * While most control point edges generate the number of edges specified by the resolution,
+ * vector segments only generate one edge.
+ *
+ * \note The length of the result is one greater than the number of points, so that the last item
+ * is the total number of evaluated points. This is useful to avoid recalculating the size of the
+ * last segment everywhere.
+ */
blender::Span<int> control_point_offsets() const;
+ /**
+ * Returns non-owning access to an array of values containing the information necessary to
+ * interpolate values from the original control points to evaluated points. The control point
+ * index is the integer part of each value, and the factor used for interpolating to the next
+ * control point is the remaining factional part.
+ */
blender::Span<float> evaluated_mappings() const;
blender::Span<blender::float3> evaluated_positions() const final;
struct InterpolationData {
@@ -346,6 +420,11 @@ class BezierSpline final : public Spline {
*/
float factor;
};
+ /**
+ * Convert the data encoded in #evaulated_mappings into its parts-- the information necessary
+ * to interpolate data from control points to evaluated points between them. The next control
+ * point index result will not overflow the size of the control point vectors.
+ */
InterpolationData interpolation_data_from_index_factor(const float index_factor) const;
virtual blender::fn::GVArray interpolate_to_evaluated(
@@ -354,6 +433,9 @@ class BezierSpline final : public Spline {
void evaluate_segment(const int index,
const int next_index,
blender::MutableSpan<blender::float3> positions) const;
+ /**
+ * \warning This functional assumes that the spline has more than one point.
+ */
bool segment_is_vector(const int start_index) const;
/** See comment and diagram for #calculate_segment_insertion. */
@@ -364,11 +446,36 @@ class BezierSpline final : public Spline {
blender::float3 right_handle;
blender::float3 handle_next;
};
+ /**
+ * De Casteljau Bezier subdivision.
+ * \param index: The index of the segment's start control point.
+ * \param next_index: The index of the control point at the end of the segment. Could be 0,
+ * if the spline is cyclic.
+ * \param parameter: The factor along the segment, between 0 and 1. Note that this is used
+ * directly by the calculation, it doesn't correspond to a portion of the evaluated length.
+ *
+ * <pre>
+ * handle_prev handle_next
+ * x----------------x
+ * / \
+ * / x---O---x \
+ * / result \
+ * / \
+ * O O
+ * point_prev point_next
+ * </pre>
+ */
InsertResult calculate_segment_insertion(const int index,
const int next_index,
const float parameter);
private:
+ /**
+ * If the spline is not cyclic, the direction for the first and last points is just the
+ * direction formed by the corresponding handles and control points. In the unlikely situation
+ * that the handles define a zero direction, fallback to using the direction defined by the
+ * first and last evaluated segments already calculated in #Spline::evaluated_tangents().
+ */
void correct_end_tangents() const final;
void copy_settings(Spline &dst) const final;
void copy_data(Spline &dst) const final;
@@ -460,6 +567,9 @@ class NURBSpline final : public Spline {
uint8_t order() const;
void set_order(const uint8_t value);
+ /**
+ * \warning Call #reallocate on the spline's attributes after adding all points.
+ */
void add_point(const blender::float3 position,
const float radius,
const float tilt,
@@ -498,9 +608,12 @@ class NURBSpline final : public Spline {
};
/**
- * A Poly spline is like a bezier spline with a resolution of one. The main reason to distinguish
+ * A Poly spline is like a Bézier spline with a resolution of one. The main reason to distinguish
* the two is for reduced complexity and increased performance, since interpolating data to control
* points does not change it.
+ *
+ * Poly spline code is very simple, since it doesn't do anything that the base #Spline doesn't
+ * handle. Mostly it just worries about storing the data used by the base class.
*/
class PolySpline final : public Spline {
blender::Vector<blender::float3> positions_;
@@ -521,6 +634,9 @@ class PolySpline final : public Spline {
int size() const final;
+ /**
+ * \warning Call #reallocate on the spline's attributes after adding all points.
+ */
void add_point(const blender::float3 position, const float radius, const float tilt);
void resize(const int size) final;
@@ -536,6 +652,12 @@ class PolySpline final : public Spline {
blender::Span<blender::float3> evaluated_positions() const final;
+ /**
+ * Poly spline interpolation from control points to evaluated points is a special case, since
+ * the result data is the same as the input data. This function returns a #GVArray that points to
+ * the original data. Therefore the lifetime of the returned virtual array must not be longer
+ * than the source data.
+ */
blender::fn::GVArray interpolate_to_evaluated(const blender::fn::GVArray &src) const final;
protected:
@@ -546,8 +668,12 @@ class PolySpline final : public Spline {
};
/**
- * A #CurveEval corresponds to the #Curve object data. The name is different for clarity, since
- * more of the data is stored in the splines, but also just to be different than the name in DNA.
+ * A collection of #Spline objects with the same attribute types and names. Most data and
+ * functionality is in splines, but this contains some helpers for working with them as a group.
+ *
+ * \note A #CurveEval corresponds to the #Curve object data. The name is different for clarity,
+ * since more of the data is stored in the splines, but also just to be different than the name in
+ * DNA.
*/
struct CurveEval {
private:
@@ -566,22 +692,56 @@ struct CurveEval {
blender::Span<SplinePtr> splines() const;
blender::MutableSpan<SplinePtr> splines();
+ /**
+ * \return True if the curve contains a spline with the given type.
+ *
+ * \note If you are looping over all of the splines in the same scope anyway,
+ * it's better to avoid calling this function, in case there are many splines.
+ */
bool has_spline_with_type(const Spline::Type type) const;
void resize(const int size);
+ /**
+ * \warning Call #reallocate on the spline's attributes after adding all splines.
+ */
void add_spline(SplinePtr spline);
+ void add_splines(blender::MutableSpan<SplinePtr> splines);
void remove_splines(blender::IndexMask mask);
void translate(const blender::float3 &translation);
void transform(const blender::float4x4 &matrix);
void bounds_min_max(blender::float3 &min, blender::float3 &max, const bool use_evaluated) const;
+ /**
+ * Return the start indices for each of the curve spline's control points, if they were part
+ * of a flattened array. This can be used to facilitate parallelism by avoiding the need to
+ * accumulate an offset while doing more complex calculations.
+ *
+ * \note The result is one longer than the spline count; the last element is the total size.
+ */
blender::Array<int> control_point_offsets() const;
+ /**
+ * Exactly like #control_point_offsets, but uses the number of evaluated points instead.
+ */
blender::Array<int> evaluated_point_offsets() const;
+ /**
+ * Return the accumulated length at the start of every spline in the curve.
+ * \note The result is one longer than the spline count; the last element is the total length.
+ */
blender::Array<float> accumulated_spline_lengths() const;
+ float total_length() const;
+ int total_control_point_size() const;
+
void mark_cache_invalid();
+ /**
+ * Check the invariants that curve control point attributes should always uphold, necessary
+ * because attributes are stored on splines rather than in a flat array on the curve:
+ * - The same set of attributes exists on every spline.
+ * - Attributes with the same name have the same type on every spline.
+ * - Attributes are in the same order on every spline.
+ */
void assert_valid_point_attributes() const;
};
diff --git a/source/blender/blenkernel/BKE_studiolight.h b/source/blender/blenkernel/BKE_studiolight.h
index 59b1c2b28d9..792186dd260 100644
--- a/source/blender/blenkernel/BKE_studiolight.h
+++ b/source/blender/blenkernel/BKE_studiolight.h
@@ -143,6 +143,8 @@ typedef struct StudioLight {
void *free_function_data;
} StudioLight;
+/* API */
+
void BKE_studiolight_init(void);
void BKE_studiolight_free(void);
void BKE_studiolight_default(SolidLight lights[4], float light_ambient[3]);
@@ -151,12 +153,18 @@ struct StudioLight *BKE_studiolight_findindex(int index, int flag);
struct StudioLight *BKE_studiolight_find_default(int flag);
void BKE_studiolight_preview(uint *icon_buffer, StudioLight *sl, int icon_id_type);
struct ListBase *BKE_studiolight_listbase(void);
+/**
+ * Ensure state of studio-lights.
+ */
void BKE_studiolight_ensure_flag(StudioLight *sl, int flag);
void BKE_studiolight_refresh(void);
StudioLight *BKE_studiolight_load(const char *path, int type);
StudioLight *BKE_studiolight_create(const char *path,
const SolidLight light[4],
const float light_ambient[3]);
+/**
+ * Only useful for workbench while editing the user-preferences.
+ */
StudioLight *BKE_studiolight_studio_edit_get(void);
void BKE_studiolight_remove(StudioLight *sl);
void BKE_studiolight_set_free_function(StudioLight *sl,
diff --git a/source/blender/blenkernel/BKE_subsurf.h b/source/blender/blenkernel/BKE_subsurf.h
index 3816a822279..db57076082c 100644
--- a/source/blender/blenkernel/BKE_subsurf.h
+++ b/source/blender/blenkernel/BKE_subsurf.h
@@ -66,18 +66,30 @@ struct DerivedMesh *subsurf_make_derived_from_derived(struct DerivedMesh *dm,
void subsurf_calculate_limit_positions(struct Mesh *me, float (*r_positions)[3]);
-/* get gridsize from 'level', level must be greater than zero */
+/**
+ * Get grid-size from 'level', level must be greater than zero.
+ */
int BKE_ccg_gridsize(int level);
-/* x/y grid coordinates at 'low_level' can be multiplied by the result
- * of this function to convert to grid coordinates at 'high_level' */
+/**
+ * X/Y grid coordinates at 'low_level' can be multiplied by the result
+ * of this function to convert to grid coordinates at 'high_level'.
+ */
int BKE_ccg_factor(int low_level, int high_level);
+/**
+ * Translate #GridHidden into the #ME_HIDE flag for MVerts. Assumes
+ * vertices are in the order output by #ccgDM_copyFinalVertArray.
+ */
void subsurf_copy_grid_hidden(struct DerivedMesh *dm,
const struct MPoly *mpoly,
struct MVert *mvert,
const struct MDisps *mdisps);
+/**
+ * Translate #GridPaintMask into vertex paint masks. Assumes vertices
+ * are in the order output by #ccgDM_copyFinalVertArray.
+ */
void subsurf_copy_grid_paint_mask(struct DerivedMesh *dm,
const struct MPoly *mpoly,
float *paint_mask,
diff --git a/source/blender/blenkernel/BKE_text.h b/source/blender/blenkernel/BKE_text.h
index c7120c60020..a979ba6d2cc 100644
--- a/source/blender/blenkernel/BKE_text.h
+++ b/source/blender/blenkernel/BKE_text.h
@@ -30,17 +30,44 @@ struct Main;
struct Text;
struct TextLine;
+/**
+ * \note caller must handle `compiled` member.
+ */
void BKE_text_free_lines(struct Text *text);
struct Text *BKE_text_add(struct Main *bmain, const char *name);
+/**
+ * Use to a valid UTF-8 sequences.
+ * this function replaces extended ascii characters.
+ */
int txt_extended_ascii_as_utf8(char **str);
bool BKE_text_reload(struct Text *text);
+/**
+ * Load a text file.
+ *
+ * \param is_internal: If \a true, this text data-block only exists in memory,
+ * not as a file on disk.
+ *
+ * \note text data-blocks have no real user but have 'fake user' enabled by default
+ */
struct Text *BKE_text_load_ex(struct Main *bmain,
const char *file,
const char *relpath,
const bool is_internal);
+/**
+ * Load a text file.
+ *
+ * \note Text data-blocks have no user by default, only the 'real user' flag.
+ */
struct Text *BKE_text_load(struct Main *bmain, const char *file, const char *relpath);
void BKE_text_clear(struct Text *text);
void BKE_text_write(struct Text *text, const char *str);
+/**
+ * \return codes:
+ * - 0 if file on disk is the same or Text is in memory only.
+ * - 1 if file has been modified on disk since last local edit.
+ * - 2 if file on disk has been deleted.
+ * - -1 is returned if an error occurs.
+ */
int BKE_text_file_modified_check(struct Text *text);
void BKE_text_file_modified_ignore(struct Text *text);
@@ -61,12 +88,20 @@ void txt_move_eof(struct Text *text, const bool sel);
void txt_move_bol(struct Text *text, const bool sel);
void txt_move_eol(struct Text *text, const bool sel);
void txt_move_toline(struct Text *text, unsigned int line, const bool sel);
+/**
+ * Moves to a certain byte in a line, not a certain utf8-character.
+ */
void txt_move_to(struct Text *text, unsigned int line, unsigned int ch, const bool sel);
void txt_pop_sel(struct Text *text);
void txt_delete_char(struct Text *text);
void txt_delete_word(struct Text *text);
void txt_delete_selected(struct Text *text);
void txt_sel_all(struct Text *text);
+/**
+ * Reverse of #txt_pop_sel
+ * Clears the selection and ensures the cursor is located
+ * at the selection (where the cursor is visually while editing).
+ */
void txt_sel_clear(struct Text *text);
void txt_sel_line(struct Text *text);
void txt_sel_set(struct Text *text, int startl, int startc, int endl, int endc);
@@ -91,7 +126,9 @@ bool txt_cursor_is_line_end(const struct Text *text);
int txt_calc_tab_left(struct TextLine *tl, int ch);
int txt_calc_tab_right(struct TextLine *tl, int ch);
-/* Utility functions, could be moved somewhere more generic but are python/text related. */
+/**
+ * Utility functions, could be moved somewhere more generic but are python/text related.
+ */
int text_check_bracket(const char ch);
bool text_check_delim(const char ch);
bool text_check_digit(const char ch);
@@ -100,7 +137,7 @@ bool text_check_identifier_nodigit(const char ch);
bool text_check_whitespace(const char ch);
int text_find_identifier_start(const char *str, int i);
-/* defined in bpy_interface.c */
+/* EVIL: defined in `bpy_interface.c`. */
extern int text_check_identifier_unicode(const unsigned int ch);
extern int text_check_identifier_nodigit_unicode(const unsigned int ch);
@@ -110,7 +147,14 @@ enum {
};
/* Fast non-validating buffer conversion for undo. */
+
+/**
+ * Create a buffer, the only requirement is #txt_from_buf_for_undo can decode it.
+ */
char *txt_to_buf_for_undo(struct Text *text, int *r_buf_len);
+/**
+ * Decode a buffer from #txt_to_buf_for_undo.
+ */
void txt_from_buf_for_undo(struct Text *text, const char *buf, int buf_len);
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_texture.h b/source/blender/blenkernel/BKE_texture.h
index ef322d0cd31..380b5cf035c 100644
--- a/source/blender/blenkernel/BKE_texture.h
+++ b/source/blender/blenkernel/BKE_texture.h
@@ -42,6 +42,9 @@ struct TexResult;
/** #ColorBand.data length. */
#define MAXCOLORBAND 32
+/**
+ * Utility for all IDs using those texture slots.
+ */
void BKE_texture_mtex_foreach_id(struct LibraryForeachIDData *data, struct MTex *mtex);
void BKE_texture_default(struct Tex *tex);
@@ -50,6 +53,9 @@ void BKE_texture_type_set(struct Tex *tex, int type);
void BKE_texture_mtex_default(struct MTex *mtex);
struct MTex *BKE_texture_mtex_add(void);
+/**
+ * Slot -1 for first free ID.
+ */
struct MTex *BKE_texture_mtex_add_id(struct ID *id, int slot);
/* UNUSED */
// void autotexname(struct Tex *tex);
@@ -79,6 +85,9 @@ struct PointDensity *BKE_texture_pointdensity_add(void);
struct PointDensity *BKE_texture_pointdensity_copy(const struct PointDensity *pd, const int flag);
bool BKE_texture_dependsOnTime(const struct Tex *texture);
+/**
+ * \returns true if this texture can use its #Texture.ima (even if its NULL).
+ */
bool BKE_texture_is_image_user(const struct Tex *tex);
void BKE_texture_get_value_ex(const struct Scene *scene,
@@ -94,6 +103,9 @@ void BKE_texture_get_value(const struct Scene *scene,
struct TexResult *texres,
bool use_color_management);
+/**
+ * Make sure all images used by texture are loaded into pool.
+ */
void BKE_texture_fetch_images_for_pool(struct Tex *texture, struct ImagePool *pool);
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_tracking.h b/source/blender/blenkernel/BKE_tracking.h
index 47145a7d6bd..9caf5d31765 100644
--- a/source/blender/blenkernel/BKE_tracking.h
+++ b/source/blender/blenkernel/BKE_tracking.h
@@ -46,20 +46,53 @@ struct rcti;
/* **** Common functions **** */
+/**
+ * Free tracking structure, only frees structure contents
+ * (if structure is allocated in heap, it shall be handled outside).
+ *
+ * All the pointers inside structure becomes invalid after this call.
+ */
void BKE_tracking_free(struct MovieTracking *tracking);
+/**
+ * Copy tracking structure content.
+ */
void BKE_tracking_copy(struct MovieTracking *tracking_dst,
const struct MovieTracking *tracking_src,
const int flag);
+/**
+ * Initialize motion tracking settings to default values,
+ * used when new movie clip data-block is created.
+ */
void BKE_tracking_settings_init(struct MovieTracking *tracking);
+/**
+ * Get list base of active object's tracks.
+ */
struct ListBase *BKE_tracking_get_active_tracks(struct MovieTracking *tracking);
+/**
+ * Get list base of active object's plane tracks.
+ */
struct ListBase *BKE_tracking_get_active_plane_tracks(struct MovieTracking *tracking);
+/**
+ * Get reconstruction data of active object.
+ */
struct MovieTrackingReconstruction *BKE_tracking_get_active_reconstruction(
struct MovieTracking *tracking);
-/* matrices for constraints and drawing */
+/* Matrices for constraints and drawing. */
+
+/**
+ * Get transformation matrix for a given object which is used
+ * for parenting motion tracker reconstruction to 3D world.
+ */
void BKE_tracking_get_camera_object_matrix(struct Object *camera_object, float mat[4][4]);
+/**
+ * Get projection matrix for camera specified by given tracking object
+ * and frame number.
+ *
+ * \note frame number should be in clip space, not scene space.
+ */
void BKE_tracking_get_projection_matrix(struct MovieTracking *tracking,
struct MovieTrackingObject *object,
int framenr,
@@ -68,16 +101,45 @@ void BKE_tracking_get_projection_matrix(struct MovieTracking *tracking,
float mat[4][4]);
/* **** Clipboard **** */
+/**
+ * Free clipboard by freeing memory used by all tracks in it.
+ */
void BKE_tracking_clipboard_free(void);
+/**
+ * Copy selected tracks from specified object to the clipboard.
+ */
void BKE_tracking_clipboard_copy_tracks(struct MovieTracking *tracking,
struct MovieTrackingObject *object);
+/**
+ * Check whether there are any tracks in the clipboard.
+ */
bool BKE_tracking_clipboard_has_tracks(void);
+/**
+ * Paste tracks from clipboard to specified object.
+ *
+ * Names of new tracks in object are guaranteed to be unique here.
+ */
void BKE_tracking_clipboard_paste_tracks(struct MovieTracking *tracking,
struct MovieTrackingObject *object);
/* **** Track **** */
+
+/**
+ * Add new empty track to the given list of tracks.
+ *
+ * It is required that caller will append at least one marker to avoid degenerate tracks.
+ */
struct MovieTrackingTrack *BKE_tracking_track_add_empty(struct MovieTracking *tracking,
struct ListBase *tracks_list);
+/**
+ * Add new track to a specified tracks base.
+ *
+ * Coordinates are expected to be in normalized 0..1 space,
+ * frame number is expected to be in clip space.
+ *
+ * Width and height are clip's dimension used to scale track's
+ * pattern and search regions.
+ */
struct MovieTrackingTrack *BKE_tracking_track_add(struct MovieTracking *tracking,
struct ListBase *tracksbase,
float x,
@@ -85,14 +147,35 @@ struct MovieTrackingTrack *BKE_tracking_track_add(struct MovieTracking *tracking
int framenr,
int width,
int height);
+/**
+ * Duplicate the specified track, result will no belong to any list.
+ */
struct MovieTrackingTrack *BKE_tracking_track_duplicate(struct MovieTrackingTrack *track);
+/**
+ * Ensure specified track has got unique name,
+ * if it's not name of specified track will be changed
+ * keeping names of all other tracks unchanged.
+ */
void BKE_tracking_track_unique_name(struct ListBase *tracksbase, struct MovieTrackingTrack *track);
+/**
+ * Free specified track, only frees contents of a structure
+ * (if track is allocated in heap, it shall be handled outside).
+ *
+ * All the pointers inside track becomes invalid after this call.
+ */
void BKE_tracking_track_free(struct MovieTrackingTrack *track);
+/**
+ * Get frame numbers of the very first and last markers.
+ * There is no check on whether the marker is enabled or not.
+ */
void BKE_tracking_track_first_last_frame_get(const struct MovieTrackingTrack *track,
int *r_first_frame,
int *r_last_frame);
+/**
+ * Find the minimum starting frame and maximum ending frame within given set of tracks.
+ */
void BKE_tracking_tracks_first_last_frame_minmax(/*const*/ struct MovieTrackingTrack **tracks,
const int num_tracks,
int *r_first_frame,
@@ -101,17 +184,50 @@ void BKE_tracking_tracks_first_last_frame_minmax(/*const*/ struct MovieTrackingT
int BKE_tracking_count_selected_tracks_in_list(const struct ListBase *tracks_list);
int BKE_tracking_count_selected_tracks_in_active_object(/*const*/ struct MovieTracking *tracking);
-/* Get array of selected tracks from the current active object in the tracking structure.
- * If nothing is selected then the result is nullptr and `r_num_tracks` is set to 0. */
+/**
+ * Get array of selected tracks from the current active object in the tracking structure.
+ * If nothing is selected then the result is nullptr and `r_num_tracks` is set to 0.
+ */
struct MovieTrackingTrack **BKE_tracking_selected_tracks_in_active_object(
struct MovieTracking *tracking, int *r_num_tracks);
+/**
+ * Set flag for all specified track's areas.
+ *
+ * \param area: which part of marker should be selected. see TRACK_AREA_* constants.
+ * \param flag: flag to be set for areas.
+ */
void BKE_tracking_track_flag_set(struct MovieTrackingTrack *track, int area, int flag);
+/**
+ * Clear flag from all specified track's areas.
+ *
+ * \param area: which part of marker should be selected. see TRACK_AREA_* constants.
+ * \param flag: flag to be cleared for areas.
+ */
void BKE_tracking_track_flag_clear(struct MovieTrackingTrack *track, int area, int flag);
+/**
+ * Check whether track has got marker at specified frame.
+ *
+ * \note frame number should be in clip space, not scene space.
+ */
bool BKE_tracking_track_has_marker_at_frame(struct MovieTrackingTrack *track, int framenr);
+/**
+ * Check whether track has got enabled marker at specified frame.
+ *
+ * \note frame number should be in clip space, not scene space.
+ */
bool BKE_tracking_track_has_enabled_marker_at_frame(struct MovieTrackingTrack *track, int framenr);
+/**
+ * Clear track's path:
+ *
+ * - If action is #TRACK_CLEAR_REMAINED path from `ref_frame+1` up to end will be clear.
+ * - If action is #TRACK_CLEAR_UPTO path from the beginning up to `ref_frame-1` will be clear.
+ * - If action is #TRACK_CLEAR_ALL only marker at frame ref_frame will remain.
+ *
+ * \note frame number should be in clip space, not scene space.
+ */
void BKE_tracking_track_path_clear(struct MovieTrackingTrack *track, int ref_frame, int action);
void BKE_tracking_tracks_join(struct MovieTracking *tracking,
@@ -140,7 +256,11 @@ float BKE_tracking_track_get_weight_for_marker(struct MovieClip *clip,
struct MovieTrackingTrack *track,
struct MovieTrackingMarker *marker);
-/* selection */
+/* Selection */
+
+/**
+ * \param area: which part of marker should be selected. see TRACK_AREA_* constants.
+ */
void BKE_tracking_track_select(struct ListBase *tracksbase,
struct MovieTrackingTrack *track,
int area,
@@ -155,19 +275,31 @@ void BKE_tracking_marker_delete(struct MovieTrackingTrack *track, int framenr);
void BKE_tracking_marker_clamp(struct MovieTrackingMarker *marker, int event);
+/**
+ * Get marker closest to the given frame number.
+ *
+ * If there is maker with exact frame number it returned.
+ * Otherwise, marker with highest frame number but lower than the requested
+ * frame is returned if such marker exists. Otherwise, the marker with lowest
+ * frame number greater than the requested frame number is returned.
+ *
+ * This function has complexity of `O(log number_of_markers)`.
+ */
struct MovieTrackingMarker *BKE_tracking_marker_get(struct MovieTrackingTrack *track, int framenr);
struct MovieTrackingMarker *BKE_tracking_marker_get_exact(struct MovieTrackingTrack *track,
int framenr);
struct MovieTrackingMarker *BKE_tracking_marker_ensure(struct MovieTrackingTrack *track,
int framenr);
-/* Get marker position, possibly interpolating gap between key-framed/tracked markers.
+/**
+ * Get marker position, possibly interpolating gap between key-framed/tracked markers.
*
* The result marker frame number is set to the requested frame number. Its flags are 0 if the
* marker is interpolated, and is set to original marker flag if there were no interpolation
* involved.
*
- * Returns truth if the result is usable. */
+ * \returns truth if the result is usable.
+ */
bool BKE_tracking_marker_get_interpolated(struct MovieTrackingTrack *track,
const int framenr,
struct MovieTrackingMarker *r_marker);
@@ -181,12 +313,21 @@ void BKE_tracking_marker_get_subframe_position(struct MovieTrackingTrack *track,
float pos[2]);
/* **** Plane Track **** */
+/**
+ * Creates new plane track out of selected point tracks.
+ */
struct MovieTrackingPlaneTrack *BKE_tracking_plane_track_add(struct MovieTracking *tracking,
struct ListBase *plane_tracks_base,
struct ListBase *tracks,
int framenr);
void BKE_tracking_plane_track_unique_name(struct ListBase *plane_tracks_base,
struct MovieTrackingPlaneTrack *plane_track);
+/**
+ * Free specified plane track, only frees contents of a structure
+ * (if track is allocated in heap, it shall be handled outside).
+ *
+ * All the pointers inside track becomes invalid after this call.
+ */
void BKE_tracking_plane_track_free(struct MovieTrackingPlaneTrack *plane_track);
bool BKE_tracking_plane_track_has_marker_at_frame(struct MovieTrackingPlaneTrack *plane_track,
@@ -222,10 +363,21 @@ struct MovieTrackingPlaneMarker *BKE_tracking_plane_marker_insert(
struct MovieTrackingPlaneTrack *plane_track, struct MovieTrackingPlaneMarker *plane_marker);
void BKE_tracking_plane_marker_delete(struct MovieTrackingPlaneTrack *plane_track, int framenr);
+/**
+ * Get a plane marker at given frame,
+ * If there's no such marker, closest one from the left side will be returned.
+ */
struct MovieTrackingPlaneMarker *BKE_tracking_plane_marker_get(
struct MovieTrackingPlaneTrack *plane_track, int framenr);
+/**
+ * Get a plane marker at exact given frame, if there's no marker at the frame,
+ * NULL will be returned.
+ */
struct MovieTrackingPlaneMarker *BKE_tracking_plane_marker_get_exact(
struct MovieTrackingPlaneTrack *plane_track, int framenr);
+/**
+ * Ensure there's a marker for the given frame.
+ */
struct MovieTrackingPlaneMarker *BKE_tracking_plane_marker_ensure(
struct MovieTrackingPlaneTrack *plane_track, int framenr);
void BKE_tracking_plane_marker_get_subframe_corners(struct MovieTrackingPlaneTrack *plane_track,
@@ -255,6 +407,9 @@ struct MovieTrackingReconstruction *BKE_tracking_object_get_reconstruction(
struct MovieTracking *tracking, struct MovieTrackingObject *object);
/* **** Camera **** */
+/**
+ * Converts principal offset from center to offset of blender's camera.
+ */
void BKE_tracking_camera_shift_get(
struct MovieTracking *tracking, int winx, int winy, float *shiftx, float *shifty);
void BKE_tracking_camera_to_blender(struct MovieTracking *tracking,
@@ -346,10 +501,21 @@ struct ImBuf *BKE_tracking_get_search_imbuf(struct ImBuf *ibuf,
bool anchored,
bool disable_channels);
+/**
+ * Zap channels from the imbuf that are disabled by the user. this can lead to
+ * better tracks sometimes. however, instead of simply zeroing the channels
+ * out, do a partial gray-scale conversion so the display is better.
+ */
void BKE_tracking_disable_channels(
struct ImBuf *ibuf, bool disable_red, bool disable_green, bool disable_blue, bool grayscale);
/* **** 2D tracking **** */
+
+/**
+ * Refine marker's position using previously known keyframe.
+ * Direction of searching for a keyframe depends on backwards flag,
+ * which means if backwards is false, previous keyframe will be as reference.
+ */
void BKE_tracking_refine_marker(struct MovieClip *clip,
struct MovieTrackingTrack *track,
struct MovieTrackingMarker *marker,
@@ -368,6 +534,9 @@ void BKE_autotrack_context_free(struct AutoTrackContext *context);
/* **** Plane tracking **** */
+/**
+ * \note frame number should be in clip space, not scene space.
+ */
void BKE_tracking_track_plane_from_existing_motion(struct MovieTrackingPlaneTrack *plane_track,
int start_frame);
void BKE_tracking_retrack_plane_from_existing_motion_at_segment(
@@ -377,11 +546,20 @@ void BKE_tracking_homography_between_two_quads(/*const*/ float reference_corners
float H[3][3]);
/* **** Camera solving **** */
+
+/**
+ * Perform early check on whether everything is fine to start reconstruction.
+ */
bool BKE_tracking_reconstruction_check(struct MovieTracking *tracking,
struct MovieTrackingObject *object,
char *error_msg,
int error_size);
+/**
+ * Create context for camera/object motion reconstruction.
+ * Copies all data needed for reconstruction from movie clip datablock,
+ * so editing this clip is safe during reconstruction job is in progress.
+ */
struct MovieReconstructContext *BKE_tracking_reconstruction_context_new(
struct MovieClip *clip,
struct MovieTrackingObject *object,
@@ -389,13 +567,29 @@ struct MovieReconstructContext *BKE_tracking_reconstruction_context_new(
int keyframe2,
int width,
int height);
+/**
+ * Free memory used by a reconstruction process.
+ */
void BKE_tracking_reconstruction_context_free(struct MovieReconstructContext *context);
+/**
+ * Solve camera/object motion and reconstruct 3D markers position
+ * from a prepared reconstruction context.
+ *
+ * stop is not actually used at this moment, so reconstruction
+ * job could not be stopped.
+ *
+ * do_update, progress and stat_message are set by reconstruction
+ * callback in libmv side and passing to an interface.
+ */
void BKE_tracking_reconstruction_solve(struct MovieReconstructContext *context,
short *stop,
short *do_update,
float *progress,
char *stats_message,
int message_size);
+/**
+ * Finish reconstruction process by copying reconstructed data to an actual movie clip data-block.
+ */
bool BKE_tracking_reconstruction_finish(struct MovieReconstructContext *context,
struct MovieTracking *tracking);
@@ -405,9 +599,16 @@ void BKE_tracking_reconstruction_report_error_message(struct MovieReconstructCon
const char *BKE_tracking_reconstruction_error_message_get(
const struct MovieReconstructContext *context);
+/**
+ * Apply scale on all reconstructed cameras and bundles, used by camera scale apply operator.
+ */
void BKE_tracking_reconstruction_scale(struct MovieTracking *tracking, float scale[3]);
/* **** Feature detection **** */
+
+/**
+ * Detect features using FAST detector.
+ */
void BKE_tracking_detect_fast(struct MovieTracking *tracking,
struct ListBase *tracksbase,
struct ImBuf *ibuf,
@@ -418,6 +619,9 @@ void BKE_tracking_detect_fast(struct MovieTracking *tracking,
struct bGPDlayer *layer,
bool place_outside_layer);
+/**
+ * Detect features using Harris detector.
+ */
void BKE_tracking_detect_harris(struct MovieTracking *tracking,
struct ListBase *tracksbase,
struct ImBuf *ibuf,
@@ -429,6 +633,24 @@ void BKE_tracking_detect_harris(struct MovieTracking *tracking,
bool place_outside_layer);
/* **** 2D stabilization **** */
+
+/**
+ * Get stabilization data (translation, scaling and angle) for a given frame.
+ * Returned data describes how to compensate the detected movement, but with any
+ * chosen scale factor already applied and any target frame position already compensated.
+ * In case stabilization fails or is disabled, neutral values are returned.
+ *
+ * \param framenr: is a frame number, relative to the clip (not relative to the scene timeline).
+ * \param width: is an effective width of the canvas (square pixels), used to scale the
+ * determined translation.
+ *
+ * Outputs:
+ * \param translation: of the lateral shift, absolute canvas coordinates (square pixels).
+ * \param scale: of the scaling to apply.
+ * \param angle: of the rotation angle, relative to the frame center.
+ *
+ * TODO(sergey): Use `r_` prefix for output parameters here.
+ */
void BKE_tracking_stabilization_data_get(struct MovieClip *clip,
int framenr,
int width,
@@ -436,12 +658,30 @@ void BKE_tracking_stabilization_data_get(struct MovieClip *clip,
float translation[2],
float *scale,
float *angle);
+/**
+ * Stabilize given image buffer using stabilization data for a specified frame number.
+ *
+ * \note frame number should be in clip space, not scene space.
+ *
+ * TODO(sergey): Use `r_` prefix for output parameters here.
+ */
struct ImBuf *BKE_tracking_stabilize_frame(struct MovieClip *clip,
int framenr,
struct ImBuf *ibuf,
float translation[2],
float *scale,
float *angle);
+/**
+ * Build a 4x4 transformation matrix based on the given 2D stabilization data.
+ * mat is a 4x4 matrix in homogeneous coordinates, adapted to the
+ * final image buffer size and compensated for pixel aspect ratio,
+ * ready for direct OpenGL drawing.
+ *
+ * TODO(sergey): The signature of this function should be changed. we actually
+ * don't need the dimensions of the image buffer. Instead we
+ * should consider to provide the pivot point of the rotation as a
+ * further stabilization data parameter.
+ */
void BKE_tracking_stabilization_data_to_mat4(int width,
int height,
float aspect,
@@ -450,17 +690,30 @@ void BKE_tracking_stabilization_data_to_mat4(int width,
float angle,
float mat[4][4]);
-/* Dopesheet */
+/* Dope-sheet */
+
+/**
+ * Tag dope-sheet for update, actual update will happen later when it'll be actually needed.
+ */
void BKE_tracking_dopesheet_tag_update(struct MovieTracking *tracking);
+/**
+ * Do dope-sheet update, if update is not needed nothing will happen.
+ */
void BKE_tracking_dopesheet_update(struct MovieTracking *tracking);
/* **** Query/search **** */
+/**
+ * \note Returns NULL if the track comes from camera object,.
+ */
struct MovieTrackingObject *BKE_tracking_find_object_for_track(
const struct MovieTracking *tracking, const struct MovieTrackingTrack *track);
struct ListBase *BKE_tracking_find_tracks_list_for_track(struct MovieTracking *tracking,
const struct MovieTrackingTrack *track);
+/**
+ * \note Returns NULL if the track comes from camera object,.
+ */
struct MovieTrackingObject *BKE_tracking_find_object_for_plane_track(
const struct MovieTracking *tracking, const struct MovieTrackingPlaneTrack *plane_track);
struct ListBase *BKE_tracking_find_tracks_list_for_plane_track(
diff --git a/source/blender/nodes/NOD_type_conversions.hh b/source/blender/blenkernel/BKE_type_conversions.hh
index c8b24fd1260..ebfb13cd08f 100644
--- a/source/blender/nodes/NOD_type_conversions.hh
+++ b/source/blender/blenkernel/BKE_type_conversions.hh
@@ -18,7 +18,7 @@
#include "FN_multi_function.hh"
-namespace blender::nodes {
+namespace blender::bke {
using fn::CPPType;
@@ -72,6 +72,8 @@ class DataTypeConversions {
const void *from_value,
void *to_value) const;
+ void convert_to_initialized_n(fn::GSpan from_span, fn::GMutableSpan to_span) const;
+
fn::GVArray try_convert(fn::GVArray varray, const CPPType &to_type) const;
fn::GVMutableArray try_convert(fn::GVMutableArray varray, const CPPType &to_type) const;
@@ -79,4 +81,4 @@ class DataTypeConversions {
const DataTypeConversions &get_implicit_type_conversions();
-} // namespace blender::nodes
+} // namespace blender::bke
diff --git a/source/blender/blenkernel/BKE_undo_system.h b/source/blender/blenkernel/BKE_undo_system.h
index 2a90211f8e0..6e1f9468ce4 100644
--- a/source/blender/blenkernel/BKE_undo_system.h
+++ b/source/blender/blenkernel/BKE_undo_system.h
@@ -171,7 +171,12 @@ typedef enum eUndoTypeFlags {
UNDOTYPE_FLAG_DECODE_ACTIVE_STEP = 1 << 1,
} eUndoTypeFlags;
-/* Expose since we need to perform operations on specific undo types (rarely). */
+/* -------------------------------------------------------------------- */
+/** \name Public Undo Types
+ *
+ * Expose since we need to perform operations on specific undo types (rarely).
+ * \{ */
+
extern const UndoType *BKE_UNDOSYS_TYPE_IMAGE;
extern const UndoType *BKE_UNDOSYS_TYPE_MEMFILE;
extern const UndoType *BKE_UNDOSYS_TYPE_PAINTCURVE;
@@ -179,17 +184,25 @@ extern const UndoType *BKE_UNDOSYS_TYPE_PARTICLE;
extern const UndoType *BKE_UNDOSYS_TYPE_SCULPT;
extern const UndoType *BKE_UNDOSYS_TYPE_TEXT;
+/** \} */
+
#define BKE_UNDOSYS_TYPE_IS_MEMFILE_SKIP(ty) ELEM(ty, BKE_UNDOSYS_TYPE_IMAGE)
UndoStack *BKE_undosys_stack_create(void);
void BKE_undosys_stack_destroy(UndoStack *ustack);
void BKE_undosys_stack_clear(UndoStack *ustack);
void BKE_undosys_stack_clear_active(UndoStack *ustack);
+/* name optional */
bool BKE_undosys_stack_has_undo(const UndoStack *ustack, const char *name);
void BKE_undosys_stack_init_from_main(UndoStack *ustack, struct Main *bmain);
+/* called after 'BKE_undosys_stack_init_from_main' */
void BKE_undosys_stack_init_from_context(UndoStack *ustack, struct bContext *C);
UndoStep *BKE_undosys_stack_active_with_type(UndoStack *ustack, const UndoType *ut);
UndoStep *BKE_undosys_stack_init_or_active_with_type(UndoStack *ustack, const UndoType *ut);
+/**
+ * \param steps: Limit the number of undo steps.
+ * \param memory_limit: Limit the amount of memory used by the undo stack.
+ */
void BKE_undosys_stack_limit_steps_and_memory(UndoStack *ustack, int steps, size_t memory_limit);
#define BKE_undosys_stack_limit_steps_and_memory_defaults(ustack) \
BKE_undosys_stack_limit_steps_and_memory(ustack, U.undosteps, (size_t)U.undomemory * 1024 * 1024)
@@ -197,13 +210,18 @@ void BKE_undosys_stack_limit_steps_and_memory(UndoStack *ustack, int steps, size
void BKE_undosys_stack_group_begin(UndoStack *ustack);
void BKE_undosys_stack_group_end(UndoStack *ustack);
-/* Only some UndoType's require init. */
+/**
+ * Only some UndoType's require init.
+ */
UndoStep *BKE_undosys_step_push_init_with_type(UndoStack *ustack,
struct bContext *C,
const char *name,
const UndoType *ut);
UndoStep *BKE_undosys_step_push_init(UndoStack *ustack, struct bContext *C, const char *name);
+/**
+ * \param C: Can be NULL from some callers if their encoding function doesn't need it
+ */
eUndoPushReturn BKE_undosys_step_push_with_type(UndoStack *ustack,
struct bContext *C,
const char *name,
@@ -216,40 +234,117 @@ UndoStep *BKE_undosys_step_find_by_name_with_type(UndoStack *ustack,
UndoStep *BKE_undosys_step_find_by_type(UndoStack *ustack, const UndoType *ut);
UndoStep *BKE_undosys_step_find_by_name(UndoStack *ustack, const char *name);
+/**
+ * Return direction of the undo/redo from `us_reference` (or `ustack->step_active` if NULL), and
+ * `us_target`.
+ *
+ * \note If `us_reference` and `us_target` are the same, we consider this is an undo.
+ *
+ * \return -1 for undo, 1 for redo, 0 in case of error.
+ */
eUndoStepDir BKE_undosys_step_calc_direction(const UndoStack *ustack,
const UndoStep *us_target,
const UndoStep *us_reference);
+/**
+ * Undo/Redo until the given `us_target` step becomes the active (currently loaded) one.
+ *
+ * \note Unless `us_target` is a 'skipped' one and `use_skip` is true, `us_target`
+ * will become the active step.
+ *
+ * \note In case `use_skip` is true, the final target will always be **beyond** the given one
+ * (if the given one has to be skipped).
+ *
+ * \param us_reference: If NULL, will be set to current active step in the undo stack. Otherwise,
+ * it is assumed to match the current state, and will be used as basis for the undo/redo process
+ * (i.e. all steps in-between `us_reference` and `us_target` will be processed).
+ */
bool BKE_undosys_step_load_data_ex(UndoStack *ustack,
struct bContext *C,
UndoStep *us_target,
UndoStep *us_reference,
const bool use_skip);
+/**
+ * Undo/Redo until the given `us_target` step becomes the active (currently loaded) one.
+ */
bool BKE_undosys_step_load_data(UndoStack *ustack, struct bContext *C, UndoStep *us_target);
+/**
+ * Undo/Redo until the step matching given `index` in the undo stack becomes the active
+ * (currently loaded) one.
+ */
void BKE_undosys_step_load_from_index(UndoStack *ustack, struct bContext *C, const int index);
+/**
+ * Undo until `us_target` step becomes the active (currently loaded) one.
+ *
+ * \warning This function assumes that the given target step is _before_ current active one.
+ *
+ * \note Unless `us_target` is a 'skipped' one and `use_skip` is true,
+ * `us_target` will become the active step.
+ *
+ * \note In case `use_skip` is true, the final target will always be **before** the given one
+ * (if the given one has to be skipped).
+ */
bool BKE_undosys_step_undo_with_data_ex(UndoStack *ustack,
struct bContext *C,
UndoStep *us,
bool use_skip);
+/**
+ * Undo until `us_target` step becomes the active (currently loaded) one.
+ *
+ * \note See #BKE_undosys_step_undo_with_data_ex for details.
+ */
bool BKE_undosys_step_undo_with_data(UndoStack *ustack, struct bContext *C, UndoStep *us_target);
+/**
+ * Undo one step from current active (currently loaded) one.
+ */
bool BKE_undosys_step_undo(UndoStack *ustack, struct bContext *C);
+/**
+ * Redo until `us_target` step becomes the active (currently loaded) one.
+ *
+ * \warning This function assumes that the given target step is _after_ current active one.
+ *
+ * \note Unless `us_target` is a 'skipped' one and `use_skip` is true,
+ * `us_target` will become the active step.
+ *
+ * \note In case `use_skip` is true, the final target will always be **after** the given one
+ * (if the given one has to be skipped).
+ */
bool BKE_undosys_step_redo_with_data_ex(UndoStack *ustack,
struct bContext *C,
UndoStep *us,
bool use_skip);
+/**
+ * Redo until `us_target` step becomes the active (currently loaded) one.
+ *
+ * \note See #BKE_undosys_step_redo_with_data_ex for details.
+ */
bool BKE_undosys_step_redo_with_data(UndoStack *ustack, struct bContext *C, UndoStep *us_target);
+/**
+ * Redo one step from current active one.
+ */
bool BKE_undosys_step_redo(UndoStack *ustack, struct bContext *C);
+/**
+ * Useful when we want to diff against previous undo data but can't be sure the types match.
+ */
UndoStep *BKE_undosys_step_same_type_next(UndoStep *us);
+/**
+ * Useful when we want to diff against previous undo data but can't be sure the types match.
+ */
UndoStep *BKE_undosys_step_same_type_prev(UndoStep *us);
-/* Type System */
+/* Type System. */
+
+/**
+ * Similar to #WM_operatortype_append
+ */
UndoType *BKE_undosys_type_append(void (*undosys_fn)(UndoType *));
void BKE_undosys_type_free_all(void);
-/* ID Accessor */
+/* ID Accessor. */
+
#if 0 /* functionality is only used internally for now. */
void BKE_undosys_foreach_ID_ref(UndoStack *ustack,
UndoTypeForEachIDRefFn foreach_ID_ref_fn,
diff --git a/source/blender/blenkernel/BKE_unit.h b/source/blender/blenkernel/BKE_unit.h
index b28215a72d1..505cfee3adf 100644
--- a/source/blender/blenkernel/BKE_unit.h
+++ b/source/blender/blenkernel/BKE_unit.h
@@ -26,9 +26,11 @@ extern "C" {
struct UnitSettings;
-/* in all cases the value is assumed to be scaled by the user preference */
+/* In all cases the value is assumed to be scaled by the user-preference. */
-/* humanly readable representation of a value in units (used for button drawing) */
+/**
+ * Humanly readable representation of a value in units (used for button drawing).
+ */
size_t BKE_unit_value_as_string_adaptive(
char *str, int len_max, double value, int prec, int system, int type, bool split, bool pad);
size_t BKE_unit_value_as_string(char *str,
@@ -39,29 +41,59 @@ size_t BKE_unit_value_as_string(char *str,
const struct UnitSettings *settings,
bool pad);
-/* replace units with values, used before python button evaluation */
+/**
+ * Replace units with values, used before python button evaluation.
+ *
+ * Make a copy of the string that replaces the units with numbers.
+ * This is only used when evaluating user input and can afford to be a bit slower
+ *
+ * This is to be used before python evaluation so:
+ * `10.1km -> 10.1*1000.0`
+ * ...will be resolved by Python.
+ *
+ * Values will be split by an add sign:
+ * `5'2" -> 5*0.3048 + 2*0.0254`
+ *
+ * \param str_prev: is optional, when valid it is used to get a base unit when none is set.
+ *
+ * \return True of a change was made.
+ */
bool BKE_unit_replace_string(
char *str, int len_max, const char *str_prev, double scale_pref, int system, int type);
-/* return true if the string contains any valid unit for the given type */
+/**
+ * \return true if the string contains any valid unit for the given type.
+ */
bool BKE_unit_string_contains_unit(const char *str, int type);
-/* If user does not specify a unit, this converts it to the unit from the settings. */
+/**
+ * If user does not specify a unit, this converts it to the unit from the settings.
+ */
double BKE_unit_apply_preferred_unit(const struct UnitSettings *settings, int type, double value);
-/* make string keyboard-friendly: 10µm --> 10um */
+/**
+ * Make string keyboard-friendly, e.g: `10µm -> 10um`.
+ */
void BKE_unit_name_to_alt(char *str, int len_max, const char *orig_str, int system, int type);
-/* the size of the unit used for this value (used for calculating the ckickstep) */
+/**
+ * The size of the unit used for this value (used for calculating the click-step).
+ */
double BKE_unit_closest_scalar(double value, int system, int type);
-/* base scale for these units */
+/**
+ * Base scale for these units.
+ */
double BKE_unit_base_scalar(int system, int type);
-/* return true is the unit system exists */
+/**
+ * \return true is the unit system exists.
+ */
bool BKE_unit_is_valid(int system, int type);
-/* loop over scales, could add names later */
+/**
+ * Loop over scales, could add names later.
+ */
// double bUnit_Iter(void **unit, char **name, int system, int type);
void BKE_unit_system_get(int system, int type, const void **r_usys_pt, int *r_len);
@@ -73,7 +105,7 @@ const char *BKE_unit_identifier_get(const void *usys_pt, int index);
double BKE_unit_scalar_get(const void *usys_pt, int index);
bool BKE_unit_is_suppressed(const void *usys_pt, int index);
-/* aligned with PropertyUnit */
+/** Aligned with #PropertyUnit. */
enum {
B_UNIT_NONE = 0,
B_UNIT_LENGTH = 1,
diff --git a/source/blender/blenkernel/BKE_vfont.h b/source/blender/blenkernel/BKE_vfont.h
index 827ae1b6a0f..cd1b30b9358 100644
--- a/source/blender/blenkernel/BKE_vfont.h
+++ b/source/blender/blenkernel/BKE_vfont.h
@@ -84,6 +84,9 @@ bool BKE_vfont_to_curve_ex(struct Object *ob,
bool *r_text_free,
struct CharTrans **r_chartransdata);
bool BKE_vfont_to_curve_nubase(struct Object *ob, int mode, struct ListBase *r_nubase);
+/**
+ * \warning Expects to have access to evaluated data (i.e. passed object should be evaluated one).
+ */
bool BKE_vfont_to_curve(struct Object *ob, int mode);
void BKE_vfont_build_char(struct Curve *cu,
struct ListBase *nubase,
diff --git a/source/blender/blenkernel/BKE_vfontdata.h b/source/blender/blenkernel/BKE_vfontdata.h
index b6e57dad934..692857b0458 100644
--- a/source/blender/blenkernel/BKE_vfontdata.h
+++ b/source/blender/blenkernel/BKE_vfontdata.h
@@ -49,6 +49,12 @@ typedef struct VChar {
float width;
} VChar;
+/**
+ * Construct a new #VFontData structure from free-type font data in `pf`.
+ *
+ * \param pf: The font data.
+ * \retval A new #VFontData structure, or NULL if unable to load.
+ */
VFontData *BKE_vfontdata_from_freetypefont(struct PackedFile *pf);
VFontData *BKE_vfontdata_copy(const VFontData *vfont_src, const int flag);
diff --git a/source/blender/blenkernel/BKE_volume.h b/source/blender/blenkernel/BKE_volume.h
index 601e0cf26a9..f4f00844b8d 100644
--- a/source/blender/blenkernel/BKE_volume.h
+++ b/source/blender/blenkernel/BKE_volume.h
@@ -88,6 +88,7 @@ const char *BKE_volume_grids_frame_filepath(const struct Volume *volume);
const VolumeGrid *BKE_volume_grid_get_for_read(const struct Volume *volume, int grid_index);
VolumeGrid *BKE_volume_grid_get_for_write(struct Volume *volume, int grid_index);
const VolumeGrid *BKE_volume_grid_active_get_for_read(const struct Volume *volume);
+/* Tries to find a grid with the given name. Make sure that the volume has been loaded. */
const VolumeGrid *BKE_volume_grid_find_for_read(const struct Volume *volume, const char *name);
/* Grid
@@ -115,9 +116,13 @@ void BKE_volume_grid_unload(const struct Volume *volume, const struct VolumeGrid
bool BKE_volume_grid_is_loaded(const struct VolumeGrid *grid);
/* Metadata */
+
const char *BKE_volume_grid_name(const struct VolumeGrid *grid);
VolumeGridType BKE_volume_grid_type(const struct VolumeGrid *grid);
int BKE_volume_grid_channels(const struct VolumeGrid *grid);
+/**
+ * Transformation from index space to object space.
+ */
void BKE_volume_grid_transform_matrix(const struct VolumeGrid *grid, float mat[4][4]);
/* Volume Editing
diff --git a/source/blender/blenkernel/BKE_volume_to_mesh.hh b/source/blender/blenkernel/BKE_volume_to_mesh.hh
index 9532da8c23c..dd8ae7ea554 100644
--- a/source/blender/blenkernel/BKE_volume_to_mesh.hh
+++ b/source/blender/blenkernel/BKE_volume_to_mesh.hh
@@ -14,6 +14,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#pragma once
+
#include "BLI_span.hh"
#include "DNA_modifier_types.h"
diff --git a/source/blender/blenkernel/BKE_workspace.h b/source/blender/blenkernel/BKE_workspace.h
index 82a4e5fe08e..ff4e21732c4 100644
--- a/source/blender/blenkernel/BKE_workspace.h
+++ b/source/blender/blenkernel/BKE_workspace.h
@@ -31,9 +31,17 @@ struct bScreen;
struct bToolRef;
/* -------------------------------------------------------------------- */
-/* Create, delete, init */
+/** \name Create, Delete, Initialize
+ * \{ */
struct WorkSpace *BKE_workspace_add(struct Main *bmain, const char *name);
+/**
+ * Remove \a workspace by freeing itself and its data. This is a higher-level wrapper that
+ * calls #workspace_free_data (through #BKE_id_free) to free the workspace data, and frees
+ * other data-blocks owned by \a workspace and its layouts (currently that is screens only).
+ *
+ * Always use this to remove (and free) workspaces. Don't free non-ID workspace members here.
+ */
void BKE_workspace_remove(struct Main *bmain, struct WorkSpace *workspace);
struct WorkSpaceInstanceHook *BKE_workspace_instance_hook_create(const struct Main *bmain,
@@ -41,6 +49,9 @@ struct WorkSpaceInstanceHook *BKE_workspace_instance_hook_create(const struct Ma
void BKE_workspace_instance_hook_free(const struct Main *bmain,
struct WorkSpaceInstanceHook *hook);
+/**
+ * Add a new layout to \a workspace for \a screen.
+ */
struct WorkSpaceLayout *BKE_workspace_layout_add(struct Main *bmain,
struct WorkSpace *workspace,
struct bScreen *screen,
@@ -51,17 +62,36 @@ void BKE_workspace_layout_remove(struct Main *bmain,
void BKE_workspace_relations_free(ListBase *relation_list);
+/** \} */
+
/* -------------------------------------------------------------------- */
-/* General Utils */
+/** \name General Utilities
+ * \{ */
struct WorkSpaceLayout *BKE_workspace_layout_find(const struct WorkSpace *workspace,
const struct bScreen *screen)
ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+/**
+ * Find the layout for \a screen without knowing which workspace to look in.
+ * Can also be used to find the workspace that contains \a screen.
+ *
+ * \param r_workspace: Optionally return the workspace that contains the
+ * looked up layout (if found).
+ */
struct WorkSpaceLayout *BKE_workspace_layout_find_global(const struct Main *bmain,
const struct bScreen *screen,
struct WorkSpace **r_workspace)
ATTR_NONNULL(1, 2);
+/**
+ * Circular workspace layout iterator.
+ *
+ * \param callback: Custom function which gets executed for each layout.
+ * Can return false to stop iterating.
+ * \param arg: Custom data passed to each \a callback call.
+ *
+ * \return the layout at which \a callback returned false.
+ */
struct WorkSpaceLayout *BKE_workspace_layout_iter_circular(
const struct WorkSpace *workspace,
struct WorkSpaceLayout *start,
@@ -72,8 +102,11 @@ struct WorkSpaceLayout *BKE_workspace_layout_iter_circular(
void BKE_workspace_tool_remove(struct WorkSpace *workspace, struct bToolRef *tref)
ATTR_NONNULL(1, 2);
+/** \} */
+
/* -------------------------------------------------------------------- */
-/* Getters/Setters */
+/** \name Getters/Setters
+ * \{ */
#define GETTER_ATTRS ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT
#define SETTER_ATTRS ATTR_NONNULL(1)
@@ -81,8 +114,23 @@ void BKE_workspace_tool_remove(struct WorkSpace *workspace, struct bToolRef *tre
struct WorkSpace *BKE_workspace_active_get(struct WorkSpaceInstanceHook *hook) GETTER_ATTRS;
void BKE_workspace_active_set(struct WorkSpaceInstanceHook *hook,
struct WorkSpace *workspace) SETTER_ATTRS;
+/**
+ * Get the layout that is active for \a hook (which is the visible layout for the active workspace
+ * in \a hook).
+ */
struct WorkSpaceLayout *BKE_workspace_active_layout_get(const struct WorkSpaceInstanceHook *hook)
GETTER_ATTRS;
+/**
+ * \brief Activate a layout
+ *
+ * Sets \a layout as active for \a workspace when activated through or already active in \a hook.
+ * So when the active workspace of \a hook is \a workspace, \a layout becomes the active layout of
+ * \a hook too. See #BKE_workspace_active_set().
+ *
+ * \a workspace does not need to be active for this.
+ *
+ * #WorkSpaceInstanceHook.act_layout should only be modified directly to update the layout pointer.
+ */
void BKE_workspace_active_layout_set(struct WorkSpaceInstanceHook *hook,
const int winid,
struct WorkSpace *workspace,
@@ -100,6 +148,9 @@ void BKE_workspace_layout_name_set(struct WorkSpace *workspace,
const char *new_name) ATTR_NONNULL();
struct bScreen *BKE_workspace_layout_screen_get(const struct WorkSpaceLayout *layout) GETTER_ATTRS;
+/**
+ * Get the layout to be activated should \a workspace become or be the active workspace in \a hook.
+ */
struct WorkSpaceLayout *BKE_workspace_active_layout_for_workspace_get(
const struct WorkSpaceInstanceHook *hook, const struct WorkSpace *workspace) GETTER_ATTRS;
@@ -111,6 +162,8 @@ void BKE_workspace_id_tag_all_visible(struct Main *bmain, int tag) ATTR_NONNULL(
#undef GETTER_ATTRS
#undef SETTER_ATTRS
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_writeavi.h b/source/blender/blenkernel/BKE_writeavi.h
index 97f998cc1c1..d2a5100ffad 100644
--- a/source/blender/blenkernel/BKE_writeavi.h
+++ b/source/blender/blenkernel/BKE_writeavi.h
@@ -64,6 +64,10 @@ typedef struct bMovieHandle {
} bMovieHandle;
bMovieHandle *BKE_movie_handle_get(const char imtype);
+
+/**
+ * \note Similar to #BKE_image_path_from_imformat()
+ */
void BKE_movie_filepath_get(char *string,
const struct RenderData *rd,
bool preview,
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index b2418d0539c..f6e7f1c2473 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -100,6 +100,7 @@ set(SRC
intern/blender_undo.c
intern/blender_user_menu.c
intern/blendfile.c
+ intern/blendfile_link_append.c
intern/boids.c
intern/bpath.c
intern/brush.c
@@ -117,7 +118,7 @@ set(SRC
intern/context.c
intern/crazyspace.c
intern/cryptomatte.cc
- intern/curve.c
+ intern/curve.cc
intern/curve_bevel.c
intern/curve_convert.c
intern/curve_decimate.c
@@ -138,7 +139,6 @@ set(SRC
intern/editmesh_cache.c
intern/editmesh_tangent.c
intern/effect.c
- intern/extern_implementations.cc
intern/fcurve.c
intern/fcurve_cache.c
intern/fcurve_driver.c
@@ -164,7 +164,7 @@ set(SRC
intern/idtype.c
intern/image.c
intern/image_gen.c
- intern/image_gpu.c
+ intern/image_gpu.cc
intern/image_save.c
intern/ipo.c
intern/kelvinlet.c
@@ -226,6 +226,7 @@ set(SRC
intern/multires_versioning.c
intern/nla.c
intern/node.cc
+ intern/type_conversions.cc
intern/object.cc
intern/object_deform.c
intern/object_dupli.cc
@@ -326,6 +327,7 @@ set(SRC
BKE_blender_user_menu.h
BKE_blender_version.h
BKE_blendfile.h
+ BKE_blendfile_link_append.h
BKE_boids.h
BKE_bpath.h
BKE_brush.h
@@ -455,6 +457,7 @@ set(SRC
BKE_text_suggestions.h
BKE_texture.h
BKE_tracking.h
+ BKE_type_conversions.hh
BKE_undo_system.h
BKE_unit.h
BKE_vfont.h
@@ -806,6 +809,7 @@ if(WITH_GTESTS)
intern/asset_library_service_test.cc
intern/asset_library_test.cc
intern/asset_test.cc
+ intern/bpath_test.cc
intern/cryptomatte_test.cc
intern/fcurve_test.cc
intern/lattice_deform_test.cc
diff --git a/source/blender/blenkernel/intern/CCGSubSurf.c b/source/blender/blenkernel/intern/CCGSubSurf.c
index 67e7b890548..74f848ac580 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf.c
@@ -939,7 +939,6 @@ void ccgSubSurf__effectedFaceNeighbors(CCGSubSurf *ss,
*numEdges = numE;
}
-/* copy face grid coordinates to other places */
CCGError ccgSubSurf_updateFromFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF)
{
int i, S, x, gridSize, cornerIdx, subdivLevels;
@@ -986,7 +985,6 @@ CCGError ccgSubSurf_updateFromFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF
return eCCGError_None;
}
-/* copy other places to face grid coordinates */
CCGError ccgSubSurf_updateToFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF)
{
int i, S, x, gridSize, cornerIdx, subdivLevels;
@@ -1035,8 +1033,6 @@ CCGError ccgSubSurf_updateToFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF,
return eCCGError_None;
}
-/* stitch together face grids, averaging coordinates at edges
- * and vertices, for multires displacements */
CCGError ccgSubSurf_stitchFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF)
{
CCGVert **effectedV;
diff --git a/source/blender/blenkernel/intern/CCGSubSurf.h b/source/blender/blenkernel/intern/CCGSubSurf.h
index a9e0d6882c1..9349c33d72a 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf.h
+++ b/source/blender/blenkernel/intern/CCGSubSurf.h
@@ -100,13 +100,30 @@ CCGError ccgSubSurf_syncFaceDel(CCGSubSurf *ss, CCGFaceHDL fHDL);
CCGError ccgSubSurf_processSync(CCGSubSurf *ss);
+/**
+ * Copy face grid coordinates to other places.
+ */
CCGError ccgSubSurf_updateFromFaces(CCGSubSurf *ss,
int lvl,
CCGFace **effectedF,
int numEffectedF);
+/**
+ * Copy other places to face grid coordinates.
+ */
CCGError ccgSubSurf_updateToFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF);
+/**
+ * Update normals for specified faces.
+ */
CCGError ccgSubSurf_updateNormals(CCGSubSurf *ss, CCGFace **effectedF, int numEffectedF);
+/**
+ * Compute subdivision levels from a given starting point, used by multi-res subdivide/propagate,
+ * by filling in coordinates at a certain level, and then subdividing that up to the highest level.
+ */
CCGError ccgSubSurf_updateLevels(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF);
+/**
+ * Stitch together face grids, averaging coordinates at edges and vertices, for multi-res
+ * displacements.
+ */
CCGError ccgSubSurf_stitchFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF);
CCGError ccgSubSurf_setSubdivisionLevels(CCGSubSurf *ss, int subdivisionLevels);
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_legacy.c b/source/blender/blenkernel/intern/CCGSubSurf_legacy.c
index 99ea1fb9607..e19e01ec034 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf_legacy.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf_legacy.c
@@ -1309,7 +1309,6 @@ void ccgSubSurf__sync_legacy(CCGSubSurf *ss)
/* ** Public API exposed to other areas which depends on old CCG code. ** */
-/* Update normals for specified faces. */
CCGError ccgSubSurf_updateNormals(CCGSubSurf *ss, CCGFace **effectedF, int numEffectedF)
{
CCGVert **effectedV;
@@ -1344,9 +1343,6 @@ CCGError ccgSubSurf_updateNormals(CCGSubSurf *ss, CCGFace **effectedF, int numEf
return eCCGError_None;
}
-/* compute subdivision levels from a given starting point, used by
- * multires subdivide/propagate, by filling in coordinates at a
- * certain level, and then subdividing that up to the highest level */
CCGError ccgSubSurf_updateLevels(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF)
{
CCGVert **effectedV;
diff --git a/source/blender/blenkernel/intern/DerivedMesh.cc b/source/blender/blenkernel/intern/DerivedMesh.cc
index ced9076bbfd..6c9c5490ca0 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.cc
+++ b/source/blender/blenkernel/intern/DerivedMesh.cc
@@ -295,10 +295,6 @@ static CustomData *dm_getPolyCData(DerivedMesh *dm)
return &dm->polyData;
}
-/**
- * Utility function to initialize a DerivedMesh's function pointers to
- * the default implementation (for those functions which have a default)
- */
void DM_init_funcs(DerivedMesh *dm)
{
/* default function implementations */
@@ -335,11 +331,6 @@ void DM_init_funcs(DerivedMesh *dm)
dm->getLoopDataArray = DM_get_loop_data_layer;
}
-/**
- * Utility function to initialize a DerivedMesh for the desired number
- * of vertices, edges and faces (doesn't allocate memory for them, just
- * sets up the custom data layers)
- */
void DM_init(DerivedMesh *dm,
DerivedMeshType type,
int numVerts,
@@ -368,10 +359,6 @@ void DM_init(DerivedMesh *dm,
copy_vn_i(dm->polyData.typemap, CD_NUMTYPES, -1);
}
-/**
- * Utility function to initialize a DerivedMesh for the desired number
- * of vertices, edges and faces, with a layer setup copied from source
- */
void DM_from_template_ex(DerivedMesh *dm,
DerivedMesh *source,
DerivedMeshType type,
@@ -485,12 +472,6 @@ void DM_ensure_normals(DerivedMesh *dm)
BLI_assert((dm->dirty & DM_DIRTY_NORMALS) == 0);
}
-/**
- * Ensure the array is large enough
- *
- * \note This function must always be thread-protected by caller.
- * It should only be used by internal code.
- */
void DM_ensure_looptri_data(DerivedMesh *dm)
{
const unsigned int totpoly = dm->numPolyData;
@@ -519,11 +500,11 @@ void DM_ensure_looptri_data(DerivedMesh *dm)
}
}
-/** Utility function to convert an (evaluated) Mesh to a shape key block. */
-/* Just a shallow wrapper around BKE_keyblock_convert_from_mesh,
- * that ensures both evaluated mesh and original one has same number of vertices. */
void BKE_mesh_runtime_eval_to_meshkey(Mesh *me_deformed, Mesh *me, KeyBlock *kb)
{
+ /* Just a shallow wrapper around #BKE_keyblock_convert_from_mesh,
+ * that ensures both evaluated mesh and original one has same number of vertices. */
+
const int totvert = me_deformed->totvert;
if (totvert == 0 || me->totvert == 0 || me->totvert != totvert) {
@@ -533,11 +514,6 @@ void BKE_mesh_runtime_eval_to_meshkey(Mesh *me_deformed, Mesh *me, KeyBlock *kb)
BKE_keyblock_convert_from_mesh(me_deformed, me->key, kb);
}
-/**
- * set the CD_FLAG_NOCOPY flag in custom data layers where the mask is
- * zero for the layer type, so only layer types specified by the mask
- * will be copied
- */
void DM_set_only_copy(DerivedMesh *dm, const CustomData_MeshMasks *mask)
{
CustomData_set_only_copy(&dm->vertData, mask->vmask);
@@ -658,11 +634,6 @@ void DM_copy_vert_data(
CustomData_copy_data(&source->vertData, &dest->vertData, source_index, dest_index, count);
}
-/**
- * interpolates vertex data from the vertices indexed by src_indices in the
- * source mesh using the given weights and stores the result in the vertex
- * indexed by dest_index in the dest mesh
- */
void DM_interp_vert_data(DerivedMesh *source,
DerivedMesh *dest,
int *src_indices,
@@ -2097,12 +2068,10 @@ Mesh *mesh_create_eval_final(Depsgraph *depsgraph,
Object *ob,
const CustomData_MeshMasks *dataMask)
{
- Mesh *final;
-
+ Mesh *result;
mesh_calc_modifiers(
- depsgraph, scene, ob, true, false, dataMask, -1, false, false, nullptr, &final, nullptr);
-
- return final;
+ depsgraph, scene, ob, true, false, dataMask, -1, false, false, nullptr, &result, nullptr);
+ return result;
}
Mesh *mesh_create_eval_final_index_render(Depsgraph *depsgraph,
@@ -2111,12 +2080,10 @@ Mesh *mesh_create_eval_final_index_render(Depsgraph *depsgraph,
const CustomData_MeshMasks *dataMask,
int index)
{
- Mesh *final;
-
+ Mesh *result;
mesh_calc_modifiers(
- depsgraph, scene, ob, true, false, dataMask, index, false, false, nullptr, &final, nullptr);
-
- return final;
+ depsgraph, scene, ob, true, false, dataMask, index, false, false, nullptr, &result, nullptr);
+ return result;
}
Mesh *mesh_create_eval_no_deform(Depsgraph *depsgraph,
@@ -2124,12 +2091,10 @@ Mesh *mesh_create_eval_no_deform(Depsgraph *depsgraph,
Object *ob,
const CustomData_MeshMasks *dataMask)
{
- Mesh *final;
-
+ Mesh *result;
mesh_calc_modifiers(
- depsgraph, scene, ob, false, false, dataMask, -1, false, false, nullptr, &final, nullptr);
-
- return final;
+ depsgraph, scene, ob, false, false, dataMask, -1, false, false, nullptr, &result, nullptr);
+ return result;
}
Mesh *mesh_create_eval_no_deform_render(Depsgraph *depsgraph,
@@ -2137,12 +2102,10 @@ Mesh *mesh_create_eval_no_deform_render(Depsgraph *depsgraph,
Object *ob,
const CustomData_MeshMasks *dataMask)
{
- Mesh *final;
-
+ Mesh *result;
mesh_calc_modifiers(
- depsgraph, scene, ob, false, false, dataMask, -1, false, false, nullptr, &final, nullptr);
-
- return final;
+ depsgraph, scene, ob, false, false, dataMask, -1, false, false, nullptr, &result, nullptr);
+ return result;
}
/***/
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index 2cc1cba99cd..ddba726ba83 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -289,7 +289,7 @@ static void action_blend_read_expand(BlendExpander *expander, ID *id)
static IDProperty *action_asset_type_property(const bAction *action)
{
- const bool is_single_frame = !BKE_action_has_single_frame(action);
+ const bool is_single_frame = BKE_action_has_single_frame(action);
IDPropertyTemplate idprop = {0};
idprop.i = is_single_frame;
@@ -320,6 +320,7 @@ IDTypeInfo IDType_ID_AC = {
.name_plural = "actions",
.translation_context = BLT_I18NCONTEXT_ID_ACTION,
.flags = IDTYPE_FLAGS_NO_ANIMDATA,
+ .asset_type_info = &AssetType_AC,
.init_data = NULL,
.copy_data = action_copy_data,
@@ -327,6 +328,7 @@ IDTypeInfo IDType_ID_AC = {
.make_local = NULL,
.foreach_id = action_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = action_blend_write,
@@ -337,8 +339,6 @@ IDTypeInfo IDType_ID_AC = {
.blend_read_undo_preserve = NULL,
.lib_override_apply_post = NULL,
-
- .asset_type_info = &AssetType_AC,
};
/* ***************** Library data level operations on action ************** */
@@ -356,7 +356,6 @@ bAction *BKE_action_add(Main *bmain, const char name[])
/* *************** Action Groups *************** */
-/* Get the active action-group for an Action */
bActionGroup *get_active_actiongroup(bAction *act)
{
bActionGroup *agrp = NULL;
@@ -372,7 +371,6 @@ bActionGroup *get_active_actiongroup(bAction *act)
return agrp;
}
-/* Make the given Action-Group the active one */
void set_active_action_group(bAction *act, bActionGroup *agrp, short select)
{
bActionGroup *grp;
@@ -393,7 +391,6 @@ void set_active_action_group(bAction *act, bActionGroup *agrp, short select)
}
}
-/* Sync colors used for action/bone group with theme settings */
void action_group_colors_sync(bActionGroup *grp, const bActionGroup *ref_grp)
{
/* Only do color copying if using a custom color (i.e. not default color). */
@@ -424,7 +421,6 @@ void action_group_colors_sync(bActionGroup *grp, const bActionGroup *ref_grp)
}
}
-/* Add a new action group with the given name to the action */
bActionGroup *action_groups_add_new(bAction *act, const char name[])
{
bActionGroup *agrp;
@@ -450,10 +446,6 @@ bActionGroup *action_groups_add_new(bAction *act, const char name[])
return agrp;
}
-/* Add given channel into (active) group
- * - assumes that channel is not linked to anything anymore
- * - always adds at the end of the group
- */
void action_groups_add_channel(bAction *act, bActionGroup *agrp, FCurve *fcurve)
{
/* sanity checks */
@@ -522,10 +514,6 @@ void action_groups_add_channel(bAction *act, bActionGroup *agrp, FCurve *fcurve)
fcurve->grp = agrp;
}
-/* Reconstruct group channel pointers.
- * Assumes that the groups referred to by the FCurves are already in act->groups.
- * Reorders the main channel list to match group order.
- */
void BKE_action_groups_reconstruct(bAction *act)
{
/* Sanity check. */
@@ -565,7 +553,6 @@ void BKE_action_groups_reconstruct(bAction *act)
BLI_movelisttolist(&act->curves, &ungrouped);
}
-/* Remove the given channel from all groups */
void action_groups_remove_channel(bAction *act, FCurve *fcu)
{
/* sanity checks */
@@ -606,7 +593,6 @@ void action_groups_remove_channel(bAction *act, FCurve *fcu)
BLI_remlink(&act->curves, fcu);
}
-/* Find a group with the given name */
bActionGroup *BKE_action_group_find_name(bAction *act, const char name[])
{
/* sanity checks */
@@ -618,7 +604,6 @@ bActionGroup *BKE_action_group_find_name(bAction *act, const char name[])
return BLI_findstring(&act->groups, name, offsetof(bActionGroup, name));
}
-/* Clear all 'temp' flags on all groups */
void action_groups_clear_tempflags(bAction *act)
{
bActionGroup *agrp;
@@ -641,10 +626,6 @@ void BKE_pose_channel_session_uuid_generate(bPoseChannel *pchan)
pchan->runtime.session_uuid = BLI_session_uuid_generate();
}
-/**
- * Return a pointer to the pose channel of the given name
- * from this pose.
- */
bPoseChannel *BKE_pose_channel_find_name(const bPose *pose, const char *name)
{
if (ELEM(NULL, pose, name) || (name[0] == '\0')) {
@@ -658,14 +639,6 @@ bPoseChannel *BKE_pose_channel_find_name(const bPose *pose, const char *name)
return BLI_findstring(&pose->chanbase, name, offsetof(bPoseChannel, name));
}
-/**
- * Looks to see if the channel with the given name
- * already exists in this pose - if not a new one is
- * allocated and initialized.
- *
- * \note Use with care, not on Armature poses but for temporal ones.
- * \note (currently used for action constraints and in rebuild_pose).
- */
bPoseChannel *BKE_pose_channel_ensure(bPose *pose, const char *name)
{
bPoseChannel *chan;
@@ -732,12 +705,6 @@ bool BKE_pose_channels_is_valid(const bPose *pose)
#endif
-/**
- * Find the active pose-channel for an object
- * (we can't just use pose, as layer info is in armature)
- *
- * \note #Object, not #bPose is used here, as we need layer info from Armature.
- */
bPoseChannel *BKE_pose_channel_active(Object *ob)
{
bArmature *arm = (ob) ? ob->data : NULL;
@@ -757,15 +724,6 @@ bPoseChannel *BKE_pose_channel_active(Object *ob)
return NULL;
}
-/**
- * Use this when detecting the "other selected bone",
- * when we have multiple armatures in pose mode.
- *
- * In this case the active-selected is an obvious choice when finding the target for a
- * constraint for eg. however from the users perspective the active pose bone of the
- * active object is the _real_ active bone, so any other non-active selected bone
- * is a candidate for being the other selected bone, see: T58447.
- */
bPoseChannel *BKE_pose_channel_active_or_first_selected(struct Object *ob)
{
bArmature *arm = (ob) ? ob->data : NULL;
@@ -789,9 +747,6 @@ bPoseChannel *BKE_pose_channel_active_or_first_selected(struct Object *ob)
return NULL;
}
-/**
- * \see #ED_armature_ebone_get_mirrored (edit-mode, matching function)
- */
bPoseChannel *BKE_pose_channel_get_mirrored(const bPose *pose, const char *name)
{
char name_flip[MAXBONENAME];
@@ -818,12 +773,6 @@ const char *BKE_pose_ikparam_get_name(bPose *pose)
return NULL;
}
-/**
- * Allocate a new pose on the heap, and copy the src pose and its channels
- * into the new pose. *dst is set to the newly allocated structure, and assumed to be NULL.
- *
- * \param dst: Should be freed already, makes entire duplicate.
- */
void BKE_pose_copy_data_ex(bPose **dst,
const bPose *src,
const int flag,
@@ -975,10 +924,6 @@ bool BKE_pose_channel_in_IK_chain(Object *ob, bPoseChannel *pchan)
return pose_channel_in_IK_chain(ob, pchan, 0);
}
-/**
- * Removes the hash for quick lookup of channels, must
- * be done when adding/removing channels.
- */
void BKE_pose_channels_hash_ensure(bPose *pose)
{
if (!pose->chanhash) {
@@ -1014,9 +959,6 @@ static void pose_channels_remove_internal_links(Object *ob, bPoseChannel *unlink
}
}
-/**
- * Selectively remove pose channels.
- */
void BKE_pose_channels_remove(Object *ob,
bool (*filter_fn)(const char *bone_name, void *user_data),
void *user_data)
@@ -1086,10 +1028,6 @@ void BKE_pose_channels_remove(Object *ob,
}
}
-/**
- * Deallocates a pose channel.
- * Does not free the pose channel itself.
- */
void BKE_pose_channel_free_ex(bPoseChannel *pchan, bool do_id_user)
{
if (pchan->custom) {
@@ -1118,13 +1056,11 @@ void BKE_pose_channel_free_ex(bPoseChannel *pchan, bool do_id_user)
BKE_pose_channel_runtime_free(&pchan->runtime);
}
-/** Clears the runtime cache of a pose channel without free. */
void BKE_pose_channel_runtime_reset(bPoseChannel_Runtime *runtime)
{
memset(runtime, 0, sizeof(*runtime));
}
-/* Reset all non-persistent fields. */
void BKE_pose_channel_runtime_reset_on_copy(bPoseChannel_Runtime *runtime)
{
const SessionUUID uuid = runtime->session_uuid;
@@ -1132,13 +1068,11 @@ void BKE_pose_channel_runtime_reset_on_copy(bPoseChannel_Runtime *runtime)
runtime->session_uuid = uuid;
}
-/** Deallocates runtime cache of a pose channel */
void BKE_pose_channel_runtime_free(bPoseChannel_Runtime *runtime)
{
BKE_pose_channel_free_bbone_cache(runtime);
}
-/** Deallocates runtime cache of a pose channel's B-Bone shape. */
void BKE_pose_channel_free_bbone_cache(bPoseChannel_Runtime *runtime)
{
runtime->bbone_segments = 0;
@@ -1153,10 +1087,6 @@ void BKE_pose_channel_free(bPoseChannel *pchan)
BKE_pose_channel_free_ex(pchan, true);
}
-/**
- * Removes and deallocates all channels from a pose.
- * Does not free the pose itself.
- */
void BKE_pose_channels_free_ex(bPose *pose, bool do_id_user)
{
bPoseChannel *pchan;
@@ -1203,9 +1133,6 @@ void BKE_pose_free_data(bPose *pose)
BKE_pose_free_data_ex(pose, true);
}
-/**
- * Removes and deallocates all data from a pose, and also frees the pose.
- */
void BKE_pose_free_ex(bPose *pose, bool do_id_user)
{
if (pose) {
@@ -1220,13 +1147,6 @@ void BKE_pose_free(bPose *pose)
BKE_pose_free_ex(pose, true);
}
-/**
- * Copy the internal members of each pose channel including constraints
- * and ID-Props, used when duplicating bones in editmode.
- * (unlike copy_pose_channel_data which only does posing-related stuff).
- *
- * \note use when copying bones in editmode (on returned value from #BKE_pose_channel_ensure)
- */
void BKE_pose_channel_copy_data(bPoseChannel *pchan, const bPoseChannel *pchan_from)
{
/* copy transform locks */
@@ -1276,10 +1196,6 @@ void BKE_pose_channel_copy_data(bPoseChannel *pchan, const bPoseChannel *pchan_f
pchan->drawflag = pchan_from->drawflag;
}
-/* checks for IK constraint, Spline IK, and also for Follow-Path constraint.
- * can do more constraints flags later
- */
-/* pose should be entirely OK */
void BKE_pose_update_constraint_flags(bPose *pose)
{
bPoseChannel *pchan, *parchan;
@@ -1354,7 +1270,6 @@ void BKE_pose_tag_update_constraint_flags(bPose *pose)
/* ************************** Bone Groups ************************** */
-/* Adds a new bone-group (name may be NULL) */
bActionGroup *BKE_pose_add_group(bPose *pose, const char *name)
{
bActionGroup *grp;
@@ -1373,8 +1288,6 @@ bActionGroup *BKE_pose_add_group(bPose *pose, const char *name)
return grp;
}
-/* Remove the given bone-group (expects 'virtual' index (+1 one, used by active_group etc.))
- * index might be invalid ( < 1), in which case it will be find from grp. */
void BKE_pose_remove_group(bPose *pose, bActionGroup *grp, const int index)
{
bPoseChannel *pchan;
@@ -1413,7 +1326,6 @@ void BKE_pose_remove_group(bPose *pose, bActionGroup *grp, const int index)
}
}
-/* Remove the indexed bone-group (expects 'virtual' index (+1 one, used by active_group etc.)) */
void BKE_pose_remove_group_index(bPose *pose, const int index)
{
bActionGroup *grp = NULL;
@@ -1427,7 +1339,6 @@ void BKE_pose_remove_group_index(bPose *pose, const int index)
/* ************** F-Curve Utilities for Actions ****************** */
-/* Check if the given action has any keyframes */
bool action_has_motion(const bAction *act)
{
FCurve *fcu;
@@ -1486,7 +1397,6 @@ bool BKE_action_has_single_frame(const struct bAction *act)
return found_key;
}
-/* Calculate the extents of given action */
void calc_action_range(const bAction *act, float *start, float *end, short incl_modifiers)
{
FCurve *fcu;
@@ -1574,9 +1484,27 @@ void calc_action_range(const bAction *act, float *start, float *end, short incl_
}
}
-/* Return flags indicating which transforms the given object/posechannel has
- * - if 'curves' is provided, a list of links to these curves are also returned
- */
+void BKE_action_get_frame_range(const struct bAction *act, float *r_start, float *r_end)
+{
+ if (act && (act->flag & ACT_FRAME_RANGE)) {
+ *r_start = act->frame_start;
+ *r_end = act->frame_end;
+ }
+ else {
+ calc_action_range(act, r_start, r_end, false);
+ }
+
+ /* Ensure that action is at least 1 frame long (for NLA strips to have a valid length). */
+ if (*r_start >= *r_end) {
+ *r_end = *r_start + 1.0f;
+ }
+}
+
+bool BKE_action_is_cyclic(const struct bAction *act)
+{
+ return act && (act->flag & ACT_FRAME_RANGE) && (act->flag & ACT_CYCLIC);
+}
+
short action_get_item_transforms(bAction *act, Object *ob, bPoseChannel *pchan, ListBase *curves)
{
PointerRNA ptr;
@@ -1707,9 +1635,6 @@ short action_get_item_transforms(bAction *act, Object *ob, bPoseChannel *pchan,
/* ************** Pose Management Tools ****************** */
-/**
- * Zero the pose transforms for the entire pose or only for selected bones.
- */
void BKE_pose_rest(bPose *pose, bool selected_bones_only)
{
bPoseChannel *pchan;
@@ -1774,7 +1699,6 @@ void BKE_pose_copy_pchan_result(bPoseChannel *pchanto, const bPoseChannel *pchan
pchanto->protectflag = pchanfrom->protectflag;
}
-/* both poses should be in sync */
bool BKE_pose_copy_result(bPose *to, bPose *from)
{
bPoseChannel *pchanto, *pchanfrom;
@@ -1799,7 +1723,6 @@ bool BKE_pose_copy_result(bPose *to, bPose *from)
return true;
}
-/* Tag pose for recalc. Also tag all related data to be recalc. */
void BKE_pose_tag_recalc(Main *bmain, bPose *pose)
{
pose->flag |= POSE_RECALC;
@@ -1809,9 +1732,6 @@ void BKE_pose_tag_recalc(Main *bmain, bPose *pose)
DEG_relations_tag_update(bmain);
}
-/* For the calculation of the effects of an Action at the given frame on an object
- * This is currently only used for the Action Constraint
- */
void what_does_obaction(Object *ob,
Object *workob,
bPose *pose,
diff --git a/source/blender/blenkernel/intern/anim_data.c b/source/blender/blenkernel/intern/anim_data.c
index 21887d514d9..d93d5c456d8 100644
--- a/source/blender/blenkernel/intern/anim_data.c
+++ b/source/blender/blenkernel/intern/anim_data.c
@@ -69,7 +69,6 @@ static CLG_LogRef LOG = {"bke.anim_sys"};
/* Getter/Setter -------------------------------------------- */
-/* Check if ID can have AnimData */
bool id_type_can_have_animdata(const short id_type)
{
const IDTypeInfo *typeinfo = BKE_idtype_get_info_from_idcode(id_type);
@@ -89,9 +88,6 @@ bool id_can_have_animdata(const ID *id)
return id_type_can_have_animdata(GS(id->name));
}
-/**
- * Get #AnimData from the given ID-block.
- */
AnimData *BKE_animdata_from_id(ID *id)
{
/* In order for this to work, we assume that the #AnimData pointer is stored
@@ -106,9 +102,6 @@ AnimData *BKE_animdata_from_id(ID *id)
return NULL;
}
-/**
- * Ensure #AnimData exists in the given ID-block (when supported).
- */
AnimData *BKE_animdata_ensure_id(ID *id)
{
/* In order for this to work, we assume that the #AnimData pointer is stored
@@ -137,16 +130,6 @@ AnimData *BKE_animdata_ensure_id(ID *id)
/* Action Setter --------------------------------------- */
-/**
- * Called when user tries to change the active action of an #AnimData block
- * (via RNA, Outliner, etc.)
- *
- * \param reports: Can be NULL.
- * \param id: The owner of the animation data
- * \param act: The Action to set, or NULL to clear.
- *
- * \return true when the action was successfully updated, false otherwise.
- */
bool BKE_animdata_set_action(ReportList *reports, ID *id, bAction *act)
{
AnimData *adt = BKE_animdata_from_id(id);
@@ -226,7 +209,6 @@ bool BKE_animdata_action_ensure_idroot(const ID *owner, bAction *action)
/* Freeing -------------------------------------------- */
-/* Free AnimData used by the nominated ID-block, and clear ID-block's AnimData pointer */
void BKE_animdata_free(ID *id, const bool do_id_user)
{
/* Only some ID-blocks have this info for now, so we cast the
@@ -287,10 +269,6 @@ bool BKE_animdata_id_is_animated(const struct ID *id)
!BLI_listbase_is_empty(&adt->overrides);
}
-/**
- * Callback used by lib_query to walk over all ID usages (mimics `foreach_id` callback of
- * `IDTypeInfo` structure).
- */
void BKE_animdata_foreach_id(AnimData *adt, LibraryForeachIDData *data)
{
LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) {
@@ -309,12 +287,6 @@ void BKE_animdata_foreach_id(AnimData *adt, LibraryForeachIDData *data)
/* Copying -------------------------------------------- */
-/**
- * Make a copy of the given AnimData - to be used when copying data-blocks.
- * \param flag: Control ID pointers management,
- * see LIB_ID_CREATE_.../LIB_ID_COPY_... flags in BKE_lib_id.h
- * \return The copied animdata.
- */
AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const int flag)
{
AnimData *dadt;
@@ -367,11 +339,6 @@ AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const int flag)
return dadt;
}
-/**
- * \param flag: Control ID pointers management,
- * see LIB_ID_CREATE_.../LIB_ID_COPY_... flags in BKE_lib_id.h
- * \return true is successfully copied.
- */
bool BKE_animdata_copy_id(Main *bmain, ID *id_to, ID *id_from, const int flag)
{
AnimData *adt;
@@ -432,7 +399,6 @@ void BKE_animdata_duplicate_id_action(struct Main *bmain,
}
}
-/* Merge copies of the data from the src AnimData into the destination AnimData */
void BKE_animdata_merge_copy(
Main *bmain, ID *dst_id, ID *src_id, eAnimData_MergeCopy_Modes action_mode, bool fix_drivers)
{
@@ -647,12 +613,6 @@ static void animdata_move_drivers_by_basepath(AnimData *srcAdt,
}
}
-/* Transfer the animation data from srcID to dstID where the srcID
- * animation data is based off "basepath", creating new AnimData and
- * associated data as necessary.
- *
- * basepaths is a list of AnimationBasePathChange.
- */
void BKE_animdata_transfer_by_basepath(Main *bmain, ID *srcID, ID *dstID, ListBase *basepaths)
{
AnimData *srcAdt = NULL, *dstAdt = NULL;
@@ -716,17 +676,6 @@ void BKE_animdata_transfer_by_basepath(Main *bmain, ID *srcID, ID *dstID, ListBa
}
}
-/**
- * Temporary wrapper for driver operators for buttons to make it easier to create
- * such drivers by rerouting all paths through the active object instead so that
- * they will get picked up by the dependency system.
- *
- * \param C: Context pointer - for getting active data
- * \param[in,out] ptr: RNA pointer for property's data-block.
- * May be modified as result of path remapping.
- * \param prop: RNA definition of property to add for
- * \return MEM_alloc'd string representing the path to the property from the given #PointerRNA
- */
char *BKE_animdata_driver_path_hack(bContext *C,
PointerRNA *ptr,
PropertyRNA *prop,
@@ -956,14 +905,6 @@ static bool nlastrips_path_rename_fix(ID *owner_id,
/* Rename Sub-ID Entities in RNA Paths ----------------------- */
-/* Fix up the given RNA-Path
- *
- * This is just an external wrapper for the RNA-Path fixing function,
- * with input validity checks on top of the basic method.
- *
- * NOTE: it is assumed that the structure we're replacing is <prefix><["><name><"]>
- * i.e. pose.bones["Bone"]
- */
char *BKE_animsys_fix_rna_path_rename(ID *owner_id,
char *old_path,
const char *prefix,
@@ -1019,14 +960,6 @@ char *BKE_animsys_fix_rna_path_rename(ID *owner_id,
return result;
}
-/* Fix all RNA_Paths in the given Action, relative to the given ID block
- *
- * This is just an external wrapper for the F-Curve fixing function,
- * with input validity checks on top of the basic method.
- *
- * NOTE: it is assumed that the structure we're replacing is <prefix><["><name><"]>
- * i.e. pose.bones["Bone"]
- */
void BKE_action_fix_paths_rename(ID *owner_id,
bAction *act,
const char *prefix,
@@ -1070,10 +1003,6 @@ void BKE_action_fix_paths_rename(ID *owner_id,
MEM_freeN(newN);
}
-/* Fix all RNA-Paths in the AnimData block used by the given ID block
- * NOTE: it is assumed that the structure we're replacing is <prefix><["><name><"]>
- * i.e. pose.bones["Bone"]
- */
void BKE_animdata_fix_paths_rename(ID *owner_id,
AnimData *adt,
ID *ref_id,
@@ -1282,7 +1211,6 @@ void BKE_fcurves_id_cb(ID *id, ID_FCurve_Edit_Callback func, void *user_data)
}
}
-/* apply the given callback function on all F-Curves attached to data in main database */
void BKE_fcurves_main_cb(Main *bmain, ID_FCurve_Edit_Callback func, void *user_data)
{
/* Wrap F-Curve operation stuff to pass to the general AnimData-level func */
@@ -1294,7 +1222,6 @@ void BKE_fcurves_main_cb(Main *bmain, ID_FCurve_Edit_Callback func, void *user_d
/* Whole Database Ops -------------------------------------------- */
-/* apply the given callback function on all data in main database */
void BKE_animdata_main_cb(Main *bmain, ID_AnimData_Edit_Callback func, void *user_data)
{
ID *id;
@@ -1405,10 +1332,6 @@ void BKE_animdata_main_cb(Main *bmain, ID_AnimData_Edit_Callback func, void *use
ANIMDATA_IDS_CB(bmain->simulations.first);
}
-/* Fix all RNA-Paths throughout the database (directly access the Global.main version)
- * NOTE: it is assumed that the structure we're replacing is <prefix><["><name><"]>
- * i.e. pose.bones["Bone"]
- */
void BKE_animdata_fix_paths_rename_all(ID *ref_id,
const char *prefix,
const char *oldName,
@@ -1418,11 +1341,6 @@ void BKE_animdata_fix_paths_rename_all(ID *ref_id,
BKE_animdata_fix_paths_rename_all_ex(bmain, ref_id, prefix, oldName, newName, 0, 0, 1);
}
-/* Fix all RNA-Paths throughout the database
- * NOTE: it is assumed that the structure we're replacing is <prefix><["><name><"]>
- * i.e. pose.bones["Bone"]
- */
-/* TODO: use BKE_animdata_main_cb for looping over all data. */
void BKE_animdata_fix_paths_rename_all_ex(Main *bmain,
ID *ref_id,
const char *prefix,
@@ -1432,6 +1350,7 @@ void BKE_animdata_fix_paths_rename_all_ex(Main *bmain,
const int newSubscript,
const bool verify_paths)
{
+ /* TODO: use BKE_animdata_main_cb for looping over all data. */
ID *id;
diff --git a/source/blender/blenkernel/intern/anim_path.c b/source/blender/blenkernel/intern/anim_path.c
index de470a15041..43af55e9b6b 100644
--- a/source/blender/blenkernel/intern/anim_path.c
+++ b/source/blender/blenkernel/intern/anim_path.c
@@ -230,14 +230,6 @@ static bool binary_search_anim_path(const float *accum_len_arr,
}
}
-/**
- * Calculate the deformation implied by the curve path at a given parametric position,
- * and returns whether this operation succeeded.
- *
- * \param ctime: Time is normalized range <0-1>.
- *
- * \return success.
- */
bool BKE_where_on_path(const Object *ob,
float ctime,
float r_vec[4],
@@ -254,6 +246,10 @@ bool BKE_where_on_path(const Object *ob,
CLOG_WARN(&LOG, "No curve cache!");
return false;
}
+ if (ob->runtime.curve_cache->anim_path_accum_length == NULL) {
+ CLOG_WARN(&LOG, "No anim path!");
+ return false;
+ }
/* We only use the first curve. */
BevList *bl = ob->runtime.curve_cache->bev.first;
if (bl == NULL || !bl->nr) {
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index cbdcf43c039..b5ea68aaadc 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -84,8 +84,6 @@ static CLG_LogRef LOG = {"bke.anim_sys"};
/* Finding Tools --------------------------- */
-/* Find the first path that matches the given criteria */
-/* TODO: do we want some method to perform partial matches too? */
KS_Path *BKE_keyingset_find_path(KeyingSet *ks,
ID *id,
const char group_name[],
@@ -138,8 +136,6 @@ KS_Path *BKE_keyingset_find_path(KeyingSet *ks,
/* Defining Tools --------------------------- */
-/* Used to create a new 'custom' KeyingSet for the user,
- * that will be automatically added to the stack */
KeyingSet *BKE_keyingset_add(
ListBase *list, const char idname[], const char name[], short flag, short keyingflag)
{
@@ -174,9 +170,6 @@ KeyingSet *BKE_keyingset_add(
return ks;
}
-/* Add a path to a KeyingSet. Nothing is returned for now...
- * Checks are performed to ensure that destination is appropriate for the KeyingSet in question
- */
KS_Path *BKE_keyingset_add_path(KeyingSet *ks,
ID *id,
const char group_name[],
@@ -240,7 +233,6 @@ KS_Path *BKE_keyingset_add_path(KeyingSet *ks,
return ksp;
}
-/* Free the given Keying Set path */
void BKE_keyingset_free_path(KeyingSet *ks, KS_Path *ksp)
{
/* sanity check */
@@ -257,7 +249,6 @@ void BKE_keyingset_free_path(KeyingSet *ks, KS_Path *ksp)
BLI_freelinkN(&ks->paths, ksp);
}
-/* Copy all KeyingSets in the given list */
void BKE_keyingsets_copy(ListBase *newlist, const ListBase *list)
{
KeyingSet *ksn;
@@ -276,7 +267,6 @@ void BKE_keyingsets_copy(ListBase *newlist, const ListBase *list)
/* Freeing Tools --------------------------- */
-/* Free data for KeyingSet but not set itself */
void BKE_keyingset_free(KeyingSet *ks)
{
KS_Path *ksp, *kspn;
@@ -293,7 +283,6 @@ void BKE_keyingset_free(KeyingSet *ks)
}
}
-/* Free all the KeyingSets in the given list */
void BKE_keyingsets_free(ListBase *list)
{
KeyingSet *ks, *ksn;
@@ -490,7 +479,6 @@ bool BKE_animsys_read_from_rna_path(PathResolvedRNA *anim_rna, float *r_value)
return true;
}
-/* Write the given value to a setting using RNA, and return success */
bool BKE_animsys_write_to_rna_path(PathResolvedRNA *anim_rna, const float value)
{
PropertyRNA *prop = anim_rna->prop;
@@ -831,7 +819,6 @@ static void action_idcode_patch_check(ID *id, bAction *act)
/* ----------------------------------------- */
-/* Evaluate Action Group */
void animsys_evaluate_action_group(PointerRNA *ptr,
bAction *act,
bActionGroup *agrp,
@@ -864,7 +851,6 @@ void animsys_evaluate_action_group(PointerRNA *ptr,
}
}
-/* Evaluate Action (F-Curve Bag) */
void animsys_evaluate_action(PointerRNA *ptr,
bAction *act,
const AnimationEvalContext *anim_eval_context,
@@ -881,7 +867,6 @@ void animsys_evaluate_action(PointerRNA *ptr,
animsys_evaluate_fcurves(ptr, &act->curves, anim_eval_context, flush_to_original);
}
-/* Evaluate Action and blend it into the current values of the animated properties. */
void animsys_blend_in_action(PointerRNA *ptr,
bAction *act,
const AnimationEvalContext *anim_eval_context,
@@ -960,7 +945,6 @@ static void nlastrip_evaluate_controls(NlaStrip *strip,
}
}
-/* gets the strip active at the current time for a list of strips for evaluation purposes */
NlaEvalStrip *nlastrips_ctime_get_strip(ListBase *list,
ListBase *strips,
short index,
@@ -2402,7 +2386,6 @@ static void nlastrip_evaluate_meta(PointerRNA *ptr,
nlaeval_fmodifiers_split_stacks(&strip->modifiers, modifiers);
}
-/* evaluates the given evaluation strip */
void nlastrip_evaluate(PointerRNA *ptr,
NlaEvalData *channels,
ListBase *modifiers,
@@ -2447,7 +2430,6 @@ void nlastrip_evaluate(PointerRNA *ptr,
strip->flag &= ~NLASTRIP_FLAG_EDIT_TOUCHED;
}
-/* write the accumulated settings to */
void nladata_flush_channels(PointerRNA *ptr,
NlaEvalData *channels,
NlaEvalSnapshot *snapshot,
@@ -2977,14 +2959,6 @@ void nlasnapshot_ensure_channels(NlaEvalData *eval_data, NlaEvalSnapshot *snapsh
}
}
-/**
- * Blends the \a lower_snapshot with the \a upper_snapshot into \a r_blended_snapshot according
- * to the given \a upper_blendmode and \a upper_influence.
- *
- * For \a upper_snapshot, blending limited to values in the \a blend_domain.
- * For Replace blend-mode, this allows the upper snapshot to have a location XYZ channel
- * where only a subset of values are blended.
- */
void nlasnapshot_blend(NlaEvalData *eval_data,
NlaEvalSnapshot *lower_snapshot,
NlaEvalSnapshot *upper_snapshot,
@@ -3012,14 +2986,6 @@ void nlasnapshot_blend(NlaEvalData *eval_data,
}
}
-/**
- * Using \a blended_snapshot and \a lower_snapshot, we can solve for the \a r_upper_snapshot.
- *
- * Only channels that exist within \a blended_snapshot are inverted.
- *
- * For \a r_upper_snapshot, disables \a NlaEvalChannelSnapshot->remap_domain for failed inversions.
- * Only values within the \a remap_domain are processed.
- */
void nlasnapshot_blend_get_inverted_upper_snapshot(NlaEvalData *eval_data,
NlaEvalSnapshot *lower_snapshot,
NlaEvalSnapshot *blended_snapshot,
@@ -3050,15 +3016,6 @@ void nlasnapshot_blend_get_inverted_upper_snapshot(NlaEvalData *eval_data,
/* ---------------------- */
-/**
- * Prepare data necessary to compute correct keyframe values for NLA strips
- * with non-Replace mode or influence different from 1.
- *
- * \param cache: List used to cache contexts for reuse when keying
- * multiple channels in one operation.
- * \param ptr: RNA pointer to the Object with the animation.
- * \return Keyframing context, or NULL if not necessary.
- */
NlaKeyframingContext *BKE_animsys_get_nla_keyframing_context(
struct ListBase *cache,
struct PointerRNA *ptr,
@@ -3095,18 +3052,6 @@ NlaKeyframingContext *BKE_animsys_get_nla_keyframing_context(
return ctx;
}
-/**
- * Apply correction from the NLA context to the values about to be keyframed.
- *
- * \param context: Context to use (may be NULL).
- * \param prop_ptr: Property about to be keyframed.
- * \param[in,out] values: Array of property values to adjust.
- * \param count: Number of values in the array.
- * \param index: Index of the element about to be updated, or -1.
- * \param[out] r_force_all: Set to true if all channels must be inserted. May be NULL.
- * \return False if correction fails due to a division by zero,
- * or null r_force_all when all channels are required.
- */
bool BKE_animsys_nla_remap_keyframe_values(struct NlaKeyframingContext *context,
struct PointerRNA *prop_ptr,
struct PropertyRNA *prop,
@@ -3202,9 +3147,6 @@ bool BKE_animsys_nla_remap_keyframe_values(struct NlaKeyframingContext *context,
return successful_remap;
}
-/**
- * Free all cached contexts from the list.
- */
void BKE_animsys_free_nla_keyframing_context_cache(struct ListBase *cache)
{
LISTBASE_FOREACH (NlaKeyframingContext *, ctx, cache) {
@@ -3270,12 +3212,6 @@ static void animsys_evaluate_overrides(PointerRNA *ptr, AnimData *adt)
* However, the code for this is relatively harmless, so is left in the code for now.
*/
-/* Evaluation loop for evaluation animation data
- *
- * This assumes that the animation-data provided belongs to the ID block in question,
- * and that the flags for which parts of the anim-data settings need to be recalculated
- * have been set already by the depsgraph. Now, we use the recalc
- */
void BKE_animsys_evaluate_animdata(ID *id,
AnimData *adt,
const AnimationEvalContext *anim_eval_context,
@@ -3329,13 +3265,6 @@ void BKE_animsys_evaluate_animdata(ID *id,
animsys_evaluate_overrides(&id_ptr, adt);
}
-/* Evaluation of all ID-blocks with Animation Data blocks - Animation Data Only
- *
- * This will evaluate only the animation info available in the animation data-blocks
- * encountered. In order to enforce the system by which some settings controlled by a
- * 'local' (i.e. belonging in the nearest ID-block that setting is related to, not a
- * standard 'root') block are overridden by a larger 'user'
- */
void BKE_animsys_evaluate_all_animation(Main *main, Depsgraph *depsgraph, float ctime)
{
ID *id;
diff --git a/source/blender/blenkernel/intern/anim_visualization.c b/source/blender/blenkernel/intern/anim_visualization.c
index 56bd8e769bc..fdea52bcd64 100644
--- a/source/blender/blenkernel/intern/anim_visualization.c
+++ b/source/blender/blenkernel/intern/anim_visualization.c
@@ -39,7 +39,6 @@
/* ******************************************************************** */
/* Animation Visualization */
-/* Initialize the default settings for animation visualization */
void animviz_settings_init(bAnimVizSettings *avs)
{
/* sanity check */
@@ -62,7 +61,6 @@ void animviz_settings_init(bAnimVizSettings *avs)
/* ------------------- */
-/* Free the given motion path's cache */
void animviz_free_motionpath_cache(bMotionPath *mpath)
{
/* sanity check */
@@ -84,9 +82,6 @@ void animviz_free_motionpath_cache(bMotionPath *mpath)
mpath->length = 0;
}
-/* Free the given motion path instance and its data
- * NOTE: this frees the motion path given!
- */
void animviz_free_motionpath(bMotionPath *mpath)
{
/* sanity check */
@@ -103,7 +98,6 @@ void animviz_free_motionpath(bMotionPath *mpath)
/* ------------------- */
-/* Make a copy of motionpath data, so that viewing with copy on write works */
bMotionPath *animviz_copy_motionpath(const bMotionPath *mpath_src)
{
bMotionPath *mpath_dst;
@@ -125,14 +119,6 @@ bMotionPath *animviz_copy_motionpath(const bMotionPath *mpath_src)
/* ------------------- */
-/**
- * Setup motion paths for the given data.
- * \note Only used when explicitly calculating paths on bones which may/may not be consider already
- *
- * \param scene: Current scene (for frame ranges, etc.)
- * \param ob: Object to add paths for (must be provided)
- * \param pchan: Posechannel to add paths for (optional; if not provided, object-paths are assumed)
- */
bMotionPath *animviz_verify_motionpaths(ReportList *reports,
Scene *scene,
Object *ob,
diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c
index d872dc67dcb..9dd4c7e503a 100644
--- a/source/blender/blenkernel/intern/appdir.c
+++ b/source/blender/blenkernel/intern/appdir.c
@@ -99,15 +99,6 @@ static bool is_appdir_init = false;
# define ASSERT_IS_INIT() ((void)0)
#endif
-/**
- * Sanity check to ensure correct API use in debug mode.
- *
- * Run this once the first level of arguments has been passed so we can be sure
- * `--env-system-datafiles`, and other `--env-*` arguments has been passed.
- *
- * Without this any callers to this module that run early on,
- * will miss out on changes from parsing arguments.
- */
void BKE_appdir_init(void)
{
#ifndef NDEBUG
@@ -147,14 +138,6 @@ static char *blender_version_decimal(const int version)
/** \name Default Directories
* \{ */
-/**
- * Get the folder that's the "natural" starting point for browsing files on an OS.
- * - Unix: `$HOME`
- * - Windows: `%userprofile%/Documents`
- *
- * \note On Windows `Users/{MyUserName}/Documents` is used as it's the default location to save
- * documents.
- */
const char *BKE_appdir_folder_default(void)
{
#ifndef WIN32
@@ -190,29 +173,17 @@ const char *BKE_appdir_folder_default_or_root(void)
return path;
}
-/**
- * Get the user's home directory, i.e.
- * - Unix: `$HOME`
- * - Windows: `%userprofile%`
- */
const char *BKE_appdir_folder_home(void)
{
-#ifndef WIN32
- return BLI_getenv("HOME");
-#else /* Windows */
+#ifdef WIN32
return BLI_getenv("userprofile");
+#elif defined(__APPLE__)
+ return BLI_expand_tilde("~/");
+#else
+ return BLI_getenv("HOME");
#endif
}
-/**
- * Get the user's document directory, i.e.
- * - Linux: `$HOME/Documents`
- * - Windows: `%userprofile%/Documents`
- *
- * If this can't be found using OS queries (via Ghost), try manually finding it.
- *
- * \returns True if the path is valid and points to an existing directory.
- */
bool BKE_appdir_folder_documents(char *dir)
{
dir[0] = '\0';
@@ -243,15 +214,6 @@ bool BKE_appdir_folder_documents(char *dir)
return true;
}
-/**
- * Get the user's cache directory, i.e.
- * - Linux: `$HOME/.cache/blender/`
- * - Windows: `%USERPROFILE%\AppData\Local\Blender Foundation\Blender\`
- * - MacOS: `/Library/Caches/Blender`
- *
- * \returns True if the path is valid. It doesn't create or checks format
- * if the `blender` folder exists. It does check if the parent of the path exists.
- */
bool BKE_appdir_folder_caches(char *r_path, const size_t path_len)
{
r_path[0] = '\0';
@@ -276,9 +238,6 @@ bool BKE_appdir_folder_caches(char *r_path, const size_t path_len)
return true;
}
-/**
- * Gets a good default directory for fonts.
- */
bool BKE_appdir_font_folder_default(char *dir)
{
char test_dir[FILE_MAXDIR];
@@ -291,10 +250,8 @@ bool BKE_appdir_font_folder_default(char *dir)
BLI_strncpy_wchar_as_utf8(test_dir, wpath, sizeof(test_dir));
}
#elif defined(__APPLE__)
- const char *home = BLI_getenv("HOME");
- if (home) {
- BLI_path_join(test_dir, sizeof(test_dir), home, "Library", "Fonts", NULL);
- }
+ STRNCPY(test_dir, BLI_expand_tilde("~/Library/Fonts/"));
+ BLI_path_slash_ensure(test_dir);
#else
STRNCPY(test_dir, "/usr/share/fonts");
#endif
@@ -458,10 +415,6 @@ static bool get_path_local(char *targetpath,
targetpath, targetpath_len, folder_name, subfolder_name, version, check_is_dir);
}
-/**
- * Check if this is an install with user files kept together
- * with the Blender executable and its installation files.
- */
bool BKE_appdir_app_is_portable_install(void)
{
/* Detect portable install by the existence of `config` folder. */
@@ -626,13 +579,6 @@ static bool get_path_system(char *targetpath,
/** \name Path Presets API
* \{ */
-/**
- * Get a folder out of the \a folder_id presets for paths.
- *
- * \param subfolder: The name of a directory to check for,
- * this may contain path separators but must resolve to a directory, checked with #BLI_is_dir.
- * \return The path if found, NULL string if not.
- */
bool BKE_appdir_folder_id_ex(const int folder_id,
const char *subfolder,
char *path,
@@ -746,9 +692,6 @@ const char *BKE_appdir_folder_id(const int folder_id, const char *subfolder)
return NULL;
}
-/**
- * Returns the path to a folder in the user area without checking that it actually exists first.
- */
const char *BKE_appdir_folder_id_user_notest(const int folder_id, const char *subfolder)
{
const int version = BLENDER_VERSION;
@@ -795,9 +738,6 @@ const char *BKE_appdir_folder_id_user_notest(const int folder_id, const char *su
return path;
}
-/**
- * Returns the path to a folder in the user area, creating it if it doesn't exist.
- */
const char *BKE_appdir_folder_id_create(const int folder_id, const char *subfolder)
{
const char *path;
@@ -823,10 +763,6 @@ const char *BKE_appdir_folder_id_create(const int folder_id, const char *subfold
return path;
}
-/**
- * Returns the path of the top-level version-specific local, user or system directory.
- * If check_is_dir, then the result will be NULL if the directory doesn't exist.
- */
const char *BKE_appdir_folder_id_version(const int folder_id,
const int version,
const bool check_is_dir)
@@ -942,18 +878,12 @@ void BKE_appdir_program_path_init(const char *argv0)
BLI_split_dir_part(g_app.program_filename, g_app.program_dirname, sizeof(g_app.program_dirname));
}
-/**
- * Path to executable
- */
const char *BKE_appdir_program_path(void)
{
BLI_assert(g_app.program_filename[0]);
return g_app.program_filename;
}
-/**
- * Path to directory of executable
- */
const char *BKE_appdir_program_dir(void)
{
BLI_assert(g_app.program_dirname[0]);
@@ -1047,9 +977,6 @@ static const int app_template_directory_id[2] = {
BLENDER_SYSTEM_SCRIPTS,
};
-/**
- * Return true if templates exist
- */
bool BKE_appdir_app_template_any(void)
{
char temp_dir[FILE_MAX];
@@ -1217,14 +1144,13 @@ static void tempdir_session_create(char *tempdir_session,
BLI_strncpy(tempdir_session, tempdir, tempdir_session_len);
}
-/**
- * Sets #g_app.temp_dirname_base to \a userdir if specified and is a valid directory,
- * otherwise chooses a suitable OS-specific temporary directory.
- * Sets #g_app.temp_dirname_session to a #mkdtemp
- * generated sub-dir of #g_app.temp_dirname_base.
- */
void BKE_tempdir_init(const char *userdir)
{
+ /* Sets #g_app.temp_dirname_base to \a userdir if specified and is a valid directory,
+ * otherwise chooses a suitable OS-specific temporary directory.
+ * Sets #g_app.temp_dirname_session to a #mkdtemp
+ * generated sub-dir of #g_app.temp_dirname_base. */
+
where_is_temp(g_app.temp_dirname_base, sizeof(g_app.temp_dirname_base), userdir);
/* Clear existing temp dir, if needed. */
@@ -1234,25 +1160,16 @@ void BKE_tempdir_init(const char *userdir)
g_app.temp_dirname_session, sizeof(g_app.temp_dirname_session), g_app.temp_dirname_base);
}
-/**
- * Path to temporary directory (with trailing slash)
- */
const char *BKE_tempdir_session(void)
{
return g_app.temp_dirname_session[0] ? g_app.temp_dirname_session : BKE_tempdir_base();
}
-/**
- * Path to persistent temporary directory (with trailing slash)
- */
const char *BKE_tempdir_base(void)
{
return g_app.temp_dirname_base;
}
-/**
- * Delete content of this instance's temp dir.
- */
void BKE_tempdir_session_purge(void)
{
if (g_app.temp_dirname_session[0] && BLI_is_dir(g_app.temp_dirname_session)) {
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index b830c9de5f5..0a91d662c1b 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -322,6 +322,7 @@ IDTypeInfo IDType_ID_AR = {
.name_plural = "armatures",
.translation_context = BLT_I18NCONTEXT_ID_ARMATURE,
.flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = armature_init_data,
.copy_data = armature_copy_data,
@@ -329,6 +330,7 @@ IDTypeInfo IDType_ID_AR = {
.make_local = NULL,
.foreach_id = armature_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = armature_blend_write,
@@ -607,10 +609,6 @@ static Bone *get_named_bone_bonechildren(ListBase *lb, const char *name)
return NULL;
}
-/**
- * Walk the list until the bone is found (slow!),
- * use #BKE_armature_bone_from_name_map for multiple lookups.
- */
Bone *BKE_armature_find_bone_name(bArmature *arm, const char *name)
{
if (!arm) {
@@ -715,10 +713,6 @@ void BKE_armature_refresh_layer_used(struct Depsgraph *depsgraph, struct bArmatu
/** \name Armature Layer Refresh Used
* \{ */
-/* Finds the best possible extension to the name on a particular axis. (For renaming, check for
- * unique names afterwards) strip_number: removes number extensions (TODO: not used)
- * axis: the axis to name on
- * head/tail: the head/tail co-ordinate of the bone on the specified axis */
bool bone_autoside_name(
char name[MAXBONENAME], int UNUSED(strip_number), short axis, float head, float tail)
{
@@ -930,7 +924,6 @@ static void evaluate_cubic_bezier(const float control[4][3],
madd_v3_v3v3fl(r_pos, layer2[0], r_tangent, t);
}
-/* Get "next" and "prev" bones - these are used for handle calculations. */
void BKE_pchan_bbone_handles_get(bPoseChannel *pchan, bPoseChannel **r_prev, bPoseChannel **r_next)
{
if (pchan->bone->bbone_prev_type == BBONE_HANDLE_AUTO) {
@@ -957,7 +950,6 @@ void BKE_pchan_bbone_handles_get(bPoseChannel *pchan, bPoseChannel **r_prev, bPo
}
}
-/* Compute B-Bone spline parameters for the given channel. */
void BKE_pchan_bbone_spline_params_get(struct bPoseChannel *pchan,
const bool rest,
struct BBoneSplineParameters *param)
@@ -1203,8 +1195,6 @@ void BKE_pchan_bbone_spline_params_get(struct bPoseChannel *pchan,
}
}
-/* Fills the array with the desired amount of bone->segments elements.
- * This calculation is done within unit bone space. */
void BKE_pchan_bbone_spline_setup(bPoseChannel *pchan,
const bool rest,
const bool for_deform,
@@ -1217,7 +1207,6 @@ void BKE_pchan_bbone_spline_setup(bPoseChannel *pchan,
pchan->bone->segments = BKE_pchan_bbone_spline_compute(&param, for_deform, result_array);
}
-/* Computes the bezier handle vectors and rolls coming from custom handles. */
void BKE_pchan_bbone_handles_compute(const BBoneSplineParameters *param,
float h1[3],
float *r_roll1,
@@ -1375,8 +1364,6 @@ static void ease_handle_axis(const float deriv1[3], const float deriv2[3], float
}
}
-/* Fills the array with the desired amount of bone->segments elements.
- * This calculation is done within unit bone space. */
int BKE_pchan_bbone_spline_compute(BBoneSplineParameters *param,
const bool for_deform,
Mat4 *result_array)
@@ -1511,7 +1498,6 @@ static void allocate_bbone_cache(bPoseChannel *pchan, int segments)
}
}
-/** Compute and cache the B-Bone shape in the channel runtime struct. */
void BKE_pchan_bbone_segments_cache_compute(bPoseChannel *pchan)
{
bPoseChannel_Runtime *runtime = &pchan->runtime;
@@ -1563,7 +1549,6 @@ void BKE_pchan_bbone_segments_cache_compute(bPoseChannel *pchan)
}
}
-/** Copy cached B-Bone segments from one channel to another */
void BKE_pchan_bbone_segments_cache_copy(bPoseChannel *pchan, bPoseChannel *pchan_from)
{
bPoseChannel_Runtime *runtime = &pchan->runtime;
@@ -1587,10 +1572,6 @@ void BKE_pchan_bbone_segments_cache_copy(bPoseChannel *pchan, bPoseChannel *pcha
}
}
-/**
- * Calculate index and blend factor for the two B-Bone segment nodes
- * affecting the point at 0 <= pos <= 1.
- */
void BKE_pchan_bbone_deform_segment_index(const bPoseChannel *pchan,
float pos,
int *r_index,
@@ -1622,7 +1603,6 @@ void BKE_pchan_bbone_deform_segment_index(const bPoseChannel *pchan,
/** \name Bone Space to Space Conversion API
* \{ */
-/* Convert World-Space Matrix to Pose-Space Matrix */
void BKE_armature_mat_world_to_pose(Object *ob, const float inmat[4][4], float outmat[4][4])
{
float obmat[4][4];
@@ -1639,9 +1619,6 @@ void BKE_armature_mat_world_to_pose(Object *ob, const float inmat[4][4], float o
mul_m4_m4m4(outmat, inmat, obmat);
}
-/* Convert World-Space Location to Pose-Space Location
- * NOTE: this cannot be used to convert to pose-space location of the supplied
- * pose-channel into its local space (i.e. 'visual'-keyframing) */
void BKE_armature_loc_world_to_pose(Object *ob, const float inloc[3], float outloc[3])
{
float xLocMat[4][4];
@@ -1662,8 +1639,6 @@ void BKE_armature_loc_world_to_pose(Object *ob, const float inloc[3], float outl
/** \name Bone Matrix Calculation API
* \{ */
-/* Simple helper, computes the offset bone matrix.
- * offs_bone = yoffs(b-1) + root(b) + bonemat(b). */
void BKE_bone_offset_matrix_get(const Bone *bone, float offs_bone[4][4])
{
BLI_assert(bone->parent != NULL);
@@ -1678,24 +1653,6 @@ void BKE_bone_offset_matrix_get(const Bone *bone, float offs_bone[4][4])
offs_bone[3][1] += bone->parent->length;
}
-/* Construct the matrices (rot/scale and loc)
- * to apply the PoseChannels into the armature (object) space.
- * I.e. (roughly) the "pose_mat(b-1) * yoffs(b-1) * d_root(b) * bone_mat(b)" in the
- * pose_mat(b)= pose_mat(b-1) * yoffs(b-1) * d_root(b) * bone_mat(b) * chan_mat(b)
- * ...function.
- *
- * This allows to get the transformations of a bone in its object space,
- * *before* constraints (and IK) get applied (used by pose evaluation code).
- * And reverse: to find pchan transformations needed to place a bone at a given loc/rot/scale
- * in object space (used by interactive transform, and snapping code).
- *
- * Note that, with the HINGE/NO_SCALE/NO_LOCAL_LOCATION options, the location matrix
- * will differ from the rotation/scale matrix...
- *
- * NOTE: This cannot be used to convert to pose-space transforms of the supplied
- * pose-channel into its local space (i.e. 'visual'-keyframing).
- * (note: I don't understand that, so I keep it :p --mont29).
- */
void BKE_bone_parent_transform_calc_from_pchan(const bPoseChannel *pchan,
BoneParentTransform *r_bpt)
{
@@ -1725,12 +1682,6 @@ void BKE_bone_parent_transform_calc_from_pchan(const bPoseChannel *pchan,
}
}
-/* Compute the parent transform using data decoupled from specific data structures.
- *
- * bone_flag: Bone->flag containing settings
- * offs_bone: delta from parent to current arm_mat (or just arm_mat if no parent)
- * parent_arm_mat, parent_pose_mat: arm_mat and pose_mat of parent, or NULL
- * r_bpt: OUTPUT parent transform */
void BKE_bone_parent_transform_calc_from_matrices(int bone_flag,
int inherit_scale_mode,
const float offs_bone[4][4],
@@ -1912,9 +1863,6 @@ void BKE_bone_parent_transform_apply(const struct BoneParentTransform *bpt,
rescale_m4(outmat, bpt->post_scale);
}
-/* Convert Pose-Space Matrix to Bone-Space Matrix.
- * NOTE: this cannot be used to convert to pose-space transforms of the supplied
- * pose-channel into its local space (i.e. 'visual'-keyframing) */
void BKE_armature_mat_pose_to_bone(bPoseChannel *pchan,
const float inmat[4][4],
float outmat[4][4])
@@ -1926,7 +1874,6 @@ void BKE_armature_mat_pose_to_bone(bPoseChannel *pchan,
BKE_bone_parent_transform_apply(&bpt, inmat, outmat);
}
-/* Convert Bone-Space Matrix to Pose-Space Matrix. */
void BKE_armature_mat_bone_to_pose(bPoseChannel *pchan,
const float inmat[4][4],
float outmat[4][4])
@@ -1937,9 +1884,6 @@ void BKE_armature_mat_bone_to_pose(bPoseChannel *pchan,
BKE_bone_parent_transform_apply(&bpt, inmat, outmat);
}
-/* Convert Pose-Space Location to Bone-Space Location
- * NOTE: this cannot be used to convert to pose-space location of the supplied
- * pose-channel into its local space (i.e. 'visual'-keyframing) */
void BKE_armature_loc_pose_to_bone(bPoseChannel *pchan, const float inloc[3], float outloc[3])
{
float xLocMat[4][4];
@@ -1982,9 +1926,6 @@ void BKE_armature_mat_pose_to_bone_ex(struct Depsgraph *depsgraph,
BKE_armature_mat_pose_to_bone(&work_pchan, inmat, outmat);
}
-/**
- * Same as #BKE_object_mat3_to_rot().
- */
void BKE_pchan_mat3_to_rot(bPoseChannel *pchan, const float mat[3][3], bool use_compat)
{
BLI_ASSERT_UNIT_M3(mat);
@@ -2007,9 +1948,6 @@ void BKE_pchan_mat3_to_rot(bPoseChannel *pchan, const float mat[3][3], bool use_
}
}
-/**
- * Same as #BKE_object_rot_to_mat3().
- */
void BKE_pchan_rot_to_mat3(const bPoseChannel *pchan, float r_mat[3][3])
{
/* rotations may either be quats, eulers (with various rotation orders), or axis-angle */
@@ -2034,10 +1972,6 @@ void BKE_pchan_rot_to_mat3(const bPoseChannel *pchan, float r_mat[3][3])
}
}
-/**
- * Apply a 4x4 matrix to the pose bone,
- * similar to #BKE_object_apply_mat4().
- */
void BKE_pchan_apply_mat4(bPoseChannel *pchan, const float mat[4][4], bool use_compat)
{
float rot[3][3];
@@ -2045,11 +1979,6 @@ void BKE_pchan_apply_mat4(bPoseChannel *pchan, const float mat[4][4], bool use_c
BKE_pchan_mat3_to_rot(pchan, rot, use_compat);
}
-/**
- * Remove rest-position effects from pose-transform for obtaining
- * 'visual' transformation of pose-channel.
- * (used by the Visual-Keyframing stuff).
- */
void BKE_armature_mat_pose_to_delta(float delta_mat[4][4],
float pose_mat[4][4],
float arm_mat[4][4])
@@ -2068,11 +1997,6 @@ void BKE_armature_mat_pose_to_delta(float delta_mat[4][4],
* Used for Objects and Pose Channels, since both can have multiple rotation representations.
* \{ */
-/**
- * Called from RNA when rotation mode changes
- * - the result should be that the rotations given in the provided pointers have had conversions
- * applied (as appropriate), such that the rotation of the element hasn't 'visually' changed.
- */
void BKE_rotMode_change_values(
float quat[4], float eul[3], float axis[3], float *angle, short oldMode, short newMode)
{
@@ -2146,8 +2070,6 @@ void BKE_rotMode_change_values(
*
* \{ */
-/* Computes vector and roll based on a rotation.
- * "mat" must contain only a rotation, and no scaling. */
void mat3_to_vec_roll(const float mat[3][3], float r_vec[3], float *r_roll)
{
if (r_vec) {
@@ -2159,8 +2081,6 @@ void mat3_to_vec_roll(const float mat[3][3], float r_vec[3], float *r_roll)
}
}
-/* Computes roll around the vector that best approximates the matrix.
- * If vec is the Y vector from purely rotational mat, result should be exact. */
void mat3_vec_to_roll(const float mat[3][3], const float vec[3], float *r_roll)
{
float vecmat[3][3], vecmatinv[3][3], rollmat[3][3], q[4];
@@ -2176,79 +2096,6 @@ void mat3_vec_to_roll(const float mat[3][3], const float vec[3], float *r_roll)
*r_roll = quat_split_swing_and_twist(q, 1, NULL, NULL);
}
-/* Calculates the rest matrix of a bone based on its vector and a roll around that vector. */
-/**
- * Given `v = (v.x, v.y, v.z)` our (normalized) bone vector, we want the rotation matrix M
- * from the Y axis (so that `M * (0, 1, 0) = v`).
- * - The rotation axis a lays on XZ plane, and it is orthonormal to v,
- * hence to the projection of v onto XZ plane.
- * - `a = (v.z, 0, -v.x)`
- *
- * We know a is eigenvector of M (so M * a = a).
- * Finally, we have w, such that M * w = (0, 1, 0)
- * (i.e. the vector that will be aligned with Y axis once transformed).
- * We know w is symmetric to v by the Y axis.
- * - `w = (-v.x, v.y, -v.z)`
- *
- * Solving this, we get (x, y and z being the components of v):
- * <pre>
- * ┌ (x^2 * y + z^2) / (x^2 + z^2), x, x * z * (y - 1) / (x^2 + z^2) ┐
- * M = │ x * (y^2 - 1) / (x^2 + z^2), y, z * (y^2 - 1) / (x^2 + z^2) │
- * └ x * z * (y - 1) / (x^2 + z^2), z, (x^2 + z^2 * y) / (x^2 + z^2) ┘
- * </pre>
- *
- * This is stable as long as v (the bone) is not too much aligned with +/-Y
- * (i.e. x and z components are not too close to 0).
- *
- * Since v is normalized, we have `x^2 + y^2 + z^2 = 1`,
- * hence `x^2 + z^2 = 1 - y^2 = (1 - y)(1 + y)`.
- *
- * This allows to simplifies M like this:
- * <pre>
- * ┌ 1 - x^2 / (1 + y), x, -x * z / (1 + y) ┐
- * M = │ -x, y, -z │
- * └ -x * z / (1 + y), z, 1 - z^2 / (1 + y) ┘
- * </pre>
- *
- * Written this way, we see the case v = +Y is no more a singularity.
- * The only one
- * remaining is the bone being aligned with -Y.
- *
- * Let's handle
- * the asymptotic behavior when bone vector is reaching the limit of y = -1.
- * Each of the four corner elements can vary from -1 to 1,
- * depending on the axis a chosen for doing the rotation.
- * And the "rotation" here is in fact established by mirroring XZ plane by that given axis,
- * then inversing the Y-axis.
- * For sufficiently small x and z, and with y approaching -1,
- * all elements but the four corner ones of M will degenerate.
- * So let's now focus on these corner elements.
- *
- * We rewrite M so that it only contains its four corner elements,
- * and combine the `1 / (1 + y)` factor:
- * <pre>
- * ┌ 1 + y - x^2, -x * z ┐
- * M* = 1 / (1 + y) * │ │
- * └ -x * z, 1 + y - z^2 ┘
- * </pre>
- *
- * When y is close to -1, computing 1 / (1 + y) will cause severe numerical instability,
- * so we use a different approach based on x and z as inputs.
- * We know `y^2 = 1 - (x^2 + z^2)`, and `y < 0`, hence `y = -sqrt(1 - (x^2 + z^2))`.
- *
- * Since x and z are both close to 0, we apply the binomial expansion to the second order:
- * `y = -sqrt(1 - (x^2 + z^2)) = -1 + (x^2 + z^2) / 2 + (x^2 + z^2)^2 / 8`, which allows
- * eliminating the problematic `1` constant.
- *
- * A first order expansion allows simplifying to this, but second order is more precise:
- * <pre>
- * ┌ z^2 - x^2, -2 * x * z ┐
- * M* = 1 / (x^2 + z^2) * │ │
- * └ -2 * x * z, x^2 - z^2 ┘
- * </pre>
- *
- * P.S. In the end, this basically is a heavily optimized version of Damped Track +Y.
- */
void vec_roll_to_mat3_normalized(const float nor[3], const float roll, float r_mat[3][3])
{
const float SAFE_THRESHOLD = 6.1e-3f; /* Theta above this value has good enough precision. */
@@ -2319,10 +2166,6 @@ void vec_roll_to_mat3(const float vec[3], const float roll, float r_mat[3][3])
/** \name Armature Bone Matrix Calculation (Recursive)
* \{ */
-/**
- * Recursive part, calculates rest-position of entire tree of children.
- * \note Used when exiting edit-mode too.
- */
void BKE_armature_where_is_bone(Bone *bone, const Bone *bone_parent, const bool use_recursion)
{
float vec[3];
@@ -2361,8 +2204,6 @@ void BKE_armature_where_is_bone(Bone *bone, const Bone *bone_parent, const bool
}
}
-/* updates vectors and matrices on rest-position level, only needed
- * after editing armature itself, now only on reading file */
void BKE_armature_where_is(bArmature *arm)
{
Bone *bone;
@@ -2579,10 +2420,6 @@ static int rebuild_pose_bone(
return counter;
}
-/**
- * Clear pointers of object's pose
- * (needed in remap case, since we cannot always wait for a complete pose rebuild).
- */
void BKE_pose_clear_pointers(bPose *pose)
{
LISTBASE_FOREACH (bPoseChannel *, pchan, &pose->chanbase) {
@@ -2604,7 +2441,6 @@ static bPoseChannel *pose_channel_find_bone(bPose *pose, Bone *bone)
return (bone != NULL) ? BKE_pose_channel_find_name(pose, bone->name) : NULL;
}
-/** Update the links for the B-Bone handles from Bone data. */
void BKE_pchan_rebuild_bbone_handles(bPose *pose, bPoseChannel *pchan)
{
pchan->bbone_prev = pose_channel_find_bone(pose, pchan->bone->bbone_prev);
@@ -2622,13 +2458,6 @@ void BKE_pose_channels_clear_with_null_bone(bPose *pose, const bool do_id_user)
}
}
-/**
- * Only after leave editmode, duplicating, validating older files, library syncing.
- *
- * \note pose->flag is set for it.
- *
- * \param bmain: May be NULL, only used to tag depsgraph as being dirty...
- */
void BKE_pose_rebuild(Main *bmain, Object *ob, bArmature *arm, const bool do_id_user)
{
Bone *bone;
@@ -2696,11 +2525,6 @@ void BKE_pose_rebuild(Main *bmain, Object *ob, bArmature *arm, const bool do_id_
}
}
-/**
- * Ensures object's pose is rebuilt if needed.
- *
- * \param bmain: May be NULL, only used to tag depsgraph as being dirty...
- */
void BKE_pose_ensure(Main *bmain, Object *ob, bArmature *arm, const bool do_id_user)
{
BLI_assert(!ELEM(NULL, arm, ob));
@@ -2716,9 +2540,6 @@ void BKE_pose_ensure(Main *bmain, Object *ob, bArmature *arm, const bool do_id_u
/** \name Pose Solver
* \{ */
-/**
- * Convert the loc/rot/size to \a r_chanmat (typically #bPoseChannel.chan_mat).
- */
void BKE_pchan_to_mat4(const bPoseChannel *pchan, float r_chanmat[4][4])
{
float smat[3][3];
@@ -2742,8 +2563,6 @@ void BKE_pchan_to_mat4(const bPoseChannel *pchan, float r_chanmat[4][4])
}
}
-/* loc/rot/size to mat4 */
-/* used in constraint.c too */
void BKE_pchan_calc_mat(bPoseChannel *pchan)
{
/* this is just a wrapper around the copy of this function which calculates the matrix
@@ -2752,7 +2571,6 @@ void BKE_pchan_calc_mat(bPoseChannel *pchan)
BKE_pchan_to_mat4(pchan, pchan->chan_mat);
}
-/* calculate tail of posechannel */
void BKE_pose_where_is_bone_tail(bPoseChannel *pchan)
{
float vec[3];
@@ -2762,10 +2580,6 @@ void BKE_pose_where_is_bone_tail(bPoseChannel *pchan)
add_v3_v3v3(pchan->pose_tail, pchan->pose_head, vec);
}
-/* The main armature solver, does all constraints excluding IK */
-/* pchan is validated, as having bone and parent pointer
- * 'do_extra': when zero skips loc/size/rot, constraints and strip modifiers.
- */
void BKE_pose_where_is_bone(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob,
@@ -2830,8 +2644,6 @@ void BKE_pose_where_is_bone(struct Depsgraph *depsgraph,
BKE_pose_where_is_bone_tail(pchan);
}
-/* This only reads anim data from channels, and writes to channels */
-/* This is the only function adding poses */
void BKE_pose_where_is(struct Depsgraph *depsgraph, Scene *scene, Object *ob)
{
bArmature *arm;
diff --git a/source/blender/blenkernel/intern/armature_deform.c b/source/blender/blenkernel/intern/armature_deform.c
index 5f721b49361..a8e74f6b4c3 100644
--- a/source/blender/blenkernel/intern/armature_deform.c
+++ b/source/blender/blenkernel/intern/armature_deform.c
@@ -121,7 +121,6 @@ static void b_bone_deform(const bPoseChannel *pchan,
&quats[index + 1], mats[index + 2].mat, co, weight * blend, vec, dq, defmat);
}
-/* using vec with dist to bone b1 - b2 */
float distfactor_to_bone(
const float vec[3], const float b1[3], const float b2[3], float rad1, float rad2, float rdist)
{
diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c
index 35ae2d2dbef..05c318663e9 100644
--- a/source/blender/blenkernel/intern/armature_update.c
+++ b/source/blender/blenkernel/intern/armature_update.c
@@ -277,46 +277,59 @@ static void apply_curve_transform(
*r_radius = (radius + *r_radius) / 2;
}
+static float dist_to_sphere_shell(const float sphere_origin[3],
+ const float sphere_radius,
+ const float point[3])
+{
+ float vec[3];
+ sub_v3_v3v3(vec, sphere_origin, point);
+ return sphere_radius - len_v3(vec);
+}
+
/* This function positions the tail of the bone so that it preserves the length of it.
* The length of the bone can be seen as a sphere radius.
*/
static int position_tail_on_spline(bSplineIKConstraint *ik_data,
const float head_pos[3],
const float sphere_radius,
- const int prev_seg_idx,
+ int prev_seg_idx,
float r_tail_pos[3],
float *r_new_curve_pos,
float *r_radius)
{
/* This is using the tessellated curve data.
* So we are working with piece-wise linear curve segments.
- * The same method is use in #BKE_where_on_path to get curve location data. */
+ * The same method is used in #BKE_where_on_path to get curve location data. */
const CurveCache *cache = ik_data->tar->runtime.curve_cache;
- const BevList *bl = cache->bev.first;
- BevPoint *bp = bl->bevpoints;
- const float spline_len = BKE_anim_path_get_length(cache);
const float *seg_accum_len = cache->anim_path_accum_length;
int max_seg_idx = BKE_anim_path_get_array_size(cache) - 1;
- /* Convert our initial intersection point guess to a point index.
- * If the curve was a straight line, then pointEnd would be the correct location.
+ /* Make an initial guess of where our intersection point will be.
+ * If the curve was a straight line, then the faction passed in r_new_curve_pos
+ * would be the correct location.
* So make it our first initial guess.
*/
+ const float spline_len = BKE_anim_path_get_length(cache);
const float guessed_len = *r_new_curve_pos * spline_len;
BLI_assert(prev_seg_idx >= 0);
-
int cur_seg_idx = prev_seg_idx;
while (cur_seg_idx < max_seg_idx && guessed_len > seg_accum_len[cur_seg_idx]) {
cur_seg_idx++;
}
+ /* Convert the segment to bev points.
+ * For example, the segment with index 0 will have bev points 0 and 1.
+ */
int bp_idx = cur_seg_idx + 1;
- bp = bp + bp_idx;
+ const BevList *bl = cache->bev.first;
bool is_cyclic = bl->poly >= 0;
- BevPoint *prev_bp = bp - 1;
+ BevPoint *bp = bl->bevpoints;
+ BevPoint *prev_bp;
+ bp = bp + bp_idx;
+ prev_bp = bp - 1;
/* Go to the next tessellated curve point until we cross to outside of the sphere. */
while (len_v3v3(head_pos, bp->vec) < sphere_radius) {
@@ -337,35 +350,53 @@ static int position_tail_on_spline(bSplineIKConstraint *ik_data,
bp_idx++;
}
- float isect_1[3], isect_2[3];
-
- /* Calculate the intersection point. */
- int ret = isect_line_sphere_v3(prev_bp->vec, bp->vec, head_pos, sphere_radius, isect_1, isect_2);
+ /* Calculate the intersection point using the secant root finding method */
+ float x0 = 0.0f, x1 = 1.0f, x2 = 0.5f;
+ float x0_point[3], x1_point[3], start_p[3];
+ float epsilon = max_fff(1.0f, len_v3(head_pos), len_v3(bp->vec)) * FLT_EPSILON;
- if (ret > 0) {
- /* Because of how `isect_line_sphere_v3` works, we know that `isect_1` contains the
- * intersection point we want. And it will always intersect as we go from inside to outside
- * of the sphere.
+ if (prev_seg_idx == bp_idx - 1) {
+ /* The intersection lies inside the same segment as the last point.
+ * Set the last point to be the start search point so we minimize the risks of going backwards
+ * on the curve.
*/
- copy_v3_v3(r_tail_pos, isect_1);
+ copy_v3_v3(start_p, head_pos);
}
else {
- /* Couldn't find an intersection point. This means that the floating point
- * values are too small and thus the intersection check fails.
- * So assume that the distance is so small that tail_pos == head_pos.
- */
- copy_v3_v3(r_tail_pos, head_pos);
+ copy_v3_v3(start_p, prev_bp->vec);
}
- cur_seg_idx = bp_idx - 2;
+ for (int i = 0; i < 10; i++) {
+ interp_v3_v3v3(x0_point, start_p, bp->vec, x0);
+ interp_v3_v3v3(x1_point, start_p, bp->vec, x1);
+
+ float f_x0 = dist_to_sphere_shell(head_pos, sphere_radius, x0_point);
+ float f_x1 = dist_to_sphere_shell(head_pos, sphere_radius, x1_point);
+
+ if (fabsf(f_x1) <= epsilon || f_x0 == f_x1) {
+ break;
+ }
+
+ x2 = x1 - f_x1 * (x1 - x0) / (f_x1 - f_x0);
+ x0 = x1;
+ x1 = x2;
+ }
+ /* Found the bone tail position! */
+ copy_v3_v3(r_tail_pos, x1_point);
+
+ /* Because our intersection point lies inside the current segment,
+ * Convert our bevpoint index back to the previous segment index (-2 instead of -1).
+ * This is because our actual location is prev_seg_len + isect_seg_len.
+ */
+ prev_seg_idx = bp_idx - 2;
float prev_seg_len = 0;
- if (cur_seg_idx < 0) {
- cur_seg_idx = 0;
+ if (prev_seg_idx < 0) {
+ prev_seg_idx = 0;
prev_seg_len = 0;
}
else {
- prev_seg_len = seg_accum_len[cur_seg_idx];
+ prev_seg_len = seg_accum_len[prev_seg_idx];
}
/* Convert the point back into the 0-1 interpolation range. */
@@ -380,7 +411,8 @@ static int position_tail_on_spline(bSplineIKConstraint *ik_data,
*r_radius = (1.0f - frac) * prev_bp->radius + frac * bp->radius;
}
- return cur_seg_idx;
+ /* Return the current segment. */
+ return bp_idx - 1;
}
/* Evaluate spline IK for a given bone. */
diff --git a/source/blender/blenkernel/intern/asset.cc b/source/blender/blenkernel/intern/asset.cc
index 59e402b6680..e5509b09e20 100644
--- a/source/blender/blenkernel/intern/asset.cc
+++ b/source/blender/blenkernel/intern/asset.cc
@@ -39,7 +39,7 @@
using namespace blender;
-AssetMetaData *BKE_asset_metadata_create(void)
+AssetMetaData *BKE_asset_metadata_create()
{
AssetMetaData *asset_data = (AssetMetaData *)MEM_callocN(sizeof(*asset_data), __func__);
memcpy(asset_data, DNA_struct_default_get(AssetMetaData), sizeof(*asset_data));
@@ -78,9 +78,6 @@ AssetTag *BKE_asset_metadata_tag_add(AssetMetaData *asset_data, const char *name
return tag;
}
-/**
- * Make sure there is a tag with name \a name, create one if needed.
- */
struct AssetTagEnsureResult BKE_asset_metadata_tag_ensure(AssetMetaData *asset_data,
const char *name)
{
diff --git a/source/blender/blenkernel/intern/asset_catalog.cc b/source/blender/blenkernel/intern/asset_catalog.cc
index 03043f3b784..aec622bb71f 100644
--- a/source/blender/blenkernel/intern/asset_catalog.cc
+++ b/source/blender/blenkernel/intern/asset_catalog.cc
@@ -36,12 +36,7 @@ namespace blender::bke {
const CatalogFilePath AssetCatalogService::DEFAULT_CATALOG_FILENAME = "blender_assets.cats.txt";
-/* For now this is the only version of the catalog definition files that is supported.
- * Later versioning code may be added to handle older files. */
const int AssetCatalogDefinitionFile::SUPPORTED_VERSION = 1;
-/* String that's matched in the catalog definition file to know that the line is the version
- * declaration. It has to start with a space to ensure it won't match any hypothetical future field
- * that starts with "VERSION". */
const std::string AssetCatalogDefinitionFile::VERSION_MARKER = "VERSION ";
const std::string AssetCatalogDefinitionFile::HEADER =
@@ -98,6 +93,14 @@ bool AssetCatalogService::has_unsaved_changes() const
return catalog_collection_->has_unsaved_changes_;
}
+void AssetCatalogService::tag_all_catalogs_as_unsaved_changes()
+{
+ for (auto &catalog : catalog_collection_->catalogs_.values()) {
+ catalog->flags.has_unsaved_changes = true;
+ }
+ catalog_collection_->has_unsaved_changes_ = true;
+}
+
bool AssetCatalogService::is_empty() const
{
BLI_assert(catalog_collection_);
@@ -486,6 +489,24 @@ bool AssetCatalogService::write_to_disk_ex(const CatalogFilePath &blend_file_pat
return catalog_collection_->catalog_definition_file_->write_to_disk();
}
+void AssetCatalogService::prepare_to_merge_on_write()
+{
+ /* TODO(Sybren): expand to support multiple CDFs. */
+
+ if (!catalog_collection_->catalog_definition_file_) {
+ /* There is no CDF connected, so it's a no-op. */
+ return;
+ }
+
+ /* Remove any association with the CDF, so that a new location will be chosen
+ * when the blend file is saved. */
+ catalog_collection_->catalog_definition_file_.reset();
+
+ /* Mark all in-memory catalogs as "dirty", to force them to be kept around on
+ * the next "load-merge-write" cycle. */
+ tag_all_catalogs_as_unsaved_changes();
+}
+
CatalogFilePath AssetCatalogService::find_suitable_cdf_path_for_writing(
const CatalogFilePath &blend_file_path)
{
diff --git a/source/blender/blenkernel/intern/asset_catalog_path.cc b/source/blender/blenkernel/intern/asset_catalog_path.cc
index 20cac76b40b..d789150dba5 100644
--- a/source/blender/blenkernel/intern/asset_catalog_path.cc
+++ b/source/blender/blenkernel/intern/asset_catalog_path.cc
@@ -74,8 +74,6 @@ StringRefNull AssetCatalogPath::name() const
return StringRefNull(this->path_.c_str() + last_sep_index + 1);
}
-/* In-class operators, because of the implicit `AssetCatalogPath(StringRef)` constructor.
- * Otherwise `string == string` could cast both sides to `AssetCatalogPath`. */
bool AssetCatalogPath::operator==(const AssetCatalogPath &other_path) const
{
return this->path_ == other_path.path_;
diff --git a/source/blender/blenkernel/intern/asset_library.cc b/source/blender/blenkernel/intern/asset_library.cc
index 68e43852a21..74de9b93c25 100644
--- a/source/blender/blenkernel/intern/asset_library.cc
+++ b/source/blender/blenkernel/intern/asset_library.cc
@@ -71,7 +71,7 @@ bool BKE_asset_library_find_suitable_root_path_from_path(const char *input_path,
bool BKE_asset_library_find_suitable_root_path_from_main(const Main *bmain, char *r_library_path)
{
- return BKE_asset_library_find_suitable_root_path_from_path(bmain->name, r_library_path);
+ return BKE_asset_library_find_suitable_root_path_from_path(bmain->filepath, r_library_path);
}
blender::bke::AssetCatalogService *BKE_asset_library_get_catalog_service(
@@ -168,7 +168,7 @@ void AssetLibrary::on_blend_save_post(struct Main *main,
}
if (save_catalogs_when_file_is_saved) {
- this->catalog_service->write_to_disk(main->name);
+ this->catalog_service->write_to_disk(main->filepath);
}
}
diff --git a/source/blender/blenkernel/intern/asset_library_service.cc b/source/blender/blenkernel/intern/asset_library_service.cc
index d202d6462cf..6b3f1fa3408 100644
--- a/source/blender/blenkernel/intern/asset_library_service.cc
+++ b/source/blender/blenkernel/intern/asset_library_service.cc
@@ -125,9 +125,6 @@ static void on_blendfile_load(struct Main * /*bMain*/,
AssetLibraryService::destroy();
}
-/**
- * Ensure the AssetLibraryService instance is destroyed before a new blend file is loaded.
- * This makes memory management simple, and ensures a fresh start for every blend file. */
void AssetLibraryService::app_handler_register()
{
/* The callback system doesn't own `on_load_callback_store_`. */
diff --git a/source/blender/blenkernel/intern/asset_library_service_test.cc b/source/blender/blenkernel/intern/asset_library_service_test.cc
index ee910cab945..9fa6d100a53 100644
--- a/source/blender/blenkernel/intern/asset_library_service_test.cc
+++ b/source/blender/blenkernel/intern/asset_library_service_test.cc
@@ -97,7 +97,7 @@ TEST_F(AssetLibraryServiceTest, get_destroy)
AssetLibraryService::destroy();
AssetLibraryService::destroy();
- /* Note: there used to be a test for the opposite here, that after a call to
+ /* NOTE: there used to be a test for the opposite here, that after a call to
* AssetLibraryService::destroy() the above calls should return freshly allocated objects. This
* cannot be reliably tested by just pointer comparison, though. */
}
@@ -113,7 +113,7 @@ TEST_F(AssetLibraryServiceTest, library_pointers)
EXPECT_EQ(curfile_lib, service->get_asset_library_current_file())
<< "Calling twice without destroying in between should return the same instance.";
- /* Note: there used to be a test for the opposite here, that after a call to
+ /* NOTE: there used to be a test for the opposite here, that after a call to
* AssetLibraryService::destroy() the above calls should return freshly allocated objects. This
* cannot be reliably tested by just pointer comparison, though. */
}
diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc
index 3f2c1f13337..1a4265d936b 100644
--- a/source/blender/blenkernel/intern/attribute_access.cc
+++ b/source/blender/blenkernel/intern/attribute_access.cc
@@ -23,6 +23,7 @@
#include "BKE_geometry_set.hh"
#include "BKE_mesh.h"
#include "BKE_pointcloud.h"
+#include "BKE_type_conversions.hh"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
@@ -36,8 +37,6 @@
#include "CLG_log.h"
-#include "NOD_type_conversions.hh"
-
#include "attribute_access_intern.hh"
static CLG_LogRef LOG = {"bke.attribute_access"};
@@ -50,7 +49,7 @@ using blender::bke::AttributeIDRef;
using blender::bke::OutputAttribute;
using blender::fn::GMutableSpan;
using blender::fn::GSpan;
-using blender::fn::GVMutableArrayImpl_For_GMutableSpan;
+using blender::fn::GVArrayImpl_For_GSpan;
namespace blender::bke {
@@ -183,10 +182,6 @@ static int attribute_domain_priority(const AttributeDomain domain)
}
}
-/**
- * Domains with a higher "information density" have a higher priority, in order
- * to choose a domain that will not lose data through domain conversion.
- */
AttributeDomain attribute_domain_highest_priority(Span<AttributeDomain> domains)
{
int highest_priority = INT_MIN;
@@ -288,7 +283,7 @@ static void *add_generic_custom_data_layer(CustomData &custom_data,
char attribute_name_c[MAX_NAME];
attribute_id.name().copy(attribute_name_c);
return CustomData_add_layer_named(
- &custom_data, data_type, CD_DEFAULT, nullptr, domain_size, attribute_name_c);
+ &custom_data, data_type, alloctype, layer_data, domain_size, attribute_name_c);
}
const AnonymousAttributeID &anonymous_id = attribute_id.anonymous_id();
return CustomData_add_layer_anonymous(
@@ -400,7 +395,9 @@ WriteAttributeLookup BuiltinCustomDataLayerProvider::try_get_for_write(
}
if (data != new_data) {
- custom_data_access_.update_custom_data_pointers(component);
+ if (custom_data_access_.update_custom_data_pointers) {
+ custom_data_access_.update_custom_data_pointers(component);
+ }
data = new_data;
}
@@ -441,7 +438,9 @@ bool BuiltinCustomDataLayerProvider::try_delete(GeometryComponent &component) co
const bool delete_success = CustomData_free_layer(
custom_data, stored_type_, domain_size, layer_index);
if (delete_success) {
- custom_data_access_.update_custom_data_pointers(component);
+ if (custom_data_access_.update_custom_data_pointers) {
+ custom_data_access_.update_custom_data_pointers(component);
+ }
}
return delete_success;
}
@@ -476,7 +475,9 @@ bool BuiltinCustomDataLayerProvider::try_create(GeometryComponent &component,
*custom_data, stored_type_, domain_size, initializer);
}
if (success) {
- custom_data_access_.update_custom_data_pointers(component);
+ if (custom_data_access_.update_custom_data_pointers) {
+ custom_data_access_.update_custom_data_pointers(component);
+ }
}
return success;
}
@@ -644,7 +645,9 @@ WriteAttributeLookup NamedLegacyCustomDataProvider::try_get_for_write(
void *data_new = CustomData_duplicate_referenced_layer_named(
custom_data, stored_type_, layer.name, domain_size);
if (data_old != data_new) {
- custom_data_access_.update_custom_data_pointers(component);
+ if (custom_data_access_.update_custom_data_pointers) {
+ custom_data_access_.update_custom_data_pointers(component);
+ }
}
return {as_write_attribute_(layer.data, domain_size), domain_};
}
@@ -666,7 +669,9 @@ bool NamedLegacyCustomDataProvider::try_delete(GeometryComponent &component,
if (custom_data_layer_matches_attribute_id(layer, attribute_id)) {
const int domain_size = component.attribute_domain_size(domain_);
CustomData_free_layer(custom_data, stored_type_, domain_size, i);
- custom_data_access_.update_custom_data_pointers(component);
+ if (custom_data_access_.update_custom_data_pointers) {
+ custom_data_access_.update_custom_data_pointers(component);
+ }
return true;
}
}
@@ -734,7 +739,6 @@ CustomDataAttributes &CustomDataAttributes::operator=(const CustomDataAttributes
std::optional<GSpan> CustomDataAttributes::get_for_read(const AttributeIDRef &attribute_id) const
{
- BLI_assert(size_ != 0);
for (const CustomDataLayer &layer : Span(data.layers, data.totlayer)) {
if (custom_data_layer_matches_attribute_id(layer, attribute_id)) {
const CPPType *cpp_type = custom_data_type_to_cpp_type((CustomDataType)layer.type);
@@ -745,11 +749,6 @@ std::optional<GSpan> CustomDataAttributes::get_for_read(const AttributeIDRef &at
return {};
}
-/**
- * Return a virtual array for a stored attribute, or a single value virtual array with the default
- * value if the attribute doesn't exist. If no default value is provided, the default value for the
- * type will be used.
- */
GVArray CustomDataAttributes::get_for_read(const AttributeIDRef &attribute_id,
const CustomDataType data_type,
const void *default_value) const
@@ -766,15 +765,13 @@ GVArray CustomDataAttributes::get_for_read(const AttributeIDRef &attribute_id,
if (attribute->type() == *type) {
return GVArray::ForSpan(*attribute);
}
- const blender::nodes::DataTypeConversions &conversions =
- blender::nodes::get_implicit_type_conversions();
+ const blender::bke::DataTypeConversions &conversions =
+ blender::bke::get_implicit_type_conversions();
return conversions.try_convert(GVArray::ForSpan(*attribute), *type);
}
std::optional<GMutableSpan> CustomDataAttributes::get_for_write(const AttributeIDRef &attribute_id)
{
- /* If this assert hits, it most likely means that #reallocate was not called at some point. */
- BLI_assert(size_ != 0);
for (CustomDataLayer &layer : MutableSpan(data.layers, data.totlayer)) {
if (custom_data_layer_matches_attribute_id(layer, attribute_id)) {
const CPPType *cpp_type = custom_data_type_to_cpp_type((CustomDataType)layer.type);
@@ -821,6 +818,12 @@ void CustomDataAttributes::reallocate(const int size)
CustomData_realloc(&data, size);
}
+void CustomDataAttributes::clear()
+{
+ CustomData_free(&data, size_);
+ size_ = 0;
+}
+
bool CustomDataAttributes::foreach_attribute(const AttributeForeachCallback callback,
const AttributeDomain domain) const
{
@@ -1044,10 +1047,6 @@ Set<AttributeIDRef> GeometryComponent::attribute_ids() const
return attributes;
}
-/**
- * \return False if the callback explicitly returned false at any point, otherwise true,
- * meaning the callback made it all the way through.
- */
bool GeometryComponent::attribute_foreach(const AttributeForeachCallback callback) const
{
using namespace blender::bke;
@@ -1112,8 +1111,8 @@ std::optional<AttributeMetaData> GeometryComponent::attribute_get_meta_data(
static blender::fn::GVArray try_adapt_data_type(blender::fn::GVArray varray,
const blender::fn::CPPType &to_type)
{
- const blender::nodes::DataTypeConversions &conversions =
- blender::nodes::get_implicit_type_conversions();
+ const blender::bke::DataTypeConversions &conversions =
+ blender::bke::get_implicit_type_conversions();
return conversions.try_convert(std::move(varray), to_type);
}
@@ -1178,8 +1177,8 @@ blender::bke::ReadAttributeLookup GeometryComponent::attribute_try_get_for_read(
if (attribute.varray.type() == *type) {
return attribute;
}
- const blender::nodes::DataTypeConversions &conversions =
- blender::nodes::get_implicit_type_conversions();
+ const blender::bke::DataTypeConversions &conversions =
+ blender::bke::get_implicit_type_conversions();
return {conversions.try_convert(std::move(attribute.varray), *type), attribute.domain};
}
@@ -1200,8 +1199,7 @@ blender::fn::GVArray GeometryComponent::attribute_get_for_read(const AttributeID
return blender::fn::GVArray::ForSingle(*type, domain_size, default_value);
}
-class GVMutableAttribute_For_OutputAttribute
- : public blender::fn::GVMutableArrayImpl_For_GMutableSpan {
+class GVMutableAttribute_For_OutputAttribute : public blender::fn::GVArrayImpl_For_GSpan {
public:
GeometryComponent *component;
std::string attribute_name;
@@ -1210,7 +1208,7 @@ class GVMutableAttribute_For_OutputAttribute
GVMutableAttribute_For_OutputAttribute(GMutableSpan data,
GeometryComponent &component,
const AttributeIDRef &attribute_id)
- : blender::fn::GVMutableArrayImpl_For_GMutableSpan(data), component(&component)
+ : blender::fn::GVArrayImpl_For_GSpan(data), component(&component)
{
if (attribute_id.is_named()) {
this->attribute_name = attribute_id.name();
@@ -1300,7 +1298,7 @@ static OutputAttribute create_output_attribute(GeometryComponent &component,
const CPPType *cpp_type = custom_data_type_to_cpp_type(data_type);
BLI_assert(cpp_type != nullptr);
- const nodes::DataTypeConversions &conversions = nodes::get_implicit_type_conversions();
+ const DataTypeConversions &conversions = get_implicit_type_conversions();
if (component.attribute_is_builtin(attribute_id)) {
const StringRef attribute_name = attribute_id.name();
@@ -1409,23 +1407,27 @@ OutputAttribute GeometryComponent::attribute_try_get_for_output_only(
namespace blender::bke {
-GVArray AttributeFieldInput::get_varray_for_context(const fn::FieldContext &context,
- IndexMask UNUSED(mask),
- ResourceScope &UNUSED(scope)) const
+GVArray GeometryFieldInput::get_varray_for_context(const fn::FieldContext &context,
+ IndexMask mask,
+ ResourceScope &UNUSED(scope)) const
{
if (const GeometryComponentFieldContext *geometry_context =
dynamic_cast<const GeometryComponentFieldContext *>(&context)) {
const GeometryComponent &component = geometry_context->geometry_component();
const AttributeDomain domain = geometry_context->domain();
- const CustomDataType data_type = cpp_type_to_custom_data_type(*type_);
- GVArray attribute = component.attribute_try_get_for_read(name_, domain, data_type);
- if (attribute) {
- return attribute;
- }
+ return this->get_varray_for_context(component, domain, mask);
}
return {};
}
+GVArray AttributeFieldInput::get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const
+{
+ const CustomDataType data_type = cpp_type_to_custom_data_type(*type_);
+ return component.attribute_try_get_for_read(name_, domain, data_type);
+}
+
std::string AttributeFieldInput::socket_inspection_name() const
{
std::stringstream ss;
@@ -1457,25 +1459,20 @@ static StringRef get_random_id_attribute_name(const AttributeDomain domain)
}
}
-GVArray IDAttributeFieldInput::get_varray_for_context(const fn::FieldContext &context,
- IndexMask mask,
- ResourceScope &scope) const
+GVArray IDAttributeFieldInput::get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask mask) const
{
- if (const GeometryComponentFieldContext *geometry_context =
- dynamic_cast<const GeometryComponentFieldContext *>(&context)) {
- const GeometryComponent &component = geometry_context->geometry_component();
- const AttributeDomain domain = geometry_context->domain();
- const StringRef name = get_random_id_attribute_name(domain);
- GVArray attribute = component.attribute_try_get_for_read(name, domain, CD_PROP_INT32);
- if (attribute) {
- BLI_assert(attribute.size() == component.attribute_domain_size(domain));
- return attribute;
- }
- /* Use the index as the fallback if no random ID attribute exists. */
- return fn::IndexFieldInput::get_index_varray(mask, scope);
+ const StringRef name = get_random_id_attribute_name(domain);
+ GVArray attribute = component.attribute_try_get_for_read(name, domain, CD_PROP_INT32);
+ if (attribute) {
+ BLI_assert(attribute.size() == component.attribute_domain_size(domain));
+ return attribute;
}
- return {};
+
+ /* Use the index as the fallback if no random ID attribute exists. */
+ return fn::IndexFieldInput::get_index_varray(mask);
}
std::string IDAttributeFieldInput::socket_inspection_name() const
@@ -1495,20 +1492,12 @@ bool IDAttributeFieldInput::is_equal_to(const fn::FieldNode &other) const
return dynamic_cast<const IDAttributeFieldInput *>(&other) != nullptr;
}
-GVArray AnonymousAttributeFieldInput::get_varray_for_context(const fn::FieldContext &context,
- IndexMask UNUSED(mask),
- ResourceScope &UNUSED(scope)) const
+GVArray AnonymousAttributeFieldInput::get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const
{
- if (const GeometryComponentFieldContext *geometry_context =
- dynamic_cast<const GeometryComponentFieldContext *>(&context)) {
- const GeometryComponent &component = geometry_context->geometry_component();
- const AttributeDomain domain = geometry_context->domain();
- const CustomDataType data_type = cpp_type_to_custom_data_type(*type_);
- GVArray attribute = component.attribute_try_get_for_read(
- anonymous_id_.get(), domain, data_type);
- return attribute;
- }
- return {};
+ const CustomDataType data_type = cpp_type_to_custom_data_type(*type_);
+ return component.attribute_try_get_for_read(anonymous_id_.get(), domain, data_type);
}
std::string AnonymousAttributeFieldInput::socket_inspection_name() const
@@ -1533,3 +1522,5 @@ bool AnonymousAttributeFieldInput::is_equal_to(const fn::FieldNode &other) const
}
} // namespace blender::bke
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/autoexec.c b/source/blender/blenkernel/intern/autoexec.c
index 3aec646b024..ed2b4e4ab1b 100644
--- a/source/blender/blenkernel/intern/autoexec.c
+++ b/source/blender/blenkernel/intern/autoexec.c
@@ -36,10 +36,6 @@
#include "BKE_autoexec.h" /* own include */
-/**
- * \param path: The path to check against.
- * \return Success
- */
bool BKE_autoexec_match(const char *path)
{
bPathCompare *path_cmp;
diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c
index fb65a9bec7e..b914b0cdf66 100644
--- a/source/blender/blenkernel/intern/blender.c
+++ b/source/blender/blenkernel/intern/blender.c
@@ -71,7 +71,6 @@ UserDef U;
/** \name Blender Free on Exit
* \{ */
-/* only to be called on exit blender */
void BKE_blender_free(void)
{
/* samples are in a global list..., also sets G_MAIN->sound->sample NULL */
@@ -272,10 +271,6 @@ static void userdef_free_addons(UserDef *userdef)
BLI_listbase_clear(&userdef->addons);
}
-/**
- * When loading a new userdef from file,
- * or when exiting Blender.
- */
void BKE_blender_userdef_data_free(UserDef *userdef, bool clear_fonts)
{
#define U BLI_STATIC_ASSERT(false, "Global 'U' not allowed, only use arguments passed in!")
@@ -310,10 +305,6 @@ void BKE_blender_userdef_data_free(UserDef *userdef, bool clear_fonts)
/** \name Blender Preferences (Application Templates)
* \{ */
-/**
- * Write U from userdef.
- * This function defines which settings a template will override for the user preferences.
- */
void BKE_blender_userdef_app_template_data_swap(UserDef *userdef_a, UserDef *userdef_b)
{
/* TODO:
diff --git a/source/blender/blenkernel/intern/blender_copybuffer.c b/source/blender/blenkernel/intern/blender_copybuffer.c
index f8b943d3479..211d7f693d4 100644
--- a/source/blender/blenkernel/intern/blender_copybuffer.c
+++ b/source/blender/blenkernel/intern/blender_copybuffer.c
@@ -38,6 +38,7 @@
#include "BKE_blender_copybuffer.h" /* own include */
#include "BKE_blendfile.h"
+#include "BKE_blendfile_link_append.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_layer.h"
@@ -57,25 +58,16 @@
/** \name Copy/Paste `.blend`, partial saves.
* \{ */
-/** Initialize a copy operation. */
void BKE_copybuffer_copy_begin(Main *bmain_src)
{
BKE_blendfile_write_partial_begin(bmain_src);
}
-/** Mark an ID to be copied. Should only be called after a call to #BKE_copybuffer_copy_begin. */
void BKE_copybuffer_copy_tag_ID(ID *id)
{
BKE_blendfile_write_partial_tag_ID(id, true);
}
-/**
- * Finalize a copy operation into given .blend file 'buffer'.
- *
- * \param filename: Full path to the .blend file used as copy/paste buffer.
- *
- * \return true on success, false otherwise.
- */
bool BKE_copybuffer_copy_end(Main *bmain_src, const char *filename, ReportList *reports)
{
const int write_flags = 0;
@@ -88,63 +80,60 @@ bool BKE_copybuffer_copy_end(Main *bmain_src, const char *filename, ReportList *
return retval;
}
-/**
- * Paste datablocks from the given .blend file 'buffer' (i.e. append them).
- *
- * Unlike #BKE_copybuffer_paste, it does not perform any instantiation of collections/objects/etc.
- *
- * \param libname: Full path to the .blend file used as copy/paste buffer.
- * \param id_types_mask: Only directly link IDs of those types from the given .blend file buffer.
- *
- * \return true on success, false otherwise.
- */
+/* Common helper for paste functions. */
+static void copybuffer_append(BlendfileLinkAppendContext *lapp_context,
+ Main *bmain,
+ ReportList *reports)
+{
+ /* Tag existing IDs in given `bmain_dst` as already existing. */
+ BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
+
+ BKE_blendfile_link(lapp_context, reports);
+
+ /* Mark all library linked objects to be updated. */
+ BKE_main_lib_objects_recalc_all(bmain);
+ IMB_colormanagement_check_file_config(bmain);
+
+ /* Append, rather than linking */
+ BKE_blendfile_append(lapp_context, reports);
+
+ /* This must be unset, otherwise these object won't link into other scenes from this blend
+ * file. */
+ BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
+
+ /* Recreate dependency graph to include new objects. */
+ DEG_relations_tag_update(bmain);
+}
+
bool BKE_copybuffer_read(Main *bmain_dst,
const char *libname,
ReportList *reports,
const uint64_t id_types_mask)
{
- BlendFileReadReport bf_reports = {.reports = reports};
- BlendHandle *bh = BLO_blendhandle_from_file(libname, &bf_reports);
- if (bh == NULL) {
- /* Error reports will have been made by BLO_blendhandle_from_file(). */
- return false;
- }
- /* Here appending/linking starts. */
+ /* Note: No recursive append here (no `BLO_LIBLINK_APPEND_RECURSIVE`), external linked data
+ * should remain linked. */
const int flag = 0;
const int id_tag_extra = 0;
struct LibraryLink_Params liblink_params;
BLO_library_link_params_init(&liblink_params, bmain_dst, flag, id_tag_extra);
- Main *mainl = BLO_library_link_begin(&bh, libname, &liblink_params);
- BLO_library_link_copypaste(mainl, bh, id_types_mask);
- BLO_library_link_end(mainl, &bh, &liblink_params);
- /* Mark all library linked objects to be updated. */
- BKE_main_lib_objects_recalc_all(bmain_dst);
- IMB_colormanagement_check_file_config(bmain_dst);
- /* Append, rather than linking. */
- Library *lib = BLI_findstring(&bmain_dst->libraries, libname, offsetof(Library, filepath_abs));
- BKE_library_make_local(bmain_dst, lib, NULL, true, false);
- /* Important we unset, otherwise these object won't
- * link into other scenes from this blend file.
- */
- BKE_main_id_tag_all(bmain_dst, LIB_TAG_PRE_EXISTING, false);
- BLO_blendhandle_close(bh);
+
+ BlendfileLinkAppendContext *lapp_context = BKE_blendfile_link_append_context_new(
+ &liblink_params);
+ BKE_blendfile_link_append_context_library_add(lapp_context, libname, NULL);
+
+ const int num_pasted = BKE_blendfile_link_append_context_item_idtypes_from_library_add(
+ lapp_context, reports, id_types_mask, 0);
+ if (num_pasted == BLENDFILE_LINK_APPEND_INVALID) {
+ BKE_blendfile_link_append_context_free(lapp_context);
+ return false;
+ }
+
+ copybuffer_append(lapp_context, bmain_dst, reports);
+
+ BKE_blendfile_link_append_context_free(lapp_context);
return true;
}
-/**
- * Paste datablocks from the given .blend file 'buffer' (i.e. append them).
- *
- * Similar to #BKE_copybuffer_read, but also handles instantiation of collections/objects/etc.
- *
- * \param libname: Full path to the .blend file used as copy/paste buffer.
- * \param flag: A combination of #eBLOLibLinkFlags and ##eFileSel_Params_Flag to control
- * link/append behavior.
- * \note: Ignores #FILE_LINK flag, since it always appends IDs.
- * \param id_types_mask: Only directly link IDs of those types from the given .blend file buffer.
- *
- * \return Number of IDs directly pasted from the buffer (does not includes indirectly linked
- * ones).
- */
int BKE_copybuffer_paste(bContext *C,
const char *libname,
const int flag,
@@ -155,59 +144,31 @@ int BKE_copybuffer_paste(bContext *C,
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
View3D *v3d = CTX_wm_view3d(C); /* may be NULL. */
- Main *mainl = NULL;
- Library *lib;
- BlendHandle *bh;
const int id_tag_extra = 0;
- BlendFileReadReport bf_reports = {.reports = reports};
- bh = BLO_blendhandle_from_file(libname, &bf_reports);
-
- if (bh == NULL) {
- /* error reports will have been made by BLO_blendhandle_from_file() */
- return 0;
- }
-
- BKE_view_layer_base_deselect_all(view_layer);
-
- /* tag everything, all untagged data can be made local
- * its also generally useful to know what is new
- *
- * take extra care BKE_main_id_flag_all(bmain, LIB_TAG_PRE_EXISTING, false) is called after! */
- BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
+ /* Note: No recursive append here, external linked data should remain linked. */
+ BLI_assert((flag & BLO_LIBLINK_APPEND_RECURSIVE) == 0);
- /* here appending/linking starts */
struct LibraryLink_Params liblink_params;
BLO_library_link_params_init_with_context(
&liblink_params, bmain, flag, id_tag_extra, scene, view_layer, v3d);
- mainl = BLO_library_link_begin(&bh, libname, &liblink_params);
-
- const int num_pasted = BLO_library_link_copypaste(mainl, bh, id_types_mask);
-
- BLO_library_link_end(mainl, &bh, &liblink_params);
-
- /* mark all library linked objects to be updated */
- BKE_main_lib_objects_recalc_all(bmain);
- IMB_colormanagement_check_file_config(bmain);
- /* append, rather than linking */
- lib = BLI_findstring(&bmain->libraries, libname, offsetof(Library, filepath_abs));
- BKE_library_make_local(bmain, lib, NULL, true, false);
+ BlendfileLinkAppendContext *lapp_context = BKE_blendfile_link_append_context_new(
+ &liblink_params);
+ BKE_blendfile_link_append_context_library_add(lapp_context, libname, NULL);
- /* important we unset, otherwise these object won't
- * link into other scenes from this blend file */
- BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
-
- /* recreate dependency graph to include new objects */
- DEG_relations_tag_update(bmain);
+ const int num_pasted = BKE_blendfile_link_append_context_item_idtypes_from_library_add(
+ lapp_context, reports, id_types_mask, 0);
+ if (num_pasted == BLENDFILE_LINK_APPEND_INVALID) {
+ BKE_blendfile_link_append_context_free(lapp_context);
+ return 0;
+ }
- /* Tag update the scene to flush base collection settings, since the new object is added to a
- * new (active) collection, not its original collection, thus need recalculation. */
- DEG_id_tag_update(&scene->id, 0);
+ BKE_view_layer_base_deselect_all(view_layer);
- BLO_blendhandle_close(bh);
- /* remove library... */
+ copybuffer_append(lapp_context, bmain, reports);
+ BKE_blendfile_link_append_context_free(lapp_context);
return num_pasted;
}
diff --git a/source/blender/blenkernel/intern/blender_undo.c b/source/blender/blenkernel/intern/blender_undo.c
index 411ece21599..6c443a94def 100644
--- a/source/blender/blenkernel/intern/blender_undo.c
+++ b/source/blender/blenkernel/intern/blender_undo.c
@@ -68,7 +68,7 @@ bool BKE_memfile_undo_decode(MemFileUndoData *mfu,
bContext *C)
{
Main *bmain = CTX_data_main(C);
- char mainstr[sizeof(bmain->name)];
+ char mainstr[sizeof(bmain->filepath)];
int success = 0, fileflags;
BLI_strncpy(mainstr, BKE_main_blendfile_path(bmain), sizeof(mainstr)); /* temporal store */
@@ -101,7 +101,7 @@ bool BKE_memfile_undo_decode(MemFileUndoData *mfu,
/* Restore, bmain has been re-allocated. */
bmain = CTX_data_main(C);
- BLI_strncpy(bmain->name, mainstr, sizeof(bmain->name));
+ STRNCPY(bmain->filepath, mainstr);
G.fileflags = fileflags;
if (success) {
diff --git a/source/blender/blenkernel/intern/blender_user_menu.c b/source/blender/blenkernel/intern/blender_user_menu.c
index edd89357fd5..b186d376e52 100644
--- a/source/blender/blenkernel/intern/blender_user_menu.c
+++ b/source/blender/blenkernel/intern/blender_user_menu.c
@@ -110,3 +110,5 @@ void BKE_blender_user_menu_item_free_list(ListBase *lb)
}
BLI_listbase_clear(lb);
}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c
index fc535fc2ad1..6ae19c8036f 100644
--- a/source/blender/blenkernel/intern/blendfile.c
+++ b/source/blender/blenkernel/intern/blendfile.c
@@ -78,7 +78,9 @@
/** \name High Level `.blend` file read/write.
* \{ */
-static bool clean_paths_visit_cb(void *UNUSED(userdata), char *path_dst, const char *path_src)
+static bool foreach_path_clean_cb(BPathForeachPathData *UNUSED(bpath_data),
+ char *path_dst,
+ const char *path_src)
{
strcpy(path_dst, path_src);
BLI_path_slash_native(path_dst);
@@ -86,13 +88,16 @@ static bool clean_paths_visit_cb(void *UNUSED(userdata), char *path_dst, const c
}
/* make sure path names are correct for OS */
-static void clean_paths(Main *main)
+static void clean_paths(Main *bmain)
{
- Scene *scene;
-
- BKE_bpath_traverse_main(main, clean_paths_visit_cb, BKE_BPATH_TRAVERSE_SKIP_MULTIFILE, NULL);
-
- for (scene = main->scenes.first; scene; scene = scene->id.next) {
+ BKE_bpath_foreach_path_main(&(BPathForeachPathData){
+ .bmain = bmain,
+ .callback_function = foreach_path_clean_cb,
+ .flag = BKE_BPATH_FOREACH_PATH_SKIP_MULTIFILE,
+ .user_data = NULL,
+ });
+
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
BLI_path_slash_native(scene->r.pic);
}
}
@@ -355,12 +360,12 @@ static void setup_app_data(bContext *C,
/* startup.blend or recovered startup */
if (is_startup) {
- bmain->name[0] = '\0';
+ bmain->filepath[0] = '\0';
}
else if (recover) {
- /* In case of autosave or quit.blend, use original filename instead. */
+ /* In case of autosave or quit.blend, use original filepath instead. */
bmain->recovered = 1;
- BLI_strncpy(bmain->name, bfd->filename, FILE_MAX);
+ STRNCPY(bmain->filepath, bfd->filepath);
}
/* baseflags, groups, make depsgraph, etc */
@@ -447,14 +452,6 @@ static void handle_subversion_warning(Main *main, BlendFileReadReport *reports)
}
}
-/**
- * Shared setup function that makes the data from `bfd` into the current blend file,
- * replacing the contents of #G.main.
- * This uses the bfd #BKE_blendfile_read and similarly named functions.
- *
- * This is done in a separate step so the caller may perform actions after it is known the file
- * loaded correctly but before the file replaces the existing blend file contents.
- */
void BKE_blendfile_read_setup_ex(bContext *C,
BlendFileData *bfd,
const struct BlendFileReadParams *params,
@@ -480,9 +477,6 @@ void BKE_blendfile_read_setup(bContext *C,
BKE_blendfile_read_setup_ex(C, bfd, params, reports, false, NULL);
}
-/**
- * \return Blend file data, this must be passed to #BKE_blendfile_read_setup when non-NULL.
- */
struct BlendFileData *BKE_blendfile_read(const char *filepath,
const struct BlendFileReadParams *params,
BlendFileReadReport *reports)
@@ -502,9 +496,6 @@ struct BlendFileData *BKE_blendfile_read(const char *filepath,
return bfd;
}
-/**
- * \return Blend file data, this must be passed to #BKE_blendfile_read_setup when non-NULL.
- */
struct BlendFileData *BKE_blendfile_read_from_memory(const void *filebuf,
int filelength,
const struct BlendFileReadParams *params,
@@ -520,10 +511,6 @@ struct BlendFileData *BKE_blendfile_read_from_memory(const void *filebuf,
return bfd;
}
-/**
- * \return Blend file data, this must be passed to #BKE_blendfile_read_setup when non-NULL.
- * \note `memfile` is the undo buffer.
- */
struct BlendFileData *BKE_blendfile_read_from_memfile(Main *bmain,
struct MemFile *memfile,
const struct BlendFileReadParams *params,
@@ -546,10 +533,6 @@ struct BlendFileData *BKE_blendfile_read_from_memfile(Main *bmain,
return bfd;
}
-/**
- * Utility to make a file 'empty' used for startup to optionally give an empty file.
- * Handy for tests.
- */
void BKE_blendfile_read_make_empty(bContext *C)
{
Main *bmain = CTX_data_main(C);
@@ -568,7 +551,6 @@ void BKE_blendfile_read_make_empty(bContext *C)
FOREACH_MAIN_LISTBASE_END;
}
-/* only read the userdef from a .blend */
UserDef *BKE_blendfile_userdef_read(const char *filepath, ReportList *reports)
{
BlendFileData *bfd;
@@ -671,10 +653,6 @@ UserDef *BKE_blendfile_userdef_from_defaults(void)
return userdef;
}
-/**
- * Only write the userdef in a .blend
- * \return success
- */
bool BKE_blendfile_userdef_write(const char *filepath, ReportList *reports)
{
Main *mainb = MEM_callocN(sizeof(Main), "empty main");
@@ -695,13 +673,6 @@ bool BKE_blendfile_userdef_write(const char *filepath, ReportList *reports)
return ok;
}
-/**
- * Only write the userdef in a .blend, merging with the existing blend file.
- * \return success
- *
- * \note In the future we should re-evaluate user preferences,
- * possibly splitting out system/hardware specific prefs.
- */
bool BKE_blendfile_userdef_write_app_template(const char *filepath, ReportList *reports)
{
/* if it fails, overwrite is OK. */
@@ -872,10 +843,6 @@ static void blendfile_write_partial_cb(void *UNUSED(handle), Main *UNUSED(bmain)
}
}
-/**
- * \param remap_mode: Choose the kind of path remapping or none #eBLO_WritePathRemap.
- * \return Success.
- */
bool BKE_blendfile_write_partial(Main *bmain_src,
const char *filepath,
const int write_flags,
@@ -887,11 +854,12 @@ bool BKE_blendfile_write_partial(Main *bmain_src,
int a, retval;
void *path_list_backup = NULL;
- const int path_list_flag = (BKE_BPATH_TRAVERSE_SKIP_LIBRARY | BKE_BPATH_TRAVERSE_SKIP_MULTIFILE);
+ const eBPathForeachFlag path_list_flag = (BKE_BPATH_FOREACH_PATH_SKIP_LINKED |
+ BKE_BPATH_FOREACH_PATH_SKIP_MULTIFILE);
/* This is needed to be able to load that file as a real one later
- * (otherwise main->name will not be set at read time). */
- BLI_strncpy(bmain_dst->name, bmain_src->name, sizeof(bmain_dst->name));
+ * (otherwise `main->filepath` will not be set at read time). */
+ STRNCPY(bmain_dst->filepath, bmain_src->filepath);
BLO_main_expander(blendfile_write_partial_cb);
BLO_expand_main(NULL, bmain_src);
diff --git a/source/blender/blenkernel/intern/blendfile_link_append.c b/source/blender/blenkernel/intern/blendfile_link_append.c
new file mode 100644
index 00000000000..c265a6e2b7d
--- /dev/null
+++ b/source/blender/blenkernel/intern/blendfile_link_append.c
@@ -0,0 +1,1615 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup bke
+ *
+ * High level `.blend` file link/append code,
+ * including linking/appending several IDs from different libraries, handling instantiations of
+ * collections/objects/object-data in current scene.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "CLG_log.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_ID.h"
+#include "DNA_collection_types.h"
+#include "DNA_key_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+
+#include "BLI_bitmap.h"
+#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
+#include "BLI_linklist.h"
+#include "BLI_math.h"
+#include "BLI_memarena.h"
+#include "BLI_utildefines.h"
+
+#include "BLT_translation.h"
+
+#include "BKE_idtype.h"
+#include "BKE_key.h"
+#include "BKE_layer.h"
+#include "BKE_lib_id.h"
+#include "BKE_lib_override.h"
+#include "BKE_lib_query.h"
+#include "BKE_lib_remap.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_object.h"
+#include "BKE_report.h"
+#include "BKE_rigidbody.h"
+#include "BKE_scene.h"
+
+#include "BKE_blendfile_link_append.h"
+
+#include "BLO_readfile.h"
+#include "BLO_writefile.h"
+
+static CLG_LogRef LOG = {"bke.blendfile_link_append"};
+
+/* -------------------------------------------------------------------- */
+/** \name Link/append context implementation and public management API.
+ * \{ */
+
+typedef struct BlendfileLinkAppendContextItem {
+ /** Name of the ID (without the heading two-chars IDcode). */
+ char *name;
+ /** All libs (from BlendfileLinkAppendContext.libraries) to try to load this ID from. */
+ BLI_bitmap *libraries;
+ /** ID type. */
+ short idcode;
+
+ /** Type of action to perform on this item, and general status tag information.
+ * NOTE: Mostly used by append post-linking processing. */
+ char action;
+ char tag;
+
+ /** Newly linked ID (NULL until it has been successfully linked). */
+ ID *new_id;
+ /** Library ID from which the #new_id has been linked (NULL until it has been successfully
+ * linked). */
+ Library *source_library;
+ /** Opaque user data pointer. */
+ void *userdata;
+} BlendfileLinkAppendContextItem;
+
+/* A blendfile library entry in the `libraries` list of #BlendfileLinkAppendContext. */
+typedef struct BlendfileLinkAppendContextLibrary {
+ char *path; /* Absolute .blend file path. */
+ BlendHandle *blo_handle; /* Blend file handle, if any. */
+ bool blo_handle_is_owned; /* Whether the blend file handle is owned, or borrowed. */
+ /* The blendfile report associated with the `blo_handle`, if owned. */
+ BlendFileReadReport bf_reports;
+} BlendfileLinkAppendContextLibrary;
+
+typedef struct BlendfileLinkAppendContext {
+ /** List of library paths to search IDs in. */
+ LinkNodePair libraries;
+ /** List of all ID to try to link from #libraries. */
+ LinkNodePair items;
+ int num_libraries;
+ int num_items;
+ /** Linking/appending parameters. Including `bmain`, `scene`, `viewlayer` and `view3d`. */
+ LibraryLink_Params *params;
+
+ /** Allows to easily find an existing items from an ID pointer. */
+ GHash *new_id_to_item;
+
+ /** Runtime info used by append code to manage re-use of already appended matching IDs. */
+ GHash *library_weak_reference_mapping;
+
+ /** Embedded blendfile and its size, if needed. */
+ const void *blendfile_mem;
+ size_t blendfile_memsize;
+
+ /** Internal 'private' data */
+ MemArena *memarena;
+} BlendfileLinkAppendContext;
+
+typedef struct BlendfileLinkAppendContextCallBack {
+ BlendfileLinkAppendContext *lapp_context;
+ BlendfileLinkAppendContextItem *item;
+ ReportList *reports;
+
+} BlendfileLinkAppendContextCallBack;
+
+/* Actions to apply to an item (i.e. linked ID). */
+enum {
+ LINK_APPEND_ACT_UNSET = 0,
+ LINK_APPEND_ACT_KEEP_LINKED,
+ LINK_APPEND_ACT_REUSE_LOCAL,
+ LINK_APPEND_ACT_MAKE_LOCAL,
+ LINK_APPEND_ACT_COPY_LOCAL,
+};
+
+/* Various status info about an item (i.e. linked ID). */
+enum {
+ /* An indirectly linked ID. */
+ LINK_APPEND_TAG_INDIRECT = 1 << 0,
+};
+
+static BlendHandle *link_append_context_library_blohandle_ensure(
+ BlendfileLinkAppendContext *lapp_context,
+ BlendfileLinkAppendContextLibrary *lib_context,
+ ReportList *reports)
+{
+ if (reports != NULL) {
+ lib_context->bf_reports.reports = reports;
+ }
+
+ char *libname = lib_context->path;
+ BlendHandle *blo_handle = lib_context->blo_handle;
+ if (blo_handle == NULL) {
+ if (STREQ(libname, BLO_EMBEDDED_STARTUP_BLEND)) {
+ blo_handle = BLO_blendhandle_from_memory(lapp_context->blendfile_mem,
+ (int)lapp_context->blendfile_memsize,
+ &lib_context->bf_reports);
+ }
+ else {
+ blo_handle = BLO_blendhandle_from_file(libname, &lib_context->bf_reports);
+ }
+ lib_context->blo_handle = blo_handle;
+ lib_context->blo_handle_is_owned = true;
+ }
+
+ return blo_handle;
+}
+
+static void link_append_context_library_blohandle_release(
+ BlendfileLinkAppendContext *UNUSED(lapp_context),
+ BlendfileLinkAppendContextLibrary *lib_context)
+{
+ if (lib_context->blo_handle_is_owned && lib_context->blo_handle != NULL) {
+ BLO_blendhandle_close(lib_context->blo_handle);
+ lib_context->blo_handle = NULL;
+ }
+}
+
+BlendfileLinkAppendContext *BKE_blendfile_link_append_context_new(LibraryLink_Params *params)
+{
+ MemArena *ma = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+ BlendfileLinkAppendContext *lapp_context = BLI_memarena_calloc(ma, sizeof(*lapp_context));
+
+ lapp_context->params = params;
+ lapp_context->memarena = ma;
+
+ return lapp_context;
+}
+
+void BKE_blendfile_link_append_context_free(BlendfileLinkAppendContext *lapp_context)
+{
+ if (lapp_context->new_id_to_item != NULL) {
+ BLI_ghash_free(lapp_context->new_id_to_item, NULL, NULL);
+ }
+
+ for (LinkNode *liblink = lapp_context->libraries.list; liblink != NULL;
+ liblink = liblink->next) {
+ BlendfileLinkAppendContextLibrary *lib_context = liblink->link;
+ link_append_context_library_blohandle_release(lapp_context, lib_context);
+ }
+
+ BLI_assert(lapp_context->library_weak_reference_mapping == NULL);
+
+ BLI_memarena_free(lapp_context->memarena);
+}
+
+void BKE_blendfile_link_append_context_flag_set(BlendfileLinkAppendContext *lapp_context,
+ const int flag,
+ const bool do_set)
+{
+ if (do_set) {
+ lapp_context->params->flag |= flag;
+ }
+ else {
+ lapp_context->params->flag &= ~flag;
+ }
+}
+
+void BKE_blendfile_link_append_context_embedded_blendfile_set(
+ BlendfileLinkAppendContext *lapp_context, const void *blendfile_mem, int blendfile_memsize)
+{
+ BLI_assert_msg(lapp_context->blendfile_mem == NULL,
+ "Please explicitly clear reference to an embedded blender memfile before "
+ "setting a new one");
+ lapp_context->blendfile_mem = blendfile_mem;
+ lapp_context->blendfile_memsize = (size_t)blendfile_memsize;
+}
+
+void BKE_blendfile_link_append_context_embedded_blendfile_clear(
+ BlendfileLinkAppendContext *lapp_context)
+{
+ lapp_context->blendfile_mem = NULL;
+ lapp_context->blendfile_memsize = 0;
+}
+
+void BKE_blendfile_link_append_context_library_add(BlendfileLinkAppendContext *lapp_context,
+ const char *libname,
+ BlendHandle *blo_handle)
+{
+ BLI_assert(lapp_context->items.list == NULL);
+
+ BlendfileLinkAppendContextLibrary *lib_context = BLI_memarena_calloc(lapp_context->memarena,
+ sizeof(*lib_context));
+
+ size_t len = strlen(libname) + 1;
+ char *libpath = BLI_memarena_alloc(lapp_context->memarena, len);
+ BLI_strncpy(libpath, libname, len);
+
+ lib_context->path = libpath;
+ lib_context->blo_handle = blo_handle;
+ lib_context->blo_handle_is_owned = (blo_handle == NULL);
+
+ BLI_linklist_append_arena(&lapp_context->libraries, lib_context, lapp_context->memarena);
+ lapp_context->num_libraries++;
+}
+
+BlendfileLinkAppendContextItem *BKE_blendfile_link_append_context_item_add(
+ BlendfileLinkAppendContext *lapp_context,
+ const char *idname,
+ const short idcode,
+ void *userdata)
+{
+ BlendfileLinkAppendContextItem *item = BLI_memarena_calloc(lapp_context->memarena,
+ sizeof(*item));
+ size_t len = strlen(idname) + 1;
+
+ item->name = BLI_memarena_alloc(lapp_context->memarena, len);
+ BLI_strncpy(item->name, idname, len);
+ item->idcode = idcode;
+ item->libraries = BLI_BITMAP_NEW_MEMARENA(lapp_context->memarena, lapp_context->num_libraries);
+
+ item->new_id = NULL;
+ item->action = LINK_APPEND_ACT_UNSET;
+ item->userdata = userdata;
+
+ BLI_linklist_append_arena(&lapp_context->items, item, lapp_context->memarena);
+ lapp_context->num_items++;
+
+ return item;
+}
+
+int BKE_blendfile_link_append_context_item_idtypes_from_library_add(
+ BlendfileLinkAppendContext *lapp_context,
+ ReportList *reports,
+ const uint64_t id_types_filter,
+ const int library_index)
+{
+ int id_num = 0;
+ int id_code_iter = 0;
+ short id_code;
+
+ LinkNode *lib_context_link = BLI_linklist_find(lapp_context->libraries.list, library_index);
+ BlendfileLinkAppendContextLibrary *lib_context = lib_context_link->link;
+ BlendHandle *blo_handle = link_append_context_library_blohandle_ensure(
+ lapp_context, lib_context, reports);
+
+ if (blo_handle == NULL) {
+ return BLENDFILE_LINK_APPEND_INVALID;
+ }
+
+ const bool use_assets_only = (lapp_context->params->flag & FILE_ASSETS_ONLY) != 0;
+
+ while ((id_code = BKE_idtype_idcode_iter_step(&id_code_iter))) {
+ if (!BKE_idtype_idcode_is_linkable(id_code) ||
+ (id_types_filter != 0 &&
+ (BKE_idtype_idcode_to_idfilter(id_code) & id_types_filter) == 0)) {
+ continue;
+ }
+
+ int id_names_num;
+ LinkNode *id_names_list = BLO_blendhandle_get_datablock_names(
+ blo_handle, id_code, use_assets_only, &id_names_num);
+
+ for (LinkNode *link_next = NULL; id_names_list != NULL; id_names_list = link_next) {
+ link_next = id_names_list->next;
+
+ char *id_name = id_names_list->link;
+ BlendfileLinkAppendContextItem *item = BKE_blendfile_link_append_context_item_add(
+ lapp_context, id_name, id_code, NULL);
+ BKE_blendfile_link_append_context_item_library_index_enable(
+ lapp_context, item, library_index);
+
+ MEM_freeN(id_name);
+ MEM_freeN(id_names_list);
+ }
+
+ id_num += id_names_num;
+ }
+
+ return id_num;
+}
+
+void BKE_blendfile_link_append_context_item_library_index_enable(
+ BlendfileLinkAppendContext *UNUSED(lapp_context),
+ BlendfileLinkAppendContextItem *item,
+ const int library_index)
+{
+ BLI_BITMAP_ENABLE(item->libraries, library_index);
+}
+
+bool BKE_blendfile_link_append_context_is_empty(struct BlendfileLinkAppendContext *lapp_context)
+{
+ return lapp_context->num_items == 0;
+}
+
+void *BKE_blendfile_link_append_context_item_userdata_get(
+ BlendfileLinkAppendContext *UNUSED(lapp_context), BlendfileLinkAppendContextItem *item)
+{
+ return item->userdata;
+}
+
+ID *BKE_blendfile_link_append_context_item_newid_get(
+ BlendfileLinkAppendContext *UNUSED(lapp_context), BlendfileLinkAppendContextItem *item)
+{
+ return item->new_id;
+}
+
+short BKE_blendfile_link_append_context_item_idcode_get(
+ struct BlendfileLinkAppendContext *UNUSED(lapp_context),
+ struct BlendfileLinkAppendContextItem *item)
+{
+ return item->idcode;
+}
+
+void BKE_blendfile_link_append_context_item_foreach(
+ struct BlendfileLinkAppendContext *lapp_context,
+ BKE_BlendfileLinkAppendContexteItemFunction callback_function,
+ const eBlendfileLinkAppendForeachItemFlag flag,
+ void *userdata)
+{
+ for (LinkNode *itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+
+ if ((flag & BKE_BLENDFILE_LINK_APPEND_FOREACH_ITEM_FLAG_DO_DIRECT) == 0 &&
+ (item->tag & LINK_APPEND_TAG_INDIRECT) == 0) {
+ continue;
+ }
+ if ((flag & BKE_BLENDFILE_LINK_APPEND_FOREACH_ITEM_FLAG_DO_INDIRECT) == 0 &&
+ (item->tag & LINK_APPEND_TAG_INDIRECT) != 0) {
+ continue;
+ }
+
+ if (!callback_function(lapp_context, item, userdata)) {
+ break;
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Library link/append helper functions.
+ *
+ * \{ */
+
+/* Struct gathering all required data to handle instantiation of loose data-blocks. */
+typedef struct LooseDataInstantiateContext {
+ BlendfileLinkAppendContext *lapp_context;
+
+ /* The collection in which to add loose collections/objects. */
+ Collection *active_collection;
+} LooseDataInstantiateContext;
+
+static bool object_in_any_scene(Main *bmain, Object *ob)
+{
+ LISTBASE_FOREACH (Scene *, sce, &bmain->scenes) {
+ if (BKE_scene_object_find(sce, ob)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool object_in_any_collection(Main *bmain, Object *ob)
+{
+ LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
+ if (BKE_collection_has_object(collection, ob)) {
+ return true;
+ }
+ }
+
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ if (scene->master_collection != NULL &&
+ BKE_collection_has_object(scene->master_collection, ob)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static ID *loose_data_instantiate_process_check(LooseDataInstantiateContext *instantiate_context,
+ BlendfileLinkAppendContextItem *item)
+{
+ BlendfileLinkAppendContext *lapp_context = instantiate_context->lapp_context;
+ /* In linking case, we always want to handle instantiation. */
+ if (lapp_context->params->flag & FILE_LINK) {
+ return item->new_id;
+ }
+
+ /* We consider that if we either kept it linked, or re-used already local data, instantiation
+ * status of those should not be modified. */
+ if (!ELEM(item->action, LINK_APPEND_ACT_COPY_LOCAL, LINK_APPEND_ACT_MAKE_LOCAL)) {
+ return NULL;
+ }
+
+ ID *id = item->new_id;
+ if (id == NULL) {
+ return NULL;
+ }
+
+ if (item->action == LINK_APPEND_ACT_COPY_LOCAL) {
+ BLI_assert(ID_IS_LINKED(id));
+ id = id->newid;
+ if (id == NULL) {
+ return NULL;
+ }
+
+ BLI_assert(!ID_IS_LINKED(id));
+ return id;
+ }
+
+ BLI_assert(!ID_IS_LINKED(id));
+ return id;
+}
+
+static void loose_data_instantiate_ensure_active_collection(
+ LooseDataInstantiateContext *instantiate_context)
+{
+
+ BlendfileLinkAppendContext *lapp_context = instantiate_context->lapp_context;
+ Main *bmain = instantiate_context->lapp_context->params->bmain;
+ Scene *scene = instantiate_context->lapp_context->params->context.scene;
+ ViewLayer *view_layer = instantiate_context->lapp_context->params->context.view_layer;
+
+ /* Find or add collection as needed. */
+ if (instantiate_context->active_collection == NULL) {
+ if (lapp_context->params->flag & FILE_ACTIVE_COLLECTION) {
+ LayerCollection *lc = BKE_layer_collection_get_active(view_layer);
+ instantiate_context->active_collection = lc->collection;
+ }
+ else {
+ if (lapp_context->params->flag & FILE_LINK) {
+ instantiate_context->active_collection = BKE_collection_add(
+ bmain, scene->master_collection, DATA_("Linked Data"));
+ }
+ else {
+ instantiate_context->active_collection = BKE_collection_add(
+ bmain, scene->master_collection, DATA_("Appended Data"));
+ }
+ }
+ }
+}
+
+static void loose_data_instantiate_object_base_instance_init(Main *bmain,
+ Collection *collection,
+ Object *ob,
+ ViewLayer *view_layer,
+ const View3D *v3d,
+ const int flag,
+ bool set_active)
+{
+ /* Auto-select and appending. */
+ if ((flag & FILE_AUTOSELECT) && ((flag & FILE_LINK) == 0)) {
+ /* While in general the object should not be manipulated,
+ * when the user requests the object to be selected, ensure it's visible and selectable. */
+ ob->visibility_flag &= ~(OB_HIDE_VIEWPORT | OB_HIDE_SELECT);
+ }
+
+ BKE_collection_object_add(bmain, collection, ob);
+
+ Base *base = BKE_view_layer_base_find(view_layer, ob);
+
+ if (v3d != NULL) {
+ base->local_view_bits |= v3d->local_view_uuid;
+ }
+
+ if (flag & FILE_AUTOSELECT) {
+ /* All objects that use #FILE_AUTOSELECT must be selectable (unless linking data). */
+ BLI_assert((base->flag & BASE_SELECTABLE) || (flag & FILE_LINK));
+ if (base->flag & BASE_SELECTABLE) {
+ base->flag |= BASE_SELECTED;
+ }
+ }
+
+ if (set_active) {
+ view_layer->basact = base;
+ }
+
+ BKE_scene_object_base_flag_sync_from_base(base);
+}
+
+/* Tag obdata that actually need to be instantiated (those referenced by an object do not, since
+ * the object will be instantiated instead if needed. */
+static void loose_data_instantiate_obdata_preprocess(
+ LooseDataInstantiateContext *instantiate_context)
+{
+ BlendfileLinkAppendContext *lapp_context = instantiate_context->lapp_context;
+ LinkNode *itemlink;
+
+ /* First pass on obdata to enable their instantiation by default, then do a second pass on
+ * objects to clear it for any obdata already in use. */
+ for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+ ID *id = loose_data_instantiate_process_check(instantiate_context, item);
+ if (id == NULL) {
+ continue;
+ }
+ const ID_Type idcode = GS(id->name);
+ if (!OB_DATA_SUPPORT_ID(idcode)) {
+ continue;
+ }
+
+ id->tag |= LIB_TAG_DOIT;
+ }
+ for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+ ID *id = item->new_id;
+ if (id == NULL || GS(id->name) != ID_OB) {
+ continue;
+ }
+
+ Object *ob = (Object *)id;
+ Object *new_ob = (Object *)id->newid;
+ if (ob->data != NULL) {
+ ((ID *)(ob->data))->tag &= ~LIB_TAG_DOIT;
+ }
+ if (new_ob != NULL && new_ob->data != NULL) {
+ ((ID *)(new_ob->data))->tag &= ~LIB_TAG_DOIT;
+ }
+ }
+}
+
+/* Test whether some ancestor collection is also tagged for instantiation (return true) or not
+ * (return false). */
+static bool loose_data_instantiate_collection_parents_check_recursive(Collection *collection)
+{
+ for (CollectionParent *parent_collection = collection->parents.first; parent_collection != NULL;
+ parent_collection = parent_collection->next) {
+ if ((parent_collection->collection->id.tag & LIB_TAG_DOIT) != 0) {
+ return true;
+ }
+ if (loose_data_instantiate_collection_parents_check_recursive(parent_collection->collection)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static void loose_data_instantiate_collection_process(
+ LooseDataInstantiateContext *instantiate_context)
+{
+ BlendfileLinkAppendContext *lapp_context = instantiate_context->lapp_context;
+ Main *bmain = lapp_context->params->bmain;
+ Scene *scene = lapp_context->params->context.scene;
+ ViewLayer *view_layer = lapp_context->params->context.view_layer;
+ const View3D *v3d = lapp_context->params->context.v3d;
+
+ const bool do_append = (lapp_context->params->flag & FILE_LINK) == 0;
+ const bool do_instantiate_as_empty = (lapp_context->params->flag &
+ BLO_LIBLINK_COLLECTION_INSTANCE) != 0;
+
+ /* NOTE: For collections we only view_layer-instantiate duplicated collections that have
+ * non-instantiated objects in them.
+ * NOTE: Also avoid view-layer-instantiating of collections children of other instantiated
+ * collections. This is why we need two passes here. */
+ LinkNode *itemlink;
+ for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+ ID *id = loose_data_instantiate_process_check(instantiate_context, item);
+ if (id == NULL || GS(id->name) != ID_GR) {
+ continue;
+ }
+
+ /* Forced instantiation of indirectly appended collections is not wanted. Users can now
+ * easily instantiate collections (and their objects) as needed by themselves. See T67032. */
+ /* We need to check that objects in that collections are already instantiated in a scene.
+ * Otherwise, it's better to add the collection to the scene's active collection, than to
+ * instantiate its objects in active scene's collection directly. See T61141.
+ *
+ * NOTE: We only check object directly into that collection, not recursively into its
+ * children.
+ */
+ Collection *collection = (Collection *)id;
+ /* Always consider adding collections directly selected by the user. */
+ bool do_add_collection = (item->tag & LINK_APPEND_TAG_INDIRECT) == 0;
+ /* In linking case, do not enforce instantiating non-directly linked collections/objects.
+ * This avoids cluttering the ViewLayers, user can instantiate themselves specific collections
+ * or objects easily from the Outliner if needed. */
+ if (!do_add_collection && do_append) {
+ LISTBASE_FOREACH (CollectionObject *, coll_ob, &collection->gobject) {
+ Object *ob = coll_ob->ob;
+ if (!object_in_any_scene(bmain, ob)) {
+ do_add_collection = true;
+ break;
+ }
+ }
+ }
+ if (do_add_collection) {
+ collection->id.tag |= LIB_TAG_DOIT;
+ }
+ }
+
+ /* Second loop to actually instantiate collections tagged as such in first loop, unless some of
+ * their ancestor is also instantiated in case this is not an empty-instantiation. */
+ for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+ ID *id = loose_data_instantiate_process_check(instantiate_context, item);
+ if (id == NULL || GS(id->name) != ID_GR) {
+ continue;
+ }
+
+ Collection *collection = (Collection *)id;
+ bool do_add_collection = (id->tag & LIB_TAG_DOIT) != 0;
+
+ /* When instantiated into view-layer, do not add collections if one of their parents is also
+ * instantiated. In case of empty-instantiation though, instantiation of all user-selected
+ * collections is the desired behavior. */
+ if (!do_add_collection ||
+ (!do_instantiate_as_empty &&
+ loose_data_instantiate_collection_parents_check_recursive(collection))) {
+ continue;
+ }
+
+ loose_data_instantiate_ensure_active_collection(instantiate_context);
+ Collection *active_collection = instantiate_context->active_collection;
+
+ /* In case user requested instantiation of collections as empties, do so for the one they
+ * explicitly selected (originally directly linked IDs) only. */
+ if (do_instantiate_as_empty && (item->tag & LINK_APPEND_TAG_INDIRECT) == 0) {
+ /* BKE_object_add(...) messes with the selection. */
+ Object *ob = BKE_object_add_only_object(bmain, OB_EMPTY, collection->id.name + 2);
+ ob->type = OB_EMPTY;
+ ob->empty_drawsize = U.collection_instance_empty_size;
+
+ const bool set_selected = (lapp_context->params->flag & FILE_AUTOSELECT) != 0;
+ /* TODO: why is it OK to make this active here but not in other situations?
+ * See other callers of #object_base_instance_init */
+ const bool set_active = set_selected;
+ loose_data_instantiate_object_base_instance_init(
+ bmain, active_collection, ob, view_layer, v3d, lapp_context->params->flag, set_active);
+
+ /* Assign the collection. */
+ ob->instance_collection = collection;
+ id_us_plus(&collection->id);
+ ob->transflag |= OB_DUPLICOLLECTION;
+ copy_v3_v3(ob->loc, scene->cursor.location);
+ }
+ else {
+ /* Add collection as child of active collection. */
+ BKE_collection_child_add(bmain, active_collection, collection);
+
+ if ((lapp_context->params->flag & FILE_AUTOSELECT) != 0) {
+ LISTBASE_FOREACH (CollectionObject *, coll_ob, &collection->gobject) {
+ Object *ob = coll_ob->ob;
+ Base *base = BKE_view_layer_base_find(view_layer, ob);
+ if (base) {
+ base->flag |= BASE_SELECTED;
+ BKE_scene_object_base_flag_sync_from_base(base);
+ }
+ }
+ }
+ }
+ }
+}
+
+static void loose_data_instantiate_object_process(LooseDataInstantiateContext *instantiate_context)
+{
+ BlendfileLinkAppendContext *lapp_context = instantiate_context->lapp_context;
+ Main *bmain = lapp_context->params->bmain;
+ ViewLayer *view_layer = lapp_context->params->context.view_layer;
+ const View3D *v3d = lapp_context->params->context.v3d;
+
+ /* Do NOT make base active here! screws up GUI stuff,
+ * if you want it do it at the editor level. */
+ const bool object_set_active = false;
+
+ /* NOTE: For objects we only view_layer-instantiate duplicated objects that are not yet used
+ * anywhere. */
+ LinkNode *itemlink;
+ for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+ ID *id = loose_data_instantiate_process_check(instantiate_context, item);
+ if (id == NULL || GS(id->name) != ID_OB) {
+ continue;
+ }
+
+ Object *ob = (Object *)id;
+
+ if (object_in_any_collection(bmain, ob)) {
+ continue;
+ }
+
+ loose_data_instantiate_ensure_active_collection(instantiate_context);
+ Collection *active_collection = instantiate_context->active_collection;
+
+ CLAMP_MIN(ob->id.us, 0);
+ ob->mode = OB_MODE_OBJECT;
+
+ loose_data_instantiate_object_base_instance_init(bmain,
+ active_collection,
+ ob,
+ view_layer,
+ v3d,
+ lapp_context->params->flag,
+ object_set_active);
+ }
+}
+
+static void loose_data_instantiate_obdata_process(LooseDataInstantiateContext *instantiate_context)
+{
+ BlendfileLinkAppendContext *lapp_context = instantiate_context->lapp_context;
+ Main *bmain = lapp_context->params->bmain;
+ Scene *scene = lapp_context->params->context.scene;
+ ViewLayer *view_layer = lapp_context->params->context.view_layer;
+ const View3D *v3d = lapp_context->params->context.v3d;
+
+ /* Do NOT make base active here! screws up GUI stuff,
+ * if you want it do it at the editor level. */
+ const bool object_set_active = false;
+
+ LinkNode *itemlink;
+ for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+ ID *id = loose_data_instantiate_process_check(instantiate_context, item);
+ if (id == NULL) {
+ continue;
+ }
+ const ID_Type idcode = GS(id->name);
+ if (!OB_DATA_SUPPORT_ID(idcode)) {
+ continue;
+ }
+ if ((id->tag & LIB_TAG_DOIT) == 0) {
+ continue;
+ }
+
+ loose_data_instantiate_ensure_active_collection(instantiate_context);
+ Collection *active_collection = instantiate_context->active_collection;
+
+ const int type = BKE_object_obdata_to_type(id);
+ BLI_assert(type != -1);
+ Object *ob = BKE_object_add_only_object(bmain, type, id->name + 2);
+ ob->data = id;
+ id_us_plus(id);
+ BKE_object_materials_test(bmain, ob, ob->data);
+
+ loose_data_instantiate_object_base_instance_init(bmain,
+ active_collection,
+ ob,
+ view_layer,
+ v3d,
+ lapp_context->params->flag,
+ object_set_active);
+
+ copy_v3_v3(ob->loc, scene->cursor.location);
+
+ id->tag &= ~LIB_TAG_DOIT;
+ }
+}
+
+static void loose_data_instantiate_object_rigidbody_postprocess(
+ LooseDataInstantiateContext *instantiate_context)
+{
+ BlendfileLinkAppendContext *lapp_context = instantiate_context->lapp_context;
+ Main *bmain = lapp_context->params->bmain;
+
+ LinkNode *itemlink;
+ /* Add rigid body objects and constraints to current RB world(s). */
+ for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+ ID *id = loose_data_instantiate_process_check(instantiate_context, item);
+ if (id == NULL || GS(id->name) != ID_OB) {
+ continue;
+ }
+ BKE_rigidbody_ensure_local_object(bmain, (Object *)id);
+ }
+}
+
+static void loose_data_instantiate(LooseDataInstantiateContext *instantiate_context)
+{
+ if (instantiate_context->lapp_context->params->context.scene == NULL) {
+ /* In some cases, like the asset drag&drop e.g., the caller code manages instantiation itself.
+ */
+ return;
+ }
+
+ BlendfileLinkAppendContext *lapp_context = instantiate_context->lapp_context;
+ const bool do_obdata = (lapp_context->params->flag & BLO_LIBLINK_OBDATA_INSTANCE) != 0;
+
+ /* First pass on obdata to enable their instantiation by default, then do a second pass on
+ * objects to clear it for any obdata already in use. */
+ if (do_obdata) {
+ loose_data_instantiate_obdata_preprocess(instantiate_context);
+ }
+
+ /* First do collections, then objects, then obdata. */
+ loose_data_instantiate_collection_process(instantiate_context);
+ loose_data_instantiate_object_process(instantiate_context);
+ if (do_obdata) {
+ loose_data_instantiate_obdata_process(instantiate_context);
+ }
+
+ loose_data_instantiate_object_rigidbody_postprocess(instantiate_context);
+}
+
+static void new_id_to_item_mapping_add(BlendfileLinkAppendContext *lapp_context,
+ ID *id,
+ BlendfileLinkAppendContextItem *item)
+{
+ BLI_ghash_insert(lapp_context->new_id_to_item, id, item);
+
+ /* This ensures that if a liboverride reference is also linked/used by some other appended
+ * data, it gets a local copy instead of being made directly local, so that the liboverride
+ * references remain valid (i.e. linked data). */
+ if (ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
+ id->override_library->reference->tag |= LIB_TAG_PRE_EXISTING;
+ }
+}
+
+/* Generate a mapping between newly linked IDs and their items, and tag linked IDs used as
+ * liboverride references as already existing. */
+static void new_id_to_item_mapping_create(BlendfileLinkAppendContext *lapp_context)
+{
+ lapp_context->new_id_to_item = BLI_ghash_new(
+ BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
+ for (LinkNode *itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+ ID *id = item->new_id;
+ if (id == NULL) {
+ continue;
+ }
+
+ new_id_to_item_mapping_add(lapp_context, id, item);
+ }
+}
+
+static int foreach_libblock_link_append_callback(LibraryIDLinkCallbackData *cb_data)
+{
+ /* NOTE: It is important to also skip liboverride references here, as those should never be made
+ * local. */
+ if (cb_data->cb_flag & (IDWALK_CB_EMBEDDED | IDWALK_CB_INTERNAL | IDWALK_CB_LOOPBACK |
+ IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE)) {
+ return IDWALK_RET_NOP;
+ }
+
+ BlendfileLinkAppendContextCallBack *data = cb_data->user_data;
+ ID *id = *cb_data->id_pointer;
+
+ if (id == NULL) {
+ return IDWALK_RET_NOP;
+ }
+
+ if (!BKE_idtype_idcode_is_linkable(GS(id->name))) {
+ /* While we do not want to add non-linkable ID (shape keys...) to the list of linked items,
+ * unfortunately they can use fully linkable valid IDs too, like actions. Those need to be
+ * processed, so we need to recursively deal with them here. */
+ /* NOTE: Since we are by-passing checks in `BKE_library_foreach_ID_link` by manually calling it
+ * recursively, we need to take care of potential recursion cases ourselves (e.g.animdata of
+ * shape-key referencing the shape-key itself). */
+ if (id != cb_data->id_self) {
+ BKE_library_foreach_ID_link(
+ cb_data->bmain, id, foreach_libblock_link_append_callback, data, IDWALK_NOP);
+ }
+ return IDWALK_RET_NOP;
+ }
+
+ /* In linking case, we always consider all linked IDs, even indirectly ones, for instantiation,
+ * so we need to add them all to the items list.
+ *
+ * In appending case, when `do_recursive` is false, we only make local IDs from same
+ * library(-ies) as the initially directly linked ones.
+ *
+ * NOTE: Since in append case, linked IDs are also fully skipped during instantiation step (see
+ * #append_loose_data_instantiate_process_check), we can avoid adding them to the items list
+ * completely. */
+ const bool do_link = (data->lapp_context->params->flag & FILE_LINK) != 0;
+ const bool do_recursive = (data->lapp_context->params->flag & BLO_LIBLINK_APPEND_RECURSIVE) !=
+ 0 ||
+ do_link;
+ if (!do_recursive && cb_data->id_owner->lib != id->lib) {
+ return IDWALK_RET_NOP;
+ }
+
+ BlendfileLinkAppendContextItem *item = BLI_ghash_lookup(data->lapp_context->new_id_to_item, id);
+ if (item == NULL) {
+ item = BKE_blendfile_link_append_context_item_add(
+ data->lapp_context, id->name, GS(id->name), NULL);
+ item->new_id = id;
+ item->source_library = id->lib;
+ /* Since we did not have an item for that ID yet, we know user did not selected it explicitly,
+ * it was rather linked indirectly. This info is important for instantiation of collections. */
+ item->tag |= LINK_APPEND_TAG_INDIRECT;
+ /* In linking case we already know what we want to do with those items. */
+ if (do_link) {
+ item->action = LINK_APPEND_ACT_KEEP_LINKED;
+ }
+ new_id_to_item_mapping_add(data->lapp_context, id, item);
+ }
+
+ /* NOTE: currently there is no need to do anything else here, but in the future this would be
+ * the place to add specific per-usage decisions on how to append an ID. */
+
+ return IDWALK_RET_NOP;
+}
+
+/** \} */
+
+/** \name Library link/append code.
+ * \{ */
+
+void BKE_blendfile_append(BlendfileLinkAppendContext *lapp_context, ReportList *reports)
+{
+ if (lapp_context->num_items == 0) {
+ /* Nothing to append. */
+ return;
+ }
+
+ Main *bmain = lapp_context->params->bmain;
+
+ BLI_assert((lapp_context->params->flag & FILE_LINK) == 0);
+
+ const bool set_fakeuser = (lapp_context->params->flag & BLO_LIBLINK_APPEND_SET_FAKEUSER) != 0;
+ const bool do_reuse_local_id = (lapp_context->params->flag &
+ BLO_LIBLINK_APPEND_LOCAL_ID_REUSE) != 0;
+
+ const int make_local_common_flags = LIB_ID_MAKELOCAL_FULL_LIBRARY |
+ ((lapp_context->params->flag &
+ BLO_LIBLINK_APPEND_ASSET_DATA_CLEAR) != 0 ?
+ LIB_ID_MAKELOCAL_ASSET_DATA_CLEAR :
+ 0);
+
+ LinkNode *itemlink;
+
+ new_id_to_item_mapping_create(lapp_context);
+ lapp_context->library_weak_reference_mapping = BKE_main_library_weak_reference_create(bmain);
+
+ /* NOTE: Since we append items for IDs not already listed (i.e. implicitly linked indirect
+ * dependencies), this list will grow and we will process those IDs later, leading to a flatten
+ * recursive processing of all the linked dependencies. */
+ for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+ ID *id = item->new_id;
+ if (id == NULL) {
+ continue;
+ }
+ BLI_assert(item->userdata == NULL);
+
+ ID *existing_local_id = BKE_idtype_idcode_append_is_reusable(GS(id->name)) ?
+ BKE_main_library_weak_reference_search_item(
+ lapp_context->library_weak_reference_mapping,
+ id->lib->filepath,
+ id->name) :
+ NULL;
+
+ if (item->action != LINK_APPEND_ACT_UNSET) {
+ /* Already set, pass. */
+ }
+ if (GS(id->name) == ID_OB && ((Object *)id)->proxy_from != NULL) {
+ CLOG_INFO(&LOG, 3, "Appended ID '%s' is proxified, keeping it linked...", id->name);
+ item->action = LINK_APPEND_ACT_KEEP_LINKED;
+ }
+ else if (do_reuse_local_id && existing_local_id != NULL) {
+ CLOG_INFO(&LOG, 3, "Appended ID '%s' as a matching local one, re-using it...", id->name);
+ item->action = LINK_APPEND_ACT_REUSE_LOCAL;
+ item->userdata = existing_local_id;
+ }
+ else if (id->tag & LIB_TAG_PRE_EXISTING) {
+ CLOG_INFO(&LOG, 3, "Appended ID '%s' was already linked, need to copy it...", id->name);
+ item->action = LINK_APPEND_ACT_COPY_LOCAL;
+ }
+ else {
+ CLOG_INFO(&LOG, 3, "Appended ID '%s' will be made local...", id->name);
+ item->action = LINK_APPEND_ACT_MAKE_LOCAL;
+ }
+
+ /* Only check dependencies if we are not keeping linked data, nor re-using existing local data.
+ */
+ if (!ELEM(item->action, LINK_APPEND_ACT_KEEP_LINKED, LINK_APPEND_ACT_REUSE_LOCAL)) {
+ BlendfileLinkAppendContextCallBack cb_data = {
+ .lapp_context = lapp_context, .item = item, .reports = reports};
+ BKE_library_foreach_ID_link(
+ bmain, id, foreach_libblock_link_append_callback, &cb_data, IDWALK_NOP);
+ }
+
+ /* If we found a matching existing local id but are not re-using it, we need to properly clear
+ * its weak reference to linked data. */
+ if (existing_local_id != NULL &&
+ !ELEM(item->action, LINK_APPEND_ACT_KEEP_LINKED, LINK_APPEND_ACT_REUSE_LOCAL)) {
+ BKE_main_library_weak_reference_remove_item(lapp_context->library_weak_reference_mapping,
+ id->lib->filepath,
+ id->name,
+ existing_local_id);
+ }
+ }
+
+ /* Effectively perform required operation on every linked ID. */
+ for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+ ID *id = item->new_id;
+ if (id == NULL) {
+ continue;
+ }
+
+ ID *local_appended_new_id = NULL;
+ char lib_filepath[FILE_MAX];
+ BLI_strncpy(lib_filepath, id->lib->filepath, sizeof(lib_filepath));
+ char lib_id_name[MAX_ID_NAME];
+ BLI_strncpy(lib_id_name, id->name, sizeof(lib_id_name));
+
+ switch (item->action) {
+ case LINK_APPEND_ACT_COPY_LOCAL:
+ BKE_lib_id_make_local(bmain, id, make_local_common_flags | LIB_ID_MAKELOCAL_FORCE_COPY);
+ local_appended_new_id = id->newid;
+ break;
+ case LINK_APPEND_ACT_MAKE_LOCAL:
+ BKE_lib_id_make_local(bmain,
+ id,
+ make_local_common_flags | LIB_ID_MAKELOCAL_FORCE_LOCAL |
+ LIB_ID_MAKELOCAL_OBJECT_NO_PROXY_CLEARING);
+ BLI_assert(id->newid == NULL);
+ local_appended_new_id = id;
+ break;
+ case LINK_APPEND_ACT_KEEP_LINKED:
+ /* Nothing to do here. */
+ break;
+ case LINK_APPEND_ACT_REUSE_LOCAL:
+ /* We only need to set `newid` to ID found in previous loop, for proper remapping. */
+ ID_NEW_SET(id, item->userdata);
+ /* This is not a 'new' local appended id, do not set `local_appended_new_id` here. */
+ break;
+ case LINK_APPEND_ACT_UNSET:
+ CLOG_ERROR(
+ &LOG, "Unexpected unset append action for '%s' ID, assuming 'keep link'", id->name);
+ break;
+ default:
+ BLI_assert(0);
+ }
+
+ if (local_appended_new_id != NULL) {
+ if (BKE_idtype_idcode_append_is_reusable(GS(local_appended_new_id->name))) {
+ BKE_main_library_weak_reference_add_item(lapp_context->library_weak_reference_mapping,
+ lib_filepath,
+ lib_id_name,
+ local_appended_new_id);
+ }
+
+ if (set_fakeuser) {
+ if (!ELEM(GS(local_appended_new_id->name), ID_OB, ID_GR)) {
+ /* Do not set fake user on objects nor collections (instancing). */
+ id_fake_user_set(local_appended_new_id);
+ }
+ }
+ }
+ }
+
+ BKE_main_library_weak_reference_destroy(lapp_context->library_weak_reference_mapping);
+ lapp_context->library_weak_reference_mapping = NULL;
+
+ /* Remap IDs as needed. */
+ for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+
+ if (item->action == LINK_APPEND_ACT_KEEP_LINKED) {
+ continue;
+ }
+
+ ID *id = item->new_id;
+ if (id == NULL) {
+ continue;
+ }
+ if (ELEM(item->action, LINK_APPEND_ACT_COPY_LOCAL, LINK_APPEND_ACT_REUSE_LOCAL)) {
+ BLI_assert(ID_IS_LINKED(id));
+ id = id->newid;
+ if (id == NULL) {
+ continue;
+ }
+ }
+
+ BLI_assert(!ID_IS_LINKED(id));
+
+ BKE_libblock_relink_to_newid(bmain, id, 0);
+ }
+
+ /* Remove linked IDs when a local existing data has been reused instead. */
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
+ for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+
+ if (item->action != LINK_APPEND_ACT_REUSE_LOCAL) {
+ continue;
+ }
+
+ ID *id = item->new_id;
+ if (id == NULL) {
+ continue;
+ }
+ BLI_assert(ID_IS_LINKED(id));
+ BLI_assert(id->newid != NULL);
+
+ id->tag |= LIB_TAG_DOIT;
+ item->new_id = id->newid;
+ }
+ BKE_id_multi_tagged_delete(bmain);
+
+ /* Instantiate newly created (duplicated) IDs as needed. */
+ LooseDataInstantiateContext instantiate_context = {.lapp_context = lapp_context,
+ .active_collection = NULL};
+ loose_data_instantiate(&instantiate_context);
+
+ /* Attempt to deal with object proxies.
+ *
+ * NOTE: Copied from `BKE_library_make_local`, but this is not really working (as in, not
+ * producing any useful result in any known use case), neither here nor in
+ * `BKE_library_make_local` currently.
+ * Proxies are end of life anyway, so not worth spending time on this. */
+ for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+
+ if (item->action != LINK_APPEND_ACT_COPY_LOCAL) {
+ continue;
+ }
+
+ ID *id = item->new_id;
+ if (id == NULL) {
+ continue;
+ }
+ BLI_assert(ID_IS_LINKED(id));
+
+ /* Attempt to re-link copied proxy objects. This allows appending of an entire scene
+ * from another blend file into this one, even when that blend file contains proxified
+ * armatures that have local references. Since the proxified object needs to be linked
+ * (not local), this will only work when the "Localize all" checkbox is disabled.
+ * TL;DR: this is a dirty hack on top of an already weak feature (proxies). */
+ if (GS(id->name) == ID_OB && ((Object *)id)->proxy != NULL) {
+ Object *ob = (Object *)id;
+ Object *ob_new = (Object *)id->newid;
+ bool is_local = false, is_lib = false;
+
+ /* Proxies only work when the proxified object is linked-in from a library. */
+ if (!ID_IS_LINKED(ob->proxy)) {
+ CLOG_WARN(&LOG,
+ "Proxy object %s will lose its link to %s, because the "
+ "proxified object is local",
+ id->newid->name,
+ ob->proxy->id.name);
+ continue;
+ }
+
+ BKE_library_ID_test_usages(bmain, id, &is_local, &is_lib);
+
+ /* We can only switch the proxy'ing to a made-local proxy if it is no longer
+ * referred to from a library. Not checking for local use; if new local proxy
+ * was not used locally would be a nasty bug! */
+ if (is_local || is_lib) {
+ CLOG_WARN(&LOG,
+ "Made-local proxy object %s will lose its link to %s, "
+ "because the linked-in proxy is referenced (is_local=%i, is_lib=%i)",
+ id->newid->name,
+ ob->proxy->id.name,
+ is_local,
+ is_lib);
+ }
+ else {
+ /* we can switch the proxy'ing from the linked-in to the made-local proxy.
+ * BKE_object_make_proxy() shouldn't be used here, as it allocates memory that
+ * was already allocated by object_make_local() (which called BKE_object_copy). */
+ ob_new->proxy = ob->proxy;
+ ob_new->proxy_group = ob->proxy_group;
+ ob_new->proxy_from = ob->proxy_from;
+ ob_new->proxy->proxy_from = ob_new;
+ ob->proxy = ob->proxy_from = ob->proxy_group = NULL;
+ }
+ }
+ }
+
+ BKE_main_id_newptr_and_tag_clear(bmain);
+}
+
+void BKE_blendfile_link(BlendfileLinkAppendContext *lapp_context, ReportList *reports)
+{
+ if (lapp_context->num_items == 0) {
+ /* Nothing to be linked. */
+ return;
+ }
+
+ BLI_assert(lapp_context->num_libraries != 0);
+
+ Main *mainl;
+ Library *lib;
+
+ LinkNode *liblink, *itemlink;
+ int lib_idx, item_idx;
+
+ for (lib_idx = 0, liblink = lapp_context->libraries.list; liblink;
+ lib_idx++, liblink = liblink->next) {
+ BlendfileLinkAppendContextLibrary *lib_context = liblink->link;
+ char *libname = lib_context->path;
+ BlendHandle *blo_handle = link_append_context_library_blohandle_ensure(
+ lapp_context, lib_context, reports);
+
+ if (blo_handle == NULL) {
+ /* Unlikely since we just browsed it, but possible
+ * Error reports will have been made by BLO_blendhandle_from_file() */
+ continue;
+ }
+
+ /* here appending/linking starts */
+
+ mainl = BLO_library_link_begin(&blo_handle, libname, lapp_context->params);
+ lib = mainl->curlib;
+ BLI_assert(lib);
+ UNUSED_VARS_NDEBUG(lib);
+
+ if (mainl->versionfile < 250) {
+ BKE_reportf(reports,
+ RPT_WARNING,
+ "Linking or appending from a very old .blend file format (%d.%d), no animation "
+ "conversion will "
+ "be done! You may want to re-save your lib file with current Blender",
+ mainl->versionfile,
+ mainl->subversionfile);
+ }
+
+ /* For each lib file, we try to link all items belonging to that lib,
+ * and tag those successful to not try to load them again with the other libs. */
+ for (item_idx = 0, itemlink = lapp_context->items.list; itemlink;
+ item_idx++, itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+ ID *new_id;
+
+ if (!BLI_BITMAP_TEST(item->libraries, lib_idx)) {
+ continue;
+ }
+
+ new_id = BLO_library_link_named_part(
+ mainl, &blo_handle, item->idcode, item->name, lapp_context->params);
+
+ if (new_id) {
+ /* If the link is successful, clear item's libs 'todo' flags.
+ * This avoids trying to link same item with other libraries to come. */
+ BLI_bitmap_set_all(item->libraries, false, lapp_context->num_libraries);
+ item->new_id = new_id;
+ item->source_library = new_id->lib;
+ }
+ }
+
+ BLO_library_link_end(mainl, &blo_handle, lapp_context->params);
+ link_append_context_library_blohandle_release(lapp_context, lib_context);
+ }
+
+ /* Instantiate newly linked IDs as needed, if no append is scheduled. */
+ if ((lapp_context->params->flag & FILE_LINK) != 0 &&
+ lapp_context->params->context.scene != NULL) {
+ new_id_to_item_mapping_create(lapp_context);
+ /* NOTE: Since we append items for IDs not already listed (i.e. implicitly linked indirect
+ * dependencies), this list will grow and we will process those IDs later, leading to a flatten
+ * recursive processing of all the linked dependencies. */
+ for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+ ID *id = item->new_id;
+ if (id == NULL) {
+ continue;
+ }
+ BLI_assert(item->userdata == NULL);
+
+ BlendfileLinkAppendContextCallBack cb_data = {
+ .lapp_context = lapp_context, .item = item, .reports = reports};
+ BKE_library_foreach_ID_link(lapp_context->params->bmain,
+ id,
+ foreach_libblock_link_append_callback,
+ &cb_data,
+ IDWALK_NOP);
+ }
+
+ LooseDataInstantiateContext instantiate_context = {.lapp_context = lapp_context,
+ .active_collection = NULL};
+ loose_data_instantiate(&instantiate_context);
+ }
+}
+
+/** \} */
+
+/** \name Library relocating code.
+ * \{ */
+
+static void blendfile_library_relocate_remap(Main *bmain,
+ ID *old_id,
+ ID *new_id,
+ ReportList *reports,
+ const bool do_reload,
+ const short remap_flags)
+{
+ BLI_assert(old_id);
+ if (do_reload) {
+ /* Since we asked for placeholders in case of missing IDs,
+ * we expect to always get a valid one. */
+ BLI_assert(new_id);
+ }
+ if (new_id) {
+ CLOG_INFO(&LOG,
+ 4,
+ "Before remap of %s, old_id users: %d, new_id users: %d",
+ old_id->name,
+ old_id->us,
+ new_id->us);
+ BKE_libblock_remap_locked(bmain, old_id, new_id, remap_flags);
+
+ if (old_id->flag & LIB_FAKEUSER) {
+ id_fake_user_clear(old_id);
+ id_fake_user_set(new_id);
+ }
+
+ CLOG_INFO(&LOG,
+ 4,
+ "After remap of %s, old_id users: %d, new_id users: %d",
+ old_id->name,
+ old_id->us,
+ new_id->us);
+
+ /* In some cases, new_id might become direct link, remove parent of library in this case. */
+ if (new_id->lib->parent && (new_id->tag & LIB_TAG_INDIRECT) == 0) {
+ if (do_reload) {
+ BLI_assert_unreachable(); /* Should not happen in 'pure' reload case... */
+ }
+ new_id->lib->parent = NULL;
+ }
+ }
+
+ if (old_id->us > 0 && new_id && old_id->lib == new_id->lib) {
+ /* Note that this *should* not happen - but better be safe than sorry in this area,
+ * at least until we are 100% sure this cannot ever happen.
+ * Also, we can safely assume names were unique so far,
+ * so just replacing '.' by '~' should work,
+ * but this does not totally rules out the possibility of name collision. */
+ size_t len = strlen(old_id->name);
+ size_t dot_pos;
+ bool has_num = false;
+
+ for (dot_pos = len; dot_pos--;) {
+ char c = old_id->name[dot_pos];
+ if (c == '.') {
+ break;
+ }
+ if (c < '0' || c > '9') {
+ has_num = false;
+ break;
+ }
+ has_num = true;
+ }
+
+ if (has_num) {
+ old_id->name[dot_pos] = '~';
+ }
+ else {
+ len = MIN2(len, MAX_ID_NAME - 7);
+ BLI_strncpy(&old_id->name[len], "~000", 7);
+ }
+
+ id_sort_by_name(which_libbase(bmain, GS(old_id->name)), old_id, NULL);
+
+ BKE_reportf(
+ reports,
+ RPT_WARNING,
+ "Lib Reload: Replacing all references to old data-block '%s' by reloaded one failed, "
+ "old one (%d remaining users) had to be kept and was renamed to '%s'",
+ new_id->name,
+ old_id->us,
+ old_id->name);
+ }
+}
+
+void BKE_blendfile_library_relocate(BlendfileLinkAppendContext *lapp_context,
+ ReportList *reports,
+ Library *library,
+ const bool do_reload)
+{
+ ListBase *lbarray[INDEX_ID_MAX];
+ int lba_idx;
+
+ LinkNode *itemlink;
+ int item_idx;
+
+ Main *bmain = lapp_context->params->bmain;
+
+ /* All override rules need to be up to date, since there will be no do_version here, otherwise
+ * older, now-invalid rules might be applied and likely fail, or some changes might be missing,
+ * etc. See T93353. */
+ BKE_lib_override_library_main_operations_create(bmain, true);
+
+ /* Remove all IDs to be reloaded from Main. */
+ lba_idx = set_listbasepointers(bmain, lbarray);
+ while (lba_idx--) {
+ ID *id = lbarray[lba_idx]->first;
+ const short idcode = id ? GS(id->name) : 0;
+
+ if (!id || !BKE_idtype_idcode_is_linkable(idcode)) {
+ /* No need to reload non-linkable datatypes,
+ * those will get relinked with their 'users ID'. */
+ continue;
+ }
+
+ for (; id; id = id->next) {
+ if (id->lib == library) {
+ BlendfileLinkAppendContextItem *item;
+
+ /* We remove it from current Main, and add it to items to link... */
+ /* Note that non-linkable IDs (like e.g. shapekeys) are also explicitly linked here... */
+ BLI_remlink(lbarray[lba_idx], id);
+ /* Usual special code for ShapeKeys snowflakes... */
+ Key *old_key = BKE_key_from_id(id);
+ if (old_key != NULL) {
+ BLI_remlink(which_libbase(bmain, GS(old_key->id.name)), &old_key->id);
+ }
+
+ item = BKE_blendfile_link_append_context_item_add(lapp_context, id->name + 2, idcode, id);
+ BLI_bitmap_set_all(item->libraries, true, (size_t)lapp_context->num_libraries);
+
+ CLOG_INFO(&LOG, 4, "Datablock to seek for: %s", id->name);
+ }
+ }
+ }
+
+ if (lapp_context->num_items == 0) {
+ /* Early out in case there is nothing to do. */
+ return;
+ }
+
+ BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
+
+ /* We do not want any instantiation here! */
+ BKE_blendfile_link(lapp_context, reports);
+
+ BKE_main_lock(bmain);
+
+ /* We add back old id to bmain.
+ * We need to do this in a first, separated loop, otherwise some of those may not be handled by
+ * ID remapping, which means they would still reference old data to be deleted... */
+ for (item_idx = 0, itemlink = lapp_context->items.list; itemlink;
+ item_idx++, itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+ ID *old_id = item->userdata;
+
+ BLI_assert(old_id);
+ BLI_addtail(which_libbase(bmain, GS(old_id->name)), old_id);
+
+ /* Usual special code for ShapeKeys snowflakes... */
+ Key *old_key = BKE_key_from_id(old_id);
+ if (old_key != NULL) {
+ BLI_addtail(which_libbase(bmain, GS(old_key->id.name)), &old_key->id);
+ }
+ }
+
+ /* Since our (old) reloaded IDs were removed from main, the user count done for them in linking
+ * code is wrong, we need to redo it here after adding them back to main. */
+ BKE_main_id_refcount_recompute(bmain, false);
+
+ /* Note that in reload case, we also want to replace indirect usages. */
+ const short remap_flags = ID_REMAP_SKIP_NEVER_NULL_USAGE |
+ ID_REMAP_NO_INDIRECT_PROXY_DATA_USAGE |
+ (do_reload ? 0 : ID_REMAP_SKIP_INDIRECT_USAGE);
+ for (item_idx = 0, itemlink = lapp_context->items.list; itemlink;
+ item_idx++, itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+ ID *old_id = item->userdata;
+ ID *new_id = item->new_id;
+
+ blendfile_library_relocate_remap(bmain, old_id, new_id, reports, do_reload, remap_flags);
+ if (new_id == NULL) {
+ continue;
+ }
+ /* Usual special code for ShapeKeys snowflakes... */
+ Key **old_key_p = BKE_key_from_id_p(old_id);
+ if (old_key_p == NULL) {
+ continue;
+ }
+ Key *old_key = *old_key_p;
+ Key *new_key = BKE_key_from_id(new_id);
+ if (old_key != NULL) {
+ *old_key_p = NULL;
+ id_us_min(&old_key->id);
+ blendfile_library_relocate_remap(
+ bmain, &old_key->id, &new_key->id, reports, do_reload, remap_flags);
+ *old_key_p = old_key;
+ id_us_plus_no_lib(&old_key->id);
+ }
+ }
+
+ BKE_main_unlock(bmain);
+
+ for (item_idx = 0, itemlink = lapp_context->items.list; itemlink;
+ item_idx++, itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+ ID *old_id = item->userdata;
+
+ if (old_id->us == 0) {
+ BKE_id_free(bmain, old_id);
+ }
+ }
+
+ /* Some datablocks can get reloaded/replaced 'silently' because they are not linkable
+ * (shape keys e.g.), so we need another loop here to clear old ones if possible. */
+ lba_idx = set_listbasepointers(bmain, lbarray);
+ while (lba_idx--) {
+ ID *id, *id_next;
+ for (id = lbarray[lba_idx]->first; id; id = id_next) {
+ id_next = id->next;
+ /* XXX That check may be a bit to generic/permissive? */
+ if (id->lib && (id->flag & LIB_TAG_PRE_EXISTING) && id->us == 0) {
+ BKE_id_free(bmain, id);
+ }
+ }
+ }
+
+ /* Get rid of no more used libraries... */
+ BKE_main_id_tag_idcode(bmain, ID_LI, LIB_TAG_DOIT, true);
+ lba_idx = set_listbasepointers(bmain, lbarray);
+ while (lba_idx--) {
+ ID *id;
+ for (id = lbarray[lba_idx]->first; id; id = id->next) {
+ if (id->lib) {
+ id->lib->id.tag &= ~LIB_TAG_DOIT;
+ }
+ }
+ }
+ Library *lib, *lib_next;
+ for (lib = which_libbase(bmain, ID_LI)->first; lib; lib = lib_next) {
+ lib_next = lib->id.next;
+ if (lib->id.tag & LIB_TAG_DOIT) {
+ id_us_clear_real(&lib->id);
+ if (lib->id.us == 0) {
+ BKE_id_free(bmain, (ID *)lib);
+ }
+ }
+ }
+
+ /* Update overrides of reloaded linked data-blocks. */
+ ID *id;
+ FOREACH_MAIN_ID_BEGIN (bmain, id) {
+ if (ID_IS_LINKED(id) || !ID_IS_OVERRIDE_LIBRARY_REAL(id) ||
+ (id->tag & LIB_TAG_PRE_EXISTING) == 0) {
+ continue;
+ }
+ if ((id->override_library->reference->tag & LIB_TAG_PRE_EXISTING) == 0) {
+ BKE_lib_override_library_update(bmain, id);
+ }
+ }
+ FOREACH_MAIN_ID_END;
+
+ /* Resync overrides if needed. */
+ if (!USER_EXPERIMENTAL_TEST(&U, no_override_auto_resync)) {
+ BKE_lib_override_library_main_resync(bmain,
+ lapp_context->params->context.scene,
+ lapp_context->params->context.view_layer,
+ &(struct BlendFileReadReport){
+ .reports = reports,
+ });
+ /* We need to rebuild some of the deleted override rules (for UI feedback purpose). */
+ BKE_lib_override_library_main_operations_create(bmain, true);
+ }
+
+ BKE_main_collection_sync(bmain);
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/boids.c b/source/blender/blenkernel/intern/boids.c
index a7257133821..a9f26d00007 100644
--- a/source/blender/blenkernel/intern/boids.c
+++ b/source/blender/blenkernel/intern/boids.c
@@ -1061,7 +1061,6 @@ static int boid_condition_is_true(BoidCondition *cond)
}
#endif
-/* determines the velocity the boid wants to have */
void boid_brain(BoidBrainData *bbd, int p, ParticleData *pa)
{
BoidRule *rule;
@@ -1218,7 +1217,6 @@ void boid_brain(BoidBrainData *bbd, int p, ParticleData *pa)
}
}
}
-/* tries to realize the wanted velocity taking all constraints into account */
void boid_body(BoidBrainData *bbd, ParticleData *pa)
{
BoidSettings *boids = bbd->part->boids;
diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c
index 9ce58d8129b..85e49774dfd 100644
--- a/source/blender/blenkernel/intern/bpath.c
+++ b/source/blender/blenkernel/intern/bpath.c
@@ -66,6 +66,7 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BKE_idtype.h"
#include "BKE_image.h"
#include "BKE_lib_id.h"
#include "BKE_library.h"
@@ -87,213 +88,156 @@
static CLG_LogRef LOG = {"bke.bpath"};
/* -------------------------------------------------------------------- */
-/** \name Check Missing Files
+/** \name Generic File Path Traversal API
* \{ */
-static bool checkMissingFiles_visit_cb(void *userdata,
- char *UNUSED(path_dst),
- const char *path_src)
+void BKE_bpath_foreach_path_id(BPathForeachPathData *bpath_data, ID *id)
{
- ReportList *reports = (ReportList *)userdata;
+ const eBPathForeachFlag flag = bpath_data->flag;
+ const char *absbase = (flag & BKE_BPATH_FOREACH_PATH_ABSOLUTE) ?
+ ID_BLEND_PATH(bpath_data->bmain, id) :
+ NULL;
+ bpath_data->absolute_base_path = absbase;
- if (!BLI_exists(path_src)) {
- BKE_reportf(reports, RPT_WARNING, "Path '%s' not found", path_src);
+ if ((flag & BKE_BPATH_FOREACH_PATH_SKIP_LINKED) && ID_IS_LINKED(id)) {
+ return;
}
- return false;
-}
-
-/* high level function */
-void BKE_bpath_missing_files_check(Main *bmain, ReportList *reports)
-{
- BKE_bpath_traverse_main(bmain,
- checkMissingFiles_visit_cb,
- BKE_BPATH_TRAVERSE_ABS | BKE_BPATH_TRAVERSE_SKIP_PACKED,
- reports);
-}
+ if (id->library_weak_reference != NULL &&
+ (flag & BKE_BPATH_TRAVERSE_SKIP_WEAK_REFERENCES) == 0) {
+ BKE_bpath_foreach_path_fixed_process(bpath_data, id->library_weak_reference->library_filepath);
+ }
-/** \} */
+ bNodeTree *embedded_node_tree = ntreeFromID(id);
+ if (embedded_node_tree != NULL) {
+ BKE_bpath_foreach_path_id(bpath_data, &embedded_node_tree->id);
+ }
-/* -------------------------------------------------------------------- */
-/** \name Rebase Relative Paths
- * \{ */
+ const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id);
-typedef struct BPathRebase_Data {
- const char *basedir_src;
- const char *basedir_dst;
- ReportList *reports;
+ BLI_assert(id_type != NULL);
+ if (id_type == NULL || id_type->foreach_path == NULL) {
+ return;
+ }
- int count_tot;
- int count_changed;
- int count_failed;
-} BPathRebase_Data;
+ id_type->foreach_path(id, bpath_data);
+}
-static bool bpath_relative_rebase_visit_cb(void *userdata, char *path_dst, const char *path_src)
+void BKE_bpath_foreach_path_main(BPathForeachPathData *bpath_data)
{
- BPathRebase_Data *data = (BPathRebase_Data *)userdata;
+ ID *id;
+ FOREACH_MAIN_ID_BEGIN (bpath_data->bmain, id) {
+ BKE_bpath_foreach_path_id(bpath_data, id);
+ }
+ FOREACH_MAIN_ID_END;
+}
- data->count_tot++;
+bool BKE_bpath_foreach_path_fixed_process(BPathForeachPathData *bpath_data, char *path)
+{
+ const char *absolute_base_path = bpath_data->absolute_base_path;
- if (BLI_path_is_rel(path_src)) {
- char filepath[(FILE_MAXDIR * 2) + FILE_MAXFILE];
- BLI_strncpy(filepath, path_src, FILE_MAX);
- if (BLI_path_abs(filepath, data->basedir_src)) {
- BLI_path_normalize(NULL, filepath);
+ char path_src_buf[FILE_MAX];
+ const char *path_src;
+ char path_dst[FILE_MAX];
- /* This may fail, if so it's fine to leave absolute since the path is still valid. */
- BLI_path_rel(filepath, data->basedir_dst);
+ if (absolute_base_path) {
+ BLI_strncpy(path_src_buf, path, sizeof(path_src_buf));
+ BLI_path_abs(path_src_buf, absolute_base_path);
+ path_src = path_src_buf;
+ }
+ else {
+ path_src = path;
+ }
- BLI_strncpy(path_dst, filepath, FILE_MAX);
- data->count_changed++;
- return true;
- }
+ /* so functions can check old value */
+ BLI_strncpy(path_dst, path, FILE_MAX);
- /* Failed to make relative path absolute. */
- BLI_assert(0);
- BKE_reportf(data->reports, RPT_WARNING, "Path '%s' cannot be made absolute", path_src);
- data->count_failed++;
- return false;
+ if (bpath_data->callback_function(bpath_data, path_dst, path_src)) {
+ BLI_strncpy(path, path_dst, FILE_MAX);
+ return true;
}
- /* Absolute, leave this as-is. */
return false;
}
-void BKE_bpath_relative_rebase(Main *bmain,
- const char *basedir_src,
- const char *basedir_dst,
- ReportList *reports)
+bool BKE_bpath_foreach_path_dirfile_fixed_process(BPathForeachPathData *bpath_data,
+ char *path_dir,
+ char *path_file)
{
- BPathRebase_Data data = {NULL};
- const int flag = (BKE_BPATH_TRAVERSE_SKIP_LIBRARY | BKE_BPATH_TRAVERSE_SKIP_MULTIFILE);
-
- BLI_assert(basedir_src[0] != '\0');
- BLI_assert(basedir_dst[0] != '\0');
+ const char *absolute_base_path = bpath_data->absolute_base_path;
- data.basedir_src = basedir_src;
- data.basedir_dst = basedir_dst;
- data.reports = reports;
-
- BKE_bpath_traverse_main(bmain, bpath_relative_rebase_visit_cb, flag, (void *)&data);
+ char path_src[FILE_MAX];
+ char path_dst[FILE_MAX];
- BKE_reportf(reports,
- data.count_failed ? RPT_WARNING : RPT_INFO,
- "Total files %d | Changed %d | Failed %d",
- data.count_tot,
- data.count_changed,
- data.count_failed);
-}
+ BLI_join_dirfile(path_src, sizeof(path_src), path_dir, path_file);
-/** \} */
+ /* So that functions can access the old value. */
+ BLI_strncpy(path_dst, path_src, FILE_MAX);
-/* -------------------------------------------------------------------- */
-/** \name Make Paths Relative
- * \{ */
+ if (absolute_base_path) {
+ BLI_path_abs(path_src, absolute_base_path);
+ }
-typedef struct BPathRemap_Data {
- const char *basedir;
- ReportList *reports;
+ if (bpath_data->callback_function(bpath_data, path_dst, (const char *)path_src)) {
+ BLI_split_dirfile(path_dst, path_dir, path_file, FILE_MAXDIR, FILE_MAXFILE);
+ return true;
+ }
- int count_tot;
- int count_changed;
- int count_failed;
-} BPathRemap_Data;
+ return false;
+}
-static bool bpath_relative_convert_visit_cb(void *userdata, char *path_dst, const char *path_src)
+bool BKE_bpath_foreach_path_allocated_process(BPathForeachPathData *bpath_data, char **path)
{
- BPathRemap_Data *data = (BPathRemap_Data *)userdata;
+ const char *absolute_base_path = bpath_data->absolute_base_path;
- data->count_tot++;
-
- if (BLI_path_is_rel(path_src)) {
- return false; /* already relative */
- }
+ char path_src_buf[FILE_MAX];
+ const char *path_src;
+ char path_dst[FILE_MAX];
- strcpy(path_dst, path_src);
- BLI_path_rel(path_dst, data->basedir);
- if (BLI_path_is_rel(path_dst)) {
- data->count_changed++;
+ if (absolute_base_path) {
+ BLI_strncpy(path_src_buf, *path, sizeof(path_src_buf));
+ BLI_path_abs(path_src_buf, absolute_base_path);
+ path_src = path_src_buf;
}
else {
- BKE_reportf(data->reports, RPT_WARNING, "Path '%s' cannot be made relative", path_src);
- data->count_failed++;
+ path_src = *path;
}
- return true;
-}
-
-void BKE_bpath_relative_convert(Main *bmain, const char *basedir, ReportList *reports)
-{
- BPathRemap_Data data = {NULL};
- const int flag = BKE_BPATH_TRAVERSE_SKIP_LIBRARY;
- if (basedir[0] == '\0') {
- CLOG_ERROR(&LOG, "basedir='', this is a bug");
- return;
+ if (bpath_data->callback_function(bpath_data, path_dst, path_src)) {
+ MEM_freeN(*path);
+ (*path) = BLI_strdup(path_dst);
+ return true;
}
- data.basedir = basedir;
- data.reports = reports;
-
- BKE_bpath_traverse_main(bmain, bpath_relative_convert_visit_cb, flag, (void *)&data);
-
- BKE_reportf(reports,
- data.count_failed ? RPT_WARNING : RPT_INFO,
- "Total files %d | Changed %d | Failed %d",
- data.count_tot,
- data.count_changed,
- data.count_failed);
+ return false;
}
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Make Paths Absolute
+/** \name Check Missing Files
* \{ */
-static bool bpath_absolute_convert_visit_cb(void *userdata, char *path_dst, const char *path_src)
+static bool check_missing_files_foreach_path_cb(BPathForeachPathData *bpath_data,
+ char *UNUSED(path_dst),
+ const char *path_src)
{
- BPathRemap_Data *data = (BPathRemap_Data *)userdata;
-
- data->count_tot++;
+ ReportList *reports = (ReportList *)bpath_data->user_data;
- if (BLI_path_is_rel(path_src) == false) {
- return false; /* already absolute */
+ if (!BLI_exists(path_src)) {
+ BKE_reportf(reports, RPT_WARNING, "Path '%s' not found", path_src);
}
- strcpy(path_dst, path_src);
- BLI_path_abs(path_dst, data->basedir);
- if (BLI_path_is_rel(path_dst) == false) {
- data->count_changed++;
- }
- else {
- BKE_reportf(data->reports, RPT_WARNING, "Path '%s' cannot be made absolute", path_src);
- data->count_failed++;
- }
- return true;
+ return false;
}
-/* similar to BKE_bpath_relative_convert - keep in sync! */
-void BKE_bpath_absolute_convert(Main *bmain, const char *basedir, ReportList *reports)
+void BKE_bpath_missing_files_check(Main *bmain, ReportList *reports)
{
- BPathRemap_Data data = {NULL};
- const int flag = BKE_BPATH_TRAVERSE_SKIP_LIBRARY;
-
- if (basedir[0] == '\0') {
- CLOG_ERROR(&LOG, "basedir='', this is a bug");
- return;
- }
-
- data.basedir = basedir;
- data.reports = reports;
-
- BKE_bpath_traverse_main(bmain, bpath_absolute_convert_visit_cb, flag, (void *)&data);
-
- BKE_reportf(reports,
- data.count_failed ? RPT_WARNING : RPT_INFO,
- "Total files %d | Changed %d | Failed %d",
- data.count_tot,
- data.count_changed,
- data.count_failed);
+ BKE_bpath_foreach_path_main(&(BPathForeachPathData){
+ .bmain = bmain,
+ .callback_function = check_missing_files_foreach_path_cb,
+ .flag = BKE_BPATH_FOREACH_PATH_ABSOLUTE | BKE_BPATH_FOREACH_PATH_SKIP_PACKED,
+ .user_data = reports});
}
/** \} */
@@ -302,72 +246,79 @@ void BKE_bpath_absolute_convert(Main *bmain, const char *basedir, ReportList *re
/** \name Find Missing Files
* \{ */
-/**
- * find this file recursively, use the biggest file so thumbnails don't get used by mistake
- * \param filename_new: the path will be copied here, caller must initialize as empty string.
- * \param dirname: subdir to search
- * \param filename: set this filename
- * \param filesize: filesize for the file
+#define MAX_DIR_RECURSE 16
+#define FILESIZE_INVALID_DIRECTORY -1
+
+/** Find the given filename recursively in the given search directory and its sub-directories.
+ *
+ * \note Use the biggest matching file found, so that thumbnails don't get used by mistake.
+ *
+ * \param search_directory: Directory to search in.
+ * \param filename_src: Search for this filename.
+ * \param r_filename_new: The path of the new found file will be copied here, caller must
+ * initialize as empty string.
+ * \param r_filesize: Size of the file, `FILESIZE_INVALID_DIRECTORY` if search directory could not
+ * be opened.
+ * \param r_recurse_depth: Current recursion depth.
*
- * \returns found: 1/0.
+ * \return true if found, false otherwise.
*/
-#define MAX_RECUR 16
-static bool missing_files_find__recursive(char *filename_new,
- const char *dirname,
- const char *filename,
+static bool missing_files_find__recursive(const char *search_directory,
+ const char *filename_src,
+ char r_filename_new[FILE_MAX],
int64_t *r_filesize,
- int *r_recur_depth)
+ int *r_recurse_depth)
{
- /* file searching stuff */
+ /* TODO: Move this function to BLI_path_utils? The 'biggest size' behavior is quite specific
+ * though... */
DIR *dir;
- struct dirent *de;
BLI_stat_t status;
char path[FILE_MAX];
int64_t size;
bool found = false;
- dir = opendir(dirname);
+ dir = opendir(search_directory);
if (dir == NULL) {
return found;
}
- if (*r_filesize == -1) {
- *r_filesize = 0; /* dir opened fine */
+ if (*r_filesize == FILESIZE_INVALID_DIRECTORY) {
+ *r_filesize = 0; /* The directory opened fine. */
}
- while ((de = readdir(dir)) != NULL) {
-
+ for (struct dirent *de = readdir(dir); de != NULL; de = readdir(dir)) {
if (FILENAME_IS_CURRPAR(de->d_name)) {
continue;
}
- BLI_join_dirfile(path, sizeof(path), dirname, de->d_name);
+ BLI_join_dirfile(path, sizeof(path), search_directory, de->d_name);
if (BLI_stat(path, &status) == -1) {
- continue; /* can't stat, don't bother with this file, could print debug info here */
+ CLOG_WARN(&LOG, "Cannot get file status (`stat()`) of '%s'", path);
+ continue;
}
- if (S_ISREG(status.st_mode)) { /* is file */
- if (BLI_path_ncmp(filename, de->d_name, FILE_MAX) == 0) { /* name matches */
- /* open the file to read its size */
+ if (S_ISREG(status.st_mode)) { /* It is a file. */
+ if (BLI_path_ncmp(filename_src, de->d_name, FILE_MAX) == 0) { /* Names match. */
size = status.st_size;
- if ((size > 0) && (size > *r_filesize)) { /* find the biggest file */
+ if ((size > 0) && (size > *r_filesize)) { /* Find the biggest matching file. */
*r_filesize = size;
- BLI_strncpy(filename_new, path, FILE_MAX);
+ BLI_strncpy(r_filename_new, path, FILE_MAX);
found = true;
}
}
}
- else if (S_ISDIR(status.st_mode)) { /* is subdir */
- if (*r_recur_depth <= MAX_RECUR) {
- (*r_recur_depth)++;
+ else if (S_ISDIR(status.st_mode)) { /* It is a sub-directory. */
+ if (*r_recurse_depth <= MAX_DIR_RECURSE) {
+ (*r_recurse_depth)++;
found |= missing_files_find__recursive(
- filename_new, path, filename, r_filesize, r_recur_depth);
- (*r_recur_depth)--;
+ path, filename_src, r_filename_new, r_filesize, r_recurse_depth);
+ (*r_recurse_depth)--;
}
}
}
+
closedir(dir);
return found;
}
@@ -376,37 +327,37 @@ typedef struct BPathFind_Data {
const char *basedir;
const char *searchdir;
ReportList *reports;
- bool find_all;
+ bool find_all; /* Also search for files which current path is still valid. */
} BPathFind_Data;
-static bool missing_files_find__visit_cb(void *userdata, char *path_dst, const char *path_src)
+static bool missing_files_find_foreach_path_cb(BPathForeachPathData *bpath_data,
+ char *path_dst,
+ const char *path_src)
{
- BPathFind_Data *data = (BPathFind_Data *)userdata;
+ BPathFind_Data *data = (BPathFind_Data *)bpath_data->user_data;
char filename_new[FILE_MAX];
- int64_t filesize = -1;
- int recur_depth = 0;
- bool found;
+ int64_t filesize = FILESIZE_INVALID_DIRECTORY;
+ int recurse_depth = 0;
+ bool is_found;
- if (data->find_all == false) {
- if (BLI_exists(path_src)) {
- return false;
- }
+ if (!data->find_all && BLI_exists(path_src)) {
+ return false;
}
filename_new[0] = '\0';
- found = missing_files_find__recursive(
- filename_new, data->searchdir, BLI_path_basename(path_src), &filesize, &recur_depth);
+ is_found = missing_files_find__recursive(
+ data->searchdir, BLI_path_basename(path_src), filename_new, &filesize, &recurse_depth);
- if (filesize == -1) { /* could not open dir */
+ if (filesize == FILESIZE_INVALID_DIRECTORY) {
BKE_reportf(data->reports,
RPT_WARNING,
- "Could not open directory '%s'",
+ "Could not open the directory '%s'",
BLI_path_basename(data->searchdir));
return false;
}
- if (found == false) {
+ if (is_found == false) {
BKE_reportf(data->reports,
RPT_WARNING,
"Could not find '%s' in '%s'",
@@ -419,7 +370,7 @@ static bool missing_files_find__visit_cb(void *userdata, char *path_dst, const c
BLI_strncpy(path_dst, filename_new, FILE_MAX);
- /* keep path relative if the previous one was relative */
+ /* Keep the path relative if the previous one was relative. */
if (was_relative) {
BLI_path_rel(path_dst, data->basedir);
}
@@ -433,480 +384,281 @@ void BKE_bpath_missing_files_find(Main *bmain,
const bool find_all)
{
struct BPathFind_Data data = {NULL};
- const int flag = BKE_BPATH_TRAVERSE_ABS | BKE_BPATH_TRAVERSE_RELOAD_EDITED;
+ const int flag = BKE_BPATH_FOREACH_PATH_ABSOLUTE | BKE_BPATH_FOREACH_PATH_RELOAD_EDITED;
data.basedir = BKE_main_blendfile_path(bmain);
data.reports = reports;
data.searchdir = searchpath;
data.find_all = find_all;
- BKE_bpath_traverse_main(bmain, missing_files_find__visit_cb, flag, (void *)&data);
+ BKE_bpath_foreach_path_main(
+ &(BPathForeachPathData){.bmain = bmain,
+ .callback_function = missing_files_find_foreach_path_cb,
+ .flag = flag,
+ .user_data = &data});
}
+#undef MAX_DIR_RECURSE
+#undef FILESIZE_INVALID_DIRECTORY
+
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Generic File Path Traversal API
+/** \name Rebase Relative Paths
* \{ */
-/**
- * Run a visitor on a string, replacing the contents of the string as needed.
- */
-static bool rewrite_path_fixed(char *path,
- BPathVisitor visit_cb,
- const char *absbase,
- void *userdata)
+typedef struct BPathRebase_Data {
+ const char *basedir_src;
+ const char *basedir_dst;
+ ReportList *reports;
+
+ int count_tot;
+ int count_changed;
+ int count_failed;
+} BPathRebase_Data;
+
+static bool relative_rebase_foreach_path_cb(BPathForeachPathData *bpath_data,
+ char *path_dst,
+ const char *path_src)
{
- char path_src_buf[FILE_MAX];
- const char *path_src;
- char path_dst[FILE_MAX];
+ BPathRebase_Data *data = (BPathRebase_Data *)bpath_data->user_data;
- if (absbase) {
- BLI_strncpy(path_src_buf, path, sizeof(path_src_buf));
- BLI_path_abs(path_src_buf, absbase);
- path_src = path_src_buf;
+ data->count_tot++;
+
+ if (!BLI_path_is_rel(path_src)) {
+ /* Absolute, leave this as-is. */
+ return false;
}
- else {
- path_src = path;
+
+ char filepath[(FILE_MAXDIR * 2) + FILE_MAXFILE];
+ BLI_strncpy(filepath, path_src, FILE_MAX);
+ if (!BLI_path_abs(filepath, data->basedir_src)) {
+ BKE_reportf(data->reports, RPT_WARNING, "Path '%s' cannot be made absolute", path_src);
+ data->count_failed++;
+ return false;
}
- /* so functions can check old value */
- BLI_strncpy(path_dst, path, FILE_MAX);
+ BLI_path_normalize(NULL, filepath);
- if (visit_cb(userdata, path_dst, path_src)) {
- BLI_strncpy(path, path_dst, FILE_MAX);
- return true;
- }
+ /* This may fail, if so it's fine to leave absolute since the path is still valid. */
+ BLI_path_rel(filepath, data->basedir_dst);
- return false;
+ BLI_strncpy(path_dst, filepath, FILE_MAX);
+ data->count_changed++;
+ return true;
}
-static bool rewrite_path_fixed_dirfile(char path_dir[FILE_MAXDIR],
- char path_file[FILE_MAXFILE],
- BPathVisitor visit_cb,
- const char *absbase,
- void *userdata)
+void BKE_bpath_relative_rebase(Main *bmain,
+ const char *basedir_src,
+ const char *basedir_dst,
+ ReportList *reports)
{
- char path_src[FILE_MAX];
- char path_dst[FILE_MAX];
-
- BLI_join_dirfile(path_src, sizeof(path_src), path_dir, path_file);
+ BPathRebase_Data data = {NULL};
+ const int flag = (BKE_BPATH_FOREACH_PATH_SKIP_LINKED | BKE_BPATH_FOREACH_PATH_SKIP_MULTIFILE);
- /* so functions can check old value */
- BLI_strncpy(path_dst, path_src, FILE_MAX);
+ BLI_assert(basedir_src[0] != '\0');
+ BLI_assert(basedir_dst[0] != '\0');
- if (absbase) {
- BLI_path_abs(path_src, absbase);
- }
+ data.basedir_src = basedir_src;
+ data.basedir_dst = basedir_dst;
+ data.reports = reports;
- if (visit_cb(userdata, path_dst, (const char *)path_src)) {
- BLI_split_dirfile(path_dst, path_dir, path_file, FILE_MAXDIR, FILE_MAXFILE);
- return true;
- }
+ BKE_bpath_foreach_path_main(
+ &(BPathForeachPathData){.bmain = bmain,
+ .callback_function = relative_rebase_foreach_path_cb,
+ .flag = flag,
+ .user_data = &data});
- return false;
+ BKE_reportf(reports,
+ data.count_failed ? RPT_WARNING : RPT_INFO,
+ "Total files %d | Changed %d | Failed %d",
+ data.count_tot,
+ data.count_changed,
+ data.count_failed);
}
-static bool rewrite_path_alloc(char **path,
- BPathVisitor visit_cb,
- const char *absbase,
- void *userdata)
-{
- char path_src_buf[FILE_MAX];
- const char *path_src;
- char path_dst[FILE_MAX];
-
- if (absbase) {
- BLI_strncpy(path_src_buf, *path, sizeof(path_src_buf));
- BLI_path_abs(path_src_buf, absbase);
- path_src = path_src_buf;
- }
- else {
- path_src = *path;
- }
+/** \} */
- if (visit_cb(userdata, path_dst, path_src)) {
- MEM_freeN(*path);
- (*path) = BLI_strdup(path_dst);
- return true;
- }
+/* -------------------------------------------------------------------- */
+/** \name Make Paths Relative Or Absolute
+ * \{ */
- return false;
-}
+typedef struct BPathRemap_Data {
+ const char *basedir;
+ ReportList *reports;
-typedef struct Seq_callback_data {
- const char *absbase;
- void *bpath_user_data;
- BPathVisitor visit_cb;
- const int flag;
-} Seq_callback_data;
+ int count_tot;
+ int count_changed;
+ int count_failed;
+} BPathRemap_Data;
-static bool seq_rewrite_path_callback(Sequence *seq, void *user_data)
+static bool relative_convert_foreach_path_cb(BPathForeachPathData *bpath_data,
+ char *path_dst,
+ const char *path_src)
{
- if (SEQ_HAS_PATH(seq)) {
- StripElem *se = seq->strip->stripdata;
- Seq_callback_data *cd = (Seq_callback_data *)user_data;
+ BPathRemap_Data *data = (BPathRemap_Data *)bpath_data->user_data;
- if (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_SOUND_RAM) && se) {
- rewrite_path_fixed_dirfile(
- seq->strip->dir, se->name, cd->visit_cb, cd->absbase, cd->bpath_user_data);
- }
- else if ((seq->type == SEQ_TYPE_IMAGE) && se) {
- /* might want an option not to loop over all strips */
- unsigned int len = (unsigned int)MEM_allocN_len(se) / (unsigned int)sizeof(*se);
- unsigned int i;
-
- if (cd->flag & BKE_BPATH_TRAVERSE_SKIP_MULTIFILE) {
- /* only operate on one path */
- len = MIN2(1u, len);
- }
+ data->count_tot++;
- for (i = 0; i < len; i++, se++) {
- rewrite_path_fixed_dirfile(
- seq->strip->dir, se->name, cd->visit_cb, cd->absbase, cd->bpath_user_data);
- }
- }
- else {
- /* simple case */
- rewrite_path_fixed(seq->strip->dir, cd->visit_cb, cd->absbase, cd->bpath_user_data);
- }
+ if (BLI_path_is_rel(path_src)) {
+ return false; /* Already relative. */
+ }
+
+ BLI_strncpy(path_dst, path_src, FILE_MAX);
+ BLI_path_rel(path_dst, data->basedir);
+ if (BLI_path_is_rel(path_dst)) {
+ data->count_changed++;
+ }
+ else {
+ BKE_reportf(data->reports, RPT_WARNING, "Path '%s' cannot be made relative", path_src);
+ data->count_failed++;
}
return true;
}
-/**
- * Run visitor function 'visit' on all paths contained in 'id'.
- */
-void BKE_bpath_traverse_id(
- Main *bmain, ID *id, BPathVisitor visit_cb, const int flag, void *bpath_user_data)
+static bool absolute_convert_foreach_path_cb(BPathForeachPathData *bpath_data,
+ char *path_dst,
+ const char *path_src)
{
- const char *absbase = (flag & BKE_BPATH_TRAVERSE_ABS) ? ID_BLEND_PATH(bmain, id) : NULL;
+ BPathRemap_Data *data = (BPathRemap_Data *)bpath_data->user_data;
- if ((flag & BKE_BPATH_TRAVERSE_SKIP_LIBRARY) && ID_IS_LINKED(id)) {
- return;
- }
+ data->count_tot++;
- if (id->library_weak_reference != NULL) {
- rewrite_path_fixed(
- id->library_weak_reference->library_filepath, visit_cb, absbase, bpath_user_data);
+ if (!BLI_path_is_rel(path_src)) {
+ return false; /* Already absolute. */
}
- switch (GS(id->name)) {
- case ID_IM: {
- Image *ima;
- ima = (Image *)id;
- if (BKE_image_has_packedfile(ima) == false || (flag & BKE_BPATH_TRAVERSE_SKIP_PACKED) == 0) {
- /* Skip empty file paths, these are typically from generated images and
- * don't make sense to add directories to until the image has been saved
- * once to give it a meaningful value. */
- if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE, IMA_SRC_TILED) &&
- ima->filepath[0]) {
- if (rewrite_path_fixed(ima->filepath, visit_cb, absbase, bpath_user_data)) {
- if (flag & BKE_BPATH_TRAVERSE_RELOAD_EDITED) {
- if (!BKE_image_has_packedfile(ima) &&
- /* image may have been painted onto (and not saved, T44543) */
- !BKE_image_is_dirty(ima)) {
- BKE_image_signal(bmain, ima, NULL, IMA_SIGNAL_RELOAD);
- }
- }
- }
- }
- }
- break;
- }
- case ID_BR: {
- Brush *brush = (Brush *)id;
- if (brush->icon_filepath[0]) {
- rewrite_path_fixed(brush->icon_filepath, visit_cb, absbase, bpath_user_data);
- }
- break;
- }
- case ID_OB: {
- Object *ob = (Object *)id;
- ModifierData *md;
- ParticleSystem *psys;
-
-#define BPATH_TRAVERSE_POINTCACHE(ptcaches) \
- { \
- PointCache *cache; \
- for (cache = (ptcaches).first; cache; cache = cache->next) { \
- if (cache->flag & PTCACHE_DISK_CACHE) { \
- rewrite_path_fixed(cache->path, visit_cb, absbase, bpath_user_data); \
- } \
- } \
- } \
- (void)0
-
- for (md = ob->modifiers.first; md; md = md->next) {
- if (md->type == eModifierType_Fluidsim) {
- FluidsimModifierData *fluidmd = (FluidsimModifierData *)md;
- if (fluidmd->fss) {
- rewrite_path_fixed(fluidmd->fss->surfdataPath, visit_cb, absbase, bpath_user_data);
- }
- }
- else if (md->type == eModifierType_Fluid) {
- FluidModifierData *fmd = (FluidModifierData *)md;
- if (fmd->type & MOD_FLUID_TYPE_DOMAIN && fmd->domain) {
- rewrite_path_fixed(fmd->domain->cache_directory, visit_cb, absbase, bpath_user_data);
- }
- }
- else if (md->type == eModifierType_Cloth) {
- ClothModifierData *clmd = (ClothModifierData *)md;
- BPATH_TRAVERSE_POINTCACHE(clmd->ptcaches);
- }
- else if (md->type == eModifierType_Ocean) {
- OceanModifierData *omd = (OceanModifierData *)md;
- rewrite_path_fixed(omd->cachepath, visit_cb, absbase, bpath_user_data);
- }
- else if (md->type == eModifierType_MeshCache) {
- MeshCacheModifierData *mcmd = (MeshCacheModifierData *)md;
- rewrite_path_fixed(mcmd->filepath, visit_cb, absbase, bpath_user_data);
- }
- }
-
- if (ob->soft) {
- BPATH_TRAVERSE_POINTCACHE(ob->soft->shared->ptcaches);
- }
-
- for (psys = ob->particlesystem.first; psys; psys = psys->next) {
- BPATH_TRAVERSE_POINTCACHE(psys->ptcaches);
- }
-
-#undef BPATH_TRAVERSE_POINTCACHE
-
- break;
- }
- case ID_SO: {
- bSound *sound = (bSound *)id;
- if (sound->packedfile == NULL || (flag & BKE_BPATH_TRAVERSE_SKIP_PACKED) == 0) {
- rewrite_path_fixed(sound->filepath, visit_cb, absbase, bpath_user_data);
- }
- break;
- }
- case ID_VO: {
- Volume *volume = (Volume *)id;
- if (volume->packedfile == NULL || (flag & BKE_BPATH_TRAVERSE_SKIP_PACKED) == 0) {
- rewrite_path_fixed(volume->filepath, visit_cb, absbase, bpath_user_data);
- }
- break;
- }
- case ID_TXT:
- if (((Text *)id)->filepath) {
- rewrite_path_alloc(&((Text *)id)->filepath, visit_cb, absbase, bpath_user_data);
- }
- break;
- case ID_VF: {
- VFont *vfont = (VFont *)id;
- if (vfont->packedfile == NULL || (flag & BKE_BPATH_TRAVERSE_SKIP_PACKED) == 0) {
- if (BKE_vfont_is_builtin(vfont) == false) {
- rewrite_path_fixed(((VFont *)id)->filepath, visit_cb, absbase, bpath_user_data);
- }
- }
- break;
- }
- case ID_MA: {
- Material *ma = (Material *)id;
- bNodeTree *ntree = ma->nodetree;
-
- if (ntree) {
- bNode *node;
-
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->type == SH_NODE_SCRIPT) {
- NodeShaderScript *nss = (NodeShaderScript *)node->storage;
- rewrite_path_fixed(nss->filepath, visit_cb, absbase, bpath_user_data);
- }
- else if (node->type == SH_NODE_TEX_IES) {
- NodeShaderTexIES *ies = (NodeShaderTexIES *)node->storage;
- rewrite_path_fixed(ies->filepath, visit_cb, absbase, bpath_user_data);
- }
- }
- }
- break;
- }
- case ID_NT: {
- bNodeTree *ntree = (bNodeTree *)id;
- bNode *node;
-
- if (ntree->type == NTREE_SHADER) {
- /* same as lines above */
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->type == SH_NODE_SCRIPT) {
- NodeShaderScript *nss = (NodeShaderScript *)node->storage;
- rewrite_path_fixed(nss->filepath, visit_cb, absbase, bpath_user_data);
- }
- else if (node->type == SH_NODE_TEX_IES) {
- NodeShaderTexIES *ies = (NodeShaderTexIES *)node->storage;
- rewrite_path_fixed(ies->filepath, visit_cb, absbase, bpath_user_data);
- }
- }
- }
- break;
- }
- case ID_SCE: {
- Scene *scene = (Scene *)id;
- if (scene->ed) {
- Seq_callback_data user_data = {absbase, bpath_user_data, visit_cb, flag};
- SEQ_for_each_callback(&scene->ed->seqbase, seq_rewrite_path_callback, &user_data);
- }
- break;
- }
- case ID_ME: {
- Mesh *me = (Mesh *)id;
- if (me->ldata.external) {
- rewrite_path_fixed(me->ldata.external->filename, visit_cb, absbase, bpath_user_data);
- }
- break;
- }
- case ID_LI: {
- Library *lib = (Library *)id;
- /* keep packedfile paths always relative to the blend */
- if (lib->packedfile == NULL) {
- if (rewrite_path_fixed(lib->filepath, visit_cb, absbase, bpath_user_data)) {
- BKE_library_filepath_set(bmain, lib, lib->filepath);
- }
- }
- break;
- }
- case ID_MC: {
- MovieClip *clip = (MovieClip *)id;
- rewrite_path_fixed(clip->filepath, visit_cb, absbase, bpath_user_data);
- break;
- }
- case ID_CF: {
- CacheFile *cache_file = (CacheFile *)id;
- rewrite_path_fixed(cache_file->filepath, visit_cb, absbase, bpath_user_data);
- break;
- }
- default:
- /* Nothing to do for other IDs that don't contain file paths. */
- break;
+ BLI_strncpy(path_dst, path_src, FILENAME_MAX);
+ BLI_path_abs(path_dst, data->basedir);
+ if (BLI_path_is_rel(path_dst) == false) {
+ data->count_changed++;
+ }
+ else {
+ BKE_reportf(data->reports, RPT_WARNING, "Path '%s' cannot be made absolute", path_src);
+ data->count_failed++;
}
+ return true;
}
-void BKE_bpath_traverse_id_list(
- Main *bmain, ListBase *lb, BPathVisitor visit_cb, const int flag, void *bpath_user_data)
+static void bpath_absolute_relative_convert(Main *bmain,
+ const char *basedir,
+ ReportList *reports,
+ BPathForeachPathFunctionCallback callback_function)
{
- ID *id;
- for (id = lb->first; id; id = id->next) {
- BKE_bpath_traverse_id(bmain, id, visit_cb, flag, bpath_user_data);
+ BPathRemap_Data data = {NULL};
+ const int flag = BKE_BPATH_FOREACH_PATH_SKIP_LINKED;
+
+ BLI_assert(basedir[0] != '\0');
+ if (basedir[0] == '\0') {
+ CLOG_ERROR(&LOG, "basedir='', this is a bug");
+ return;
}
+
+ data.basedir = basedir;
+ data.reports = reports;
+
+ BKE_bpath_foreach_path_main(&(BPathForeachPathData){
+ .bmain = bmain, .callback_function = callback_function, .flag = flag, .user_data = &data});
+
+ BKE_reportf(reports,
+ data.count_failed ? RPT_WARNING : RPT_INFO,
+ "Total files %d | Changed %d | Failed %d",
+ data.count_tot,
+ data.count_changed,
+ data.count_failed);
}
-void BKE_bpath_traverse_main(Main *bmain,
- BPathVisitor visit_cb,
- const int flag,
- void *bpath_user_data)
+void BKE_bpath_relative_convert(Main *bmain, const char *basedir, ReportList *reports)
{
- ListBase *lbarray[INDEX_ID_MAX];
- int a = set_listbasepointers(bmain, lbarray);
- while (a--) {
- BKE_bpath_traverse_id_list(bmain, lbarray[a], visit_cb, flag, bpath_user_data);
- }
+ bpath_absolute_relative_convert(bmain, basedir, reports, relative_convert_foreach_path_cb);
}
-/**
- * Rewrites a relative path to be relative to the main file - unless the path is
- * absolute, in which case it is not altered.
- */
-bool BKE_bpath_relocate_visitor(void *pathbase_v, char *path_dst, const char *path_src)
+void BKE_bpath_absolute_convert(Main *bmain, const char *basedir, ReportList *reports)
{
- /* be sure there is low chance of the path being too short */
- char filepath[(FILE_MAXDIR * 2) + FILE_MAXFILE];
- const char *base_new = ((char **)pathbase_v)[0];
- const char *base_old = ((char **)pathbase_v)[1];
-
- if (BLI_path_is_rel(base_old)) {
- CLOG_ERROR(&LOG, "old base path '%s' is not absolute.", base_old);
- return false;
- }
-
- /* Make referenced file absolute. This would be a side-effect of
- * BLI_path_normalize, but we do it explicitly so we know if it changed. */
- BLI_strncpy(filepath, path_src, FILE_MAX);
- if (BLI_path_abs(filepath, base_old)) {
- /* Path was relative and is now absolute. Remap.
- * Important BLI_path_normalize runs before the path is made relative
- * because it won't work for paths that start with "//../" */
- BLI_path_normalize(base_new, filepath);
- BLI_path_rel(filepath, base_new);
- BLI_strncpy(path_dst, filepath, FILE_MAX);
- return true;
- }
-
- /* Path was not relative to begin with. */
- return false;
+ bpath_absolute_relative_convert(bmain, basedir, reports, absolute_convert_foreach_path_cb);
}
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Backup/Restore/Free functions,
+/** \name Backup/Restore/Free paths list functions.
*
- * \note These functions assume the data won't change order.
* \{ */
struct PathStore {
struct PathStore *next, *prev;
};
-static bool bpath_list_append(void *userdata, char *UNUSED(path_dst), const char *path_src)
+static bool bpath_list_append(BPathForeachPathData *bpath_data,
+ char *UNUSED(path_dst),
+ const char *path_src)
{
- /* store the path and string in a single alloc */
- ListBase *ls = userdata;
+ ListBase *path_list = bpath_data->user_data;
size_t path_size = strlen(path_src) + 1;
+
+ /* NOTE: the PathStore and its string are allocated together in a single alloc. */
struct PathStore *path_store = MEM_mallocN(sizeof(struct PathStore) + path_size, __func__);
char *filepath = (char *)(path_store + 1);
- memcpy(filepath, path_src, path_size);
- BLI_addtail(ls, path_store);
+ BLI_strncpy(filepath, path_src, path_size);
+ BLI_addtail(path_list, path_store);
return false;
}
-static bool bpath_list_restore(void *userdata, char *path_dst, const char *path_src)
+static bool bpath_list_restore(BPathForeachPathData *bpath_data,
+ char *path_dst,
+ const char *path_src)
{
- /* assume ls->first won't be NULL because the number of paths can't change!
- * (if they do caller is wrong) */
- ListBase *ls = userdata;
- struct PathStore *path_store = ls->first;
+ ListBase *path_list = bpath_data->user_data;
+
+ /* `ls->first` should never be NULL, because the number of paths should not change.
+ * If this happens, there is a bug in caller code. */
+ BLI_assert(!BLI_listbase_is_empty(path_list));
+
+ struct PathStore *path_store = path_list->first;
const char *filepath = (char *)(path_store + 1);
- bool ret;
+ bool is_path_changed = false;
- if (STREQ(path_src, filepath)) {
- ret = false;
- }
- else {
+ if (!STREQ(path_src, filepath)) {
BLI_strncpy(path_dst, filepath, FILE_MAX);
- ret = true;
+ is_path_changed = true;
}
- BLI_freelinkN(ls, path_store);
- return ret;
+ BLI_freelinkN(path_list, path_store);
+ return is_path_changed;
}
-/* return ls_handle */
-void *BKE_bpath_list_backup(Main *bmain, const int flag)
+void *BKE_bpath_list_backup(Main *bmain, const eBPathForeachFlag flag)
{
- ListBase *ls = MEM_callocN(sizeof(ListBase), __func__);
+ ListBase *path_list = MEM_callocN(sizeof(ListBase), __func__);
- BKE_bpath_traverse_main(bmain, bpath_list_append, flag, ls);
+ BKE_bpath_foreach_path_main(&(BPathForeachPathData){.bmain = bmain,
+ .callback_function = bpath_list_append,
+ .flag = flag,
+ .user_data = path_list});
- return ls;
+ return path_list;
}
-void BKE_bpath_list_restore(Main *bmain, const int flag, void *ls_handle)
+void BKE_bpath_list_restore(Main *bmain, const eBPathForeachFlag flag, void *path_list_handle)
{
- ListBase *ls = ls_handle;
+ ListBase *path_list = path_list_handle;
- BKE_bpath_traverse_main(bmain, bpath_list_restore, flag, ls);
+ BKE_bpath_foreach_path_main(&(BPathForeachPathData){.bmain = bmain,
+ .callback_function = bpath_list_restore,
+ .flag = flag,
+ .user_data = path_list});
}
-void BKE_bpath_list_free(void *ls_handle)
+void BKE_bpath_list_free(void *path_list_handle)
{
- ListBase *ls = ls_handle;
- BLI_assert(BLI_listbase_is_empty(ls)); /* assumes we were used */
- BLI_freelistN(ls);
- MEM_freeN(ls);
+ ListBase *path_list = path_list_handle;
+ /* The whole list should have been consumed by #BKE_bpath_list_restore, see also comment in
+ * #bpath_list_restore. */
+ BLI_assert(BLI_listbase_is_empty(path_list));
+
+ BLI_freelistN(path_list);
+ MEM_freeN(path_list);
}
/** \} */
diff --git a/source/blender/blenkernel/intern/bpath_test.cc b/source/blender/blenkernel/intern/bpath_test.cc
new file mode 100644
index 00000000000..121d47af75f
--- /dev/null
+++ b/source/blender/blenkernel/intern/bpath_test.cc
@@ -0,0 +1,181 @@
+/*
+ * 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) 2021 by Blender Foundation.
+ */
+#include "testing/testing.h"
+
+#include "CLG_log.h"
+
+#include "BKE_bpath.h"
+#include "BKE_idtype.h"
+#include "BKE_lib_id.h"
+#include "BKE_main.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+#include "DNA_movieclip_types.h"
+#include "DNA_text_types.h"
+
+#include "BLI_listbase.h"
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+
+namespace blender::bke::tests {
+
+#ifdef WIN32
+# define ABSOLUTE_ROOT "C:" SEP_STR
+#else
+# define ABSOLUTE_ROOT SEP_STR
+#endif
+
+#define RELATIVE_ROOT "//"
+#define BASE_DIR ABSOLUTE_ROOT "blendfiles" SEP_STR
+#define REBASE_DIR BASE_DIR "rebase" SEP_STR
+
+#define BLENDFILE_NAME "bpath.blend"
+#define BLENDFILE_PATH BASE_DIR BLENDFILE_NAME
+
+#define TEXT_PATH_ITEM "texts" SEP_STR "text.txt"
+#define TEXT_PATH_ABSOLUTE ABSOLUTE_ROOT TEXT_PATH_ITEM
+#define TEXT_PATH_ABSOLUTE_MADE_RELATIVE RELATIVE_ROOT ".." SEP_STR TEXT_PATH_ITEM
+#define TEXT_PATH_RELATIVE RELATIVE_ROOT TEXT_PATH_ITEM
+#define TEXT_PATH_RELATIVE_MADE_ABSOLUTE BASE_DIR TEXT_PATH_ITEM
+
+#define MOVIECLIP_PATH_ITEM "movieclips" SEP_STR "movieclip.avi"
+#define MOVIECLIP_PATH_ABSOLUTE ABSOLUTE_ROOT MOVIECLIP_PATH_ITEM
+#define MOVIECLIP_PATH_ABSOLUTE_MADE_RELATIVE RELATIVE_ROOT ".." SEP_STR MOVIECLIP_PATH_ITEM
+#define MOVIECLIP_PATH_RELATIVE RELATIVE_ROOT MOVIECLIP_PATH_ITEM
+#define MOVIECLIP_PATH_RELATIVE_MADE_ABSOLUTE BASE_DIR MOVIECLIP_PATH_ITEM
+
+class BPathTest : public testing::Test {
+ public:
+ static void SetUpTestSuite()
+ {
+ CLG_init();
+ BKE_idtype_init();
+ }
+ static void TearDownTestSuite()
+ {
+ CLG_exit();
+ }
+
+ void SetUp() override
+ {
+ bmain = BKE_main_new();
+ STRNCPY(bmain->filepath, BLENDFILE_PATH);
+
+ BKE_id_new(bmain, ID_TXT, nullptr);
+ BKE_id_new(bmain, ID_MC, nullptr);
+ }
+
+ void TearDown() override
+ {
+ BKE_main_free(bmain);
+ }
+
+ Main *bmain;
+};
+
+TEST_F(BPathTest, rebase_on_relative)
+{
+ // Test on relative paths, should be modified.
+ Text *text = reinterpret_cast<Text *>(bmain->texts.first);
+ text->filepath = BLI_strdup(TEXT_PATH_RELATIVE);
+
+ MovieClip *movie_clip = reinterpret_cast<MovieClip *>(bmain->movieclips.first);
+ BLI_strncpy(movie_clip->filepath, MOVIECLIP_PATH_RELATIVE, sizeof(movie_clip->filepath));
+
+ BKE_bpath_relative_rebase(bmain, BASE_DIR, REBASE_DIR, nullptr);
+
+ EXPECT_STREQ(text->filepath, RELATIVE_ROOT ".." SEP_STR TEXT_PATH_ITEM);
+ EXPECT_STREQ(movie_clip->filepath, RELATIVE_ROOT ".." SEP_STR MOVIECLIP_PATH_ITEM);
+}
+
+TEST_F(BPathTest, rebase_on_absolute)
+{
+ // Test on absolute paths, should not be modified.
+ Text *text = reinterpret_cast<Text *>(bmain->texts.first);
+ text->filepath = BLI_strdup(TEXT_PATH_ABSOLUTE);
+
+ MovieClip *movie_clip = reinterpret_cast<MovieClip *>(bmain->movieclips.first);
+ BLI_strncpy(movie_clip->filepath, MOVIECLIP_PATH_ABSOLUTE, sizeof(movie_clip->filepath));
+
+ BKE_bpath_relative_rebase(bmain, BASE_DIR, REBASE_DIR, nullptr);
+
+ EXPECT_STREQ(text->filepath, TEXT_PATH_ABSOLUTE);
+ EXPECT_STREQ(movie_clip->filepath, MOVIECLIP_PATH_ABSOLUTE);
+}
+
+TEST_F(BPathTest, convert_to_relative)
+{
+ Text *text = reinterpret_cast<Text *>(bmain->texts.first);
+ text->filepath = BLI_strdup(TEXT_PATH_RELATIVE);
+
+ MovieClip *movie_clip = reinterpret_cast<MovieClip *>(bmain->movieclips.first);
+ BLI_strncpy(movie_clip->filepath, MOVIECLIP_PATH_ABSOLUTE, sizeof(movie_clip->filepath));
+
+ BKE_bpath_relative_convert(bmain, BASE_DIR, nullptr);
+
+ // Already relative path should not be modified.
+ EXPECT_STREQ(text->filepath, TEXT_PATH_RELATIVE);
+ // Absolute path should be modified.
+ EXPECT_STREQ(movie_clip->filepath, MOVIECLIP_PATH_ABSOLUTE_MADE_RELATIVE);
+}
+
+TEST_F(BPathTest, convert_to_absolute)
+{
+ Text *text = reinterpret_cast<Text *>(bmain->texts.first);
+ text->filepath = BLI_strdup(TEXT_PATH_RELATIVE);
+
+ MovieClip *movie_clip = reinterpret_cast<MovieClip *>(bmain->movieclips.first);
+ BLI_strncpy(movie_clip->filepath, MOVIECLIP_PATH_ABSOLUTE, sizeof(movie_clip->filepath));
+
+ BKE_bpath_absolute_convert(bmain, BASE_DIR, nullptr);
+
+ // Relative path should be modified.
+ EXPECT_STREQ(text->filepath, TEXT_PATH_RELATIVE_MADE_ABSOLUTE);
+ // Already absolute path should not be modified.
+ EXPECT_STREQ(movie_clip->filepath, MOVIECLIP_PATH_ABSOLUTE);
+}
+
+TEST_F(BPathTest, list_backup_restore)
+{
+ Text *text = reinterpret_cast<Text *>(bmain->texts.first);
+ text->filepath = BLI_strdup(TEXT_PATH_RELATIVE);
+
+ MovieClip *movie_clip = reinterpret_cast<MovieClip *>(bmain->movieclips.first);
+ BLI_strncpy(movie_clip->filepath, MOVIECLIP_PATH_ABSOLUTE, sizeof(movie_clip->filepath));
+
+ void *path_list_handle = BKE_bpath_list_backup(bmain, static_cast<eBPathForeachFlag>(0));
+
+ ListBase *path_list = reinterpret_cast<ListBase *>(path_list_handle);
+ EXPECT_EQ(BLI_listbase_count(path_list), 2);
+
+ MEM_freeN(text->filepath);
+ text->filepath = BLI_strdup(TEXT_PATH_ABSOLUTE);
+ BLI_strncpy(movie_clip->filepath, MOVIECLIP_PATH_RELATIVE, sizeof(movie_clip->filepath));
+
+ BKE_bpath_list_restore(bmain, static_cast<eBPathForeachFlag>(0), path_list_handle);
+
+ EXPECT_STREQ(text->filepath, TEXT_PATH_RELATIVE);
+ EXPECT_STREQ(movie_clip->filepath, MOVIECLIP_PATH_ABSOLUTE);
+ EXPECT_EQ(BLI_listbase_count(path_list), 0);
+
+ BKE_bpath_list_free(path_list_handle);
+}
+
+} // namespace blender::bke::tests
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index dc3c2a8e55e..153a65d67db 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -33,6 +33,7 @@
#include "BLT_translation.h"
+#include "BKE_bpath.h"
#include "BKE_brush.h"
#include "BKE_colortools.h"
#include "BKE_context.h"
@@ -218,6 +219,14 @@ static void brush_foreach_id(ID *id, LibraryForeachIDData *data)
BKE_texture_mtex_foreach_id(data, &brush->mask_mtex));
}
+static void brush_foreach_path(ID *id, BPathForeachPathData *bpath_data)
+{
+ Brush *brush = (Brush *)id;
+ if (brush->icon_filepath[0] != '\0') {
+ BKE_bpath_foreach_path_fixed_process(bpath_data, brush->icon_filepath);
+ }
+}
+
static void brush_blend_write(BlendWriter *writer, ID *id, const void *id_address)
{
Brush *brush = (Brush *)id;
@@ -414,6 +423,7 @@ IDTypeInfo IDType_ID_BR = {
.name_plural = "brushes",
.translation_context = BLT_I18NCONTEXT_ID_BRUSH,
.flags = IDTYPE_FLAGS_NO_ANIMDATA,
+ .asset_type_info = NULL,
.init_data = brush_init_data,
.copy_data = brush_copy_data,
@@ -421,6 +431,7 @@ IDTypeInfo IDType_ID_BR = {
.make_local = brush_make_local,
.foreach_id = brush_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = brush_foreach_path,
.owner_get = NULL,
.blend_write = brush_blend_write,
@@ -503,10 +514,6 @@ static void brush_defaults(Brush *brush)
/* Datablock add/copy/free/make_local */
-/**
- * \note Resulting brush will have two users: one as a fake user,
- * another is assumed to be used by the caller.
- */
Brush *BKE_brush_add(Main *bmain, const char *name, const eObjectMode ob_mode)
{
Brush *brush;
@@ -518,7 +525,6 @@ Brush *BKE_brush_add(Main *bmain, const char *name, const eObjectMode ob_mode)
return brush;
}
-/* add grease pencil settings */
void BKE_brush_init_gpencil_settings(Brush *brush)
{
if (brush->gpencil_settings == NULL) {
@@ -546,7 +552,6 @@ void BKE_brush_init_gpencil_settings(Brush *brush)
brush->gpencil_settings->curve_rand_value = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
}
-/* add a new gp-brush */
Brush *BKE_brush_add_gpencil(Main *bmain, ToolSettings *ts, const char *name, eObjectMode mode)
{
Paint *paint = NULL;
@@ -586,7 +591,6 @@ Brush *BKE_brush_add_gpencil(Main *bmain, ToolSettings *ts, const char *name, eO
return brush;
}
-/* Delete a Brush. */
bool BKE_brush_delete(Main *bmain, Brush *brush)
{
if (brush->id.tag & LIB_TAG_INDIRECT) {
@@ -1320,7 +1324,6 @@ static Brush *gpencil_brush_ensure(
return brush;
}
-/* Create a set of grease pencil Drawing presets. */
void BKE_brush_gpencil_paint_presets(Main *bmain, ToolSettings *ts, const bool reset)
{
bool r_new = false;
@@ -1422,7 +1425,6 @@ void BKE_brush_gpencil_paint_presets(Main *bmain, ToolSettings *ts, const bool r
}
}
-/* Create a set of grease pencil Vertex Paint presets. */
void BKE_brush_gpencil_vertex_presets(Main *bmain, ToolSettings *ts, const bool reset)
{
bool r_new = false;
@@ -1469,7 +1471,6 @@ void BKE_brush_gpencil_vertex_presets(Main *bmain, ToolSettings *ts, const bool
}
}
-/* Create a set of grease pencil Sculpt Paint presets. */
void BKE_brush_gpencil_sculpt_presets(Main *bmain, ToolSettings *ts, const bool reset)
{
bool r_new = false;
@@ -1544,7 +1545,6 @@ void BKE_brush_gpencil_sculpt_presets(Main *bmain, ToolSettings *ts, const bool
}
}
-/* Create a set of grease pencil Weight Paint presets. */
void BKE_brush_gpencil_weight_presets(Main *bmain, ToolSettings *ts, const bool reset)
{
bool r_new = false;
@@ -1946,9 +1946,6 @@ void BKE_brush_sculpt_reset(Brush *br)
}
}
-/**
- * Library Operations
- */
void BKE_brush_curve_preset(Brush *b, eCurveMappingPreset preset)
{
CurveMapping *cumap = NULL;
@@ -1966,10 +1963,6 @@ void BKE_brush_curve_preset(Brush *b, eCurveMappingPreset preset)
BKE_curvemapping_changed(cumap, false);
}
-/* Generic texture sampler for 3D painting systems. point has to be either in
- * region space mouse coordinates, or 3d world coordinates for 3D mapping.
- *
- * rgba outputs straight alpha. */
float BKE_brush_sample_tex_3d(const Scene *scene,
const Brush *br,
const float point[3],
@@ -2362,7 +2355,6 @@ void BKE_brush_weight_set(const Scene *scene, Brush *brush, float value)
}
}
-/* scale unprojected radius to reflect a change in the brush's 2D size */
void BKE_brush_scale_unprojected_radius(float *unprojected_radius,
int new_brush_size,
int old_brush_size)
@@ -2375,7 +2367,6 @@ void BKE_brush_scale_unprojected_radius(float *unprojected_radius,
(*unprojected_radius) *= scale;
}
-/* scale brush size to reflect a change in the brush's unprojected radius */
void BKE_brush_scale_size(int *r_brush_size,
float new_unprojected_radius,
float old_unprojected_radius)
@@ -2426,7 +2417,6 @@ void BKE_brush_randomize_texture_coords(UnifiedPaintSettings *ups, bool mask)
}
}
-/* Uses the brush curve control to find a strength value */
float BKE_brush_curve_strength(const Brush *br, float p, const float len)
{
float strength = 1.0f;
@@ -2474,8 +2464,7 @@ float BKE_brush_curve_strength(const Brush *br, float p, const float len)
return strength;
}
-/* Uses the brush curve control to find a strength value between 0 and 1 */
-float BKE_brush_curve_strength_clamped(Brush *br, float p, const float len)
+float BKE_brush_curve_strength_clamped(const Brush *br, float p, const float len)
{
float strength = BKE_brush_curve_strength(br, p, len);
@@ -2517,7 +2506,6 @@ unsigned int *BKE_brush_gen_texture_cache(Brush *br, int half_side, bool use_sec
return texcache;
}
-/**** Radial Control ****/
struct ImBuf *BKE_brush_gen_radial_control_imbuf(Brush *br, bool secondary, bool display_gradient)
{
ImBuf *im = MEM_callocN(sizeof(ImBuf), "radial control texture");
diff --git a/source/blender/blenkernel/intern/bvhutils.cc b/source/blender/blenkernel/intern/bvhutils.cc
index 1f92f834972..a68119fbc1d 100644
--- a/source/blender/blenkernel/intern/bvhutils.cc
+++ b/source/blender/blenkernel/intern/bvhutils.cc
@@ -125,7 +125,7 @@ bool bvhcache_has_tree(const BVHCache *bvh_cache, const BVHTree *tree)
return false;
}
-BVHCache *bvhcache_init(void)
+BVHCache *bvhcache_init()
{
BVHCache *cache = (BVHCache *)MEM_callocN(sizeof(BVHCache), __func__);
BLI_mutex_init(&cache->mutex);
@@ -147,9 +147,6 @@ static void bvhcache_insert(BVHCache *bvh_cache, BVHTree *tree, BVHCacheType typ
item->is_filled = true;
}
-/**
- * frees a bvhcache
- */
void bvhcache_free(BVHCache *bvh_cache)
{
for (int index = 0; index < BVHTREE_MAX_ITEM; index++) {
@@ -184,6 +181,7 @@ static void bvhtree_balance(BVHTree *tree, const bool isolate)
}
/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Local Callbacks
* \{ */
@@ -669,9 +667,6 @@ static void bvhtree_from_mesh_verts_setup_data(BVHTreeFromMesh *data,
data->vert_allocated = vert_allocated;
}
-/**
- * Builds a BVH-tree where nodes are the vertices of the given `em`.
- */
BVHTree *bvhtree_from_editmesh_verts_ex(BVHTreeFromEditMesh *data,
BMEditMesh *em,
const BLI_bitmap *verts_mask,
@@ -727,13 +722,6 @@ BVHTree *bvhtree_from_editmesh_verts(
data, em, nullptr, -1, epsilon, tree_type, axis, BVHTREE_FROM_VERTS, nullptr, nullptr);
}
-/**
- * Builds a BVH-tree where nodes are the given vertices (NOTE: does not copy given `vert`!).
- * \param vert_allocated: if true, vert freeing will be done when freeing data.
- * \param verts_mask: if not null, true elements give which vert to add to BVH-tree.
- * \param verts_num_active: if >= 0, number of active verts to add to BVH-tree
- * (else will be computed from mask).
- */
BVHTree *bvhtree_from_mesh_verts_ex(BVHTreeFromMesh *data,
const MVert *vert,
const int verts_num,
@@ -884,9 +872,6 @@ static void bvhtree_from_mesh_edges_setup_data(BVHTreeFromMesh *data,
data->edge_allocated = edge_allocated;
}
-/**
- * Builds a BVH-tree where nodes are the edges of the given `em`.
- */
BVHTree *bvhtree_from_editmesh_edges_ex(BVHTreeFromEditMesh *data,
BMEditMesh *em,
const BLI_bitmap *edges_mask,
@@ -941,14 +926,6 @@ BVHTree *bvhtree_from_editmesh_edges(
data, em, nullptr, -1, epsilon, tree_type, axis, BVHTREE_FROM_VERTS, nullptr, nullptr);
}
-/**
- * Builds a BVH-tree where nodes are the given edges.
- * \param vert, vert_allocated: if true, elem freeing will be done when freeing data.
- * \param edge, edge_allocated: if true, elem freeing will be done when freeing data.
- * \param edges_mask: if not null, true elements give which vert to add to BVH-tree.
- * \param edges_num_active: if >= 0, number of active edges to add to BVH-tree
- * (else will be computed from mask).
- */
BVHTree *bvhtree_from_mesh_edges_ex(BVHTreeFromMesh *data,
const MVert *vert,
const bool vert_allocated,
@@ -1075,15 +1052,6 @@ static void bvhtree_from_mesh_faces_setup_data(BVHTreeFromMesh *data,
data->face_allocated = face_allocated;
}
-/**
- * Builds a BVH-tree where nodes are the given tessellated faces
- * (NOTE: does not copy given mfaces!).
- * \param vert_allocated: if true, vert freeing will be done when freeing data.
- * \param face_allocated: if true, face freeing will be done when freeing data.
- * \param faces_mask: if not null, true elements give which faces to add to BVH-tree.
- * \param faces_num_active: if >= 0, number of active faces to add to BVH-tree
- * (else will be computed from mask).
- */
BVHTree *bvhtree_from_mesh_faces_ex(BVHTreeFromMesh *data,
const MVert *vert,
const bool vert_allocated,
@@ -1257,9 +1225,6 @@ static void bvhtree_from_mesh_looptri_setup_data(BVHTreeFromMesh *data,
data->looptri_allocated = looptri_allocated;
}
-/**
- * Builds a BVH-tree where nodes are the `looptri` faces of the given `bm`.
- */
BVHTree *bvhtree_from_editmesh_looptri_ex(BVHTreeFromEditMesh *data,
BMEditMesh *em,
const BLI_bitmap *looptri_mask,
@@ -1314,11 +1279,6 @@ BVHTree *bvhtree_from_editmesh_looptri(
data, em, nullptr, -1, epsilon, tree_type, axis, BVHTREE_FROM_VERTS, nullptr, nullptr);
}
-/**
- * Builds a BVH-tree where nodes are the looptri faces of the given mesh.
- *
- * \note for edit-mesh this is currently a duplicate of #bvhtree_from_mesh_faces_ex
- */
BVHTree *bvhtree_from_mesh_looptri_ex(BVHTreeFromMesh *data,
const struct MVert *vert,
const bool vert_allocated,
@@ -1461,12 +1421,6 @@ static BLI_bitmap *looptri_no_hidden_map_get(const MPoly *mpoly,
return looptri_mask;
}
-/**
- * Builds or queries a bvhcache for the cache bvhtree of the request type.
- *
- * \note This function only fills a cache, and therefore the mesh argument can
- * be considered logically const. Concurrent access is protected by a mutex.
- */
BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
const struct Mesh *mesh,
const BVHCacheType bvh_cache_type,
@@ -1650,9 +1604,6 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
return tree;
}
-/**
- * Builds or queries a bvhcache for the cache bvhtree of the request type.
- */
BVHTree *BKE_bvhtree_from_editmesh_get(BVHTreeFromEditMesh *data,
struct BMEditMesh *em,
const int tree_type,
@@ -1767,9 +1718,10 @@ BVHTree *BKE_bvhtree_from_editmesh_get(BVHTreeFromEditMesh *data,
/** \} */
-/**
- * Frees data allocated by a call to `bvhtree_from_editmesh_*`.
- */
+/* -------------------------------------------------------------------- */
+/** \name Free Functions
+ * \{ */
+
void free_bvhtree_from_editmesh(struct BVHTreeFromEditMesh *data)
{
if (data->tree) {
@@ -1780,9 +1732,6 @@ void free_bvhtree_from_editmesh(struct BVHTreeFromEditMesh *data)
}
}
-/**
- * Frees data allocated by a call to `bvhtree_from_mesh_*`.
- */
void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data)
{
if (data->tree && !data->cached) {
diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c
index e642bbc9e06..8833f3eabe9 100644
--- a/source/blender/blenkernel/intern/cachefile.c
+++ b/source/blender/blenkernel/intern/cachefile.c
@@ -40,6 +40,7 @@
#include "BLT_translation.h"
#include "BKE_anim_data.h"
+#include "BKE_bpath.h"
#include "BKE_cachefile.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
@@ -94,6 +95,12 @@ static void cache_file_free_data(ID *id)
BLI_freelistN(&cache_file->object_paths);
}
+static void cache_file_foreach_path(ID *id, BPathForeachPathData *bpath_data)
+{
+ CacheFile *cache_file = (CacheFile *)id;
+ BKE_bpath_foreach_path_fixed_process(bpath_data, cache_file->filepath);
+}
+
static void cache_file_blend_write(BlendWriter *writer, ID *id, const void *id_address)
{
CacheFile *cache_file = (CacheFile *)id;
@@ -134,6 +141,7 @@ IDTypeInfo IDType_ID_CF = {
.name_plural = "cache_files",
.translation_context = BLT_I18NCONTEXT_ID_CACHEFILE,
.flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = cache_file_init_data,
.copy_data = cache_file_copy_data,
@@ -141,6 +149,7 @@ IDTypeInfo IDType_ID_CF = {
.make_local = NULL,
.foreach_id = NULL,
.foreach_cache = NULL,
+ .foreach_path = cache_file_foreach_path,
.owner_get = NULL,
.blend_write = cache_file_blend_write,
@@ -411,12 +420,6 @@ float BKE_cachefile_time_offset(const CacheFile *cache_file, const float time, c
return cache_file->is_sequence ? frame : frame / fps - time_offset;
}
-/**
- * Determine whether the #CacheFile should use a render engine procedural. If so, data is not read
- * from the file and bounding boxes are used to represent the objects in the Scene.
- * Render engines will receive the bounding box as a placeholder but can instead
- * load the data directly if they support it.
- */
bool BKE_cache_file_uses_render_procedural(const CacheFile *cache_file,
Scene *scene,
const int dag_eval_mode)
diff --git a/source/blender/blenkernel/intern/callbacks.c b/source/blender/blenkernel/intern/callbacks.c
index 72dd51a940d..992eb896d2d 100644
--- a/source/blender/blenkernel/intern/callbacks.c
+++ b/source/blender/blenkernel/intern/callbacks.c
@@ -115,7 +115,6 @@ void BKE_callback_global_init(void)
callbacks_initialized = true;
}
-/* call on application exit */
void BKE_callback_global_finalize(void)
{
eCbEvent evt;
diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c
index d355de73170..7940936b64a 100644
--- a/source/blender/blenkernel/intern/camera.c
+++ b/source/blender/blenkernel/intern/camera.c
@@ -182,6 +182,7 @@ IDTypeInfo IDType_ID_CA = {
.name_plural = "cameras",
.translation_context = BLT_I18NCONTEXT_ID_CAMERA,
.flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = camera_init_data,
.copy_data = camera_copy_data,
@@ -189,6 +190,7 @@ IDTypeInfo IDType_ID_CA = {
.make_local = NULL,
.foreach_id = camera_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = camera_blend_write,
@@ -216,7 +218,6 @@ void *BKE_camera_add(Main *bmain, const char *name)
return cam;
}
-/* get the camera's dof value, takes the dof object into account */
float BKE_camera_object_dof_distance(Object *ob)
{
Camera *cam = (Camera *)ob->data;
@@ -425,7 +426,6 @@ void BKE_camera_params_compute_viewplane(
params->viewplane = viewplane;
}
-/* viewplane is assumed to be already computed */
void BKE_camera_params_compute_matrix(CameraParams *params)
{
rctf viewplane = params->viewplane;
@@ -756,8 +756,6 @@ static bool camera_frame_fit_calc_from_data(CameraParams *params,
return false;
}
-/* don't move the camera, just yield the fit location */
-/* r_scale only valid/useful for ortho cameras */
bool BKE_camera_view_frame_fit_to_scene(
Depsgraph *depsgraph, const Scene *scene, Object *camera_ob, float r_co[3], float *r_scale)
{
@@ -908,7 +906,6 @@ static void camera_stereo3d_model_matrix(const Object *camera,
}
}
-/* the view matrix is used by the viewport drawing, it is basically the inverted model matrix */
void BKE_camera_multiview_view_matrix(const RenderData *rd,
const Object *camera,
const bool is_left,
@@ -1031,7 +1028,6 @@ static Object *camera_multiview_advanced(const Scene *scene, Object *camera, con
return camera;
}
-/* returns the camera to be used for render */
Object *BKE_camera_multiview_render(const Scene *scene, Object *camera, const char *viewname)
{
const bool is_multiview = (camera != NULL) && (scene->r.scemode & R_MULTIVIEW) != 0;
diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c
index 080a7c90c46..42633ff3809 100644
--- a/source/blender/blenkernel/intern/cloth.c
+++ b/source/blender/blenkernel/intern/cloth.c
@@ -326,6 +326,7 @@ static int do_step_cloth(
/************************************************
* clothModifier_do - main simulation function
************************************************/
+
void clothModifier_do(ClothModifierData *clmd,
Depsgraph *depsgraph,
Scene *scene,
@@ -433,7 +434,6 @@ void clothModifier_do(ClothModifierData *clmd,
clmd->clothObject->last_frame = framenr;
}
-/* frees all */
void cloth_free_modifier(ClothModifierData *clmd)
{
Cloth *cloth = NULL;
@@ -504,7 +504,6 @@ void cloth_free_modifier(ClothModifierData *clmd)
}
}
-/* frees all */
void cloth_free_modifier_extern(ClothModifierData *clmd)
{
Cloth *cloth = NULL;
diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c
index 22b939d3cf9..21a9159004f 100644
--- a/source/blender/blenkernel/intern/collection.c
+++ b/source/blender/blenkernel/intern/collection.c
@@ -375,6 +375,7 @@ IDTypeInfo IDType_ID_GR = {
.name_plural = "collections",
.translation_context = BLT_I18NCONTEXT_ID_COLLECTION,
.flags = IDTYPE_FLAGS_NO_ANIMDATA,
+ .asset_type_info = NULL,
.init_data = collection_init_data,
.copy_data = collection_copy_data,
@@ -382,6 +383,7 @@ IDTypeInfo IDType_ID_GR = {
.make_local = NULL,
.foreach_id = collection_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = collection_owner_get,
.blend_write = collection_blend_write,
@@ -429,10 +431,6 @@ static Collection *collection_add(Main *bmain,
return collection;
}
-/**
- * Add a collection to a collection ListBase and synchronize all render layers
- * The ListBase is NULL when the collection is to be added to the master collection
- */
Collection *BKE_collection_add(Main *bmain, Collection *collection_parent, const char *name_custom)
{
Collection *collection = collection_add(bmain, collection_parent, name_custom);
@@ -440,12 +438,6 @@ Collection *BKE_collection_add(Main *bmain, Collection *collection_parent, const
return collection;
}
-/**
- * Add \a collection_dst to all scene collections that reference object \a ob_src is in.
- * Used to replace an instance object with a collection (library override operator).
- *
- * Logic is very similar to #BKE_collection_object_add_from().
- */
void BKE_collection_add_from_object(Main *bmain,
Scene *scene,
const Object *ob_src,
@@ -468,12 +460,6 @@ void BKE_collection_add_from_object(Main *bmain,
BKE_main_collection_sync(bmain);
}
-/**
- * Add \a collection_dst to all scene collections that reference collection \a collection_src is
- * in.
- *
- * Logic is very similar to #BKE_collection_object_add_from().
- */
void BKE_collection_add_from_collection(Main *bmain,
Scene *scene,
Collection *collection_src,
@@ -507,17 +493,12 @@ void BKE_collection_add_from_collection(Main *bmain,
/** \name Free and Delete Collection
* \{ */
-/** Free (or release) any data used by this collection (does not free the collection itself). */
void BKE_collection_free_data(Collection *collection)
{
BKE_libblock_free_data(&collection->id, false);
collection_free_data(&collection->id);
}
-/**
- * Remove a collection, optionally removing its child objects or moving
- * them to parent collections.
- */
bool BKE_collection_delete(Main *bmain, Collection *collection, bool hierarchy)
{
/* Master collection is not real datablock, can't be removed. */
@@ -678,14 +659,6 @@ static Collection *collection_duplicate_recursive(Main *bmain,
return collection_new;
}
-/**
- * Make a deep copy (aka duplicate) of the given collection and all of its children, recursively.
- *
- * \warning This functions will clear all \a bmain #ID.idnew pointers, unless \a
- * #LIB_ID_DUPLICATE_IS_SUBPROCESS duplicate option is passed on, in which case caller is
- * responsible to reconstruct collection dependencies information's
- * (i.e. call #BKE_main_collection_sync).
- */
Collection *BKE_collection_duplicate(Main *bmain,
Collection *parent,
Collection *collection,
@@ -744,9 +717,6 @@ Collection *BKE_collection_duplicate(Main *bmain,
/** \name Collection Naming
* \{ */
-/**
- * The automatic/fallback name of a new collection.
- */
void BKE_collection_new_name_get(Collection *collection_parent, char *rname)
{
char *name;
@@ -769,9 +739,6 @@ void BKE_collection_new_name_get(Collection *collection_parent, char *rname)
MEM_freeN(name);
}
-/**
- * The name to show in the interface.
- */
const char *BKE_collection_ui_name_get(struct Collection *collection)
{
if (collection->flag & COLLECTION_IS_MASTER) {
@@ -1127,9 +1094,6 @@ static bool collection_object_remove(Main *bmain,
return true;
}
-/**
- * Add object to collection
- */
bool BKE_collection_object_add(Main *bmain, Collection *collection, Object *ob)
{
if (ELEM(NULL, collection, ob)) {
@@ -1158,12 +1122,6 @@ bool BKE_collection_object_add(Main *bmain, Collection *collection, Object *ob)
return true;
}
-/**
- * Add \a ob_dst to all scene collections that reference object \a ob_src is in.
- * Used for copying objects.
- *
- * Logic is very similar to #BKE_collection_add_from_object()
- */
void BKE_collection_object_add_from(Main *bmain, Scene *scene, Object *ob_src, Object *ob_dst)
{
bool is_instantiated = false;
@@ -1186,9 +1144,6 @@ void BKE_collection_object_add_from(Main *bmain, Scene *scene, Object *ob_src, O
BKE_main_collection_sync(bmain);
}
-/**
- * Remove object from collection.
- */
bool BKE_collection_object_remove(Main *bmain,
Collection *collection,
Object *ob,
@@ -1236,9 +1191,6 @@ static bool scene_collections_object_remove(
return removed;
}
-/**
- * Remove object from all collections of scene
- */
bool BKE_scene_collections_object_remove(Main *bmain, Scene *scene, Object *ob, const bool free_us)
{
return scene_collections_object_remove(bmain, scene, ob, free_us, NULL);
@@ -1302,18 +1254,6 @@ static void collection_missing_parents_remove(Collection *collection)
}
}
-/**
- * Remove all NULL children from parent collections of changed \a collection.
- * This is used for library remapping, where these pointers have been set to NULL.
- * Otherwise this should never happen.
- *
- * \note caller must ensure #BKE_main_collection_sync_remap() is called afterwards!
- *
- * \param parent_collection: The collection owning the pointers that were remapped. May be \a NULL,
- * in which case whole \a bmain database of collections is checked.
- * \param child_collection: The collection that was remapped to another pointer. May be \a NULL,
- * in which case whole \a bmain database of collections is checked.
- */
void BKE_collections_child_remove_nulls(Main *bmain,
Collection *parent_collection,
Collection *child_collection)
@@ -1358,11 +1298,6 @@ void BKE_collections_child_remove_nulls(Main *bmain,
}
}
-/**
- * Move object from a collection into another
- *
- * If source collection is NULL move it from all the existing collections.
- */
void BKE_collection_object_move(
Main *bmain, Scene *scene, Collection *collection_dst, Collection *collection_src, Object *ob)
{
@@ -1437,15 +1372,6 @@ static bool collection_instance_find_recursive(Collection *collection,
return false;
}
-/**
- * Find potential cycles in collections.
- *
- * \param new_ancestor: the potential new owner of given \a collection,
- * or the collection to check if the later is NULL.
- * \param collection: the collection we want to add to \a new_ancestor,
- * may be NULL if we just want to ensure \a new_ancestor does not already have cycles.
- * \return true if a cycle is found.
- */
bool BKE_collection_cycle_find(Collection *new_ancestor, Collection *collection)
{
if (collection == new_ancestor) {
@@ -1509,12 +1435,6 @@ static bool collection_cycle_fix_recursive(Main *bmain,
return cycles_found;
}
-/**
- * Find and fix potential cycles in collections.
- *
- * \param collection: The collection to check for existing cycles.
- * \return true if cycles are found and fixed.
- */
bool BKE_collection_cycles_fix(Main *bmain, Collection *collection)
{
return collection_cycle_fix_recursive(bmain, collection, collection) ||
@@ -1627,11 +1547,6 @@ bool BKE_collection_child_remove(Main *bmain, Collection *parent, Collection *ch
return true;
}
-/**
- * Rebuild parent relationships from child ones, for all children of given \a collection.
- *
- * \note Given collection is assumed to already have valid parents.
- */
void BKE_collection_parent_relations_rebuild(Collection *collection)
{
LISTBASE_FOREACH_MUTABLE (CollectionChild *, child, &collection->children) {
@@ -1680,9 +1595,6 @@ static void collection_parents_rebuild_recursive(Collection *collection)
}
}
-/**
- * Rebuild parent relationships from child ones, for all collections in given \a bmain.
- */
void BKE_main_collections_parent_relations_rebuild(Main *bmain)
{
/* Only collections not in bmain (master ones in scenes) have no parent... */
@@ -1743,11 +1655,6 @@ static Collection *collection_from_index_recursive(Collection *collection,
return NULL;
}
-/**
- * Return Scene Collection for a given index.
- *
- * The index is calculated from top to bottom counting the children before the siblings.
- */
Collection *BKE_collection_from_index(Scene *scene, const int index)
{
int index_current = 0;
@@ -1791,10 +1698,6 @@ static bool collection_objects_select(ViewLayer *view_layer, Collection *collect
return changed;
}
-/**
- * Select all the objects in this Collection (and its nested collections) for this ViewLayer.
- * Return true if any object was selected.
- */
bool BKE_collection_objects_select(ViewLayer *view_layer, Collection *collection, bool deselect)
{
LayerCollection *layer_collection = BKE_layer_collection_first_from_scene_collection(view_layer,
@@ -1920,10 +1823,6 @@ static void scene_collections_array(Scene *scene,
scene_collection_callback(collection, scene_collections_build_array, &array);
}
-/**
- * Only use this in non-performance critical situations
- * (it iterates over all scene collections twice)
- */
void BKE_scene_collections_iterator_begin(BLI_Iterator *iter, void *data_in)
{
Scene *scene = data_in;
@@ -2065,13 +1964,6 @@ void BKE_scene_objects_iterator_end(BLI_Iterator *iter)
}
}
-/**
- * Generate a new GSet (or extend given `objects_gset` if not NULL) with all objects referenced by
- * all collections of given `scene`.
- *
- * \note This will include objects without a base currently
- * (because they would belong to excluded collections only e.g.).
- */
GSet *BKE_scene_objects_as_gset(Scene *scene, GSet *objects_gset)
{
BLI_Iterator iter;
diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c
index 03957d54629..671c6530685 100644
--- a/source/blender/blenkernel/intern/collision.c
+++ b/source/blender/blenkernel/intern/collision.c
@@ -78,7 +78,6 @@ typedef struct SelfColDetectData {
* Collision modifier code start
***********************************/
-/* step is limited from 0 (frame start position) to 1 (frame end position) */
void collision_move_object(CollisionModifierData *collmd,
const float step,
const float prevstep,
@@ -1261,9 +1260,6 @@ static void add_collision_object(ListBase *relations,
}
}
-/* Create list of collision relations in the collection or entire scene.
- * This is used by the depsgraph to build relations, as well as faster
- * lookup of colliders during evaluation. */
ListBase *BKE_collision_relations_create(Depsgraph *depsgraph,
Collection *collection,
unsigned int modifier_type)
@@ -1292,8 +1288,6 @@ void BKE_collision_relations_free(ListBase *relations)
}
}
-/* Create effective list of colliders from relations built beforehand.
- * Self will be excluded. */
Object **BKE_collision_objects_create(Depsgraph *depsgraph,
Object *self,
Collection *collection,
@@ -1341,8 +1335,6 @@ void BKE_collision_objects_free(Object **objects)
}
}
-/* Create effective list of colliders from relations built beforehand.
- * Self will be excluded. */
ListBase *BKE_collider_cache_create(Depsgraph *depsgraph, Object *self, Collection *collection)
{
ListBase *relations = DEG_get_collision_relations(
diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c
index 62b817487fc..b12b19453ae 100644
--- a/source/blender/blenkernel/intern/colortools.c
+++ b/source/blender/blenkernel/intern/colortools.c
@@ -183,7 +183,6 @@ void BKE_curvemapping_set_black_white(CurveMapping *cumap,
/* ***************** operations on single curve ************* */
/* ********** NOTE: requires BKE_curvemapping_changed() call after ******** */
-/* remove specified point */
bool BKE_curvemap_remove_point(CurveMap *cuma, CurveMapPoint *point)
{
CurveMapPoint *cmp;
@@ -213,7 +212,6 @@ bool BKE_curvemap_remove_point(CurveMap *cuma, CurveMapPoint *point)
return (removed != 0);
}
-/* removes with flag set */
void BKE_curvemap_remove(CurveMap *cuma, const short flag)
{
CurveMapPoint *cmp = MEM_mallocN((cuma->totpoint) * sizeof(CurveMapPoint), "curve points");
@@ -439,9 +437,6 @@ void BKE_curvemap_reset(CurveMap *cuma, const rctf *clipr, int preset, int slope
}
}
-/**
- * \param type: eBezTriple_Handle
- */
void BKE_curvemap_handle_set(CurveMap *cuma, int type)
{
int a;
@@ -800,10 +795,10 @@ static void curvemap_make_table(const CurveMapping *cumap, CurveMap *cuma)
cuma->table = cmp;
}
-/* call when you do images etc, needs restore too. also verifies tables */
-/* it uses a flag to prevent premul or free to happen twice */
-void BKE_curvemapping_premultiply(CurveMapping *cumap, int restore)
+void BKE_curvemapping_premultiply(CurveMapping *cumap, bool restore)
{
+ /* It uses a flag to prevent pre-multiply or free to happen twice. */
+
int a;
if (restore) {
@@ -873,7 +868,6 @@ static int sort_curvepoints(const void *a1, const void *a2)
/* ************************ more CurveMapping calls *************** */
-/* NOTE: only does current curvemap! */
void BKE_curvemapping_changed(CurveMapping *cumap, const bool rem_doubles)
{
CurveMap *cuma = cumap->cm + cumap->cur;
@@ -965,13 +959,11 @@ void BKE_curvemapping_changed_all(CurveMapping *cumap)
cumap->cur = cur;
}
-/* Reset the view for current curve. */
void BKE_curvemapping_reset_view(CurveMapping *cumap)
{
cumap->curr = cumap->clipr;
}
-/* table should be verified */
float BKE_curvemap_evaluateF(const CurveMapping *cumap, const CurveMap *cuma, float value)
{
/* index in table */
@@ -994,7 +986,6 @@ float BKE_curvemap_evaluateF(const CurveMapping *cumap, const CurveMap *cuma, fl
return (1.0f - fi) * cuma->table[i].y + (fi)*cuma->table[i + 1].y;
}
-/* works with curve 'cur' */
float BKE_curvemapping_evaluateF(const CurveMapping *cumap, int cur, float value)
{
const CurveMap *cuma = cumap->cm + cur;
@@ -1013,7 +1004,6 @@ float BKE_curvemapping_evaluateF(const CurveMapping *cumap, int cur, float value
return val;
}
-/* vector case */
void BKE_curvemapping_evaluate3F(const CurveMapping *cumap, float vecout[3], const float vecin[3])
{
vecout[0] = BKE_curvemap_evaluateF(cumap, &cumap->cm[0], vecin[0]);
@@ -1021,7 +1011,6 @@ void BKE_curvemapping_evaluate3F(const CurveMapping *cumap, float vecout[3], con
vecout[2] = BKE_curvemap_evaluateF(cumap, &cumap->cm[2], vecin[2]);
}
-/* RGB case, no black/white points, no premult */
void BKE_curvemapping_evaluateRGBF(const CurveMapping *cumap,
float vecout[3],
const float vecin[3])
@@ -1052,16 +1041,6 @@ static void curvemapping_evaluateRGBF_filmlike(const CurveMapping *cumap,
vecout[channel_offset[2]] = v2;
}
-/**
- * Same as #BKE_curvemapping_evaluate_premulRGBF
- * but black/bwmul are passed as args for the compositor
- * where they can change per pixel.
- *
- * Use in conjunction with #BKE_curvemapping_set_black_white_ex
- *
- * \param black: Use instead of cumap->black
- * \param bwmul: Use instead of cumap->bwmul
- */
void BKE_curvemapping_evaluate_premulRGBF_ex(const CurveMapping *cumap,
float vecout[3],
const float vecin[3],
@@ -1127,7 +1106,6 @@ void BKE_curvemapping_evaluate_premulRGBF_ex(const CurveMapping *cumap,
}
}
-/* RGB with black/white points and premult. tables are checked */
void BKE_curvemapping_evaluate_premulRGBF(const CurveMapping *cumap,
float vecout[3],
const float vecin[3])
@@ -1135,7 +1113,6 @@ void BKE_curvemapping_evaluate_premulRGBF(const CurveMapping *cumap,
BKE_curvemapping_evaluate_premulRGBF_ex(cumap, vecout, vecin, cumap->black, cumap->bwmul);
}
-/* same as above, byte version */
void BKE_curvemapping_evaluate_premulRGB(const CurveMapping *cumap,
unsigned char vecout_byte[3],
const unsigned char vecin_byte[3])
@@ -1262,7 +1239,6 @@ void BKE_curvemapping_curves_blend_write(BlendWriter *writer, const CurveMapping
}
}
-/* cumap itself has been read already. */
void BKE_curvemapping_blend_read(BlendDataReader *reader, CurveMapping *cumap)
{
/* flag seems to be able to hang? Maybe old files... not bad to clear anyway */
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index 3455baa9292..d284c32b1df 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -123,7 +123,6 @@ static bConstraint *constraint_find_original_for_update(bConstraintOb *cob, bCon
/* -------------- Naming -------------- */
-/* Find the first available, non-duplicate name for a given constraint */
void BKE_constraint_unique_name(bConstraint *con, ListBase *list)
{
BLI_uniquename(list, con, DATA_("Const"), '.', offsetof(bConstraint, name), sizeof(con->name));
@@ -132,8 +131,6 @@ void BKE_constraint_unique_name(bConstraint *con, ListBase *list)
/* ----------------- Evaluation Loop Preparation --------------- */
/* package an object/bone for use in constraint evaluation */
-/* This function MEM_calloc's a bConstraintOb struct,
- * that will need to be freed after evaluation */
bConstraintOb *BKE_constraints_make_evalob(
Depsgraph *depsgraph, Scene *scene, Object *ob, void *subdata, short datatype)
{
@@ -211,7 +208,6 @@ bConstraintOb *BKE_constraints_make_evalob(
return cob;
}
-/* cleanup after constraint evaluation */
void BKE_constraints_clear_evalob(bConstraintOb *cob)
{
float delta[4][4], imat[4][4];
@@ -261,10 +257,6 @@ void BKE_constraints_clear_evalob(bConstraintOb *cob)
/* -------------- Space-Conversion API -------------- */
-/* This function is responsible for the correct transformations/conversions
- * of a matrix from one space to another for constraint evaluation.
- * For now, this is only implemented for Objects and PoseChannels.
- */
void BKE_constraint_mat_convertspace(Object *ob,
bPoseChannel *pchan,
bConstraintOb *cob,
@@ -5556,9 +5548,6 @@ static void constraints_init_typeinfo(void)
constraintsTypeInfo[30] = &CTI_ARMATURE; /* Armature Constraint */
}
-/* This function should be used for getting the appropriate type-info when only
- * a constraint type is known
- */
const bConstraintTypeInfo *BKE_constraint_typeinfo_from_type(int type)
{
/* initialize the type-info list? */
@@ -5578,9 +5567,6 @@ const bConstraintTypeInfo *BKE_constraint_typeinfo_from_type(int type)
return NULL;
}
-/* This function should always be used to get the appropriate type-info, as it
- * has checks which prevent segfaults in some weird cases.
- */
const bConstraintTypeInfo *BKE_constraint_typeinfo_get(bConstraint *con)
{
/* only return typeinfo for valid constraints */
@@ -5611,11 +5597,6 @@ static void con_unlink_refs_cb(bConstraint *UNUSED(con),
}
}
-/**
- * Free data of a specific constraint if it has any info.
- * be sure to run #BIK_clear_data() when freeing an IK constraint,
- * unless DAG_relations_tag_update is called.
- */
void BKE_constraint_free_data_ex(bConstraint *con, bool do_id_user)
{
if (con->data) {
@@ -5643,7 +5624,6 @@ void BKE_constraint_free_data(bConstraint *con)
BKE_constraint_free_data_ex(con, true);
}
-/* Free all constraints from a constraint-stack */
void BKE_constraints_free_ex(ListBase *list, bool do_id_user)
{
/* Free constraint data and also any extra data */
@@ -5660,7 +5640,6 @@ void BKE_constraints_free(ListBase *list)
BKE_constraints_free_ex(list, true);
}
-/* Remove the specified constraint from the given constraint stack */
bool BKE_constraint_remove(ListBase *list, bConstraint *con)
{
if (con) {
@@ -5686,7 +5665,6 @@ bool BKE_constraint_remove_ex(ListBase *list, Object *ob, bConstraint *con, bool
return false;
}
-/* Apply the specified constraint in the given constraint stack */
bool BKE_constraint_apply_for_object(Depsgraph *depsgraph,
Scene *scene,
Object *ob,
@@ -5920,7 +5898,6 @@ bool BKE_constraint_target_uses_bbone(struct bConstraint *con,
/* ......... */
-/* Add new constraint for the given bone */
bConstraint *BKE_constraint_add_for_pose(Object *ob,
bPoseChannel *pchan,
const char *name,
@@ -5933,7 +5910,6 @@ bConstraint *BKE_constraint_add_for_pose(Object *ob,
return add_new_constraint(ob, pchan, name, type);
}
-/* Add new constraint for the given object */
bConstraint *BKE_constraint_add_for_object(Object *ob, const char *name, short type)
{
return add_new_constraint(ob, NULL, name, type);
@@ -5941,7 +5917,6 @@ bConstraint *BKE_constraint_add_for_object(Object *ob, const char *name, short t
/* ......... */
-/* Run the given callback on all ID-blocks in list of constraints */
void BKE_constraints_id_loop(ListBase *conlist, ConstraintIDFunc func, void *userdata)
{
LISTBASE_FOREACH (bConstraint *, con, conlist) {
@@ -6016,7 +5991,6 @@ static void constraint_copy_data_ex(bConstraint *dst,
}
}
-/** Allocate and duplicate a single constraint, outside of any object/pose context. */
bConstraint *BKE_constraint_duplicate_ex(bConstraint *src, const int flag, const bool do_extern)
{
bConstraint *dst = MEM_dupallocN(src);
@@ -6025,7 +5999,6 @@ bConstraint *BKE_constraint_duplicate_ex(bConstraint *src, const int flag, const
return dst;
}
-/* Add a copy of the given constraint for the given bone */
bConstraint *BKE_constraint_copy_for_pose(Object *ob, bPoseChannel *pchan, bConstraint *src)
{
if (pchan == NULL) {
@@ -6037,7 +6010,6 @@ bConstraint *BKE_constraint_copy_for_pose(Object *ob, bPoseChannel *pchan, bCons
return new_con;
}
-/* Add a copy of the given constraint for the given object */
bConstraint *BKE_constraint_copy_for_object(Object *ob, bConstraint *src)
{
bConstraint *new_con = BKE_constraint_duplicate_ex(src, 0, !ID_IS_LINKED(ob));
@@ -6045,7 +6017,6 @@ bConstraint *BKE_constraint_copy_for_object(Object *ob, bConstraint *src)
return new_con;
}
-/* duplicate all of the constraints in a constraint stack */
void BKE_constraints_copy_ex(ListBase *dst, const ListBase *src, const int flag, bool do_extern)
{
bConstraint *con, *srccon;
@@ -6074,7 +6045,6 @@ bConstraint *BKE_constraints_find_name(ListBase *list, const char *name)
return BLI_findstring(list, name, offsetof(bConstraint, name));
}
-/* finds the 'active' constraint in a constraint stack */
bConstraint *BKE_constraints_active_get(ListBase *list)
{
@@ -6091,7 +6061,6 @@ bConstraint *BKE_constraints_active_get(ListBase *list)
return NULL;
}
-/* Set the given constraint as the active one (clearing all the others) */
void BKE_constraints_active_set(ListBase *list, bConstraint *con)
{
@@ -6127,7 +6096,6 @@ static bConstraint *constraint_list_find_from_target(ListBase *constraints, bCon
return NULL;
}
-/* Finds the constraint that owns the given target within the object. */
bConstraint *BKE_constraint_find_from_target(Object *ob,
bConstraintTarget *tgt,
bPoseChannel **r_pchan)
@@ -6225,12 +6193,6 @@ static bConstraint *constraint_find_original_for_update(bConstraintOb *cob, bCon
return orig_con;
}
-/**
- * Check whether given constraint is not local (i.e. from linked data) when the object is a library
- * override.
- *
- * \param con: May be NULL, in which case we consider it as a non-local constraint case.
- */
bool BKE_constraint_is_nonlocal_in_liboverride(const Object *ob, const bConstraint *con)
{
return (ID_IS_OVERRIDE_LIBRARY(ob) &&
@@ -6239,8 +6201,6 @@ bool BKE_constraint_is_nonlocal_in_liboverride(const Object *ob, const bConstrai
/* -------- Constraints and Proxies ------- */
-/* Rescue all constraints tagged as being CONSTRAINT_PROXY_LOCAL
- * (i.e. added to bone that's proxy-synced in this file) */
void BKE_constraints_proxylocal_extract(ListBase *dst, ListBase *src)
{
bConstraint *con, *next;
@@ -6257,7 +6217,6 @@ void BKE_constraints_proxylocal_extract(ListBase *dst, ListBase *src)
}
}
-/* Returns if the owner of the constraint is proxy-protected */
bool BKE_constraints_proxylocked_owner(Object *ob, bPoseChannel *pchan)
{
/* Currently, constraints can only be on object or bone level */
@@ -6281,13 +6240,6 @@ bool BKE_constraints_proxylocked_owner(Object *ob, bPoseChannel *pchan)
/* -------- Target-Matrix Stuff ------- */
-/* This function is a relic from the prior implementations of the constraints system, when all
- * constraints either had one or no targets. It used to be called during the main constraint
- * solving loop, but is now only used for the remaining cases for a few constraints.
- *
- * None of the actual calculations of the matrices should be done here! Also, this function is
- * not to be used by any new constraints, particularly any that have multiple targets.
- */
void BKE_constraint_target_matrix_get(struct Depsgraph *depsgraph,
Scene *scene,
bConstraint *con,
@@ -6364,7 +6316,6 @@ void BKE_constraint_target_matrix_get(struct Depsgraph *depsgraph,
}
}
-/* Get the list of targets required for solving a constraint */
void BKE_constraint_targets_for_solving_get(struct Depsgraph *depsgraph,
bConstraint *con,
bConstraintOb *cob,
@@ -6434,12 +6385,6 @@ void BKE_constraint_custom_object_space_get(float r_mat[4][4], bConstraint *con)
/* ---------- Evaluation ----------- */
-/* This function is called whenever constraints need to be evaluated. Currently, all
- * constraints that can be evaluated are every time this gets run.
- *
- * BKE_constraints_make_evalob and BKE_constraints_clear_evalob should be called before and
- * after running this function, to sort out cob
- */
void BKE_constraints_solve(struct Depsgraph *depsgraph,
ListBase *conlist,
bConstraintOb *cob,
diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c
index c235a1bbb6a..ceaed5d2bba 100644
--- a/source/blender/blenkernel/intern/context.c
+++ b/source/blender/blenkernel/intern/context.c
@@ -547,12 +547,6 @@ static void data_dir_add(ListBase *lb, const char *member, const bool use_all)
BLI_addtail(lb, link);
}
-/**
- * \param C: Context
- * \param use_store: Use 'C->wm.store'
- * \param use_rna: Use Include the properties from 'RNA_Context'
- * \param use_all: Don't skip values (currently only "scene")
- */
ListBase CTX_data_dir_get_ex(const bContext *C,
const bool use_store,
const bool use_rna,
@@ -1127,13 +1121,6 @@ RenderEngineType *CTX_data_engine_type(const bContext *C)
return RE_engines_find(scene->r.engine);
}
-/**
- * This is tricky. Sometimes the user overrides the render_layer
- * but not the scene_collection. In this case what to do?
- *
- * If the scene_collection is linked to the ViewLayer we use it.
- * Otherwise we fallback to the active one of the ViewLayer.
- */
LayerCollection *CTX_data_layer_collection(const bContext *C)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
diff --git a/source/blender/blenkernel/intern/crazyspace.c b/source/blender/blenkernel/intern/crazyspace.c
index 26894495777..6bbb9957b03 100644
--- a/source/blender/blenkernel/intern/crazyspace.c
+++ b/source/blender/blenkernel/intern/crazyspace.c
@@ -98,7 +98,6 @@ static bool modifiers_disable_subsurf_temporary(struct Scene *scene, Object *ob)
return disabled;
}
-/* disable subsurf temporal, get mapped cos, and enable it */
float (*BKE_crazyspace_get_mapped_editverts(struct Depsgraph *depsgraph, Object *obedit))[3]
{
Scene *scene = DEG_get_input_scene(depsgraph);
@@ -243,10 +242,6 @@ void BKE_crazyspace_set_quats_mesh(Mesh *me,
}
}
-/**
- * Returns an array of deform matrices for crazy-space correction,
- * and the number of modifiers left.
- */
int BKE_crazyspace_get_first_deform_matrices_editbmesh(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob,
diff --git a/source/blender/blenkernel/intern/cryptomatte.cc b/source/blender/blenkernel/intern/cryptomatte.cc
index 1ff0ca92306..d532ed9e4b2 100644
--- a/source/blender/blenkernel/intern/cryptomatte.cc
+++ b/source/blender/blenkernel/intern/cryptomatte.cc
@@ -139,7 +139,7 @@ std::optional<std::string> CryptomatteSession::operator[](float encoded_hash) co
return std::nullopt;
}
-CryptomatteSession *BKE_cryptomatte_init(void)
+CryptomatteSession *BKE_cryptomatte_init()
{
CryptomatteSession *session = new CryptomatteSession();
return session;
@@ -212,7 +212,6 @@ float BKE_cryptomatte_hash_to_float(uint32_t cryptomatte_hash)
return blender::bke::cryptomatte::CryptomatteHash(cryptomatte_hash).float_encoded();
}
-/* Find an ID in the given main that matches the given encoded float. */
bool BKE_cryptomatte_find_name(const CryptomatteSession *session,
const float encoded_hash,
char *r_name,
@@ -489,10 +488,6 @@ std::string BKE_cryptomatte_meta_data_key(const StringRef layer_name, const Stri
return "cryptomatte/" + cryptomatte_layer_name_hash(layer_name) + "/" + key_name;
}
-/* Extracts the cryptomatte name from a render pass name.
- *
- * Example: A render pass could be named `CryptoObject00`. This
- * function would remove the trailing digits and return `CryptoObject`. */
StringRef BKE_cryptomatte_extract_layer_name(const StringRef render_pass_name)
{
int64_t last_token = render_pass_name.size();
@@ -525,16 +520,6 @@ std::string CryptomatteHash::hex_encoded() const
return encoded.str();
}
-/* Convert a cryptomatte hash to a float.
- *
- * Cryptomatte hashes are stored in float textures and images. The conversion is taken from the
- * cryptomatte specification. See Floating point conversion section in
- * https://github.com/Psyop/Cryptomatte/blob/master/specification/cryptomatte_specification.pdf.
- *
- * The conversion uses as many 32 bit floating point values as possible to minimize hash
- * collisions. Unfortunately not all 32 bits can be used as NaN and Inf can be problematic.
- *
- * Note that this conversion assumes to be running on a L-endian system. */
float CryptomatteHash::float_encoded() const
{
uint32_t mantissa = hash & ((1 << 23) - 1);
@@ -626,7 +611,6 @@ void CryptomatteStampDataCallbackData::extract_layer_names(void *_data,
data->hash_to_layer_name.add(layer_hash, propvalue);
}
-/* C type callback function (StampCallback). */
void CryptomatteStampDataCallbackData::extract_layer_manifest(void *_data,
const char *propname,
char *propvalue,
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.cc
index aae9ac383a4..dc2527f9b62 100644
--- a/source/blender/blenkernel/intern/curve.c
+++ b/source/blender/blenkernel/intern/curve.cc
@@ -21,9 +21,9 @@
* \ingroup bke
*/
-#include <math.h> /* floor */
-#include <stdlib.h>
-#include <string.h>
+#include <cmath> /* floor */
+#include <cstdlib>
+#include <cstring>
#include "MEM_guardedalloc.h"
@@ -43,7 +43,7 @@
#include "DNA_defaults.h"
#include "DNA_material_types.h"
-/* for dereferencing pointers */
+/* For dereferencing pointers. */
#include "DNA_key_types.h"
#include "DNA_object_types.h"
#include "DNA_vfont_types.h"
@@ -89,12 +89,12 @@ static void curve_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int
BLI_listbase_clear(&curve_dst->nurb);
BKE_nurbList_duplicate(&(curve_dst->nurb), &(curve_src->nurb));
- curve_dst->mat = MEM_dupallocN(curve_src->mat);
+ curve_dst->mat = (Material **)MEM_dupallocN(curve_src->mat);
- curve_dst->str = MEM_dupallocN(curve_src->str);
- curve_dst->strinfo = MEM_dupallocN(curve_src->strinfo);
- curve_dst->tb = MEM_dupallocN(curve_src->tb);
- curve_dst->batch_cache = NULL;
+ curve_dst->str = (char *)MEM_dupallocN(curve_src->str);
+ curve_dst->strinfo = (CharInfo *)MEM_dupallocN(curve_src->strinfo);
+ curve_dst->tb = (TextBox *)MEM_dupallocN(curve_src->tb);
+ curve_dst->batch_cache = nullptr;
curve_dst->bevel_profile = BKE_curveprofile_copy(curve_src->bevel_profile);
@@ -104,8 +104,8 @@ static void curve_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int
curve_dst->key->from = &curve_dst->id;
}
- curve_dst->editnurb = NULL;
- curve_dst->editfont = NULL;
+ curve_dst->editnurb = nullptr;
+ curve_dst->editfont = nullptr;
}
static void curve_free_data(ID *id)
@@ -148,9 +148,9 @@ static void curve_blend_write(BlendWriter *writer, ID *id, const void *id_addres
Curve *cu = (Curve *)id;
/* Clean up, important in undo case to reduce false detection of changed datablocks. */
- cu->editnurb = NULL;
- cu->editfont = NULL;
- cu->batch_cache = NULL;
+ cu->editnurb = nullptr;
+ cu->editfont = nullptr;
+ cu->batch_cache = nullptr;
/* write LibData */
BLO_write_id_struct(writer, Curve, id_address, &cu->id);
@@ -188,7 +188,7 @@ static void curve_blend_write(BlendWriter *writer, ID *id, const void *id_addres
}
}
- if (cu->bevel_profile != NULL) {
+ if (cu->bevel_profile != nullptr) {
BKE_curveprofile_blend_write(writer, cu->bevel_profile);
}
}
@@ -218,13 +218,13 @@ static void curve_blend_read_data(BlendDataReader *reader, ID *id)
BLO_read_data_address(reader, &cu->strinfo);
BLO_read_data_address(reader, &cu->tb);
- if (cu->vfont == NULL) {
+ if (cu->vfont == nullptr) {
BLO_read_list(reader, &(cu->nurb));
}
else {
- cu->nurb.first = cu->nurb.last = NULL;
+ cu->nurb.first = cu->nurb.last = nullptr;
- TextBox *tb = MEM_calloc_arrayN(MAXTEXTBOX, sizeof(TextBox), "TextBoxread");
+ TextBox *tb = (TextBox *)MEM_calloc_arrayN(MAXTEXTBOX, sizeof(TextBox), "TextBoxread");
if (cu->tb) {
memcpy(tb, cu->tb, cu->totbox * sizeof(TextBox));
MEM_freeN(cu->tb);
@@ -241,16 +241,16 @@ static void curve_blend_read_data(BlendDataReader *reader, ID *id)
}
}
- cu->editnurb = NULL;
- cu->editfont = NULL;
- cu->batch_cache = NULL;
+ cu->editnurb = nullptr;
+ cu->editfont = nullptr;
+ cu->batch_cache = nullptr;
LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
BLO_read_data_address(reader, &nu->bezt);
BLO_read_data_address(reader, &nu->bp);
BLO_read_data_address(reader, &nu->knotsu);
BLO_read_data_address(reader, &nu->knotsv);
- if (cu->vfont == NULL) {
+ if (cu->vfont == nullptr) {
nu->charidx = 0;
}
@@ -261,7 +261,7 @@ static void curve_blend_read_data(BlendDataReader *reader, ID *id)
cu->texflag &= ~CU_AUTOSPACE_EVALUATED;
BLO_read_data_address(reader, &cu->bevel_profile);
- if (cu->bevel_profile != NULL) {
+ if (cu->bevel_profile != nullptr) {
BKE_curveprofile_blend_read(reader, cu->bevel_profile);
}
}
@@ -304,34 +304,35 @@ static void curve_blend_read_expand(BlendExpander *expander, ID *id)
}
IDTypeInfo IDType_ID_CU = {
- .id_code = ID_CU,
- .id_filter = FILTER_ID_CU,
- .main_listbase_index = INDEX_ID_CU,
- .struct_size = sizeof(Curve),
- .name = "Curve",
- .name_plural = "curves",
- .translation_context = BLT_I18NCONTEXT_ID_CURVE,
- .flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
-
- .init_data = curve_init_data,
- .copy_data = curve_copy_data,
- .free_data = curve_free_data,
- .make_local = NULL,
- .foreach_id = curve_foreach_id,
- .foreach_cache = NULL,
- .owner_get = NULL,
-
- .blend_write = curve_blend_write,
- .blend_read_data = curve_blend_read_data,
- .blend_read_lib = curve_blend_read_lib,
- .blend_read_expand = curve_blend_read_expand,
-
- .blend_read_undo_preserve = NULL,
-
- .lib_override_apply_post = NULL,
+ /* id_code */ ID_CU,
+ /* id_filter */ FILTER_ID_CU,
+ /* main_listbase_index */ INDEX_ID_CU,
+ /* struct_size */ sizeof(Curve),
+ /* name */ "Curve",
+ /* name_plural */ "curves",
+ /* translation_context */ BLT_I18NCONTEXT_ID_CURVE,
+ /* flags */ IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ /* asset_type_info */ nullptr,
+
+ /* init_data */ curve_init_data,
+ /* copy_data */ curve_copy_data,
+ /* free_data */ curve_free_data,
+ /* make_local */ nullptr,
+ /* foreach_id */ curve_foreach_id,
+ /* foreach_cache */ nullptr,
+ /* foreach_path */ nullptr,
+ /* owner_get */ nullptr,
+
+ /* blend_write */ curve_blend_write,
+ /* blend_read_data */ curve_blend_read_data,
+ /* blend_read_lib */ curve_blend_read_lib,
+ /* blend_read_expand */ curve_blend_read_expand,
+
+ /* blend_read_undo_preserve */ nullptr,
+
+ /* lib_override_apply_post */ nullptr,
};
-/* frees editcurve entirely */
void BKE_curve_editfont_free(Curve *cu)
{
if (cu->editfont) {
@@ -348,21 +349,21 @@ void BKE_curve_editfont_free(Curve *cu)
}
MEM_freeN(ef);
- cu->editfont = NULL;
+ cu->editfont = nullptr;
}
}
static void curve_editNurb_keyIndex_cv_free_cb(void *val)
{
- CVKeyIndex *index = val;
+ CVKeyIndex *index = (CVKeyIndex *)val;
MEM_freeN(index->orig_cv);
MEM_freeN(val);
}
void BKE_curve_editNurb_keyIndex_delCV(GHash *keyindex, const void *cv)
{
- BLI_assert(keyindex != NULL);
- BLI_ghash_remove(keyindex, cv, NULL, curve_editNurb_keyIndex_cv_free_cb);
+ BLI_assert(keyindex != nullptr);
+ BLI_ghash_remove(keyindex, cv, nullptr, curve_editNurb_keyIndex_cv_free_cb);
}
void BKE_curve_editNurb_keyIndex_free(GHash **keyindex)
@@ -370,8 +371,8 @@ void BKE_curve_editNurb_keyIndex_free(GHash **keyindex)
if (!(*keyindex)) {
return;
}
- BLI_ghash_free(*keyindex, NULL, curve_editNurb_keyIndex_cv_free_cb);
- *keyindex = NULL;
+ BLI_ghash_free(*keyindex, nullptr, curve_editNurb_keyIndex_cv_free_cb);
+ *keyindex = nullptr;
}
void BKE_curve_editNurb_free(Curve *cu)
@@ -380,7 +381,7 @@ void BKE_curve_editNurb_free(Curve *cu)
BKE_nurbList_free(&cu->editnurb->nurbs);
BKE_curve_editNurb_keyIndex_free(&cu->editnurb->keyindex);
MEM_freeN(cu->editnurb);
- cu->editnurb = NULL;
+ cu->editnurb = nullptr;
}
}
@@ -394,12 +395,12 @@ void BKE_curve_init(Curve *cu, const short curve_type)
cu->flag |= CU_FRONT | CU_BACK;
cu->vfont = cu->vfontb = cu->vfonti = cu->vfontbi = BKE_vfont_builtin_get();
cu->vfont->id.us += 4;
- cu->str = MEM_malloc_arrayN(12, sizeof(unsigned char), "str");
+ cu->str = (char *)MEM_malloc_arrayN(12, sizeof(unsigned char), "str");
BLI_strncpy(cu->str, "Text", 12);
cu->len = cu->len_char32 = cu->pos = 4;
- cu->strinfo = MEM_calloc_arrayN(12, sizeof(CharInfo), "strinfo new");
+ cu->strinfo = (CharInfo *)MEM_calloc_arrayN(12, sizeof(CharInfo), "strinfo new");
cu->totbox = cu->actbox = 1;
- cu->tb = MEM_calloc_arrayN(MAXTEXTBOX, sizeof(TextBox), "textbox");
+ cu->tb = (TextBox *)MEM_calloc_arrayN(MAXTEXTBOX, sizeof(TextBox), "textbox");
cu->tb[0].w = cu->tb[0].h = 0.0;
}
else if (cu->type == OB_SURF) {
@@ -407,7 +408,7 @@ void BKE_curve_init(Curve *cu, const short curve_type)
cu->resolu = 4;
cu->resolv = 4;
}
- cu->bevel_profile = NULL;
+ cu->bevel_profile = nullptr;
}
Curve *BKE_curve_add(Main *bmain, const char *name, int type)
@@ -415,21 +416,20 @@ Curve *BKE_curve_add(Main *bmain, const char *name, int type)
Curve *cu;
/* We cannot use #BKE_id_new here as we need some custom initialization code. */
- cu = BKE_libblock_alloc(bmain, ID_CU, name, 0);
+ cu = (Curve *)BKE_libblock_alloc(bmain, ID_CU, name, 0);
BKE_curve_init(cu, type);
return cu;
}
-/* Get list of nurbs from editnurbs structure */
ListBase *BKE_curve_editNurbs_get(Curve *cu)
{
if (cu->editnurb) {
return &cu->editnurb->nurbs;
}
- return NULL;
+ return nullptr;
}
const ListBase *BKE_curve_editNurbs_get_for_read(const Curve *cu)
@@ -438,7 +438,7 @@ const ListBase *BKE_curve_editNurbs_get_for_read(const Curve *cu)
return &cu->editnurb->nurbs;
}
- return NULL;
+ return nullptr;
}
short BKE_curve_type_get(const Curve *cu)
@@ -481,10 +481,10 @@ void BKE_curve_dimension_update(Curve *cu)
void BKE_curve_type_test(Object *ob)
{
- ob->type = BKE_curve_type_get(ob->data);
+ ob->type = BKE_curve_type_get((Curve *)ob->data);
if (ob->type == OB_CURVE) {
- Curve *cu = ob->data;
+ Curve *cu = (Curve *)ob->data;
if (CU_IS_2D(cu)) {
BKE_curve_dimension_update(cu);
}
@@ -495,15 +495,15 @@ BoundBox *BKE_curve_boundbox_get(Object *ob)
{
/* This is Object-level data access,
* DO NOT touch to Mesh's bb, would be totally thread-unsafe. */
- if (ob->runtime.bb == NULL || ob->runtime.bb->flag & BOUNDBOX_DIRTY) {
- Curve *cu = ob->data;
+ if (ob->runtime.bb == nullptr || ob->runtime.bb->flag & BOUNDBOX_DIRTY) {
+ Curve *cu = (Curve *)ob->data;
float min[3], max[3];
INIT_MINMAX(min, max);
BKE_curve_minmax(cu, true, min, max);
- if (ob->runtime.bb == NULL) {
- ob->runtime.bb = MEM_mallocN(sizeof(*ob->runtime.bb), __func__);
+ if (ob->runtime.bb == nullptr) {
+ ob->runtime.bb = (BoundBox *)MEM_mallocN(sizeof(*ob->runtime.bb), __func__);
}
BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY;
@@ -618,26 +618,26 @@ int BKE_nurbList_verts_count_without_handles(const ListBase *nurb)
void BKE_nurb_free(Nurb *nu)
{
- if (nu == NULL) {
+ if (nu == nullptr) {
return;
}
if (nu->bezt) {
MEM_freeN(nu->bezt);
}
- nu->bezt = NULL;
+ nu->bezt = nullptr;
if (nu->bp) {
MEM_freeN(nu->bp);
}
- nu->bp = NULL;
+ nu->bp = nullptr;
if (nu->knotsu) {
MEM_freeN(nu->knotsu);
}
- nu->knotsu = NULL;
+ nu->knotsu = nullptr;
if (nu->knotsv) {
MEM_freeN(nu->knotsv);
}
- nu->knotsv = NULL;
+ nu->knotsv = nullptr;
// if (nu->trim.first) freeNurblist(&(nu->trim));
MEM_freeN(nu);
@@ -645,7 +645,7 @@ void BKE_nurb_free(Nurb *nu)
void BKE_nurbList_free(ListBase *lb)
{
- if (lb == NULL) {
+ if (lb == nullptr) {
return;
}
@@ -661,8 +661,8 @@ Nurb *BKE_nurb_duplicate(const Nurb *nu)
int len;
newnu = (Nurb *)MEM_mallocN(sizeof(Nurb), "duplicateNurb");
- if (newnu == NULL) {
- return NULL;
+ if (newnu == nullptr) {
+ return nullptr;
}
memcpy(newnu, nu, sizeof(Nurb));
@@ -675,19 +675,19 @@ Nurb *BKE_nurb_duplicate(const Nurb *nu)
newnu->bp = (BPoint *)MEM_malloc_arrayN(len, sizeof(BPoint), "duplicateNurb3");
memcpy(newnu->bp, nu->bp, len * sizeof(BPoint));
- newnu->knotsu = newnu->knotsv = NULL;
+ newnu->knotsu = newnu->knotsv = nullptr;
if (nu->knotsu) {
len = KNOTSU(nu);
if (len) {
- newnu->knotsu = MEM_malloc_arrayN(len, sizeof(float), "duplicateNurb4");
+ newnu->knotsu = (float *)MEM_malloc_arrayN(len, sizeof(float), "duplicateNurb4");
memcpy(newnu->knotsu, nu->knotsu, sizeof(float) * len);
}
}
if (nu->pntsv > 1 && nu->knotsv) {
len = KNOTSV(nu);
if (len) {
- newnu->knotsv = MEM_malloc_arrayN(len, sizeof(float), "duplicateNurb5");
+ newnu->knotsv = (float *)MEM_malloc_arrayN(len, sizeof(float), "duplicateNurb5");
memcpy(newnu->knotsv, nu->knotsv, sizeof(float) * len);
}
}
@@ -695,7 +695,6 @@ Nurb *BKE_nurb_duplicate(const Nurb *nu)
return newnu;
}
-/* copy the nurb but allow for different number of points (to be copied after this) */
Nurb *BKE_nurb_copy(Nurb *src, int pntsu, int pntsv)
{
Nurb *newnu = (Nurb *)MEM_mallocN(sizeof(Nurb), "copyNurb");
@@ -708,8 +707,8 @@ Nurb *BKE_nurb_copy(Nurb *src, int pntsu, int pntsv)
newnu->pntsv = pntsv;
/* caller can manually handle these arrays */
- newnu->knotsu = NULL;
- newnu->knotsv = NULL;
+ newnu->knotsu = nullptr;
+ newnu->knotsv = nullptr;
if (src->bezt) {
newnu->bezt = (BezTriple *)MEM_malloc_arrayN(pntsu * pntsv, sizeof(BezTriple), "copyNurb2");
@@ -757,10 +756,6 @@ void BKE_nurb_project_2d(Nurb *nu)
}
}
-/**
- * if use_radius is truth, minmax will take points' radius into account,
- * which will make boundbox closer to beveled curve.
- */
void BKE_nurb_minmax(const Nurb *nu, bool use_radius, float min[3], float max[3])
{
BezTriple *bezt;
@@ -842,7 +837,7 @@ float BKE_nurb_calc_length(const Nurb *nu, int resolution)
}
}
else if (nu->type == CU_BEZIER) {
- points = MEM_mallocN(sizeof(float[3]) * (resolu + 1), "getLength_bezier");
+ points = (float *)MEM_mallocN(sizeof(float[3]) * (resolu + 1), "getLength_bezier");
a = nu->pntsu - 1;
bezt = nu->bezt;
if (nu->flagu & CU_NURB_CYCLIC) {
@@ -886,9 +881,9 @@ float BKE_nurb_calc_length(const Nurb *nu, int resolution)
else if (nu->type == CU_NURBS) {
if (nu->pntsv == 1) {
/* important to zero for BKE_nurb_makeCurve. */
- points = MEM_callocN(sizeof(float[3]) * pntsu * resolu, "getLength_nurbs");
+ points = (float *)MEM_callocN(sizeof(float[3]) * pntsu * resolu, "getLength_nurbs");
- BKE_nurb_makeCurve(nu, points, NULL, NULL, NULL, resolu, sizeof(float[3]));
+ BKE_nurb_makeCurve(nu, points, nullptr, nullptr, nullptr, resolu, sizeof(float[3]));
if (nu->flagu & CU_NURB_CYCLIC) {
b = pntsu * resolu + 1;
@@ -914,10 +909,9 @@ float BKE_nurb_calc_length(const Nurb *nu, int resolution)
return length;
}
-/* be sure to call makeknots after this */
void BKE_nurb_points_add(Nurb *nu, int number)
{
- nu->bp = MEM_recallocN(nu->bp, (nu->pntsu + number) * sizeof(BPoint));
+ nu->bp = (BPoint *)MEM_recallocN(nu->bp, (nu->pntsu + number) * sizeof(BPoint));
BPoint *bp;
int i;
@@ -933,7 +927,7 @@ void BKE_nurb_bezierPoints_add(Nurb *nu, int number)
BezTriple *bezt;
int i;
- nu->bezt = MEM_recallocN(nu->bezt, (nu->pntsu + number) * sizeof(BezTriple));
+ nu->bezt = (BezTriple *)MEM_recallocN(nu->bezt, (nu->pntsu + number) * sizeof(BezTriple));
for (i = 0, bezt = &nu->bezt[nu->pntsu]; i < number; i++, bezt++) {
bezt->radius = 1.0f;
@@ -984,7 +978,7 @@ BezTriple *BKE_nurb_bezt_get_next(Nurb *nu, BezTriple *bezt)
bezt_next = nu->bezt;
}
else {
- bezt_next = NULL;
+ bezt_next = nullptr;
}
}
else {
@@ -1005,7 +999,7 @@ BPoint *BKE_nurb_bpoint_get_next(Nurb *nu, BPoint *bp)
bp_next = nu->bp;
}
else {
- bp_next = NULL;
+ bp_next = nullptr;
}
}
else {
@@ -1027,7 +1021,7 @@ BezTriple *BKE_nurb_bezt_get_prev(Nurb *nu, BezTriple *bezt)
bezt_prev = &nu->bezt[nu->pntsu - 1];
}
else {
- bezt_prev = NULL;
+ bezt_prev = nullptr;
}
}
else {
@@ -1049,7 +1043,7 @@ BPoint *BKE_nurb_bpoint_get_prev(Nurb *nu, BPoint *bp)
bp_prev = &nu->bp[nu->pntsu - 1];
}
else {
- bp_prev = NULL;
+ bp_prev = nullptr;
}
}
else {
@@ -1217,7 +1211,7 @@ static void makecyclicknots(float *knots, int pnts, short order)
{
int a, b, order2, c;
- if (knots == NULL) {
+ if (knots == nullptr) {
return;
}
@@ -1252,7 +1246,7 @@ static void makeknots(Nurb *nu, short uv)
MEM_freeN(nu->knotsu);
}
if (BKE_nurb_check_valid_u(nu)) {
- nu->knotsu = MEM_calloc_arrayN(KNOTSU(nu) + 1, sizeof(float), "makeknots");
+ nu->knotsu = (float *)MEM_calloc_arrayN(KNOTSU(nu) + 1, sizeof(float), "makeknots");
if (nu->flagu & CU_NURB_CYCLIC) {
calcknots(nu->knotsu, nu->pntsu, nu->orderu, 0); /* cyclic should be uniform */
makecyclicknots(nu->knotsu, nu->pntsu, nu->orderu);
@@ -1262,7 +1256,7 @@ static void makeknots(Nurb *nu, short uv)
}
}
else {
- nu->knotsu = NULL;
+ nu->knotsu = nullptr;
}
}
else if (uv == 2) {
@@ -1270,7 +1264,7 @@ static void makeknots(Nurb *nu, short uv)
MEM_freeN(nu->knotsv);
}
if (BKE_nurb_check_valid_v(nu)) {
- nu->knotsv = MEM_calloc_arrayN(KNOTSV(nu) + 1, sizeof(float), "makeknots");
+ nu->knotsv = (float *)MEM_calloc_arrayN(KNOTSV(nu) + 1, sizeof(float), "makeknots");
if (nu->flagv & CU_NURB_CYCLIC) {
calcknots(nu->knotsv, nu->pntsv, nu->orderv, 0); /* cyclic should be uniform */
makecyclicknots(nu->knotsv, nu->pntsv, nu->orderv);
@@ -1280,7 +1274,7 @@ static void makeknots(Nurb *nu, short uv)
}
}
else {
- nu->knotsv = NULL;
+ nu->knotsv = nullptr;
}
}
}
@@ -1374,9 +1368,6 @@ static void basisNurb(
}
}
-/**
- * \param coord_array: has to be (3 * 4 * resolu * resolv) in size, and zero-ed.
- */
void BKE_nurb_makeFaces(const Nurb *nu, float *coord_array, int rowstride, int resolu, int resolv)
{
BPoint *bp;
@@ -1387,7 +1378,7 @@ void BKE_nurb_makeFaces(const Nurb *nu, float *coord_array, int rowstride, int r
int totu = nu->pntsu * resolu, totv = nu->pntsv * resolv;
- if (nu->knotsu == NULL || nu->knotsv == NULL) {
+ if (nu->knotsu == nullptr || nu->knotsv == nullptr) {
return;
}
if (nu->orderu > nu->pntsu) {
@@ -1396,7 +1387,7 @@ void BKE_nurb_makeFaces(const Nurb *nu, float *coord_array, int rowstride, int r
if (nu->orderv > nu->pntsv) {
return;
}
- if (coord_array == NULL) {
+ if (coord_array == nullptr) {
return;
}
@@ -1447,7 +1438,7 @@ void BKE_nurb_makeFaces(const Nurb *nu, float *coord_array, int rowstride, int r
jstart = (int *)MEM_malloc_arrayN(totv, sizeof(float), "makeNurbfaces4");
jend = (int *)MEM_malloc_arrayN(totv, sizeof(float), "makeNurbfaces5");
- /* precalculation of basisv and jstart, jend */
+ /* Pre-calculation of `basisv` and `jstart`, `jend`. */
if (nu->flagv & CU_NURB_CYCLIC) {
cycl = nu->orderv - 1;
}
@@ -1569,11 +1560,6 @@ void BKE_nurb_makeFaces(const Nurb *nu, float *coord_array, int rowstride, int r
MEM_freeN(jend);
}
-/**
- * \param coord_array: Has to be 3 * 4 * pntsu * resolu in size and zero-ed
- * \param tilt_array: set when non-NULL
- * \param radius_array: set when non-NULL
- */
void BKE_nurb_makeCurve(const Nurb *nu,
float *coord_array,
float *tilt_array,
@@ -1590,13 +1576,13 @@ void BKE_nurb_makeCurve(const Nurb *nu,
*weight_fp = weight_array;
int i, len, istart, iend, cycl;
- if (nu->knotsu == NULL) {
+ if (nu->knotsu == nullptr) {
return;
}
if (nu->orderu > nu->pntsu) {
return;
}
- if (coord_array == NULL) {
+ if (coord_array == nullptr) {
return;
}
@@ -1690,16 +1676,16 @@ void BKE_nurb_makeCurve(const Nurb *nu,
}
}
- coord_fp = POINTER_OFFSET(coord_fp, stride);
+ coord_fp = (float *)POINTER_OFFSET(coord_fp, stride);
if (tilt_fp) {
- tilt_fp = POINTER_OFFSET(tilt_fp, stride);
+ tilt_fp = (float *)POINTER_OFFSET(tilt_fp, stride);
}
if (radius_fp) {
- radius_fp = POINTER_OFFSET(radius_fp, stride);
+ radius_fp = (float *)POINTER_OFFSET(radius_fp, stride);
}
if (weight_fp) {
- weight_fp = POINTER_OFFSET(weight_fp, stride);
+ weight_fp = (float *)POINTER_OFFSET(weight_fp, stride);
}
u += ustep;
@@ -1710,9 +1696,6 @@ void BKE_nurb_makeCurve(const Nurb *nu,
MEM_freeN(basisu);
}
-/**
- * Calculate the length for arrays filled in by #BKE_curve_calc_coords_axis.
- */
unsigned int BKE_curve_calc_coords_axis_len(const unsigned int bezt_array_len,
const unsigned int resolu,
const bool is_cyclic,
@@ -1724,12 +1707,6 @@ unsigned int BKE_curve_calc_coords_axis_len(const unsigned int bezt_array_len,
return points_len;
}
-/**
- * Calculate an array for the entire curve (cyclic or non-cyclic).
- * \note Call for each axis.
- *
- * \param use_cyclic_duplicate_endpoint: Duplicate values at the beginning & end of the array.
- */
void BKE_curve_calc_coords_axis(const BezTriple *bezt_array,
const unsigned int bezt_array_len,
const unsigned int resolu,
@@ -1757,7 +1734,7 @@ void BKE_curve_calc_coords_axis(const BezTriple *bezt_array,
r_points_offset,
(int)resolu,
stride);
- r_points_offset = POINTER_OFFSET(r_points_offset, resolu_stride);
+ r_points_offset = (float *)POINTER_OFFSET(r_points_offset, resolu_stride);
}
if (is_cyclic) {
@@ -1770,23 +1747,22 @@ void BKE_curve_calc_coords_axis(const BezTriple *bezt_array,
r_points_offset,
(int)resolu,
stride);
- r_points_offset = POINTER_OFFSET(r_points_offset, resolu_stride);
+ r_points_offset = (float *)POINTER_OFFSET(r_points_offset, resolu_stride);
if (use_cyclic_duplicate_endpoint) {
*r_points_offset = *r_points;
- r_points_offset = POINTER_OFFSET(r_points_offset, stride);
+ r_points_offset = (float *)POINTER_OFFSET(r_points_offset, stride);
}
}
else {
- float *r_points_last = POINTER_OFFSET(r_points, bezt_array_last * resolu_stride);
+ float *r_points_last = (float *)POINTER_OFFSET(r_points, bezt_array_last * resolu_stride);
*r_points_last = bezt_array[bezt_array_last].vec[1][axis];
- r_points_offset = POINTER_OFFSET(r_points_offset, stride);
+ r_points_offset = (float *)POINTER_OFFSET(r_points_offset, stride);
}
- BLI_assert(POINTER_OFFSET(r_points, points_len * stride) == r_points_offset);
+ BLI_assert((float *)POINTER_OFFSET(r_points, points_len * stride) == r_points_offset);
UNUSED_VARS_NDEBUG(points_len);
}
-/* forward differencing method for bezier curve */
void BKE_curve_forward_diff_bezier(
float q0, float q1, float q2, float q3, float *p, int it, int stride)
{
@@ -1808,14 +1784,13 @@ void BKE_curve_forward_diff_bezier(
for (a = 0; a <= it; a++) {
*p = q0;
- p = POINTER_OFFSET(p, stride);
+ p = (float *)POINTER_OFFSET(p, stride);
q0 += q1;
q1 += q2;
q2 += q3;
}
}
-/* forward differencing method for first derivative of cubic bezier curve */
void BKE_curve_forward_diff_tangent_bezier(
float q0, float q1, float q2, float q3, float *p, int it, int stride)
{
@@ -1834,7 +1809,7 @@ void BKE_curve_forward_diff_tangent_bezier(
for (a = 0; a <= it; a++) {
*p = q0;
- p = POINTER_OFFSET(p, stride);
+ p = (float *)POINTER_OFFSET(p, stride);
q0 += q1;
q1 += q2;
}
@@ -1860,7 +1835,7 @@ static void forward_diff_bezier_cotangent(const float p0[3],
(-18.0f * t + 6.0f) * p2[i] + (6.0f * t) * p3[i];
}
normalize_v3(p);
- p = POINTER_OFFSET(p, stride);
+ p = (float *)POINTER_OFFSET(p, stride);
}
}
@@ -1973,7 +1948,7 @@ struct BevelSort {
static int vergxcobev(const void *a1, const void *a2)
{
- const struct BevelSort *x1 = a1, *x2 = a2;
+ const struct BevelSort *x1 = (BevelSort *)a1, *x2 = (BevelSort *)a2;
if (x1->left > x2->left) {
return 1;
@@ -2047,7 +2022,7 @@ static void tilt_bezpart(const BezTriple *prevbezt,
float fac, dfac, t[4];
int a;
- if (tilt_array == NULL && radius_array == NULL) {
+ if (tilt_array == nullptr && radius_array == nullptr) {
return;
}
@@ -2095,7 +2070,7 @@ static void tilt_bezpart(const BezTriple *prevbezt,
t[3] * next->tilt;
}
- tilt_array = POINTER_OFFSET(tilt_array, stride);
+ tilt_array = (float *)POINTER_OFFSET(tilt_array, stride);
}
if (radius_array) {
@@ -2109,14 +2084,14 @@ static void tilt_bezpart(const BezTriple *prevbezt,
else {
/* reuse interpolation from tilt if we can */
- if (tilt_array == NULL || nu->tilt_interp != nu->radius_interp) {
+ if (tilt_array == nullptr || nu->tilt_interp != nu->radius_interp) {
key_curve_position_weights(fac, t, nu->radius_interp);
}
*radius_array = t[0] * pprev->radius + t[1] * prevbezt->radius + t[2] * bezt->radius +
t[3] * next->radius;
}
- radius_array = POINTER_OFFSET(radius_array, stride);
+ radius_array = (float *)POINTER_OFFSET(radius_array, stride);
}
if (weight_array) {
@@ -2124,15 +2099,15 @@ static void tilt_bezpart(const BezTriple *prevbezt,
*weight_array = prevbezt->weight + (bezt->weight - prevbezt->weight) *
(3.0f * fac * fac - 2.0f * fac * fac * fac);
- weight_array = POINTER_OFFSET(weight_array, stride);
+ weight_array = (float *)POINTER_OFFSET(weight_array, stride);
}
}
}
-/* make_bevel_list_3D_* funcs, at a minimum these must
- * fill in the bezp->quat and bezp->dir values */
+/* `make_bevel_list_3D_*` functions, at a minimum these must
+ * fill in the #BevPoint.quat and #BevPoint.dir values. */
-/* utility for make_bevel_list_3D_* funcs */
+/** Utility for `make_bevel_list_3D_*` functions. */
static void bevel_list_calc_bisect(BevList *bl)
{
BevPoint *bevp2, *bevp1, *bevp0;
@@ -2354,14 +2329,14 @@ static void make_bevel_list_3D_minimum_twist(BevList *bl)
/* Need to correct for the start/end points not matching
* do this by calculating the tilt angle difference, then apply
- * the rotation gradually over the entire curve
+ * the rotation gradually over the entire curve.
*
- * note that the split is between last and second last, rather than first/last as youd expect.
+ * Note that the split is between last and second last, rather than first/last as you'd expect.
*
* real order is like this
* 0,1,2,3,4 --> 1,2,3,4,0
*
- * this is why we compare last with second last
+ * This is why we compare last with second last.
*/
float vec_1[3] = {0, 1, 0}, vec_2[3] = {0, 1, 0}, angle, ang_fac, cross_tmp[3];
@@ -2622,13 +2597,13 @@ static void bevlist_firstlast_direction_calc_from_bpoint(const Nurb *nu, BevList
void BKE_curve_bevelList_free(ListBase *bev)
{
LISTBASE_FOREACH_MUTABLE (BevList *, bl, bev) {
- if (bl->seglen != NULL) {
+ if (bl->seglen != nullptr) {
MEM_freeN(bl->seglen);
}
- if (bl->segbevcount != NULL) {
+ if (bl->segbevcount != nullptr) {
MEM_freeN(bl->segbevcount);
}
- if (bl->bevpoints != NULL) {
+ if (bl->bevpoints != nullptr) {
MEM_freeN(bl->bevpoints);
}
MEM_freeN(bl);
@@ -2639,22 +2614,21 @@ void BKE_curve_bevelList_free(ListBase *bev)
void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_render)
{
- /*
- * - convert all curves to polys, with indication of resol and flags for double-vertices
- * - possibly; do a smart vertice removal (in case Nurb)
- * - separate in individual blocks with BoundBox
- * - AutoHole detection
+ /* - Convert all curves to polys, with indication of resolution and flags for double-vertices.
+ * - Possibly; do a smart vertex removal (in case #Nurb).
+ * - Separate in individual blocks with #BoundBox.
+ * - Auto-hole detection.
*/
- /* this function needs an object, because of tflag and upflag */
- Curve *cu = ob->data;
+ /* This function needs an object, because of `tflag` and `upflag`. */
+ Curve *cu = (Curve *)ob->data;
BezTriple *bezt, *prevbezt;
BPoint *bp;
BevList *blnew;
- BevPoint *bevp2, *bevp1 = NULL, *bevp0;
+ BevPoint *bevp2, *bevp1 = nullptr, *bevp0;
const float threshold = 0.00001f;
float min, inp;
- float *seglen = NULL;
+ float *seglen = nullptr;
struct BevelSort *sortdata, *sd, *sd1;
int a, b, nr, poly, resolu = 0, len = 0, segcount;
int *segbevcount;
@@ -2662,7 +2636,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
bool is_editmode = false;
ListBase *bev;
- /* segbevcount alsp requires seglen. */
+ /* segbevcount also requires seglen. */
const bool need_seglen = ELEM(
cu->bevfac1_mapping, CU_BEVFAC_MAP_SEGMENT, CU_BEVFAC_MAP_SPLINE) ||
ELEM(cu->bevfac2_mapping, CU_BEVFAC_MAP_SEGMENT, CU_BEVFAC_MAP_SPLINE);
@@ -2679,7 +2653,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
BKE_curve_bevelList_free(&ob->runtime.curve_cache->bev);
if (cu->editnurb && ob->type != OB_FONT) {
- is_editmode = 1;
+ is_editmode = true;
}
LISTBASE_FOREACH (const Nurb *, nu, nurbs) {
@@ -2690,8 +2664,8 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
/* check we are a single point? also check we are not a surface and that the orderu is sane,
* enforced in the UI but can go wrong possibly */
if (!BKE_nurb_check_valid_u(nu)) {
- BevList *bl = MEM_callocN(sizeof(BevList), "makeBevelList1");
- bl->bevpoints = MEM_calloc_arrayN(1, sizeof(BevPoint), "makeBevelPoints1");
+ BevList *bl = (BevList *)MEM_callocN(sizeof(BevList), "makeBevelList1");
+ bl->bevpoints = (BevPoint *)MEM_calloc_arrayN(1, sizeof(BevPoint), "makeBevelPoints1");
BLI_addtail(bev, bl);
bl->nr = 0;
bl->charidx = nu->charidx;
@@ -2720,11 +2694,11 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
if (nu->type == CU_POLY) {
len = nu->pntsu;
- BevList *bl = MEM_callocN(sizeof(BevList), "makeBevelList2");
- bl->bevpoints = MEM_calloc_arrayN(len, sizeof(BevPoint), "makeBevelPoints2");
+ BevList *bl = (BevList *)MEM_callocN(sizeof(BevList), __func__);
+ bl->bevpoints = (BevPoint *)MEM_calloc_arrayN(len, sizeof(BevPoint), __func__);
if (need_seglen && (nu->flagu & CU_NURB_CYCLIC) == 0) {
- bl->seglen = MEM_malloc_arrayN(segcount, sizeof(float), "makeBevelList2_seglen");
- bl->segbevcount = MEM_malloc_arrayN(segcount, sizeof(int), "makeBevelList2_segbevcount");
+ bl->seglen = (float *)MEM_malloc_arrayN(segcount, sizeof(float), __func__);
+ bl->segbevcount = (int *)MEM_malloc_arrayN(segcount, sizeof(int), __func__);
}
BLI_addtail(bev, bl);
@@ -2744,7 +2718,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
bevp->radius = bp->radius;
bevp->weight = bp->weight;
bp++;
- if (seglen != NULL && len != 0) {
+ if (seglen != nullptr && len != 0) {
*seglen = len_v3v3(bevp->vec, bp->vec);
bevp++;
bevp->offset = *seglen;
@@ -2770,11 +2744,11 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
/* in case last point is not cyclic */
len = segcount * resolu + 1;
- BevList *bl = MEM_callocN(sizeof(BevList), "makeBevelBPoints");
- bl->bevpoints = MEM_calloc_arrayN(len, sizeof(BevPoint), "makeBevelBPointsPoints");
+ BevList *bl = (BevList *)MEM_callocN(sizeof(BevList), __func__);
+ bl->bevpoints = (BevPoint *)MEM_calloc_arrayN(len, sizeof(BevPoint), __func__);
if (need_seglen && (nu->flagu & CU_NURB_CYCLIC) == 0) {
- bl->seglen = MEM_malloc_arrayN(segcount, sizeof(float), "makeBevelBPoints_seglen");
- bl->segbevcount = MEM_malloc_arrayN(segcount, sizeof(int), "makeBevelBPoints_segbevcount");
+ bl->seglen = (float *)MEM_malloc_arrayN(segcount, sizeof(float), __func__);
+ bl->segbevcount = (int *)MEM_malloc_arrayN(segcount, sizeof(int), __func__);
}
BLI_addtail(bev, bl);
@@ -2786,7 +2760,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
segbevcount = bl->segbevcount;
bevp->offset = 0;
- if (seglen != NULL) {
+ if (seglen != nullptr) {
*seglen = 0;
*segbevcount = 0;
}
@@ -2818,7 +2792,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
bevp++;
bl->nr++;
bl->dupe_nr = 1;
- if (seglen != NULL) {
+ if (seglen != nullptr) {
*seglen = len_v3v3(prevbezt->vec[1], bezt->vec[1]);
bevp->offset = *seglen;
seglen++;
@@ -2830,10 +2804,10 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
}
}
else {
- /* always do all three, to prevent data hanging around */
+ /* Always do all three, to prevent data hanging around. */
int j;
- /* BevPoint must stay aligned to 4 so sizeof(BevPoint)/sizeof(float) works */
+ /* #BevPoint must stay aligned to 4 so `sizeof(BevPoint) / sizeof(float)` works. */
for (j = 0; j < 3; j++) {
BKE_curve_forward_diff_bezier(prevbezt->vec[1][j],
prevbezt->vec[2][j],
@@ -2844,13 +2818,13 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
sizeof(BevPoint));
}
- /* if both arrays are NULL do nothiong */
+ /* If both arrays are `nullptr` do nothing. */
tilt_bezpart(prevbezt,
bezt,
nu,
- do_tilt ? &bevp->tilt : NULL,
- do_radius ? &bevp->radius : NULL,
- do_weight ? &bevp->weight : NULL,
+ do_tilt ? &bevp->tilt : nullptr,
+ do_radius ? &bevp->radius : nullptr,
+ do_weight ? &bevp->weight : nullptr,
resolu,
sizeof(BevPoint));
@@ -2864,15 +2838,15 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
sizeof(BevPoint));
}
- /* seglen */
- if (seglen != NULL) {
+ /* `seglen`. */
+ if (seglen != nullptr) {
*seglen = 0;
*segbevcount = 0;
for (j = 0; j < resolu; j++) {
bevp0 = bevp;
bevp++;
bevp->offset = len_v3v3(bevp0->vec, bevp->vec);
- /* match seglen and segbevcount to the cleaned up bevel lists (see STEP 2) */
+ /* Match `seglen` and `segbevcount` to the cleaned up bevel lists (see STEP 2). */
if (bevp->offset > threshold) {
*seglen += bevp->offset;
*segbevcount += 1;
@@ -2906,11 +2880,11 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
if (nu->pntsv == 1) {
len = (resolu * segcount);
- BevList *bl = MEM_callocN(sizeof(BevList), "makeBevelList3");
- bl->bevpoints = MEM_calloc_arrayN(len, sizeof(BevPoint), "makeBevelPoints3");
+ BevList *bl = (BevList *)MEM_callocN(sizeof(BevList), __func__);
+ bl->bevpoints = (BevPoint *)MEM_calloc_arrayN(len, sizeof(BevPoint), __func__);
if (need_seglen && (nu->flagu & CU_NURB_CYCLIC) == 0) {
- bl->seglen = MEM_malloc_arrayN(segcount, sizeof(float), "makeBevelList3_seglen");
- bl->segbevcount = MEM_malloc_arrayN(segcount, sizeof(int), "makeBevelList3_segbevcount");
+ bl->seglen = (float *)MEM_malloc_arrayN(segcount, sizeof(float), __func__);
+ bl->segbevcount = (int *)MEM_malloc_arrayN(segcount, sizeof(int), __func__);
}
BLI_addtail(bev, bl);
bl->nr = len;
@@ -2924,14 +2898,14 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
BKE_nurb_makeCurve(nu,
&bevp->vec[0],
- do_tilt ? &bevp->tilt : NULL,
- do_radius ? &bevp->radius : NULL,
- do_weight ? &bevp->weight : NULL,
+ do_tilt ? &bevp->tilt : nullptr,
+ do_radius ? &bevp->radius : nullptr,
+ do_weight ? &bevp->weight : nullptr,
resolu,
sizeof(BevPoint));
/* match seglen and segbevcount to the cleaned up bevel lists (see STEP 2) */
- if (seglen != NULL) {
+ if (seglen != nullptr) {
nr = segcount;
bevp0 = bevp;
bevp++;
@@ -2983,7 +2957,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
}
nr--;
while (nr--) {
- if (seglen != NULL) {
+ if (seglen != nullptr) {
if (fabsf(bevp1->offset) < threshold) {
bevp0->dupe_tag = true;
bl->dupe_nr++;
@@ -3005,10 +2979,10 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
continue;
}
- nr = bl->nr - bl->dupe_nr + 1; /* +1 because vectorbezier sets flag too */
- blnew = MEM_mallocN(sizeof(BevList), "makeBevelList4");
+ nr = bl->nr - bl->dupe_nr + 1; /* +1 because vector-bezier sets flag too. */
+ blnew = (BevList *)MEM_mallocN(sizeof(BevList), "makeBevelList4");
memcpy(blnew, bl, sizeof(BevList));
- blnew->bevpoints = MEM_calloc_arrayN(nr, sizeof(BevPoint), "makeBevelPoints4");
+ blnew->bevpoints = (BevPoint *)MEM_calloc_arrayN(nr, sizeof(BevPoint), "makeBevelPoints4");
if (!blnew->bevpoints) {
MEM_freeN(blnew);
break;
@@ -3017,7 +2991,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
blnew->seglen = bl->seglen;
blnew->nr = 0;
BLI_remlink(bev, bl);
- BLI_insertlinkbefore(bev, bl->next, blnew); /* to make sure bevlist is tuned with nurblist */
+ BLI_insertlinkbefore(bev, bl->next, blnew); /* Ensure `bevlist` is tuned with `nurblist`. */
bevp0 = bl->bevpoints;
bevp1 = blnew->bevpoints;
nr = bl->nr;
@@ -3029,7 +3003,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
}
bevp0++;
}
- if (bl->bevpoints != NULL) {
+ if (bl->bevpoints != nullptr) {
MEM_freeN(bl->bevpoints);
}
MEM_freeN(bl);
@@ -3048,7 +3022,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
/* find extreme left points, also test (turning) direction */
if (poly > 0) {
- sd = sortdata = MEM_malloc_arrayN(poly, sizeof(struct BevelSort), "makeBevelList5");
+ sd = sortdata = (BevelSort *)MEM_malloc_arrayN(poly, sizeof(struct BevelSort), __func__);
LISTBASE_FOREACH (BevList *, bl, bev) {
if (bl->poly > 0) {
BevPoint *bevp;
@@ -3139,7 +3113,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
BevPoint *bevp = bl->bevpoints;
unit_qt(bevp->quat);
}
- else if (bl->nr == 2) { /* 2 pnt, treat separate */
+ else if (bl->nr == 2) { /* 2 points, treat separately. */
make_bevel_list_segment_2D(bl);
}
else {
@@ -3154,7 +3128,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
BevPoint *bevp = bl->bevpoints;
unit_qt(bevp->quat);
}
- else if (bl->nr == 2) { /* 2 pnt, treat separate */
+ else if (bl->nr == 2) { /* 2 points, treat separately. */
make_bevel_list_segment_3D(bl);
}
else {
@@ -3194,7 +3168,7 @@ static void calchandleNurb_intern(BezTriple *bezt,
p2 = bezt->vec[1];
- if (prev == NULL) {
+ if (prev == nullptr) {
p3 = next->vec[1];
pt[0] = 2.0f * p2[0] - p3[0];
pt[1] = 2.0f * p2[1] - p3[1];
@@ -3205,7 +3179,7 @@ static void calchandleNurb_intern(BezTriple *bezt,
p1 = prev->vec[1];
}
- if (next == NULL) {
+ if (next == nullptr) {
pt[0] = 2.0f * p2[0] - p1[0];
pt[1] = 2.0f * p2[1] - p1[1];
pt[2] = 2.0f * p2[2] - p1[2];
@@ -3283,13 +3257,13 @@ static void calchandleNurb_intern(BezTriple *bezt,
if (ydiff1 <= 0.0f) {
if (prev->vec[1][1] > bezt->vec[0][1]) {
bezt->vec[0][1] = prev->vec[1][1];
- leftviolate = 1;
+ leftviolate = true;
}
}
else {
if (prev->vec[1][1] < bezt->vec[0][1]) {
bezt->vec[0][1] = prev->vec[1][1];
- leftviolate = 1;
+ leftviolate = true;
}
}
}
@@ -3310,13 +3284,13 @@ static void calchandleNurb_intern(BezTriple *bezt,
if (ydiff1 <= 0.0f) {
if (next->vec[1][1] < bezt->vec[2][1]) {
bezt->vec[2][1] = next->vec[1][1];
- rightviolate = 1;
+ rightviolate = true;
}
}
else {
if (next->vec[1][1] > bezt->vec[2][1]) {
bezt->vec[2][1] = next->vec[1][1];
- rightviolate = 1;
+ rightviolate = true;
}
}
}
@@ -3346,13 +3320,13 @@ static void calchandleNurb_intern(BezTriple *bezt,
}
if (skip_align ||
- /* when one handle is free, alignming makes no sense, see: T35952 */
+ /* When one handle is free, aligning makes no sense, see: T35952 */
ELEM(HD_FREE, bezt->h1, bezt->h2) ||
- /* also when no handles are aligned, skip this step */
+ /* Also when no handles are aligned, skip this step. */
(!ELEM(HD_ALIGN, bezt->h1, bezt->h2) && !ELEM(HD_ALIGN_DOUBLESIDE, bezt->h1, bezt->h2))) {
- /* handles need to be updated during animation and applying stuff like hooks,
+ /* Handles need to be updated during animation and applying stuff like hooks,
* but in such situations it's quite difficult to distinguish in which order
- * align handles should be aligned so skip them for now */
+ * align handles should be aligned so skip them for now. */
return;
}
@@ -3427,19 +3401,19 @@ static void calchandlesNurb_intern(Nurb *nu, eBezTriple_Flag handle_sel_flag, bo
prev = bezt + (a - 1);
}
else {
- prev = NULL;
+ prev = nullptr;
}
next = bezt + 1;
while (a--) {
- calchandleNurb_intern(bezt, prev, next, handle_sel_flag, 0, skip_align, 0);
+ calchandleNurb_intern(bezt, prev, next, handle_sel_flag, false, skip_align, 0);
prev = bezt;
if (a == 1) {
if (nu->flagu & CU_NURB_CYCLIC) {
next = nu->bezt;
}
else {
- next = NULL;
+ next = nullptr;
}
}
else {
@@ -3455,7 +3429,8 @@ static void calchandlesNurb_intern(Nurb *nu, eBezTriple_Flag handle_sel_flag, bo
* with easy error checking and de-allocation, and an easy way to add or remove
* arrays that are processed in this way when changing code.
*
- * floats, chars: NULL-terminated arrays of pointers to array pointers that need to be allocated.
+ * floats, chars: null-terminated arrays of pointers to array pointers that need to be
+ * allocated.
*
* Returns: pointer to the buffer that contains all of the arrays.
*/
@@ -3474,10 +3449,10 @@ static void *allocate_arrays(int count, float ***floats, char ***chars, const ch
void *buffer = (float *)MEM_malloc_arrayN(count, (sizeof(float) * num_floats + num_chars), name);
if (!buffer) {
- return NULL;
+ return nullptr;
}
- float *fptr = buffer;
+ float *fptr = (float *)buffer;
for (int i = 0; i < num_floats; i++, fptr += count) {
*floats[i] = fptr;
@@ -3546,9 +3521,9 @@ static bool tridiagonal_solve_with_limits(float *a,
int solve_count)
{
float *a0, *b0, *c0, *d0;
- float **arrays[] = {&a0, &b0, &c0, &d0, NULL};
+ float **arrays[] = {&a0, &b0, &c0, &d0, nullptr};
char *is_locked, *num_unlocks;
- char **flagarrays[] = {&is_locked, &num_unlocks, NULL};
+ char **flagarrays[] = {&is_locked, &num_unlocks, nullptr};
void *tmps = allocate_arrays(solve_count, arrays, flagarrays, "tridiagonal_solve_with_limits");
if (!tmps) {
@@ -3815,7 +3790,7 @@ static void bezier_handle_calc_smooth_fcurve(
BezTriple *bezt, int total, int start, int count, bool cycle)
{
float *dx, *dy, *l, *a, *b, *c, *d, *h, *hmax, *hmin;
- float **arrays[] = {&dx, &dy, &l, &a, &b, &c, &d, &h, &hmax, &hmin, NULL};
+ float **arrays[] = {&dx, &dy, &l, &a, &b, &c, &d, &h, &hmax, &hmin, nullptr};
int solve_count = count;
@@ -3844,7 +3819,7 @@ static void bezier_handle_calc_smooth_fcurve(
/* allocate all */
- void *tmp_buffer = allocate_arrays(count, arrays, NULL, "bezier_calc_smooth_tmp");
+ void *tmp_buffer = allocate_arrays(count, arrays, nullptr, "bezier_calc_smooth_tmp");
if (!tmp_buffer) {
return;
}
@@ -4020,8 +3995,8 @@ void BKE_nurb_handle_smooth_fcurve(BezTriple *bezt, int total, bool cyclic)
}
}
- /* Find continuous subsequences of free auto handles and smooth them, starting at
- * search_base. In cyclic mode these subsequences can span the cycle boundary. */
+ /* Find continuous sub-sequences of free auto handles and smooth them, starting at search_base.
+ * In cyclic mode these sub-sequences can span the cycle boundary. */
int start = search_base, count = 1;
for (int i = 1, j = start + 1; i < total; i++, j++) {
@@ -4046,23 +4021,12 @@ void BKE_nurb_handle_smooth_fcurve(BezTriple *bezt, int total, bool cyclic)
}
}
-/**
- * Recalculate the handles of a nurb bezier-triple. Acts based on handle selection with `SELECT`
- * flag. To use a different flag, use #BKE_nurb_handle_calc_ex().
- */
void BKE_nurb_handle_calc(
BezTriple *bezt, BezTriple *prev, BezTriple *next, const bool is_fcurve, const char smoothing)
{
- calchandleNurb_intern(bezt, prev, next, SELECT, is_fcurve, false, smoothing);
+ calchandleNurb_intern(bezt, prev, next, (eBezTriple_Flag)SELECT, is_fcurve, false, smoothing);
}
-/**
- * Variant of #BKE_nurb_handle_calc() that allows calculating based on a different select flag.
- *
- * \param handle_sel_flag: The flag (bezt.f1/2/3) value to use to determine selection.
- * Usually #SELECT, but may want to use a different one at times
- * (if caller does not operate on selection).
- */
void BKE_nurb_handle_calc_ex(BezTriple *bezt,
BezTriple *prev,
BezTriple *next,
@@ -4070,12 +4034,13 @@ void BKE_nurb_handle_calc_ex(BezTriple *bezt,
const bool is_fcurve,
const char smoothing)
{
- calchandleNurb_intern(bezt, prev, next, handle_sel_flag, is_fcurve, false, smoothing);
+ calchandleNurb_intern(
+ bezt, prev, next, (eBezTriple_Flag)handle_sel_flag, is_fcurve, false, smoothing);
}
void BKE_nurb_handles_calc(Nurb *nu) /* first, if needed, set handle flags */
{
- calchandlesNurb_intern(nu, SELECT, false);
+ calchandlesNurb_intern(nu, (eBezTriple_Flag)SELECT, false);
}
/**
@@ -4103,14 +4068,12 @@ static void nurb_handles_calc__align_selected(Nurb *nu)
nurbList_handles_swap_select(nu);
}
-/* similar to BKE_nurb_handle_calc but for curves and
- * figures out the previous and next for us */
void BKE_nurb_handle_calc_simple(Nurb *nu, BezTriple *bezt)
{
if (nu->pntsu > 1) {
BezTriple *prev = BKE_nurb_bezt_get_prev(nu, bezt);
BezTriple *next = BKE_nurb_bezt_get_next(nu, bezt);
- BKE_nurb_handle_calc(bezt, prev, next, 0, 0);
+ BKE_nurb_handle_calc(bezt, prev, next, false, 0);
}
}
@@ -4129,19 +4092,6 @@ void BKE_nurb_handle_calc_simple_auto(Nurb *nu, BezTriple *bezt)
}
}
-/**
- * Update selected handle types to ensure valid state, e.g. deduce "Auto" types to concrete ones.
- * Thereby \a sel_flag defines what qualifies as selected.
- * Use when something has changed handle positions.
- *
- * The caller needs to recalculate handles.
- *
- * \param sel_flag: The flag (bezt.f1/2/3) value to use to determine selection. Usually `SELECT`,
- * but may want to use a different one at times (if caller does not operate on
- * selection).
- * \param use_handle: Check selection state of individual handles, otherwise always update both
- * handles if the key is selected.
- */
void BKE_nurb_bezt_handle_test(BezTriple *bezt,
const eBezTriple_Flag__Alias sel_flag,
const bool use_handle,
@@ -4223,7 +4173,7 @@ void BKE_nurb_handles_autocalc(Nurb *nu, uint8_t flag)
const float eps = 0.0001f;
const float eps_sq = eps * eps;
- if (nu == NULL || nu->bezt == NULL) {
+ if (nu == nullptr || nu->bezt == nullptr) {
return;
}
@@ -4238,13 +4188,13 @@ void BKE_nurb_handles_autocalc(Nurb *nu, uint8_t flag)
/* left handle: */
if (flag == 0 || (bezt1->f1 & flag)) {
bezt1->h1 = HD_FREE;
- /* distance too short: vectorhandle */
+ /* Distance too short: vector-handle. */
if (len_squared_v3v3(bezt1->vec[1], bezt0->vec[1]) < eps_sq) {
bezt1->h1 = HD_VECT;
leftsmall = true;
}
else {
- /* aligned handle? */
+ /* Aligned handle? */
if (dist_squared_to_line_v3(bezt1->vec[1], bezt1->vec[0], bezt1->vec[2]) < eps_sq) {
align = true;
bezt1->h1 = HD_ALIGN;
@@ -4258,13 +4208,13 @@ void BKE_nurb_handles_autocalc(Nurb *nu, uint8_t flag)
/* right handle: */
if (flag == 0 || (bezt1->f3 & flag)) {
bezt1->h2 = HD_FREE;
- /* distance too short: vectorhandle */
+ /* Distance too short: vector-handle. */
if (len_squared_v3v3(bezt1->vec[1], bezt2->vec[1]) < eps_sq) {
bezt1->h2 = HD_VECT;
rightsmall = true;
}
else {
- /* aligned handle? */
+ /* Aligned handle? */
if (align) {
bezt1->h2 = HD_ALIGN;
}
@@ -4305,15 +4255,6 @@ void BKE_nurbList_handles_autocalc(ListBase *editnurb, uint8_t flag)
}
}
-/**
- * \param code:
- * - 1 (#HD_AUTO): set auto-handle.
- * - 2 (#HD_VECT): set vector-handle.
- * - 3 (#HD_ALIGN) it toggle, vector-handles become #HD_FREE.
- *
- * - 5: Set align, like 3 but no toggle.
- * - 6: Clear align (setting #HD_FREE), like 3 but no toggle.
- */
void BKE_nurbList_handles_set(ListBase *editnurb, const char code)
{
BezTriple *bezt;
@@ -4491,9 +4432,6 @@ void BKE_nurbList_flag_set(ListBase *editnurb, uint8_t flag, bool set)
}
}
-/**
- * Set \a flag for every point that already has \a from_flag set.
- */
bool BKE_nurbList_flag_set_from_flag(ListBase *editnurb, uint8_t from_flag, uint8_t flag)
{
bool changed = false;
@@ -4608,7 +4546,7 @@ void BKE_nurb_direction_switch(Nurb *nu)
/* and make in increasing order again */
a = KNOTSU(nu);
fp1 = nu->knotsu;
- fp2 = tempf = MEM_malloc_arrayN(a, sizeof(float), "switchdirect");
+ fp2 = tempf = (float *)MEM_malloc_arrayN(a, sizeof(float), "switchdirect");
a--;
fp2[a] = fp1[a];
while (a--) {
@@ -4678,7 +4616,8 @@ void BKE_curve_nurbs_vert_coords_get(const ListBase *lb, float (*vert_coords)[3]
float (*BKE_curve_nurbs_vert_coords_alloc(const ListBase *lb, int *r_vert_len))[3]
{
const int vert_len = BKE_nurbList_verts_count(lb);
- float(*vert_coords)[3] = MEM_malloc_arrayN(vert_len, sizeof(*vert_coords), __func__);
+ float(*vert_coords)[3] = (float(*)[3])MEM_malloc_arrayN(
+ vert_len, sizeof(*vert_coords), __func__);
BKE_curve_nurbs_vert_coords_get(lb, vert_coords, vert_len);
*r_vert_len = vert_len;
return vert_coords;
@@ -4717,7 +4656,7 @@ void BKE_curve_nurbs_vert_coords_apply_with_mat4(ListBase *lb,
BKE_nurb_project_2d(nu);
}
- calchandlesNurb_intern(nu, SELECT, true);
+ calchandlesNurb_intern(nu, (eBezTriple_Flag)SELECT, true);
}
}
@@ -4753,14 +4692,14 @@ void BKE_curve_nurbs_vert_coords_apply(ListBase *lb,
BKE_nurb_project_2d(nu);
}
- calchandlesNurb_intern(nu, SELECT, true);
+ calchandlesNurb_intern(nu, (eBezTriple_Flag)SELECT, true);
}
}
float (*BKE_curve_nurbs_key_vert_coords_alloc(const ListBase *lb, float *key, int *r_vert_len))[3]
{
int vert_len = BKE_nurbList_verts_count(lb);
- float(*cos)[3] = MEM_malloc_arrayN(vert_len, sizeof(*cos), __func__);
+ float(*cos)[3] = (float(*)[3])MEM_malloc_arrayN(vert_len, sizeof(*cos), __func__);
float *co = cos[0];
LISTBASE_FOREACH (const Nurb *, nu, lb) {
@@ -4910,9 +4849,6 @@ bool BKE_nurb_order_clamp_v(struct Nurb *nu)
return changed;
}
-/**
- * \note caller must ensure active vertex remains valid.
- */
bool BKE_nurb_type_convert(Nurb *nu,
const short type,
const bool use_handles,
@@ -4923,7 +4859,7 @@ bool BKE_nurb_type_convert(Nurb *nu,
int a, c, nr;
if (nu->type == CU_POLY) {
- if (type == CU_BEZIER) { /* To Bezier with vecthandles. */
+ if (type == CU_BEZIER) { /* To Bezier with vector-handles. */
nr = nu->pntsu;
bezt = (BezTriple *)MEM_calloc_arrayN(nr, sizeof(BezTriple), "setsplinetype2");
nu->bezt = bezt;
@@ -4939,7 +4875,7 @@ bool BKE_nurb_type_convert(Nurb *nu,
bezt++;
}
MEM_freeN(nu->bp);
- nu->bp = NULL;
+ nu->bp = nullptr;
nu->pntsu = nr;
nu->pntsv = 0;
nu->type = CU_BEZIER;
@@ -4961,7 +4897,7 @@ bool BKE_nurb_type_convert(Nurb *nu,
else if (nu->type == CU_BEZIER) { /* Bezier */
if (ELEM(type, CU_POLY, CU_NURBS)) {
nr = use_handles ? (3 * nu->pntsu) : nu->pntsu;
- nu->bp = MEM_calloc_arrayN(nr, sizeof(BPoint), "setsplinetype");
+ nu->bp = (BPoint *)MEM_calloc_arrayN(nr, sizeof(BPoint), "setsplinetype");
a = nu->pntsu;
bezt = nu->bezt;
bp = nu->bp;
@@ -4993,7 +4929,7 @@ bool BKE_nurb_type_convert(Nurb *nu,
bezt++;
}
MEM_freeN(nu->bezt);
- nu->bezt = NULL;
+ nu->bezt = nullptr;
nu->pntsu = nr;
nu->pntsv = 1;
nu->orderu = 4;
@@ -5013,20 +4949,20 @@ bool BKE_nurb_type_convert(Nurb *nu,
if (nu->knotsu) {
MEM_freeN(nu->knotsu); /* python created nurbs have a knotsu of zero */
}
- nu->knotsu = NULL;
+ nu->knotsu = nullptr;
MEM_SAFE_FREE(nu->knotsv);
}
else if (type == CU_BEZIER) { /* to Bezier */
nr = nu->pntsu / 3;
if (nr < 2) {
- if (r_err_msg != NULL) {
+ if (r_err_msg != nullptr) {
*r_err_msg = "At least 6 points required for conversion";
}
return false; /* conversion impossible */
}
- bezt = MEM_calloc_arrayN(nr, sizeof(BezTriple), "setsplinetype2");
+ bezt = (BezTriple *)MEM_calloc_arrayN(nr, sizeof(BezTriple), "setsplinetype2");
nu->bezt = bezt;
a = nr;
bp = nu->bp;
@@ -5045,9 +4981,9 @@ bool BKE_nurb_type_convert(Nurb *nu,
bezt++;
}
MEM_freeN(nu->bp);
- nu->bp = NULL;
+ nu->bp = nullptr;
MEM_freeN(nu->knotsu);
- nu->knotsu = NULL;
+ nu->knotsu = nullptr;
nu->pntsu = nr;
nu->type = CU_BEZIER;
}
@@ -5056,7 +4992,6 @@ bool BKE_nurb_type_convert(Nurb *nu,
return true;
}
-/* Get edit nurbs or normal nurbs list */
ListBase *BKE_curve_nurbs_get(Curve *cu)
{
if (cu->editnurb) {
@@ -5077,7 +5012,7 @@ const ListBase *BKE_curve_nurbs_get_for_read(const Curve *cu)
void BKE_curve_nurb_active_set(Curve *cu, const Nurb *nu)
{
- if (nu == NULL) {
+ if (nu == nullptr) {
cu->actnu = CU_ACT_NONE;
}
else {
@@ -5090,14 +5025,13 @@ void BKE_curve_nurb_active_set(Curve *cu, const Nurb *nu)
Nurb *BKE_curve_nurb_active_get(Curve *cu)
{
ListBase *nurbs = BKE_curve_editNurbs_get(cu);
- return BLI_findlink(nurbs, cu->actnu);
+ return (Nurb *)BLI_findlink(nurbs, cu->actnu);
}
-/* Get active vert for curve */
void *BKE_curve_vert_active_get(Curve *cu)
{
- Nurb *nu = NULL;
- void *vert = NULL;
+ Nurb *nu = nullptr;
+ void *vert = nullptr;
BKE_curve_nurb_vert_active_get(cu, &nu, &vert);
return vert;
@@ -5114,7 +5048,6 @@ int BKE_curve_nurb_vert_index_get(const Nurb *nu, const void *vert)
return (BPoint *)vert - nu->bp;
}
-/* Set active nurb and active vert for curve */
void BKE_curve_nurb_vert_active_set(Curve *cu, const Nurb *nu, const void *vert)
{
if (nu) {
@@ -5132,15 +5065,14 @@ void BKE_curve_nurb_vert_active_set(Curve *cu, const Nurb *nu, const void *vert)
}
}
-/* Get points to the active nurb and active vert for curve. */
bool BKE_curve_nurb_vert_active_get(Curve *cu, Nurb **r_nu, void **r_vert)
{
- Nurb *nu = NULL;
- void *vert = NULL;
+ Nurb *nu = nullptr;
+ void *vert = nullptr;
if (cu->actvert != CU_ACT_NONE) {
ListBase *nurbs = BKE_curve_editNurbs_get(cu);
- nu = BLI_findlink(nurbs, cu->actnu);
+ nu = (Nurb *)BLI_findlink(nurbs, cu->actnu);
if (nu) {
if (nu->type == CU_BEZIER) {
@@ -5157,7 +5089,7 @@ bool BKE_curve_nurb_vert_active_get(Curve *cu, Nurb **r_nu, void **r_vert)
*r_nu = nu;
*r_vert = vert;
- return (*r_vert != NULL);
+ return (*r_vert != nullptr);
}
void BKE_curve_nurb_vert_active_validate(Curve *cu)
@@ -5167,13 +5099,13 @@ void BKE_curve_nurb_vert_active_validate(Curve *cu)
if (BKE_curve_nurb_vert_active_get(cu, &nu, &vert)) {
if (nu->type == CU_BEZIER) {
- BezTriple *bezt = vert;
+ BezTriple *bezt = (BezTriple *)vert;
if (BEZT_ISSEL_ANY(bezt) == 0) {
cu->actvert = CU_ACT_NONE;
}
}
else {
- BPoint *bp = vert;
+ BPoint *bp = (BPoint *)vert;
if ((bp->f1 & SELECT) == 0) {
cu->actvert = CU_ACT_NONE;
}
@@ -5185,11 +5117,10 @@ void BKE_curve_nurb_vert_active_validate(Curve *cu)
}
}
-/* basic vertex data functions */
bool BKE_curve_minmax(Curve *cu, bool use_radius, float min[3], float max[3])
{
ListBase *nurb_lb = BKE_curve_nurbs_get(cu);
- ListBase temp_nurb_lb = {NULL, NULL};
+ ListBase temp_nurb_lb = {nullptr, nullptr};
const bool is_font = (BLI_listbase_is_empty(nurb_lb)) && (cu->len != 0);
/* For font curves we generate temp list of splines.
*
@@ -5198,7 +5129,7 @@ bool BKE_curve_minmax(Curve *cu, bool use_radius, float min[3], float max[3])
*/
if (is_font) {
nurb_lb = &temp_nurb_lb;
- BKE_vfont_to_curve_ex(NULL, cu, FO_EDIT, nurb_lb, NULL, NULL, NULL, NULL);
+ BKE_vfont_to_curve_ex(nullptr, cu, FO_EDIT, nurb_lb, nullptr, nullptr, nullptr, nullptr);
use_radius = false;
}
/* Do bounding box based on splines. */
@@ -5303,7 +5234,7 @@ void BKE_curve_transform_ex(Curve *cu,
if (do_keys && cu->key) {
LISTBASE_FOREACH (KeyBlock *, kb, &cu->key->block) {
- float *fp = kb->data;
+ float *fp = (float *)kb->data;
int n = kb->totelem;
LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
@@ -5361,7 +5292,7 @@ void BKE_curve_translate(Curve *cu, const float offset[3], const bool do_keys)
if (do_keys && cu->key) {
LISTBASE_FOREACH (KeyBlock *, kb, &cu->key->block) {
- float *fp = kb->data;
+ float *fp = (float *)kb->data;
int n = kb->totelem;
LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
@@ -5513,11 +5444,10 @@ void BKE_curve_material_remap(Curve *cu, const unsigned int *remap, unsigned int
}
}
else {
- Nurb *nu;
ListBase *nurbs = BKE_curve_editNurbs_get(cu);
if (nurbs) {
- for (nu = nurbs->first; nu; nu = nu->next) {
+ LISTBASE_FOREACH (Nurb *, nu, nurbs) {
MAT_NR_REMAP(nu->mat_nr);
}
}
@@ -5551,8 +5481,6 @@ void BKE_curve_rect_from_textbox(const struct Curve *cu,
r_rect->ymin = r_rect->ymax - tb->h;
}
-/* This function is almost the same as BKE_fcurve_correct_bezpart(), but doesn't allow as large a
- * tangent. */
void BKE_curve_correct_bezpart(const float v1[2], float v2[2], float v3[2], const float v4[2])
{
float h1[2], h2[2], len1, len2, len, fac;
@@ -5609,8 +5537,8 @@ void BKE_curve_eval_geometry(Depsgraph *depsgraph, Curve *curve)
}
/* Draw Engine */
-void (*BKE_curve_batch_cache_dirty_tag_cb)(Curve *cu, int mode) = NULL;
-void (*BKE_curve_batch_cache_free_cb)(Curve *cu) = NULL;
+void (*BKE_curve_batch_cache_dirty_tag_cb)(Curve *cu, int mode) = nullptr;
+void (*BKE_curve_batch_cache_free_cb)(Curve *cu) = nullptr;
void BKE_curve_batch_cache_dirty_tag(Curve *cu, int mode)
{
diff --git a/source/blender/blenkernel/intern/curve_bevel.c b/source/blender/blenkernel/intern/curve_bevel.c
index d205d8cca46..18e4ab3ade1 100644
--- a/source/blender/blenkernel/intern/curve_bevel.c
+++ b/source/blender/blenkernel/intern/curve_bevel.c
@@ -64,8 +64,8 @@ static void bevel_quarter_fill(const Curve *curve,
float angle = 0.0f;
const float dangle = (float)M_PI_2 / (curve->bevresol + 1);
for (int i = 0; i < curve->bevresol + 1; i++) {
- quarter_coords_x[i] = (float)(cosf(angle) * (curve->ext2));
- quarter_coords_y[i] = (float)(sinf(angle) * (curve->ext2));
+ quarter_coords_x[i] = (float)(cosf(angle) * (curve->bevel_radius));
+ quarter_coords_y[i] = (float)(sinf(angle) * (curve->bevel_radius));
angle += dangle;
}
}
@@ -76,11 +76,11 @@ static void bevel_quarter_fill(const Curve *curve,
/* If there aren't enough samples, the curveprofile won't
* sample the start vertex, so set it manually instead. */
- quarter_coords_x[0] = curve->ext2;
+ quarter_coords_x[0] = curve->bevel_radius;
quarter_coords_y[0] = 0.0f;
for (int i = 1; i < curve->bevresol + 1; i++) {
- quarter_coords_x[i] = (float)(curve->bevel_profile->segments[i].x * (curve->ext2));
- quarter_coords_y[i] = (float)(curve->bevel_profile->segments[i].y * (curve->ext2));
+ quarter_coords_x[i] = (float)(curve->bevel_profile->segments[i].x * (curve->bevel_radius));
+ quarter_coords_y[i] = (float)(curve->bevel_profile->segments[i].y * (curve->bevel_radius));
}
}
}
@@ -133,13 +133,13 @@ static void curve_bevel_make_extrude_and_fill(const Curve *cu,
/* Add the bottom vertex. */
fp[0] = 0.0f;
fp[1] = 0.0f;
- fp[2] = -cu->ext1 - cu->ext2;
+ fp[2] = -cu->extrude - cu->bevel_radius;
fp += 3;
for (int i = cu->bevresol; i >= 0; i--) {
fp[0] = 0.0f;
fp[1] = quarter_coords_x[i];
- fp[2] = -quarter_coords_y[i] - cu->ext1;
+ fp[2] = -quarter_coords_y[i] - cu->extrude;
fp += 3;
}
}
@@ -147,8 +147,8 @@ static void curve_bevel_make_extrude_and_fill(const Curve *cu,
/* Add the extrusion if we're only building either the back or the front. */
if (use_extrude && ELEM(fill_type, FRONT, BACK)) {
fp[0] = 0.0f;
- fp[1] = cu->ext2;
- fp[2] = (fill_type == FRONT) ? -cu->ext1 : cu->ext1;
+ fp[1] = cu->bevel_radius;
+ fp[2] = (fill_type == FRONT) ? -cu->extrude : cu->extrude;
fp += 3;
}
@@ -159,13 +159,13 @@ static void curve_bevel_make_extrude_and_fill(const Curve *cu,
for (int i = front_start; i < cu->bevresol + 1; i++) {
fp[0] = 0.0f;
fp[1] = quarter_coords_x[i];
- fp[2] = quarter_coords_y[i] + cu->ext1;
+ fp[2] = quarter_coords_y[i] + cu->extrude;
fp += 3;
}
/* Add the top vertex. */
fp[0] = 0.0f;
fp[1] = 0.0f;
- fp[2] = cu->ext1 + cu->ext2;
+ fp[2] = cu->extrude + cu->bevel_radius;
fp += 3;
}
@@ -174,22 +174,22 @@ static void curve_bevel_make_extrude_and_fill(const Curve *cu,
for (int i = cu->bevresol; i > 0; i--) {
fp[0] = 0.0f;
fp[1] = -quarter_coords_x[i];
- fp[2] = quarter_coords_y[i] + cu->ext1;
+ fp[2] = quarter_coords_y[i] + cu->extrude;
fp += 3;
}
if (use_extrude) {
/* Add the extrusion. */
fp[0] = 0.0f;
- fp[1] = -cu->ext2;
- fp[2] = cu->ext1;
+ fp[1] = -cu->bevel_radius;
+ fp[2] = cu->extrude;
fp += 3;
}
for (int i = 0; i < cu->bevresol + 1; i++) {
fp[0] = 0.0f;
fp[1] = -quarter_coords_x[i];
- fp[2] = -quarter_coords_y[i] - cu->ext1;
+ fp[2] = -quarter_coords_y[i] - cu->extrude;
fp += 3;
}
}
@@ -213,8 +213,8 @@ static void curve_bevel_make_full_circle(const Curve *cu, ListBase *disp)
for (int i = 0; i < nr; i++) {
fp[0] = 0.0;
- fp[1] = (cosf(angle) * (cu->ext2));
- fp[2] = (sinf(angle) * (cu->ext2)) - cu->ext1;
+ fp[1] = (cosf(angle) * (cu->bevel_radius));
+ fp[2] = (sinf(angle) * (cu->bevel_radius)) - cu->extrude;
angle += dangle;
fp += 3;
}
@@ -232,9 +232,9 @@ static void curve_bevel_make_only_extrude(const Curve *cu, ListBase *disp)
float *fp = dl->verts;
fp[0] = fp[1] = 0.0;
- fp[2] = -cu->ext1;
+ fp[2] = -cu->extrude;
fp[3] = fp[4] = 0.0;
- fp[5] = cu->ext1;
+ fp[5] = cu->extrude;
}
static void curve_bevel_make_from_object(const Curve *cu, ListBase *disp)
@@ -247,7 +247,7 @@ static void curve_bevel_make_from_object(const Curve *cu, ListBase *disp)
}
Curve *bevcu = cu->bevobj->data;
- if (bevcu->ext1 == 0.0f && bevcu->ext2 == 0.0f) {
+ if (bevcu->extrude == 0.0f && bevcu->bevel_radius == 0.0f) {
ListBase bevdisp = {NULL, NULL};
float facx = cu->bevobj->scale[0];
float facy = cu->bevobj->scale[1];
@@ -299,8 +299,8 @@ ListBase BKE_curve_bevel_make(const Curve *curve)
}
}
else {
- const bool use_extrude = curve->ext1 != 0.0f;
- const bool use_bevel = curve->ext2 != 0.0f;
+ const bool use_extrude = curve->extrude != 0.0f;
+ const bool use_bevel = curve->bevel_radius != 0.0f;
/* Pass. */
if (use_extrude && !use_bevel) {
curve_bevel_make_only_extrude(curve, &bevel_shape);
diff --git a/source/blender/blenkernel/intern/curve_deform.c b/source/blender/blenkernel/intern/curve_deform.c
index b8b8506d681..d754f8cc27d 100644
--- a/source/blender/blenkernel/intern/curve_deform.c
+++ b/source/blender/blenkernel/intern/curve_deform.c
@@ -410,12 +410,6 @@ void BKE_curve_deform_coords_with_editmesh(const Object *ob_curve,
em_target);
}
-/**
- * \param orco: Input vec and orco = local coord in curve space
- * orco is original not-animated or deformed reference point.
- *
- * The result written in vec and r_mat.
- */
void BKE_curve_deform_co(const Object *ob_curve,
const Object *ob_target,
const float orco[3],
diff --git a/source/blender/blenkernel/intern/curve_eval.cc b/source/blender/blenkernel/intern/curve_eval.cc
index ff0478f2543..38f736e6907 100644
--- a/source/blender/blenkernel/intern/curve_eval.cc
+++ b/source/blender/blenkernel/intern/curve_eval.cc
@@ -50,12 +50,6 @@ blender::MutableSpan<SplinePtr> CurveEval::splines()
return splines_;
}
-/**
- * \return True if the curve contains a spline with the given type.
- *
- * \note If you are looping over all of the splines in the same scope anyway,
- * it's better to avoid calling this function, in case there are many splines.
- */
bool CurveEval::has_spline_with_type(const Spline::Type type) const
{
for (const SplinePtr &spline : this->splines()) {
@@ -72,14 +66,18 @@ void CurveEval::resize(const int size)
attributes.reallocate(size);
}
-/**
- * \warning Call #reallocate on the spline's attributes after adding all splines.
- */
void CurveEval::add_spline(SplinePtr spline)
{
splines_.append(std::move(spline));
}
+void CurveEval::add_splines(MutableSpan<SplinePtr> splines)
+{
+ for (SplinePtr &spline : splines) {
+ this->add_spline(std::move(spline));
+ }
+}
+
void CurveEval::remove_splines(blender::IndexMask mask)
{
for (int i = mask.size() - 1; i >= 0; i--) {
@@ -109,13 +107,24 @@ void CurveEval::bounds_min_max(float3 &min, float3 &max, const bool use_evaluate
}
}
-/**
- * Return the start indices for each of the curve spline's control points, if they were part
- * of a flattened array. This can be used to facilitate parallelism by avoiding the need to
- * accumulate an offset while doing more complex calculations.
- *
- * \note The result array is one longer than the spline count; the last element is the total size.
- */
+float CurveEval::total_length() const
+{
+ float length = 0.0f;
+ for (const SplinePtr &spline : this->splines()) {
+ length += spline->length();
+ }
+ return length;
+}
+
+int CurveEval::total_control_point_size() const
+{
+ int count = 0;
+ for (const SplinePtr &spline : this->splines()) {
+ count += spline->size();
+ }
+ return count;
+}
+
blender::Array<int> CurveEval::control_point_offsets() const
{
Array<int> offsets(splines_.size() + 1);
@@ -128,9 +137,6 @@ blender::Array<int> CurveEval::control_point_offsets() const
return offsets;
}
-/**
- * Exactly like #control_point_offsets, but uses the number of evaluated points instead.
- */
blender::Array<int> CurveEval::evaluated_point_offsets() const
{
Array<int> offsets(splines_.size() + 1);
@@ -143,11 +149,6 @@ blender::Array<int> CurveEval::evaluated_point_offsets() const
return offsets;
}
-/**
- * Return the accumulated length at the start of every spline in the curve.
- *
- * \note The result is one longer than the spline count; the last element is the total length.
- */
blender::Array<float> CurveEval::accumulated_spline_lengths() const
{
Array<float> spline_lengths(splines_.size() + 1);
@@ -343,13 +344,6 @@ std::unique_ptr<CurveEval> curve_eval_from_dna_curve(const Curve &dna_curve)
return curve_eval_from_dna_curve(dna_curve, *BKE_curve_nurbs_get_for_read(&dna_curve));
}
-/**
- * Check the invariants that curve control point attributes should always uphold, necessary
- * because attributes are stored on splines rather than in a flat array on the curve:
- * - The same set of attributes exists on every spline.
- * - Attributes with the same name have the same type on every spline.
- * - Attributes are in the same order on every spline.
- */
void CurveEval::assert_valid_point_attributes() const
{
#ifdef DEBUG
diff --git a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
index 03525e32a52..5522a84d094 100644
--- a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
+++ b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
@@ -691,16 +691,6 @@ static void copy_spline_domain_attributes_to_mesh(const CurveEval &curve,
}
}
-/**
- * Extrude all splines in the profile curve along the path of every spline in the curve input.
- * Transfer curve attributes to the mesh.
- *
- * \note Normal calculation is by far the slowest part of calculations relating to the result mesh.
- * Although it would be a sensible decision to use the better topology information available while
- * generating the mesh to also generate the normals, that work may wasted if the output mesh is
- * changed anyway in a way that affects the normals. So currently this code uses the safer /
- * simpler solution of deferring normal calculation to the rest of Blender.
- */
Mesh *curve_to_mesh_sweep(const CurveEval &curve, const CurveEval &profile, const bool fill_caps)
{
Span<SplinePtr> profiles = profile.splines();
@@ -776,10 +766,6 @@ static CurveEval get_curve_single_vert()
return curve;
}
-/**
- * Create a loose-edge mesh based on the evaluated path of the curve's splines.
- * Transfer curve attributes to the mesh.
- */
Mesh *curve_to_wire_mesh(const CurveEval &curve)
{
static const CurveEval vert_curve = get_curve_single_vert();
diff --git a/source/blender/blenkernel/intern/curveprofile.cc b/source/blender/blenkernel/intern/curveprofile.cc
index 7f2a2bc342d..387709fca29 100644
--- a/source/blender/blenkernel/intern/curveprofile.cc
+++ b/source/blender/blenkernel/intern/curveprofile.cc
@@ -44,9 +44,6 @@
/** \name Data Handling
* \{ */
-/**
- * Returns a pointer to a newly allocated curve profile, using the given preset.
- */
struct CurveProfile *BKE_curveprofile_add(eCurveProfilePresets preset)
{
CurveProfile *profile = (CurveProfile *)MEM_callocN(sizeof(CurveProfile), __func__);
@@ -104,7 +101,6 @@ void BKE_curveprofile_blend_write(struct BlendWriter *writer, const struct Curve
BLO_write_struct_array(writer, CurveProfilePoint, profile->path_len, profile->path);
}
-/* Expects that the curve profile itself has been read already. */
void BKE_curveprofile_blend_read(struct BlendDataReader *reader, struct CurveProfile *profile)
{
BLO_read_data_address(reader, &profile->path);
@@ -125,14 +121,6 @@ void BKE_curveprofile_blend_read(struct BlendDataReader *reader, struct CurvePro
/** \name Editing
* \{ */
-/**
- * Move a point's handle, accounting for the alignment of handles with the #HD_ALIGN type.
- *
- * \param handle_1: Whether to move the 1st or 2nd control point.
- * \param delta: The *relative* change in the handle's position.
- * \note Requires #BKE_curveprofile_update call after.
- * \return Whether the handle moved from its start position.
- */
bool BKE_curveprofile_move_handle(struct CurveProfilePoint *point,
const bool handle_1,
const bool snap,
@@ -173,14 +161,6 @@ bool BKE_curveprofile_move_handle(struct CurveProfilePoint *point,
return false;
}
-/**
- * Moves a control point, accounting for clipping and snapping, and moving free handles.
- *
- * \param snap: Whether to snap the point to the grid
- * \param delta: The *relative* change of the point's location.
- * \return Whether the point moved from its start position.
- * \note Requires #BKE_curveprofile_update call after.
- */
bool BKE_curveprofile_move_point(struct CurveProfile *profile,
struct CurveProfilePoint *point,
const bool snap,
@@ -228,10 +208,6 @@ bool BKE_curveprofile_move_point(struct CurveProfile *profile,
return false;
}
-/**
- * Removes a specific point from the path of control points.
- * \note Requires #BKE_curveprofile_update call after.
- */
bool BKE_curveprofile_remove_point(CurveProfile *profile, CurveProfilePoint *point)
{
/* Must have 2 points minimum. */
@@ -262,13 +238,6 @@ bool BKE_curveprofile_remove_point(CurveProfile *profile, CurveProfilePoint *poi
return true;
}
-/**
- * Removes every point in the widget with the supplied flag set, except for the first and last.
- *
- * \param flag: #CurveProfilePoint.flag.
- *
- * \note Requires #BKE_curveprofile_update call after.
- */
void BKE_curveprofile_remove_by_flag(CurveProfile *profile, const short flag)
{
/* Copy every point without the flag into the new path. */
@@ -308,13 +277,6 @@ static void point_init(CurveProfilePoint *point, float x, float y, short flag, c
point->h2 = h2;
}
-/**
- * Adds a new point at the specified location. The choice for which points to place the new vertex
- * between is made by checking which control point line segment is closest to the new point and
- * placing the new vertex in between that segment's points.
- *
- * \note Requires #BKE_curveprofile_update call after.
- */
CurveProfilePoint *BKE_curveprofile_insert(CurveProfile *profile, float x, float y)
{
const float new_loc[2] = {x, y};
@@ -370,11 +332,6 @@ CurveProfilePoint *BKE_curveprofile_insert(CurveProfile *profile, float x, float
return new_pt;
}
-/**
- * Sets the handle type of the selected control points.
- * \param type_1, type_2: Handle type for the first handle. HD_VECT, HD_AUTO, HD_FREE, or HD_ALIGN.
- * \note Requires #BKE_curveprofile_update call after.
- */
void BKE_curveprofile_selected_handle_set(CurveProfile *profile, int type_1, int type_2)
{
for (int i = 0; i < profile->path_len; i++) {
@@ -397,11 +354,6 @@ static CurveProfilePoint mirror_point(const CurveProfilePoint *point)
return new_point;
}
-/**
- * Flips the profile across the diagonal so that its orientation is reversed.
- *
- * \note Requires #BKE_curveprofile_update call after.
- */
void BKE_curveprofile_reverse(CurveProfile *profile)
{
/* When there are only two points, reversing shouldn't do anything. */
@@ -478,19 +430,11 @@ static void curveprofile_build_steps(CurveProfile *profile)
}
}
-/**
- * Reset the view to the clipping rectangle.
- */
void BKE_curveprofile_reset_view(CurveProfile *profile)
{
profile->view_rect = profile->clip_rect;
}
-/**
- * Resets the profile to the current preset.
- *
- * \note Requires #BKE_curveprofile_update call after.
- */
void BKE_curveprofile_reset(CurveProfile *profile)
{
MEM_SAFE_FREE(profile->path);
@@ -871,10 +815,6 @@ static void create_samples(CurveProfile *profile,
MEM_freeN(n_samples);
}
-/**
- * Sets the default settings and clip range for the profile widget.
- * Does not generate either table.
- */
void BKE_curveprofile_set_defaults(CurveProfile *profile)
{
profile->flag = PROF_USE_CLIP;
@@ -895,12 +835,6 @@ void BKE_curveprofile_set_defaults(CurveProfile *profile)
profile->changed_timestamp = 0;
}
-/**
- * Refreshes the higher resolution table sampled from the input points. A call to this or
- * #BKE_curveprofile_update is needed before evaluation functions that use the table.
- * Also sets the number of segments used for the display preview of the locations
- * of the sampled points.
- */
void BKE_curveprofile_init(CurveProfile *profile, short segments_len)
{
if (segments_len != profile->segments_len) {
@@ -1044,12 +978,6 @@ static void curveprofile_make_segments_table(CurveProfile *profile)
profile->segments = new_table;
}
-/**
- * Should be called after the widget is changed. Does profile and remove double checks and more
- * importantly, recreates the display / evaluation and segments tables.
- * \param update_flags: Bitfield with fields defined in header file. Controls removing doubles and
- * clipping.
- */
void BKE_curveprofile_update(CurveProfile *profile, const int update_flags)
{
CurveProfilePoint *points = profile->path;
@@ -1105,13 +1033,6 @@ void BKE_curveprofile_update(CurveProfile *profile, const int update_flags)
}
}
-/**
- * Does a single evaluation along the profile's path.
- * Travels down (length_portion * path) length and returns the position at that point.
- *
- * \param length_portion: The portion (0 to 1) of the path's full length to sample at.
- * \note Requires #BKE_curveprofile_init or #BKE_curveprofile_update call before to fill table.
- */
void BKE_curveprofile_evaluate_length_portion(const CurveProfile *profile,
float length_portion,
float *x_out,
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index 743d5471aa7..090de26c230 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -73,7 +73,6 @@ BLI_STATIC_ASSERT(ARRAY_SIZE(((CustomData *)NULL)->typemap) == CD_NUMTYPES, "siz
static CLG_LogRef LOG = {"bke.customdata"};
-/** Update mask_dst with layers defined in mask_src (equivalent to a bitwise OR). */
void CustomData_MeshMasks_update(CustomData_MeshMasks *mask_dst,
const CustomData_MeshMasks *mask_src)
{
@@ -84,7 +83,6 @@ void CustomData_MeshMasks_update(CustomData_MeshMasks *mask_dst,
mask_dst->lmask |= mask_src->lmask;
}
-/** Return True if all layers set in \a mask_required are also set in \a mask_ref */
bool CustomData_MeshMasks_are_matching(const CustomData_MeshMasks *mask_ref,
const CustomData_MeshMasks *mask_required)
{
@@ -2182,7 +2180,6 @@ bool CustomData_merge(const struct CustomData *source,
return changed;
}
-/* NOTE: Take care of referenced layers by yourself! */
void CustomData_realloc(CustomData *data, int totelem)
{
for (int i = 0; i < data->totlayer; i++) {
@@ -2444,8 +2441,6 @@ void CustomData_set_layer_stencil(CustomData *data, int type, int n)
}
}
-/* For using with an index from CustomData_get_active_layer_index and
- * CustomData_get_render_layer_index. */
void CustomData_set_layer_active_index(CustomData *data, int type, int n)
{
for (int i = 0; i < data->totlayer; i++) {
@@ -2648,7 +2643,6 @@ void *CustomData_add_layer(
return NULL;
}
-/* Same as above but accepts a name. */
void *CustomData_add_layer_named(CustomData *data,
int type,
eCDAllocType alloctype,
@@ -3068,18 +3062,6 @@ void CustomData_free_elem(CustomData *data, int index, int count)
#define SOURCE_BUF_SIZE 100
-/**
- * Interpolate given custom data source items into a single destination one.
- *
- * \param src_indices: Indices of every source items to interpolate into the destination one.
- * \param weights: The weight to apply to each source value individually. If NULL, they will be
- * averaged.
- * \param sub_weights: The weights of sub-items, only used to affect each corners of a
- * tessellated face data (should always be and array of four values).
- * \param count: The number of source items to interpolate.
- * \param dest_index: Index of the destination item, in which to put the result of the
- * interpolation.
- */
void CustomData_interp(const CustomData *source,
CustomData *dest,
const int *src_indices,
@@ -3162,13 +3144,6 @@ void CustomData_interp(const CustomData *source,
}
}
-/**
- * Swap data inside each item, for all layers.
- * This only applies to item types that may store several sub-item data
- * (e.g. corner data [UVs, VCol, ...] of tessellated faces).
- *
- * \param corner_indices: A mapping 'new_index -> old_index' of sub-item data.
- */
void CustomData_swap_corners(struct CustomData *data, int index, const int *corner_indices)
{
for (int i = 0; i < data->totlayer; i++) {
@@ -3182,9 +3157,6 @@ void CustomData_swap_corners(struct CustomData *data, int index, const int *corn
}
}
-/**
- * Swap two items of given custom data, in all available layers.
- */
void CustomData_swap(struct CustomData *data, const int index_a, const int index_b)
{
char buff_static[256];
@@ -3362,7 +3334,7 @@ void CustomData_set(const CustomData *data, int index, int type, const void *sou
}
/* BMesh functions */
-/* needed to convert to/from different face reps */
+
void CustomData_to_bmeshpoly(CustomData *fdata, CustomData *ldata, int totloop)
{
for (int i = 0; i < fdata->totlayer; i++) {
@@ -3418,12 +3390,6 @@ void CustomData_from_bmeshpoly(CustomData *fdata, CustomData *ldata, int total)
}
#ifndef NDEBUG
-/**
- * Debug check, used to assert when we expect layers to be in/out of sync.
- *
- * \param fallback: Use when there are no layers to handle,
- * since callers may expect success or failure.
- */
bool CustomData_from_bmeshpoly_test(CustomData *fdata, CustomData *ldata, bool fallback)
{
int a_num = 0, b_num = 0;
@@ -3491,11 +3457,6 @@ void CustomData_bmesh_update_active_layers(CustomData *fdata, CustomData *ldata)
}
}
-/* update active indices for active/render/clone/stencil custom data layers
- * based on indices from fdata layers
- * used by do_versions in readfile.c when creating pdata and ldata for pre-bmesh
- * meshes and needed to preserve active/render/clone/stencil flags set in pre-bmesh files
- */
void CustomData_bmesh_do_versions_update_active_layers(CustomData *fdata, CustomData *ldata)
{
int act;
@@ -3677,9 +3638,6 @@ void CustomData_bmesh_free_block(CustomData *data, void **block)
*block = NULL;
}
-/**
- * Same as #CustomData_bmesh_free_block but zero the memory rather than freeing.
- */
void CustomData_bmesh_free_block_data(CustomData *data, void *block)
{
if (block == NULL) {
@@ -3713,9 +3671,6 @@ static void CustomData_bmesh_alloc_block(CustomData *data, void **block)
}
}
-/**
- * A selective version of #CustomData_bmesh_free_block_data.
- */
void CustomData_bmesh_free_block_data_exclude_by_type(CustomData *data,
void *block,
const CustomDataMask mask_exclude)
@@ -3832,9 +3787,6 @@ void CustomData_bmesh_copy_data(const CustomData *source,
CustomData_bmesh_copy_data_exclude_by_type(source, dest, src_block, dest_block, 0);
}
-/* BMesh Custom Data Functions.
- * Should replace edit-mesh ones with these as well, due to more efficient memory alloc.
- */
void *CustomData_bmesh_get(const CustomData *data, void *block, int type)
{
/* get the layer index of the first layer of type */
@@ -3857,7 +3809,6 @@ void *CustomData_bmesh_get_n(const CustomData *data, void *block, int type, int
return POINTER_OFFSET(block, data->layers[layer_index + n].offset);
}
-/* Gets from the layer at physical index n, NOTE: doesn't check type. */
void *CustomData_bmesh_get_layer_n(const CustomData *data, void *block, int n)
{
if (n < 0 || n >= data->totlayer) {
@@ -3902,7 +3853,6 @@ bool CustomData_has_math(const struct CustomData *data)
return false;
}
-/* a non bmesh version would have to check layer->data */
bool CustomData_bmesh_has_free(const struct CustomData *data)
{
for (int i = 0; i < data->totlayer; i++) {
@@ -3938,8 +3888,6 @@ bool CustomData_has_referenced(const struct CustomData *data)
return false;
}
-/* copies the "value" (e.g. mloopuv uv or mloopcol colors) from one block to
- * another, while not overwriting anything else (e.g. flags). */
void CustomData_data_copy_value(int type, const void *source, void *dest)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
@@ -3956,8 +3904,6 @@ void CustomData_data_copy_value(int type, const void *source, void *dest)
}
}
-/* Mixes the "value" (e.g. mloopuv uv or mloopcol colors) from one block into
- * another, while not overwriting anything else (e.g. flags). */
void CustomData_data_mix_value(
int type, const void *source, void *dest, const int mixmode, const float mixfactor)
{
@@ -4074,10 +4020,6 @@ void CustomData_bmesh_set_layer_n(CustomData *data, void *block, int n, const vo
}
}
-/**
- * \note src_blocks_ofs & dst_block_ofs
- * must be pointers to the data, offset by layer->offset already.
- */
void CustomData_bmesh_interp_n(CustomData *data,
const void **src_blocks_ofs,
const float *weights,
@@ -4146,11 +4088,6 @@ void CustomData_bmesh_interp(CustomData *data,
}
}
-/**
- * \param use_default_init: initializes data which can't be copied,
- * typically you'll want to use this if the BM_xxx create function
- * is called with BM_CREATE_SKIP_CD flag
- */
void CustomData_to_bmesh_block(const CustomData *source,
CustomData *dest,
int src_index,
@@ -4265,25 +4202,6 @@ void CustomData_file_write_info(int type, const char **r_struct_name, int *r_str
*r_struct_num = typeInfo->structnum;
}
-/**
- * Prepare given custom data for file writing.
- *
- * \param data: the customdata to tweak for .blend file writing (modified in place).
- * \param r_write_layers: contains a reduced set of layers to be written to file,
- * use it with writestruct_at_address()
- * (caller must free it if != \a write_layers_buff).
- *
- * \param write_layers_buff: an optional buffer for r_write_layers (to avoid allocating it).
- * \param write_layers_size: the size of pre-allocated \a write_layer_buff.
- *
- * \warning After this func has ran, given custom data is no more valid from Blender PoV
- * (its totlayer is invalid). This func shall always be called with localized data
- * (as it is in write_meshes()).
- *
- * \note data->typemap is not updated here, since it is always rebuilt on file read anyway.
- * This means written typemap does not match written layers (as returned by \a r_write_layers).
- * Trivial to fix is ever needed.
- */
void CustomData_blend_write_prepare(CustomData *data,
CustomDataLayer **r_write_layers,
CustomDataLayer *write_layers_buff,
@@ -4337,20 +4255,12 @@ const char *CustomData_layertype_name(int type)
return layerType_getName(type);
}
-/**
- * Can only ever be one of these.
- */
bool CustomData_layertype_is_singleton(int type)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
return typeInfo->defaultname == NULL;
}
-/**
- * Has dynamically allocated members.
- * This is useful to know if operations such as #memcmp are
- * valid when comparing data from two layers.
- */
bool CustomData_layertype_is_dynamic(int type)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
@@ -4358,9 +4268,6 @@ bool CustomData_layertype_is_dynamic(int type)
return (typeInfo->free != NULL);
}
-/**
- * \return Maximum number of layers of given \a type, -1 means 'no limit'.
- */
int CustomData_layertype_layers_max(const int type)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
@@ -4502,12 +4409,6 @@ bool CustomData_verify_versions(struct CustomData *data, int index)
return keeplayer;
}
-/**
- * Validate and fix data of \a layer,
- * if possible (needs relevant callback in layer's type to be defined).
- *
- * \return True if some errors were found.
- */
bool CustomData_layer_validate(CustomDataLayer *layer, const uint totitems, const bool do_fixes)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type);
@@ -4971,7 +4872,6 @@ static void customdata_data_transfer_interp_generic(const CustomDataTransferLaye
MEM_freeN(tmp_dst);
}
-/* Normals are special, we need to take care of source & destination spaces... */
void customdata_data_transfer_interp_normal_normals(const CustomDataTransferLayerMap *laymap,
void *data_dst,
const void **sources,
@@ -5118,9 +5018,6 @@ static void write_grid_paint_mask(BlendWriter *writer, int count, GridPaintMask
}
}
-/**
- * \param layers: The layers argument assigned by #CustomData_blend_write_prepare.
- */
void CustomData_blend_write(BlendWriter *writer,
CustomData *data,
CustomDataLayer *layers,
diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c
index b83621e8b79..f036f1ced87 100644
--- a/source/blender/blenkernel/intern/data_transfer.c
+++ b/source/blender/blenkernel/intern/data_transfer.c
@@ -93,10 +93,6 @@ void BKE_object_data_transfer_dttypes_to_cdmask(const int dtdata_types,
}
}
-/**
- * Check what can do each layer type
- * (if it is actually handled by transfer-data, if it supports advanced mixing.
- */
bool BKE_object_data_transfer_get_dttypes_capacity(const int dtdata_types,
bool *r_advanced_mixing,
bool *r_threshold)
@@ -1232,12 +1228,6 @@ static bool data_transfer_layersmapping_generate(ListBase *r_map,
return false;
}
-/**
- * Transfer data *layout* of selected types from source to destination object.
- * By default, it only creates new data layers if needed on \a ob_dst.
- * If \a use_delete is true, it will also delete data layers on \a ob_dst that do not match those
- * from \a ob_src, to get (as much as possible) exact copy of source data layout.
- */
void BKE_object_data_transfer_layout(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob_src,
diff --git a/source/blender/blenkernel/intern/data_transfer_intern.h b/source/blender/blenkernel/intern/data_transfer_intern.h
index c5d7dd42cb8..e40b4946f52 100644
--- a/source/blender/blenkernel/intern/data_transfer_intern.h
+++ b/source/blender/blenkernel/intern/data_transfer_intern.h
@@ -68,6 +68,10 @@ bool data_transfer_layersmapping_vgroups(struct ListBase *r_map,
const int tolayers);
/* Defined in customdata.c */
+
+/**
+ * Normals are special, we need to take care of source & destination spaces.
+ */
void customdata_data_transfer_interp_normal_normals(const CustomDataTransferLayerMap *laymap,
void *data_dst,
const void **sources,
diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c
index 13222747a52..6b429a146d4 100644
--- a/source/blender/blenkernel/intern/deform.c
+++ b/source/blender/blenkernel/intern/deform.c
@@ -107,11 +107,6 @@ bDeformGroup *BKE_defgroup_duplicate(const bDeformGroup *ingroup)
return outgroup;
}
-/**
- * Overwrite weights filtered by vgroup_subset.
- * - do nothing if neither are set.
- * - add destination weight if needed
- */
void BKE_defvert_copy_subset(MDeformVert *dvert_dst,
const MDeformVert *dvert_src,
const bool *vgroup_subset,
@@ -125,11 +120,6 @@ void BKE_defvert_copy_subset(MDeformVert *dvert_dst,
}
}
-/**
- * Overwrite weights filtered by vgroup_subset and with mirroring specified by the flip map
- * - do nothing if neither are set.
- * - add destination weight if needed
- */
void BKE_defvert_mirror_subset(MDeformVert *dvert_dst,
const MDeformVert *dvert_src,
const bool *vgroup_subset,
@@ -168,11 +158,6 @@ void BKE_defvert_copy(MDeformVert *dvert_dst, const MDeformVert *dvert_src)
}
}
-/**
- * Copy an index from one dvert to another.
- * - do nothing if neither are set.
- * - add destination weight if needed.
- */
void BKE_defvert_copy_index(MDeformVert *dvert_dst,
const int defgroup_dst,
const MDeformVert *dvert_src,
@@ -197,10 +182,6 @@ void BKE_defvert_copy_index(MDeformVert *dvert_dst,
}
}
-/**
- * Only sync over matching weights, don't add or remove groups
- * warning, loop within loop.
- */
void BKE_defvert_sync(MDeformVert *dvert_dst, const MDeformVert *dvert_src, const bool use_ensure)
{
if (dvert_src->totweight && dvert_dst->totweight) {
@@ -221,9 +202,6 @@ void BKE_defvert_sync(MDeformVert *dvert_dst, const MDeformVert *dvert_src, cons
}
}
-/**
- * be sure all flip_map values are valid
- */
void BKE_defvert_sync_mapped(MDeformVert *dvert_dst,
const MDeformVert *dvert_src,
const int *flip_map,
@@ -250,9 +228,6 @@ void BKE_defvert_sync_mapped(MDeformVert *dvert_dst,
}
}
-/**
- * be sure all flip_map values are valid
- */
void BKE_defvert_remap(MDeformVert *dvert, const int *map, const int map_len)
{
MDeformWeight *dw = dvert->dw;
@@ -265,9 +240,6 @@ void BKE_defvert_remap(MDeformVert *dvert, const int *map, const int map_len)
}
}
-/**
- * Same as #BKE_defvert_normalize but takes a bool array.
- */
void BKE_defvert_normalize_subset(MDeformVert *dvert,
const bool *vgroup_subset,
const int vgroup_tot)
@@ -334,9 +306,6 @@ void BKE_defvert_normalize(MDeformVert *dvert)
}
}
-/**
- * Same as BKE_defvert_normalize() if the locked vgroup is not a member of the subset
- */
void BKE_defvert_normalize_lock_single(MDeformVert *dvert,
const bool *vgroup_subset,
const int vgroup_tot,
@@ -391,9 +360,6 @@ void BKE_defvert_normalize_lock_single(MDeformVert *dvert,
}
}
-/**
- * Same as BKE_defvert_normalize() if no locked vgroup is a member of the subset
- */
void BKE_defvert_normalize_lock_map(MDeformVert *dvert,
const bool *vgroup_subset,
const int vgroup_tot,
@@ -557,11 +523,35 @@ bDeformGroup *BKE_object_defgroup_find_name(const Object *ob, const char *name)
int BKE_id_defgroup_name_index(const ID *id, const char *name)
{
- if (name == NULL || name[0] == '\0') {
+ int index;
+ if (!BKE_id_defgroup_name_find(id, name, &index, NULL)) {
return -1;
}
+ return index;
+}
+
+bool BKE_id_defgroup_name_find(const struct ID *id,
+ const char *name,
+ int *r_index,
+ struct bDeformGroup **r_group)
+{
+ if (name == NULL || name[0] == '\0') {
+ return false;
+ }
const ListBase *defbase = BKE_id_defgroup_list_get(id);
- return BLI_findstringindex(defbase, name, offsetof(bDeformGroup, name));
+ int index;
+ LISTBASE_FOREACH_INDEX (bDeformGroup *, group, defbase, index) {
+ if (STREQ(name, group->name)) {
+ if (r_index != NULL) {
+ *r_index = index;
+ }
+ if (r_group != NULL) {
+ *r_group = group;
+ }
+ return true;
+ }
+ }
+ return false;
}
const ListBase *BKE_object_defgroup_list(const Object *ob)
@@ -586,17 +576,11 @@ int BKE_object_defgroup_count(const Object *ob)
return BLI_listbase_count(BKE_object_defgroup_list(ob));
}
-/**
- * \note For historical reasons, the index starts at 1 rather than 0.
- */
int BKE_object_defgroup_active_index_get(const Object *ob)
{
return *object_defgroup_active_index_get_p(ob);
}
-/**
- * \note For historical reasons, the index starts at 1 rather than 0.
- */
void BKE_object_defgroup_active_index_set(Object *ob, const int new_index)
{
/* Cast away const just for the accessor. */
@@ -604,9 +588,6 @@ void BKE_object_defgroup_active_index_set(Object *ob, const int new_index)
*index = new_index;
}
-/**
- * \note caller must free.
- */
int *BKE_object_defgroup_flip_map(const Object *ob, int *flip_map_len, const bool use_default)
{
const ListBase *defbase = BKE_object_defgroup_list(ob);
@@ -646,9 +627,6 @@ int *BKE_object_defgroup_flip_map(const Object *ob, int *flip_map_len, const boo
return map;
}
-/**
- * \note caller must free.
- */
int *BKE_object_defgroup_flip_map_single(const Object *ob,
int *flip_map_len,
const bool use_default,
@@ -745,13 +723,6 @@ float BKE_defvert_find_weight(const struct MDeformVert *dvert, const int defgrou
return dw ? dw->weight : 0.0f;
}
-/**
- * Take care with this the rationale is:
- * - if the object has no vertex group. act like vertex group isn't set and return 1.0,
- * - if the vertex group exists but the 'defgroup' isn't found on this vertex, _still_ return 0.0
- *
- * This is a bit confusing, just saves some checks from the caller.
- */
float BKE_defvert_array_find_weight_safe(const struct MDeformVert *dvert,
const int index,
const int defgroup)
@@ -790,11 +761,6 @@ MDeformWeight *BKE_defvert_find_index(const MDeformVert *dvert, const int defgro
return NULL;
}
-/**
- * Ensures that mv has a deform weight entry for the specified defweight group.
- *
- * \note this function is mirrored in editmesh_tools.c, for use for editvertices.
- */
MDeformWeight *BKE_defvert_ensure_index(MDeformVert *dvert, const int defgroup)
{
MDeformWeight *dw_new;
@@ -826,15 +792,10 @@ MDeformWeight *BKE_defvert_ensure_index(MDeformVert *dvert, const int defgroup)
return dw_new;
}
-/* TODO: merge with code above! */
-
-/**
- * Adds the given vertex to the specified vertex group, with given weight.
- *
- * \warning this does NOT check for existing, assume caller already knows its not there.
- */
void BKE_defvert_add_index_notest(MDeformVert *dvert, int defgroup, const float weight)
{
+ /* TODO: merge with #BKE_defvert_ensure_index! */
+
MDeformWeight *dw_new;
/* do this check always, this function is used to check for it */
@@ -856,11 +817,6 @@ void BKE_defvert_add_index_notest(MDeformVert *dvert, int defgroup, const float
dvert->totweight++;
}
-/**
- * Removes the given vertex from the vertex group.
- *
- * \warning This function frees the given MDeformWeight, do not use it afterward!
- */
void BKE_defvert_remove_group(MDeformVert *dvert, MDeformWeight *dw)
{
if (dvert && dw) {
@@ -899,10 +855,6 @@ void BKE_defvert_clear(MDeformVert *dvert)
dvert->totweight = 0;
}
-/**
- * \return The first group index shared by both deform verts
- * or -1 if none are found.
- */
int BKE_defvert_find_shared(const MDeformVert *dvert_a, const MDeformVert *dvert_b)
{
if (dvert_a->totweight && dvert_b->totweight) {
@@ -919,9 +871,6 @@ int BKE_defvert_find_shared(const MDeformVert *dvert_a, const MDeformVert *dvert
return -1;
}
-/**
- * return true if has no weights
- */
bool BKE_defvert_is_weight_zero(const struct MDeformVert *dvert, const int defgroup_tot)
{
MDeformWeight *dw = dvert->dw;
@@ -936,9 +885,6 @@ bool BKE_defvert_is_weight_zero(const struct MDeformVert *dvert, const int defgr
return true;
}
-/**
- * \return The total weight in all groups marked in the selection mask.
- */
float BKE_defvert_total_selected_weight(const struct MDeformVert *dv,
int defbase_tot,
const bool *defbase_sel)
@@ -961,14 +907,6 @@ float BKE_defvert_total_selected_weight(const struct MDeformVert *dv,
return total;
}
-/**
- * \return The representative weight of a multipaint group, used for
- * viewport colors and actual painting.
- *
- * Result equal to sum of weights with auto normalize, and average otherwise.
- * Value is not clamped, since painting relies on multiplication being always
- * commutative with the collective weight function.
- */
float BKE_defvert_multipaint_collective_weight(const struct MDeformVert *dv,
int defbase_tot,
const bool *defbase_sel,
@@ -986,11 +924,6 @@ float BKE_defvert_multipaint_collective_weight(const struct MDeformVert *dv,
return total;
}
-/**
- * Computes the display weight for the lock relative weight paint mode.
- *
- * \return weight divided by 1-locked_weight with division by zero check
- */
float BKE_defvert_calc_lock_relative_weight(float weight,
float locked_weight,
float unlocked_weight)
@@ -1019,11 +952,6 @@ float BKE_defvert_calc_lock_relative_weight(float weight,
return weight / (1.0f - locked_weight);
}
-/**
- * Computes the display weight for the lock relative weight paint mode, using weight data.
- *
- * \return weight divided by unlocked, or 1-locked_weight with division by zero check.
- */
float BKE_defvert_lock_relative_weight(float weight,
const struct MDeformVert *dv,
int defbase_tot,
@@ -1115,10 +1043,6 @@ void BKE_defvert_extract_vgroup_to_vertweights(MDeformVert *dvert,
}
}
-/**
- * The following three make basic interpolation,
- * using temp vert_weights array to avoid looking up same weight several times.
- */
void BKE_defvert_extract_vgroup_to_edgeweights(MDeformVert *dvert,
const int defgroup,
const int num_verts,
@@ -1451,7 +1375,7 @@ bool data_transfer_layersmapping_vgroups(ListBase *r_map,
* and even have to support NULL data_src in transfer data code
* (we always create a data_dst, though).
*
- * Note: Above comment is outdated, but this function was written when that was true.
+ * NOTE: Above comment is outdated, but this function was written when that was true.
*/
const ListBase *src_defbase = BKE_object_defgroup_list(ob_src);
diff --git a/source/blender/blenkernel/intern/displist.cc b/source/blender/blenkernel/intern/displist.cc
index 0bf436aa8b2..edf043de63f 100644
--- a/source/blender/blenkernel/intern/displist.cc
+++ b/source/blender/blenkernel/intern/displist.cc
@@ -66,8 +66,6 @@
using blender::IndexRange;
-static void boundbox_displist_object(Object *ob);
-
static void displist_elem_free(DispList *dl)
{
if (dl) {
@@ -404,12 +402,6 @@ static void curve_to_displist(const Curve *cu,
}
}
-/**
- * \param normal_proj: Optional normal that's used to project the scanfill verts into 2d coords.
- * Pass this along if known since it saves time calculating the normal.
- * This is also used to initialize #DispList.nors (one normal per display list).
- * \param flipnormal: Flip the normal (same as passing \a normal_proj negated)
- */
void BKE_displist_fill(const ListBase *dispbase,
ListBase *to,
const float normal_proj[3],
@@ -832,7 +824,7 @@ static bool do_curve_implicit_mesh_conversion(const Curve *curve,
}
/* Curve objects with implicit "tube" meshes should convert implicitly to a mesh. */
- if (curve->ext1 != 0.0f || curve->ext2 != 0.0f) {
+ if (curve->extrude != 0.0f || curve->bevel_radius != 0.0f) {
return true;
}
@@ -1312,11 +1304,11 @@ static GeometrySet evaluate_curve_type_object(Depsgraph *depsgraph,
ListBase dlbev = BKE_curve_bevel_make(cu);
/* no bevel or extrude, and no width correction? */
- if (BLI_listbase_is_empty(&dlbev) && cu->width == 1.0f) {
+ if (BLI_listbase_is_empty(&dlbev) && cu->offset == 1.0f) {
curve_to_displist(cu, deformed_nurbs, for_render, r_dispbase);
}
else {
- const float widfac = cu->width - 1.0f;
+ const float widfac = cu->offset - 1.0f;
const BevList *bl = (BevList *)ob->runtime.curve_cache->bev.first;
const Nurb *nu = (Nurb *)deformed_nurbs->first;
@@ -1528,7 +1520,7 @@ void BKE_displist_make_curveTypes(Depsgraph *depsgraph,
ob->runtime.geometry_set_eval = new GeometrySet(std::move(geometry));
}
- boundbox_displist_object(ob);
+ BKE_object_boundbox_calc_from_evaluated_geometry(ob);
}
void BKE_displist_minmax(const ListBase *dispbase, float min[3], float max[3])
@@ -1536,7 +1528,7 @@ void BKE_displist_minmax(const ListBase *dispbase, float min[3], float max[3])
bool doit = false;
LISTBASE_FOREACH (const DispList *, dl, dispbase) {
- const int tot = (dl->type == DL_INDEX3) ? dl->nr : dl->nr * dl->parts;
+ const int tot = (ELEM(dl->type, DL_INDEX3, DL_INDEX4)) ? dl->nr : dl->nr * dl->parts;
for (const int i : IndexRange(tot)) {
minmax_v3v3_v3(min, max, &dl->verts[i * 3]);
}
@@ -1551,30 +1543,3 @@ void BKE_displist_minmax(const ListBase *dispbase, float min[3], float max[3])
zero_v3(max);
}
}
-
-/* this is confusing, there's also min_max_object, applying the obmat... */
-static void boundbox_displist_object(Object *ob)
-{
- BLI_assert(ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT));
- /* Curve's BB is already calculated as a part of modifier stack,
- * here we only calculate object BB based on final display list. */
-
- /* object's BB is calculated from final displist */
- if (ob->runtime.bb == nullptr) {
- ob->runtime.bb = (BoundBox *)MEM_callocN(sizeof(BoundBox), __func__);
- }
-
- const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
- if (mesh_eval) {
- BKE_object_boundbox_calc_from_mesh(ob, mesh_eval);
- }
- else {
- float min[3], max[3];
-
- INIT_MINMAX(min, max);
- BKE_displist_minmax(&ob->runtime.curve_cache->disp, min, max);
- BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
-
- ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY;
- }
-}
diff --git a/source/blender/blenkernel/intern/displist_tangent.c b/source/blender/blenkernel/intern/displist_tangent.c
index 5c969d52aea..4451961ad94 100644
--- a/source/blender/blenkernel/intern/displist_tangent.c
+++ b/source/blender/blenkernel/intern/displist_tangent.c
@@ -29,6 +29,10 @@
/* interface */
#include "mikktspace.h"
+/* -------------------------------------------------------------------- */
+/** \name Internal Types
+ * \{ */
+
typedef struct {
const DispList *dl;
float (*tangent)[4]; /* destination */
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index 05f1e9b286f..ce92a34de47 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -327,7 +327,6 @@ static int dynamicPaint_surfaceNumOfPoints(DynamicPaintSurface *surface)
return 0;
}
-/* get currently active surface (in user interface) */
DynamicPaintSurface *get_activeSurface(DynamicPaintCanvasSettings *canvas)
{
return BLI_findlink(&canvas->surfaces, canvas->active_sur);
@@ -420,7 +419,6 @@ void dynamicPaintSurface_setUniqueName(DynamicPaintSurface *surface, const char
surface_duplicateNameExists, surface, name, '.', surface->name, sizeof(surface->name));
}
-/* change surface data to defaults on new type */
void dynamicPaintSurface_updateType(struct DynamicPaintSurface *surface)
{
if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
@@ -855,7 +853,6 @@ static void surfaceGenerateGrid(struct DynamicPaintSurface *surface)
/***************************** Freeing data ******************************/
-/* Free brush data */
void dynamicPaint_freeBrush(struct DynamicPaintModifierData *pmd)
{
if (pmd->brush) {
@@ -992,7 +989,6 @@ void dynamicPaint_freeSurface(const DynamicPaintModifierData *pmd, DynamicPaintS
MEM_freeN(surface);
}
-/* Free canvas data */
void dynamicPaint_freeCanvas(DynamicPaintModifierData *pmd)
{
if (pmd->canvas) {
@@ -1011,7 +1007,6 @@ void dynamicPaint_freeCanvas(DynamicPaintModifierData *pmd)
}
}
-/* Free whole dp modifier */
void dynamicPaint_Modifier_free(DynamicPaintModifierData *pmd)
{
if (pmd == NULL) {
@@ -1024,11 +1019,6 @@ void dynamicPaint_Modifier_free(DynamicPaintModifierData *pmd)
/***************************** Initialize and reset ******************************/
-/*
- * Creates a new surface and adds it to the list
- * If scene is null, frame range of 1-250 is used
- * A pointer to this surface is returned
- */
DynamicPaintSurface *dynamicPaint_createNewSurface(DynamicPaintCanvasSettings *canvas,
Scene *scene)
{
@@ -1106,9 +1096,6 @@ DynamicPaintSurface *dynamicPaint_createNewSurface(DynamicPaintCanvasSettings *c
return surface;
}
-/*
- * Initialize modifier data
- */
bool dynamicPaint_createType(struct DynamicPaintModifierData *pmd, int type, struct Scene *scene)
{
if (pmd) {
@@ -1721,7 +1708,6 @@ static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface
}
}
-/* clears surface data back to zero */
void dynamicPaint_clearSurface(const Scene *scene, DynamicPaintSurface *surface)
{
PaintSurfaceData *sData = surface->data;
@@ -1751,7 +1737,6 @@ void dynamicPaint_clearSurface(const Scene *scene, DynamicPaintSurface *surface)
}
}
-/* Completely (re)initializes surface (only for point cache types). */
bool dynamicPaint_resetSurface(const Scene *scene, DynamicPaintSurface *surface)
{
int numOfPoints = dynamicPaint_surfaceNumOfPoints(surface);
@@ -2079,7 +2064,6 @@ static Mesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, Object *
return result;
}
-/* update cache frame range */
void dynamicPaint_cacheUpdateFrames(DynamicPaintSurface *surface)
{
if (surface->pointcache) {
@@ -2189,7 +2173,6 @@ static void dynamicPaint_frameUpdate(DynamicPaintModifierData *pmd,
}
}
-/* Modifier call. Processes dynamic paint modifier step. */
Mesh *dynamicPaint_Modifier_do(DynamicPaintModifierData *pmd,
struct Depsgraph *depsgraph,
Scene *scene,
@@ -6369,9 +6352,6 @@ static int dynamicPaint_doStep(Depsgraph *depsgraph,
return ret;
}
-/**
- * Calculate a single frame and included sub-frames for surface.
- */
int dynamicPaint_calculateFrame(DynamicPaintSurface *surface,
struct Depsgraph *depsgraph,
Scene *scene,
diff --git a/source/blender/blenkernel/intern/editmesh.c b/source/blender/blenkernel/intern/editmesh.c
index 83e03ef44f5..805d3cdb5e3 100644
--- a/source/blender/blenkernel/intern/editmesh.c
+++ b/source/blender/blenkernel/intern/editmesh.c
@@ -39,10 +39,6 @@
#include "BKE_mesh_wrapper.h"
#include "BKE_object.h"
-/**
- * \note The caller is responsible for ensuring triangulation data,
- * typically by calling #BKE_editmesh_looptri_calc.
- */
BMEditMesh *BKE_editmesh_create(BMesh *bm)
{
BMEditMesh *em = MEM_callocN(sizeof(BMEditMesh), __func__);
@@ -75,12 +71,6 @@ BMEditMesh *BKE_editmesh_copy(BMEditMesh *em)
return em_copy;
}
-/**
- * \brief Return the BMEditMesh for a given object
- *
- * \note this function assumes this is a mesh object,
- * don't add NULL data check here. caller must do that
- */
BMEditMesh *BKE_editmesh_from_object(Object *ob)
{
BLI_assert(ob->type == OB_MESH);
@@ -158,10 +148,6 @@ void BKE_editmesh_looptri_calc(BMEditMesh *em)
});
}
-/**
- * Performing the face normal calculation at the same time as tessellation
- * gives a reasonable performance boost (approx ~20% faster).
- */
void BKE_editmesh_looptri_and_normals_calc(BMEditMesh *em)
{
BKE_editmesh_looptri_calc_ex(em,
@@ -221,7 +207,6 @@ void BKE_editmesh_free_derived_caches(BMEditMesh *em)
MEM_SAFE_FREE(em->bb_cage);
}
-/* Does not free the #BMEditMesh struct itself. */
void BKE_editmesh_free_data(BMEditMesh *em)
{
BKE_editmesh_free_derived_caches(em);
@@ -342,7 +327,6 @@ void BKE_editmesh_lnorspace_update(BMEditMesh *em, Mesh *me)
BM_lnorspace_update(bm);
}
-/* If autosmooth not already set, set it */
void BKE_editmesh_ensure_autosmooth(BMEditMesh *em, Mesh *me)
{
if (!(me->flag & ME_AUTOSMOOTH)) {
diff --git a/source/blender/blenkernel/intern/editmesh_bvh.c b/source/blender/blenkernel/intern/editmesh_bvh.c
index 5058863912f..e200a504b5d 100644
--- a/source/blender/blenkernel/intern/editmesh_bvh.c
+++ b/source/blender/blenkernel/intern/editmesh_bvh.c
@@ -565,9 +565,6 @@ static bool bmbvh_overlap_cb(void *userdata, int index_a, int index_b, int UNUSE
((verts_shared == 0) || (len_squared_v3v3(ix_pair[0], ix_pair[1]) > data->epsilon)));
}
-/**
- * Overlap indices reference the looptri's
- */
BVHTreeOverlap *BKE_bmbvh_overlap(const BMBVHTree *bmtree_a,
const BMBVHTree *bmtree_b,
unsigned int *r_overlap_tot)
@@ -591,9 +588,6 @@ static bool bmbvh_overlap_self_cb(void *userdata, int index_a, int index_b, int
return false;
}
-/**
- * Overlap indices reference the looptri's
- */
BVHTreeOverlap *BKE_bmbvh_overlap_self(const BMBVHTree *bmtree, unsigned int *r_overlap_tot)
{
struct BMBVHTree_OverlapData data;
diff --git a/source/blender/blenkernel/intern/editmesh_tangent.c b/source/blender/blenkernel/intern/editmesh_tangent.c
index da4ea742656..ff0d47e534e 100644
--- a/source/blender/blenkernel/intern/editmesh_tangent.c
+++ b/source/blender/blenkernel/intern/editmesh_tangent.c
@@ -273,13 +273,6 @@ static void emDM_calc_loop_tangents_thread(TaskPool *__restrict UNUSED(pool), vo
}
}
-/**
- * \see #BKE_mesh_calc_loop_tangent, same logic but used arrays instead of #BMesh data.
- *
- * \note This function is not so normal, its using #BMesh.ldata as input,
- * but output's to #Mesh.ldata.
- * This is done because #CD_TANGENT is cache data used only for drawing.
- */
void BKE_editmesh_loop_tangent_calc(BMEditMesh *em,
bool calc_active_tangent,
const char (*tangent_names)[MAX_NAME],
diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c
index a88339082fe..8229228976c 100644
--- a/source/blender/blenkernel/intern/effect.c
+++ b/source/blender/blenkernel/intern/effect.c
@@ -221,9 +221,6 @@ static void add_effector_evaluation(ListBase **effectors,
precalculate_effector(depsgraph, eff);
}
-/* Create list of effector relations in the collection or entire scene.
- * This is used by the depsgraph to build relations, as well as faster
- * lookup of effectors during evaluation. */
ListBase *BKE_effector_relations_create(Depsgraph *depsgraph,
ViewLayer *view_layer,
Collection *collection)
@@ -329,7 +326,6 @@ static bool is_effector_relevant(PartDeflect *pd, EffectorWeights *weights, bool
is_effector_nonzero_strength(pd);
}
-/* Create effective list of effectors from relations built beforehand. */
ListBase *BKE_effectors_create(Depsgraph *depsgraph,
Object *ob_src,
ParticleSystem *psys_src,
@@ -656,11 +652,11 @@ float effector_falloff(EffectorCache *eff,
return falloff;
}
-int closest_point_on_surface(SurfaceModifierData *surmd,
- const float co[3],
- float surface_co[3],
- float surface_nor[3],
- float surface_vel[3])
+bool closest_point_on_surface(SurfaceModifierData *surmd,
+ const float co[3],
+ float surface_co[3],
+ float surface_nor[3],
+ float surface_vel[3])
{
BVHTreeNearest nearest;
@@ -687,18 +683,18 @@ int closest_point_on_surface(SurfaceModifierData *surmd,
mul_v3_fl(surface_vel, (1.0f / 3.0f));
}
- return 1;
+ return true;
}
- return 0;
+ return false;
}
-int get_effector_data(EffectorCache *eff,
- EffectorData *efd,
- EffectedPoint *point,
- int real_velocity)
+bool get_effector_data(EffectorCache *eff,
+ EffectorData *efd,
+ EffectedPoint *point,
+ int real_velocity)
{
float cfra = DEG_get_ctime(eff->depsgraph);
- int ret = 0;
+ bool ret = false;
/* In case surface object is in Edit mode when loading the .blend,
* surface modifier is never executed and bvhtree never built, see T48415. */
@@ -730,7 +726,7 @@ int get_effector_data(EffectorCache *eff,
efd->size = 0.0f;
- ret = 1;
+ ret = true;
}
}
else if (eff->psys) {
@@ -798,7 +794,7 @@ int get_effector_data(EffectorCache *eff,
zero_v3(efd->vel);
efd->size = 0.0f;
- ret = 1;
+ ret = true;
}
if (ret) {
@@ -1130,20 +1126,6 @@ static void do_physical_effector(EffectorCache *eff,
}
}
-/* -------- BKE_effectors_apply() --------
- * generic force/speed system, now used for particles and softbodies
- * scene = scene where it runs in, for time and stuff
- * lb = listbase with objects that take part in effecting
- * opco = global coord, as input
- * force = accumulator for force
- * wind_force = accumulator for force only acting perpendicular to a surface
- * speed = actual current speed which can be altered
- * cur_time = "external" time in frames, is constant for static particles
- * loc_time = "local" time in frames, range <0-1> for the lifetime of particle
- * par_layer = layer the caller is in
- * flags = only used for softbody wind now
- * guide = old speed of particle
- */
void BKE_effectors_apply(ListBase *effectors,
ListBase *colliders,
EffectorWeights *weights,
@@ -1152,6 +1134,22 @@ void BKE_effectors_apply(ListBase *effectors,
float *wind_force,
float *impulse)
{
+ /* WARNING(@campbellbarton): historic comment?
+ * Many of these parameters don't exist!
+ *
+ * scene = scene where it runs in, for time and stuff.
+ * lb = listbase with objects that take part in effecting.
+ * opco = global coord, as input.
+ * force = accumulator for force.
+ * wind_force = accumulator for force only acting perpendicular to a surface.
+ * speed = actual current speed which can be altered.
+ * cur_time = "external" time in frames, is constant for static particles.
+ * loc_time = "local" time in frames, range <0-1> for the lifetime of particle.
+ * par_layer = layer the caller is in.
+ * flags = only used for soft-body wind now.
+ * guide = old speed of particle.
+ */
+
/*
* Modifies the force on a particle according to its
* relation with the effector object
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index bbf61c51bfb..5bbfc0913a1 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -77,7 +77,6 @@ FCurve *BKE_fcurve_create(void)
/** \name F-Curve Data Free
* \{ */
-/* Frees the F-Curve itself too, so make sure BLI_remlink is called before calling this... */
void BKE_fcurve_free(FCurve *fcu)
{
if (fcu == NULL) {
@@ -99,7 +98,6 @@ void BKE_fcurve_free(FCurve *fcu)
MEM_freeN(fcu);
}
-/* Frees a list of F-Curves. */
void BKE_fcurves_free(ListBase *list)
{
FCurve *fcu, *fcn;
@@ -128,7 +126,6 @@ void BKE_fcurves_free(ListBase *list)
/** \name F-Curve Data Copy
* \{ */
-/* Duplicate a F-Curve. */
FCurve *BKE_fcurve_copy(const FCurve *fcu)
{
FCurve *fcu_d;
@@ -161,7 +158,6 @@ FCurve *BKE_fcurve_copy(const FCurve *fcu)
return fcu_d;
}
-/* Duplicate a list of F-Curves. */
void BKE_fcurves_copy(ListBase *dst, ListBase *src)
{
FCurve *dfcu, *sfcu;
@@ -181,10 +177,6 @@ void BKE_fcurves_copy(ListBase *dst, ListBase *src)
}
}
-/**
- * Callback used by lib_query to walk over all ID usages (mimics `foreach_id` callback of
- * `IDTypeInfo` structure).
- */
void BKE_fcurve_foreach_id(FCurve *fcu, LibraryForeachIDData *data)
{
ChannelDriver *driver = fcu->driver;
@@ -221,7 +213,6 @@ void BKE_fcurve_foreach_id(FCurve *fcu, LibraryForeachIDData *data)
/* ----------------- Finding F-Curves -------------------------- */
-/* High level function to get an fcurve from C without having the RNA. */
FCurve *id_data_find_fcurve(
ID *id, void *data, StructRNA *type, const char *prop_name, int index, bool *r_driven)
{
@@ -273,8 +264,6 @@ FCurve *id_data_find_fcurve(
return fcu;
}
-/* Find the F-Curve affecting the given RNA-access path + index,
- * in the list of F-Curves provided. */
FCurve *BKE_fcurve_find(ListBase *list, const char rna_path[], const int array_index)
{
FCurve *fcu;
@@ -304,7 +293,6 @@ FCurve *BKE_fcurve_find(ListBase *list, const char rna_path[], const int array_i
/** \name FCurve Iteration
* \{ */
-/* Quick way to loop over all fcurves of a given 'path'. */
FCurve *BKE_fcurve_iter_step(FCurve *fcu_iter, const char rna_path[])
{
FCurve *fcu;
@@ -325,18 +313,6 @@ FCurve *BKE_fcurve_iter_step(FCurve *fcu_iter, const char rna_path[])
return NULL;
}
-/**
- * Get list of LinkData's containing pointers to the F-Curves
- * which control the types of data indicated.
- *
- * Lists...
- * - dst: list of LinkData's matching the criteria returned.
- * List must be freed after use, and is assumed to be empty when passed.
- * - src: list of F-Curves to search through
- * Filters...
- * - dataPrefix: i.e. 'pose.bones[' or 'nodes['
- * - dataName: name of entity within "" immediately following the prefix
- */
int BKE_fcurves_filter(ListBase *dst, ListBase *src, const char *dataPrefix, const char *dataName)
{
FCurve *fcu;
@@ -601,9 +577,6 @@ static int BKE_fcurve_bezt_binarysearch_index_ex(const BezTriple array[],
return start;
}
-/* Binary search algorithm for finding where to insert BezTriple. (for use by insert_bezt_fcurve)
- * Returns the index to insert at (data already at that index will be offset if replace is 0)
- */
int BKE_fcurve_bezt_binarysearch_index(const BezTriple array[],
const float frame,
const int arraylen,
@@ -667,7 +640,6 @@ static short get_fcurve_end_keyframes(FCurve *fcu,
return found;
}
-/* Calculate the extents of F-Curve's data. */
bool BKE_fcurve_calc_bounds(FCurve *fcu,
float *xmin,
float *xmax,
@@ -798,7 +770,6 @@ bool BKE_fcurve_calc_bounds(FCurve *fcu,
return foundvert;
}
-/* Calculate the extents of F-Curve's keyframes. */
bool BKE_fcurve_calc_range(
FCurve *fcu, float *start, float *end, const bool do_sel_only, const bool do_min_length)
{
@@ -846,14 +817,6 @@ bool BKE_fcurve_calc_range(
return foundvert;
}
-/**
- * Return an array of keyed frames, rounded to `interval`.
- *
- * \param interval: Set to 1.0 to round to whole keyframes, 0.5 for in-between key-frames, etc.
- *
- * \note An interval of zero could be supported (this implies no rounding at all),
- * however this risks very small differences in float values being treated as separate keyframes.
- */
float *BKE_fcurves_calc_keyed_frames_ex(FCurve **fcurve_array,
int fcurve_array_len,
const float interval,
@@ -902,10 +865,6 @@ float *BKE_fcurves_calc_keyed_frames(FCurve **fcurve_array,
/** \name Active Keyframe
* \{ */
-/**
- * Set the index that stores the FCurve's active keyframe, assuming that \a active_bezt
- * is already part of `fcu->bezt`. If NULL, set active keyframe index to "none."
- */
void BKE_fcurve_active_keyframe_set(FCurve *fcu, const BezTriple *active_bezt)
{
if (active_bezt == NULL) {
@@ -927,9 +886,6 @@ void BKE_fcurve_active_keyframe_set(FCurve *fcu, const BezTriple *active_bezt)
fcu->active_keyframe_index = (int)offset;
}
-/**
- * Get the active keyframe index, with sanity checks for point bounds.
- */
int BKE_fcurve_active_keyframe_index(const FCurve *fcu)
{
const int active_keyframe_index = fcu->active_keyframe_index;
@@ -963,10 +919,6 @@ void BKE_fcurve_keyframe_move_value_with_handles(struct BezTriple *keyframe, con
/** \name Status Checks
* \{ */
-/* Are keyframes on F-Curve of any use?
- * Usability of keyframes refers to whether they should be displayed,
- * and also whether they will have any influence on the final result.
- */
bool BKE_fcurve_are_keyframes_usable(FCurve *fcu)
{
/* F-Curve must exist. */
@@ -1032,9 +984,6 @@ bool BKE_fcurve_is_protected(FCurve *fcu)
return ((fcu->flag & FCURVE_PROTECTED) || ((fcu->grp) && (fcu->grp->flag & AGRP_PROTECTED)));
}
-/* Can keyframes be added to F-Curve?
- * Keyframes can only be added if they are already visible.
- */
bool BKE_fcurve_is_keyframable(FCurve *fcu)
{
/* F-Curve's keyframes must be "usable" (i.e. visible + have an effect on final result) */
@@ -1057,7 +1006,6 @@ bool BKE_fcurve_is_keyframable(FCurve *fcu)
/** \name Keyframe Column Tools
* \{ */
-/* Add a BezTriple to a column. */
static void UNUSED_FUNCTION(bezt_add_to_cfra_elem)(ListBase *lb, BezTriple *bezt)
{
CfraElem *ce, *cen;
@@ -1100,18 +1048,12 @@ static void UNUSED_FUNCTION(bezt_add_to_cfra_elem)(ListBase *lb, BezTriple *bezt
* which BezTriples/Keyframe data are ill equipped to do.
*/
-/* Basic sampling callback which acts as a wrapper for evaluate_fcurve()
- * 'data' arg here is unneeded here...
- */
float fcurve_samplingcb_evalcurve(FCurve *fcu, void *UNUSED(data), float evaltime)
{
/* Assume any interference from drivers on the curve is intended... */
return evaluate_fcurve(fcu, evaltime);
}
-/* Main API function for creating a set of sampled curve data, given some callback function
- * used to retrieve the values to store.
- */
void fcurve_store_samples(FCurve *fcu, void *data, int start, int end, FcuSampleFunc sample_cb)
{
FPoint *fpt, *new_fpt;
@@ -1159,7 +1101,6 @@ static void init_unbaked_bezt_data(BezTriple *bezt)
bezt->h1 = bezt->h2 = HD_AUTO_ANIM;
}
-/* Convert baked/sampled fcurves into bezt/regular fcurves. */
void fcurve_samples_to_keyframes(FCurve *fcu, const int start, const int end)
{
@@ -1235,7 +1176,6 @@ void fcurve_samples_to_keyframes(FCurve *fcu, const int start, const int end)
* that the handles are correct.
*/
-/* Checks if the F-Curve has a Cycles modifier, and returns the type of the cycle behavior. */
eFCU_Cycle_Type BKE_fcurve_get_cycle_type(FCurve *fcu)
{
FModifier *fcm = fcu->modifiers.first;
@@ -1269,8 +1209,6 @@ eFCU_Cycle_Type BKE_fcurve_get_cycle_type(FCurve *fcu)
return FCU_CYCLE_NONE;
}
-/* Checks if the F-Curve has a Cycles modifier with simple settings
- * that warrant transition smoothing. */
bool BKE_fcurve_is_cyclic(FCurve *fcu)
{
return BKE_fcurve_get_cycle_type(fcu) != FCU_CYCLE_NONE;
@@ -1299,13 +1237,6 @@ static BezTriple *cycle_offset_triple(
return out;
}
-/**
- * Variant of #calchandles_fcurve() that allows calculating based on a different select flag.
- *
- * \param handle_sel_flag: The flag (bezt.f1/2/3) value to use to determine selection.
- * Usually `SELECT`, but may want to use a different one at times
- * (if caller does not operate on selection).
- */
void calchandles_fcurve_ex(FCurve *fcu, eBezTriple_Flag handle_sel_flag)
{
BezTriple *bezt, *prev, *next;
@@ -1389,28 +1320,11 @@ void calchandles_fcurve_ex(FCurve *fcu, eBezTriple_Flag handle_sel_flag)
}
}
-/**
- * This function recalculates the handles of an F-Curve. Acts based on selection with `SELECT`
- * flag. To use a different flag, use #calchandles_fcurve_ex().
- *
- * If the BezTriples have been rearranged, sort them first before using this.
- */
void calchandles_fcurve(FCurve *fcu)
{
calchandles_fcurve_ex(fcu, SELECT);
}
-/**
- * Update handles, making sure the handle-types are valid (e.g. correctly deduced from an "Auto"
- * type), and recalculating their position vectors.
- * Use when something has changed handle positions.
- *
- * \param sel_flag: The flag (bezt.f1/2/3) value to use to determine selection. Usually `SELECT`,
- * but may want to use a different one at times (if caller does not operate on
- * selection).
- * \param use_handle: Check selection state of individual handles, otherwise always update both
- * handles if the key is selected.
- */
void testhandles_fcurve(FCurve *fcu, eBezTriple_Flag sel_flag, const bool use_handle)
{
BezTriple *bezt;
@@ -1430,9 +1344,6 @@ void testhandles_fcurve(FCurve *fcu, eBezTriple_Flag sel_flag, const bool use_ha
calchandles_fcurve_ex(fcu, sel_flag);
}
-/* This function sorts BezTriples so that they are arranged in chronological order,
- * as tools working on F-Curves expect that the BezTriples are in order.
- */
void sort_time_fcurve(FCurve *fcu)
{
if (fcu->bezt == NULL) {
@@ -1475,7 +1386,6 @@ void sort_time_fcurve(FCurve *fcu)
}
}
-/* This function tests if any BezTriples are out of order, thus requiring a sort. */
bool test_time_fcurve(FCurve *fcu)
{
unsigned int a;
@@ -1517,14 +1427,6 @@ bool test_time_fcurve(FCurve *fcu)
/** \name F-Curve Calculations
* \{ */
-/**
- * The length of each handle is not allowed to be more
- * than the horizontal distance between (v1-v4).
- * This is to prevent curve loops.
- *
- * This function is very similar to BKE_curve_correct_bezpart(), but allows a steeper tangent for
- * more snappy animations. This is not desired for other areas in which curves are used, though.
- */
void BKE_fcurve_correct_bezpart(const float v1[2], float v2[2], float v3[2], const float v4[2])
{
float h1[2], h2[2], len1, len2, len, fac;
@@ -1709,14 +1611,6 @@ static void berekeny(float f1, float f2, float f3, float f4, float *o, int b)
}
}
-/**
- * Adjust Bezier handles of all three given BezTriples, so that `bezt` can be inserted between
- * `prev` and `next` without changing the resulting curve shape.
- *
- * \param r_pdelta: return Y difference between `bezt` and the original curve value at its X
- * position.
- * \return Whether the split was successful.
- */
bool BKE_fcurve_bezt_subdivide_handles(struct BezTriple *bezt,
struct BezTriple *prev,
struct BezTriple *next,
@@ -2252,14 +2146,12 @@ float evaluate_fcurve_driver(PathResolvedRNA *anim_rna,
return evaluate_fcurve_ex(fcu, evaltime, cvalue);
}
-/* Checks if the curve has valid keys, drivers or modifiers that produce an actual curve. */
bool BKE_fcurve_is_empty(FCurve *fcu)
{
return (fcu->totvert == 0) && (fcu->driver == NULL) &&
!list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE);
}
-/* Calculate the value of the given F-Curve at the given frame, and set its curval. */
float calculate_fcurve(PathResolvedRNA *anim_rna,
FCurve *fcu,
const AnimationEvalContext *anim_eval_context)
diff --git a/source/blender/blenkernel/intern/fcurve_cache.c b/source/blender/blenkernel/intern/fcurve_cache.c
index 8142b871edd..4f27bad5b91 100644
--- a/source/blender/blenkernel/intern/fcurve_cache.c
+++ b/source/blender/blenkernel/intern/fcurve_cache.c
@@ -155,11 +155,6 @@ FCurve *BKE_fcurve_pathcache_find(struct FCurvePathCache *fcache,
return NULL;
}
-/**
- * Fill in an array of F-Curve, leave NULL when not found.
- *
- * \return The number of F-Curves found.
- */
int BKE_fcurve_pathcache_find_array(struct FCurvePathCache *fcache,
const char *rna_path,
FCurve **fcurve_result,
diff --git a/source/blender/blenkernel/intern/fcurve_driver.c b/source/blender/blenkernel/intern/fcurve_driver.c
index 3ac64dbf84b..5496519e53b 100644
--- a/source/blender/blenkernel/intern/fcurve_driver.c
+++ b/source/blender/blenkernel/intern/fcurve_driver.c
@@ -199,9 +199,6 @@ static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar)
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,
@@ -621,7 +618,6 @@ static void quaternion_to_angles(float quat[4], int 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])
{
@@ -720,7 +716,6 @@ static const DriverVarTypeInfo *get_dvar_typeinfo(int type)
/** \name Driver API
* \{ */
-/* Perform actual freeing driver variable and remove it from the given list */
void driver_free_variable(ListBase *variables, DriverVar *dvar)
{
/* Sanity checks. */
@@ -745,7 +740,6 @@ void driver_free_variable(ListBase *variables, DriverVar *dvar)
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. */
@@ -755,7 +749,6 @@ void driver_free_variable_ex(ChannelDriver *driver, DriverVar *dvar)
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));
@@ -773,7 +766,6 @@ void driver_variables_copy(ListBase *dst_vars, const ListBase *src_vars)
}
}
-/* Change the type of driver variable */
void driver_change_variable_type(DriverVar *dvar, int type)
{
const DriverVarTypeInfo *dvti = get_dvar_typeinfo(type);
@@ -803,7 +795,6 @@ void driver_change_variable_type(DriverVar *dvar, int type)
DRIVER_TARGETS_LOOPER_END;
}
-/* Validate driver name (after being renamed) */
void driver_variable_name_validate(DriverVar *dvar)
{
/* Special character blacklist */
@@ -873,7 +864,6 @@ void driver_variable_name_validate(DriverVar *dvar)
}
}
-/* Add a new driver variable */
DriverVar *driver_add_new_variable(ChannelDriver *driver)
{
DriverVar *dvar;
@@ -906,7 +896,6 @@ DriverVar *driver_add_new_variable(ChannelDriver *driver)
return dvar;
}
-/* This frees the driver itself */
void fcurve_free_driver(FCurve *fcu)
{
ChannelDriver *driver;
@@ -939,7 +928,6 @@ void fcurve_free_driver(FCurve *fcu)
fcu->driver = NULL;
}
-/* This makes a copy of the given driver */
ChannelDriver *fcurve_copy_driver(const ChannelDriver *driver)
{
ChannelDriver *ndriver;
@@ -1082,7 +1070,6 @@ static bool driver_try_evaluate_simple_expr(ChannelDriver *driver,
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);
@@ -1109,7 +1096,6 @@ static bool python_driver_exression_depends_on_time(const char *expression)
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) {
@@ -1125,7 +1111,6 @@ bool BKE_driver_expression_depends_on_time(ChannelDriver *driver)
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)
@@ -1152,7 +1137,6 @@ void BKE_driver_invalidate_expression(ChannelDriver *driver,
/** \name 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;
@@ -1269,14 +1253,6 @@ static void evaluate_driver_python(PathResolvedRNA *anim_rna,
}
}
-/**
- * Evaluate an Channel-Driver to get a 'time' value to use
- * instead of `anim_eval_context->eval_time`.
- *
- * - `anim_eval_context->eval_time` is the frame at which F-Curve is being evaluated.
- * - Has to return a float value.
- * - \a driver_orig is where we cache Python expressions, in case of COW
- */
float evaluate_driver(PathResolvedRNA *anim_rna,
ChannelDriver *driver,
ChannelDriver *driver_orig,
@@ -1309,3 +1285,5 @@ float evaluate_driver(PathResolvedRNA *anim_rna,
/* Return value for driver. */
return driver->curval;
}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c
index 9d26a1528f3..39122b33683 100644
--- a/source/blender/blenkernel/intern/fluid.c
+++ b/source/blender/blenkernel/intern/fluid.c
@@ -4437,8 +4437,6 @@ static void manta_smoke_calc_transparency(FluidDomainSettings *fds, ViewLayer *v
}
}
-/* Get fluid velocity and density at given coordinates
- * Returns fluid density or -1.0f if outside domain. */
float BKE_fluid_get_velocity_at(struct Object *ob, float position[3], float velocity[3])
{
FluidModifierData *fmd = (FluidModifierData *)BKE_modifiers_findby_type(ob, eModifierType_Fluid);
@@ -4575,10 +4573,10 @@ void BKE_fluid_particle_system_destroy(struct Object *ob, const int particle_typ
}
}
-#endif /* WITH_FLUID */
-
/** \} */
+#endif /* WITH_FLUID */
+
/* -------------------------------------------------------------------- */
/** \name Public Data Access API
*
diff --git a/source/blender/blenkernel/intern/fmodifier.c b/source/blender/blenkernel/intern/fmodifier.c
index 121927513cc..d140e70978a 100644
--- a/source/blender/blenkernel/intern/fmodifier.c
+++ b/source/blender/blenkernel/intern/fmodifier.c
@@ -1065,10 +1065,6 @@ static void fmods_init_typeinfo(void)
fmodifiersTypeInfo[9] = &FMI_STEPPED; /* Stepped F-Curve Modifier */
}
-/**
- * This function should be used for getting the appropriate type-info when only
- * a F-Curve modifier type is known.
- */
const FModifierTypeInfo *get_fmodifier_typeinfo(const int type)
{
/* initialize the type-info list? */
@@ -1088,10 +1084,6 @@ const FModifierTypeInfo *get_fmodifier_typeinfo(const int type)
return NULL;
}
-/**
- * This function should always be used to get the appropriate type-info,
- * as it has checks which prevent segfaults in some weird cases.
- */
const FModifierTypeInfo *fmodifier_get_typeinfo(const FModifier *fcm)
{
/* only return typeinfo for valid modifiers */
@@ -1108,9 +1100,6 @@ const FModifierTypeInfo *fmodifier_get_typeinfo(const FModifier *fcm)
/** \name F-Curve Modifier Public API
* \{ */
-/**
- * Add a new F-Curve Modifier to the given F-Curve of a certain type.
- */
FModifier *add_fmodifier(ListBase *modifiers, int type, FCurve *owner_fcu)
{
const FModifierTypeInfo *fmi = get_fmodifier_typeinfo(type);
@@ -1161,9 +1150,6 @@ FModifier *add_fmodifier(ListBase *modifiers, int type, FCurve *owner_fcu)
return fcm;
}
-/**
- * Make a copy of the specified F-Modifier.
- */
FModifier *copy_fmodifier(const FModifier *src)
{
const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(src);
@@ -1191,9 +1177,6 @@ FModifier *copy_fmodifier(const FModifier *src)
return dst;
}
-/**
- * Duplicate all of the F-Modifiers in the Modifier stacks.
- */
void copy_fmodifiers(ListBase *dst, const ListBase *src)
{
FModifier *fcm, *srcfcm;
@@ -1220,9 +1203,6 @@ void copy_fmodifiers(ListBase *dst, const ListBase *src)
}
}
-/**
- * Remove and free the given F-Modifier from the given stack.
- */
bool remove_fmodifier(ListBase *modifiers, FModifier *fcm)
{
const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
@@ -1263,9 +1243,6 @@ bool remove_fmodifier(ListBase *modifiers, FModifier *fcm)
return false;
}
-/**
- * Remove all of a given F-Curve's modifiers.
- */
void free_fmodifiers(ListBase *modifiers)
{
FModifier *fcm, *fmn;
@@ -1282,9 +1259,6 @@ void free_fmodifiers(ListBase *modifiers)
}
}
-/**
- * Find the active F-Modifier.
- */
FModifier *find_active_fmodifier(ListBase *modifiers)
{
FModifier *fcm;
@@ -1305,9 +1279,6 @@ FModifier *find_active_fmodifier(ListBase *modifiers)
return NULL;
}
-/**
- * Set the active F-Modifier.
- */
void set_active_fmodifier(ListBase *modifiers, FModifier *fcm)
{
FModifier *fm;
@@ -1328,12 +1299,6 @@ void set_active_fmodifier(ListBase *modifiers, FModifier *fcm)
}
}
-/**
- * Do we have any modifiers which match certain criteria.
- *
- * \param mtype: Type of modifier (if 0, doesn't matter).
- * \param acttype: Type of action to perform (if -1, doesn't matter).
- */
bool list_has_suitable_fmodifier(ListBase *modifiers, int mtype, short acttype)
{
FModifier *fcm;
@@ -1443,19 +1408,6 @@ static float eval_fmodifier_influence(FModifier *fcm, float evaltime)
return influence;
}
-/**
- * Evaluate time modifications imposed by some F-Curve Modifiers.
- *
- * - This step acts as an optimization to prevent the F-Curve stack being evaluated
- * several times by modifiers requesting the time be modified, as the final result
- * would have required using the modified time
- * - Modifiers only ever receive the unmodified time, as subsequent modifiers should be
- * working on the 'global' result of the modified curve, not some localized segment,
- * so \a evaltime gets set to whatever the last time-modifying modifier likes.
- * - We start from the end of the stack, as only the last one matters for now.
- *
- * \param fcu: Can be NULL.
- */
float evaluate_time_fmodifiers(FModifiersStackStorage *storage,
ListBase *modifiers,
FCurve *fcu,
@@ -1513,10 +1465,6 @@ float evaluate_time_fmodifiers(FModifiersStackStorage *storage,
return evaltime;
}
-/**
- * Evaluates the given set of F-Curve Modifiers using the given data
- * Should only be called after evaluate_time_fmodifiers() has been called.
- */
void evaluate_value_fmodifiers(FModifiersStackStorage *storage,
ListBase *modifiers,
FCurve *fcu,
@@ -1565,10 +1513,6 @@ void evaluate_value_fmodifiers(FModifiersStackStorage *storage,
/* ---------- */
-/**
- * Bake modifiers for given F-Curve to curve sample data, in the frame range defined
- * by start and end (inclusive).
- */
void fcurve_bake_modifiers(FCurve *fcu, int start, int end)
{
ChannelDriver *driver;
diff --git a/source/blender/blenkernel/intern/freestyle.c b/source/blender/blenkernel/intern/freestyle.c
index d9b3faf8623..68b7e274970 100644
--- a/source/blender/blenkernel/intern/freestyle.c
+++ b/source/blender/blenkernel/intern/freestyle.c
@@ -152,10 +152,6 @@ bool BKE_freestyle_module_delete(FreestyleConfig *config, FreestyleModuleConfig
return true;
}
-/**
- * Reinsert \a module_conf offset by \a direction from current position.
- * \return if position of \a module_conf changed.
- */
bool BKE_freestyle_module_move(FreestyleConfig *config,
FreestyleModuleConfig *module_conf,
int direction)
diff --git a/source/blender/blenkernel/intern/geometry_component_curve.cc b/source/blender/blenkernel/intern/geometry_component_curve.cc
index 598c61fd877..1e24b29038d 100644
--- a/source/blender/blenkernel/intern/geometry_component_curve.cc
+++ b/source/blender/blenkernel/intern/geometry_component_curve.cc
@@ -77,7 +77,6 @@ bool CurveComponent::has_curve() const
return curve_ != nullptr;
}
-/* Clear the component and replace it with the new curve. */
void CurveComponent::replace(CurveEval *curve, GeometryOwnershipType ownership)
{
BLI_assert(this->is_mutable());
@@ -128,10 +127,6 @@ void CurveComponent::ensure_owns_direct_data()
}
}
-/**
- * Create empty curve data used for rendering the spline's wire edges.
- * \note See comment on #curve_for_render_ for further explanation.
- */
const Curve *CurveComponent::get_curve_for_render() const
{
if (curve_ == nullptr) {
@@ -391,14 +386,14 @@ static const CurveEval *get_curve_from_component_for_read(const GeometryComponen
/** \} */
+namespace blender::bke {
+
/* -------------------------------------------------------------------- */
/** \name Builtin Spline Attributes
*
* Attributes with a value for every spline, stored contiguously or in every spline separately.
* \{ */
-namespace blender::bke {
-
class BuiltinSplineAttributeProvider final : public BuiltinAttributeProvider {
using AsReadAttribute = GVArray (*)(const CurveEval &data);
using AsWriteAttribute = GVMutableArray (*)(CurveEval &data);
@@ -714,46 +709,15 @@ static bool remove_point_attribute(GeometryComponent &component,
}
/**
- * Virtual array for any control point data accessed with spans and an offset array.
- */
-template<typename T> class VArray_For_SplinePoints : public VArrayImpl<T> {
- private:
- const Array<Span<T>> data_;
- Array<int> offsets_;
-
- public:
- VArray_For_SplinePoints(Array<Span<T>> data, Array<int> offsets)
- : VArrayImpl<T>(offsets.last()), data_(std::move(data)), offsets_(std::move(offsets))
- {
- }
-
- T get(const int64_t index) const final
- {
- const PointIndices indices = lookup_point_indices(offsets_, index);
- return data_[indices.spline_index][indices.point_index];
- }
-
- void materialize(const IndexMask mask, MutableSpan<T> r_span) const final
- {
- point_attribute_materialize(data_.as_span(), offsets_, mask, r_span);
- }
-
- void materialize_to_uninitialized(const IndexMask mask, MutableSpan<T> r_span) const final
- {
- point_attribute_materialize_to_uninitialized(data_.as_span(), offsets_, mask, r_span);
- }
-};
-
-/**
* Mutable virtual array for any control point data accessed with spans and an offset array.
*/
-template<typename T> class VMutableArray_For_SplinePoints final : public VMutableArrayImpl<T> {
+template<typename T> class VArrayImpl_For_SplinePoints final : public VMutableArrayImpl<T> {
private:
Array<MutableSpan<T>> data_;
Array<int> offsets_;
public:
- VMutableArray_For_SplinePoints(Array<MutableSpan<T>> data, Array<int> offsets)
+ VArrayImpl_For_SplinePoints(Array<MutableSpan<T>> data, Array<int> offsets)
: VMutableArrayImpl<T>(offsets.last()), data_(std::move(data)), offsets_(std::move(offsets))
{
}
@@ -791,16 +755,17 @@ template<typename T> class VMutableArray_For_SplinePoints final : public VMutabl
}
};
-template<typename T> VArray<T> point_data_varray(Array<Span<T>> spans, Array<int> offsets)
+template<typename T> VArray<T> point_data_varray(Array<MutableSpan<T>> spans, Array<int> offsets)
{
- return VArray<T>::template For<VArray_For_SplinePoints<T>>(std::move(spans), std::move(offsets));
+ return VArray<T>::template For<VArrayImpl_For_SplinePoints<T>>(std::move(spans),
+ std::move(offsets));
}
template<typename T>
-VMutableArray<T> point_data_varray(Array<MutableSpan<T>> spans, Array<int> offsets)
+VMutableArray<T> point_data_varray_mutable(Array<MutableSpan<T>> spans, Array<int> offsets)
{
- return VMutableArray<T>::template For<VMutableArray_For_SplinePoints<T>>(std::move(spans),
- std::move(offsets));
+ return VMutableArray<T>::template For<VArrayImpl_For_SplinePoints<T>>(std::move(spans),
+ std::move(offsets));
}
/**
@@ -811,13 +776,13 @@ VMutableArray<T> point_data_varray(Array<MutableSpan<T>> spans, Array<int> offse
* \note There is no need to check the handle type to avoid changing auto handles, since
* retrieving write access to the position data will mark them for recomputation anyway.
*/
-class VMutableArray_For_SplinePosition final : public VMutableArrayImpl<float3> {
+class VArrayImpl_For_SplinePosition final : public VMutableArrayImpl<float3> {
private:
MutableSpan<SplinePtr> splines_;
Array<int> offsets_;
public:
- VMutableArray_For_SplinePosition(MutableSpan<SplinePtr> splines, Array<int> offsets)
+ VArrayImpl_For_SplinePosition(MutableSpan<SplinePtr> splines, Array<int> offsets)
: VMutableArrayImpl<float3>(offsets.last()), splines_(splines), offsets_(std::move(offsets))
{
}
@@ -889,104 +854,16 @@ class VMutableArray_For_SplinePosition final : public VMutableArrayImpl<float3>
}
};
-class VArray_For_BezierHandle final : public VArrayImpl<float3> {
- private:
- Span<SplinePtr> splines_;
- Array<int> offsets_;
- bool is_right_;
-
- public:
- VArray_For_BezierHandle(Span<SplinePtr> splines, Array<int> offsets, const bool is_right)
- : VArrayImpl<float3>(offsets.last()),
- splines_(std::move(splines)),
- offsets_(std::move(offsets)),
- is_right_(is_right)
- {
- }
-
- static float3 get_internal(const int64_t index,
- Span<SplinePtr> splines,
- Span<int> offsets,
- const bool is_right)
- {
- const PointIndices indices = lookup_point_indices(offsets, index);
- const Spline &spline = *splines[indices.spline_index];
- if (spline.type() == Spline::Type::Bezier) {
- const BezierSpline &bezier_spline = static_cast<const BezierSpline &>(spline);
- return is_right ? bezier_spline.handle_positions_right()[indices.point_index] :
- bezier_spline.handle_positions_left()[indices.point_index];
- }
- return float3(0);
- }
-
- float3 get(const int64_t index) const final
- {
- return get_internal(index, splines_, offsets_, is_right_);
- }
-
- /**
- * Utility so we can pass handle positions to the materialize functions above.
- *
- * \note This relies on the ability of the materialize implementations to
- * handle empty spans, since only Bezier splines have handles.
- */
- static Array<Span<float3>> get_handle_spans(Span<SplinePtr> splines, const bool is_right)
- {
- Array<Span<float3>> spans(splines.size());
- for (const int i : spans.index_range()) {
- if (splines[i]->type() == Spline::Type::Bezier) {
- BezierSpline &bezier_spline = static_cast<BezierSpline &>(*splines[i]);
- spans[i] = is_right ? bezier_spline.handle_positions_right() :
- bezier_spline.handle_positions_left();
- }
- else {
- spans[i] = {};
- }
- }
- return spans;
- }
-
- static void materialize_internal(const IndexMask mask,
- Span<SplinePtr> splines,
- Span<int> offsets,
- const bool is_right,
- MutableSpan<float3> r_span)
- {
- Array<Span<float3>> spans = get_handle_spans(splines, is_right);
- point_attribute_materialize(spans.as_span(), offsets, mask, r_span);
- }
-
- static void materialize_to_uninitialized_internal(const IndexMask mask,
- Span<SplinePtr> splines,
- Span<int> offsets,
- const bool is_right,
- MutableSpan<float3> r_span)
- {
- Array<Span<float3>> spans = get_handle_spans(splines, is_right);
- point_attribute_materialize_to_uninitialized(spans.as_span(), offsets, mask, r_span);
- }
-
- void materialize(const IndexMask mask, MutableSpan<float3> r_span) const final
- {
- materialize_internal(mask, splines_, offsets_, is_right_, r_span);
- }
-
- void materialize_to_uninitialized(const IndexMask mask, MutableSpan<float3> r_span) const final
- {
- materialize_to_uninitialized_internal(mask, splines_, offsets_, is_right_, r_span);
- }
-};
-
-class VMutableArray_For_BezierHandles final : public VMutableArrayImpl<float3> {
+class VArrayImpl_For_BezierHandles final : public VMutableArrayImpl<float3> {
private:
MutableSpan<SplinePtr> splines_;
Array<int> offsets_;
bool is_right_;
public:
- VMutableArray_For_BezierHandles(MutableSpan<SplinePtr> splines,
- Array<int> offsets,
- const bool is_right)
+ VArrayImpl_For_BezierHandles(MutableSpan<SplinePtr> splines,
+ Array<int> offsets,
+ const bool is_right)
: VMutableArrayImpl<float3>(offsets.last()),
splines_(splines),
offsets_(std::move(offsets)),
@@ -996,7 +873,14 @@ class VMutableArray_For_BezierHandles final : public VMutableArrayImpl<float3> {
float3 get(const int64_t index) const final
{
- return VArray_For_BezierHandle::get_internal(index, splines_, offsets_, is_right_);
+ const PointIndices indices = lookup_point_indices(offsets_, index);
+ const Spline &spline = *splines_[indices.spline_index];
+ if (spline.type() == Spline::Type::Bezier) {
+ const BezierSpline &bezier_spline = static_cast<const BezierSpline &>(spline);
+ return is_right_ ? bezier_spline.handle_positions_right()[indices.point_index] :
+ bezier_spline.handle_positions_left()[indices.point_index];
+ }
+ return float3(0);
}
void set(const int64_t index, float3 value) final
@@ -1040,13 +924,36 @@ class VMutableArray_For_BezierHandles final : public VMutableArrayImpl<float3> {
void materialize(const IndexMask mask, MutableSpan<float3> r_span) const final
{
- VArray_For_BezierHandle::materialize_internal(mask, splines_, offsets_, is_right_, r_span);
+ Array<Span<float3>> spans = get_handle_spans(splines_, is_right_);
+ point_attribute_materialize(spans.as_span(), offsets_, mask, r_span);
}
void materialize_to_uninitialized(const IndexMask mask, MutableSpan<float3> r_span) const final
{
- VArray_For_BezierHandle::materialize_to_uninitialized_internal(
- mask, splines_, offsets_, is_right_, r_span);
+ Array<Span<float3>> spans = get_handle_spans(splines_, is_right_);
+ point_attribute_materialize_to_uninitialized(spans.as_span(), offsets_, mask, r_span);
+ }
+
+ /**
+ * Utility so we can pass handle positions to the materialize functions above.
+ *
+ * \note This relies on the ability of the materialize implementations to
+ * handle empty spans, since only Bezier splines have handles.
+ */
+ static Array<Span<float3>> get_handle_spans(Span<SplinePtr> splines, const bool is_right)
+ {
+ Array<Span<float3>> spans(splines.size());
+ for (const int i : spans.index_range()) {
+ if (splines[i]->type() == Spline::Type::Bezier) {
+ BezierSpline &bezier_spline = static_cast<BezierSpline &>(*splines[i]);
+ spans[i] = is_right ? bezier_spline.handle_positions_right() :
+ bezier_spline.handle_positions_left();
+ }
+ else {
+ spans[i] = {};
+ }
+ }
+ return spans;
}
};
@@ -1102,9 +1009,12 @@ template<typename T> class BuiltinPointAttributeProvider : public BuiltinAttribu
}
Array<int> offsets = curve->control_point_offsets();
- Array<Span<T>> spans(splines.size());
+ Array<MutableSpan<T>> spans(splines.size());
for (const int i : splines.index_range()) {
- spans[i] = get_span_(*splines[i]);
+ Span<T> span = get_span_(*splines[i]);
+ /* Use const-cast because the underlying virtual array implementation is shared between const
+ * and non const data. */
+ spans[i] = MutableSpan<T>(const_cast<T *>(span.data()), span.size());
}
return point_data_varray(spans, offsets);
@@ -1143,7 +1053,7 @@ template<typename T> class BuiltinPointAttributeProvider : public BuiltinAttribu
spans[i] = get_mutable_span_(*splines[i]);
}
- return {point_data_varray(spans, offsets), domain_, tag_modified_fn};
+ return {point_data_varray_mutable(spans, offsets), domain_, tag_modified_fn};
}
bool try_delete(GeometryComponent &component) const final
@@ -1235,8 +1145,8 @@ class PositionAttributeProvider final : public BuiltinPointAttributeProvider<flo
};
Array<int> offsets = curve->control_point_offsets();
- return {VMutableArray<float3>::For<VMutableArray_For_SplinePosition>(curve->splines(),
- std::move(offsets)),
+ return {VMutableArray<float3>::For<VArrayImpl_For_SplinePosition>(curve->splines(),
+ std::move(offsets)),
domain_,
tag_modified_fn};
}
@@ -1270,8 +1180,10 @@ class BezierHandleAttributeProvider : public BuiltinAttributeProvider {
}
Array<int> offsets = curve->control_point_offsets();
- return VArray<float3>::For<VArray_For_BezierHandle>(
- curve->splines(), std::move(offsets), is_right_);
+ /* Use const-cast because the underlying virtual array implementation is shared between const
+ * and non const data. */
+ return VArray<float3>::For<VArrayImpl_For_BezierHandles>(
+ const_cast<CurveEval *>(curve)->splines(), std::move(offsets), is_right_);
}
WriteAttributeLookup try_get_for_write(GeometryComponent &component) const override
@@ -1288,7 +1200,7 @@ class BezierHandleAttributeProvider : public BuiltinAttributeProvider {
auto tag_modified_fn = [curve]() { curve->mark_cache_invalid(); };
Array<int> offsets = curve->control_point_offsets();
- return {VMutableArray<float3>::For<VMutableArray_For_BezierHandles>(
+ return {VMutableArray<float3>::For<VArrayImpl_For_BezierHandles>(
curve->splines(), std::move(offsets), is_right_),
domain_,
tag_modified_fn};
@@ -1377,9 +1289,12 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider {
Array<int> offsets = curve->control_point_offsets();
attribute_math::convert_to_static_type(spans[0].type(), [&](auto dummy) {
using T = decltype(dummy);
- Array<Span<T>> data(splines.size());
+ Array<MutableSpan<T>> data(splines.size());
for (const int i : splines.index_range()) {
- data[i] = spans[i].typed<T>();
+ Span<T> span = spans[i].typed<T>();
+ /* Use const-cast because the underlying virtual array implementation is shared between
+ * const and non const data. */
+ data[i] = MutableSpan<T>(const_cast<T *>(span.data()), span.size());
BLI_assert(data[i].data() != nullptr);
}
attribute = {point_data_varray(data, offsets), ATTR_DOMAIN_POINT};
@@ -1435,7 +1350,7 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider {
data[i] = spans[i].typed<T>();
BLI_assert(data[i].data() != nullptr);
}
- attribute = {point_data_varray(data, offsets), ATTR_DOMAIN_POINT};
+ attribute = {point_data_varray_mutable(data, offsets), ATTR_DOMAIN_POINT};
});
return attribute;
}
@@ -1570,6 +1485,8 @@ static ComponentAttributeProviders create_attribute_providers_for_curve()
{&spline_custom_data, &point_custom_data});
}
+/** \} */
+
} // namespace blender::bke
const blender::bke::ComponentAttributeProviders *CurveComponent::get_attribute_providers() const
@@ -1578,5 +1495,3 @@ const blender::bke::ComponentAttributeProviders *CurveComponent::get_attribute_p
blender::bke::create_attribute_providers_for_curve();
return &providers;
}
-
-/** \} */
diff --git a/source/blender/blenkernel/intern/geometry_component_instances.cc b/source/blender/blenkernel/intern/geometry_component_instances.cc
index 9a30c86c1e5..93a7646fed0 100644
--- a/source/blender/blenkernel/intern/geometry_component_instances.cc
+++ b/source/blender/blenkernel/intern/geometry_component_instances.cc
@@ -31,12 +31,17 @@
#include "attribute_access_intern.hh"
+#include "FN_cpp_type_make.hh"
+
using blender::float4x4;
using blender::Map;
using blender::MutableSpan;
using blender::Set;
using blender::Span;
using blender::VectorSet;
+using blender::fn::GSpan;
+
+MAKE_CPP_TYPE(InstanceReference, InstanceReference, CPPTypeFlags::None)
/* -------------------------------------------------------------------- */
/** \name Geometry Component Implementation
@@ -51,8 +56,8 @@ GeometryComponent *InstancesComponent::copy() const
InstancesComponent *new_component = new InstancesComponent();
new_component->instance_reference_handles_ = instance_reference_handles_;
new_component->instance_transforms_ = instance_transforms_;
- new_component->instance_ids_ = instance_ids_;
new_component->references_ = references_;
+ new_component->attributes_ = attributes_;
return new_component;
}
@@ -60,32 +65,21 @@ void InstancesComponent::reserve(int min_capacity)
{
instance_reference_handles_.reserve(min_capacity);
instance_transforms_.reserve(min_capacity);
- if (!instance_ids_.is_empty()) {
- this->instance_ids_ensure();
- }
+ attributes_.reallocate(min_capacity);
}
-/**
- * Resize the transform, handles, and ID vectors to the specified capacity.
- *
- * \note This function should be used carefully, only when it's guaranteed
- * that the data will be filled.
- */
void InstancesComponent::resize(int capacity)
{
instance_reference_handles_.resize(capacity);
instance_transforms_.resize(capacity);
- if (!instance_ids_.is_empty()) {
- this->instance_ids_ensure();
- }
+ attributes_.reallocate(capacity);
}
void InstancesComponent::clear()
{
instance_reference_handles_.clear();
instance_transforms_.clear();
- instance_ids_.clear();
-
+ attributes_.clear();
references_.clear();
}
@@ -95,9 +89,7 @@ void InstancesComponent::add_instance(const int instance_handle, const float4x4
BLI_assert(instance_handle < references_.size());
instance_reference_handles_.append(instance_handle);
instance_transforms_.append(transform);
- if (!instance_ids_.is_empty()) {
- this->instance_ids_ensure();
- }
+ attributes_.reallocate(this->instances_amount());
}
blender::Span<int> InstancesComponent::instance_reference_handles() const
@@ -119,36 +111,6 @@ blender::Span<blender::float4x4> InstancesComponent::instance_transforms() const
return instance_transforms_;
}
-blender::MutableSpan<int> InstancesComponent::instance_ids()
-{
- return instance_ids_;
-}
-blender::Span<int> InstancesComponent::instance_ids() const
-{
- return instance_ids_;
-}
-
-/**
- * Make sure the ID storage size matches the number of instances. By directly resizing the
- * component's vectors internally, it is possible to be in a situation where the IDs are not
- * empty but they do not have the correct size; this function resolves that.
- */
-blender::MutableSpan<int> InstancesComponent::instance_ids_ensure()
-{
- instance_ids_.append_n_times(0, this->instances_amount() - instance_ids_.size());
- return instance_ids_;
-}
-
-void InstancesComponent::instance_ids_clear()
-{
- instance_ids_.clear_and_make_inline();
-}
-
-/**
- * With write access to the instances component, the data in the instanced geometry sets can be
- * changed. This is a function on the component rather than each reference to ensure `const`
- * correctness for that reason.
- */
GeometrySet &InstancesComponent::geometry_set_from_reference(const int reference_index)
{
/* If this assert fails, it means #ensure_geometry_instances must be called first or that the
@@ -160,11 +122,6 @@ GeometrySet &InstancesComponent::geometry_set_from_reference(const int reference
return const_cast<GeometrySet &>(references_[reference_index].geometry_set());
}
-/**
- * Returns a handle for the given reference.
- * If the reference exists already, the handle of the existing reference is returned.
- * Otherwise a new handle is added.
- */
int InstancesComponent::add_reference(const InstanceReference &reference)
{
return references_.index_of_or_add_as(reference);
@@ -347,15 +304,17 @@ static blender::Array<int> generate_unique_instance_ids(Span<int> original_ids)
blender::Span<int> InstancesComponent::almost_unique_ids() const
{
std::lock_guard lock(almost_unique_ids_mutex_);
- if (instance_ids().is_empty()) {
- almost_unique_ids_.reinitialize(this->instances_amount());
- for (const int i : almost_unique_ids_.index_range()) {
- almost_unique_ids_[i] = i;
+ std::optional<GSpan> instance_ids_gspan = attributes_.get_for_read("id");
+ if (instance_ids_gspan) {
+ Span<int> instance_ids = instance_ids_gspan->typed<int>();
+ if (almost_unique_ids_.size() != instance_ids.size()) {
+ almost_unique_ids_ = generate_unique_instance_ids(instance_ids);
}
}
else {
- if (almost_unique_ids_.size() != instance_ids_.size()) {
- almost_unique_ids_ = generate_unique_instance_ids(instance_ids_);
+ almost_unique_ids_.reinitialize(this->instances_amount());
+ for (const int i : almost_unique_ids_.index_range()) {
+ almost_unique_ids_[i] = i;
}
}
return almost_unique_ids_;
@@ -434,81 +393,21 @@ class InstancePositionAttributeProvider final : public BuiltinAttributeProvider
}
};
-class InstanceIDAttributeProvider final : public BuiltinAttributeProvider {
- public:
- InstanceIDAttributeProvider()
- : BuiltinAttributeProvider(
- "id", ATTR_DOMAIN_INSTANCE, CD_PROP_INT32, Creatable, Writable, Deletable)
- {
- }
-
- GVArray try_get_for_read(const GeometryComponent &component) const final
- {
- const InstancesComponent &instances = static_cast<const InstancesComponent &>(component);
- if (instances.instance_ids().is_empty()) {
- return {};
- }
- return VArray<int>::ForSpan(instances.instance_ids());
- }
-
- WriteAttributeLookup try_get_for_write(GeometryComponent &component) const final
- {
- InstancesComponent &instances = static_cast<InstancesComponent &>(component);
- if (instances.instance_ids().is_empty()) {
- return {};
- }
- return {VMutableArray<int>::ForSpan(instances.instance_ids()), domain_};
- }
-
- bool try_delete(GeometryComponent &component) const final
- {
- InstancesComponent &instances = static_cast<InstancesComponent &>(component);
- if (instances.instance_ids().is_empty()) {
- return false;
- }
- instances.instance_ids_clear();
- return true;
- }
-
- bool try_create(GeometryComponent &component, const AttributeInit &initializer) const final
- {
- InstancesComponent &instances = static_cast<InstancesComponent &>(component);
- if (instances.instances_amount() == 0) {
- return false;
- }
- MutableSpan<int> ids = instances.instance_ids_ensure();
- switch (initializer.type) {
- case AttributeInit::Type::Default: {
- ids.fill(0);
- break;
- }
- case AttributeInit::Type::VArray: {
- const GVArray &varray = static_cast<const AttributeInitVArray &>(initializer).varray;
- varray.materialize_to_uninitialized(varray.index_range(), ids.data());
- break;
- }
- case AttributeInit::Type::MoveArray: {
- void *source_data = static_cast<const AttributeInitMove &>(initializer).data;
- ids.copy_from({static_cast<int *>(source_data), instances.instances_amount()});
- MEM_freeN(source_data);
- break;
- }
- }
- return true;
- }
+template<typename T>
+static GVArray make_array_read_attribute(const void *data, const int domain_size)
+{
+ return VArray<T>::ForSpan(Span<T>((const T *)data, domain_size));
+}
- bool exists(const GeometryComponent &component) const final
- {
- const InstancesComponent &instances = static_cast<const InstancesComponent &>(component);
- return !instances.instance_ids().is_empty();
- }
-};
+template<typename T>
+static GVMutableArray make_array_write_attribute(void *data, const int domain_size)
+{
+ return VMutableArray<T>::ForSpan(MutableSpan<T>((T *)data, domain_size));
+}
static ComponentAttributeProviders create_attribute_providers_for_instances()
{
static InstancePositionAttributeProvider position;
- static InstanceIDAttributeProvider id;
-
static CustomDataAccessInfo instance_custom_data_access = {
[](GeometryComponent &component) -> CustomData * {
InstancesComponent &inst = static_cast<InstancesComponent &>(component);
@@ -520,6 +419,24 @@ static ComponentAttributeProviders create_attribute_providers_for_instances()
},
nullptr};
+ /**
+ * IDs of the instances. They are used for consistency over multiple frames for things like
+ * motion blur. Proper stable ID data that actually helps when rendering can only be generated
+ * in some situations, so this vector is allowed to be empty, in which case the index of each
+ * instance will be used for the final ID.
+ */
+ static BuiltinCustomDataLayerProvider id("id",
+ ATTR_DOMAIN_INSTANCE,
+ CD_PROP_INT32,
+ CD_PROP_INT32,
+ BuiltinAttributeProvider::Creatable,
+ BuiltinAttributeProvider::Writable,
+ BuiltinAttributeProvider::Deletable,
+ instance_custom_data_access,
+ make_array_read_attribute<int>,
+ make_array_write_attribute<int>,
+ nullptr);
+
static CustomDataAttributeProvider instance_custom_data(ATTR_DOMAIN_INSTANCE,
instance_custom_data_access);
diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc
index 86a52b420b6..cc15e6d7b84 100644
--- a/source/blender/blenkernel/intern/geometry_component_mesh.cc
+++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc
@@ -29,7 +29,6 @@
#include "attribute_access_intern.hh"
-/* Can't include BKE_object_deform.h right now, due to an enum forward declaration. */
extern "C" MDeformVert *BKE_object_defgroup_data_create(ID *id);
/* -------------------------------------------------------------------- */
@@ -71,7 +70,6 @@ bool MeshComponent::has_mesh() const
return mesh_ != nullptr;
}
-/* Clear the component and replace it with the new mesh. */
void MeshComponent::replace(Mesh *mesh, GeometryOwnershipType ownership)
{
BLI_assert(this->is_mutable());
@@ -80,8 +78,6 @@ void MeshComponent::replace(Mesh *mesh, GeometryOwnershipType ownership)
ownership_ = ownership;
}
-/* Return the mesh and clear the component. The caller takes over responsibility for freeing the
- * mesh (if the component was responsible before). */
Mesh *MeshComponent::release()
{
BLI_assert(this->is_mutable());
@@ -90,15 +86,11 @@ Mesh *MeshComponent::release()
return mesh;
}
-/* Get the mesh from this component. This method can be used by multiple threads at the same
- * time. Therefore, the returned mesh should not be modified. No ownership is transferred. */
const Mesh *MeshComponent::get_for_read() const
{
return mesh_;
}
-/* Get the mesh from this component. This method can only be used when the component is mutable,
- * i.e. it is not shared. The returned mesh can be modified. No ownership is transferred. */
Mesh *MeshComponent::get_for_write()
{
BLI_assert(this->is_mutable());
@@ -996,57 +988,36 @@ static void set_crease(MEdge &edge, float value)
edge.crease = round_fl_to_uchar_clamp(value * 255.0f);
}
-class VMutableArray_For_VertexWeights final : public VMutableArrayImpl<float> {
+class VArrayImpl_For_VertexWeights final : public VMutableArrayImpl<float> {
private:
MDeformVert *dverts_;
const int dvert_index_;
public:
- VMutableArray_For_VertexWeights(MDeformVert *dverts, const int totvert, const int dvert_index)
+ VArrayImpl_For_VertexWeights(MDeformVert *dverts, const int totvert, const int dvert_index)
: VMutableArrayImpl<float>(totvert), dverts_(dverts), dvert_index_(dvert_index)
{
}
float get(const int64_t index) const override
{
- return get_internal(dverts_, dvert_index_, index);
- }
-
- void set(const int64_t index, const float value) override
- {
- MDeformWeight *weight = BKE_defvert_ensure_index(&dverts_[index], dvert_index_);
- weight->weight = value;
- }
-
- static float get_internal(const MDeformVert *dverts, const int dvert_index, const int64_t index)
- {
- if (dverts == nullptr) {
+ if (dverts_ == nullptr) {
return 0.0f;
}
- const MDeformVert &dvert = dverts[index];
+ const MDeformVert &dvert = dverts_[index];
for (const MDeformWeight &weight : Span(dvert.dw, dvert.totweight)) {
- if (weight.def_nr == dvert_index) {
+ if (weight.def_nr == dvert_index_) {
return weight.weight;
}
}
return 0.0f;
+ ;
}
-};
-
-class VArray_For_VertexWeights final : public VArrayImpl<float> {
- private:
- const MDeformVert *dverts_;
- const int dvert_index_;
- public:
- VArray_For_VertexWeights(const MDeformVert *dverts, const int totvert, const int dvert_index)
- : VArrayImpl<float>(totvert), dverts_(dverts), dvert_index_(dvert_index)
- {
- }
-
- float get(const int64_t index) const override
+ void set(const int64_t index, const float value) override
{
- return VMutableArray_For_VertexWeights::get_internal(dverts_, dvert_index_, index);
+ MDeformWeight *weight = BKE_defvert_ensure_index(&dverts_[index], dvert_index_);
+ weight->weight = value;
}
};
@@ -1077,7 +1048,7 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider {
static const float default_value = 0.0f;
return {VArray<float>::ForSingle(default_value, mesh->totvert), ATTR_DOMAIN_POINT};
}
- return {VArray<float>::For<VArray_For_VertexWeights>(
+ return {VArray<float>::For<VArrayImpl_For_VertexWeights>(
mesh->dvert, mesh->totvert, vertex_group_index),
ATTR_DOMAIN_POINT};
}
@@ -1109,7 +1080,7 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider {
mesh->dvert = (MDeformVert *)CustomData_duplicate_referenced_layer(
&mesh->vdata, CD_MDEFORMVERT, mesh->totvert);
}
- return {VMutableArray<float>::For<VMutableArray_For_VertexWeights>(
+ return {VMutableArray<float>::For<VArrayImpl_For_VertexWeights>(
mesh->dvert, mesh->totvert, vertex_group_index),
ATTR_DOMAIN_POINT};
}
@@ -1127,16 +1098,19 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider {
}
const std::string name = attribute_id.name();
- const int vertex_group_index = BLI_findstringindex(
- &mesh->vertex_group_names, name.c_str(), offsetof(bDeformGroup, name));
- if (vertex_group_index < 0) {
+
+ int index;
+ bDeformGroup *group;
+ if (!BKE_id_defgroup_name_find(&mesh->id, name.c_str(), &index, &group)) {
return false;
}
+ BLI_remlink(&mesh->vertex_group_names, group);
+ MEM_freeN(group);
if (mesh->dvert == nullptr) {
return true;
}
for (MDeformVert &dvert : MutableSpan(mesh->dvert, mesh->totvert)) {
- MDeformWeight *weight = BKE_defvert_find_index(&dvert, vertex_group_index);
+ MDeformWeight *weight = BKE_defvert_find_index(&dvert, index);
BKE_defvert_remove_group(&dvert, weight);
}
return true;
diff --git a/source/blender/blenkernel/intern/geometry_component_pointcloud.cc b/source/blender/blenkernel/intern/geometry_component_pointcloud.cc
index c6a1c61a96d..80c09a7ed4a 100644
--- a/source/blender/blenkernel/intern/geometry_component_pointcloud.cc
+++ b/source/blender/blenkernel/intern/geometry_component_pointcloud.cc
@@ -62,7 +62,6 @@ bool PointCloudComponent::has_pointcloud() const
return pointcloud_ != nullptr;
}
-/* Clear the component and replace it with the new point cloud. */
void PointCloudComponent::replace(PointCloud *pointcloud, GeometryOwnershipType ownership)
{
BLI_assert(this->is_mutable());
@@ -71,8 +70,6 @@ void PointCloudComponent::replace(PointCloud *pointcloud, GeometryOwnershipType
ownership_ = ownership;
}
-/* Return the point cloud and clear the component. The caller takes over responsibility for freeing
- * the point cloud (if the component was responsible before). */
PointCloud *PointCloudComponent::release()
{
BLI_assert(this->is_mutable());
@@ -81,17 +78,11 @@ PointCloud *PointCloudComponent::release()
return pointcloud;
}
-/* Get the point cloud from this component. This method can be used by multiple threads at the same
- * time. Therefore, the returned point cloud should not be modified. No ownership is transferred.
- */
const PointCloud *PointCloudComponent::get_for_read() const
{
return pointcloud_;
}
-/* Get the point cloud from this component. This method can only be used when the component is
- * mutable, i.e. it is not shared. The returned point cloud can be modified. No ownership is
- * transferred. */
PointCloud *PointCloudComponent::get_for_write()
{
BLI_assert(this->is_mutable());
diff --git a/source/blender/blenkernel/intern/geometry_component_volume.cc b/source/blender/blenkernel/intern/geometry_component_volume.cc
index 94ed07a63de..e9874153b4c 100644
--- a/source/blender/blenkernel/intern/geometry_component_volume.cc
+++ b/source/blender/blenkernel/intern/geometry_component_volume.cc
@@ -59,7 +59,6 @@ bool VolumeComponent::has_volume() const
return volume_ != nullptr;
}
-/* Clear the component and replace it with the new volume. */
void VolumeComponent::replace(Volume *volume, GeometryOwnershipType ownership)
{
BLI_assert(this->is_mutable());
@@ -68,8 +67,6 @@ void VolumeComponent::replace(Volume *volume, GeometryOwnershipType ownership)
ownership_ = ownership;
}
-/* Return the volume and clear the component. The caller takes over responsibility for freeing the
- * volume (if the component was responsible before). */
Volume *VolumeComponent::release()
{
BLI_assert(this->is_mutable());
@@ -78,15 +75,11 @@ Volume *VolumeComponent::release()
return volume;
}
-/* Get the volume from this component. This method can be used by multiple threads at the same
- * time. Therefore, the returned volume should not be modified. No ownership is transferred. */
const Volume *VolumeComponent::get_for_read() const
{
return volume_;
}
-/* Get the volume from this component. This method can only be used when the component is mutable,
- * i.e. it is not shared. The returned volume can be modified. No ownership is transferred. */
Volume *VolumeComponent::get_for_write()
{
BLI_assert(this->is_mutable());
diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc
index c250c14f1d7..ef5609ec9a8 100644
--- a/source/blender/blenkernel/intern/geometry_set.cc
+++ b/source/blender/blenkernel/intern/geometry_set.cc
@@ -105,7 +105,6 @@ bool GeometryComponent::is_empty() const
/** \name Geometry Set
* \{ */
-/* The methods are defaulted here so that they are not instantiated in every translation unit. */
GeometrySet::GeometrySet() = default;
GeometrySet::GeometrySet(const GeometrySet &other) = default;
GeometrySet::GeometrySet(GeometrySet &&other) = default;
@@ -113,36 +112,24 @@ GeometrySet::~GeometrySet() = default;
GeometrySet &GeometrySet::operator=(const GeometrySet &other) = default;
GeometrySet &GeometrySet::operator=(GeometrySet &&other) = default;
-/* This method can only be used when the geometry set is mutable. It returns a mutable geometry
- * component of the given type.
- */
GeometryComponent &GeometrySet::get_component_for_write(GeometryComponentType component_type)
{
- return components_.add_or_modify(
- component_type,
- [&](GeometryComponentPtr *value_ptr) -> GeometryComponent & {
- /* If the component did not exist before, create a new one. */
- new (value_ptr) GeometryComponentPtr(GeometryComponent::create(component_type));
- return **value_ptr;
- },
- [&](GeometryComponentPtr *value_ptr) -> GeometryComponent & {
- GeometryComponentPtr &value = *value_ptr;
- if (value->is_mutable()) {
- /* If the referenced component is already mutable, return it directly. */
- return *value;
- }
- /* If the referenced component is shared, make a copy. The copy is not shared and is
- * therefore mutable. */
- GeometryComponent *copied_component = value->copy();
- value = GeometryComponentPtr{copied_component};
- return *copied_component;
- });
+ GeometryComponentPtr &component_ptr = components_[component_type];
+ if (!component_ptr) {
+ /* If the component did not exist before, create a new one. */
+ component_ptr = GeometryComponent::create(component_type);
+ return *component_ptr;
+ }
+ if (component_ptr->is_mutable()) {
+ /* If the referenced component is already mutable, return it directly. */
+ return *component_ptr;
+ }
+ /* If the referenced component is shared, make a copy. The copy is not shared and is
+ * therefore mutable. */
+ component_ptr = component_ptr->copy();
+ return *component_ptr;
}
-/**
- * Retrieve the pointer to a component without creating it if it does not exist,
- * unlike #get_component_for_write.
- */
GeometryComponent *GeometrySet::get_component_ptr(GeometryComponentType type)
{
if (this->has(type)) {
@@ -151,56 +138,47 @@ GeometryComponent *GeometrySet::get_component_ptr(GeometryComponentType type)
return nullptr;
}
-/* Get the component of the given type. Might return null if the component does not exist yet. */
const GeometryComponent *GeometrySet::get_component_for_read(
GeometryComponentType component_type) const
{
- const GeometryComponentPtr *component = components_.lookup_ptr(component_type);
- if (component != nullptr) {
- return component->get();
- }
- return nullptr;
+ return components_[component_type].get();
}
bool GeometrySet::has(const GeometryComponentType component_type) const
{
- return components_.contains(component_type);
+ return components_[component_type].has_value();
}
void GeometrySet::remove(const GeometryComponentType component_type)
{
- components_.remove(component_type);
+ components_[component_type].reset();
}
-/**
- * Remove all geometry components with types that are not in the provided list.
- */
void GeometrySet::keep_only(const blender::Span<GeometryComponentType> component_types)
{
- for (auto it = components_.keys().begin(); it != components_.keys().end(); ++it) {
- const GeometryComponentType type = *it;
- if (!component_types.contains(type)) {
- components_.remove(it);
+ for (GeometryComponentPtr &component_ptr : components_) {
+ if (component_ptr) {
+ if (!component_types.contains(component_ptr->type())) {
+ component_ptr.reset();
+ }
}
}
}
void GeometrySet::add(const GeometryComponent &component)
{
- BLI_assert(!components_.contains(component.type()));
+ BLI_assert(!components_[component.type()]);
component.user_add();
- GeometryComponentPtr component_ptr{const_cast<GeometryComponent *>(&component)};
- components_.add_new(component.type(), std::move(component_ptr));
+ components_[component.type()] = const_cast<GeometryComponent *>(&component);
}
-/**
- * Get all geometry components in this geometry set for read-only access.
- */
Vector<const GeometryComponent *> GeometrySet::get_components_for_read() const
{
Vector<const GeometryComponent *> components;
- for (const GeometryComponentPtr &ptr : components_.values()) {
- components.append(ptr.get());
+ for (const GeometryComponentPtr &component_ptr : components_) {
+ if (component_ptr) {
+ components.append(component_ptr.get());
+ }
}
return components;
}
@@ -233,122 +211,111 @@ std::ostream &operator<<(std::ostream &stream, const GeometrySet &geometry_set)
return stream;
}
-/* Remove all geometry components from the geometry set. */
void GeometrySet::clear()
{
- components_.clear();
+ for (GeometryComponentPtr &component_ptr : components_) {
+ component_ptr.reset();
+ }
}
-/* Make sure that the geometry can be cached. This does not ensure ownership of object/collection
- * instances. */
void GeometrySet::ensure_owns_direct_data()
{
- for (GeometryComponentType type : components_.keys()) {
- const GeometryComponent *component = this->get_component_for_read(type);
- if (!component->owns_direct_data()) {
- GeometryComponent &component_for_write = this->get_component_for_write(type);
- component_for_write.ensure_owns_direct_data();
+ for (GeometryComponentPtr &component_ptr : components_) {
+ if (!component_ptr) {
+ continue;
}
+ if (component_ptr->owns_direct_data()) {
+ continue;
+ }
+ GeometryComponent &component_for_write = this->get_component_for_write(component_ptr->type());
+ component_for_write.ensure_owns_direct_data();
}
}
bool GeometrySet::owns_direct_data() const
{
- for (const GeometryComponentPtr &component : components_.values()) {
- if (!component->owns_direct_data()) {
- return false;
+ for (const GeometryComponentPtr &component_ptr : components_) {
+ if (component_ptr) {
+ if (!component_ptr->owns_direct_data()) {
+ return false;
+ }
}
}
return true;
}
-/* Returns a read-only mesh or null. */
const Mesh *GeometrySet::get_mesh_for_read() const
{
const MeshComponent *component = this->get_component_for_read<MeshComponent>();
return (component == nullptr) ? nullptr : component->get_for_read();
}
-/* Returns true when the geometry set has a mesh component that has a mesh. */
bool GeometrySet::has_mesh() const
{
const MeshComponent *component = this->get_component_for_read<MeshComponent>();
return component != nullptr && component->has_mesh();
}
-/* Returns a read-only point cloud of null. */
const PointCloud *GeometrySet::get_pointcloud_for_read() const
{
const PointCloudComponent *component = this->get_component_for_read<PointCloudComponent>();
return (component == nullptr) ? nullptr : component->get_for_read();
}
-/* Returns a read-only volume or null. */
const Volume *GeometrySet::get_volume_for_read() const
{
const VolumeComponent *component = this->get_component_for_read<VolumeComponent>();
return (component == nullptr) ? nullptr : component->get_for_read();
}
-/* Returns a read-only curve or null. */
const CurveEval *GeometrySet::get_curve_for_read() const
{
const CurveComponent *component = this->get_component_for_read<CurveComponent>();
return (component == nullptr) ? nullptr : component->get_for_read();
}
-/* Returns true when the geometry set has a point cloud component that has a point cloud. */
bool GeometrySet::has_pointcloud() const
{
const PointCloudComponent *component = this->get_component_for_read<PointCloudComponent>();
return component != nullptr && component->has_pointcloud();
}
-/* Returns true when the geometry set has an instances component that has at least one instance. */
bool GeometrySet::has_instances() const
{
const InstancesComponent *component = this->get_component_for_read<InstancesComponent>();
return component != nullptr && component->instances_amount() >= 1;
}
-/* Returns true when the geometry set has a volume component that has a volume. */
bool GeometrySet::has_volume() const
{
const VolumeComponent *component = this->get_component_for_read<VolumeComponent>();
return component != nullptr && component->has_volume();
}
-/* Returns true when the geometry set has a curve component that has a curve. */
bool GeometrySet::has_curve() const
{
const CurveComponent *component = this->get_component_for_read<CurveComponent>();
return component != nullptr && component->has_curve();
}
-/* Returns true when the geometry set has any data that is not an instance. */
bool GeometrySet::has_realized_data() const
{
- if (components_.is_empty()) {
- return false;
- }
- if (components_.size() > 1) {
- return true;
+ for (const GeometryComponentPtr &component_ptr : components_) {
+ if (component_ptr) {
+ if (component_ptr->type() != GEO_COMPONENT_TYPE_INSTANCES) {
+ return true;
+ }
+ }
}
- /* Check if the only component is an #InstancesComponent. */
- return this->get_component_for_read<InstancesComponent>() == nullptr;
+ return false;
}
-/* Return true if the geometry set has any component that isn't empty. */
bool GeometrySet::is_empty() const
{
- if (components_.is_empty()) {
- return true;
- }
- return !(this->has_mesh() || this->has_curve() || this->has_pointcloud() ||
+ return !(this->has_mesh() || this->has_curve() || this->has_pointcloud() || this->has_volume() ||
this->has_instances());
}
-/* Create a new geometry set that only contains the given mesh. */
GeometrySet GeometrySet::create_with_mesh(Mesh *mesh, GeometryOwnershipType ownership)
{
GeometrySet geometry_set;
@@ -359,7 +326,6 @@ GeometrySet GeometrySet::create_with_mesh(Mesh *mesh, GeometryOwnershipType owne
return geometry_set;
}
-/* Create a new geometry set that only contains the given point cloud. */
GeometrySet GeometrySet::create_with_pointcloud(PointCloud *pointcloud,
GeometryOwnershipType ownership)
{
@@ -371,7 +337,6 @@ GeometrySet GeometrySet::create_with_pointcloud(PointCloud *pointcloud,
return geometry_set;
}
-/* Create a new geometry set that only contains the given curve. */
GeometrySet GeometrySet::create_with_curve(CurveEval *curve, GeometryOwnershipType ownership)
{
GeometrySet geometry_set;
@@ -382,76 +347,80 @@ GeometrySet GeometrySet::create_with_curve(CurveEval *curve, GeometryOwnershipTy
return geometry_set;
}
-/* Clear the existing mesh and replace it with the given one. */
void GeometrySet::replace_mesh(Mesh *mesh, GeometryOwnershipType ownership)
{
if (mesh == nullptr) {
this->remove<MeshComponent>();
+ return;
}
- else {
- MeshComponent &component = this->get_component_for_write<MeshComponent>();
- component.replace(mesh, ownership);
+ if (mesh == this->get_mesh_for_read()) {
+ return;
}
+ this->remove<MeshComponent>();
+ MeshComponent &component = this->get_component_for_write<MeshComponent>();
+ component.replace(mesh, ownership);
}
-/* Clear the existing curve and replace it with the given one. */
void GeometrySet::replace_curve(CurveEval *curve, GeometryOwnershipType ownership)
{
if (curve == nullptr) {
this->remove<CurveComponent>();
+ return;
}
- else {
- CurveComponent &component = this->get_component_for_write<CurveComponent>();
- component.replace(curve, ownership);
+ if (curve == this->get_curve_for_read()) {
+ return;
}
+ this->remove<CurveComponent>();
+ CurveComponent &component = this->get_component_for_write<CurveComponent>();
+ component.replace(curve, ownership);
}
-/* Clear the existing point cloud and replace with the given one. */
void GeometrySet::replace_pointcloud(PointCloud *pointcloud, GeometryOwnershipType ownership)
{
if (pointcloud == nullptr) {
this->remove<PointCloudComponent>();
+ return;
}
- else {
- PointCloudComponent &component = this->get_component_for_write<PointCloudComponent>();
- component.replace(pointcloud, ownership);
+ if (pointcloud == this->get_pointcloud_for_read()) {
+ return;
}
+ this->remove<PointCloudComponent>();
+ PointCloudComponent &component = this->get_component_for_write<PointCloudComponent>();
+ component.replace(pointcloud, ownership);
}
-/* Clear the existing volume and replace with the given one. */
void GeometrySet::replace_volume(Volume *volume, GeometryOwnershipType ownership)
{
if (volume == nullptr) {
this->remove<VolumeComponent>();
+ return;
}
- else {
- VolumeComponent &component = this->get_component_for_write<VolumeComponent>();
- component.replace(volume, ownership);
+ if (volume == this->get_volume_for_read()) {
+ return;
}
+ this->remove<VolumeComponent>();
+ VolumeComponent &component = this->get_component_for_write<VolumeComponent>();
+ component.replace(volume, ownership);
}
-/* Returns a mutable mesh or null. No ownership is transferred. */
Mesh *GeometrySet::get_mesh_for_write()
{
MeshComponent *component = this->get_component_ptr<MeshComponent>();
return component == nullptr ? nullptr : component->get_for_write();
}
-/* Returns a mutable point cloud or null. No ownership is transferred. */
PointCloud *GeometrySet::get_pointcloud_for_write()
{
PointCloudComponent *component = this->get_component_ptr<PointCloudComponent>();
return component == nullptr ? nullptr : component->get_for_write();
}
-/* Returns a mutable volume or null. No ownership is transferred. */
Volume *GeometrySet::get_volume_for_write()
{
VolumeComponent *component = this->get_component_ptr<VolumeComponent>();
return component == nullptr ? nullptr : component->get_for_write();
}
-/* Returns a mutable curve or null. No ownership is transferred. */
CurveEval *GeometrySet::get_curve_for_write()
{
CurveComponent *component = this->get_component_ptr<CurveComponent>();
@@ -512,13 +481,18 @@ void GeometrySet::gather_attributes_for_propagation(
return;
}
+ AttributeDomain domain = meta_data.domain;
+ if (dst_component_type != GEO_COMPONENT_TYPE_INSTANCES && domain == ATTR_DOMAIN_INSTANCE) {
+ domain = ATTR_DOMAIN_POINT;
+ }
+
auto add_info = [&](AttributeKind *attribute_kind) {
- attribute_kind->domain = meta_data.domain;
+ attribute_kind->domain = domain;
attribute_kind->data_type = meta_data.data_type;
};
auto modify_info = [&](AttributeKind *attribute_kind) {
attribute_kind->domain = bke::attribute_domain_highest_priority(
- {attribute_kind->domain, meta_data.domain});
+ {attribute_kind->domain, domain});
attribute_kind->data_type = bke::attribute_data_type_highest_complexity(
{attribute_kind->data_type, meta_data.data_type});
};
@@ -581,10 +555,6 @@ static void gather_mutable_geometry_sets(GeometrySet &geometry_set,
}
}
-/**
- * Modify every (recursive) instance separately. This is often more efficient than realizing all
- * instances just to change the same thing on all of them.
- */
void GeometrySet::modify_geometry_sets(ForeachSubGeometryCallback callback)
{
Vector<GeometrySet *> geometry_sets;
diff --git a/source/blender/blenkernel/intern/geometry_set_instances.cc b/source/blender/blenkernel/intern/geometry_set_instances.cc
index c73da7d9659..4d84d5d899d 100644
--- a/source/blender/blenkernel/intern/geometry_set_instances.cc
+++ b/source/blender/blenkernel/intern/geometry_set_instances.cc
@@ -53,9 +53,6 @@ static void add_final_mesh_as_geometry_component(const Object &object, GeometryS
}
}
-/**
- * \note This doesn't extract instances from the "dupli" system for non-geometry-nodes instances.
- */
GeometrySet object_get_evaluated_geometry_set(const Object &object)
{
if (object.type == OB_MESH && object.mode == OB_MODE_EDIT) {
@@ -77,7 +74,7 @@ GeometrySet object_get_evaluated_geometry_set(const Object &object)
add_final_mesh_as_geometry_component(object, geometry_set);
}
- /* TODO: Cover the case of point-clouds without modifiers-- they may not be covered by the
+ /* TODO: Cover the case of point clouds without modifiers-- they may not be covered by the
* #geometry_set_eval case above. */
/* TODO: Add volume support. */
@@ -169,16 +166,6 @@ static void geometry_set_collect_recursive(const GeometrySet &geometry_set,
}
}
-/**
- * Return flattened vector of the geometry component's recursive instances. I.e. all collection
- * instances and object instances will be expanded into the instances of their geometry components.
- * Even the instances in those geometry components' will be included.
- *
- * \note For convenience (to avoid duplication in the caller), the returned vector also contains
- * the argument geometry set.
- *
- * \note This doesn't extract instances from the "dupli" system for non-geometry-nodes instances.
- */
void geometry_set_gather_instances(const GeometrySet &geometry_set,
Vector<GeometryInstanceGroup> &r_instance_groups)
{
@@ -220,375 +207,6 @@ void geometry_set_gather_instances_attribute_info(Span<GeometryInstanceGroup> se
}
}
-static Mesh *join_mesh_topology_and_builtin_attributes(Span<GeometryInstanceGroup> set_groups)
-{
- int totverts = 0;
- int totloops = 0;
- int totedges = 0;
- int totpolys = 0;
- int64_t cd_dirty_vert = 0;
- int64_t cd_dirty_poly = 0;
- int64_t cd_dirty_edge = 0;
- int64_t cd_dirty_loop = 0;
- VectorSet<Material *> materials;
-
- for (const GeometryInstanceGroup &set_group : set_groups) {
- const GeometrySet &set = set_group.geometry_set;
- const int tot_transforms = set_group.transforms.size();
- if (set.has_mesh()) {
- const Mesh &mesh = *set.get_mesh_for_read();
- totverts += mesh.totvert * tot_transforms;
- totloops += mesh.totloop * tot_transforms;
- totedges += mesh.totedge * tot_transforms;
- totpolys += mesh.totpoly * tot_transforms;
- cd_dirty_vert |= mesh.runtime.cd_dirty_vert;
- cd_dirty_poly |= mesh.runtime.cd_dirty_poly;
- cd_dirty_edge |= mesh.runtime.cd_dirty_edge;
- cd_dirty_loop |= mesh.runtime.cd_dirty_loop;
- for (const int slot_index : IndexRange(mesh.totcol)) {
- Material *material = mesh.mat[slot_index];
- materials.add(material);
- }
- }
- }
-
- /* Don't create an empty mesh. */
- if ((totverts + totloops + totedges + totpolys) == 0) {
- return nullptr;
- }
-
- Mesh *new_mesh = BKE_mesh_new_nomain(totverts, totedges, 0, totloops, totpolys);
- /* Copy settings from the first input geometry set with a mesh. */
- for (const GeometryInstanceGroup &set_group : set_groups) {
- const GeometrySet &set = set_group.geometry_set;
- if (set.has_mesh()) {
- const Mesh &mesh = *set.get_mesh_for_read();
- BKE_mesh_copy_parameters_for_eval(new_mesh, &mesh);
- break;
- }
- }
- for (const int i : IndexRange(materials.size())) {
- Material *material = materials[i];
- BKE_id_material_eval_assign(&new_mesh->id, i + 1, material);
- }
- new_mesh->runtime.cd_dirty_vert = cd_dirty_vert;
- new_mesh->runtime.cd_dirty_poly = cd_dirty_poly;
- new_mesh->runtime.cd_dirty_edge = cd_dirty_edge;
- new_mesh->runtime.cd_dirty_loop = cd_dirty_loop;
-
- int vert_offset = 0;
- int loop_offset = 0;
- int edge_offset = 0;
- int poly_offset = 0;
- for (const GeometryInstanceGroup &set_group : set_groups) {
- const GeometrySet &set = set_group.geometry_set;
- if (set.has_mesh()) {
- const Mesh &mesh = *set.get_mesh_for_read();
-
- Array<int> material_index_map(mesh.totcol);
- for (const int i : IndexRange(mesh.totcol)) {
- Material *material = mesh.mat[i];
- const int new_material_index = materials.index_of(material);
- material_index_map[i] = new_material_index;
- }
-
- for (const float4x4 &transform : set_group.transforms) {
- for (const int i : IndexRange(mesh.totvert)) {
- const MVert &old_vert = mesh.mvert[i];
- MVert &new_vert = new_mesh->mvert[vert_offset + i];
-
- new_vert = old_vert;
-
- const float3 new_position = transform * float3(old_vert.co);
- copy_v3_v3(new_vert.co, new_position);
- }
- for (const int i : IndexRange(mesh.totedge)) {
- const MEdge &old_edge = mesh.medge[i];
- MEdge &new_edge = new_mesh->medge[edge_offset + i];
- new_edge = old_edge;
- new_edge.v1 += vert_offset;
- new_edge.v2 += vert_offset;
- }
- for (const int i : IndexRange(mesh.totloop)) {
- const MLoop &old_loop = mesh.mloop[i];
- MLoop &new_loop = new_mesh->mloop[loop_offset + i];
- new_loop = old_loop;
- new_loop.v += vert_offset;
- new_loop.e += edge_offset;
- }
- for (const int i : IndexRange(mesh.totpoly)) {
- const MPoly &old_poly = mesh.mpoly[i];
- MPoly &new_poly = new_mesh->mpoly[poly_offset + i];
- new_poly = old_poly;
- new_poly.loopstart += loop_offset;
- if (old_poly.mat_nr >= 0 && old_poly.mat_nr < mesh.totcol) {
- new_poly.mat_nr = material_index_map[new_poly.mat_nr];
- }
- else {
- /* The material index was invalid before. */
- new_poly.mat_nr = 0;
- }
- }
-
- vert_offset += mesh.totvert;
- loop_offset += mesh.totloop;
- edge_offset += mesh.totedge;
- poly_offset += mesh.totpoly;
- }
- }
- }
-
- /* A possible optimization is to only tag the normals dirty when there are transforms that change
- * normals. */
- BKE_mesh_normals_tag_dirty(new_mesh);
-
- return new_mesh;
-}
-
-static void join_attributes(Span<GeometryInstanceGroup> set_groups,
- Span<GeometryComponentType> component_types,
- const Map<AttributeIDRef, AttributeKind> &attribute_info,
- GeometryComponent &result)
-{
- for (Map<AttributeIDRef, AttributeKind>::Item entry : attribute_info.items()) {
- const AttributeIDRef attribute_id = entry.key;
- const AttributeDomain domain_output = entry.value.domain;
- const CustomDataType data_type_output = entry.value.data_type;
- const CPPType *cpp_type = bke::custom_data_type_to_cpp_type(data_type_output);
- BLI_assert(cpp_type != nullptr);
-
- result.attribute_try_create(
- entry.key, domain_output, data_type_output, AttributeInitDefault());
- WriteAttributeLookup write_attribute = result.attribute_try_get_for_write(attribute_id);
- if (!write_attribute || &write_attribute.varray.type() != cpp_type ||
- write_attribute.domain != domain_output) {
- continue;
- }
-
- fn::GVMutableArray_GSpan dst_span{write_attribute.varray};
-
- int offset = 0;
- for (const GeometryInstanceGroup &set_group : set_groups) {
- const GeometrySet &set = set_group.geometry_set;
- for (const GeometryComponentType component_type : component_types) {
- if (set.has(component_type)) {
- const GeometryComponent &component = *set.get_component_for_read(component_type);
- const int domain_size = component.attribute_domain_size(domain_output);
- if (domain_size == 0) {
- continue; /* Domain size is 0, so no need to increment the offset. */
- }
- GVArray source_attribute = component.attribute_try_get_for_read(
- attribute_id, domain_output, data_type_output);
-
- if (source_attribute) {
- fn::GVArray_GSpan src_span{source_attribute};
- const void *src_buffer = src_span.data();
- for (const int UNUSED(i) : set_group.transforms.index_range()) {
- void *dst_buffer = dst_span[offset];
- cpp_type->copy_assign_n(src_buffer, dst_buffer, domain_size);
- offset += domain_size;
- }
- }
- else {
- offset += domain_size * set_group.transforms.size();
- }
- }
- }
- }
-
- dst_span.save();
- }
-}
-
-static PointCloud *join_pointcloud_position_attribute(Span<GeometryInstanceGroup> set_groups)
-{
- /* Count the total number of points. */
- int totpoint = 0;
- for (const GeometryInstanceGroup &set_group : set_groups) {
- const GeometrySet &set = set_group.geometry_set;
- if (set.has<PointCloudComponent>()) {
- const PointCloudComponent &component = *set.get_component_for_read<PointCloudComponent>();
- totpoint += component.attribute_domain_size(ATTR_DOMAIN_POINT);
- }
- }
- if (totpoint == 0) {
- return nullptr;
- }
-
- PointCloud *new_pointcloud = BKE_pointcloud_new_nomain(totpoint);
- MutableSpan new_positions{(float3 *)new_pointcloud->co, new_pointcloud->totpoint};
-
- /* Transform each instance's point locations into the new point cloud. */
- int offset = 0;
- for (const GeometryInstanceGroup &set_group : set_groups) {
- const GeometrySet &set = set_group.geometry_set;
- const PointCloud *pointcloud = set.get_pointcloud_for_read();
- if (pointcloud == nullptr) {
- continue;
- }
- for (const float4x4 &transform : set_group.transforms) {
- for (const int i : IndexRange(pointcloud->totpoint)) {
- new_positions[offset + i] = transform * float3(pointcloud->co[i]);
- }
- offset += pointcloud->totpoint;
- }
- }
-
- return new_pointcloud;
-}
-
-static CurveEval *join_curve_splines_and_builtin_attributes(Span<GeometryInstanceGroup> set_groups)
-{
- Vector<SplinePtr> new_splines;
- for (const GeometryInstanceGroup &set_group : set_groups) {
- const GeometrySet &set = set_group.geometry_set;
- if (!set.has_curve()) {
- continue;
- }
-
- const CurveEval &source_curve = *set.get_curve_for_read();
- for (const SplinePtr &source_spline : source_curve.splines()) {
- for (const float4x4 &transform : set_group.transforms) {
- SplinePtr new_spline = source_spline->copy_without_attributes();
- new_spline->transform(transform);
- new_splines.append(std::move(new_spline));
- }
- }
- }
- if (new_splines.is_empty()) {
- return nullptr;
- }
-
- CurveEval *new_curve = new CurveEval();
- for (SplinePtr &new_spline : new_splines) {
- new_curve->add_spline(std::move(new_spline));
- }
-
- new_curve->attributes.reallocate(new_curve->splines().size());
- return new_curve;
-}
-
-static void join_instance_groups_mesh(Span<GeometryInstanceGroup> set_groups, GeometrySet &result)
-{
- Mesh *new_mesh = join_mesh_topology_and_builtin_attributes(set_groups);
- if (new_mesh == nullptr) {
- return;
- }
-
- MeshComponent &dst_component = result.get_component_for_write<MeshComponent>();
- dst_component.replace(new_mesh);
-
- /* Don't copy attributes that are stored directly in the mesh data structs. */
- Map<AttributeIDRef, AttributeKind> attributes;
- geometry_set_gather_instances_attribute_info(
- set_groups,
- {GEO_COMPONENT_TYPE_MESH},
- {"position", "material_index", "normal", "shade_smooth", "crease"},
- attributes);
- join_attributes(set_groups,
- {GEO_COMPONENT_TYPE_MESH},
- attributes,
- static_cast<GeometryComponent &>(dst_component));
-}
-
-static void join_instance_groups_pointcloud(Span<GeometryInstanceGroup> set_groups,
- GeometrySet &result)
-{
- PointCloud *new_pointcloud = join_pointcloud_position_attribute(set_groups);
- if (new_pointcloud == nullptr) {
- return;
- }
-
- PointCloudComponent &dst_component = result.get_component_for_write<PointCloudComponent>();
- dst_component.replace(new_pointcloud);
-
- Map<AttributeIDRef, AttributeKind> attributes;
- geometry_set_gather_instances_attribute_info(
- set_groups, {GEO_COMPONENT_TYPE_POINT_CLOUD}, {"position"}, attributes);
- join_attributes(set_groups,
- {GEO_COMPONENT_TYPE_POINT_CLOUD},
- attributes,
- static_cast<GeometryComponent &>(dst_component));
-}
-
-static void join_instance_groups_volume(Span<GeometryInstanceGroup> set_groups,
- GeometrySet &result)
-{
- /* Not yet supported; for now only return the first volume. Joining volume grids with the same
- * name requires resampling of at least one of the grids. The cell size of the resulting volume
- * has to be determined somehow. */
- for (const GeometryInstanceGroup &set_group : set_groups) {
- const GeometrySet &set = set_group.geometry_set;
- if (set.has<VolumeComponent>()) {
- result.add(*set.get_component_for_read<VolumeComponent>());
- return;
- }
- }
-}
-
-/**
- * Curve point domain attributes must be in the same order on every spline. The order might have
- * been different on separate instances, so ensure that all splines have the same order. Note that
- * because #Map is used, the order is not necessarily consistent every time, but it is the same for
- * every spline, and that's what matters.
- */
-static void sort_curve_point_attributes(const Map<AttributeIDRef, AttributeKind> &info,
- MutableSpan<SplinePtr> splines)
-{
- Vector<AttributeIDRef> new_order;
- for (Map<AttributeIDRef, AttributeKind>::Item item : info.items()) {
- if (item.value.domain == ATTR_DOMAIN_POINT) {
- /* Only sort attributes stored on splines. */
- new_order.append(item.key);
- }
- }
- for (SplinePtr &spline : splines) {
- spline->attributes.reorder(new_order);
- }
-}
-
-static void join_instance_groups_curve(Span<GeometryInstanceGroup> set_groups, GeometrySet &result)
-{
- CurveEval *curve = join_curve_splines_and_builtin_attributes(set_groups);
- if (curve == nullptr) {
- return;
- }
-
- CurveComponent &dst_component = result.get_component_for_write<CurveComponent>();
- dst_component.replace(curve);
-
- Map<AttributeIDRef, AttributeKind> attributes;
- geometry_set_gather_instances_attribute_info(
- set_groups,
- {GEO_COMPONENT_TYPE_CURVE},
- {"position", "radius", "tilt", "handle_left", "handle_right", "cyclic", "resolution"},
- attributes);
- join_attributes(set_groups,
- {GEO_COMPONENT_TYPE_CURVE},
- attributes,
- static_cast<GeometryComponent &>(dst_component));
- sort_curve_point_attributes(attributes, curve->splines());
- curve->assert_valid_point_attributes();
-}
-
-GeometrySet geometry_set_realize_instances(const GeometrySet &geometry_set)
-{
- if (!geometry_set.has_instances()) {
- return geometry_set;
- }
-
- GeometrySet new_geometry_set;
-
- Vector<GeometryInstanceGroup> set_groups;
- geometry_set_gather_instances(geometry_set, set_groups);
- join_instance_groups_mesh(set_groups, new_geometry_set);
- join_instance_groups_pointcloud(set_groups, new_geometry_set);
- join_instance_groups_volume(set_groups, new_geometry_set);
- join_instance_groups_curve(set_groups, new_geometry_set);
-
- return new_geometry_set;
-}
-
} // namespace blender::bke
void InstancesComponent::foreach_referenced_geometry(
@@ -624,11 +242,6 @@ void InstancesComponent::foreach_referenced_geometry(
}
}
-/**
- * If references have a collection or object type, convert them into geometry instances
- * recursively. After that, the geometry sets can be edited. There may still be instances of other
- * types of they can't be converted to geometry sets.
- */
void InstancesComponent::ensure_geometry_instances()
{
using namespace blender;
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index bea65030c06..13338f33bd6 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -320,6 +320,7 @@ IDTypeInfo IDType_ID_GD = {
.name_plural = "grease_pencils",
.translation_context = BLT_I18NCONTEXT_ID_GPENCIL,
.flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = NULL,
.copy_data = greasepencil_copy_data,
@@ -327,6 +328,7 @@ IDTypeInfo IDType_ID_GD = {
.make_local = NULL,
.foreach_id = greasepencil_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = greasepencil_blend_write,
@@ -363,7 +365,6 @@ void BKE_gpencil_batch_cache_free(bGPdata *gpd)
/* ************************************************** */
/* Memory Management */
-/* clean vertex groups weights */
void BKE_gpencil_free_point_weights(MDeformVert *dvert)
{
if (dvert == NULL) {
@@ -402,7 +403,6 @@ void BKE_gpencil_free_stroke_editcurve(bGPDstroke *gps)
gps->editcurve = NULL;
}
-/* free stroke, doesn't unlink from any listbase */
void BKE_gpencil_free_stroke(bGPDstroke *gps)
{
if (gps == NULL) {
@@ -426,7 +426,6 @@ void BKE_gpencil_free_stroke(bGPDstroke *gps)
MEM_freeN(gps);
}
-/* Free strokes belonging to a gp-frame */
bool BKE_gpencil_free_strokes(bGPDframe *gpf)
{
bool changed = (BLI_listbase_is_empty(&gpf->strokes) == false);
@@ -440,7 +439,6 @@ bool BKE_gpencil_free_strokes(bGPDframe *gpf)
return changed;
}
-/* Free all of a gp-layer's frames */
void BKE_gpencil_free_frames(bGPDlayer *gpl)
{
bGPDframe *gpf_next;
@@ -470,7 +468,6 @@ void BKE_gpencil_free_layer_masks(bGPDlayer *gpl)
BLI_freelinkN(&gpl->mask_layers, mask);
}
}
-/* Free all of the gp-layers for a viewport (list should be &gpd->layers or so) */
void BKE_gpencil_free_layers(ListBase *list)
{
bGPDlayer *gpl_next;
@@ -494,7 +491,6 @@ void BKE_gpencil_free_layers(ListBase *list)
}
}
-/** Free (or release) any data used by this grease pencil (does not free the gpencil itself). */
void BKE_gpencil_free_data(bGPdata *gpd, bool free_all)
{
/* free layers */
@@ -512,10 +508,6 @@ void BKE_gpencil_free_data(bGPdata *gpd, bool free_all)
}
}
-/**
- * Delete grease pencil evaluated data
- * \param gpd_eval: Grease pencil data-block
- */
void BKE_gpencil_eval_delete(bGPdata *gpd_eval)
{
BKE_gpencil_free_data(gpd_eval, true);
@@ -524,11 +516,6 @@ void BKE_gpencil_eval_delete(bGPdata *gpd_eval)
MEM_freeN(gpd_eval);
}
-/**
- * Tag data-block for depsgraph update.
- * Wrapper to avoid include Depsgraph tag functions in other modules.
- * \param gpd: Grease pencil data-block.
- */
void BKE_gpencil_tag(bGPdata *gpd)
{
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
@@ -537,12 +524,6 @@ void BKE_gpencil_tag(bGPdata *gpd)
/* ************************************************** */
/* Container Creation */
-/**
- * Add a new gp-frame to the given layer.
- * \param gpl: Grease pencil layer
- * \param cframe: Frame number
- * \return Pointer to new frame
- */
bGPDframe *BKE_gpencil_frame_addnew(bGPDlayer *gpl, int cframe)
{
bGPDframe *gpf = NULL, *gf = NULL;
@@ -596,12 +577,6 @@ bGPDframe *BKE_gpencil_frame_addnew(bGPDlayer *gpl, int cframe)
return gpf;
}
-/**
- * Add a copy of the active gp-frame to the given layer.
- * \param gpl: Grease pencil layer
- * \param cframe: Frame number
- * \return Pointer to new frame
- */
bGPDframe *BKE_gpencil_frame_addcopy(bGPDlayer *gpl, int cframe)
{
bGPDframe *new_frame;
@@ -656,14 +631,6 @@ bGPDframe *BKE_gpencil_frame_addcopy(bGPDlayer *gpl, int cframe)
return new_frame;
}
-/**
- * Add a new gp-layer and make it the active layer.
- * \param gpd: Grease pencil data-block
- * \param name: Name of the layer
- * \param setactive: Set as active
- * \param add_to_header: Used to force the layer added at header
- * \return Pointer to new layer
- */
bGPDlayer *BKE_gpencil_layer_addnew(bGPdata *gpd,
const char *name,
const bool setactive,
@@ -748,12 +715,6 @@ bGPDlayer *BKE_gpencil_layer_addnew(bGPdata *gpd,
return gpl;
}
-/**
- * Add a new grease pencil data-block.
- * \param bmain: Main pointer
- * \param name: Name of the datablock
- * \return Pointer to new data-block
- */
bGPdata *BKE_gpencil_data_addnew(Main *bmain, const char name[])
{
bGPdata *gpd;
@@ -805,13 +766,6 @@ bGPdata *BKE_gpencil_data_addnew(Main *bmain, const char name[])
/* Primitive Creation */
/* Utilities for easier bulk-creation of geometry */
-/**
- * Create a new stroke, with pre-allocated data buffers.
- * \param mat_idx: Index of the material
- * \param totpoints: Total points
- * \param thickness: Stroke thickness
- * \return Pointer to new stroke
- */
bGPDstroke *BKE_gpencil_stroke_new(int mat_idx, int totpoints, short thickness)
{
/* allocate memory for a new stroke */
@@ -848,15 +802,6 @@ bGPDstroke *BKE_gpencil_stroke_new(int mat_idx, int totpoints, short thickness)
return gps;
}
-/**
- * Create a new stroke and add to frame.
- * \param gpf: Grease pencil frame
- * \param mat_idx: Material index
- * \param totpoints: Total points
- * \param thickness: Stroke thickness
- * \param insert_at_head: Add to the head of the strokes list
- * \return Pointer to new stroke
- */
bGPDstroke *BKE_gpencil_stroke_add(
bGPDframe *gpf, int mat_idx, int totpoints, short thickness, const bool insert_at_head)
{
@@ -875,16 +820,6 @@ bGPDstroke *BKE_gpencil_stroke_add(
return gps;
}
-/**
- * Add a stroke and copy the temporary drawing color value
- * from one of the existing stroke.
- * \param gpf: Grease pencil frame
- * \param existing: Stroke with the style to copy
- * \param mat_idx: Material index
- * \param totpoints: Total points
- * \param thickness: Stroke thickness
- * \return Pointer to new stroke
- */
bGPDstroke *BKE_gpencil_stroke_add_existing_style(
bGPDframe *gpf, bGPDstroke *existing, int mat_idx, int totpoints, short thickness)
{
@@ -909,11 +844,6 @@ bGPDcurve *BKE_gpencil_stroke_editcurve_new(const int tot_curve_points)
/* ************************************************** */
/* Data Duplication */
-/**
- * Make a copy of a given gpencil weights.
- * \param gps_src: Source grease pencil stroke
- * \param gps_dst: Destination grease pencil stroke
- */
void BKE_gpencil_stroke_weights_duplicate(bGPDstroke *gps_src, bGPDstroke *gps_dst)
{
if (gps_src == NULL) {
@@ -924,7 +854,6 @@ void BKE_gpencil_stroke_weights_duplicate(bGPDstroke *gps_src, bGPDstroke *gps_d
BKE_defvert_array_copy(gps_dst->dvert, gps_src->dvert, gps_src->totpoints);
}
-/* Make a copy of a given gpencil stroke editcurve */
bGPDcurve *BKE_gpencil_stroke_curve_duplicate(bGPDcurve *gpc_src)
{
bGPDcurve *gpc_dst = MEM_dupallocN(gpc_src);
@@ -936,13 +865,6 @@ bGPDcurve *BKE_gpencil_stroke_curve_duplicate(bGPDcurve *gpc_src)
return gpc_dst;
}
-/**
- * Make a copy of a given grease-pencil stroke.
- * \param gps_src: Source grease pencil strokes.
- * \param dup_points: Duplicate points data.
- * \param dup_curve: Duplicate curve data.
- * \return Pointer to new stroke.
- */
bGPDstroke *BKE_gpencil_stroke_duplicate(bGPDstroke *gps_src,
const bool dup_points,
const bool dup_curve)
@@ -980,11 +902,6 @@ bGPDstroke *BKE_gpencil_stroke_duplicate(bGPDstroke *gps_src,
return gps_dst;
}
-/**
- * Make a copy of a given gpencil frame.
- * \param gpf_src: Source grease pencil frame
- * \return Pointer to new frame
- */
bGPDframe *BKE_gpencil_frame_duplicate(const bGPDframe *gpf_src, const bool dup_strokes)
{
bGPDstroke *gps_dst = NULL;
@@ -1013,11 +930,6 @@ bGPDframe *BKE_gpencil_frame_duplicate(const bGPDframe *gpf_src, const bool dup_
return gpf_dst;
}
-/**
- * Make a copy of strokes between gpencil frames.
- * \param gpf_src: Source grease pencil frame
- * \param gpf_dst: Destination grease pencil frame
- */
void BKE_gpencil_frame_copy_strokes(bGPDframe *gpf_src, struct bGPDframe *gpf_dst)
{
bGPDstroke *gps_dst = NULL;
@@ -1035,11 +947,6 @@ void BKE_gpencil_frame_copy_strokes(bGPDframe *gpf_src, struct bGPDframe *gpf_ds
}
}
-/**
- * Make a copy of a given gpencil layer.
- * \param gpl_src: Source grease pencil layer
- * \return Pointer to new layer
- */
bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src,
const bool dup_frames,
const bool dup_strokes)
@@ -1078,9 +985,6 @@ bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src,
return gpl_dst;
}
-/**
- * Make a copy of a given gpencil layer settings.
- */
void BKE_gpencil_layer_copy_settings(const bGPDlayer *gpl_src, bGPDlayer *gpl_dst)
{
gpl_dst->line_change = gpl_src->line_change;
@@ -1102,11 +1006,6 @@ void BKE_gpencil_layer_copy_settings(const bGPDlayer *gpl_src, bGPDlayer *gpl_ds
gpl_dst->flag = gpl_src->flag;
}
-/**
- * Make a copy of a given gpencil data-block.
- *
- * XXX: Should this be deprecated?
- */
bGPdata *BKE_gpencil_data_duplicate(Main *bmain, const bGPdata *gpd_src, bool internal_copy)
{
bGPdata *gpd_dst;
@@ -1139,10 +1038,6 @@ bGPdata *BKE_gpencil_data_duplicate(Main *bmain, const bGPdata *gpd_src, bool in
/* ************************************************** */
/* GP Stroke API */
-/**
- * Ensure selection status of stroke is in sync with its points.
- * \param gps: Grease pencil stroke
- */
void BKE_gpencil_stroke_sync_selection(bGPdata *gpd, bGPDstroke *gps)
{
bGPDspoint *pt;
@@ -1206,14 +1101,12 @@ void BKE_gpencil_curve_sync_selection(bGPdata *gpd, bGPDstroke *gps)
}
}
-/* Assign unique stroke ID for selection. */
void BKE_gpencil_stroke_select_index_set(bGPdata *gpd, bGPDstroke *gps)
{
gpd->select_last_index++;
gps->select_index = gpd->select_last_index;
}
-/* Reset unique stroke ID for selection. */
void BKE_gpencil_stroke_select_index_reset(bGPDstroke *gps)
{
gps->select_index = 0;
@@ -1222,11 +1115,6 @@ void BKE_gpencil_stroke_select_index_reset(bGPDstroke *gps)
/* ************************************************** */
/* GP Frame API */
-/**
- * Delete the last stroke of the given frame.
- * \param gpl: Grease pencil layer
- * \param gpf: Grease pencil frame
- */
void BKE_gpencil_frame_delete_laststroke(bGPDlayer *gpl, bGPDframe *gpf)
{
bGPDstroke *gps = (gpf) ? gpf->strokes.last : NULL;
@@ -1258,11 +1146,6 @@ void BKE_gpencil_frame_delete_laststroke(bGPDlayer *gpl, bGPDframe *gpf)
/* ************************************************** */
/* GP Layer API */
-/**
- * Check if the given layer is able to be edited or not.
- * \param gpl: Grease pencil layer
- * \return True if layer is editable
- */
bool BKE_gpencil_layer_is_editable(const bGPDlayer *gpl)
{
/* Sanity check */
@@ -1279,12 +1162,6 @@ bool BKE_gpencil_layer_is_editable(const bGPDlayer *gpl)
return false;
}
-/**
- * Look up the gp-frame on the requested frame number, but don't add a new one.
- * \param gpl: Grease pencil layer
- * \param cframe: Frame number
- * \return Pointer to frame
- */
bGPDframe *BKE_gpencil_layer_frame_find(bGPDlayer *gpl, int cframe)
{
bGPDframe *gpf;
@@ -1301,16 +1178,6 @@ bGPDframe *BKE_gpencil_layer_frame_find(bGPDlayer *gpl, int cframe)
return NULL;
}
-/**
- * Get the appropriate gp-frame from a given layer
- * - this sets the layer's actframe var (if allowed to)
- * - extension beyond range (if first gp-frame is after all frame in interest and cannot add)
- *
- * \param gpl: Grease pencil layer
- * \param cframe: Frame number
- * \param addnew: Add option
- * \return Pointer to new frame
- */
bGPDframe *BKE_gpencil_layer_frame_get(bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode addnew)
{
bGPDframe *gpf = NULL;
@@ -1465,12 +1332,6 @@ bGPDframe *BKE_gpencil_layer_frame_get(bGPDlayer *gpl, int cframe, eGP_GetFrame_
return gpl->actframe;
}
-/**
- * Delete the given frame from a layer.
- * \param gpl: Grease pencil layer
- * \param gpf: Grease pencil frame
- * \return True if delete was done
- */
bool BKE_gpencil_layer_frame_delete(bGPDlayer *gpl, bGPDframe *gpf)
{
bool changed = false;
@@ -1494,12 +1355,6 @@ bool BKE_gpencil_layer_frame_delete(bGPDlayer *gpl, bGPDframe *gpf)
return changed;
}
-/**
- * Get layer by name
- * \param gpd: Grease pencil data-block
- * \param name: Layer name
- * \return Pointer to layer
- */
bGPDlayer *BKE_gpencil_layer_named_get(bGPdata *gpd, const char *name)
{
if (name[0] == '\0') {
@@ -1508,12 +1363,6 @@ bGPDlayer *BKE_gpencil_layer_named_get(bGPdata *gpd, const char *name)
return BLI_findstring(&gpd->layers, name, offsetof(bGPDlayer, info));
}
-/**
- * Get mask layer by name.
- * \param gpl: Grease pencil layer
- * \param name: Mask name
- * \return Pointer to mask layer
- */
bGPDlayer_Mask *BKE_gpencil_layer_mask_named_get(bGPDlayer *gpl, const char *name)
{
if (name[0] == '\0') {
@@ -1522,12 +1371,6 @@ bGPDlayer_Mask *BKE_gpencil_layer_mask_named_get(bGPDlayer *gpl, const char *nam
return BLI_findstring(&gpl->mask_layers, name, offsetof(bGPDlayer_Mask, name));
}
-/**
- * Add grease pencil mask layer.
- * \param gpl: Grease pencil layer
- * \param name: Name of the mask
- * \return Pointer to new mask layer
- */
bGPDlayer_Mask *BKE_gpencil_layer_mask_add(bGPDlayer *gpl, const char *name)
{
@@ -1539,11 +1382,6 @@ bGPDlayer_Mask *BKE_gpencil_layer_mask_add(bGPDlayer *gpl, const char *name)
return mask;
}
-/**
- * Remove grease pencil mask layer.
- * \param gpl: Grease pencil layer
- * \param mask: Grease pencil mask layer
- */
void BKE_gpencil_layer_mask_remove(bGPDlayer *gpl, bGPDlayer_Mask *mask)
{
BLI_freelinkN(&gpl->mask_layers, mask);
@@ -1551,11 +1389,6 @@ void BKE_gpencil_layer_mask_remove(bGPDlayer *gpl, bGPDlayer_Mask *mask)
CLAMP_MIN(gpl->act_mask, 0);
}
-/**
- * Remove any reference to mask layer.
- * \param gpd: Grease pencil data-block
- * \param name: Name of the mask layer
- */
void BKE_gpencil_layer_mask_remove_ref(bGPdata *gpd, const char *name)
{
bGPDlayer_Mask *mask_next;
@@ -1587,11 +1420,6 @@ static int gpencil_cb_sort_masks(const void *arg1, const void *arg2)
return val;
}
-/**
- * Sort grease pencil mask layers.
- * \param gpd: Grease pencil data-block
- * \param gpl: Grease pencil layer
- */
void BKE_gpencil_layer_mask_sort(bGPdata *gpd, bGPDlayer *gpl)
{
/* Update sort index. */
@@ -1607,10 +1435,6 @@ void BKE_gpencil_layer_mask_sort(bGPdata *gpd, bGPDlayer *gpl)
BLI_listbase_sort(&gpl->mask_layers, gpencil_cb_sort_masks);
}
-/**
- * Sort all grease pencil mask layer.
- * \param gpd: Grease pencil data-block
- */
void BKE_gpencil_layer_mask_sort_all(bGPdata *gpd)
{
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
@@ -1618,9 +1442,6 @@ void BKE_gpencil_layer_mask_sort_all(bGPdata *gpd)
}
}
-/**
- * Make a copy of a given gpencil mask layers.
- */
void BKE_gpencil_layer_mask_copy(const bGPDlayer *gpl_src, bGPDlayer *gpl_dst)
{
BLI_listbase_clear(&gpl_dst->mask_layers);
@@ -1631,9 +1452,6 @@ void BKE_gpencil_layer_mask_copy(const bGPDlayer *gpl_src, bGPDlayer *gpl_dst)
}
}
-/**
- * Clean any invalid mask layer.
- */
void BKE_gpencil_layer_mask_cleanup(bGPdata *gpd, bGPDlayer *gpl)
{
LISTBASE_FOREACH_MUTABLE (bGPDlayer_Mask *, mask, &gpl->mask_layers) {
@@ -1643,9 +1461,6 @@ void BKE_gpencil_layer_mask_cleanup(bGPdata *gpd, bGPDlayer *gpl)
}
}
-/**
- * Clean any invalid mask layer for all layers.
- */
void BKE_gpencil_layer_mask_cleanup_all_layers(bGPdata *gpd)
{
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
@@ -1674,21 +1489,11 @@ static int gpencil_cb_cmp_frame(void *thunk, const void *a, const void *b)
return 0;
}
-/**
- * Sort grease pencil frames.
- * \param gpl: Grease pencil layer
- * \param r_has_duplicate_frames: Duplicated frames flag
- */
void BKE_gpencil_layer_frames_sort(struct bGPDlayer *gpl, bool *r_has_duplicate_frames)
{
BLI_listbase_sort_r(&gpl->frames, gpencil_cb_cmp_frame, r_has_duplicate_frames);
}
-/**
- * Get the active grease pencil layer for editing.
- * \param gpd: Grease pencil data-block
- * \return Pointer to layer
- */
bGPDlayer *BKE_gpencil_layer_active_get(bGPdata *gpd)
{
/* error checking */
@@ -1732,11 +1537,6 @@ bGPDlayer *BKE_gpencil_layer_get_by_name(bGPdata *gpd, char *name, int first_if_
return NULL;
}
-/**
- * Set active grease pencil layer.
- * \param gpd: Grease pencil data-block
- * \param active: Grease pencil layer to set as active
- */
void BKE_gpencil_layer_active_set(bGPdata *gpd, bGPDlayer *active)
{
/* error checking */
@@ -1759,11 +1559,6 @@ void BKE_gpencil_layer_active_set(bGPdata *gpd, bGPDlayer *active)
}
}
-/**
- * Set locked layers for autolock mode.
- * \param gpd: Grease pencil data-block
- * \param unlock: Unlock flag
- */
void BKE_gpencil_layer_autolock_set(bGPdata *gpd, const bool unlock)
{
BLI_assert(gpd != NULL);
@@ -1794,11 +1589,6 @@ void BKE_gpencil_layer_autolock_set(bGPdata *gpd, const bool unlock)
}
}
-/**
- * Delete grease pencil layer.
- * \param gpd: Grease pencil data-block
- * \param gpl: Grease pencil layer
- */
void BKE_gpencil_layer_delete(bGPdata *gpd, bGPDlayer *gpl)
{
/* error checking */
@@ -1821,11 +1611,6 @@ void BKE_gpencil_layer_delete(bGPdata *gpd, bGPDlayer *gpl)
BLI_freelinkN(&gpd->layers, gpl);
}
-/**
- * Get grease pencil material from brush.
- * \param brush: Brush
- * \return Pointer to material
- */
Material *BKE_gpencil_brush_material_get(Brush *brush)
{
Material *ma = NULL;
@@ -1838,11 +1623,6 @@ Material *BKE_gpencil_brush_material_get(Brush *brush)
return ma;
}
-/**
- * Set grease pencil brush material.
- * \param brush: Brush
- * \param ma: Material
- */
void BKE_gpencil_brush_material_set(Brush *brush, Material *ma)
{
BLI_assert(brush);
@@ -1858,13 +1638,6 @@ void BKE_gpencil_brush_material_set(Brush *brush, Material *ma)
}
}
-/**
- * Adds the pinned material to the object if necessary.
- * \param bmain: Main pointer
- * \param ob: Grease pencil object
- * \param brush: Brush
- * \return Pointer to material
- */
Material *BKE_gpencil_object_material_ensure_from_brush(Main *bmain, Object *ob, Brush *brush)
{
if (brush->gpencil_settings->flag & GP_BRUSH_MATERIAL_PINNED) {
@@ -1883,13 +1656,6 @@ Material *BKE_gpencil_object_material_ensure_from_brush(Main *bmain, Object *ob,
return BKE_object_material_get(ob, ob->actcol);
}
-/**
- * Assigns the material to object (if not already present) and returns its index (mat_nr).
- * \param bmain: Main pointer
- * \param ob: Grease pencil object
- * \param material: Material
- * \return Index of the material
- */
int BKE_gpencil_object_material_ensure(Main *bmain, Object *ob, Material *material)
{
if (!material) {
@@ -1904,14 +1670,6 @@ int BKE_gpencil_object_material_ensure(Main *bmain, Object *ob, Material *materi
return index;
}
-/**
- * Creates a new grease-pencil material and assigns it to object.
- * \param bmain: Main pointer
- * \param ob: Grease pencil object
- * \param name: Material name
- * \param r_index: value is set to zero based index of the new material if \a r_index is not NULL.
- * \return Material pointer.
- */
Material *BKE_gpencil_object_material_new(Main *bmain, Object *ob, const char *name, int *r_index)
{
Material *ma = BKE_gpencil_material_add(bmain, name);
@@ -1926,12 +1684,6 @@ Material *BKE_gpencil_object_material_new(Main *bmain, Object *ob, const char *n
return ma;
}
-/**
- * Returns the material for a brush with respect to its pinned state.
- * \param ob: Grease pencil object
- * \param brush: Brush
- * \return Material pointer
- */
Material *BKE_gpencil_object_material_from_brush_get(Object *ob, Brush *brush)
{
if ((brush) && (brush->gpencil_settings) &&
@@ -1943,12 +1695,6 @@ Material *BKE_gpencil_object_material_from_brush_get(Object *ob, Brush *brush)
return BKE_object_material_get(ob, ob->actcol);
}
-/**
- * Returns the material index for a brush with respect to its pinned state.
- * \param ob: Grease pencil object
- * \param brush: Brush
- * \return Material index.
- */
int BKE_gpencil_object_material_get_index_from_brush(Object *ob, Brush *brush)
{
if ((brush) && (brush->gpencil_settings->flag & GP_BRUSH_MATERIAL_PINNED)) {
@@ -1958,12 +1704,6 @@ int BKE_gpencil_object_material_get_index_from_brush(Object *ob, Brush *brush)
return ob->actcol - 1;
}
-/**
- * Guaranteed to return a material assigned to object. Returns never NULL.
- * \param bmain: Main pointer
- * \param ob: Grease pencil object
- * \return Material pointer.
- */
Material *BKE_gpencil_object_material_ensure_from_active_input_toolsettings(Main *bmain,
Object *ob,
ToolSettings *ts)
@@ -1976,13 +1716,6 @@ Material *BKE_gpencil_object_material_ensure_from_active_input_toolsettings(Main
return BKE_gpencil_object_material_ensure_from_active_input_brush(bmain, ob, NULL);
}
-/**
- * Guaranteed to return a material assigned to object. Returns never NULL.
- * \param bmain: Main pointer
- * \param ob: Grease pencil object.
- * \param brush: Brush
- * \return Material pointer
- */
Material *BKE_gpencil_object_material_ensure_from_active_input_brush(Main *bmain,
Object *ob,
Brush *brush)
@@ -2000,12 +1733,6 @@ Material *BKE_gpencil_object_material_ensure_from_active_input_brush(Main *bmain
return BKE_gpencil_object_material_ensure_from_active_input_material(ob);
}
-/**
- * Guaranteed to return a material assigned to object. Returns never NULL.
- * Only use this for materials unrelated to user input.
- * \param ob: Grease pencil object
- * \return Material pointer
- */
Material *BKE_gpencil_object_material_ensure_from_active_input_material(Object *ob)
{
Material *ma = BKE_object_material_get(ob, ob->actcol);
@@ -2016,11 +1743,6 @@ Material *BKE_gpencil_object_material_ensure_from_active_input_material(Object *
return BKE_material_default_gpencil();
}
-/**
- * Get active color, and add all default settings if we don't find anything.
- * \param ob: Grease pencil object
- * \return Material pointer
- */
Material *BKE_gpencil_object_material_ensure_active(Object *ob)
{
Material *ma = NULL;
@@ -2039,11 +1761,6 @@ Material *BKE_gpencil_object_material_ensure_active(Object *ob)
}
/* ************************************************** */
-/**
- * Check if stroke has any point selected
- * \param gps: Grease pencil stroke
- * \return True if selected
- */
bool BKE_gpencil_stroke_select_check(const bGPDstroke *gps)
{
const bGPDspoint *pt;
@@ -2059,11 +1776,6 @@ bool BKE_gpencil_stroke_select_check(const bGPDstroke *gps)
/* ************************************************** */
/* GP Object - Vertex Groups */
-/**
- * Remove a vertex group.
- * \param ob: Grease pencil object
- * \param defgroup: deform group
- */
void BKE_gpencil_vgroup_remove(Object *ob, bDeformGroup *defgroup)
{
bGPdata *gpd = ob->data;
@@ -2103,10 +1815,6 @@ void BKE_gpencil_vgroup_remove(Object *ob, bDeformGroup *defgroup)
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
}
-/**
- * Ensure stroke has vertex group.
- * \param gps: Grease pencil stroke
- */
void BKE_gpencil_dvert_ensure(bGPDstroke *gps)
{
if (gps->dvert == NULL) {
@@ -2116,14 +1824,6 @@ void BKE_gpencil_dvert_ensure(bGPDstroke *gps)
/* ************************************************** */
-/**
- * Get range of selected frames in layer.
- * Always the active frame is considered as selected, so if no more selected the range
- * will be equal to the current active frame.
- * \param gpl: Layer.
- * \param r_initframe: Number of first selected frame.
- * \param r_endframe: Number of last selected frame.
- */
void BKE_gpencil_frame_range_selected(bGPDlayer *gpl, int *r_initframe, int *r_endframe)
{
*r_initframe = gpl->actframe->framenum;
@@ -2141,14 +1841,6 @@ void BKE_gpencil_frame_range_selected(bGPDlayer *gpl, int *r_initframe, int *r_e
}
}
-/**
- * Get Falloff factor base on frame range
- * \param gpf: Frame.
- * \param actnum: Number of active frame in layer.
- * \param f_init: Number of first selected frame.
- * \param f_end: Number of last selected frame.
- * \param cur_falloff: Curve with falloff factors.
- */
float BKE_gpencil_multiframe_falloff_calc(
bGPDframe *gpf, int actnum, int f_init, int f_end, CurveMapping *cur_falloff)
{
@@ -2180,12 +1872,6 @@ float BKE_gpencil_multiframe_falloff_calc(
return value;
}
-/**
- * Reassign strokes using a material.
- * \param gpd: Grease pencil data-block
- * \param totcol: Total materials
- * \param index: Index of the material
- */
void BKE_gpencil_material_index_reassign(bGPdata *gpd, int totcol, int index)
{
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
@@ -2201,12 +1887,6 @@ void BKE_gpencil_material_index_reassign(bGPdata *gpd, int totcol, int index)
}
}
-/**
- * Remove strokes using a material.
- * \param gpd: Grease pencil data-block
- * \param index: Index of the material
- * \return True if removed
- */
bool BKE_gpencil_material_index_used(bGPdata *gpd, int index)
{
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
@@ -2222,12 +1902,6 @@ bool BKE_gpencil_material_index_used(bGPdata *gpd, int index)
return false;
}
-/**
- * Remap material
- * \param gpd: Grease pencil data-block
- * \param remap: Remap index
- * \param remap_len: Remap length
- */
void BKE_gpencil_material_remap(struct bGPdata *gpd,
const unsigned int *remap,
unsigned int remap_len)
@@ -2253,15 +1927,6 @@ void BKE_gpencil_material_remap(struct bGPdata *gpd,
#undef MAT_NR_REMAP
}
-/**
- * Load a table with material conversion index for merged materials.
- * \param ob: Grease pencil object.
- * \param hue_threshold: Threshold for Hue.
- * \param sat_threshold: Threshold for Saturation.
- * \param val_threshold: Threshold for Value.
- * \param r_mat_table: return material table.
- * \return True if done.
- */
bool BKE_gpencil_merge_materials_table_get(Object *ob,
const float hue_threshold,
const float sat_threshold,
@@ -2381,15 +2046,6 @@ bool BKE_gpencil_merge_materials_table_get(Object *ob,
return changed;
}
-/**
- * Merge similar materials
- * \param ob: Grease pencil object
- * \param hue_threshold: Threshold for Hue
- * \param sat_threshold: Threshold for Saturation
- * \param val_threshold: Threshold for Value
- * \param r_removed: Number of materials removed
- * \return True if done
- */
bool BKE_gpencil_merge_materials(Object *ob,
const float hue_threshold,
const float sat_threshold,
@@ -2448,10 +2104,6 @@ bool BKE_gpencil_merge_materials(Object *ob,
return changed;
}
-/**
- * Calc grease pencil statistics functions.
- * \param gpd: Grease pencil data-block
- */
void BKE_gpencil_stats_update(bGPdata *gpd)
{
gpd->totlayer = 0;
@@ -2471,12 +2123,6 @@ void BKE_gpencil_stats_update(bGPdata *gpd)
}
}
-/**
- * Get material index (0-based like mat_nr not actcol).
- * \param ob: Grease pencil object
- * \param ma: Material
- * \return Index of the material
- */
int BKE_gpencil_object_material_index_get(Object *ob, Material *ma)
{
short *totcol = BKE_object_material_len_p(ob);
@@ -2519,11 +2165,6 @@ Material *BKE_gpencil_object_material_ensure_by_name(Main *bmain,
return BKE_gpencil_object_material_new(bmain, ob, name, r_index);
}
-/**
- * Create a default palette.
- * \param bmain: Main pointer
- * \param scene: Scene
- */
void BKE_gpencil_palette_ensure(Main *bmain, Scene *scene)
{
const char *hexcol[] = {
@@ -2573,15 +2214,6 @@ void BKE_gpencil_palette_ensure(Main *bmain, Scene *scene)
BKE_paint_palette_set(&ts->gp_vertexpaint->paint, palette);
}
-/**
- * Create grease pencil strokes from image
- * \param sima: Image
- * \param gpd: Grease pencil data-block
- * \param gpf: Grease pencil frame
- * \param size: Size
- * \param mask: Mask
- * \return True if done
- */
bool BKE_gpencil_from_image(
SpaceImage *sima, bGPdata *gpd, bGPDframe *gpf, const float size, const bool mask)
{
@@ -2713,6 +2345,8 @@ void BKE_gpencil_visible_stroke_iter(bGPdata *gpd,
}
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Advanced Iterator
*
@@ -2917,11 +2551,6 @@ void BKE_gpencil_visible_stroke_advanced_iter(ViewLayer *view_layer,
}
}
-/**
- * Update original pointers in evaluated frame.
- * \param gpf_orig: Original grease-pencil frame.
- * \param gpf_eval: Evaluated grease pencil frame.
- */
void BKE_gpencil_frame_original_pointers_update(const struct bGPDframe *gpf_orig,
const struct bGPDframe *gpf_eval)
{
@@ -2950,11 +2579,6 @@ void BKE_gpencil_frame_original_pointers_update(const struct bGPDframe *gpf_orig
}
}
-/**
- * Update pointers of eval data to original data to keep references.
- * \param ob_orig: Original grease pencil object
- * \param ob_eval: Evaluated grease pencil object
- */
void BKE_gpencil_update_orig_pointers(const Object *ob_orig, const Object *ob_eval)
{
bGPdata *gpd_eval = (bGPdata *)ob_eval->data;
@@ -2985,13 +2609,6 @@ void BKE_gpencil_update_orig_pointers(const Object *ob_orig, const Object *ob_ev
}
}
-/**
- * Get parent matrix, including layer parenting.
- * \param depsgraph: Depsgraph
- * \param obact: Grease pencil object
- * \param gpl: Grease pencil layer
- * \param diff_mat: Result parent matrix
- */
void BKE_gpencil_layer_transform_matrix_get(const Depsgraph *depsgraph,
Object *obact,
bGPDlayer *gpl,
@@ -3040,11 +2657,6 @@ void BKE_gpencil_layer_transform_matrix_get(const Depsgraph *depsgraph,
unit_m4(diff_mat); /* not defined type */
}
-/**
- * Update parent matrix and local transforms.
- * \param depsgraph: Depsgraph
- * \param ob: Grease pencil object
- */
void BKE_gpencil_update_layer_transforms(const Depsgraph *depsgraph, Object *ob)
{
if (ob->type != OB_GPENCIL) {
@@ -3104,12 +2716,6 @@ void BKE_gpencil_update_layer_transforms(const Depsgraph *depsgraph, Object *ob)
}
}
-/**
- * Find material by name prefix.
- * \param ob: Object pointer
- * \param name_prefix: Prefix name of the material
- * \return Index
- */
int BKE_gpencil_material_find_index_by_name_prefix(Object *ob, const char *name_prefix)
{
const int name_prefix_len = strlen(name_prefix);
@@ -3124,7 +2730,6 @@ int BKE_gpencil_material_find_index_by_name_prefix(Object *ob, const char *name_
return -1;
}
-/* Create a hash with the list of selected frame number. */
void BKE_gpencil_frame_selected_hash(bGPdata *gpd, struct GHash *r_list)
{
const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
diff --git a/source/blender/blenkernel/intern/gpencil_curve.c b/source/blender/blenkernel/intern/gpencil_curve.c
index 98e481e6ea8..d633678b873 100644
--- a/source/blender/blenkernel/intern/gpencil_curve.c
+++ b/source/blender/blenkernel/intern/gpencil_curve.c
@@ -477,17 +477,6 @@ static void gpencil_editstroke_deselect_all(bGPDcurve *gpc)
gpc->flag &= ~GP_CURVE_SELECT;
}
-/**
- * Convert a curve object to grease pencil stroke.
- *
- * \param bmain: Main thread pointer
- * \param scene: Original scene.
- * \param ob_gp: Grease pencil object to add strokes.
- * \param ob_cu: Curve to convert.
- * \param use_collections: Create layers using collection names.
- * \param scale_thickness: Scale thickness factor.
- * \param sample: Sample distance, zero to disable.
- */
void BKE_gpencil_convert_curve(Main *bmain,
Scene *scene,
Object *ob_gp,
@@ -639,9 +628,6 @@ static bGPDcurve *gpencil_stroke_editcurve_generate_edgecases(bGPDstroke *gps,
return NULL;
}
-/**
- * Creates a bGPDcurve by doing a cubic curve fitting on the grease pencil stroke points.
- */
bGPDcurve *BKE_gpencil_stroke_editcurve_generate(bGPDstroke *gps,
const float error_threshold,
const float corner_angle,
@@ -753,9 +739,6 @@ bGPDcurve *BKE_gpencil_stroke_editcurve_generate(bGPDstroke *gps,
return editcurve;
}
-/**
- * Updates the editcurve for a stroke. Frees the old curve if one exists and generates a new one.
- */
void BKE_gpencil_stroke_editcurve_update(bGPdata *gpd, bGPDlayer *gpl, bGPDstroke *gps)
{
if (gps == NULL || gps->totpoints < 0) {
@@ -778,9 +761,6 @@ void BKE_gpencil_stroke_editcurve_update(bGPdata *gpd, bGPDlayer *gpl, bGPDstrok
gps->editcurve = editcurve;
}
-/**
- * Sync the selection from stroke to editcurve
- */
void BKE_gpencil_editcurve_stroke_sync_selection(bGPdata *UNUSED(gpd),
bGPDstroke *gps,
bGPDcurve *gpc)
@@ -807,9 +787,6 @@ void BKE_gpencil_editcurve_stroke_sync_selection(bGPdata *UNUSED(gpd),
}
}
-/**
- * Sync the selection from editcurve to stroke
- */
void BKE_gpencil_stroke_editcurve_sync_selection(bGPdata *gpd, bGPDstroke *gps, bGPDcurve *gpc)
{
if (gpc->flag & GP_CURVE_SELECT) {
@@ -1055,9 +1032,6 @@ static float *gpencil_stroke_points_from_editcurve_fixed_resolu(bGPDcurve_point
return (float(*))r_points;
}
-/**
- * Recalculate stroke points with the editcurve of the stroke.
- */
void BKE_gpencil_stroke_update_geometry_from_editcurve(bGPDstroke *gps,
const uint resolution,
const bool adaptive)
@@ -1142,9 +1116,6 @@ void BKE_gpencil_stroke_update_geometry_from_editcurve(bGPDstroke *gps,
MEM_freeN(points);
}
-/**
- * Recalculate the handles of the edit curve of a grease pencil stroke
- */
void BKE_gpencil_editcurve_recalculate_handles(bGPDstroke *gps)
{
if (gps == NULL || gps->editcurve == NULL) {
diff --git a/source/blender/blenkernel/intern/gpencil_geom.cc b/source/blender/blenkernel/intern/gpencil_geom.cc
index fffc13c49a8..b5190f598c6 100644
--- a/source/blender/blenkernel/intern/gpencil_geom.cc
+++ b/source/blender/blenkernel/intern/gpencil_geom.cc
@@ -67,15 +67,10 @@
using blender::float3;
using blender::Span;
-/* GP Object - Boundbox Support */
-/**
- *Get min/max coordinate bounds for single stroke.
- * \param gps: Grease pencil stroke
- * \param use_select: Include only selected points
- * \param r_min: Result minimum coordinates
- * \param r_max: Result maximum coordinates
- * \return True if it was possible to calculate
- */
+/* -------------------------------------------------------------------- */
+/** \name Grease Pencil Object: Bound-box Support
+ * \{ */
+
bool BKE_gpencil_stroke_minmax(const bGPDstroke *gps,
const bool use_select,
float r_min[3],
@@ -104,13 +99,6 @@ bool BKE_gpencil_stroke_minmax(const bGPDstroke *gps,
return changed;
}
-/**
- * Get min/max bounds of all strokes in grease pencil data-block.
- * \param gpd: Grease pencil datablock
- * \param r_min: Result minimum coordinates
- * \param r_max: Result maximum coordinates
- * \return True if it was possible to calculate
- */
bool BKE_gpencil_data_minmax(const bGPdata *gpd, float r_min[3], float r_max[3])
{
bool changed = false;
@@ -134,11 +122,6 @@ bool BKE_gpencil_data_minmax(const bGPdata *gpd, float r_min[3], float r_max[3])
return changed;
}
-/**
- * Compute center of bounding box.
- * \param gpd: Grease pencil data-block
- * \param r_centroid: Location of the center
- */
void BKE_gpencil_centroid_3d(bGPdata *gpd, float r_centroid[3])
{
float3 min;
@@ -149,10 +132,6 @@ void BKE_gpencil_centroid_3d(bGPdata *gpd, float r_centroid[3])
mul_v3_v3fl(r_centroid, tot, 0.5f);
}
-/**
- * Compute stroke bounding box.
- * \param gps: Grease pencil Stroke
- */
void BKE_gpencil_stroke_boundingbox_calc(bGPDstroke *gps)
{
INIT_MINMAX(gps->boundbox_min, gps->boundbox_max);
@@ -184,11 +163,6 @@ static void boundbox_gpencil(Object *ob)
bb->flag &= ~BOUNDBOX_DIRTY;
}
-/**
- * Get grease pencil object bounding box.
- * \param ob: Grease pencil object
- * \return Bounding box
- */
BoundBox *BKE_gpencil_boundbox_get(Object *ob)
{
if (ELEM(nullptr, ob, ob->data)) {
@@ -218,7 +192,11 @@ BoundBox *BKE_gpencil_boundbox_get(Object *ob)
return ob->runtime.bb;
}
-/* ************************************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Sample
+ * \{ */
static int stroke_march_next_point(const bGPDstroke *gps,
const int index_next_pt,
@@ -431,12 +409,6 @@ static void stroke_interpolate_deform_weights(
}
}
-/**
- * Resample a stroke
- * \param gpd: Grease pencil data-block
- * \param gps: Stroke to sample
- * \param dist: Distance of one segment
- */
bool BKE_gpencil_stroke_sample(bGPdata *gpd, bGPDstroke *gps, const float dist, const bool select)
{
bGPDspoint *pt = gps->points;
@@ -594,15 +566,6 @@ static bool BKE_gpencil_stroke_extra_points(bGPDstroke *gps,
return true;
}
-/**
- * Backbone stretch similar to Freestyle.
- * \param gps: Stroke to sample.
- * \param dist: Length of the added section.
- * \param overshoot_fac: Relative length of the curve which is used to determine the extension.
- * \param mode: Affect to Start, End or Both extremes (0->Both, 1->Start, 2->End)
- * \param follow_curvature: True for approximating curvature of given overshoot.
- * \param extra_point_count: When follow_curvature is true, use this amount of extra points
- */
bool BKE_gpencil_stroke_stretch(bGPDstroke *gps,
const float dist,
const float overshoot_fac,
@@ -779,12 +742,12 @@ bool BKE_gpencil_stroke_stretch(bGPDstroke *gps,
return true;
}
-/**
- * Trim stroke to needed segments
- * \param gps: Target stroke
- * \param index_from: the index of the first point to be used in the trimmed result
- * \param index_to: the index of the last point to be used in the trimmed result
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Trim
+ * \{ */
+
bool BKE_gpencil_stroke_trim_points(bGPDstroke *gps, const int index_from, const int index_to)
{
bGPDspoint *pt = gps->points, *new_pt;
@@ -837,15 +800,12 @@ bool BKE_gpencil_stroke_trim_points(bGPDstroke *gps, const int index_from, const
return true;
}
-/**
- * Split stroke.
- * \param gpd: Grease pencil data-block
- * \param gpf: Grease pencil frame
- * \param gps: Grease pencil original stroke
- * \param before_index: Position of the point to split
- * \param remaining_gps: Secondary stroke after split.
- * \return True if the split was done
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Split
+ * \{ */
+
bool BKE_gpencil_stroke_split(bGPdata *gpd,
bGPDframe *gpf,
bGPDstroke *gps,
@@ -898,12 +858,12 @@ bool BKE_gpencil_stroke_split(bGPdata *gpd,
return true;
}
-/**
- * Shrink the stroke by length.
- * \param gps: Stroke to shrink
- * \param dist: delta length
- * \param mode: 1->Start, 2->End
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Shrink
+ * \{ */
+
bool BKE_gpencil_stroke_shrink(bGPDstroke *gps, const float dist, const short mode)
{
#define START 1
@@ -976,13 +936,14 @@ bool BKE_gpencil_stroke_shrink(bGPDstroke *gps, const float dist, const short mo
return true;
}
-/**
- * Apply smooth position to stroke point.
- * \param gps: Stroke to smooth
- * \param i: Point index
- * \param inf: Amount of smoothing to apply
- */
-bool BKE_gpencil_stroke_smooth_point(bGPDstroke *gps, int i, float inf)
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Smooth Positions
+ * \{ */
+
+bool BKE_gpencil_stroke_smooth_point(bGPDstroke *gps, int i, float inf, const bool smooth_caps)
{
bGPDspoint *pt = &gps->points[i];
float sco[3] = {0.0f};
@@ -996,7 +957,7 @@ bool BKE_gpencil_stroke_smooth_point(bGPDstroke *gps, int i, float inf)
/* Only affect endpoints by a fraction of the normal strength,
* to prevent the stroke from shrinking too much
*/
- if (!is_cyclic && ELEM(i, 0, gps->totpoints - 1)) {
+ if ((!smooth_caps) && (!is_cyclic && ELEM(i, 0, gps->totpoints - 1))) {
inf *= 0.1f;
}
@@ -1054,12 +1015,12 @@ bool BKE_gpencil_stroke_smooth_point(bGPDstroke *gps, int i, float inf)
return true;
}
-/**
- * Apply smooth strength to stroke point.
- * \param gps: Stroke to smooth
- * \param point_index: Point index
- * \param influence: Amount of smoothing to apply
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Smooth Strength
+ * \{ */
+
bool BKE_gpencil_stroke_smooth_strength(bGPDstroke *gps, int point_index, float influence)
{
bGPDspoint *ptb = &gps->points[point_index];
@@ -1132,12 +1093,12 @@ bool BKE_gpencil_stroke_smooth_strength(bGPDstroke *gps, int point_index, float
return true;
}
-/**
- * Apply smooth for thickness to stroke point (use pressure).
- * \param gps: Stroke to smooth
- * \param point_index: Point index
- * \param influence: Amount of smoothing to apply
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Smooth Thickness
+ * \{ */
+
bool BKE_gpencil_stroke_smooth_thickness(bGPDstroke *gps, int point_index, float influence)
{
bGPDspoint *ptb = &gps->points[point_index];
@@ -1209,12 +1170,12 @@ bool BKE_gpencil_stroke_smooth_thickness(bGPDstroke *gps, int point_index, float
return true;
}
-/**
- * Apply smooth for UV rotation to stroke point (use pressure).
- * \param gps: Stroke to smooth
- * \param point_index: Point index
- * \param influence: Amount of smoothing to apply
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Smooth UV
+ * \{ */
+
bool BKE_gpencil_stroke_smooth_uv(bGPDstroke *gps, int point_index, float influence)
{
bGPDspoint *ptb = &gps->points[point_index];
@@ -1266,14 +1227,6 @@ bool BKE_gpencil_stroke_smooth_uv(bGPDstroke *gps, int point_index, float influe
return true;
}
-/**
- * Get points of stroke always flat to view not affected
- * by camera view or view position.
- * \param points: Array of grease pencil points (3D)
- * \param totpoints: Total of points
- * \param points2d: Result array of 2D points
- * \param r_direction: Return Concave (-1), Convex (1), or Auto-detect (0)
- */
void BKE_gpencil_stroke_2d_flat(const bGPDspoint *points,
int totpoints,
float (*points2d)[2],
@@ -1348,17 +1301,6 @@ void BKE_gpencil_stroke_2d_flat(const bGPDspoint *points,
*r_direction = (cross >= 0.0f) ? 1 : -1;
}
-/**
- * Get points of stroke always flat to view not affected by camera view or view position
- * using another stroke as reference.
- * \param ref_points: Array of reference points (3D)
- * \param ref_totpoints: Total reference points
- * \param points: Array of points to flat (3D)
- * \param totpoints: Total points
- * \param points2d: Result array of 2D points
- * \param scale: Scale factor
- * \param r_direction: Return Concave (-1), Convex (1), or Auto-detect (0)
- */
void BKE_gpencil_stroke_2d_flat_ref(const bGPDspoint *ref_points,
int ref_totpoints,
const bGPDspoint *points,
@@ -1482,10 +1424,12 @@ static void gpencil_calc_stroke_fill_uv(const float (*points2d)[2],
}
}
-/**
- * Triangulate stroke to generate data for filling areas.
- * \param gps: Grease pencil stroke
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Fill Triangulate
+ * \{ */
+
void BKE_gpencil_stroke_fill_triangulate(bGPDstroke *gps)
{
BLI_assert(gps->totpoints >= 3);
@@ -1545,10 +1489,6 @@ void BKE_gpencil_stroke_fill_triangulate(bGPDstroke *gps)
MEM_SAFE_FREE(uv);
}
-/**
- * Update Stroke UV data.
- * \param gps: Grease pencil stroke
- */
void BKE_gpencil_stroke_uv_update(bGPDstroke *gps)
{
if (gps == nullptr || gps->totpoints == 0) {
@@ -1564,11 +1504,6 @@ void BKE_gpencil_stroke_uv_update(bGPDstroke *gps)
}
}
-/**
- * Recalc all internal geometry data for the stroke
- * \param gpd: Grease pencil data-block
- * \param gps: Grease pencil stroke
- */
void BKE_gpencil_stroke_geometry_update(bGPdata *gpd, bGPDstroke *gps)
{
if (gps == nullptr) {
@@ -1606,12 +1541,6 @@ void BKE_gpencil_stroke_geometry_update(bGPdata *gpd, bGPDstroke *gps)
BKE_gpencil_stroke_boundingbox_calc(gps);
}
-/**
- * Calculate grease pencil stroke length.
- * \param gps: Grease pencil stroke
- * \param use_3d: Set to true to use 3D points
- * \return Length of the stroke
- */
float BKE_gpencil_stroke_length(const bGPDstroke *gps, bool use_3d)
{
if (!gps->points || gps->totpoints < 2) {
@@ -1632,7 +1561,6 @@ float BKE_gpencil_stroke_length(const bGPDstroke *gps, bool use_3d)
return total_length;
}
-/** Calculate grease pencil stroke length between points. */
float BKE_gpencil_stroke_segment_length(const struct bGPDstroke *gps,
const int start_index,
const int end_index,
@@ -1660,10 +1588,6 @@ float BKE_gpencil_stroke_segment_length(const struct bGPDstroke *gps,
return total_length;
}
-/**
- * Trim stroke to the first intersection or loop.
- * \param gps: Stroke data
- */
bool BKE_gpencil_stroke_trim(bGPdata *gpd, bGPDstroke *gps)
{
if (gps->totpoints < 4) {
@@ -1756,10 +1680,6 @@ bool BKE_gpencil_stroke_trim(bGPdata *gpd, bGPDstroke *gps)
return intersect;
}
-/**
- * Close grease pencil stroke.
- * \param gps: Stroke to close
- */
bool BKE_gpencil_stroke_close(bGPDstroke *gps)
{
bGPDspoint *pt1 = nullptr;
@@ -1845,13 +1765,12 @@ bool BKE_gpencil_stroke_close(bGPDstroke *gps)
return true;
}
-/**
- * Dissolve points in stroke.
- * \param gpd: Grease pencil data-block
- * \param gpf: Grease pencil frame
- * \param gps: Grease pencil stroke
- * \param tag: Type of tag for point
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Dissolve Points
+ * \{ */
+
void BKE_gpencil_dissolve_points(bGPdata *gpd, bGPDframe *gpf, bGPDstroke *gps, const short tag)
{
bGPDspoint *pt;
@@ -1934,11 +1853,12 @@ void BKE_gpencil_dissolve_points(bGPdata *gpd, bGPDframe *gpf, bGPDstroke *gps,
}
}
-/**
- * Calculate stroke normals.
- * \param gps: Grease pencil stroke
- * \param r_normal: Return Normal vector normalized
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Normal Calculation
+ * \{ */
+
void BKE_gpencil_stroke_normal(const bGPDstroke *gps, float r_normal[3])
{
if (gps->totpoints < 3) {
@@ -1969,18 +1889,12 @@ void BKE_gpencil_stroke_normal(const bGPDstroke *gps, float r_normal[3])
normalize_v3(r_normal);
}
-/* Stroke Simplify ------------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Simplify
+ * \{ */
-/**
- * Reduce a series of points to a simplified version, but
- * maintains the general shape of the series
- *
- * Ramer - Douglas - Peucker algorithm
- * by http://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm
- * \param gpd: Grease pencil data-block
- * \param gps: Grease pencil stroke
- * \param epsilon: Epsilon value to define precision of the algorithm
- */
void BKE_gpencil_stroke_simplify_adaptive(bGPdata *gpd, bGPDstroke *gps, float epsilon)
{
bGPDspoint *old_points = (bGPDspoint *)MEM_dupallocN(gps->points);
@@ -2085,11 +1999,6 @@ void BKE_gpencil_stroke_simplify_adaptive(bGPdata *gpd, bGPDstroke *gps, float e
MEM_SAFE_FREE(marked);
}
-/**
- * Simplify alternate vertex of stroke except extremes.
- * \param gpd: Grease pencil data-block
- * \param gps: Grease pencil stroke
- */
void BKE_gpencil_stroke_simplify_fixed(bGPdata *gpd, bGPDstroke *gps)
{
if (gps->totpoints < 5) {
@@ -2150,13 +2059,6 @@ void BKE_gpencil_stroke_simplify_fixed(bGPdata *gpd, bGPDstroke *gps)
MEM_SAFE_FREE(old_dvert);
}
-/**
- * Subdivide a stroke
- * \param gpd: Grease pencil data-block
- * \param gps: Stroke
- * \param level: Level of subdivision
- * \param type: Type of subdivision
- */
void BKE_gpencil_stroke_subdivide(bGPdata *gpd, bGPDstroke *gps, int level, int type)
{
bGPDspoint *temp_points;
@@ -2269,19 +2171,12 @@ void BKE_gpencil_stroke_subdivide(bGPdata *gpd, bGPDstroke *gps, int level, int
BKE_gpencil_stroke_geometry_update(gpd, gps);
}
-/* Merge by distance ------------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Merge by Distance
+ * \{ */
-/**
- * Reduce a series of points when the distance is below a threshold.
- * Special case for first and last points (both are kept) for other points,
- * the merge point always is at first point.
- *
- * \param gpd: Grease pencil data-block.
- * \param gpf: Grease Pencil frame.
- * \param gps: Grease Pencil stroke.
- * \param threshold: Distance between points.
- * \param use_unselected: Set to true to analyze all stroke and not only selected points.
- */
void BKE_gpencil_stroke_merge_distance(bGPdata *gpd,
bGPDframe *gpf,
bGPDstroke *gps,
@@ -2639,22 +2534,6 @@ static void make_element_name(const char *obname, const char *name, const int ma
BLI_strncpy_utf8(r_name, str, maxlen);
}
-/**
- * Convert a mesh object to grease pencil stroke.
- *
- * \param bmain: Main thread pointer.
- * \param depsgraph: Original depsgraph.
- * \param scene: Original scene.
- * \param ob_gp: Grease pencil object to add strokes.
- * \param ob_mesh: Mesh to convert.
- * \param angle: Limit angle to consider a edge-loop ends.
- * \param thickness: Thickness of the strokes.
- * \param offset: Offset along the normals.
- * \param matrix: Transformation matrix.
- * \param frame_offset: Destination frame number offset.
- * \param use_seams: Only export seam edges.
- * \param use_faces: Export faces as filled strokes.
- */
bool BKE_gpencil_convert_mesh(Main *bmain,
Depsgraph *depsgraph,
Scene *scene,
@@ -2807,11 +2686,6 @@ bool BKE_gpencil_convert_mesh(Main *bmain,
return true;
}
-/**
- * Apply grease pencil Transforms.
- * \param gpd: Grease pencil data-block
- * \param mat: Transformation matrix
- */
void BKE_gpencil_transform(bGPdata *gpd, const float mat[4][4])
{
if (gpd == nullptr) {
@@ -2845,7 +2719,6 @@ void BKE_gpencil_transform(bGPdata *gpd, const float mat[4][4])
}
}
-/* Used for "move only origins" in object_data_transform.c */
int BKE_gpencil_stroke_point_count(const bGPdata *gpd)
{
int total_points = 0;
@@ -2872,7 +2745,6 @@ int BKE_gpencil_stroke_point_count(const bGPdata *gpd)
return total_points;
}
-/* Used for "move only origins" in object_data_transform.c */
void BKE_gpencil_point_coords_get(bGPdata *gpd, GPencilPointCoordinates *elem_data)
{
if (gpd == nullptr) {
@@ -2903,7 +2775,6 @@ void BKE_gpencil_point_coords_get(bGPdata *gpd, GPencilPointCoordinates *elem_da
}
}
-/* Used for "move only origins" in object_data_transform.c */
void BKE_gpencil_point_coords_apply(bGPdata *gpd, const GPencilPointCoordinates *elem_data)
{
if (gpd == nullptr) {
@@ -2937,7 +2808,6 @@ void BKE_gpencil_point_coords_apply(bGPdata *gpd, const GPencilPointCoordinates
}
}
-/* Used for "move only origins" in object_data_transform.c */
void BKE_gpencil_point_coords_apply_with_mat4(bGPdata *gpd,
const GPencilPointCoordinates *elem_data,
const float mat[4][4])
@@ -2974,10 +2844,6 @@ void BKE_gpencil_point_coords_apply_with_mat4(bGPdata *gpd,
}
}
-/**
- * Set a random color to stroke using vertex color.
- * \param gps: Stroke
- */
void BKE_gpencil_stroke_set_random_color(bGPDstroke *gps)
{
BLI_assert(gps->totpoints > 0);
@@ -2993,7 +2859,6 @@ void BKE_gpencil_stroke_set_random_color(bGPDstroke *gps)
}
}
-/* Flip stroke. */
void BKE_gpencil_stroke_flip(bGPDstroke *gps)
{
/* Reverse points. */
@@ -3103,20 +2968,6 @@ static void gpencil_stroke_join_islands(bGPdata *gpd,
BKE_gpencil_free_stroke(gps_last);
}
-/* Split the given stroke into several new strokes, partitioning
- * it based on whether the stroke points have a particular flag
- * is set (e.g. "GP_SPOINT_SELECT" in most cases, but not always)
- *
- * The algorithm used here is as follows:
- * 1) We firstly identify the number of "islands" of non-tagged points
- * which will all end up being in new strokes.
- * - In the most extreme case (i.e. every other vert is a 1-vert island),
- * we have at most n / 2 islands
- * - Once we start having larger islands than that, the number required
- * becomes much less
- * 2) Each island gets converted to a new stroke
- * If the number of points is <= limit, the stroke is deleted
- */
bGPDstroke *BKE_gpencil_stroke_delete_tagged_points(bGPdata *gpd,
bGPDframe *gpf,
bGPDstroke *gps,
@@ -3126,6 +2977,16 @@ bGPDstroke *BKE_gpencil_stroke_delete_tagged_points(bGPdata *gpd,
const bool flat_cap,
const int limit)
{
+ /* The algorithm used here is as follows:
+ * 1) We firstly identify the number of "islands" of non-tagged points
+ * which will all end up being in new strokes.
+ * - In the most extreme case (i.e. every other vert is a 1-vert island),
+ * we have at most `n / 2` islands
+ * - Once we start having larger islands than that, the number required
+ * becomes much less
+ * 2) Each island gets converted to a new stroke
+ * If the number of points is <= limit, the stroke is deleted. */
+
tGPDeleteIsland *islands = (tGPDeleteIsland *)MEM_callocN(
sizeof(tGPDeleteIsland) * (gps->totpoints + 1) / 2, "gp_point_islands");
bool in_island = false;
@@ -3430,7 +3291,6 @@ static void gpencil_stroke_copy_point(bGPDstroke *gps,
}
}
-/* Join two strokes using the shortest distance (reorder stroke if necessary ) */
void BKE_gpencil_stroke_join(bGPDstroke *gps_a,
bGPDstroke *gps_b,
const bool leave_gaps,
@@ -3548,7 +3408,7 @@ void BKE_gpencil_stroke_join(bGPDstroke *gps_a,
for (i = start; i < end; i++) {
pt = &gps_a->points[i];
pt->pressure += (avg_pressure - pt->pressure) * ratio;
- BKE_gpencil_stroke_smooth_point(gps_a, i, ratio * 0.6f);
+ BKE_gpencil_stroke_smooth_point(gps_a, i, ratio * 0.6f, false);
ratio += step;
/* In the center, reverse the ratio. */
@@ -3560,7 +3420,6 @@ void BKE_gpencil_stroke_join(bGPDstroke *gps_a,
}
}
-/* Copy the stroke of the frame to all frames selected (except current). */
void BKE_gpencil_stroke_copy_to_keyframes(
bGPdata *gpd, bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps, const bool tail)
{
@@ -3599,7 +3458,11 @@ void BKE_gpencil_stroke_copy_to_keyframes(
BLI_ghash_free(frame_list, nullptr, nullptr);
}
-/* Stroke Uniform Subdivide ------------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Uniform Subdivide
+ * \{ */
struct tSamplePoint {
struct tSamplePoint *next, *prev;
@@ -3649,15 +3512,6 @@ static tSampleEdge *new_sample_edge_from_sample_points(tSamplePoint *from, tSamp
return new_edge;
}
-/**
- * Subdivide the grease pencil stroke so the number of points is target_number.
- * Does not change the shape of the stroke. The new points will be distributed as
- * uniformly as possible by repeatedly subdividing the current longest edge.
- *
- * \param gps: The stroke to be up-sampled.
- * \param target_number: The number of points the up-sampled stroke should have.
- * \param select: Select/Deselect the stroke.
- */
void BKE_gpencil_stroke_uniform_subdivide(bGPdata *gpd,
bGPDstroke *gps,
const uint32_t target_number,
@@ -3793,12 +3647,6 @@ void BKE_gpencil_stroke_uniform_subdivide(bGPdata *gpd,
BKE_gpencil_stroke_geometry_update(gpd, gps);
}
-/**
- * Stroke to view space
- * Transforms a stroke to view space. This allows for manipulations in 2D but also easy conversion
- * back to 3D.
- * NOTE: also takes care of parent space transform
- */
void BKE_gpencil_stroke_to_view_space(RegionView3D *rv3d,
bGPDstroke *gps,
const float diff_mat[4][4])
@@ -3812,12 +3660,6 @@ void BKE_gpencil_stroke_to_view_space(RegionView3D *rv3d,
}
}
-/**
- * Stroke from view space
- * Transforms a stroke from view space back to world space. Inverse of
- * BKE_gpencil_stroke_to_view_space
- * NOTE: also takes care of parent space transform
- */
void BKE_gpencil_stroke_from_view_space(RegionView3D *rv3d,
bGPDstroke *gps,
const float diff_mat[4][4])
@@ -3832,8 +3674,11 @@ void BKE_gpencil_stroke_from_view_space(RegionView3D *rv3d,
}
}
-/* ----------------------------------------------------------------------------- */
-/* Stroke to perimeter */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke to Perimeter
+ * \{ */
struct tPerimeterPoint {
struct tPerimeterPoint *next, *prev;
@@ -4238,12 +4083,6 @@ static ListBase *gpencil_stroke_perimeter_ex(const bGPdata *gpd,
return perimeter_list;
}
-/**
- * Calculates the perimeter of a stroke projected from the view and
- * returns it as a new stroke.
- * \param subdivisions: Number of subdivisions for the start and end caps
- * \return: bGPDstroke pointer to stroke perimeter
- */
bGPDstroke *BKE_gpencil_stroke_perimeter_from_view(struct RegionView3D *rv3d,
bGPdata *gpd,
const bGPDlayer *gpl,
@@ -4310,7 +4149,6 @@ bGPDstroke *BKE_gpencil_stroke_perimeter_from_view(struct RegionView3D *rv3d,
return perimeter_stroke;
}
-/** Get average pressure. */
float BKE_gpencil_stroke_average_pressure_get(bGPDstroke *gps)
{
@@ -4327,7 +4165,6 @@ float BKE_gpencil_stroke_average_pressure_get(bGPDstroke *gps)
return tot / (float)gps->totpoints;
}
-/** Check if the thickness of the stroke is constant. */
bool BKE_gpencil_stroke_is_pressure_constant(bGPDstroke *gps)
{
if (gps->totpoints == 1) {
@@ -4344,4 +4181,5 @@ bool BKE_gpencil_stroke_is_pressure_constant(bGPDstroke *gps)
return true;
}
+
/** \} */
diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier.c
index a6164340477..62604286b43 100644
--- a/source/blender/blenkernel/intern/gpencil_modifier.c
+++ b/source/blender/blenkernel/intern/gpencil_modifier.c
@@ -36,6 +36,7 @@
#include "DNA_armature_types.h"
#include "DNA_gpencil_modifier_types.h"
#include "DNA_gpencil_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
@@ -50,7 +51,9 @@
#include "BKE_lib_id.h"
#include "BKE_lib_query.h"
#include "BKE_material.h"
+#include "BKE_modifier.h"
#include "BKE_object.h"
+#include "BKE_shrinkwrap.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
@@ -77,43 +80,83 @@ static GpencilVirtualModifierData virtualModifierCommonData;
*/
/**
- * Init grease pencil lattice deform data.
+ * Init grease pencil cache deform data.
* \param ob: Grease pencil object
*/
-void BKE_gpencil_lattice_init(Object *ob)
+void BKE_gpencil_cache_data_init(Depsgraph *depsgraph, Object *ob)
{
LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) {
- if (md->type == eGpencilModifierType_Lattice) {
- LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md;
- Object *latob = NULL;
+ switch (md->type) {
+ case eGpencilModifierType_Lattice: {
+ LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md;
+ Object *latob = NULL;
+
+ latob = mmd->object;
+ if ((!latob) || (latob->type != OB_LATTICE)) {
+ return;
+ }
+ if (mmd->cache_data) {
+ BKE_lattice_deform_data_destroy(mmd->cache_data);
+ }
- latob = mmd->object;
- if ((!latob) || (latob->type != OB_LATTICE)) {
- return;
+ /* init deform data */
+ mmd->cache_data = BKE_lattice_deform_data_create(latob, ob);
+ break;
}
- if (mmd->cache_data) {
- BKE_lattice_deform_data_destroy(mmd->cache_data);
+ case eGpencilModifierType_Shrinkwrap: {
+ ShrinkwrapGpencilModifierData *mmd = (ShrinkwrapGpencilModifierData *)md;
+ ob = mmd->target;
+ if (!ob) {
+ return;
+ }
+ if (mmd->cache_data) {
+ BKE_shrinkwrap_free_tree(mmd->cache_data);
+ MEM_SAFE_FREE(mmd->cache_data);
+ }
+ Object *ob_target = DEG_get_evaluated_object(depsgraph, ob);
+ Mesh *target = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob_target, false);
+ mmd->cache_data = MEM_callocN(sizeof(ShrinkwrapTreeData), __func__);
+ if (BKE_shrinkwrap_init_tree(
+ mmd->cache_data, target, mmd->shrink_type, mmd->shrink_mode, false)) {
+ }
+ else {
+ MEM_SAFE_FREE(mmd->cache_data);
+ }
+ break;
}
- /* init deform data */
- mmd->cache_data = BKE_lattice_deform_data_create(latob, ob);
+ default:
+ break;
}
}
}
/**
- * Clear grease pencil lattice deform data.
+ * Clear grease pencil cache deform data.
* \param ob: Grease pencil object
*/
-void BKE_gpencil_lattice_clear(Object *ob)
+void BKE_gpencil_cache_data_clear(Object *ob)
{
LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) {
- if (md->type == eGpencilModifierType_Lattice) {
- LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md;
- if ((mmd) && (mmd->cache_data)) {
- BKE_lattice_deform_data_destroy(mmd->cache_data);
- mmd->cache_data = NULL;
+ switch (md->type) {
+ case eGpencilModifierType_Lattice: {
+ LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md;
+ if ((mmd) && (mmd->cache_data)) {
+ BKE_lattice_deform_data_destroy(mmd->cache_data);
+ mmd->cache_data = NULL;
+ }
+ break;
}
+ case eGpencilModifierType_Shrinkwrap: {
+ ShrinkwrapGpencilModifierData *mmd = (ShrinkwrapGpencilModifierData *)md;
+ if ((mmd) && (mmd->cache_data)) {
+ BKE_shrinkwrap_free_tree(mmd->cache_data);
+ MEM_SAFE_FREE(mmd->cache_data);
+ }
+ break;
+ }
+ default:
+ break;
}
}
}
@@ -121,8 +164,6 @@ void BKE_gpencil_lattice_clear(Object *ob)
/* *************************************************** */
/* Modifier Methods - Evaluation Loops, etc. */
-/* This is to include things that are not modifiers in the evaluation of the modifier stack, for
- * example parenting to an armature or lattice without having a real modifier. */
GpencilModifierData *BKE_gpencil_modifiers_get_virtual_modifierlist(
const Object *ob, GpencilVirtualModifierData *UNUSED(virtualModifierData))
{
@@ -150,11 +191,6 @@ GpencilModifierData *BKE_gpencil_modifiers_get_virtual_modifierlist(
return md;
}
-/**
- * Check if object has grease pencil Geometry modifiers.
- * \param ob: Grease pencil object
- * \return True if exist
- */
bool BKE_gpencil_has_geometry_modifiers(Object *ob)
{
LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) {
@@ -167,11 +203,6 @@ bool BKE_gpencil_has_geometry_modifiers(Object *ob)
return false;
}
-/**
- * Check if object has grease pencil Time modifiers.
- * \param ob: Grease pencil object
- * \return True if exist
- */
bool BKE_gpencil_has_time_modifiers(Object *ob)
{
LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) {
@@ -184,11 +215,6 @@ bool BKE_gpencil_has_time_modifiers(Object *ob)
return false;
}
-/**
- * Check if object has grease pencil transform stroke modifiers.
- * \param ob: Grease pencil object
- * \return True if exist
- */
bool BKE_gpencil_has_transform_modifiers(Object *ob)
{
LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) {
@@ -258,7 +284,6 @@ bool BKE_gpencil_is_first_lineart_in_stack(const Object *ob, const GpencilModifi
return false;
}
-/* Get Time modifier frame number. */
int BKE_gpencil_time_modifier_cfra(Depsgraph *depsgraph,
Scene *scene,
Object *ob,
@@ -292,11 +317,6 @@ int BKE_gpencil_time_modifier_cfra(Depsgraph *depsgraph,
return nfra;
}
-/**
- * Set current grease pencil active frame.
- * \param depsgraph: Current depsgraph
- * \param gpd: Grease pencil data-block.
- */
void BKE_gpencil_frame_active_set(Depsgraph *depsgraph, bGPdata *gpd)
{
DEG_debug_print_eval(depsgraph, __func__, gpd->id.name, gpd);
@@ -320,9 +340,6 @@ void BKE_gpencil_frame_active_set(Depsgraph *depsgraph, bGPdata *gpd)
}
}
-/**
- * Initialize grease pencil modifier.
- */
void BKE_gpencil_modifier_init(void)
{
/* Initialize modifier types */
@@ -346,11 +363,6 @@ void BKE_gpencil_modifier_init(void)
#endif
}
-/**
- * Create new grease pencil modifier.
- * \param type: Type of modifier
- * \return New modifier pointer
- */
GpencilModifierData *BKE_gpencil_modifier_new(int type)
{
const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(type);
@@ -386,11 +398,6 @@ static void modifier_free_data_id_us_cb(void *UNUSED(userData),
}
}
-/**
- * Free grease pencil modifier data
- * \param md: Modifier data
- * \param flag: Flags
- */
void BKE_gpencil_modifier_free_ex(GpencilModifierData *md, const int flag)
{
const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
@@ -411,16 +418,11 @@ void BKE_gpencil_modifier_free_ex(GpencilModifierData *md, const int flag)
MEM_freeN(md);
}
-/**
- * Free grease pencil modifier data
- * \param md: Modifier data
- */
void BKE_gpencil_modifier_free(GpencilModifierData *md)
{
BKE_gpencil_modifier_free_ex(md, 0);
}
-/* check unique name */
bool BKE_gpencil_modifier_unique_name(ListBase *modifiers, GpencilModifierData *gmd)
{
if (modifiers && gmd) {
@@ -435,11 +437,6 @@ bool BKE_gpencil_modifier_unique_name(ListBase *modifiers, GpencilModifierData *
return false;
}
-/**
- * Check if grease pencil modifier depends on time.
- * \param md: Modifier data
- * \return True if depends on time
- */
bool BKE_gpencil_modifier_depends_ontime(GpencilModifierData *md)
{
const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
@@ -447,11 +444,6 @@ bool BKE_gpencil_modifier_depends_ontime(GpencilModifierData *md)
return mti->dependsOnTime && mti->dependsOnTime(md);
}
-/**
- * Get grease pencil modifier information.
- * \param type: Type of modifier
- * \return Pointer to type
- */
const GpencilModifierTypeInfo *BKE_gpencil_modifier_get_info(GpencilModifierType type)
{
/* type unsigned, no need to check < 0 */
@@ -463,12 +455,6 @@ const GpencilModifierTypeInfo *BKE_gpencil_modifier_get_info(GpencilModifierType
return NULL;
}
-/**
- * Get the idname of the modifier type's panel, which was defined in the #panelRegister callback.
- *
- * \param type: Type of modifier
- * \param r_idname: ID name
- */
void BKE_gpencil_modifierType_panel_id(GpencilModifierType type, char *r_idname)
{
const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(type);
@@ -482,11 +468,6 @@ void BKE_gpencil_modifier_panel_expand(GpencilModifierData *md)
md->ui_expand_flag |= UI_PANEL_DATA_EXPAND_ROOT;
}
-/**
- * Generic grease pencil modifier copy data.
- * \param md_src: Source modifier data
- * \param md_dst: Target modifier data
- */
void BKE_gpencil_modifier_copydata_generic(const GpencilModifierData *md_src,
GpencilModifierData *md_dst)
{
@@ -516,12 +497,6 @@ static void gpencil_modifier_copy_data_id_us_cb(void *UNUSED(userData),
}
}
-/**
- * Copy grease pencil modifier data.
- * \param md: Source modifier data
- * \param target: Target modifier data
- * \param flag: Flags
- */
void BKE_gpencil_modifier_copydata_ex(GpencilModifierData *md,
GpencilModifierData *target,
const int flag)
@@ -543,11 +518,6 @@ void BKE_gpencil_modifier_copydata_ex(GpencilModifierData *md,
}
}
-/**
- * Copy grease pencil modifier data.
- * \param md: Source modifier data
- * \param target: Target modifier data
- */
void BKE_gpencil_modifier_copydata(GpencilModifierData *md, GpencilModifierData *target)
{
BKE_gpencil_modifier_copydata_ex(md, target, 0);
@@ -566,19 +536,14 @@ GpencilModifierData *BKE_gpencil_modifiers_findby_type(Object *ob, GpencilModifi
return md;
}
-/**
- * Set grease pencil modifier error.
- * \param md: Modifier data
- * \param _format: Format
- */
-void BKE_gpencil_modifier_set_error(GpencilModifierData *md, const char *_format, ...)
+void BKE_gpencil_modifier_set_error(GpencilModifierData *md, const char *format, ...)
{
char buffer[512];
va_list ap;
- const char *format = TIP_(_format);
+ const char *format_tip = TIP_(format);
- va_start(ap, _format);
- vsnprintf(buffer, sizeof(buffer), format, ap);
+ va_start(ap, format);
+ vsnprintf(buffer, sizeof(buffer), format_tip, ap);
va_end(ap);
buffer[sizeof(buffer) - 1] = '\0';
@@ -591,12 +556,6 @@ void BKE_gpencil_modifier_set_error(GpencilModifierData *md, const char *_format
CLOG_STR_ERROR(&LOG, md->error);
}
-/**
- * Check whether given modifier is not local (i.e. from linked data) when the object is a library
- * override.
- *
- * \param gmd: May be NULL, in which case we consider it as a non-local modifier case.
- */
bool BKE_gpencil_modifier_is_nonlocal_in_liboverride(const Object *ob,
const GpencilModifierData *gmd)
{
@@ -604,12 +563,6 @@ bool BKE_gpencil_modifier_is_nonlocal_in_liboverride(const Object *ob,
(gmd == NULL || (gmd->flag & eGpencilModifierFlag_OverrideLibrary_Local) == 0));
}
-/**
- * Link grease pencil modifier related IDs.
- * \param ob: Grease pencil object
- * \param walk: Walk option
- * \param userData: User data
- */
void BKE_gpencil_modifiers_foreach_ID_link(Object *ob, GreasePencilIDWalkFunc walk, void *userData)
{
GpencilModifierData *md = ob->greasepencil_modifiers.first;
@@ -623,12 +576,6 @@ void BKE_gpencil_modifiers_foreach_ID_link(Object *ob, GreasePencilIDWalkFunc wa
}
}
-/**
- * Link grease pencil modifier related Texts.
- * \param ob: Grease pencil object
- * \param walk: Walk option
- * \param userData: User data
- */
void BKE_gpencil_modifiers_foreach_tex_link(Object *ob,
GreasePencilTexWalkFunc walk,
void *userData)
@@ -644,12 +591,6 @@ void BKE_gpencil_modifiers_foreach_tex_link(Object *ob,
}
}
-/**
- * Find grease pencil modifier by name.
- * \param ob: Grease pencil object
- * \param name: Name to find
- * \return Pointer to modifier
- */
GpencilModifierData *BKE_gpencil_modifiers_findby_name(Object *ob, const char *name)
{
return BLI_findstring(&(ob->greasepencil_modifiers), name, offsetof(GpencilModifierData, name));
@@ -677,14 +618,6 @@ static int gpencil_remap_time_get(Depsgraph *depsgraph, Scene *scene, Object *ob
return remap_cfra;
}
-/**
- * Get the current frame re-timed with time modifiers.
- * \param depsgraph: Current depsgraph.
- * \param scene: Current scene
- * \param ob: Grease pencil object
- * \param gpl: Grease pencil layer
- * \return New frame number
- */
bGPDframe *BKE_gpencil_frame_retime_get(Depsgraph *depsgraph,
Scene *scene,
Object *ob,
@@ -753,12 +686,6 @@ static bGPdata *gpencil_copy_for_eval(bGPdata *gpd)
return result;
}
-/**
- * Prepare grease pencil eval data for modifiers
- * \param depsgraph: Current depsgraph
- * \param scene: Current scene
- * \param ob: Grease pencil object
- */
void BKE_gpencil_prepare_eval_data(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
bGPdata *gpd_eval = (bGPdata *)ob->data;
@@ -808,12 +735,6 @@ void BKE_gpencil_prepare_eval_data(Depsgraph *depsgraph, Scene *scene, Object *o
BKE_gpencil_update_orig_pointers(ob_orig, ob);
}
-/**
- * Calculate gpencil modifiers.
- * \param depsgraph: Current depsgraph
- * \param scene: Current scene
- * \param ob: Grease pencil object
- */
void BKE_gpencil_modifiers_calc(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
bGPdata *gpd = (bGPdata *)ob->data;
@@ -829,7 +750,7 @@ void BKE_gpencil_modifiers_calc(Depsgraph *depsgraph, Scene *scene, Object *ob)
}
/* Init general modifiers data. */
- BKE_gpencil_lattice_init(ob);
+ BKE_gpencil_cache_data_init(depsgraph, ob);
const bool time_remap = BKE_gpencil_has_time_modifiers(ob);
bool is_first_lineart = true;
@@ -872,8 +793,8 @@ void BKE_gpencil_modifiers_calc(Depsgraph *depsgraph, Scene *scene, Object *ob)
}
}
- /* Clear any lattice data. */
- BKE_gpencil_lattice_clear(ob);
+ /* Clear any cache data. */
+ BKE_gpencil_cache_data_clear(ob);
MOD_lineart_clear_cache(&gpd->runtime.lineart_cache);
}
@@ -1031,6 +952,10 @@ void BKE_gpencil_modifier_blend_read_data(BlendDataReader *reader, ListBase *lb)
gpmd->segments[i].dmd = gpmd;
}
}
+ if (md->type == eGpencilModifierType_Shrinkwrap) {
+ ShrinkwrapGpencilModifierData *gpmd = (ShrinkwrapGpencilModifierData *)md;
+ gpmd->cache_data = NULL;
+ }
}
}
diff --git a/source/blender/blenkernel/intern/hair.c b/source/blender/blenkernel/intern/hair.c
index 7433ee7ac29..f2a5146422e 100644
--- a/source/blender/blenkernel/intern/hair.c
+++ b/source/blender/blenkernel/intern/hair.c
@@ -80,7 +80,7 @@ static void hair_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, co
{
Hair *hair_dst = (Hair *)id_dst;
const Hair *hair_src = (const Hair *)id_src;
- hair_dst->mat = MEM_dupallocN(hair_dst->mat);
+ hair_dst->mat = MEM_dupallocN(hair_src->mat);
const eCDAllocType alloc_type = (flag & LIB_ID_COPY_CD_REFERENCE) ? CD_REFERENCE : CD_DUPLICATE;
CustomData_copy(&hair_src->pdata, &hair_dst->pdata, CD_MASK_ALL, alloc_type, hair_dst->totpoint);
@@ -182,6 +182,7 @@ IDTypeInfo IDType_ID_HA = {
.name_plural = "hairs",
.translation_context = BLT_I18NCONTEXT_ID_HAIR,
.flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = hair_init_data,
.copy_data = hair_copy_data,
@@ -189,6 +190,7 @@ IDTypeInfo IDType_ID_HA = {
.make_local = NULL,
.foreach_id = hair_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = hair_blend_write,
@@ -406,6 +408,7 @@ void BKE_hair_data_update(struct Depsgraph *depsgraph, struct Scene *scene, Obje
}
/* Draw Cache */
+
void (*BKE_hair_batch_cache_dirty_tag_cb)(Hair *hair, int mode) = NULL;
void (*BKE_hair_batch_cache_free_cb)(Hair *hair) = NULL;
diff --git a/source/blender/blenkernel/intern/icons.cc b/source/blender/blenkernel/intern/icons.cc
index ffc39028400..059caaa27f9 100644
--- a/source/blender/blenkernel/intern/icons.cc
+++ b/source/blender/blenkernel/intern/icons.cc
@@ -210,7 +210,7 @@ void BKE_icons_init(int first_dyn_id)
}
}
-void BKE_icons_free(void)
+void BKE_icons_free()
{
BLI_assert(BLI_thread_is_main());
@@ -227,7 +227,7 @@ void BKE_icons_free(void)
BLI_linklist_lockfree_free(&g_icon_delete_queue, MEM_freeN);
}
-void BKE_icons_deferred_free(void)
+void BKE_icons_deferred_free()
{
std::scoped_lock lock(gIconMutex);
@@ -251,7 +251,7 @@ static PreviewImage *previewimg_create_ex(size_t deferred_data_size)
}
for (int i = 0; i < NUM_ICON_SIZES; i++) {
- prv_img->flag[i] |= (PRV_CHANGED | PRV_UNFINISHED);
+ prv_img->flag[i] |= PRV_CHANGED;
prv_img->changed_timestamp[i] = 0;
}
return prv_img;
@@ -271,7 +271,7 @@ static PreviewImage *previewimg_deferred_create(const char *path, int source)
return prv;
}
-PreviewImage *BKE_previewimg_create(void)
+PreviewImage *BKE_previewimg_create()
{
return previewimg_create_ex(0);
}
@@ -308,7 +308,7 @@ void BKE_previewimg_clear_single(struct PreviewImage *prv, enum eIconSizes size)
GPU_texture_free(prv->gputexture[size]);
}
prv->h[size] = prv->w[size] = 0;
- prv->flag[size] |= (PRV_CHANGED | PRV_UNFINISHED);
+ prv->flag[size] |= PRV_CHANGED;
prv->flag[size] &= ~PRV_USER_EDITED;
prv->changed_timestamp[size] = 0;
}
@@ -336,10 +336,6 @@ PreviewImage *BKE_previewimg_copy(const PreviewImage *prv)
return prv_img;
}
-/**
- * Duplicate preview image from \a id and clear icon_id,
- * to be used by datablock copy functions.
- */
void BKE_previewimg_id_copy(ID *new_id, const ID *old_id)
{
PreviewImage **old_prv_p = BKE_previewimg_id_get_p(old_id);
@@ -360,31 +356,23 @@ void BKE_previewimg_id_copy(ID *new_id, const ID *old_id)
PreviewImage **BKE_previewimg_id_get_p(const ID *id)
{
switch (GS(id->name)) {
- case ID_OB: {
- Object *ob = (Object *)id;
- /* Currently, only object types with real geometry can be rendered as preview. */
- if (!OB_TYPE_IS_GEOMETRY(ob->type)) {
- return nullptr;
- }
- return &ob->preview;
- }
-
#define ID_PRV_CASE(id_code, id_struct) \
case id_code: { \
return &((id_struct *)id)->preview; \
} \
((void)0)
- ID_PRV_CASE(ID_MA, Material);
- ID_PRV_CASE(ID_TE, Tex);
- ID_PRV_CASE(ID_WO, World);
- ID_PRV_CASE(ID_LA, Light);
- ID_PRV_CASE(ID_IM, Image);
- ID_PRV_CASE(ID_BR, Brush);
- ID_PRV_CASE(ID_GR, Collection);
- ID_PRV_CASE(ID_SCE, Scene);
- ID_PRV_CASE(ID_SCR, bScreen);
- ID_PRV_CASE(ID_AC, bAction);
- ID_PRV_CASE(ID_NT, bNodeTree);
+ ID_PRV_CASE(ID_OB, Object);
+ ID_PRV_CASE(ID_MA, Material);
+ ID_PRV_CASE(ID_TE, Tex);
+ ID_PRV_CASE(ID_WO, World);
+ ID_PRV_CASE(ID_LA, Light);
+ ID_PRV_CASE(ID_IM, Image);
+ ID_PRV_CASE(ID_BR, Brush);
+ ID_PRV_CASE(ID_GR, Collection);
+ ID_PRV_CASE(ID_SCE, Scene);
+ ID_PRV_CASE(ID_SCR, bScreen);
+ ID_PRV_CASE(ID_AC, bAction);
+ ID_PRV_CASE(ID_NT, bNodeTree);
#undef ID_PRV_CASE
default:
break;
@@ -468,9 +456,6 @@ PreviewImage *BKE_previewimg_cached_get(const char *name)
return (PreviewImage *)BLI_ghash_lookup(gCachedPreviews, name);
}
-/**
- * Generate an empty PreviewImage, if not yet existing.
- */
PreviewImage *BKE_previewimg_cached_ensure(const char *name)
{
BLI_assert(BLI_thread_is_main());
@@ -488,10 +473,6 @@ PreviewImage *BKE_previewimg_cached_ensure(const char *name)
return prv;
}
-/**
- * Generate a PreviewImage from given file path, using thumbnails management, if not yet existing.
- * Does not actually generate the preview, #BKE_previewimg_ensure() must be called for that.
- */
PreviewImage *BKE_previewimg_cached_thumbnail_read(const char *name,
const char *path,
const int source,
@@ -546,10 +527,6 @@ void BKE_previewimg_cached_release(const char *name)
BKE_previewimg_deferred_release(prv);
}
-/**
- * Handle deferred (lazy) loading/generation of preview image, if needed.
- * For now, only used with file thumbnails.
- */
void BKE_previewimg_ensure(PreviewImage *prv, const int size)
{
if ((prv->tag & PRV_TAG_DEFFERED) != 0) {
@@ -573,7 +550,7 @@ void BKE_previewimg_ensure(PreviewImage *prv, const int size)
prv->w[ICON_SIZE_PREVIEW] = thumb->x;
prv->h[ICON_SIZE_PREVIEW] = thumb->y;
prv->rect[ICON_SIZE_PREVIEW] = (uint *)MEM_dupallocN(thumb->rect);
- prv->flag[ICON_SIZE_PREVIEW] &= ~(PRV_CHANGED | PRV_USER_EDITED | PRV_UNFINISHED);
+ prv->flag[ICON_SIZE_PREVIEW] &= ~(PRV_CHANGED | PRV_USER_EDITED | PRV_RENDERING);
}
if (do_icon) {
if (thumb->x > thumb->y) {
@@ -592,7 +569,7 @@ void BKE_previewimg_ensure(PreviewImage *prv, const int size)
prv->w[ICON_SIZE_ICON] = icon_w;
prv->h[ICON_SIZE_ICON] = icon_h;
prv->rect[ICON_SIZE_ICON] = (uint *)MEM_dupallocN(thumb->rect);
- prv->flag[ICON_SIZE_ICON] &= ~(PRV_CHANGED | PRV_USER_EDITED | PRV_UNFINISHED);
+ prv->flag[ICON_SIZE_ICON] &= ~(PRV_CHANGED | PRV_USER_EDITED | PRV_RENDERING);
}
IMB_freeImBuf(thumb);
}
@@ -600,10 +577,6 @@ void BKE_previewimg_ensure(PreviewImage *prv, const int size)
}
}
-/**
- * Create an #ImBuf holding a copy of the preview image buffer in \a prv.
- * \note The returned image buffer has to be free'd (#IMB_freeImBuf()).
- */
ImBuf *BKE_previewimg_to_imbuf(PreviewImage *prv, const int size)
{
const unsigned int w = prv->w[size];
@@ -624,12 +597,12 @@ ImBuf *BKE_previewimg_to_imbuf(PreviewImage *prv, const int size)
void BKE_previewimg_finish(PreviewImage *prv, const int size)
{
/* Previews may be calculated on a thread. */
- atomic_fetch_and_and_int16(&prv->flag[size], ~PRV_UNFINISHED);
+ atomic_fetch_and_and_int16(&prv->flag[size], ~PRV_RENDERING);
}
bool BKE_previewimg_is_finished(const PreviewImage *prv, const int size)
{
- return (prv->flag[size] & PRV_UNFINISHED) == 0;
+ return (prv->flag[size] & PRV_RENDERING) == 0;
}
void BKE_previewimg_blend_write(BlendWriter *writer, const PreviewImage *prv)
@@ -663,16 +636,11 @@ void BKE_previewimg_blend_read(BlendDataReader *reader, PreviewImage *prv)
BLO_read_data_address(reader, &prv->rect[i]);
}
prv->gputexture[i] = nullptr;
- /* For now consider previews read from file as finished to not confuse File Browser preview
- * loading. That could be smarter and check if there's a preview job running instead.
- * If the preview is tagged as changed, it needs to be updated anyway, so don't remove the tag.
- */
- if ((prv->flag[i] & PRV_CHANGED) == 0) {
- BKE_previewimg_finish(prv, i);
- }
- else {
- /* Only for old files that didn't write the flag. */
- prv->flag[i] |= PRV_UNFINISHED;
+
+ /* PRV_RENDERING is a runtime only flag currently, but don't mess with it on undo! It gets
+ * special handling in #memfile_undosys_restart_unfinished_id_previews() then. */
+ if (!BLO_read_data_is_undo(reader)) {
+ prv->flag[i] &= ~PRV_RENDERING;
}
}
prv->icon_id = 0;
@@ -702,7 +670,7 @@ void BKE_icon_changed(const int icon_id)
/* If we have previews, they all are now invalid changed. */
if (p_prv && *p_prv) {
for (int i = 0; i < NUM_ICON_SIZES; i++) {
- (*p_prv)->flag[i] |= (PRV_CHANGED | PRV_UNFINISHED);
+ (*p_prv)->flag[i] |= PRV_CHANGED;
(*p_prv)->changed_timestamp[i]++;
}
}
@@ -809,9 +777,6 @@ int BKE_icon_gplayer_color_ensure(bGPDlayer *gpl)
return icon_gplayer_color_ensure_create_icon(gpl);
}
-/**
- * Return icon id of given preview, or create new icon if not found.
- */
int BKE_icon_preview_ensure(ID *id, PreviewImage *preview)
{
if (!preview || G.background) {
@@ -852,11 +817,6 @@ int BKE_icon_preview_ensure(ID *id, PreviewImage *preview)
return preview->icon_id;
}
-/**
- * Create an icon as owner or \a ibuf. The icon-ID is not stored in \a ibuf, it needs to be stored
- * separately.
- * \note Transforms ownership of \a ibuf to the newly created icon.
- */
int BKE_icon_imbuf_create(ImBuf *ibuf)
{
int icon_id = get_next_free_id();
@@ -938,9 +898,6 @@ void BKE_icon_id_delete(struct ID *id)
BLI_ghash_remove(gIcons, POINTER_FROM_INT(icon_id), nullptr, icon_free);
}
-/**
- * Remove icon and free data.
- */
bool BKE_icon_delete(const int icon_id)
{
if (icon_id == 0) {
@@ -1065,4 +1022,5 @@ int BKE_icon_ensure_studio_light(struct StudioLight *sl, int id_type)
icon->id_type = id_type;
return icon_id;
}
+
/** \} */
diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c
index f7411f541b7..bb6458331da 100644
--- a/source/blender/blenkernel/intern/idprop.c
+++ b/source/blender/blenkernel/intern/idprop.c
@@ -76,10 +76,6 @@ static size_t idp_size_table[] = {
/* --------- property array type -------------*/
-/**
- * \note as a start to move away from the stupid IDP_New function, this type
- * has its own allocation function.
- */
IDProperty *IDP_NewIDPArray(const char *name)
{
IDProperty *prop = MEM_callocN(sizeof(IDProperty), "IDProperty prop array");
@@ -127,7 +123,6 @@ static void IDP_FreeIDPArray(IDProperty *prop, const bool do_id_user)
}
}
-/* shallow copies item */
void IDP_SetIndexArray(IDProperty *prop, int index, IDProperty *item)
{
BLI_assert(prop->type == IDP_IDPARRAY);
@@ -229,7 +224,6 @@ static void idp_resize_group_array(IDProperty *prop, int newlen, void *newarr)
}
}
-/* This function works for strings too! */
void IDP_ResizeArray(IDProperty *prop, int newlen)
{
const bool is_grow = newlen >= prop->len;
@@ -351,19 +345,13 @@ static IDProperty *IDP_CopyArray(const IDProperty *prop, const int flag)
return newp;
}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name String Functions (IDProperty String API)
* \{ */
-/**
- *
- * \param st: The string to assign.
- * \param name: The property name.
- * \param maxlen: The size of the new string (including the \0 terminator).
- * \return The new string property.
- */
IDProperty *IDP_NewString(const char *st, const char *name, int maxlen)
{
IDProperty *prop = MEM_callocN(sizeof(IDProperty), "IDProperty string");
@@ -457,6 +445,7 @@ void IDP_FreeString(IDProperty *prop)
MEM_freeN(prop->data.pointer);
}
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -514,8 +503,6 @@ static IDProperty *IDP_CopyGroup(const IDProperty *prop, const int flag)
return newp;
}
-/* use for syncing proxies.
- * When values name and types match, copy the values, else ignore */
void IDP_SyncGroupValues(IDProperty *dest, const IDProperty *src)
{
BLI_assert(dest->type == IDP_GROUP);
@@ -565,9 +552,6 @@ void IDP_SyncGroupTypes(IDProperty *dest, const IDProperty *src, const bool do_a
}
}
-/**
- * Replaces all properties with the same name in a destination group from a source group.
- */
void IDP_ReplaceGroupInGroup(IDProperty *dest, const IDProperty *src)
{
BLI_assert(dest->type == IDP_GROUP);
@@ -592,10 +576,6 @@ void IDP_ReplaceGroupInGroup(IDProperty *dest, const IDProperty *src)
}
}
-/**
- * Checks if a property with the same name as prop exists, and if so replaces it.
- * Use this to preserve order!
- */
void IDP_ReplaceInGroup_ex(IDProperty *group, IDProperty *prop, IDProperty *prop_exist)
{
BLI_assert(group->type == IDP_GROUP);
@@ -618,10 +598,6 @@ void IDP_ReplaceInGroup(IDProperty *group, IDProperty *prop)
IDP_ReplaceInGroup_ex(group, prop, prop_exist);
}
-/**
- * If a property is missing in \a dest, add it.
- * Do it recursively.
- */
void IDP_MergeGroup_ex(IDProperty *dest,
const IDProperty *src,
const bool do_overwrite,
@@ -663,25 +639,11 @@ void IDP_MergeGroup_ex(IDProperty *dest,
}
}
-/**
- * If a property is missing in \a dest, add it.
- * Do it recursively.
- */
void IDP_MergeGroup(IDProperty *dest, const IDProperty *src, const bool do_overwrite)
{
IDP_MergeGroup_ex(dest, src, do_overwrite, 0);
}
-/**
- * This function has a sanity check to make sure ID properties with the same name don't
- * get added to the group.
- *
- * The sanity check just means the property is not added to the group if another property
- * exists with the same name; the client code using ID properties then needs to detect this
- * (the function that adds new properties to groups, #IDP_AddToGroup,
- * returns false if a property can't be added to the group, and true if it can)
- * and free the property.
- */
bool IDP_AddToGroup(IDProperty *group, IDProperty *prop)
{
BLI_assert(group->type == IDP_GROUP);
@@ -695,10 +657,6 @@ bool IDP_AddToGroup(IDProperty *group, IDProperty *prop)
return false;
}
-/**
- * This is the same as IDP_AddToGroup, only you pass an item
- * in the group list to be inserted after.
- */
bool IDP_InsertToGroup(IDProperty *group, IDProperty *previous, IDProperty *pnew)
{
BLI_assert(group->type == IDP_GROUP);
@@ -712,12 +670,6 @@ bool IDP_InsertToGroup(IDProperty *group, IDProperty *previous, IDProperty *pnew
return false;
}
-/**
- * \note this does not free the property!!
- *
- * To free the property, you have to do:
- * IDP_FreeProperty(prop);
- */
void IDP_RemoveFromGroup(IDProperty *group, IDProperty *prop)
{
BLI_assert(group->type == IDP_GROUP);
@@ -727,9 +679,6 @@ void IDP_RemoveFromGroup(IDProperty *group, IDProperty *prop)
BLI_remlink(&group->data.group, prop);
}
-/**
- * Removes the property from the group and frees it.
- */
void IDP_FreeFromGroup(IDProperty *group, IDProperty *prop)
{
IDP_RemoveFromGroup(group, prop);
@@ -742,7 +691,6 @@ IDProperty *IDP_GetPropertyFromGroup(const IDProperty *prop, const char *name)
return (IDProperty *)BLI_findstring(&prop->data.group, name, offsetof(IDProperty, name));
}
-/** same as above but ensure type match */
IDProperty *IDP_GetPropertyTypeFromGroup(const IDProperty *prop, const char *name, const char type)
{
IDProperty *idprop = IDP_GetPropertyFromGroup(prop, name);
@@ -762,16 +710,13 @@ static void IDP_FreeGroup(IDProperty *prop, const bool do_id_user)
}
BLI_freelistN(&prop->data.group);
}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name Main Functions (IDProperty Main API)
* \{ */
-/**
- * Return an int from an IDProperty with a compatible type. This should be avoided, but
- * it's sometimes necessary, for example when legacy files have incorrect property types.
- */
int IDP_coerce_to_int_or_zero(const IDProperty *prop)
{
switch (prop->type) {
@@ -786,10 +731,6 @@ int IDP_coerce_to_int_or_zero(const IDProperty *prop)
}
}
-/**
- * Return a double from an IDProperty with a compatible type. This should be avoided, but
- * it's sometimes necessary, for example when legacy files have incorrect property types.
- */
double IDP_coerce_to_double_or_zero(const IDProperty *prop)
{
switch (prop->type) {
@@ -804,10 +745,6 @@ double IDP_coerce_to_double_or_zero(const IDProperty *prop)
}
}
-/**
- * Return a float from an IDProperty with a compatible type. This should be avoided, but
- * it's sometimes necessary, for example when legacy files have incorrect property types.
- */
float IDP_coerce_to_float_or_zero(const IDProperty *prop)
{
switch (prop->type) {
@@ -845,10 +782,6 @@ IDProperty *IDP_CopyProperty(const IDProperty *prop)
return IDP_CopyProperty_ex(prop, 0);
}
-/**
- * Copy content from source IDProperty into destination one, freeing destination property's content
- * first.
- */
void IDP_CopyPropertyContent(IDProperty *dst, IDProperty *src)
{
IDProperty *idprop_tmp = IDP_CopyProperty(src);
@@ -858,11 +791,6 @@ void IDP_CopyPropertyContent(IDProperty *dst, IDProperty *src)
IDP_FreeProperty(idprop_tmp);
}
-/**
- * Get the Group property that contains the id properties for ID id. Set create_if_needed
- * to create the Group property and attach it to id if it doesn't exist; otherwise
- * the function will return NULL if there's no Group property attached to the ID.
- */
IDProperty *IDP_GetProperties(ID *id, const bool create_if_needed)
{
if (id->properties) {
@@ -880,8 +808,6 @@ IDProperty *IDP_GetProperties(ID *id, const bool create_if_needed)
return id->properties;
}
-/**
- * \param is_strict: When false treat missing items as a match */
bool IDP_EqualsProperties_ex(IDProperty *prop1, IDProperty *prop2, const bool is_strict)
{
if (prop1 == NULL && prop2 == NULL) {
@@ -974,33 +900,6 @@ bool IDP_EqualsProperties(IDProperty *prop1, IDProperty *prop2)
return IDP_EqualsProperties_ex(prop1, prop2, true);
}
-/**
- * Allocate a new ID.
- *
- * This function takes three arguments: the ID property type, a union which defines
- * its initial value, and a name.
- *
- * The union is simple to use; see the top of BKE_idprop.h for its definition.
- * An example of using this function:
- *
- * \code{.c}
- * IDPropertyTemplate val;
- * IDProperty *group, *idgroup, *color;
- * group = IDP_New(IDP_GROUP, val, "group1"); // groups don't need a template.
- *
- * val.array.len = 4
- * val.array.type = IDP_FLOAT;
- * color = IDP_New(IDP_ARRAY, val, "color1");
- *
- * idgroup = IDP_GetProperties(some_id, 1);
- * IDP_AddToGroup(idgroup, color);
- * IDP_AddToGroup(idgroup, group);
- * \endcode
- *
- * Note that you MUST either attach the id property to an id property group with
- * IDP_AddToGroup or MEM_freeN the property, doing anything else might result in
- * a memory leak.
- */
IDProperty *IDP_New(const char type, const IDPropertyTemplate *val, const char *name)
{
IDProperty *prop = NULL;
@@ -1096,11 +995,6 @@ IDProperty *IDP_New(const char type, const IDPropertyTemplate *val, const char *
return prop;
}
-/**
- * Free allocated pointers in the UI data that isn't shared with the UI data in the #other
- * argument. Useful for returning early on failure when updating UI data in place, or when
- * replacing a subset of the UI data's allocated pointers.
- */
void IDP_ui_data_free_unique_contents(IDPropertyUIData *ui_data,
const eIDPropertyUIDataType type,
const IDPropertyUIData *other)
@@ -1175,10 +1069,6 @@ void IDP_ui_data_free(IDProperty *prop)
prop->ui_data = NULL;
}
-/**
- * \note This will free allocated data, all child properties of arrays and groups, and unlink IDs!
- * But it does not free the actual IDProperty struct itself.
- */
void IDP_FreePropertyContent_ex(IDProperty *prop, const bool do_id_user)
{
switch (prop->type) {
@@ -1241,14 +1131,6 @@ 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,
diff --git a/source/blender/blenkernel/intern/idtype.c b/source/blender/blenkernel/intern/idtype.c
index d9dc68b1a4f..e6fd6c14d42 100644
--- a/source/blender/blenkernel/intern/idtype.c
+++ b/source/blender/blenkernel/intern/idtype.c
@@ -158,13 +158,6 @@ static const IDTypeInfo *idtype_get_info_from_name(const char *idtype_name)
/* Various helpers/wrappers around #IDTypeInfo structure. */
-/**
- * Convert an \a idcode into a name.
- *
- * \param idcode: The code to convert.
- * \return A static string representing the name of
- * the code.
- */
const char *BKE_idtype_idcode_to_name(const short idcode)
{
const IDTypeInfo *id_type = BKE_idtype_get_info_from_idcode(idcode);
@@ -172,13 +165,6 @@ const char *BKE_idtype_idcode_to_name(const short idcode)
return id_type != NULL ? id_type->name : NULL;
}
-/**
- * Convert an \a idcode into a name (plural).
- *
- * \param idcode: The code to convert.
- * \return A static string representing the name of
- * the code.
- */
const char *BKE_idtype_idcode_to_name_plural(const short idcode)
{
const IDTypeInfo *id_type = BKE_idtype_get_info_from_idcode(idcode);
@@ -186,12 +172,6 @@ const char *BKE_idtype_idcode_to_name_plural(const short idcode)
return id_type != NULL ? id_type->name_plural : NULL;
}
-/**
- * Convert an \a idcode into its translations' context.
- *
- * \param idcode: The code to convert.
- * \return A static string representing the i18n context of the code.
- */
const char *BKE_idtype_idcode_to_translation_context(const short idcode)
{
const IDTypeInfo *id_type = BKE_idtype_get_info_from_idcode(idcode);
@@ -199,12 +179,6 @@ const char *BKE_idtype_idcode_to_translation_context(const short idcode)
return id_type != NULL ? id_type->translation_context : BLT_I18NCONTEXT_DEFAULT;
}
-/**
- * Convert an ID-type name into an \a idcode (ie. #ID_SCE)
- *
- * \param idtype_name: The ID-type's "user visible name" to convert.
- * \return The \a idcode for the name, or 0 if invalid.
- */
short BKE_idtype_idcode_from_name(const char *idtype_name)
{
const IDTypeInfo *id_type = idtype_get_info_from_name(idtype_name);
@@ -212,23 +186,11 @@ short BKE_idtype_idcode_from_name(const char *idtype_name)
return id_type != NULL ? id_type->id_code : 0;
}
-/**
- * Return if the ID code is a valid ID code.
- *
- * \param idcode: The code to check.
- * \return Boolean, 0 when invalid.
- */
bool BKE_idtype_idcode_is_valid(const short idcode)
{
return BKE_idtype_get_info_from_idcode(idcode) != NULL ? true : false;
}
-/**
- * Check if an ID type is linkable.
- *
- * \param idcode: The IDType code to check.
- * \return Boolean, false when non linkable, true otherwise.
- */
bool BKE_idtype_idcode_is_linkable(const short idcode)
{
const IDTypeInfo *id_type = BKE_idtype_get_info_from_idcode(idcode);
@@ -236,12 +198,6 @@ bool BKE_idtype_idcode_is_linkable(const short idcode)
return id_type != NULL ? (id_type->flags & IDTYPE_FLAGS_NO_LIBLINKING) == 0 : false;
}
-/**
- * Check if an ID type is only appendable.
- *
- * \param idcode: The IDType code to check.
- * \return Boolean, false when also linkable, true when only appendable.
- */
bool BKE_idtype_idcode_is_only_appendable(const short idcode)
{
const IDTypeInfo *id_type = BKE_idtype_get_info_from_idcode(idcode);
@@ -254,12 +210,6 @@ bool BKE_idtype_idcode_is_only_appendable(const short idcode)
return false;
}
-/**
- * Check if an ID type can try to reuse and existing matching local one when being appended again.
- *
- * \param idcode: The IDType code to check.
- * \return Boolean, false when it cannot be re-used, true otherwise.
- */
bool BKE_idtype_idcode_append_is_reusable(const short idcode)
{
const IDTypeInfo *id_type = BKE_idtype_get_info_from_idcode(idcode);
@@ -272,9 +222,6 @@ bool BKE_idtype_idcode_append_is_reusable(const short idcode)
return false;
}
-/**
- * Convert an \a idcode into an \a idfilter (e.g. ID_OB -> FILTER_ID_OB).
- */
uint64_t BKE_idtype_idcode_to_idfilter(const short idcode)
{
#define CASE_IDFILTER(_id) \
@@ -324,9 +271,6 @@ uint64_t BKE_idtype_idcode_to_idfilter(const short idcode)
#undef CASE_IDFILTER
}
-/**
- * Convert an \a idfilter into an \a idcode (e.g. #FILTER_ID_OB -> #ID_OB).
- */
short BKE_idtype_idcode_from_idfilter(const uint64_t idfilter)
{
#define CASE_IDFILTER(_id) \
@@ -375,9 +319,6 @@ short BKE_idtype_idcode_from_idfilter(const uint64_t idfilter)
#undef CASE_IDFILTER
}
-/**
- * Convert an \a idcode into an index (e.g. #ID_OB -> #INDEX_ID_OB).
- */
int BKE_idtype_idcode_to_index(const short idcode)
{
#define CASE_IDINDEX(_id) \
@@ -437,9 +378,6 @@ int BKE_idtype_idcode_to_index(const short idcode)
#undef CASE_IDINDEX
}
-/**
- * Get an \a idcode from an index (e.g. #INDEX_ID_OB -> #ID_OB).
- */
short BKE_idtype_idcode_from_index(const int index)
{
#define CASE_IDCODE(_id) \
@@ -499,20 +437,11 @@ short BKE_idtype_idcode_from_index(const int index)
#undef CASE_IDCODE
}
-/**
- * Return an ID code and steps the index forward 1.
- *
- * \param index: start as 0.
- * \return the code, 0 when all codes have been returned.
- */
short BKE_idtype_idcode_iter_step(int *index)
{
return (*index < ARRAY_SIZE(id_types)) ? BKE_idtype_idcode_from_index((*index)++) : 0;
}
-/**
- * Wrapper around #IDTypeInfo foreach_cache that also handles embedded IDs.
- */
void BKE_idtype_id_foreach_cache(struct ID *id,
IDTypeForeachCacheFunctionCallback function_callback,
void *user_data)
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index c0efc246567..f43cf00a310 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -75,6 +75,7 @@
#include "BLT_translation.h"
+#include "BKE_bpath.h"
#include "BKE_colortools.h"
#include "BKE_global.h"
#include "BKE_icons.h"
@@ -252,6 +253,34 @@ static void image_foreach_cache(ID *id,
}
}
+static void image_foreach_path(ID *id, BPathForeachPathData *bpath_data)
+{
+ Image *ima = (Image *)id;
+ const eBPathForeachFlag flag = bpath_data->flag;
+
+ if (BKE_image_has_packedfile(ima) && (flag & BKE_BPATH_FOREACH_PATH_SKIP_PACKED) != 0) {
+ return;
+ }
+ /* Skip empty file paths, these are typically from generated images and
+ * don't make sense to add directories to until the image has been saved
+ * once to give it a meaningful value. */
+ /* TODO re-assess whether this behavior is desired in the new generic code context. */
+ if (!ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE, IMA_SRC_TILED) ||
+ ima->filepath[0] == '\0') {
+ return;
+ }
+
+ if (BKE_bpath_foreach_path_fixed_process(bpath_data, ima->filepath)) {
+ if (flag & BKE_BPATH_FOREACH_PATH_RELOAD_EDITED) {
+ if (!BKE_image_has_packedfile(ima) &&
+ /* Image may have been painted onto (and not saved, T44543). */
+ !BKE_image_is_dirty(ima)) {
+ BKE_image_signal(bpath_data->bmain, ima, NULL, IMA_SIGNAL_RELOAD);
+ }
+ }
+ }
+}
+
static void image_blend_write(BlendWriter *writer, ID *id, const void *id_address)
{
Image *ima = (Image *)id;
@@ -369,6 +398,7 @@ IDTypeInfo IDType_ID_IM = {
.name_plural = "images",
.translation_context = BLT_I18NCONTEXT_ID_IMAGE,
.flags = IDTYPE_FLAGS_NO_ANIMDATA | IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = image_init_data,
.copy_data = image_copy_data,
@@ -376,6 +406,7 @@ IDTypeInfo IDType_ID_IM = {
.make_local = NULL,
.foreach_id = NULL,
.foreach_cache = image_foreach_cache,
+ .foreach_path = image_foreach_path,
.owner_get = NULL,
.blend_write = image_blend_write,
@@ -518,10 +549,6 @@ static void image_free_anims(Image *ima)
}
}
-/**
- * Simply free the image data from memory,
- * on display the image can load again (except for render buffers).
- */
void BKE_image_free_buffers_ex(Image *ima, bool do_lock)
{
if (do_lock) {
@@ -548,7 +575,6 @@ void BKE_image_free_buffers(Image *ima)
BKE_image_free_buffers_ex(ima, false);
}
-/** Free (or release) any data used by this image (does not free the image itself). */
void BKE_image_free_data(Image *ima)
{
image_free_data(&ima->id);
@@ -675,9 +701,11 @@ void BKE_image_merge(Main *bmain, Image *dest, Image *source)
}
}
-/* NOTE: We could be clever and scale all imbuf's but since some are mipmaps its not so simple. */
bool BKE_image_scale(Image *image, int width, int height)
{
+ /* NOTE: We could be clever and scale all imbuf's
+ * but since some are mipmaps its not so simple. */
+
ImBuf *ibuf;
void *lock;
@@ -776,9 +804,6 @@ int BKE_image_get_tile_from_pos(struct Image *ima,
return tile_number;
}
-/**
- * Return the tile_number for the closest UDIM tile.
- */
int BKE_image_find_nearest_tile(const Image *image, const float co[2])
{
const float co_floor[2] = {floorf(co[0]), floorf(co[1])};
@@ -877,17 +902,13 @@ Image *BKE_image_load(Main *bmain, const char *filepath)
return ima;
}
-/* checks if image was already loaded, then returns same image */
-/* otherwise creates new. */
-/* does not load ibuf itself */
-/* pass on optional frame for #name images */
Image *BKE_image_load_exists_ex(Main *bmain, const char *filepath, bool *r_exists)
{
Image *ima;
char str[FILE_MAX], strtest[FILE_MAX];
STRNCPY(str, filepath);
- BLI_path_abs(str, bmain->name);
+ BLI_path_abs(str, bmain->filepath);
/* first search an identical filepath */
for (ima = bmain->images.first; ima; ima = ima->id.next) {
@@ -1027,7 +1048,6 @@ static ImBuf *add_ibuf_size(unsigned int width,
return ibuf;
}
-/* adds new image block, creates ImBuf and initializes color */
Image *BKE_image_add_generated(Main *bmain,
unsigned int width,
unsigned int height,
@@ -1088,11 +1108,6 @@ Image *BKE_image_add_generated(Main *bmain,
return ima;
}
-/**
- * Create an image from ibuf. The refcount of ibuf is increased,
- * caller should take care to drop its reference by calling
- * #IMB_freeImBuf if needed.
- */
Image *BKE_image_add_from_imbuf(Main *bmain, ImBuf *ibuf, const char *name)
{
/* on save, type is changed to FILE in editsima.c */
@@ -1144,7 +1159,6 @@ static bool image_memorypack_imbuf(Image *ima, ImBuf *ibuf, const char *filepath
return true;
}
-/* Pack image to memory. */
bool BKE_image_memorypack(Image *ima)
{
bool ok = true;
@@ -1377,7 +1391,6 @@ static bool imagecache_check_free_anim(ImBuf *ibuf, void *UNUSED(userkey), void
(except_frame != IMA_INDEX_ENTRY(ibuf->index));
}
-/* except_frame is weak, only works for seqs without offset... */
void BKE_image_free_anim_ibufs(Image *ima, int except_frame)
{
BLI_mutex_lock(ima->runtime.cache_mutex);
@@ -1639,8 +1652,6 @@ char BKE_imtype_valid_depths(const char imtype)
}
}
-/* string is from command line --render-format arg, keep in sync with
- * creator_args.c help info */
char BKE_imtype_from_arg(const char *imtype_arg)
{
if (STREQ(imtype_arg, "TGA")) {
@@ -2051,9 +2062,10 @@ static void stampdata(
time_t t;
if (scene->r.stamp & R_STAMP_FILENAME) {
+ const char *blendfile_path = BKE_main_blendfile_path_from_global();
SNPRINTF(stamp_data->file,
do_prefix ? "File %s" : "%s",
- G.relbase_valid ? BKE_main_blendfile_path_from_global() : "<untitled>");
+ (blendfile_path[0] != '\0') ? blendfile_path : "<untitled>");
}
else {
stamp_data->file[0] = '\0';
@@ -2744,8 +2756,6 @@ static const char *stamp_metadata_fields[] = {
NULL,
};
-/* Check whether the given metadata field name translates to a known field of
- * a stamp. */
bool BKE_stamp_is_known_field(const char *field_name)
{
int i = 0;
@@ -2907,8 +2917,6 @@ bool BKE_imbuf_alpha_test(ImBuf *ibuf)
return false;
}
-/* NOTE: imf->planes is ignored here, its assumed the image channels
- * are already set */
void BKE_imbuf_write_prepare(ImBuf *ibuf, const ImageFormatData *imf)
{
char imtype = imf->imtype;
@@ -3085,8 +3093,6 @@ int BKE_imbuf_write(ImBuf *ibuf, const char *name, const ImageFormatData *imf)
return ok;
}
-/* same as BKE_imbuf_write() but crappy workaround not to permanently modify
- * _some_, values in the imbuf */
int BKE_imbuf_write_as(ImBuf *ibuf, const char *name, ImageFormatData *imf, const bool save_copy)
{
ImBuf ibuf_back = *ibuf;
@@ -3185,7 +3191,6 @@ struct anim *openanim_noload(const char *name,
return anim;
}
-/* used by sequencer too */
struct anim *openanim(const char *name, int flags, int streamindex, char colorspace[IMA_MAX_SPACE])
{
struct anim *anim;
@@ -3231,8 +3236,6 @@ struct anim *openanim(const char *name, int flags, int streamindex, char colorsp
* -> comes from packedfile or filename or generated
*/
-/* forces existence of 1 Image for renderout or nodes, returns Image */
-/* name is only for default, when making new one */
Image *BKE_image_ensure_viewer(Main *bmain, int type, const char *name)
{
Image *ima;
@@ -3273,7 +3276,6 @@ static void image_viewer_create_views(const RenderData *rd, Image *ima)
}
}
-/* Reset the image cache and views when the Viewer Nodes views don't match the scene views */
void BKE_image_ensure_viewer_views(const RenderData *rd, Image *ima, ImageUser *iuser)
{
bool do_reset;
@@ -3928,7 +3930,6 @@ bool BKE_image_fill_tile(struct Image *ima,
/* if layer or pass changes, we need an index for the imbufs list */
/* note it is called for rendered results, but it doesn't use the index! */
-/* and because rendered results use fake layer/passes, don't correct for wrong indices here */
RenderPass *BKE_image_multilayer_index(RenderResult *rr, ImageUser *iuser)
{
RenderLayer *rl;
@@ -3983,7 +3984,6 @@ void BKE_image_multiview_index(Image *ima, ImageUser *iuser)
/* if layer or pass changes, we need an index for the imbufs list */
/* note it is called for rendered results, but it doesn't use the index! */
-/* and because rendered results use fake layer/passes, don't correct for wrong indices here */
bool BKE_image_is_multilayer(Image *ima)
{
if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_SEQUENCE, IMA_SRC_TILED)) {
@@ -4233,13 +4233,16 @@ static int image_num_files(Image *ima)
return BLI_listbase_count(&ima->views);
}
-static ImBuf *load_sequence_single(Image *ima, ImageUser *iuser, int frame, const int view_id)
+static ImBuf *load_sequence_single(
+ Image *ima, ImageUser *iuser, int frame, const int view_id, bool *r_cache_ibuf)
{
struct ImBuf *ibuf;
char name[FILE_MAX];
int flag;
ImageUser iuser_t = {0};
+ *r_cache_ibuf = true;
+
ima->lastframe = frame;
if (iuser) {
@@ -4279,6 +4282,9 @@ static ImBuf *load_sequence_single(Image *ima, ImageUser *iuser, int frame, cons
ima->type = IMA_TYPE_MULTILAYER;
IMB_freeImBuf(ibuf);
ibuf = NULL;
+ /* NULL ibuf in the cache means the image failed to load. However for multilayer we load
+ * pixels into RenderResult instead and intentionally leave ibuf NULL. */
+ *r_cache_ibuf = false;
}
}
else {
@@ -4299,17 +4305,21 @@ static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int entry,
const int totfiles = image_num_files(ima);
if (!is_multiview) {
- ibuf = load_sequence_single(ima, iuser, frame, 0);
- image_assign_ibuf(ima, ibuf, 0, entry);
+ bool put_in_cache;
+ ibuf = load_sequence_single(ima, iuser, frame, 0, &put_in_cache);
+ if (put_in_cache) {
+ image_assign_ibuf(ima, ibuf, 0, entry);
+ }
}
else {
const int totviews = BLI_listbase_count(&ima->views);
struct ImBuf **ibuf_arr;
ibuf_arr = MEM_mallocN(sizeof(ImBuf *) * totviews, "Image Views Imbufs");
+ bool *cache_ibuf_arr = MEM_mallocN(sizeof(bool) * totviews, "Image View Put In Cache");
for (int i = 0; i < totfiles; i++) {
- ibuf_arr[i] = load_sequence_single(ima, iuser, frame, i);
+ ibuf_arr[i] = load_sequence_single(ima, iuser, frame, i, cache_ibuf_arr + i);
}
if (BKE_image_is_stereo(ima) && ima->views_format == R_IMF_VIEWS_STEREO_3D) {
@@ -4320,7 +4330,9 @@ static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int entry,
ibuf = ibuf_arr[(iuser ? iuser->multi_index : 0)];
for (int i = 0; i < totviews; i++) {
- image_assign_ibuf(ima, ibuf_arr[i], i, entry);
+ if (cache_ibuf_arr[i]) {
+ image_assign_ibuf(ima, ibuf_arr[i], i, entry);
+ }
}
/* "remove" the others (decrease their refcount) */
@@ -4332,6 +4344,7 @@ static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int entry,
/* cleanup */
MEM_freeN(ibuf_arr);
+ MEM_freeN(cache_ibuf_arr);
}
return ibuf;
@@ -4493,13 +4506,19 @@ static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame)
return ibuf;
}
-static ImBuf *load_image_single(
- Image *ima, ImageUser *iuser, int cfra, const int view_id, const bool has_packed)
+static ImBuf *load_image_single(Image *ima,
+ ImageUser *iuser,
+ int cfra,
+ const int view_id,
+ const bool has_packed,
+ bool *r_cache_ibuf)
{
char filepath[FILE_MAX];
struct ImBuf *ibuf = NULL;
int flag;
+ *r_cache_ibuf = true;
+
/* is there a PackedFile with this image ? */
if (has_packed) {
ImagePackedFile *imapf;
@@ -4550,6 +4569,9 @@ static ImBuf *load_image_single(
ima->type = IMA_TYPE_MULTILAYER;
IMB_freeImBuf(ibuf);
ibuf = NULL;
+ /* NULL ibuf in the cache means the image failed to load. However for multilayer we load
+ * pixels into RenderResult instead and intentionally leave ibuf NULL. */
+ *r_cache_ibuf = false;
}
}
else
@@ -4594,8 +4616,11 @@ static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra)
}
if (!is_multiview) {
- ibuf = load_image_single(ima, iuser, cfra, 0, has_packed);
- image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0);
+ bool put_in_cache;
+ ibuf = load_image_single(ima, iuser, cfra, 0, has_packed, &put_in_cache);
+ if (put_in_cache) {
+ image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0);
+ }
}
else {
struct ImBuf **ibuf_arr;
@@ -4603,9 +4628,10 @@ static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra)
BLI_assert(totviews > 0);
ibuf_arr = MEM_callocN(sizeof(ImBuf *) * totviews, "Image Views Imbufs");
+ bool *cache_ibuf_arr = MEM_mallocN(sizeof(bool) * totviews, "Image Views Put In Cache");
for (int i = 0; i < totfiles; i++) {
- ibuf_arr[i] = load_image_single(ima, iuser, cfra, i, has_packed);
+ ibuf_arr[i] = load_image_single(ima, iuser, cfra, i, has_packed, cache_ibuf_arr + i);
}
/* multi-views/multi-layers OpenEXR files directly populate ima, and return NULL ibuf... */
@@ -4619,7 +4645,9 @@ static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra)
ibuf = ibuf_arr[i];
for (i = 0; i < totviews; i++) {
- image_assign_ibuf(ima, ibuf_arr[i], i, 0);
+ if (cache_ibuf_arr[i]) {
+ image_assign_ibuf(ima, ibuf_arr[i], i, 0);
+ }
}
/* "remove" the others (decrease their refcount) */
@@ -4631,6 +4659,7 @@ static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra)
/* cleanup */
MEM_freeN(ibuf_arr);
+ MEM_freeN(cache_ibuf_arr);
}
return ibuf;
@@ -4986,9 +5015,10 @@ BLI_INLINE bool image_quick_test(Image *ima, const ImageUser *iuser)
return true;
}
-/* Checks optional ImageUser and verifies/creates ImBuf.
+/**
+ * Checks optional #ImageUser and verifies/creates #ImBuf.
*
- * not thread-safe, so callee should worry about thread locks
+ * \warning Not thread-safe, so callee should worry about thread locks.
*/
static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
{
@@ -5109,15 +5139,15 @@ static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
return ibuf;
}
-/* return image buffer for given image and user
- *
- * - will lock render result if image type is render result and lock is not NULL
- * - will return NULL if image type if render or composite result and lock is NULL
- *
- * references the result, BKE_image_release_ibuf should be used to de-reference
- */
ImBuf *BKE_image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
{
+ /* NOTE: same as #image_acquire_ibuf, but can be used to retrieve images being rendered in
+ * a thread safe way, always call both acquire and release. */
+
+ if (ima == NULL) {
+ return NULL;
+ }
+
ImBuf *ibuf;
BLI_mutex_lock(ima->runtime.cache_mutex);
@@ -5149,7 +5179,6 @@ void BKE_image_release_ibuf(Image *ima, ImBuf *ibuf, void *lock)
}
}
-/* checks whether there's an image buffer for given image and user */
bool BKE_image_has_ibuf(Image *ima, ImageUser *iuser)
{
ImBuf *ibuf;
@@ -5657,19 +5686,16 @@ bool BKE_image_has_filepath(Image *ima)
return ima->filepath[0] != '\0';
}
-/* Checks the image buffer changes with time (not keyframed values). */
bool BKE_image_is_animated(Image *image)
{
return ELEM(image->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE);
}
-/* Checks whether the image consists of multiple buffers. */
bool BKE_image_has_multiple_ibufs(Image *image)
{
return ELEM(image->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE, IMA_SRC_TILED);
}
-/* Image modifications */
bool BKE_image_is_dirty_writable(Image *image, bool *r_is_writable)
{
bool is_dirty = false;
@@ -5745,8 +5771,12 @@ bool BKE_image_has_loaded_ibuf(Image *image)
struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache);
while (!IMB_moviecacheIter_done(iter)) {
- has_loaded_ibuf = true;
- break;
+ ImBuf *ibuf = IMB_moviecacheIter_getImBuf(iter);
+ if (ibuf != NULL) {
+ has_loaded_ibuf = true;
+ break;
+ }
+ IMB_moviecacheIter_step(iter);
}
IMB_moviecacheIter_free(iter);
}
@@ -5755,10 +5785,6 @@ bool BKE_image_has_loaded_ibuf(Image *image)
return has_loaded_ibuf;
}
-/**
- * References the result, #BKE_image_release_ibuf is to be called to de-reference.
- * Use lock=NULL when calling #BKE_image_release_ibuf().
- */
ImBuf *BKE_image_get_ibuf_with_name(Image *image, const char *name)
{
ImBuf *ibuf = NULL;
@@ -5783,15 +5809,6 @@ ImBuf *BKE_image_get_ibuf_with_name(Image *image, const char *name)
return ibuf;
}
-/**
- * References the result, #BKE_image_release_ibuf is to be called to de-reference.
- * Use lock=NULL when calling #BKE_image_release_ibuf().
- *
- * TODO(sergey): This is actually "get first item from the cache", which is
- * not so much predictable. But using first loaded image buffer
- * was also malicious logic and all the areas which uses this
- * function are to be re-considered.
- */
ImBuf *BKE_image_get_first_ibuf(Image *image)
{
ImBuf *ibuf = NULL;
diff --git a/source/blender/blenkernel/intern/image_gpu.c b/source/blender/blenkernel/intern/image_gpu.cc
index 330af1cc505..4440e4b101a 100644
--- a/source/blender/blenkernel/intern/image_gpu.c
+++ b/source/blender/blenkernel/intern/image_gpu.cc
@@ -47,7 +47,7 @@
#include "PIL_time.h"
/* Prototypes. */
-static void gpu_free_unused_buffers(void);
+static void gpu_free_unused_buffers();
static void image_free_gpu(Image *ima, const bool immediate);
static void image_free_gpu_limited_scale(Image *ima);
static void image_update_gputexture_ex(
@@ -55,13 +55,12 @@ static void image_update_gputexture_ex(
/* Internal structs. */
#define IMA_PARTIAL_REFRESH_TILE_SIZE 256
-typedef struct ImagePartialRefresh {
+struct ImagePartialRefresh {
struct ImagePartialRefresh *next, *prev;
int tile_x;
int tile_y;
-} ImagePartialRefresh;
+};
-/* Is the alpha of the `GPUTexture` for a given image/ibuf premultiplied. */
bool BKE_image_has_gpu_texture_premultiplied_alpha(Image *image, ImBuf *ibuf)
{
if (image) {
@@ -71,7 +70,7 @@ bool BKE_image_has_gpu_texture_premultiplied_alpha(Image *image, ImBuf *ibuf)
}
/* Generated images use pre multiplied float buffer, but straight alpha for byte buffers. */
if (image->type == IMA_TYPE_UV_TEST && ibuf) {
- return ibuf->rect_float != NULL;
+ return ibuf->rect_float != nullptr;
}
}
if (ibuf) {
@@ -85,8 +84,9 @@ bool BKE_image_has_gpu_texture_premultiplied_alpha(Image *image, ImBuf *ibuf)
}
/* -------------------------------------------------------------------- */
-/** \name UDIM gpu texture
+/** \name UDIM GPU Texture
* \{ */
+
static bool is_over_resolution_limit(int w, int h, bool limit_gl_texture_size)
{
return (w > GPU_texture_size_with_limit(w, limit_gl_texture_size) ||
@@ -104,8 +104,8 @@ static GPUTexture *gpu_texture_create_tile_mapping(
const int resolution = (texture_resolution == IMA_TEXTURE_RESOLUTION_LIMITED) ? 1 : 0;
GPUTexture *tilearray = ima->gputexture[TEXTARGET_2D_ARRAY][multiview_eye][resolution];
- if (tilearray == NULL) {
- return 0;
+ if (tilearray == nullptr) {
+ return nullptr;
}
float array_w = GPU_texture_width(tilearray);
@@ -142,11 +142,11 @@ static GPUTexture *gpu_texture_create_tile_mapping(
return tex;
}
-typedef struct PackTile {
+struct PackTile {
FixedSizeBoxPack boxpack;
ImageTile *tile;
float pack_score;
-} PackTile;
+};
static int compare_packtile(const void *a, const void *b)
{
@@ -163,13 +163,13 @@ static GPUTexture *gpu_texture_create_tile_array(Image *ima,
const bool limit_gl_texture_size = texture_resolution == IMA_TEXTURE_RESOLUTION_LIMITED;
const int resolution = texture_resolution == IMA_TEXTURE_RESOLUTION_LIMITED ? 1 : 0;
int arraywidth = 0, arrayheight = 0;
- ListBase boxes = {NULL};
+ ListBase boxes = {nullptr};
LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
ImageUser iuser;
BKE_imageuser_default(&iuser);
iuser.tile = tile->tile_number;
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, nullptr);
if (ibuf) {
PackTile *packtile = (PackTile *)MEM_callocN(sizeof(PackTile), __func__);
@@ -190,7 +190,7 @@ static GPUTexture *gpu_texture_create_tile_array(Image *ima,
float w = packtile->boxpack.w, h = packtile->boxpack.h;
packtile->pack_score = max_ff(w, h) / min_ff(w, h) * w * h;
- BKE_image_release_ibuf(ima, ibuf, NULL);
+ BKE_image_release_ibuf(ima, ibuf, nullptr);
BLI_addtail(&boxes, packtile);
}
}
@@ -200,10 +200,10 @@ static GPUTexture *gpu_texture_create_tile_array(Image *ima,
BLI_listbase_sort(&boxes, compare_packtile);
int arraylayers = 0;
/* Keep adding layers until all tiles are packed. */
- while (boxes.first != NULL) {
- ListBase packed = {NULL};
+ while (boxes.first != nullptr) {
+ ListBase packed = {nullptr};
BLI_box_pack_2d_fixedarea(&boxes, arraywidth, arrayheight, &packed);
- BLI_assert(packed.first != NULL);
+ BLI_assert(packed.first != nullptr);
LISTBASE_FOREACH (PackTile *, packtile, &packed) {
ImageTile *tile = packtile->tile;
@@ -241,7 +241,7 @@ static GPUTexture *gpu_texture_create_tile_array(Image *ima,
ImageUser iuser;
BKE_imageuser_default(&iuser);
iuser.tile = tile->tile_number;
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, nullptr);
if (ibuf) {
const bool store_premultiplied = BKE_image_has_gpu_texture_premultiplied_alpha(ima, ibuf);
@@ -254,7 +254,7 @@ static GPUTexture *gpu_texture_create_tile_array(Image *ima,
store_premultiplied);
}
- BKE_image_release_ibuf(ima, ibuf, NULL);
+ BKE_image_release_ibuf(ima, ibuf, nullptr);
}
if (GPU_mipmap_enabled()) {
@@ -305,7 +305,7 @@ static GPUTexture **get_image_gpu_texture_ptr(Image *ima,
if (in_range) {
return &(ima->gputexture[textarget][multiview_eye][resolution]);
}
- return NULL;
+ return nullptr;
}
static GPUTexture *image_gpu_texture_error_create(eGPUTextureTarget textarget)
@@ -342,8 +342,8 @@ static GPUTexture *image_get_gpu_texture(Image *ima,
ImBuf *ibuf,
eGPUTextureTarget textarget)
{
- if (ima == NULL) {
- return NULL;
+ if (ima == nullptr) {
+ return nullptr;
}
/* Free any unused GPU textures, since we know we are in a thread with OpenGL
@@ -373,7 +373,7 @@ static GPUTexture *image_get_gpu_texture(Image *ima,
/* Check if image has been updated and tagged to be updated (full or partial). */
ImageTile *tile = BKE_image_get_tile(ima, 0);
if (((ima->gpuflag & IMA_GPU_REFRESH) != 0) ||
- ((ibuf == NULL || tile == NULL) && ((ima->gpuflag & IMA_GPU_PARTIAL_REFRESH) != 0))) {
+ ((ibuf == nullptr || tile == nullptr) && ((ima->gpuflag & IMA_GPU_PARTIAL_REFRESH) != 0))) {
image_free_gpu(ima, true);
BLI_freelistN(&ima->gpu_refresh_areas);
ima->gpuflag &= ~(IMA_GPU_REFRESH | IMA_GPU_PARTIAL_REFRESH);
@@ -382,7 +382,8 @@ static GPUTexture *image_get_gpu_texture(Image *ima,
BLI_assert(ibuf);
BLI_assert(tile);
ImagePartialRefresh *refresh_area;
- while ((refresh_area = BLI_pophead(&ima->gpu_refresh_areas))) {
+ while ((
+ refresh_area = static_cast<ImagePartialRefresh *>(BLI_pophead(&ima->gpu_refresh_areas)))) {
const int tile_offset_x = refresh_area->tile_x * IMA_PARTIAL_REFRESH_TILE_SIZE;
const int tile_offset_y = refresh_area->tile_y * IMA_PARTIAL_REFRESH_TILE_SIZE;
const int tile_width = MIN2(IMA_PARTIAL_REFRESH_TILE_SIZE, ibuf->x - tile_offset_x);
@@ -404,7 +405,7 @@ static GPUTexture *image_get_gpu_texture(Image *ima,
}
const bool limit_resolution = U.glreslimit != 0 &&
((iuser && (iuser->flag & IMA_SHOW_MAX_RESOLUTION) == 0) ||
- (iuser == NULL)) &&
+ (iuser == nullptr)) &&
((ima->gpuflag & IMA_GPU_REUSE_MAX_RESOLUTION) == 0);
const eImageTextureResolution texture_resolution = limit_resolution ?
IMA_TEXTURE_RESOLUTION_LIMITED :
@@ -416,16 +417,16 @@ static GPUTexture *image_get_gpu_texture(Image *ima,
/* Check if we have a valid image. If not, we return a dummy
* texture with zero bind-code so we don't keep trying. */
- if (tile == NULL) {
+ if (tile == nullptr) {
*tex = image_gpu_texture_error_create(textarget);
return *tex;
}
/* check if we have a valid image buffer */
ImBuf *ibuf_intern = ibuf;
- if (ibuf_intern == NULL) {
- ibuf_intern = BKE_image_acquire_ibuf(ima, iuser, NULL);
- if (ibuf_intern == NULL) {
+ if (ibuf_intern == nullptr) {
+ ibuf_intern = BKE_image_acquire_ibuf(ima, iuser, nullptr);
+ if (ibuf_intern == nullptr) {
*tex = image_gpu_texture_error_create(textarget);
return *tex;
}
@@ -477,8 +478,8 @@ static GPUTexture *image_get_gpu_texture(Image *ima,
}
/* if `ibuf` was given, we don't own the `ibuf_intern` */
- if (ibuf == NULL) {
- BKE_image_release_ibuf(ima, ibuf_intern, NULL);
+ if (ibuf == nullptr) {
+ BKE_image_release_ibuf(ima, ibuf_intern, nullptr);
}
if (*tex) {
@@ -512,19 +513,19 @@ GPUTexture *BKE_image_get_gpu_tilemap(Image *image, ImageUser *iuser, ImBuf *ibu
* In that case we push them into a queue and free the buffers later.
* \{ */
-static LinkNode *gpu_texture_free_queue = NULL;
+static LinkNode *gpu_texture_free_queue = nullptr;
static ThreadMutex gpu_texture_queue_mutex = BLI_MUTEX_INITIALIZER;
-static void gpu_free_unused_buffers(void)
+static void gpu_free_unused_buffers()
{
- if (gpu_texture_free_queue == NULL) {
+ if (gpu_texture_free_queue == nullptr) {
return;
}
BLI_mutex_lock(&gpu_texture_queue_mutex);
- while (gpu_texture_free_queue != NULL) {
- GPUTexture *tex = BLI_linklist_pop(&gpu_texture_free_queue);
+ while (gpu_texture_free_queue != nullptr) {
+ GPUTexture *tex = static_cast<GPUTexture *>(BLI_linklist_pop(&gpu_texture_free_queue));
GPU_texture_free(tex);
}
@@ -549,7 +550,7 @@ static void image_free_gpu(Image *ima, const bool immediate)
for (int eye = 0; eye < 2; eye++) {
for (int i = 0; i < TEXTARGET_COUNT; i++) {
for (int resolution = 0; resolution < IMA_TEXTURE_RESOLUTION_LEN; resolution++) {
- if (ima->gputexture[i][eye][resolution] != NULL) {
+ if (ima->gputexture[i][eye][resolution] != nullptr) {
if (immediate) {
GPU_texture_free(ima->gputexture[i][eye][resolution]);
}
@@ -559,7 +560,7 @@ static void image_free_gpu(Image *ima, const bool immediate)
BLI_mutex_unlock(&gpu_texture_queue_mutex);
}
- ima->gputexture[i][eye][resolution] = NULL;
+ ima->gputexture[i][eye][resolution] = nullptr;
}
}
}
@@ -573,9 +574,9 @@ static void image_free_gpu_limited_scale(Image *ima)
const eImageTextureResolution resolution = IMA_TEXTURE_RESOLUTION_LIMITED;
for (int eye = 0; eye < 2; eye++) {
for (int i = 0; i < TEXTARGET_COUNT; i++) {
- if (ima->gputexture[i][eye][resolution] != NULL) {
+ if (ima->gputexture[i][eye][resolution] != nullptr) {
GPU_texture_free(ima->gputexture[i][eye][resolution]);
- ima->gputexture[i][eye][resolution] = NULL;
+ ima->gputexture[i][eye][resolution] = nullptr;
}
}
}
@@ -597,7 +598,6 @@ void BKE_image_free_all_gputextures(Main *bmain)
}
}
-/* same as above but only free animated images */
void BKE_image_free_anim_gputextures(Main *bmain)
{
if (bmain) {
@@ -644,6 +644,7 @@ void BKE_image_free_old_gputextures(Main *bmain)
}
}
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -769,7 +770,7 @@ static void gpu_texture_update_from_ibuf(GPUTexture *tex,
{
const int resolution = texture_resolution == IMA_TEXTURE_RESOLUTION_LIMITED ? 1 : 0;
bool scaled;
- if (tile != NULL) {
+ if (tile != nullptr) {
ImageTile_RuntimeTextureSlot *tile_runtime = &tile->runtime.slots[resolution];
int *tilesize = tile_runtime->tilearray_size;
scaled = (ibuf->x != tilesize[0]) || (ibuf->y != tilesize[1]);
@@ -796,14 +797,14 @@ static void gpu_texture_update_from_ibuf(GPUTexture *tex,
int tex_offset = ibuf->channels * (y * ibuf->x + x);
const bool store_premultiplied = BKE_image_has_gpu_texture_premultiplied_alpha(ima, ibuf);
- if (rect_float == NULL) {
+ if (rect_float == nullptr) {
/* Byte pixels. */
if (!IMB_colormanagement_space_is_data(ibuf->rect_colorspace)) {
const bool compress_as_srgb = !IMB_colormanagement_space_is_scene_linear(
ibuf->rect_colorspace);
rect = (uchar *)MEM_mallocN(sizeof(uchar[4]) * w * h, __func__);
- if (rect == NULL) {
+ if (rect == nullptr) {
return;
}
@@ -820,7 +821,7 @@ static void gpu_texture_update_from_ibuf(GPUTexture *tex,
/* Float pixels. */
if (ibuf->channels != 4 || scaled || !store_premultiplied) {
rect_float = (float *)MEM_mallocN(sizeof(float[4]) * w * h, __func__);
- if (rect_float == NULL) {
+ if (rect_float == nullptr) {
return;
}
@@ -834,7 +835,7 @@ static void gpu_texture_update_from_ibuf(GPUTexture *tex,
if (scaled) {
/* Slower update where we first have to scale the input pixels. */
- if (tile != NULL) {
+ if (tile != nullptr) {
ImageTile_RuntimeTextureSlot *tile_runtime = &tile->runtime.slots[resolution];
int *tileoffset = tile_runtime->tilearray_offset;
int *tilesize = tile_runtime->tilearray_size;
@@ -844,12 +845,12 @@ static void gpu_texture_update_from_ibuf(GPUTexture *tex,
}
else {
gpu_texture_update_scaled(
- tex, rect, rect_float, ibuf->x, ibuf->y, x, y, -1, NULL, NULL, w, h);
+ tex, rect, rect_float, ibuf->x, ibuf->y, x, y, -1, nullptr, nullptr, w, h);
}
}
else {
/* Fast update at same resolution. */
- if (tile != NULL) {
+ if (tile != nullptr) {
ImageTile_RuntimeTextureSlot *tile_runtime = &tile->runtime.slots[resolution];
int *tileoffset = tile_runtime->tilearray_offset;
int tilelayer = tile_runtime->tilearray_layer;
@@ -858,7 +859,7 @@ static void gpu_texture_update_from_ibuf(GPUTexture *tex,
}
else {
gpu_texture_update_unscaled(
- tex, rect, rect_float, x, y, -1, NULL, w, h, tex_stride, tex_offset);
+ tex, rect, rect_float, x, y, -1, nullptr, w, h, tex_stride, tex_offset);
}
}
@@ -886,39 +887,33 @@ static void image_update_gputexture_ex(
const int eye = 0;
for (int resolution = 0; resolution < IMA_TEXTURE_RESOLUTION_LEN; resolution++) {
GPUTexture *tex = ima->gputexture[TEXTARGET_2D][eye][resolution];
- eImageTextureResolution texture_resolution = resolution;
+ eImageTextureResolution texture_resolution = static_cast<eImageTextureResolution>(resolution);
/* Check if we need to update the main gputexture. */
- if (tex != NULL && tile == ima->tiles.first) {
- gpu_texture_update_from_ibuf(tex, ima, ibuf, NULL, x, y, w, h, texture_resolution);
+ if (tex != nullptr && tile == ima->tiles.first) {
+ gpu_texture_update_from_ibuf(tex, ima, ibuf, nullptr, x, y, w, h, texture_resolution);
}
/* Check if we need to update the array gputexture. */
tex = ima->gputexture[TEXTARGET_2D_ARRAY][eye][resolution];
- if (tex != NULL) {
+ if (tex != nullptr) {
gpu_texture_update_from_ibuf(tex, ima, ibuf, tile, x, y, w, h, texture_resolution);
}
}
}
-/* Partial update of texture for texture painting. This is often much
- * quicker than fully updating the texture for high resolution images. */
void BKE_image_update_gputexture(Image *ima, ImageUser *iuser, int x, int y, int w, int h)
{
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, nullptr);
ImageTile *tile = BKE_image_get_tile_from_iuser(ima, iuser);
- if ((ibuf == NULL) || (w == 0) || (h == 0)) {
+ if ((ibuf == nullptr) || (w == 0) || (h == 0)) {
/* Full reload of texture. */
BKE_image_free_gputextures(ima);
}
image_update_gputexture_ex(ima, tile, ibuf, x, y, w, h);
- BKE_image_release_ibuf(ima, ibuf, NULL);
+ BKE_image_release_ibuf(ima, ibuf, nullptr);
}
-/* Mark areas on the GPUTexture that needs to be updated. The areas are marked in chunks.
- * The next time the GPUTexture is used these tiles will be refreshes. This saves time
- * when writing to the same place multiple times This happens for during foreground
- * rendering. */
void BKE_image_update_gputexture_delayed(
struct Image *ima, struct ImBuf *ibuf, int x, int y, int w, int h)
{
@@ -946,7 +941,7 @@ void BKE_image_update_gputexture_delayed(
const int num_tiles_y = (end_tile_y + 1) - (start_tile_y);
const int num_tiles = num_tiles_x * num_tiles_y;
const bool allocate_on_heap = BLI_BITMAP_SIZE(num_tiles) > 16;
- BLI_bitmap *requested_tiles = NULL;
+ BLI_bitmap *requested_tiles = nullptr;
if (allocate_on_heap) {
requested_tiles = BLI_BITMAP_NEW(num_tiles, __func__);
}
@@ -976,7 +971,8 @@ void BKE_image_update_gputexture_delayed(
for (int tile_y = start_tile_y; tile_y <= end_tile_y; tile_y++) {
for (int tile_x = start_tile_x; tile_x <= end_tile_x; tile_x++) {
if (!BLI_BITMAP_TEST_BOOL(requested_tiles, tile_index)) {
- ImagePartialRefresh *area = MEM_mallocN(sizeof(ImagePartialRefresh), __func__);
+ ImagePartialRefresh *area = static_cast<ImagePartialRefresh *>(
+ MEM_mallocN(sizeof(ImagePartialRefresh), __func__));
area->tile_x = tile_x;
area->tile_y = tile_y;
BLI_addtail(&ima->gpu_refresh_areas, area);
@@ -991,10 +987,6 @@ void BKE_image_update_gputexture_delayed(
}
}
-/* these two functions are called on entering and exiting texture paint mode,
- * temporary disabling/enabling mipmapping on all images for quick texture
- * updates with glTexSubImage2D. images that didn't change don't have to be
- * re-uploaded to OpenGL */
void BKE_image_paint_set_mipmap(Main *bmain, bool mipmap)
{
LISTBASE_FOREACH (Image *, ima, &bmain->images) {
@@ -1005,7 +997,7 @@ void BKE_image_paint_set_mipmap(Main *bmain, bool mipmap)
for (int eye = 0; eye < 2; eye++) {
for (int resolution = 0; resolution < IMA_TEXTURE_RESOLUTION_LEN; resolution++) {
GPUTexture *tex = ima->gputexture[a][eye][resolution];
- if (tex != NULL) {
+ if (tex != nullptr) {
GPU_texture_mipmap_mode(tex, mipmap, true);
}
}
diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c
index 26a1240080f..d87331fd65c 100644
--- a/source/blender/blenkernel/intern/ipo.c
+++ b/source/blender/blenkernel/intern/ipo.c
@@ -185,6 +185,7 @@ IDTypeInfo IDType_ID_IP = {
.name_plural = "ipos",
.translation_context = "",
.flags = IDTYPE_FLAGS_NO_COPY | IDTYPE_FLAGS_NO_LIBLINKING | IDTYPE_FLAGS_NO_ANIMDATA,
+ .asset_type_info = NULL,
.init_data = NULL,
.copy_data = NULL,
@@ -192,6 +193,7 @@ IDTypeInfo IDType_ID_IP = {
.make_local = NULL,
.foreach_id = NULL,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = NULL,
@@ -2093,17 +2095,6 @@ static bool seq_convert_callback(Sequence *seq, void *userdata)
/* *************************************************** */
/* External API - Only Called from do_versions() */
-/* Called from do_versions() in readfile.c to convert the old 'IPO/adrcode' system
- * to the new 'Animato/RNA' system.
- *
- * The basic method used here, is to loop over data-blocks which have IPO-data,
- * and add those IPO's to new AnimData blocks as Actions.
- * Action/NLA data only works well for Objects, so these only need to be checked for there.
- *
- * Data that has been converted should be freed immediately, which means that it is immediately
- * clear which data-blocks have yet to be converted, and also prevent freeing errors when we exit.
- */
-/* XXX currently done after all file reading... */
void do_versions_ipos_to_animato(Main *bmain)
{
ListBase drivers = {NULL, NULL};
diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c
index c09fcf0715e..ff199794ab3 100644
--- a/source/blender/blenkernel/intern/key.c
+++ b/source/blender/blenkernel/intern/key.c
@@ -213,6 +213,7 @@ IDTypeInfo IDType_ID_KE = {
.name_plural = "shape_keys",
.translation_context = BLT_I18NCONTEXT_ID_SHAPEKEY,
.flags = IDTYPE_FLAGS_NO_LIBLINKING,
+ .asset_type_info = NULL,
.init_data = NULL,
.copy_data = shapekey_copy_data,
@@ -220,6 +221,7 @@ IDTypeInfo IDType_ID_KE = {
.make_local = NULL,
.foreach_id = shapekey_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
/* A bit weird, due to shapekeys not being strictly speaking embedded data... But they also
* share a lot with those (non linkable, only ever used by one owner ID, etc.). */
.owner_get = shapekey_owner_get,
@@ -244,7 +246,6 @@ typedef struct WeightsArrayCache {
float **defgroup_weights;
} WeightsArrayCache;
-/** Free (or release) any data used by this shapekey (does not free the key itself). */
void BKE_key_free_data(Key *key)
{
shapekey_free_data(&key->id);
@@ -314,11 +315,6 @@ Key *BKE_key_add(Main *bmain, ID *id) /* common function */
return key;
}
-/**
- * Sort shape keys after a change.
- * This assumes that at most one key was moved,
- * which is a valid assumption for the places it's currently being called.
- */
void BKE_key_sort(Key *key)
{
KeyBlock *kb;
@@ -392,7 +388,6 @@ void key_curve_position_weights(float t, float data[4], int type)
}
}
-/* first derivative */
void key_curve_tangent_weights(float t, float data[4], int type)
{
float t2, fc;
@@ -431,7 +426,6 @@ void key_curve_tangent_weights(float t, float data[4], int type)
}
}
-/* second derivative */
void key_curve_normal_weights(float t, float data[4], int type)
{
float fc;
@@ -1522,7 +1516,6 @@ static void do_latt_key(Object *ob, Key *key, char *out, const int tot)
}
}
-/* returns key coordinates (+ tilt) when key applied, NULL otherwise */
float *BKE_key_evaluate_object_ex(Object *ob, int *r_totelem, float *arr, size_t arr_size)
{
Key *key = BKE_key_from_object(ob);
@@ -1624,9 +1617,6 @@ float *BKE_key_evaluate_object(Object *ob, int *r_totelem)
return BKE_key_evaluate_object_ex(ob, r_totelem, NULL, 0);
}
-/**
- * \param shape_index: The index to use or all (when -1).
- */
int BKE_keyblock_element_count_from_shape(const Key *key, const int shape_index)
{
int result = 0;
@@ -1644,9 +1634,6 @@ int BKE_keyblock_element_count(const Key *key)
return BKE_keyblock_element_count_from_shape(key, -1);
}
-/**
- * \param shape_index: The index to use or all (when -1).
- */
size_t BKE_keyblock_element_calc_size_from_shape(const Key *key, const int shape_index)
{
return (size_t)BKE_keyblock_element_count_from_shape(key, shape_index) * key->elemsize;
@@ -1664,9 +1651,6 @@ size_t BKE_keyblock_element_calc_size(const Key *key)
* use #BKE_keyblock_element_calc_size to allocate the size of the data needed.
* \{ */
-/**
- * \param shape_index: The index to use or all (when -1).
- */
void BKE_keyblock_data_get_from_shape(const Key *key, float (*arr)[3], const int shape_index)
{
uint8_t *elements = (uint8_t *)arr;
@@ -1685,9 +1669,6 @@ void BKE_keyblock_data_get(const Key *key, float (*arr)[3])
BKE_keyblock_data_get_from_shape(key, arr, -1);
}
-/**
- * Set the data to all key-blocks (or shape_index if != -1).
- */
void BKE_keyblock_data_set_with_mat4(Key *key,
const int shape_index,
const float (*coords)[3],
@@ -1715,10 +1696,6 @@ void BKE_keyblock_data_set_with_mat4(Key *key,
}
}
-/**
- * Set the data for all key-blocks (or shape_index if != -1),
- * transforming by \a mat.
- */
void BKE_keyblock_curve_data_set_with_mat4(
Key *key, const ListBase *nurb, const int shape_index, const void *data, const float mat[4][4])
{
@@ -1734,9 +1711,6 @@ void BKE_keyblock_curve_data_set_with_mat4(
}
}
-/**
- * Set the data for all key-blocks (or shape_index if != -1).
- */
void BKE_keyblock_data_set(Key *key, const int shape_index, const void *data)
{
const uint8_t *elements = data;
@@ -1868,14 +1842,6 @@ KeyBlock *BKE_keyblock_add(Key *key, const char *name)
return kb;
}
-/**
- * \note sorting is a problematic side effect in some cases,
- * better only do this explicitly by having its own function,
- *
- * \param key: The key datablock to add to.
- * \param name: Optional name for the new keyblock.
- * \param do_force: always use ctime even for relative keys.
- */
KeyBlock *BKE_keyblock_add_ctime(Key *key, const char *name, const bool do_force)
{
KeyBlock *kb = BKE_keyblock_add(key, name);
@@ -1904,7 +1870,6 @@ KeyBlock *BKE_keyblock_add_ctime(Key *key, const char *name, const bool do_force
return kb;
}
-/* Only the active key-block. */
KeyBlock *BKE_keyblock_from_object(Object *ob)
{
Key *key = BKE_key_from_object(ob);
@@ -1928,7 +1893,6 @@ KeyBlock *BKE_keyblock_from_object_reference(Object *ob)
return NULL;
}
-/* get the appropriate KeyBlock given an index */
KeyBlock *BKE_keyblock_from_key(Key *key, int index)
{
if (key) {
@@ -1946,15 +1910,11 @@ KeyBlock *BKE_keyblock_from_key(Key *key, int index)
return NULL;
}
-/* get the appropriate KeyBlock given a name to search for */
KeyBlock *BKE_keyblock_find_name(Key *key, const char name[])
{
return BLI_findstring(&key->block, name, offsetof(KeyBlock, name));
}
-/**
- * \brief copy shape-key attributes, but not key data.or name/uid
- */
void BKE_keyblock_copy_settings(KeyBlock *kb_dst, const KeyBlock *kb_src)
{
kb_dst->pos = kb_src->pos;
@@ -1966,9 +1926,6 @@ void BKE_keyblock_copy_settings(KeyBlock *kb_dst, const KeyBlock *kb_src)
kb_dst->slidermax = kb_src->slidermax;
}
-/* Get RNA-Path for 'value' setting of the given ShapeKey
- * NOTE: the user needs to free the returned string once they're finish with it
- */
char *BKE_keyblock_curval_rnapath_get(Key *key, KeyBlock *kb)
{
PointerRNA ptr;
@@ -1991,6 +1948,7 @@ char *BKE_keyblock_curval_rnapath_get(Key *key, KeyBlock *kb)
/* conversion functions */
/************************* Lattice ************************/
+
void BKE_keyblock_update_from_lattice(Lattice *lt, KeyBlock *kb)
{
BPoint *bp;
@@ -2191,6 +2149,7 @@ void BKE_keyblock_convert_to_curve(KeyBlock *kb, Curve *UNUSED(cu), ListBase *nu
}
/************************* Mesh ************************/
+
void BKE_keyblock_update_from_mesh(Mesh *me, KeyBlock *kb)
{
MVert *mvert;
@@ -2243,15 +2202,6 @@ void BKE_keyblock_convert_to_mesh(KeyBlock *kb, Mesh *me)
}
}
-/**
- * Computes normals (vertices, polygons and/or loops ones) of given mesh for given shape key.
- *
- * \param kb: the KeyBlock to use to compute normals.
- * \param mesh: the Mesh to apply key-block to.
- * \param r_vertnors: if non-NULL, an array of vectors, same length as number of vertices.
- * \param r_polynors: if non-NULL, an array of vectors, same length as number of polygons.
- * \param r_loopnors: if non-NULL, an array of vectors, same length as number of loops.
- */
void BKE_keyblock_mesh_calc_normals(struct KeyBlock *kb,
struct Mesh *mesh,
float (*r_vertnors)[3],
@@ -2316,6 +2266,7 @@ void BKE_keyblock_mesh_calc_normals(struct KeyBlock *kb,
}
/************************* raw coords ************************/
+
void BKE_keyblock_update_from_vertcos(Object *ob, KeyBlock *kb, const float (*vertCos)[3])
{
const float(*co)[3] = vertCos;
@@ -2469,6 +2420,7 @@ float (*BKE_keyblock_convert_to_vertcos(Object *ob, KeyBlock *kb))[3]
}
/************************* raw coord offsets ************************/
+
void BKE_keyblock_update_from_offset(Object *ob, KeyBlock *kb, const float (*ofs)[3])
{
int a;
@@ -2506,15 +2458,6 @@ void BKE_keyblock_update_from_offset(Object *ob, KeyBlock *kb, const float (*ofs
/* ==========================================================*/
-/**
- * Move shape key from org_index to new_index. Safe, clamps index to valid range,
- * updates reference keys, the object's active shape index,
- * the 'frame' value in case of absolute keys, etc.
- * Note indices are expected in real values (not 'fake' shapenr +1 ones).
- *
- * \param org_index: if < 0, current object's active shape will be used as skey to move.
- * \return true if something was done, else false.
- */
bool BKE_keyblock_move(Object *ob, int org_index, int new_index)
{
Key *key = BKE_key_from_object(ob);
@@ -2593,9 +2536,6 @@ bool BKE_keyblock_move(Object *ob, int org_index, int new_index)
return true;
}
-/**
- * Check if given key-block (as index) is used as basis by others in given key.
- */
bool BKE_keyblock_is_basis(Key *key, const int index)
{
KeyBlock *kb;
diff --git a/source/blender/blenkernel/intern/keyconfig.c b/source/blender/blenkernel/intern/keyconfig.c
index d25f475c140..84e11c1166e 100644
--- a/source/blender/blenkernel/intern/keyconfig.c
+++ b/source/blender/blenkernel/intern/keyconfig.c
@@ -121,7 +121,6 @@ void BKE_keyconfig_pref_type_free(void)
/** \name Key-Config Versioning
* \{ */
-/* Set select mouse, for versioning code. */
void BKE_keyconfig_pref_set_select_mouse(UserDef *userdef, int value, bool override)
{
wmKeyConfigPref *kpt = BKE_keyconfig_pref_ensure(userdef, WM_KEYCONFIG_STR_DEFAULT);
@@ -201,10 +200,6 @@ void BKE_keyconfig_keymap_filter_item(wmKeyMap *keymap,
}
}
-/**
- * Filter & optionally remove key-map items,
- * intended for versioning, but may be used in other situations too.
- */
void BKE_keyconfig_pref_filter_items(struct UserDef *userdef,
const struct wmKeyConfigFilterItemParams *params,
bool (*filter_fn)(wmKeyMapItem *kmi, void *user_data),
diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c
index a2da59bca58..af0d91d29fc 100644
--- a/source/blender/blenkernel/intern/lattice.c
+++ b/source/blender/blenkernel/intern/lattice.c
@@ -197,6 +197,7 @@ IDTypeInfo IDType_ID_LT = {
.name_plural = "lattices",
.translation_context = BLT_I18NCONTEXT_ID_LATTICE,
.flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = lattice_init_data,
.copy_data = lattice_copy_data,
@@ -204,6 +205,7 @@ IDTypeInfo IDType_ID_LT = {
.make_local = NULL,
.foreach_id = lattice_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = lattice_blend_write,
diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c
index 6aa8e78c4f6..1484d35f28a 100644
--- a/source/blender/blenkernel/intern/layer.c
+++ b/source/blender/blenkernel/intern/layer.c
@@ -77,7 +77,9 @@ static const short g_base_collection_flags = (BASE_VISIBLE_DEPSGRAPH | BASE_VISI
/* prototype */
static void object_bases_iterator_next(BLI_Iterator *iter, const int flag);
-/*********************** Layer Collections and bases *************************/
+/* -------------------------------------------------------------------- */
+/** \name Layer Collections and Bases
+ * \{ */
static LayerCollection *layer_collection_add(ListBase *lb_parent, Collection *collection)
{
@@ -113,12 +115,14 @@ static Base *object_base_new(Object *ob)
return base;
}
-/********************************* View Layer ********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Layer
+ * \{ */
/* RenderLayer */
-/* Returns the default view layer to view in workspaces if there is
- * none linked to the workspace yet. */
ViewLayer *BKE_view_layer_default_view(const Scene *scene)
{
LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
@@ -131,7 +135,6 @@ ViewLayer *BKE_view_layer_default_view(const Scene *scene)
return scene->view_layers.first;
}
-/* Returns the default view layer to render if we need to render just one. */
ViewLayer *BKE_view_layer_default_render(const Scene *scene)
{
LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
@@ -144,7 +147,6 @@ ViewLayer *BKE_view_layer_default_render(const Scene *scene)
return scene->view_layers.first;
}
-/* Returns view layer with matching name, or NULL if not found. */
ViewLayer *BKE_view_layer_find(const Scene *scene, const char *layer_name)
{
LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
@@ -156,11 +158,6 @@ ViewLayer *BKE_view_layer_find(const Scene *scene, const char *layer_name)
return NULL;
}
-/**
- * This is a placeholder to know which areas of the code need to be addressed
- * for the Workspace changes. Never use this, you should typically get the
- * active layer from the context or window.
- */
ViewLayer *BKE_view_layer_context_active_PLACEHOLDER(const Scene *scene)
{
BLI_assert(scene->view_layers.first);
@@ -198,10 +195,6 @@ static void layer_collection_exclude_all(LayerCollection *layer_collection)
}
}
-/**
- * Add a new view layer
- * by default, a view layer has the master collection
- */
ViewLayer *BKE_view_layer_add(Scene *scene,
const char *name,
ViewLayer *view_layer_source,
@@ -261,9 +254,6 @@ void BKE_view_layer_free(ViewLayer *view_layer)
BKE_view_layer_free_ex(view_layer, true);
}
-/**
- * Free (or release) any data used by this ViewLayer.
- */
void BKE_view_layer_free_ex(ViewLayer *view_layer, const bool do_id_user)
{
view_layer->basact = NULL;
@@ -304,9 +294,6 @@ void BKE_view_layer_free_ex(ViewLayer *view_layer, const bool do_id_user)
MEM_freeN(view_layer);
}
-/**
- * Tag all the selected objects of a render-layer.
- */
void BKE_view_layer_selected_objects_tag(ViewLayer *view_layer, const int tag)
{
LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
@@ -332,13 +319,6 @@ static bool find_scene_collection_in_scene_collections(ListBase *lb, const Layer
return false;
}
-/**
- * Fallback for when a Scene has no camera to use
- *
- * \param view_layer: in general you want to use the same ViewLayer that is used
- * for depsgraph. If rendering you pass the scene active layer, when viewing in the viewport
- * you want to get ViewLayer from context.
- */
Object *BKE_view_layer_camera_find(ViewLayer *view_layer)
{
LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
@@ -350,9 +330,6 @@ Object *BKE_view_layer_camera_find(ViewLayer *view_layer)
return NULL;
}
-/**
- * Find the ViewLayer a LayerCollection belongs to
- */
ViewLayer *BKE_view_layer_find_from_collection(const Scene *scene, LayerCollection *lc)
{
LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
@@ -422,7 +399,12 @@ void BKE_view_layer_base_select_and_set_active(struct ViewLayer *view_layer, Bas
}
}
-/**************************** Copy View Layer and Layer Collections ***********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Copy View Layer and Layer Collections
+ * \{ */
+
static void layer_aov_copy_data(ViewLayer *view_layer_dst,
const ViewLayer *view_layer_src,
ListBase *aovs_dst,
@@ -471,11 +453,6 @@ static void layer_collections_copy_data(ViewLayer *view_layer_dst,
}
}
-/**
- * Only copy internal data of ViewLayer from source to already allocated/initialized destination.
- *
- * \param flag: Copying options (see BKE_lib_id.h's LIB_ID_COPY_... flags for more).
- */
void BKE_view_layer_copy_data(Scene *scene_dst,
const Scene *UNUSED(scene_src),
ViewLayer *view_layer_dst,
@@ -620,26 +597,17 @@ static bool layer_collection_hidden(ViewLayer *view_layer, LayerCollection *lc)
return false;
}
-/**
- * Get the collection for a given index
- */
LayerCollection *BKE_layer_collection_from_index(ViewLayer *view_layer, const int index)
{
int i = 0;
return collection_from_index(&view_layer->layer_collections, index, &i);
}
-/**
- * Get the active collection
- */
LayerCollection *BKE_layer_collection_get_active(ViewLayer *view_layer)
{
return view_layer->active_collection;
}
-/*
- * Activate collection
- */
bool BKE_layer_collection_activate(ViewLayer *view_layer, LayerCollection *lc)
{
if (lc->flag & LAYER_COLLECTION_EXCLUDE) {
@@ -650,9 +618,6 @@ bool BKE_layer_collection_activate(ViewLayer *view_layer, LayerCollection *lc)
return true;
}
-/**
- * Activate first parent collection
- */
LayerCollection *BKE_layer_collection_activate_parent(ViewLayer *view_layer, LayerCollection *lc)
{
CollectionParent *parent = lc->collection->parents.first;
@@ -690,10 +655,6 @@ static int collection_count(const ListBase *lb)
return i;
}
-/**
- * Get the total number of collections
- * (including all the nested collections)
- */
int BKE_layer_collection_count(const ViewLayer *view_layer)
{
return collection_count(&view_layer->layer_collections);
@@ -721,16 +682,16 @@ static int index_from_collection(ListBase *lb, const LayerCollection *lc, int *i
return -1;
}
-/**
- * Return -1 if not found
- */
int BKE_layer_collection_findindex(ViewLayer *view_layer, const LayerCollection *lc)
{
int i = 0;
return index_from_collection(&view_layer->layer_collections, lc, &i);
}
-/*********************************** Syncing *********************************
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Syncing
*
* The layer collection tree mirrors the scene collection tree. Whenever that
* changes we need to synchronize them so that there is a corresponding layer
@@ -740,9 +701,9 @@ int BKE_layer_collection_findindex(ViewLayer *view_layer, const LayerCollection
*
* The view layer also contains a list of bases for each object that exists
* in at least one layer collection. That list is also synchronized here, and
- * stores state like selection. */
-
-/* This API allows to temporarily forbid resync of LayerCollections.
+ * stores state like selection.
+ *
+ * This API allows to temporarily forbid resync of LayerCollections.
*
* This can greatly improve performances in cases where those functions get
* called a lot (e.g. during massive remappings of IDs).
@@ -751,19 +712,20 @@ int BKE_layer_collection_findindex(ViewLayer *view_layer, const LayerCollection
* code must ensures it resync LayerCollections before any UI/Event loop
* handling can happen.
*
- * WARNING: This is not threadsafe at all, only use from main thread.
+ * \warning This is not threadsafe at all, only use from main thread.
*
- * NOTE: It is probably needed to use #BKE_main_collection_sync_remap instead
+ * \note It is probably needed to use #BKE_main_collection_sync_remap instead
* of just #BKE_main_collection_sync after disabling LayerCollection resync,
* unless it is absolutely certain that no ID remapping (or any other process
* that may invalidate the caches) will happen while it is disabled.
*
- * NOTE: This is a quick and safe band-aid around the long-known issue
+ * \note This is a quick and safe band-aid around the long-known issue
* regarding this resync process.
* Proper fix would be to make resync itself lazy, i.e. only happen
* when actually needed.
* See also T73411.
- */
+ * \{ */
+
static bool no_resync = false;
void BKE_layer_collection_resync_forbid(void)
@@ -1220,11 +1182,6 @@ static bool view_layer_objects_base_cache_validate(ViewLayer *UNUSED(view_layer)
}
#endif
-/**
- * Update view layer collection tree from collections used in the scene.
- * This is used when collections are removed or added, both while editing
- * and on file loaded in case linked data changed or went missing.
- */
void BKE_layer_collection_sync(const Scene *scene, ViewLayer *view_layer)
{
if (no_resync) {
@@ -1377,14 +1334,12 @@ void BKE_main_collection_sync_remap(const Main *bmain)
BKE_main_collection_sync(bmain);
}
-/* ---------------------------------------------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Selection
+ * \{ */
-/**
- * Select all the objects of this layer collection
- *
- * It also select the objects that are in nested collections.
- * \note Recursive
- */
bool BKE_layer_collection_objects_select(ViewLayer *view_layer, LayerCollection *lc, bool deselect)
{
if (lc->collection->flag & COLLECTION_HIDE_SELECT) {
@@ -1461,9 +1416,12 @@ bool BKE_layer_collection_has_layer_collection(LayerCollection *lc_parent,
return false;
}
-/* ---------------------------------------------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Visibility
+ * \{ */
-/* Update after toggling visibility of an object base. */
void BKE_base_set_visible(Scene *scene, ViewLayer *view_layer, Base *base, bool extend)
{
if (!extend) {
@@ -1536,6 +1494,12 @@ bool BKE_object_is_visible_in_viewport(const View3D *v3d, const struct Object *o
return true;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Collection Isolation & Local View
+ * \{ */
+
static void layer_collection_flag_set_recursive(LayerCollection *lc, const int flag)
{
lc->flag |= flag;
@@ -1552,14 +1516,6 @@ static void layer_collection_flag_unset_recursive(LayerCollection *lc, const int
}
}
-/**
- * Isolate the collection - hide all other collections but this one.
- * Make sure to show all the direct parents and all children of the layer collection as well.
- * When extending we simply show the collections and its direct family.
- *
- * If the collection or any of its parents is disabled, make it enabled.
- * Don't change the children disable state though.
- */
void BKE_layer_collection_isolate_global(Scene *scene,
ViewLayer *view_layer,
LayerCollection *lc,
@@ -1668,9 +1624,6 @@ void BKE_layer_collection_local_sync(ViewLayer *view_layer, const View3D *v3d)
}
}
-/**
- * Sync the local collection for all the 3D Viewports.
- */
void BKE_layer_collection_local_sync_all(const Main *bmain)
{
if (no_resync) {
@@ -1694,11 +1647,6 @@ void BKE_layer_collection_local_sync_all(const Main *bmain)
}
}
-/**
- * Isolate the collection locally
- *
- * Same as BKE_layer_collection_isolate_local but for a viewport
- */
void BKE_layer_collection_isolate_local(ViewLayer *view_layer,
const View3D *v3d,
LayerCollection *lc,
@@ -1771,11 +1719,6 @@ static void layer_collection_bases_hide_recursive(ViewLayer *view_layer, LayerCo
}
}
-/**
- * Hide/show all the elements of a collection.
- * Don't change the collection children enable/disable state,
- * but it may change it for the collection itself.
- */
void BKE_layer_collection_set_visible(ViewLayer *view_layer,
LayerCollection *lc,
const bool visible,
@@ -1862,9 +1805,6 @@ static LayerCollection *find_layer_collection_by_scene_collection(LayerCollectio
return NULL;
}
-/**
- * Return the first matching LayerCollection in the ViewLayer for the Collection.
- */
LayerCollection *BKE_layer_collection_first_from_scene_collection(const ViewLayer *view_layer,
const Collection *collection)
{
@@ -1878,17 +1818,11 @@ LayerCollection *BKE_layer_collection_first_from_scene_collection(const ViewLaye
return NULL;
}
-/**
- * See if view layer has the scene collection linked directly, or indirectly (nested)
- */
bool BKE_view_layer_has_collection(const ViewLayer *view_layer, const Collection *collection)
{
return BKE_layer_collection_first_from_scene_collection(view_layer, collection) != NULL;
}
-/**
- * See if the object is in any of the scene layers of the scene
- */
bool BKE_scene_has_object(Scene *scene, Object *ob)
{
LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
@@ -1999,6 +1933,8 @@ static void objects_iterator_end(BLI_Iterator *iter)
object_bases_iterator_end(iter);
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name BKE_view_layer_selected_objects_iterator
* See: #FOREACH_SELECTED_OBJECT_BEGIN
@@ -2188,11 +2124,10 @@ void BKE_view_layer_bases_in_mode_iterator_end(BLI_Iterator *UNUSED(iter))
/** \} */
-/* Evaluation. */
+/* -------------------------------------------------------------------- */
+/** \name Evaluation
+ * \{ */
-/* Applies object's restrict flags on top of flags coming from the collection
- * and stores those in base->flag. BASE_VISIBLE_DEPSGRAPH ignores viewport flags visibility
- * (i.e., restriction and local collection). */
void BKE_base_eval_flags(Base *base)
{
/* Apply collection flags. */
@@ -2251,6 +2186,12 @@ void BKE_layer_eval_view_layer_indexed(struct Depsgraph *depsgraph,
layer_eval_view_layer(depsgraph, scene, view_layer);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Blend File I/O
+ * \{ */
+
static void write_layer_collections(BlendWriter *writer, ListBase *lb)
{
LISTBASE_FOREACH (LayerCollection *, lc, lb) {
@@ -2371,6 +2312,8 @@ void BKE_view_layer_blend_read_lib(BlendLibReader *reader, Library *lib, ViewLay
IDP_BlendReadLib(reader, view_layer->id_properties);
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Shader AOV
* \{ */
@@ -2455,12 +2398,6 @@ static void bke_view_layer_verify_aov_cb(void *userdata,
}
}
-/* Update the naming and conflicts of the AOVs.
- *
- * Name must be unique between all AOVs.
- * Conflicts with render passes will show a conflict icon. Reason is that switching a render
- * engine or activating a render pass could lead to other conflicts that wouldn't be that clear
- * for the user. */
void BKE_view_layer_verify_aov(struct RenderEngine *engine,
struct Scene *scene,
struct ViewLayer *view_layer)
@@ -2478,7 +2415,6 @@ void BKE_view_layer_verify_aov(struct RenderEngine *engine,
BLI_ghash_free(name_count, MEM_freeN, NULL);
}
-/* Check if the given view layer has at least one valid AOV. */
bool BKE_view_layer_has_valid_aov(ViewLayer *view_layer)
{
LISTBASE_FOREACH (ViewLayerAOV *, aov, &view_layer->aovs) {
diff --git a/source/blender/blenkernel/intern/layer_utils.c b/source/blender/blenkernel/intern/layer_utils.c
index 48179e0c3bf..3760fe8a976 100644
--- a/source/blender/blenkernel/intern/layer_utils.c
+++ b/source/blender/blenkernel/intern/layer_utils.c
@@ -193,13 +193,6 @@ bool BKE_view_layer_filter_edit_mesh_has_edges(const Object *ob, void *UNUSED(us
return false;
}
-/**
- * Use this in rare cases we need to detect a pair of objects (active, selected).
- * This returns the other non-active selected object.
- *
- * Returns NULL with it finds multiple other selected objects
- * as behavior in this case would be random from the user perspective.
- */
Object *BKE_view_layer_non_active_selected_object(struct ViewLayer *view_layer,
const struct View3D *v3d)
{
@@ -221,4 +214,5 @@ Object *BKE_view_layer_non_active_selected_object(struct ViewLayer *view_layer,
FOREACH_SELECTED_OBJECT_END;
return ob_result;
}
+
/** \} */
diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c
index cd5b266eb75..692e27731c5 100644
--- a/source/blender/blenkernel/intern/lib_id.c
+++ b/source/blender/blenkernel/intern/lib_id.c
@@ -89,7 +89,6 @@
static CLG_LogRef LOG = {.identifier = "bke.lib_id"};
-/* Empty shell mostly, but needed for read code. */
IDTypeInfo IDType_ID_LINK_PLACEHOLDER = {
.id_code = ID_LINK_PLACEHOLDER,
.id_filter = 0,
@@ -99,6 +98,7 @@ IDTypeInfo IDType_ID_LINK_PLACEHOLDER = {
.name_plural = "link_placeholders",
.translation_context = BLT_I18NCONTEXT_ID_ID,
.flags = IDTYPE_FLAGS_NO_COPY | IDTYPE_FLAGS_NO_LIBLINKING,
+ .asset_type_info = NULL,
.init_data = NULL,
.copy_data = NULL,
@@ -106,6 +106,8 @@ IDTypeInfo IDType_ID_LINK_PLACEHOLDER = {
.make_local = NULL,
.foreach_id = NULL,
.foreach_cache = NULL,
+ .foreach_path = NULL,
+ .owner_get = NULL,
.blend_write = NULL,
.blend_read_data = NULL,
@@ -124,18 +126,56 @@ IDTypeInfo IDType_ID_LINK_PLACEHOLDER = {
/* ************* general ************************ */
/**
+ * Rewrites a relative path to be relative to the main file - unless the path is
+ * absolute, in which case it is not altered.
+ */
+static bool lib_id_library_local_paths_callback(BPathForeachPathData *bpath_data,
+ char *r_path_dst,
+ const char *path_src)
+{
+ const char **data = bpath_data->user_data;
+ /* be sure there is low chance of the path being too short */
+ char filepath[(FILE_MAXDIR * 2) + FILE_MAXFILE];
+ const char *base_new = data[0];
+ const char *base_old = data[1];
+
+ if (BLI_path_is_rel(base_old)) {
+ CLOG_ERROR(&LOG, "old base path '%s' is not absolute.", base_old);
+ return false;
+ }
+
+ /* Make referenced file absolute. This would be a side-effect of
+ * BLI_path_normalize, but we do it explicitly so we know if it changed. */
+ BLI_strncpy(filepath, path_src, FILE_MAX);
+ if (BLI_path_abs(filepath, base_old)) {
+ /* Path was relative and is now absolute. Remap.
+ * Important BLI_path_normalize runs before the path is made relative
+ * because it won't work for paths that start with "//../" */
+ BLI_path_normalize(base_new, filepath);
+ BLI_path_rel(filepath, base_new);
+ BLI_strncpy(r_path_dst, filepath, FILE_MAX);
+ return true;
+ }
+
+ /* Path was not relative to begin with. */
+ return false;
+}
+
+/**
* This has to be called from each make_local_* func, we could call from BKE_lib_id_make_local()
* but then the make local functions would not be self contained.
* Also note that the id _must_ have a library - campbell */
+/* TODO: This can probably be replaced by an ID-level version of #BKE_bpath_relative_rebase. */
static void lib_id_library_local_paths(Main *bmain, Library *lib, ID *id)
{
const char *bpath_user_data[2] = {BKE_main_blendfile_path(bmain), lib->filepath_abs};
- BKE_bpath_traverse_id(bmain,
- id,
- BKE_bpath_relocate_visitor,
- BKE_BPATH_TRAVERSE_SKIP_MULTIFILE,
- (void *)bpath_user_data);
+ BKE_bpath_foreach_path_id(
+ &(BPathForeachPathData){.bmain = bmain,
+ .callback_function = lib_id_library_local_paths_callback,
+ .flag = BKE_BPATH_FOREACH_PATH_SKIP_MULTIFILE,
+ .user_data = (void *)bpath_user_data},
+ id);
}
static int lib_id_clear_library_data_users_update_cb(LibraryIDLinkCallbackData *cb_data)
@@ -149,12 +189,6 @@ static int lib_id_clear_library_data_users_update_cb(LibraryIDLinkCallbackData *
return IDWALK_RET_NOP;
}
-/**
- * Pull an ID out of a library (make it local). Only call this for IDs that
- * don't have other library users.
- *
- * \param flags Same set of `LIB_ID_MAKELOCAL_` flags as passed to `BKE_lib_id_make_local`.
- */
void BKE_lib_id_clear_library_data(Main *bmain, ID *id, const int flags)
{
const bool id_in_mainlist = (id->tag & LIB_TAG_NO_MAIN) == 0 &&
@@ -179,8 +213,14 @@ void BKE_lib_id_clear_library_data(Main *bmain, ID *id, const int flags)
BKE_lib_libblock_session_uuid_renew(id);
}
- if ((flags & LIB_ID_MAKELOCAL_ASSET_DATA_CLEAR) != 0 && id->asset_data != NULL) {
- BKE_asset_metadata_free(&id->asset_data);
+ if (ID_IS_ASSET(id)) {
+ if ((flags & LIB_ID_MAKELOCAL_ASSET_DATA_CLEAR) != 0) {
+ BKE_asset_metadata_free(&id->asset_data);
+ }
+ else {
+ /* Assets should always have a fake user. Ensure this is the case after "Make Local". */
+ id_fake_user_set(id);
+ }
}
/* We need to tag this IDs and all of its users, conceptually new local ID and original linked
@@ -228,14 +268,6 @@ void id_lib_indirect_weak_link(ID *id)
}
}
-/**
- * Ensure we have a real user
- *
- * \note Now that we have flags, we could get rid of the 'fake_user' special case,
- * flags are enough to ensure we always have a real user.
- * However, #ID_REAL_USERS is used in several places outside of core lib.c,
- * so think we can wait later to make this change.
- */
void id_us_ensure_real(ID *id)
{
if (id) {
@@ -266,10 +298,6 @@ void id_us_clear_real(ID *id)
}
}
-/**
- * Same as \a id_us_plus, but does not handle lib indirect -> extern.
- * Only used by readfile.c so far, but simpler/safer to keep it here nonetheless.
- */
void id_us_plus_no_lib(ID *id)
{
if (id) {
@@ -294,7 +322,6 @@ void id_us_plus(ID *id)
}
}
-/* decrements the user count for *id. */
void id_us_min(ID *id)
{
if (id) {
@@ -410,10 +437,6 @@ static int lib_id_expand_local_cb(LibraryIDLinkCallbackData *cb_data)
return IDWALK_RET_NOP;
}
-/**
- * Expand ID usages of given id as 'extern' (and no more indirect) linked data.
- * Used by ID copy/make_local functions.
- */
void BKE_lib_id_expand_local(Main *bmain, ID *id, const int flags)
{
BKE_library_foreach_ID_link(
@@ -431,9 +454,6 @@ static void lib_id_copy_ensure_local(Main *bmain, const ID *old_id, ID *new_id,
}
}
-/**
- * Generic 'make local' function, works for most of data-block types...
- */
void BKE_lib_id_make_local_generic(Main *bmain, ID *id, const int flags)
{
if (!ID_IS_LINKED(id)) {
@@ -503,15 +523,6 @@ void BKE_lib_id_make_local_generic(Main *bmain, ID *id, const int flags)
}
}
-/**
- * Calls the appropriate make_local method for the block, unless test is set.
- *
- * \note Always set #ID.newid pointer in case it gets duplicated.
- *
- * \param flags: Special flag used when making a whole library's content local,
- * it needs specific handling.
- * \return true is the ID has successfully been made local.
- */
bool BKE_lib_id_make_local(Main *bmain, ID *id, const int flags)
{
const bool lib_local = (flags & LIB_ID_MAKELOCAL_FULL_LIBRARY) != 0;
@@ -586,27 +597,6 @@ bool BKE_id_copy_is_allowed(const ID *id)
#undef LIB_ID_TYPES_NOCOPY
}
-/**
- * Generic entry point for copying a data-block (new API).
- *
- * \note Copy is generally only affecting the given data-block
- * (no ID used by copied one will be affected, besides usercount).
- * There are exceptions though:
- * - Embedded IDs (root node trees and master collections) are always copied with their owner.
- * - If #LIB_ID_COPY_ACTIONS is defined, actions used by animdata will be duplicated.
- * - If #LIB_ID_COPY_SHAPEKEY is defined, shapekeys will be duplicated.
- * - If #LIB_ID_CREATE_LOCAL is defined, root node trees will be deep-duplicated recursively.
- *
- * \note Usercount of new copy is always set to 1.
- *
- * \param bmain: Main database, may be NULL only if LIB_ID_CREATE_NO_MAIN is specified.
- * \param id: Source data-block.
- * \param r_newid: Pointer to new (copied) ID pointer, may be NULL. Used to allow copying into
- * already allocated memory.
- * \param flag: Set of copy options, see DNA_ID.h enum for details (leave to zero for default,
- * full copy).
- * \return NULL when copying that ID type is not supported, the new copy otherwise.
- */
ID *BKE_id_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag)
{
ID *newid = (r_newid != NULL) ? *r_newid : NULL;
@@ -669,19 +659,11 @@ ID *BKE_id_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag)
return newid;
}
-/**
- * Invokes the appropriate copy method for the block and returns the result in
- * newid, unless test. Returns true if the block can be copied.
- */
ID *BKE_id_copy(Main *bmain, const ID *id)
{
return BKE_id_copy_ex(bmain, id, NULL, LIB_ID_COPY_DEFAULT);
}
-/**
- * Invokes the appropriate copy method for the block and returns the result in
- * newid, unless test. Returns true if the block can be copied.
- */
ID *BKE_id_copy_for_duplicate(Main *bmain,
ID *id,
const eDupli_ID_Flags duplicate_flags,
@@ -762,31 +744,16 @@ static void id_swap(Main *bmain, ID *id_a, ID *id_b, const bool do_full_id)
}
}
-/**
- * Does a mere memory swap over the whole IDs data (including type-specific memory).
- * \note Most internal ID data itself is not swapped (only IDProperties are).
- *
- * \param bmain: May be NULL, in which case there will be no remapping of internal pointers to
- * itself.
- */
void BKE_lib_id_swap(Main *bmain, ID *id_a, ID *id_b)
{
id_swap(bmain, id_a, id_b, false);
}
-/**
- * Does a mere memory swap over the whole IDs data (including type-specific memory).
- * \note All internal ID data itself is also swapped.
- *
- * \param bmain: May be NULL, in which case there will be no remapping of internal pointers to
- * itself.
- */
void BKE_lib_id_swap_full(Main *bmain, ID *id_a, ID *id_b)
{
id_swap(bmain, id_a, id_b, true);
}
-/** Does *not* set ID->newid pointer. */
bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop)
{
ID *newid = NULL;
@@ -851,7 +818,6 @@ static int libblock_management_us_min(LibraryIDLinkCallbackData *cb_data)
return IDWALK_RET_NOP;
}
-/** Add a 'NO_MAIN' data-block to given main (also sets usercounts of its IDs if needed). */
void BKE_libblock_management_main_add(Main *bmain, void *idv)
{
ID *id = idv;
@@ -885,7 +851,6 @@ void BKE_libblock_management_main_add(Main *bmain, void *idv)
BKE_lib_libblock_session_uuid_ensure(id);
}
-/** Remove a data-block from given main (set it to 'NO_MAIN' status). */
void BKE_libblock_management_main_remove(Main *bmain, void *idv)
{
ID *id = idv;
@@ -930,9 +895,6 @@ void BKE_libblock_management_usercounts_clear(Main *bmain, void *idv)
id->tag |= LIB_TAG_NO_USER_REFCOUNT;
}
-/**
- * Clear or set given tags for all ids in listbase (runtime tags).
- */
void BKE_main_id_tag_listbase(ListBase *lb, const int tag, const bool value)
{
ID *id;
@@ -949,9 +911,6 @@ void BKE_main_id_tag_listbase(ListBase *lb, const int tag, const bool value)
}
}
-/**
- * Clear or set given tags for all ids of given type in bmain (runtime tags).
- */
void BKE_main_id_tag_idcode(struct Main *mainvar,
const short type,
const int tag,
@@ -962,9 +921,6 @@ void BKE_main_id_tag_idcode(struct Main *mainvar,
BKE_main_id_tag_listbase(lb, tag, value);
}
-/**
- * Clear or set given tags for all ids in bmain (runtime tags).
- */
void BKE_main_id_tag_all(struct Main *mainvar, const int tag, const bool value)
{
ListBase *lbarray[INDEX_ID_MAX];
@@ -976,9 +932,6 @@ void BKE_main_id_tag_all(struct Main *mainvar, const int tag, const bool value)
}
}
-/**
- * Clear or set given flags for all ids in listbase (persistent flags).
- */
void BKE_main_id_flag_listbase(ListBase *lb, const int flag, const bool value)
{
ID *id;
@@ -995,9 +948,6 @@ void BKE_main_id_flag_listbase(ListBase *lb, const int flag, const bool value)
}
}
-/**
- * Clear or set given flags for all ids in bmain (persistent flags).
- */
void BKE_main_id_flag_all(Main *bmain, const int flag, const bool value)
{
ListBase *lbarray[INDEX_ID_MAX];
@@ -1063,9 +1013,6 @@ void BKE_main_lib_objects_recalc_all(Main *bmain)
*
* **************************** */
-/**
- * Get allocation size of a given data-block type and optionally allocation name.
- */
size_t BKE_libblock_get_alloc_info(short type, const char **name)
{
const IDTypeInfo *id_type = BKE_idtype_get_info_from_idcode(type);
@@ -1083,10 +1030,6 @@ size_t BKE_libblock_get_alloc_info(short type, const char **name)
return id_type->struct_size;
}
-/**
- * Allocates and returns memory of the right size for the specified block type,
- * initialized to zero.
- */
void *BKE_libblock_alloc_notest(short type)
{
const char *name;
@@ -1098,12 +1041,6 @@ void *BKE_libblock_alloc_notest(short type)
return NULL;
}
-/**
- * Allocates and returns a block of the specified type, with the specified name
- * (adjusted as necessary to ensure uniqueness), and appended to the specified list.
- * The user count is set to 1, all other content (apart from name and links) being
- * initialized to zero.
- */
void *BKE_libblock_alloc(Main *bmain, short type, const char *name, const int flag)
{
BLI_assert((flag & LIB_ID_CREATE_NO_ALLOCATE) == 0);
@@ -1166,10 +1103,6 @@ void *BKE_libblock_alloc(Main *bmain, short type, const char *name, const int fl
return id;
}
-/**
- * Initialize an ID of given type, such that it has valid 'empty' data.
- * ID is assumed to be just calloc'ed.
- */
void BKE_libblock_init_empty(ID *id)
{
const IDTypeInfo *idtype_info = BKE_idtype_get_info_from_id(id);
@@ -1187,12 +1120,6 @@ void BKE_libblock_init_empty(ID *id)
/* ********** ID session-wise UUID management. ********** */
static uint global_session_uuid = 0;
-/**
- * Generate a session-wise uuid for the given \a id.
- *
- * \note "session-wise" here means while editing a given .blend file. Once a new .blend file is
- * loaded or created, undo history is cleared/reset, and so is the uuid counter.
- */
void BKE_lib_libblock_session_uuid_ensure(ID *id)
{
if (id->session_uuid == MAIN_ID_SESSION_UUID_UNSET) {
@@ -1206,25 +1133,12 @@ void BKE_lib_libblock_session_uuid_ensure(ID *id)
}
}
-/**
- * Re-generate a new session-wise uuid for the given \a id.
- *
- * \warning This has a few very specific use-cases, no other usage is expected currently:
- * - To handle UI-related data-blocks that are kept across new file reading, when we do keep
- * existing UI.
- * - For IDs that are made local without needing any copying.
- */
void BKE_lib_libblock_session_uuid_renew(ID *id)
{
id->session_uuid = MAIN_ID_SESSION_UUID_UNSET;
BKE_lib_libblock_session_uuid_ensure(id);
}
-/**
- * Generic helper to create a new empty data-block of given type in given \a bmain database.
- *
- * \param name: can be NULL, in which case we get default name for this ID type.
- */
void *BKE_id_new(Main *bmain, const short type, const char *name)
{
BLI_assert(bmain != NULL);
@@ -1239,11 +1153,6 @@ void *BKE_id_new(Main *bmain, const short type, const char *name)
return id;
}
-/**
- * Generic helper to create a new temporary empty data-block of given type,
- * *outside* of any Main database.
- *
- * \param name: can be NULL, in which case we get default name for this ID type. */
void *BKE_id_new_nomain(const short type, const char *name)
{
if (name == NULL) {
@@ -1357,7 +1266,6 @@ void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int ori
*r_newid = new_id;
}
-/* used everywhere in blenkernel */
void *BKE_libblock_copy(Main *bmain, const ID *id)
{
ID *idn;
@@ -1368,6 +1276,7 @@ void *BKE_libblock_copy(Main *bmain, const ID *id)
}
/* ***************** ID ************************ */
+
ID *BKE_libblock_find_name(struct Main *bmain, const short type, const char *name)
{
ListBase *lb = which_libbase(bmain, type);
@@ -1389,14 +1298,6 @@ struct ID *BKE_libblock_find_session_uuid(Main *bmain,
return NULL;
}
-/**
- * Sort given \a id into given \a lb list, using case-insensitive comparison of the id names.
- *
- * \note All other IDs beside given one are assumed already properly sorted in the list.
- *
- * \param id_sorting_hint: Ignored if NULL. Otherwise, used to check if we can insert \a id
- * immediately before or after that pointer. It must always be into given \a lb list.
- */
void id_sort_by_name(ListBase *lb, ID *id, ID *id_sorting_hint)
{
#define ID_SORT_STEP_SIZE 512
@@ -1754,16 +1655,6 @@ static bool check_for_dupid(ListBase *lb, ID *id, char *name, ID **r_id_sorting_
#undef MIN_NUMBER
#undef MAX_NUMBER
-/**
- * Ensures given ID has a unique name in given listbase.
- *
- * Only for local IDs (linked ones already have a unique ID in their library).
- *
- * \param do_linked_data: if true, also ensure a unique name in case the given \a id is linked
- * (otherwise, just ensure that it is properly sorted).
- *
- * \return true if a new name had to be created.
- */
bool BKE_id_new_name_validate(ListBase *lb, ID *id, const char *tname, const bool do_linked_data)
{
bool result = false;
@@ -1813,7 +1704,6 @@ bool BKE_id_new_name_validate(ListBase *lb, ID *id, const char *tname, const boo
return result;
}
-/* next to indirect usage in read/writefile also in editobject.c scene.c */
void BKE_main_id_newptr_and_tag_clear(Main *bmain)
{
ID *id;
@@ -1936,30 +1826,20 @@ static void library_make_local_copying_check(ID *id,
BLI_gset_remove(loop_tags, id, NULL);
}
-/**
- * Make linked data-blocks local.
- *
- * \param bmain: Almost certainly global main.
- * \param lib: If not NULL, only make local data-blocks from this library.
- * \param untagged_only: If true, only make local data-blocks not tagged with
- * LIB_TAG_PRE_EXISTING.
- * \param set_fake: If true, set fake user on all localized data-blocks
- * (except group and objects ones).
- */
/* NOTE: Old (2.77) version was simply making (tagging) data-blocks as local,
* without actually making any check whether they were also indirectly used or not...
*
* Current version uses regular id_make_local callback, with advanced pre-processing step to
* detect all cases of IDs currently indirectly used, but which will be used by local data only
* once this function is finished. This allows to avoid any unneeded duplication of IDs, and
- * hence all time lost afterwards to remove orphaned linked data-blocks...
- */
+ * hence all time lost afterwards to remove orphaned linked data-blocks. */
void BKE_library_make_local(Main *bmain,
const Library *lib,
GHash *old_to_new_ids,
const bool untagged_only,
const bool set_fake)
{
+
ListBase *lbarray[INDEX_ID_MAX];
LinkNode *todo_ids = NULL;
@@ -2233,10 +2113,6 @@ void BKE_library_make_local(Main *bmain,
#endif
}
-/**
- * Use after setting the ID's name
- * When name exists: call 'new_id'
- */
void BLI_libblock_ensure_unique_name(Main *bmain, const char *name)
{
ListBase *lb;
@@ -2256,9 +2132,6 @@ void BLI_libblock_ensure_unique_name(Main *bmain, const char *name)
}
}
-/**
- * Sets the name of a block to name, suitably adjusted for uniqueness.
- */
void BKE_libblock_rename(Main *bmain, ID *id, const char *name)
{
BLI_assert(!ID_IS_LINKED(id));
@@ -2268,16 +2141,6 @@ void BKE_libblock_rename(Main *bmain, ID *id, const char *name)
}
}
-/**
- * Generate full name of the data-block (without ID code, but with library if any).
- *
- * \note Result is unique to a given ID type in a given Main database.
- *
- * \param name: An allocated string of minimal length #MAX_ID_FULL_NAME,
- * will be filled with generated string.
- * \param separator_char: Character to use for separating name and library name. Can be 0 to use
- * default (' ').
- */
void BKE_id_full_name_get(char name[MAX_ID_FULL_NAME], const ID *id, char separator_char)
{
strcpy(name, id->name + 2);
@@ -2294,19 +2157,6 @@ void BKE_id_full_name_get(char name[MAX_ID_FULL_NAME], const ID *id, char separa
}
}
-/**
- * Generate full name of the data-block (without ID code, but with library if any),
- * with a 2 to 3 character prefix prepended indicating whether it comes from a library,
- * is overriding, has a fake or no user, etc.
- *
- * \note Result is unique to a given ID type in a given Main database.
- *
- * \param name: An allocated string of minimal length #MAX_ID_FULL_NAME_UI,
- * will be filled with generated string.
- * \param separator_char: Character to use for separating name and library name. Can be 0 to use
- * default (' ').
- * \param r_prefix_len: The length of the prefix added.
- */
void BKE_id_full_name_ui_prefix_get(char name[MAX_ID_FULL_NAME_UI],
const ID *id,
const bool add_lib_hint,
@@ -2328,11 +2178,6 @@ void BKE_id_full_name_ui_prefix_get(char name[MAX_ID_FULL_NAME_UI],
}
}
-/**
- * Generate a concatenation of ID name (including two-chars type code) and its lib name, if any.
- *
- * \return A unique allocated string key for any ID in the whole Main database.
- */
char *BKE_id_to_unique_string_key(const struct ID *id)
{
if (!ID_IS_LINKED(id)) {
@@ -2356,10 +2201,6 @@ void BKE_id_tag_clear_atomic(ID *id, int tag)
atomic_fetch_and_and_int32(&id->tag, ~tag);
}
-/**
- * Check that given ID pointer actually is in G_MAIN.
- * Main intended use is for debug asserts in places we cannot easily get rid of G_Main...
- */
bool BKE_id_is_in_global_main(ID *id)
{
/* We do not want to fail when id is NULL here, even though this is a bit strange behavior...
@@ -2406,10 +2247,6 @@ static int id_order_compare(const void *a, const void *b)
return strcmp(id_a->name, id_b->name);
}
-/**
- * Returns ordered list of data-blocks for display in the UI.
- * Result is list of LinkData of IDs that must be freed.
- */
void BKE_id_ordered_list(ListBase *ordered_lb, const ListBase *lb)
{
BLI_listbase_clear(ordered_lb);
@@ -2429,9 +2266,6 @@ void BKE_id_ordered_list(ListBase *ordered_lb, const ListBase *lb)
}
}
-/**
- * Reorder ID in the list, before or after the "relative" ID.
- */
void BKE_id_reorder(const ListBase *lb, ID *id, ID *relative, bool after)
{
int *id_order = id_order_get(id);
diff --git a/source/blender/blenkernel/intern/lib_id_delete.c b/source/blender/blenkernel/intern/lib_id_delete.c
index 502a1197616..1922a54addb 100644
--- a/source/blender/blenkernel/intern/lib_id_delete.c
+++ b/source/blender/blenkernel/intern/lib_id_delete.c
@@ -90,23 +90,6 @@ void BKE_libblock_free_datablock(ID *id, const int UNUSED(flag))
BLI_assert_msg(0, "IDType Missing IDTypeInfo");
}
-/**
- * Complete ID freeing, extended version for corner cases.
- * Can override default (and safe!) freeing process, to gain some speed up.
- *
- * At that point, given id is assumed to not be used by any other data-block already
- * (might not be actually true, in case e.g. several inter-related IDs get freed together...).
- * However, they might still be using (referencing) other IDs, this code takes care of it if
- * #LIB_TAG_NO_USER_REFCOUNT is not defined.
- *
- * \param bmain: #Main database containing the freed #ID,
- * can be NULL in case it's a temp ID outside of any #Main.
- * \param idv: Pointer to ID to be freed.
- * \param flag: Set of \a LIB_ID_FREE_... flags controlling/overriding usual freeing process,
- * 0 to get default safe behavior.
- * \param use_flag_from_idtag: Still use freeing info flags from given #ID datablock,
- * even if some overriding ones are passed in \a flag parameter.
- */
void BKE_id_free_ex(Main *bmain, void *idv, int flag, const bool use_flag_from_idtag)
{
ID *id = idv;
@@ -191,24 +174,11 @@ void BKE_id_free_ex(Main *bmain, void *idv, int flag, const bool use_flag_from_i
}
}
-/**
- * Complete ID freeing, should be usable in most cases (even for out-of-Main IDs).
- *
- * See #BKE_id_free_ex description for full details.
- *
- * \param bmain: Main database containing the freed ID,
- * can be NULL in case it's a temp ID outside of any Main.
- * \param idv: Pointer to ID to be freed.
- */
void BKE_id_free(Main *bmain, void *idv)
{
BKE_id_free_ex(bmain, idv, 0, true);
}
-/**
- * Not really a freeing function by itself,
- * it decrements usercount of given id, and only frees it if it reaches 0.
- */
void BKE_id_free_us(Main *bmain, void *idv) /* test users */
{
ID *id = idv;
@@ -378,9 +348,6 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion)
return num_datablocks_deleted;
}
-/**
- * Properly delete a single ID from given \a bmain database.
- */
void BKE_id_delete(Main *bmain, void *idv)
{
BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
@@ -389,16 +356,6 @@ void BKE_id_delete(Main *bmain, void *idv)
id_delete(bmain, false);
}
-/**
- * Properly delete all IDs tagged with \a LIB_TAG_DOIT, in given \a bmain database.
- *
- * This is more efficient than calling #BKE_id_delete repetitively on a large set of IDs
- * (several times faster when deleting most of the IDs at once)...
- *
- * \warning Considered experimental for now, seems to be working OK but this is
- * risky code in a complicated area.
- * \return Number of deleted datablocks.
- */
size_t BKE_id_multi_tagged_delete(Main *bmain)
{
return id_delete(bmain, true);
@@ -408,12 +365,6 @@ size_t BKE_id_multi_tagged_delete(Main *bmain)
/** \name Python Data Handling
* \{ */
-/**
- * In most cases #BKE_id_free_ex handles this, when lower level functions are called directly
- * this function will need to be called too, if Python has access to the data.
- *
- * ID data-blocks such as #Material.nodetree are not stored in #Main.
- */
void BKE_libblock_free_data_py(ID *id)
{
#ifdef WITH_PYTHON
diff --git a/source/blender/blenkernel/intern/lib_id_eval.c b/source/blender/blenkernel/intern/lib_id_eval.c
index 140fe403ac3..a29d9270d72 100644
--- a/source/blender/blenkernel/intern/lib_id_eval.c
+++ b/source/blender/blenkernel/intern/lib_id_eval.c
@@ -29,11 +29,6 @@
#include "BKE_lib_id.h"
#include "BKE_mesh.h"
-/**
- * Copy relatives parameters, from `id` to `id_cow`.
- * Use handle the #ID_RECALC_PARAMETERS tag.
- * \note Keep in sync with #ID_TYPE_SUPPORTS_PARAMS_WITHOUT_COW.
- */
void BKE_id_eval_properties_copy(ID *id_cow, ID *id)
{
const ID_Type id_type = GS(id->name);
diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c
index 66a550ec6b0..83ed0ee4c08 100644
--- a/source/blender/blenkernel/intern/lib_override.c
+++ b/source/blender/blenkernel/intern/lib_override.c
@@ -57,6 +57,7 @@
#include "BLI_ghash.h"
#include "BLI_linklist.h"
#include "BLI_listbase.h"
+#include "BLI_memarena.h"
#include "BLI_string.h"
#include "BLI_task.h"
#include "BLI_utildefines.h"
@@ -99,7 +100,6 @@ BLI_INLINE IDOverrideLibrary *lib_override_get(Main *bmain, ID *id)
return id->override_library;
}
-/** Initialize empty overriding of \a reference_id by \a local_id. */
IDOverrideLibrary *BKE_lib_override_library_init(ID *local_id, ID *reference_id)
{
/* If reference_id is NULL, we are creating an override template for purely local data.
@@ -134,7 +134,6 @@ IDOverrideLibrary *BKE_lib_override_library_init(ID *local_id, ID *reference_id)
return local_id->override_library;
}
-/** Shalow or deep copy of a whole override from \a src_id to \a dst_id. */
void BKE_lib_override_library_copy(ID *dst_id, const ID *src_id, const bool do_full_copy)
{
BLI_assert(ID_IS_OVERRIDE_LIBRARY(src_id) || ID_IS_OVERRIDE_LIBRARY_TEMPLATE(src_id));
@@ -176,7 +175,6 @@ void BKE_lib_override_library_copy(ID *dst_id, const ID *src_id, const bool do_f
dst_id->tag &= ~LIB_TAG_OVERRIDE_LIBRARY_REFOK;
}
-/** Clear any overriding data from given \a override. */
void BKE_lib_override_library_clear(IDOverrideLibrary *override, const bool do_id_user)
{
BLI_assert(override != NULL);
@@ -196,7 +194,6 @@ void BKE_lib_override_library_clear(IDOverrideLibrary *override, const bool do_i
}
}
-/** Free given \a override. */
void BKE_lib_override_library_free(struct IDOverrideLibrary **override, const bool do_id_user)
{
BLI_assert(*override != NULL);
@@ -245,14 +242,11 @@ static ID *lib_override_library_create_from(Main *bmain,
return local_id;
}
-/**
- * Check if given ID has some override rules that actually indicate the user edited it.
- *
- * TODO: This could be simplified by storing a flag in #IDOverrideLibrary during the diffing
- * process?
- */
+/* TODO: This could be simplified by storing a flag in #IDOverrideLibrary
+ * during the diffing process? */
bool BKE_lib_override_library_is_user_edited(struct ID *id)
{
+
if (!ID_IS_OVERRIDE_LIBRARY(id)) {
return false;
}
@@ -280,7 +274,6 @@ bool BKE_lib_override_library_is_user_edited(struct ID *id)
return false;
}
-/** Create an overridden local copy of linked reference. */
ID *BKE_lib_override_library_create_from_id(Main *bmain,
ID *reference_id,
const bool do_tagged_remap)
@@ -322,25 +315,6 @@ ID *BKE_lib_override_library_create_from_id(Main *bmain,
return local_id;
}
-/**
- * Create overridden local copies of all tagged data-blocks in given Main.
- *
- * \note Set `id->newid` of overridden libs with newly created overrides,
- * caller is responsible to clean those pointers before/after usage as needed.
- *
- * \note By default, it will only remap newly created local overriding data-blocks between
- * themselves, to avoid 'enforcing' those overrides into all other usages of the linked data in
- * main. You can add more local IDs to be remapped to use new overriding ones by setting their
- * LIB_TAG_DOIT tag.
- *
- * \param reference_library: the library from which the linked data being overridden come from
- * (i.e. the library of the linked reference ID).
- *
- * \param do_no_main: Create the new override data outside of Main database.
- * Used for resyncing of linked overrides.
- *
- * \return \a true on success, \a false otherwise.
- */
bool BKE_lib_override_library_create_from_tag(Main *bmain,
const Library *reference_library,
const bool do_no_main)
@@ -479,8 +453,59 @@ typedef struct LibOverrideGroupTagData {
bool is_override;
/* Whether we are creating new override, or resyncing existing one. */
bool is_resync;
+
+ /* Mapping linked objects to all their instantiating collections (as a linked list).
+ * Avoids calling #BKE_collection_object_find over and over, this function is very expansive. */
+ GHash *linked_object_to_instantiating_collections;
+ MemArena *mem_arena;
} LibOverrideGroupTagData;
+static void lib_override_group_tag_data_object_to_collection_init_collection_process(
+ LibOverrideGroupTagData *data, Collection *collection)
+{
+ LISTBASE_FOREACH (CollectionObject *, collection_object, &collection->gobject) {
+ Object *ob = collection_object->ob;
+ if (!ID_IS_LINKED(ob)) {
+ continue;
+ }
+
+ LinkNodePair **collections_linkedlist_p;
+ if (!BLI_ghash_ensure_p(
+ data->linked_object_to_instantiating_collections, ob, &collections_linkedlist_p)) {
+ *collections_linkedlist_p = BLI_memarena_calloc(data->mem_arena,
+ sizeof(**collections_linkedlist_p));
+ }
+ BLI_linklist_append_arena(*collections_linkedlist_p, collection, data->mem_arena);
+ }
+}
+
+/* Initialize complex data, `data` is expected to be already initialized with basic pointers and
+ * other simple data.
+ *
+ * NOTE: Currently creates a mapping from linked object to all of their instantiating collections
+ * (as returned by #BKE_collection_object_find). */
+static void lib_override_group_tag_data_object_to_collection_init(LibOverrideGroupTagData *data)
+{
+ data->mem_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+
+ data->linked_object_to_instantiating_collections = BLI_ghash_new(
+ BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
+ if (data->scene != NULL) {
+ lib_override_group_tag_data_object_to_collection_init_collection_process(
+ data, data->scene->master_collection);
+ }
+ LISTBASE_FOREACH (Collection *, collection, &data->bmain->collections) {
+ lib_override_group_tag_data_object_to_collection_init_collection_process(data, collection);
+ }
+}
+
+static void lib_override_group_tag_data_clear(LibOverrideGroupTagData *data)
+{
+ BLI_ghash_free(data->linked_object_to_instantiating_collections, NULL, NULL);
+ BLI_memarena_free(data->mem_arena);
+ memset(data, 0, sizeof(*data));
+}
+
/* Tag all IDs in dependency relationships within an override hierarchy/group.
*
* Requires existing `Main.relations`.
@@ -599,7 +624,6 @@ static void lib_override_linked_group_tag_recursive(LibOverrideGroupTagData *dat
static void lib_override_linked_group_tag(LibOverrideGroupTagData *data)
{
Main *bmain = data->bmain;
- Scene *scene = data->scene;
ID *id_root = data->id_root;
const bool is_resync = data->is_resync;
BLI_assert(!data->is_override);
@@ -637,18 +661,26 @@ static void lib_override_linked_group_tag(LibOverrideGroupTagData *data)
Collection *instantiating_collection_override_candidate = NULL;
/* Loop over all collections instantiating the object, if we already have a 'locale' one we
* have nothing to do, otherwise try to find a 'linked' one that we can override too. */
- while ((instantiating_collection = BKE_collection_object_find(
- bmain, scene, instantiating_collection, ob)) != NULL) {
- /* In (recursive) resync case, if a collection of a 'parent' lib instantiates the linked
- * object, it is also fine. */
- if (!ID_IS_LINKED(instantiating_collection) ||
- (is_resync && ID_IS_LINKED(id_root) &&
- instantiating_collection->id.lib->temp_index < id_root->lib->temp_index)) {
- break;
- }
- if (ID_IS_LINKED(instantiating_collection) &&
- (!is_resync || instantiating_collection->id.lib == id_root->lib)) {
- instantiating_collection_override_candidate = instantiating_collection;
+ LinkNodePair *instantiating_collection_linklist = BLI_ghash_lookup(
+ data->linked_object_to_instantiating_collections, ob);
+ if (instantiating_collection_linklist != NULL) {
+ for (LinkNode *instantiating_collection_linknode =
+ instantiating_collection_linklist->list;
+ instantiating_collection_linknode != NULL;
+ instantiating_collection_linknode = instantiating_collection_linknode->next) {
+ instantiating_collection = instantiating_collection_linknode->link;
+ /* In (recursive) resync case, if a collection of a 'parent' lib instantiates the
+ * linked object, it is also fine. */
+ if (!ID_IS_LINKED(instantiating_collection) ||
+ (is_resync && ID_IS_LINKED(id_root) &&
+ instantiating_collection->id.lib->temp_index < id_root->lib->temp_index)) {
+ break;
+ }
+ if (ID_IS_LINKED(instantiating_collection) &&
+ (!is_resync || instantiating_collection->id.lib == id_root->lib)) {
+ instantiating_collection_override_candidate = instantiating_collection;
+ }
+ instantiating_collection = NULL;
}
}
@@ -751,12 +783,14 @@ static bool lib_override_library_create_do(Main *bmain, Scene *scene, ID *id_roo
.missing_tag = LIB_TAG_MISSING,
.is_override = false,
.is_resync = false};
+ lib_override_group_tag_data_object_to_collection_init(&data);
lib_override_linked_group_tag(&data);
BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false);
lib_override_hierarchy_dependencies_recursive_tag(&data);
BKE_main_relations_free(bmain);
+ lib_override_group_tag_data_clear(&data);
return BKE_lib_override_library_create_from_tag(bmain, id_root->lib, false);
}
@@ -890,24 +924,6 @@ static void lib_override_library_create_post_process(Main *bmain,
BLI_gset_free(all_objects_in_scene, NULL);
}
-/**
- * Advanced 'smart' function to create fully functional overrides.
- *
- * \note Currently it only does special things if given \a id_root is an object or collection, more
- * specific behaviors may be added in the future for other ID types.
- *
- * \note It will override all IDs tagged with \a LIB_TAG_DOIT, and it does not clear that tag at
- * its beginning, so caller code can add extra data-blocks to be overridden as well.
- *
- * \param view_layer: the active view layer to search instantiated collections in, can be NULL (in
- * which case \a scene's master collection children hierarchy is used instead).
- * \param id_root: The root ID to create an override from.
- * \param id_reference: Some reference ID used to do some post-processing after overrides have been
- * created, may be NULL. Typically, the Empty object instantiating the linked collection we
- * override, currently.
- * \param r_id_root_override: if not NULL, the override generated for the given \a id_root.
- * \return true if override was successfully created.
- */
bool BKE_lib_override_library_create(Main *bmain,
Scene *scene,
ViewLayer *view_layer,
@@ -942,9 +958,6 @@ bool BKE_lib_override_library_create(Main *bmain,
return success;
}
-/**
- * Create a library override template.
- */
bool BKE_lib_override_library_template_create(struct ID *id)
{
if (ID_IS_LINKED(id)) {
@@ -958,16 +971,6 @@ bool BKE_lib_override_library_template_create(struct ID *id)
return true;
}
-/**
- * Convert a given proxy object into a library override.
- *
- * \note This is a thin wrapper around \a BKE_lib_override_library_create, only extra work is to
- * actually convert the proxy itself into an override first.
- *
- * \param view_layer: the active view layer to search instantiated collections in, can be NULL (in
- * which case \a scene's master collection children hierarchy is used instead).
- * \return true if override was successfully created.
- */
bool BKE_lib_override_library_proxy_convert(Main *bmain,
Scene *scene,
ViewLayer *view_layer,
@@ -1039,14 +1042,6 @@ static void lib_override_library_proxy_convert_do(Main *bmain,
}
}
-/**
- * Convert all proxy objects into library overrides.
- *
- * \note Only affects local proxies, linked ones are not affected.
- *
- * \param view_layer: the active view layer to search instantiated collections in, can be NULL (in
- * which case \a scene's master collection children hierarchy is used instead).
- */
void BKE_lib_override_library_main_proxy_convert(Main *bmain, BlendFileReadReport *reports)
{
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
@@ -1086,15 +1081,6 @@ void BKE_lib_override_library_main_proxy_convert(Main *bmain, BlendFileReadRepor
}
}
-/**
- * Advanced 'smart' function to resync, re-create fully functional overrides up-to-date with linked
- * data, from an existing override hierarchy.
- *
- * \param id_root: The root liboverride ID to resync from.
- * \param view_layer: the active view layer to search instantiated collections in, can be NULL (in
- * which case \a scene's master collection children hierarchy is used instead).
- * \return true if override was successfully resynced.
- */
bool BKE_lib_override_library_resync(Main *bmain,
Scene *scene,
ViewLayer *view_layer,
@@ -1125,6 +1111,7 @@ bool BKE_lib_override_library_resync(Main *bmain,
.missing_tag = LIB_TAG_MISSING,
.is_override = true,
.is_resync = true};
+ lib_override_group_tag_data_object_to_collection_init(&data);
lib_override_overrides_group_tag(&data);
BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false);
@@ -1215,6 +1202,7 @@ bool BKE_lib_override_library_resync(Main *bmain,
lib_override_hierarchy_dependencies_recursive_tag(&data);
BKE_main_relations_free(bmain);
+ lib_override_group_tag_data_clear(&data);
/* Make new override from linked data. */
/* Note that this call also remaps all pointers of tagged IDs from old override IDs to new
@@ -1607,6 +1595,14 @@ static void lib_override_library_main_resync_on_library_indirect_level(
/* Detect all linked data that would need to be overridden if we had to create an override from
* those used by current existing overrides. */
+ LibOverrideGroupTagData data = {.bmain = bmain,
+ .scene = scene,
+ .id_root = NULL,
+ .tag = LIB_TAG_DOIT,
+ .missing_tag = LIB_TAG_MISSING,
+ .is_override = false,
+ .is_resync = true};
+ lib_override_group_tag_data_object_to_collection_init(&data);
ID *id;
FOREACH_MAIN_ID_BEGIN (bmain, id) {
if (!ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
@@ -1617,19 +1613,14 @@ static void lib_override_library_main_resync_on_library_indirect_level(
continue;
}
- LibOverrideGroupTagData data = {.bmain = bmain,
- .scene = scene,
- .id_root = id->override_library->reference,
- .tag = LIB_TAG_DOIT,
- .missing_tag = LIB_TAG_MISSING,
- .is_override = false,
- .is_resync = true};
+ data.id_root = id->override_library->reference;
lib_override_linked_group_tag(&data);
BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false);
lib_override_hierarchy_dependencies_recursive_tag(&data);
BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false);
}
FOREACH_MAIN_ID_END;
+ lib_override_group_tag_data_clear(&data);
/* Now check existing overrides, those needing resync will be the one either already tagged as
* such, or the one using linked data that is now tagged as needing override. */
@@ -1801,23 +1792,6 @@ static int lib_override_libraries_index_define(Main *bmain)
return library_indirect_level_max;
}
-/**
- * Detect and handle required resync of overrides data, when relations between reference linked IDs
- * have changed.
- *
- * This is a fairly complex and costly operation, typically it should be called after
- * #BKE_lib_override_library_main_update, which would already detect and tag a lot of cases.
- *
- * This function will first detect the remaining cases requiring a resync (namely, either when an
- * existing linked ID that did not require to be overridden before now would be, or when new IDs
- * are added to the hierarchy).
- *
- * Then it will handle the resync of necessary IDs (through calls to
- * #BKE_lib_override_library_resync).
- *
- * \param view_layer: the active view layer to search instantiated collections in, can be NULL (in
- * which case \a scene's master collection children hierarchy is used instead).
- */
void BKE_lib_override_library_main_resync(Main *bmain,
Scene *scene,
ViewLayer *view_layer,
@@ -1866,14 +1840,6 @@ void BKE_lib_override_library_main_resync(Main *bmain,
}
}
-/**
- * Advanced 'smart' function to delete library overrides (including their existing override
- * hierarchy) and remap their usages to their linked reference IDs.
- *
- * \note All IDs tagged with `LIB_TAG_DOIT` will be deleted.
- *
- * \param id_root: The root liboverride ID to delete.
- */
void BKE_lib_override_library_delete(Main *bmain, ID *id_root)
{
BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_root));
@@ -1887,9 +1853,11 @@ void BKE_lib_override_library_delete(Main *bmain, ID *id_root)
.missing_tag = LIB_TAG_MISSING,
.is_override = true,
.is_resync = false};
+ lib_override_group_tag_data_object_to_collection_init(&data);
lib_override_overrides_group_tag(&data);
BKE_main_relations_free(bmain);
+ lib_override_group_tag_data_clear(&data);
ID *id;
FOREACH_MAIN_ID_BEGIN (bmain, id) {
@@ -1911,11 +1879,6 @@ void BKE_lib_override_library_delete(Main *bmain, ID *id_root)
BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
}
-/** Make given ID fully local.
- *
- * \note Only differs from lower-level `BKE_lib_override_library_free in infamous embedded ID
- * cases.
- */
void BKE_lib_override_library_make_local(ID *id)
{
if (!ID_IS_OVERRIDE_LIBRARY(id)) {
@@ -1972,9 +1935,6 @@ BLI_INLINE GHash *override_library_rna_path_mapping_ensure(IDOverrideLibrary *ov
return override_runtime->rna_path_to_override_properties;
}
-/**
- * Find override property from given RNA path, if it exists.
- */
IDOverrideLibraryProperty *BKE_lib_override_library_property_find(IDOverrideLibrary *override,
const char *rna_path)
{
@@ -1982,9 +1942,6 @@ IDOverrideLibraryProperty *BKE_lib_override_library_property_find(IDOverrideLibr
return BLI_ghash_lookup(override_runtime, rna_path);
}
-/**
- * Find override property from given RNA path, or create it if it does not exist.
- */
IDOverrideLibraryProperty *BKE_lib_override_library_property_get(IDOverrideLibrary *override,
const char *rna_path,
bool *r_created)
@@ -2010,13 +1967,6 @@ IDOverrideLibraryProperty *BKE_lib_override_library_property_get(IDOverrideLibra
return op;
}
-/**
- * Get the RNA-property matching the \a library_prop override property. Used for UI to query
- * additional data about the overridden property (e.g. UI name).
- *
- * \param idpoin: Pointer to the override ID.
- * \param library_prop: The library override property to find the matching RNA property for.
- */
bool BKE_lib_override_rna_property_find(PointerRNA *idpoin,
const IDOverrideLibraryProperty *library_prop,
PointerRNA *r_override_poin,
@@ -2053,9 +2003,6 @@ void lib_override_library_property_clear(IDOverrideLibraryProperty *op)
BLI_freelistN(&op->operations);
}
-/**
- * Remove and free given \a override_property from given ID \a override.
- */
void BKE_lib_override_library_property_delete(IDOverrideLibrary *override,
IDOverrideLibraryProperty *override_property)
{
@@ -2069,9 +2016,6 @@ void BKE_lib_override_library_property_delete(IDOverrideLibrary *override,
BLI_freelinkN(&override->properties, override_property);
}
-/**
- * Find override property operation from given sub-item(s), if it exists.
- */
IDOverrideLibraryPropertyOperation *BKE_lib_override_library_property_operation_find(
IDOverrideLibraryProperty *override_property,
const char *subitem_refname,
@@ -2158,9 +2102,6 @@ IDOverrideLibraryPropertyOperation *BKE_lib_override_library_property_operation_
return NULL;
}
-/**
- * Find override property operation from given sub-item(s), or create it if it does not exist.
- */
IDOverrideLibraryPropertyOperation *BKE_lib_override_library_property_operation_get(
IDOverrideLibraryProperty *override_property,
const short operation,
@@ -2227,9 +2168,6 @@ void lib_override_library_property_operation_clear(IDOverrideLibraryPropertyOper
}
}
-/**
- * Remove and free given \a override_property_operation from given ID \a override_property.
- */
void BKE_lib_override_library_property_operation_delete(
IDOverrideLibraryProperty *override_property,
IDOverrideLibraryPropertyOperation *override_property_operation)
@@ -2238,9 +2176,6 @@ void BKE_lib_override_library_property_operation_delete(
BLI_freelinkN(&override_property->operations, override_property_operation);
}
-/**
- * Validate that required data for a given operation are available.
- */
bool BKE_lib_override_library_property_operation_operands_validate(
struct IDOverrideLibraryPropertyOperation *override_property_operation,
struct PointerRNA *ptr_dst,
@@ -2278,7 +2213,6 @@ bool BKE_lib_override_library_property_operation_operands_validate(
return true;
}
-/** Check against potential \a bmain. */
void BKE_lib_override_library_validate(Main *UNUSED(bmain), ID *id, ReportList *reports)
{
if (id->override_library == NULL) {
@@ -2312,7 +2246,6 @@ void BKE_lib_override_library_validate(Main *UNUSED(bmain), ID *id, ReportList *
}
}
-/** Check against potential \a bmain. */
void BKE_lib_override_library_main_validate(Main *bmain, ReportList *reports)
{
ID *id;
@@ -2325,16 +2258,6 @@ void BKE_lib_override_library_main_validate(Main *bmain, ReportList *reports)
FOREACH_MAIN_ID_END;
}
-/**
- * Check that status of local data-block is still valid against current reference one.
- *
- * It means that all overridable, but not overridden, properties' local values must be equal to
- * reference ones. Clears #LIB_TAG_OVERRIDE_OK if they do not.
- *
- * This is typically used to detect whether some property has been changed in local and a new
- * #IDOverrideProperty (of #IDOverridePropertyOperation) has to be added.
- *
- * \return true if status is OK, false otherwise. */
bool BKE_lib_override_library_status_check_local(Main *bmain, ID *local)
{
BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(local));
@@ -2384,16 +2307,6 @@ bool BKE_lib_override_library_status_check_local(Main *bmain, ID *local)
return true;
}
-/**
- * Check that status of reference data-block is still valid against current local one.
- *
- * It means that all non-overridden properties' local values must be equal to reference ones.
- * Clears LIB_TAG_OVERRIDE_OK if they do not.
- *
- * This is typically used to detect whether some reference has changed and local
- * needs to be updated against it.
- *
- * \return true if status is OK, false otherwise. */
bool BKE_lib_override_library_status_check_reference(Main *bmain, ID *local)
{
BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(local));
@@ -2450,20 +2363,6 @@ bool BKE_lib_override_library_status_check_reference(Main *bmain, ID *local)
return true;
}
-/**
- * Compare local and reference data-blocks and create new override operations as needed,
- * or reset to reference values if overriding is not allowed.
- *
- * \note Defining override operations is only mandatory before saving a `.blend` file on disk
- * (not for undo!).
- * Knowing that info at runtime is only useful for UI/UX feedback.
- *
- * \note This is by far the biggest operation (the more time-consuming) of the three so far,
- * since it has to go over all properties in depth (all overridable ones at least).
- * Generating differential values and applying overrides are much cheaper.
- *
- * \return true if any library operation was created.
- */
bool BKE_lib_override_library_operations_create(Main *bmain, ID *local)
{
BLI_assert(local->override_library != NULL);
@@ -2540,7 +2439,6 @@ static void lib_override_library_operations_create_cb(TaskPool *__restrict pool,
}
}
-/** Check all overrides from given \a bmain and create/update overriding operations as needed. */
bool BKE_lib_override_library_main_operations_create(Main *bmain, const bool force_auto)
{
ID *id;
@@ -2669,7 +2567,6 @@ static bool lib_override_library_id_reset_do(Main *bmain, ID *id_root)
return was_op_deleted;
}
-/** Reset all overrides in given \a id_root, while preserving ID relations. */
void BKE_lib_override_library_id_reset(Main *bmain, ID *id_root)
{
if (!ID_IS_OVERRIDE_LIBRARY_REAL(id_root)) {
@@ -2728,7 +2625,6 @@ static void lib_override_library_id_hierarchy_recursive_reset(Main *bmain, ID *i
}
}
-/** Reset all overrides in given \a id_root and its dependencies, while preserving ID relations. */
void BKE_lib_override_library_id_hierarchy_reset(Main *bmain, ID *id_root)
{
BKE_main_relations_create(bmain, 0);
@@ -2749,7 +2645,6 @@ void BKE_lib_override_library_id_hierarchy_reset(Main *bmain, ID *id_root)
FOREACH_MAIN_ID_END;
}
-/** Set or clear given tag in all operations in that override property data. */
void BKE_lib_override_library_operations_tag(struct IDOverrideLibraryProperty *override_property,
const short tag,
const bool do_set)
@@ -2773,7 +2668,6 @@ void BKE_lib_override_library_operations_tag(struct IDOverrideLibraryProperty *o
}
}
-/** Set or clear given tag in all properties and operations in that override data. */
void BKE_lib_override_library_properties_tag(struct IDOverrideLibrary *override,
const short tag,
const bool do_set)
@@ -2785,7 +2679,6 @@ void BKE_lib_override_library_properties_tag(struct IDOverrideLibrary *override,
}
}
-/** Set or clear given tag in all properties and operations in that Main's ID override data. */
void BKE_lib_override_library_main_tag(struct Main *bmain, const short tag, const bool do_set)
{
ID *id;
@@ -2798,7 +2691,6 @@ void BKE_lib_override_library_main_tag(struct Main *bmain, const short tag, cons
FOREACH_MAIN_ID_END;
}
-/** Remove all tagged-as-unused properties and operations from that ID override data. */
void BKE_lib_override_library_id_unused_cleanup(struct ID *local)
{
if (ID_IS_OVERRIDE_LIBRARY_REAL(local)) {
@@ -2818,7 +2710,6 @@ void BKE_lib_override_library_id_unused_cleanup(struct ID *local)
}
}
-/** Remove all tagged-as-unused properties and operations from that Main's ID override data. */
void BKE_lib_override_library_main_unused_cleanup(struct Main *bmain)
{
ID *id;
@@ -2839,7 +2730,6 @@ static void lib_override_id_swap(Main *bmain, ID *id_local, ID *id_temp)
id_local->tag |= (id_temp->tag & LIB_TAG_LIB_OVERRIDE_NEED_RESYNC);
}
-/** Update given override from its reference (re-applying overridden properties). */
void BKE_lib_override_library_update(Main *bmain, ID *local)
{
if (!ID_IS_OVERRIDE_LIBRARY_REAL(local)) {
@@ -2964,7 +2854,6 @@ void BKE_lib_override_library_update(Main *bmain, ID *local)
DEG_relations_tag_update(bmain);
}
-/** Update all overrides from given \a bmain. */
void BKE_lib_override_library_main_update(Main *bmain)
{
ID *id;
@@ -2985,7 +2874,6 @@ void BKE_lib_override_library_main_update(Main *bmain)
G_MAIN = orig_gmain;
}
-/** In case an ID is used by another liboverride ID, user may not be allowed to delete it. */
bool BKE_lib_override_library_id_is_user_deletable(struct Main *bmain, struct ID *id)
{
if (!(ID_IS_LINKED(id) || ID_IS_OVERRIDE_LIBRARY(id))) {
@@ -3026,17 +2914,11 @@ bool BKE_lib_override_library_id_is_user_deletable(struct Main *bmain, struct ID
* exact same data as "desired" ones (kind of "baked" data-blocks).
*/
-/** Initialize an override storage. */
OverrideLibraryStorage *BKE_lib_override_library_operations_store_init(void)
{
return BKE_main_new();
}
-/**
- * Generate suitable 'write' data (this only affects differential override operations).
- *
- * Note that \a local ID is no more modified by this call,
- * all extra data are stored in its temp \a storage_id copy. */
ID *BKE_lib_override_library_operations_store_start(Main *bmain,
OverrideLibraryStorage *override_storage,
ID *local)
@@ -3101,10 +2983,6 @@ ID *BKE_lib_override_library_operations_store_start(Main *bmain,
return storage_id;
}
-/**
- * Restore given ID modified by #BKE_lib_override_library_operations_store_start, to its
- * original state.
- */
void BKE_lib_override_library_operations_store_end(
OverrideLibraryStorage *UNUSED(override_storage), ID *local)
{
diff --git a/source/blender/blenkernel/intern/lib_query.c b/source/blender/blenkernel/intern/lib_query.c
index 74750a9b61a..4ad0186f9b5 100644
--- a/source/blender/blenkernel/intern/lib_query.c
+++ b/source/blender/blenkernel/intern/lib_query.c
@@ -76,8 +76,6 @@ typedef struct LibraryForeachIDData {
BLI_LINKSTACK_DECLARE(ids_todo, ID *);
} LibraryForeachIDData;
-/** Check whether current iteration over ID usages should be stopped or not.
- * \return true if the iteration should be stopped, false otherwise. */
bool BKE_lib_query_foreachid_iter_stop(LibraryForeachIDData *data)
{
return (data->status & IDWALK_STOP) != 0;
@@ -162,10 +160,6 @@ void BKE_lib_query_idpropertiesForeachIDLink_callback(IDProperty *id_prop, void
BKE_LIB_FOREACHID_PROCESS_ID(data, id_prop->data.pointer, cb_flag);
}
-/** Process embedded ID pointers (root nodetrees, master collections, ...).
- *
- * Those require specific care, since they are technically sub-data of their owner, yet in some
- * cases they still behave as regular IDs. */
void BKE_library_foreach_ID_embedded(LibraryForeachIDData *data, ID **id_pp)
{
/* Needed e.g. for callbacks handling relationships. This call shall be absolutely read-only. */
@@ -367,18 +361,12 @@ static bool library_foreach_ID_link(Main *bmain,
#undef CALLBACK_INVOKE
}
-/**
- * Loop over all of the ID's this data-block links to.
- */
void BKE_library_foreach_ID_link(
Main *bmain, ID *id, LibraryIDLinkCallback callback, void *user_data, int flag)
{
library_foreach_ID_link(bmain, NULL, id, callback, user_data, flag, NULL);
}
-/**
- * re-usable function, use when replacing ID's
- */
void BKE_library_update_ID_link_user(ID *id_dst, ID *id_src, const int cb_flag)
{
if (cb_flag & IDWALK_CB_USER) {
@@ -390,12 +378,6 @@ void BKE_library_update_ID_link_user(ID *id_dst, ID *id_src, const int cb_flag)
}
}
-/**
- * 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.
- */
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. */
@@ -567,16 +549,6 @@ static int foreach_libblock_id_users_callback(LibraryIDLinkCallbackData *cb_data
return IDWALK_RET_NOP;
}
-/**
- * Return the number of times given \a id_user uses/references \a id_used.
- *
- * \note This only checks for pointer references of an ID, shallow usages
- * (like e.g. by RNA paths, as done for FCurves) are not detected at all.
- *
- * \param id_user: the ID which is supposed to use (reference) \a id_used.
- * \param id_used: the ID which is supposed to be used (referenced) by \a id_user.
- * \return the number of direct usages/references of \a id_used by \a id_user.
- */
int BKE_library_ID_use_ID(ID *id_user, ID *id_used)
{
IDUsersIter iter;
@@ -625,26 +597,16 @@ static bool library_ID_is_used(Main *bmain, void *idv, const bool check_linked)
return is_defined;
}
-/**
- * Check whether given ID is used locally (i.e. by another non-linked ID).
- */
bool BKE_library_ID_is_locally_used(Main *bmain, void *idv)
{
return library_ID_is_used(bmain, idv, false);
}
-/**
- * Check whether given ID is used indirectly (i.e. by another linked ID).
- */
bool BKE_library_ID_is_indirectly_used(Main *bmain, void *idv)
{
return library_ID_is_used(bmain, idv, true);
}
-/**
- * Combine #BKE_library_ID_is_locally_used() and #BKE_library_ID_is_indirectly_used()
- * in a single call.
- */
void BKE_library_ID_test_usages(Main *bmain, void *idv, bool *is_used_local, bool *is_used_linked)
{
IDUsersIter iter;
@@ -759,21 +721,6 @@ static void lib_query_unused_ids_tag_recurse(Main *bmain,
}
}
-/**
- * Tag all unused IDs (a.k.a 'orphaned').
- *
- * By default only tag IDs with `0` user count.
- * If `do_tag_recursive` is set, it will check dependencies to detect all IDs that are not actually
- * used in current file, including 'archipelagos` (i.e. set of IDs referencing each other in
- * loops, but without any 'external' valid usages.
- *
- * Valid usages here are defined as ref-counting usages, which are not towards embedded or
- * loop-back data.
- *
- * \param r_num_tagged: If non-NULL, must be a zero-initialized array of #INDEX_ID_MAX integers.
- * Number of tagged-as-unused IDs is then set for each type, and as total in
- * #INDEX_ID_NULL item.
- */
void BKE_lib_query_unused_ids_tag(Main *bmain,
const int tag,
const bool do_local_ids,
@@ -838,15 +785,6 @@ static int foreach_libblock_used_linked_data_tag_clear_cb(LibraryIDLinkCallbackD
return IDWALK_RET_NOP;
}
-/**
- * Detect orphaned linked data blocks (i.e. linked data not used (directly or indirectly)
- * in any way by any local data), including complex cases like 'linked archipelagoes', i.e.
- * linked data-blocks that use each other in loops,
- * which prevents their deletion by 'basic' usage checks.
- *
- * \param do_init_tag: if \a true, all linked data are checked, if \a false,
- * only linked data-blocks already tagged with #LIB_TAG_DOIT are checked.
- */
void BKE_library_unused_linked_data_set_tag(Main *bmain, const bool do_init_tag)
{
ID *id;
@@ -876,14 +814,6 @@ void BKE_library_unused_linked_data_set_tag(Main *bmain, const bool do_init_tag)
}
}
-/**
- * Untag linked data blocks used by other untagged linked data-blocks.
- * Used to detect data-blocks that we can forcefully make local
- * (instead of copying them to later get rid of original):
- * All data-blocks we want to make local are tagged by caller,
- * after this function has ran caller knows data-blocks still tagged can directly be made local,
- * since they are only used by other data-blocks that will also be made fully local.
- */
void BKE_library_indirectly_used_data_tag_clear(Main *bmain)
{
ListBase *lb_array[INDEX_ID_MAX];
diff --git a/source/blender/blenkernel/intern/lib_remap.c b/source/blender/blenkernel/intern/lib_remap.c
index 014c923f04f..3cea0de32ee 100644
--- a/source/blender/blenkernel/intern/lib_remap.c
+++ b/source/blender/blenkernel/intern/lib_remap.c
@@ -456,10 +456,6 @@ static void libblock_remap_data(
#endif
}
-/**
- * Replace all references in given Main to \a old_id by \a new_id
- * (if \a new_id is NULL, it unlinks \a old_id).
- */
void BKE_libblock_remap_locked(Main *bmain, void *old_idv, void *new_idv, const short remap_flags)
{
IDRemap id_remap_data;
@@ -565,13 +561,6 @@ void BKE_libblock_remap(Main *bmain, void *old_idv, void *new_idv, const short r
BKE_main_unlock(bmain);
}
-/**
- * Unlink given \a id from given \a bmain
- * (does not touch to indirect, i.e. library, usages of the ID).
- *
- * \param do_flag_never_null: If true, all IDs using \a idv in a 'non-NULL' way are flagged by
- * #LIB_TAG_DOIT flag (quite obviously, 'non-NULL' usages can never be unlinked by this function).
- */
void BKE_libblock_unlink(Main *bmain,
void *idv,
const bool do_flag_never_null,
@@ -587,16 +576,6 @@ void BKE_libblock_unlink(Main *bmain,
BKE_main_unlock(bmain);
}
-/**
- * Similar to libblock_remap, but only affects IDs used by given \a idv ID.
- *
- * \param old_idv: Unlike BKE_libblock_remap, can be NULL,
- * in which case all ID usages by given \a idv will be cleared.
- * \param us_min_never_null: If \a true and new_id is NULL,
- * 'NEVER_NULL' ID usages keep their old id, but this one still gets its user count decremented
- * (needed when given \a idv is going to be deleted right after being unlinked).
- */
-/* Should be able to replace all _relink() funcs (constraints, rigidbody, etc.) ? */
/* XXX Arg! Naming... :(
* _relink? avoids confusion with _remap, but is confusing with _unlink
* _remap_used_ids?
@@ -604,9 +583,13 @@ void BKE_libblock_unlink(Main *bmain,
* BKE_id_remap maybe?
* ... sigh
*/
+
void BKE_libblock_relink_ex(
Main *bmain, void *idv, void *old_idv, void *new_idv, const short remap_flags)
{
+
+ /* Should be able to replace all _relink() funcs (constraints, rigidbody, etc.) ? */
+
ID *id = idv;
ID *old_id = old_idv;
ID *new_id = new_idv;
@@ -710,15 +693,6 @@ static void libblock_relink_to_newid(Main *bmain, ID *id, const int remap_flag)
bmain, id, id_relink_to_newid_looper, POINTER_FROM_INT(remap_flag), 0);
}
-/**
- * Remaps ID usages of given ID to their `id->newid` pointer if not None, and proceeds recursively
- * in the dependency tree of IDs for all data-blocks tagged with `LIB_TAG_NEW`.
- *
- * NOTE: `LIB_TAG_NEW` is cleared
- *
- * Very specific usage, not sure we'll keep it on the long run,
- * currently only used in Object/Collection duplication code...
- */
void BKE_libblock_relink_to_newid(Main *bmain, ID *id, const int remap_flag)
{
if (ID_IS_LINKED(id)) {
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index 1dba353d8ce..c97b003d241 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -36,6 +36,7 @@
#include "BLT_translation.h"
+#include "BKE_bpath.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
#include "BKE_lib_query.h"
@@ -60,6 +61,22 @@ static void library_foreach_id(ID *id, LibraryForeachIDData *data)
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, lib->parent, IDWALK_CB_NEVER_SELF);
}
+static void library_foreach_path(ID *id, BPathForeachPathData *bpath_data)
+{
+ Library *lib = (Library *)id;
+
+ /* FIXME: Find if we should respect #BKE_BPATH_FOREACH_PATH_SKIP_PACKED here, and if not, explain
+ * why. */
+ if (lib->packedfile !=
+ NULL /*&& (bpath_data->flag & BKE_BPATH_FOREACH_PATH_SKIP_PACKED) != 0 */) {
+ return;
+ }
+
+ if (BKE_bpath_foreach_path_fixed_process(bpath_data, lib->filepath)) {
+ BKE_library_filepath_set(bpath_data->bmain, lib, lib->filepath);
+ }
+}
+
IDTypeInfo IDType_ID_LI = {
.id_code = ID_LI,
.id_filter = 0,
@@ -69,6 +86,7 @@ IDTypeInfo IDType_ID_LI = {
.name_plural = "libraries",
.translation_context = BLT_I18NCONTEXT_ID_LIBRARY,
.flags = IDTYPE_FLAGS_NO_COPY | IDTYPE_FLAGS_NO_LIBLINKING | IDTYPE_FLAGS_NO_ANIMDATA,
+ .asset_type_info = NULL,
.init_data = NULL,
.copy_data = NULL,
@@ -76,6 +94,7 @@ IDTypeInfo IDType_ID_LI = {
.make_local = NULL,
.foreach_id = library_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = library_foreach_path,
.owner_get = NULL,
.blend_write = NULL,
@@ -108,7 +127,7 @@ void BKE_library_filepath_set(Main *bmain, Library *lib, const char *filepath)
*/
/* Never make paths relative to parent lib - reading code (blenloader) always set *all*
* `lib->filepath` relative to current main, not to their parent for indirectly linked ones. */
- const char *basepath = BKE_main_blendfile_path(bmain);
- BLI_path_abs(lib->filepath_abs, basepath);
+ const char *blendfile_path = BKE_main_blendfile_path(bmain);
+ BLI_path_abs(lib->filepath_abs, blendfile_path);
}
}
diff --git a/source/blender/blenkernel/intern/light.c b/source/blender/blenkernel/intern/light.c
index 05e8d4fe978..e73cda7e24d 100644
--- a/source/blender/blenkernel/intern/light.c
+++ b/source/blender/blenkernel/intern/light.c
@@ -195,6 +195,7 @@ IDTypeInfo IDType_ID_LA = {
.name_plural = "lights",
.translation_context = BLT_I18NCONTEXT_ID_LIGHT,
.flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = light_init_data,
.copy_data = light_copy_data,
@@ -202,6 +203,7 @@ IDTypeInfo IDType_ID_LA = {
.make_local = NULL,
.foreach_id = light_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = light_blend_write,
diff --git a/source/blender/blenkernel/intern/lightprobe.c b/source/blender/blenkernel/intern/lightprobe.c
index 57ad6695db4..035e41815e5 100644
--- a/source/blender/blenkernel/intern/lightprobe.c
+++ b/source/blender/blenkernel/intern/lightprobe.c
@@ -92,6 +92,7 @@ IDTypeInfo IDType_ID_LP = {
.name_plural = "lightprobes",
.translation_context = BLT_I18NCONTEXT_ID_LIGHTPROBE,
.flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = lightprobe_init_data,
.copy_data = NULL,
@@ -99,6 +100,7 @@ IDTypeInfo IDType_ID_LP = {
.make_local = NULL,
.foreach_id = lightprobe_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = lightprobe_blend_write,
diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c
index 3c305d1fb3f..ac0dbcb715d 100644
--- a/source/blender/blenkernel/intern/linestyle.c
+++ b/source/blender/blenkernel/intern/linestyle.c
@@ -754,6 +754,7 @@ IDTypeInfo IDType_ID_LS = {
.name_plural = "linestyles",
.translation_context = BLT_I18NCONTEXT_ID_FREESTYLELINESTYLE,
.flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = linestyle_init_data,
.copy_data = linestyle_copy_data,
@@ -761,6 +762,7 @@ IDTypeInfo IDType_ID_LS = {
.make_local = NULL,
.foreach_id = linestyle_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = linestyle_blend_write,
@@ -1910,10 +1912,6 @@ int BKE_linestyle_geometry_modifier_remove(FreestyleLineStyle *linestyle, LineSt
return 0;
}
-/**
- * Reinsert \a modifier in modifier list with an offset of \a direction.
- * \return if position of \a modifier has changed.
- */
bool BKE_linestyle_color_modifier_move(FreestyleLineStyle *linestyle,
LineStyleModifier *modifier,
int direction)
diff --git a/source/blender/blenkernel/intern/main.c b/source/blender/blenkernel/intern/main.c
index a5de0bc99c8..64731be57ac 100644
--- a/source/blender/blenkernel/intern/main.c
+++ b/source/blender/blenkernel/intern/main.c
@@ -205,7 +205,6 @@ void BKE_main_free(Main *mainvar)
MEM_freeN(mainvar);
}
-/* Check whether given `bmain` is empty or contains some IDs. */
bool BKE_main_is_empty(struct Main *bmain)
{
ID *id_iter;
@@ -278,7 +277,6 @@ static int main_relations_create_idlink_cb(LibraryIDLinkCallbackData *cb_data)
return IDWALK_RET_NOP;
}
-/** Generate the mappings between used IDs and their users, and vice-versa. */
void BKE_main_relations_create(Main *bmain, const short flag)
{
if (bmain->relations != NULL) {
@@ -326,7 +324,6 @@ void BKE_main_relations_free(Main *bmain)
}
}
-/** Set or clear given `tag` in all relation entries of given `bmain`. */
void BKE_main_relations_tag_set(struct Main *bmain,
const eMainIDRelationsEntryTags tag,
const bool value)
@@ -350,12 +347,6 @@ void BKE_main_relations_tag_set(struct Main *bmain,
BLI_ghashIterator_free(gh_iter);
}
-/**
- * Create a GSet storing all IDs present in given \a bmain, by their pointers.
- *
- * \param gset: If not NULL, given GSet will be extended with IDs from given \a bmain,
- * instead of creating a new one.
- */
GSet *BKE_main_gset_create(Main *bmain, GSet *gset)
{
if (gset == NULL) {
@@ -404,12 +395,6 @@ static bool lib_weak_key_cmp(const void *a, const void *b)
STREQ(string_pair_a->id_name, string_pair_b->id_name));
}
-/**
- * Generate a mapping between 'library path' of an ID (as a pair (relative blend file path, id
- * name)), and a current local ID, if any.
- *
- * This uses the information stored in `ID.library_weak_reference`.
- */
GHash *BKE_main_library_weak_reference_create(Main *bmain)
{
GHash *library_weak_reference_mapping = BLI_ghash_new(
@@ -442,24 +427,11 @@ GHash *BKE_main_library_weak_reference_create(Main *bmain)
return library_weak_reference_mapping;
}
-/**
- * Destroy the data generated by #BKE_main_library_weak_reference_create.
- */
void BKE_main_library_weak_reference_destroy(GHash *library_weak_reference_mapping)
{
BLI_ghash_free(library_weak_reference_mapping, MEM_freeN, NULL);
}
-/**
- * Search for a local ID matching the given linked ID reference.
- *
- * \param library_weak_reference_mapping: the mapping data generated by
- * #BKE_main_library_weak_reference_create.
- * \param library_relative_path: the path of a blend file library (relative to current working
- * one).
- * \param library_id_name: the full ID name, including the leading two chars encoding the ID
- * type.
- */
ID *BKE_main_library_weak_reference_search_item(GHash *library_weak_reference_mapping,
const char *library_filepath,
const char *library_id_name)
@@ -469,16 +441,6 @@ ID *BKE_main_library_weak_reference_search_item(GHash *library_weak_reference_ma
return (ID *)BLI_ghash_lookup(library_weak_reference_mapping, &key);
}
-/**
- * Add the given ID weak library reference to given local ID and the runtime mapping.
- *
- * \param library_weak_reference_mapping: the mapping data generated by
- * #BKE_main_library_weak_reference_create.
- * \param library_relative_path: the path of a blend file library (relative to current working
- * one).
- * \param library_id_name: the full ID name, including the leading two chars encoding the ID type.
- * \param new_id: New local ID matching given weak reference.
- */
void BKE_main_library_weak_reference_add_item(GHash *library_weak_reference_mapping,
const char *library_filepath,
const char *library_id_name,
@@ -507,21 +469,6 @@ void BKE_main_library_weak_reference_add_item(GHash *library_weak_reference_mapp
*id_p = new_id;
}
-/**
- * Update the status of the given ID weak library reference in current local IDs and the runtime
- * mapping.
- *
- * This effectively transfers the 'ownership' of the given weak reference from `old_id` to
- * `new_id`.
- *
- * \param library_weak_reference_mapping: the mapping data generated by
- * #BKE_main_library_weak_reference_create.
- * \param library_relative_path: the path of a blend file library (relative to current working
- * one).
- * \param library_id_name: the full ID name, including the leading two chars encoding the ID type.
- * \param old_id: Existing local ID matching given weak reference.
- * \param new_id: New local ID matching given weak reference.
- */
void BKE_main_library_weak_reference_update_item(GHash *library_weak_reference_mapping,
const char *library_filepath,
const char *library_id_name,
@@ -545,16 +492,6 @@ void BKE_main_library_weak_reference_update_item(GHash *library_weak_reference_m
*id_p = new_id;
}
-/**
- * Remove the given ID weak library reference from the given local ID and the runtime mapping.
- *
- * \param library_weak_reference_mapping: the mapping data generated by
- * #BKE_main_library_weak_reference_create.
- * \param library_relative_path: the path of a blend file library (relative to current working
- * one).
- * \param library_id_name: the full ID name, including the leading two chars encoding the ID type.
- * \param old_id: Existing local ID matching given weak reference.
- */
void BKE_main_library_weak_reference_remove_item(GHash *library_weak_reference_mapping,
const char *library_filepath,
const char *library_id_name,
@@ -572,13 +509,6 @@ void BKE_main_library_weak_reference_remove_item(GHash *library_weak_reference_m
MEM_SAFE_FREE(old_id->library_weak_reference);
}
-/**
- * Generates a raw .blend file thumbnail data from given image.
- *
- * \param bmain: If not NULL, also store generated data in this Main.
- * \param img: ImBuf image to generate thumbnail data from.
- * \return The generated .blend file raw thumbnail data.
- */
BlendThumbnail *BKE_main_thumbnail_from_imbuf(Main *bmain, ImBuf *img)
{
BlendThumbnail *data = NULL;
@@ -603,13 +533,6 @@ BlendThumbnail *BKE_main_thumbnail_from_imbuf(Main *bmain, ImBuf *img)
return data;
}
-/**
- * Generates an image from raw .blend file thumbnail \a data.
- *
- * \param bmain: Use this bmain->blen_thumb data if given \a data is NULL.
- * \param data: Raw .blend file thumbnail data.
- * \return An ImBuf from given data, or NULL if invalid.
- */
ImBuf *BKE_main_thumbnail_to_imbuf(Main *bmain, BlendThumbnail *data)
{
ImBuf *img = NULL;
@@ -626,9 +549,6 @@ ImBuf *BKE_main_thumbnail_to_imbuf(Main *bmain, BlendThumbnail *data)
return img;
}
-/**
- * Generates an empty (black) thumbnail for given Main.
- */
void BKE_main_thumbnail_create(struct Main *bmain)
{
MEM_SAFE_FREE(bmain->blen_thumb);
@@ -638,28 +558,16 @@ void BKE_main_thumbnail_create(struct Main *bmain)
bmain->blen_thumb->height = BLEN_THUMB_SIZE;
}
-/**
- * Return filepath of given \a main.
- */
const char *BKE_main_blendfile_path(const Main *bmain)
{
- return bmain->name;
+ return bmain->filepath;
}
-/**
- * Return filepath of global main #G_MAIN.
- *
- * \warning Usage is not recommended,
- * you should always try to get a valid Main pointer from context...
- */
const char *BKE_main_blendfile_path_from_global(void)
{
return BKE_main_blendfile_path(G_MAIN);
}
-/**
- * \return A pointer to the \a ListBase of given \a bmain for requested \a type ID type.
- */
ListBase *which_libbase(Main *bmain, short type)
{
switch ((ID_Type)type) {
@@ -747,18 +655,6 @@ ListBase *which_libbase(Main *bmain, short type)
return NULL;
}
-/**
- * Put the pointers to all the #ListBase structs in given `bmain` into the `*lb[INDEX_ID_MAX]`
- * array, and return the number of those for convenience.
- *
- * This is useful for generic traversal of all the blocks in a #Main (by traversing all the lists
- * in turn), without worrying about block types.
- *
- * \param lb: Array of lists #INDEX_ID_MAX in length.
- *
- * \note The order of each ID type #ListBase in the array is determined by the `INDEX_ID_<IDTYPE>`
- * enum definitions in `DNA_ID.h`. See also the #FOREACH_MAIN_ID_BEGIN macro in `BKE_main.h`
- */
int set_listbasepointers(Main *bmain, ListBase *lb[/*INDEX_ID_MAX*/])
{
/* Libraries may be accessed from pretty much any other ID. */
diff --git a/source/blender/blenkernel/intern/main_idmap.c b/source/blender/blenkernel/intern/main_idmap.c
index c75365a788d..38523f22aad 100644
--- a/source/blender/blenkernel/intern/main_idmap.c
+++ b/source/blender/blenkernel/intern/main_idmap.c
@@ -88,18 +88,6 @@ static struct IDNameLib_TypeMap *main_idmap_from_idcode(struct IDNameLib_Map *id
return NULL;
}
-/**
- * Generate mapping from ID type/name to ID pointer for given \a bmain.
- *
- * \note When used during undo/redo, there is no guaranty that ID pointers from UI area
- * are not pointing to freed memory (when some IDs have been deleted). To avoid crashes
- * in those cases, one can provide the 'old' (aka current) Main database as reference.
- * #BKE_main_idmap_lookup_id will then check that given ID does exist in \a old_bmain
- * before trying to use it.
- *
- * \param create_valid_ids_set: If \a true, generate a reference to prevent freed memory accesses.
- * \param old_bmain: If not NULL, its IDs will be added the valid references set.
- */
struct IDNameLib_Map *BKE_main_idmap_create(struct Main *bmain,
const bool create_valid_ids_set,
struct Main *old_bmain,
diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c
index 1d3ebaac303..6f498c5c9e7 100644
--- a/source/blender/blenkernel/intern/mask.c
+++ b/source/blender/blenkernel/intern/mask.c
@@ -255,6 +255,7 @@ IDTypeInfo IDType_ID_MSK = {
.name_plural = "masks",
.translation_context = BLT_I18NCONTEXT_ID_MASK,
.flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = NULL,
.copy_data = mask_copy_data,
@@ -262,6 +263,7 @@ IDTypeInfo IDType_ID_MSK = {
.make_local = NULL,
.foreach_id = mask_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = mask_blend_write,
@@ -371,7 +373,6 @@ MaskLayer *BKE_mask_layer_new(Mask *mask, const char *name)
return masklay;
}
-/* NOTE: may still be hidden, caller needs to check. */
MaskLayer *BKE_mask_layer_active(Mask *mask)
{
return BLI_findlink(&mask->masklayers, mask->masklay_act);
@@ -787,12 +788,11 @@ BLI_INLINE void orthogonal_direction_get(const float vec[2], float result[2])
normalize_v2(result);
}
-/* TODO(sergey): This function will re-calculate loads of stuff again and again
- * when differentiating feather points. This might be easily cached
- * in the callee function for this case.
- */
void BKE_mask_point_normal(MaskSpline *spline, MaskSplinePoint *point, float u, float n[2])
{
+ /* TODO(sergey): This function will re-calculate loads of stuff again and again
+ * when differentiating feather points. This might be easily cached
+ * in the callee function for this case. */
MaskSplinePoint *point_prev, *point_next;
@@ -1132,7 +1132,6 @@ MaskSpline *BKE_mask_spline_copy(const MaskSpline *spline)
return nspline;
}
-/* NOTE: Does NOT add to the list. */
MaskLayerShape *BKE_mask_layer_shape_alloc(MaskLayer *masklay, const int frame)
{
MaskLayerShape *masklay_shape;
@@ -1156,8 +1155,6 @@ void BKE_mask_layer_shape_free(MaskLayerShape *masklay_shape)
MEM_freeN(masklay_shape);
}
-/** \brief Free all animation keys for a mask layer
- */
void BKE_mask_layer_free_shapes(MaskLayer *masklay)
{
MaskLayerShape *masklay_shape;
@@ -1245,7 +1242,6 @@ void BKE_mask_coord_from_image(Image *image, ImageUser *iuser, float r_co[2], co
BKE_mask_coord_from_frame(r_co, co, frame_size);
}
-/* as above but divide */
void BKE_mask_coord_to_frame(float r_co[2], const float co[2], const float frame_size[2])
{
if (frame_size[0] == frame_size[1]) {
@@ -1428,8 +1424,6 @@ void BKE_mask_get_handle_point_adjacent(MaskSpline *spline,
*r_point_next = mask_spline_point_next(spline, points_array, point);
}
-/* calculates the tangent of a point by its previous and next
- * (ignoring handles - as if its a poly line) */
void BKE_mask_calc_tangent_polyline(MaskSpline *spline, MaskSplinePoint *point, float t[2])
{
float tvec_a[2], tvec_b[2];
@@ -1513,11 +1507,6 @@ void BKE_mask_calc_handle_adjacent_interp(MaskSpline *spline,
}
}
-/**
- * \brief Resets auto handles even for non-auto bezier points
- *
- * Useful for giving sane defaults.
- */
void BKE_mask_calc_handle_point_auto(MaskSpline *spline,
MaskSplinePoint *point,
const bool do_recalc_length)
@@ -1640,7 +1629,6 @@ static void mask_layer_shape_to_mask_point(BezTriple *bezt,
bezt->radius = fp[7];
}
-/* these functions match. copy is swapped */
void BKE_mask_layer_shape_from_mask(MaskLayer *masklay, MaskLayerShape *masklay_shape)
{
int tot = BKE_mask_layer_shape_totvert(masklay);
@@ -1696,7 +1684,6 @@ BLI_INLINE void interp_v2_v2v2_flfl(
target[1] = s * a[1] + t * b[1];
}
-/* linear interpolation only */
void BKE_mask_layer_shape_to_mask_interp(MaskLayer *masklay,
MaskLayerShape *masklay_shape_a,
MaskLayerShape *masklay_shape_b,
@@ -1757,9 +1744,6 @@ MaskLayerShape *BKE_mask_layer_shape_find_frame(MaskLayer *masklay, const int fr
return NULL;
}
-/**
- * When returning 2 - the frame isn't found but before/after frames are.
- */
int BKE_mask_layer_shape_find_frame_range(MaskLayer *masklay,
const float frame,
MaskLayerShape **r_masklay_shape_a,
@@ -1922,7 +1906,6 @@ static void interp_weights_uv_v2_apply(const float uv[2],
r_pt[1] += dvec[0] * uv[1];
}
-/* When a new points added - resize all shape-key array. */
void BKE_mask_layer_shape_changed_add(MaskLayer *masklay,
int index,
bool do_init,
@@ -2017,7 +2000,6 @@ void BKE_mask_layer_shape_changed_add(MaskLayer *masklay,
}
}
-/* move array to account for removed point */
void BKE_mask_layer_shape_changed_remove(MaskLayer *masklay, int index, int count)
{
MaskLayerShape *masklay_shape;
@@ -2079,13 +2061,11 @@ static void mask_clipboard_free_ex(bool final_free)
}
}
-/* Free the clipboard. */
void BKE_mask_clipboard_free(void)
{
mask_clipboard_free_ex(true);
}
-/* Copy selected visible splines from the given layer to clipboard. */
void BKE_mask_clipboard_copy_from_layer(MaskLayer *mask_layer)
{
MaskSpline *spline;
@@ -2120,13 +2100,11 @@ void BKE_mask_clipboard_copy_from_layer(MaskLayer *mask_layer)
}
}
-/* Check clipboard is empty. */
bool BKE_mask_clipboard_is_empty(void)
{
return BLI_listbase_is_empty(&mask_clipboard.splines);
}
-/* Paste the contents of clipboard to given mask layer */
void BKE_mask_clipboard_paste_to_layer(Main *bmain, MaskLayer *mask_layer)
{
MaskSpline *spline;
diff --git a/source/blender/blenkernel/intern/mask_evaluate.c b/source/blender/blenkernel/intern/mask_evaluate.c
index 4584d9e527e..69fc7554eed 100644
--- a/source/blender/blenkernel/intern/mask_evaluate.c
+++ b/source/blender/blenkernel/intern/mask_evaluate.c
@@ -720,10 +720,6 @@ static float (*mask_spline_feather_differentiated_points_with_resolution__double
return feather;
}
-/**
- * values align with #BKE_mask_spline_differentiate_with_resolution
- * when \a resol arguments match.
- */
float (*BKE_mask_spline_feather_differentiated_points_with_resolution(
MaskSpline *spline,
const unsigned int resol,
@@ -788,7 +784,6 @@ float (*BKE_mask_spline_feather_points(MaskSpline *spline, int *r_tot_feather_po
return feather;
}
-/* *** mask point functions which involve evaluation *** */
float *BKE_mask_point_segment_feather_diff(MaskSpline *spline,
MaskSplinePoint *point,
int width,
diff --git a/source/blender/blenkernel/intern/mask_rasterize.c b/source/blender/blenkernel/intern/mask_rasterize.c
index 0c40a1b5078..b0876957620 100644
--- a/source/blender/blenkernel/intern/mask_rasterize.c
+++ b/source/blender/blenkernel/intern/mask_rasterize.c
@@ -1474,9 +1474,6 @@ static void maskrasterize_buffer_cb(void *__restrict userdata,
}
}
-/**
- * \brief Rasterize a buffer from a single mask (threaded execution).
- */
void BKE_maskrasterize_buffer(MaskRasterHandle *mr_handle,
const unsigned int width,
const unsigned int height,
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index 1fac83c5665..d6035887790 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -261,6 +261,7 @@ IDTypeInfo IDType_ID_MA = {
.name_plural = "materials",
.translation_context = BLT_I18NCONTEXT_ID_MATERIAL,
.flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = material_init_data,
.copy_data = material_copy_data,
@@ -268,6 +269,7 @@ IDTypeInfo IDType_ID_MA = {
.make_local = NULL,
.foreach_id = material_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = material_blend_write,
@@ -387,7 +389,6 @@ short *BKE_object_material_len_p(Object *ob)
return NULL;
}
-/* same as above but for ID's */
Material ***BKE_id_material_array_p(ID *id)
{
/* ensure we don't try get materials from non-obdata */
@@ -726,13 +727,6 @@ static ID *get_evaluated_object_data_with_materials(Object *ob)
return data;
}
-/**
- * On evaluated objects the number of materials on an object and its data might go out of sync.
- * This is because during evaluation materials can be added/removed on the object data.
- *
- * For rendering or exporting we generally use the materials on the object data. However, some
- * material indices might be overwritten by the object.
- */
Material *BKE_object_material_get_eval(Object *ob, short act)
{
BLI_assert(DEG_is_evaluated_object(ob));
@@ -806,10 +800,6 @@ void BKE_id_material_eval_assign(ID *id, int slot, Material *material)
(*materials_ptr)[slot_index] = material;
}
-/**
- * Add an empty material slot if the id has no material slots. This material slot allows the
- * material to be overwritten by object-linked materials.
- */
void BKE_id_material_eval_ensure_default_slot(ID *id)
{
short *len_ptr = BKE_id_material_len_p(id);
@@ -1099,12 +1089,6 @@ void BKE_object_material_remap(Object *ob, const unsigned int *remap)
}
}
-/**
- * Calculate a material remapping from \a ob_src to \a ob_dst.
- *
- * \param remap_src_to_dst: An array the size of `ob_src->totcol`
- * where index values are filled in which map to \a ob_dst materials.
- */
void BKE_object_material_remap_calc(Object *ob_dst, Object *ob_src, short *remap_src_to_dst)
{
if (ob_src->totcol == 0) {
@@ -1153,9 +1137,6 @@ void BKE_object_material_remap_calc(Object *ob_dst, Object *ob_src, short *remap
BLI_ghash_free(gh_mat_map, NULL, NULL);
}
-/**
- * Copy materials from evaluated geometry to the original geometry of an object.
- */
void BKE_object_material_from_eval_data(Main *bmain, Object *ob_orig, ID *data_eval)
{
ID *data_orig = ob_orig->data;
@@ -1190,7 +1171,6 @@ void BKE_object_material_from_eval_data(Main *bmain, Object *ob_orig, ID *data_e
BKE_object_materials_test(bmain, ob_orig, data_orig);
}
-/* XXX: this calls many more update calls per object then are needed, could be optimized. */
void BKE_object_material_array_assign(Main *bmain,
struct Object *ob,
struct Material ***matar,
@@ -1553,7 +1533,6 @@ bNode *BKE_texpaint_slot_material_find_node(Material *ma, short texpaint_slot)
return find_data.r_node;
}
-/* r_col = current value, col = new value, (fac == 0) is no change */
void ramp_blend(int type, float r_col[3], const float fac, const float col[3])
{
float tmp, facm = 1.0f - fac;
diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c
index 48d31361eac..ac6b0a04def 100644
--- a/source/blender/blenkernel/intern/mball.c
+++ b/source/blender/blenkernel/intern/mball.c
@@ -189,6 +189,7 @@ IDTypeInfo IDType_ID_MB = {
.name_plural = "metaballs",
.translation_context = BLT_I18NCONTEXT_ID_METABALL,
.flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = metaball_init_data,
.copy_data = metaball_copy_data,
@@ -196,6 +197,7 @@ IDTypeInfo IDType_ID_MB = {
.make_local = NULL,
.foreach_id = metaball_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = metaball_blend_write,
@@ -219,8 +221,6 @@ MetaBall *BKE_mball_add(Main *bmain, const char *name)
return mb;
}
-/* most simple meta-element adding function
- * don't do context manipulation here (rna uses) */
MetaElem *BKE_mball_element_add(MetaBall *mb, const int type)
{
MetaElem *ml = MEM_callocN(sizeof(MetaElem), "metaelem");
@@ -267,13 +267,6 @@ MetaElem *BKE_mball_element_add(MetaBall *mb, const int type)
return ml;
}
-/**
- * Compute bounding box of all #MetaElem / #MetaBall
- *
- * Bounding box is computed from polygonized surface. \a ob is
- * basic meta-balls (with name `Meta` for example). All other meta-ball objects
- * (with names `Meta.001`, `Meta.002`, etc) are included in this bounding-box.
- */
void BKE_mball_texspace_calc(Object *ob)
{
DispList *dl;
@@ -317,7 +310,6 @@ void BKE_mball_texspace_calc(Object *ob)
bb->flag &= ~BOUNDBOX_DIRTY;
}
-/** Return or compute bbox for given metaball object. */
BoundBox *BKE_mball_boundbox_get(Object *ob)
{
BLI_assert(ob->type == OB_MBALL);
@@ -370,38 +362,29 @@ float *BKE_mball_make_orco(Object *ob, ListBase *dispbase)
return orcodata;
}
-/**
- * \brief Test, if \a ob is a basis meta-ball.
- *
- * It test last character of Object ID name. If last character
- * is digit it return 0, else it return 1.
- *
- *
- * Meta-Ball Basis Notes from Blender-2.5x
- * =======================================
- *
- * This is a can of worms.
- *
- * This really needs a rewrite/refactor its totally broken in anything other than basic cases
- * Multiple Scenes + Set Scenes & mixing meta-ball basis _should_ work but fails to update the
- * depsgraph on rename and linking into scenes or removal of basis meta-ball.
- * So take care when changing this code.
- *
- * Main idiot thing here is that the system returns #BKE_mball_basis_find()
- * objects which fail a #BKE_mball_is_basis() test.
- *
- * Not only that but the depsgraph and their areas depend on this behavior,
- * so making small fixes here isn't worth it.
- * - Campbell
- */
bool BKE_mball_is_basis(Object *ob)
{
- /* just a quick test */
+ /* Meta-Ball Basis Notes from Blender-2.5x
+ * =======================================
+ *
+ * NOTE(@campbellbarton): This is a can of worms.
+ *
+ * This really needs a rewrite/refactor its totally broken in anything other than basic cases
+ * Multiple Scenes + Set Scenes & mixing meta-ball basis _should_ work but fails to update the
+ * depsgraph on rename and linking into scenes or removal of basis meta-ball.
+ * So take care when changing this code.
+ *
+ * Main idiot thing here is that the system returns #BKE_mball_basis_find()
+ * objects which fail a #BKE_mball_is_basis() test.
+ *
+ * Not only that but the depsgraph and their areas depend on this behavior,
+ * so making small fixes here isn't worth it. */
+
+ /* Just a quick test. */
const int len = strlen(ob->id.name);
return (!isdigit(ob->id.name[len - 1]));
}
-/* return nonzero if ob1 is a basis mball for ob */
bool BKE_mball_is_basis_for(Object *ob1, Object *ob2)
{
int basis1nr, basis2nr;
@@ -454,13 +437,6 @@ bool BKE_mball_is_any_unselected(const MetaBall *mb)
return false;
}
-/**
- * \brief copy some properties from object to other meta-ball object with same base name
- *
- * When some properties (wire-size, threshold, update flags) of meta-ball are changed, then this
- * properties are copied to all meta-balls in same "group" (meta-balls with same base name:
- * `MBall`, `MBall.001`, `MBall.002`, etc). The most important is to copy properties to the base
- * meta-ball, because this meta-ball influence polygonization of meta-balls. */
void BKE_mball_properties_copy(Scene *scene, Object *active_object)
{
Scene *sce_iter = scene;
@@ -499,14 +475,6 @@ void BKE_mball_properties_copy(Scene *scene, Object *active_object)
}
}
-/** \brief This function finds the basis MetaBall.
- *
- * Basis meta-ball doesn't include any number at the end of
- * its name. All meta-balls with same base of name can be
- * blended. meta-balls with different basic name can't be blended.
- *
- * \warning #BKE_mball_is_basis() can fail on returned object, see function docs for details.
- */
Object *BKE_mball_basis_find(Scene *scene, Object *object)
{
Object *bob = object;
@@ -571,7 +539,6 @@ bool BKE_mball_minmax_ex(
return changed;
}
-/* basic vertex data functions */
bool BKE_mball_minmax(const MetaBall *mb, float min[3], float max[3])
{
INIT_MINMAX(min, max);
@@ -646,7 +613,6 @@ void BKE_mball_translate(MetaBall *mb, const float offset[3])
}
}
-/* *** select funcs *** */
int BKE_mball_select_count(const MetaBall *mb)
{
int sel = 0;
diff --git a/source/blender/blenkernel/intern/mball_tessellate.c b/source/blender/blenkernel/intern/mball_tessellate.c
index a2590171abd..eebe6efad78 100644
--- a/source/blender/blenkernel/intern/mball_tessellate.c
+++ b/source/blender/blenkernel/intern/mball_tessellate.c
@@ -55,6 +55,8 @@
/* experimental (faster) normal calculation */
// #define USE_ACCUM_NORMAL
+#define MBALL_ARRAY_LEN_INIT 4096
+
/* Data types */
typedef struct corner { /* corner of a cube */
@@ -448,7 +450,7 @@ static void make_face(PROCESS *process, int i1, int i2, int i3, int i4)
#endif
if (UNLIKELY(process->totindex == process->curindex)) {
- process->totindex += 4096;
+ process->totindex = process->totindex ? (process->totindex * 2) : MBALL_ARRAY_LEN_INIT;
process->indices = MEM_reallocN(process->indices, sizeof(int[4]) * process->totindex);
}
@@ -946,8 +948,8 @@ static int getedge(EDGELIST *table[], int i1, int j1, int k1, int i2, int j2, in
*/
static void addtovertices(PROCESS *process, const float v[3], const float no[3])
{
- if (process->curvertex == process->totvertex) {
- process->totvertex += 4096;
+ if (UNLIKELY(process->curvertex == process->totvertex)) {
+ process->totvertex = process->totvertex ? process->totvertex * 2 : MBALL_ARRAY_LEN_INIT;
process->co = MEM_reallocN(process->co, process->totvertex * sizeof(float[3]));
process->no = MEM_reallocN(process->no, process->totvertex * sizeof(float[3]));
}
@@ -1447,6 +1449,16 @@ void BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob, ListBa
/* add resulting surface to displist */
if (process.curindex) {
+
+ /* Avoid over-allocation since this is stored in the displist. */
+ if (process.curindex != process.totindex) {
+ process.indices = MEM_reallocN(process.indices, sizeof(int[4]) * process.curindex);
+ }
+ if (process.curvertex != process.totvertex) {
+ process.co = MEM_reallocN(process.co, process.curvertex * sizeof(float[3]));
+ process.no = MEM_reallocN(process.no, process.curvertex * sizeof(float[3]));
+ }
+
dl = MEM_callocN(sizeof(DispList), "mballdisp");
BLI_addtail(dispbase, dl);
dl->type = DL_INDEX4;
diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc
index 73e0c2cfa74..05aa9111fa3 100644
--- a/source/blender/blenkernel/intern/mesh.cc
+++ b/source/blender/blenkernel/intern/mesh.cc
@@ -48,6 +48,7 @@
#include "BLT_translation.h"
#include "BKE_anim_data.h"
+#include "BKE_bpath.h"
#include "BKE_deform.h"
#include "BKE_editmesh.h"
#include "BKE_global.h"
@@ -183,6 +184,14 @@ static void mesh_foreach_id(ID *id, LibraryForeachIDData *data)
}
}
+static void mesh_foreach_path(ID *id, BPathForeachPathData *bpath_data)
+{
+ Mesh *me = (Mesh *)id;
+ if (me->ldata.external) {
+ BKE_bpath_foreach_path_fixed_process(bpath_data, me->ldata.external->filename);
+ }
+}
+
static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address)
{
Mesh *mesh = (Mesh *)id;
@@ -355,28 +364,33 @@ static void mesh_read_expand(BlendExpander *expander, ID *id)
}
IDTypeInfo IDType_ID_ME = {
- ID_ME,
- FILTER_ID_ME,
- INDEX_ID_ME,
- sizeof(Mesh),
- "Mesh",
- "meshes",
- BLT_I18NCONTEXT_ID_MESH,
- IDTYPE_FLAGS_APPEND_IS_REUSABLE,
-
- mesh_init_data,
- mesh_copy_data,
- mesh_free_data,
- nullptr,
- mesh_foreach_id,
- nullptr,
- nullptr,
- mesh_blend_write,
- mesh_blend_read_data,
- mesh_blend_read_lib,
- mesh_read_expand,
- nullptr,
- nullptr,
+ /* id_code */ ID_ME,
+ /* id_filter */ FILTER_ID_ME,
+ /* main_listbase_index */ INDEX_ID_ME,
+ /* struct_size */ sizeof(Mesh),
+ /* name */ "Mesh",
+ /* name_plural */ "meshes",
+ /* translation_context */ BLT_I18NCONTEXT_ID_MESH,
+ /* flags */ IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ /* asset_type_info */ nullptr,
+
+ /* init_data */ mesh_init_data,
+ /* copy_data */ mesh_copy_data,
+ /* free_data */ mesh_free_data,
+ /* make_local */ nullptr,
+ /* foreach_id */ mesh_foreach_id,
+ /* foreach_cache */ nullptr,
+ /* foreach_path */ mesh_foreach_path,
+ /* owner_get */ nullptr,
+
+ /* blend_write */ mesh_blend_write,
+ /* blend_read_data */ mesh_blend_read_data,
+ /* blend_read_lib */ mesh_blend_read_lib,
+ /* blend_read_expand */ mesh_read_expand,
+
+ /* blend_read_undo_preserve */ nullptr,
+
+ /* lib_override_apply_post */ nullptr,
};
enum {
@@ -438,13 +452,15 @@ static int customdata_compare(
const uint64_t cd_mask_all_attr = CD_MASK_PROP_ALL | cd_mask_non_generic;
for (int i = 0; i < c1->totlayer; i++) {
- if (CD_TYPE_AS_MASK(c1->layers[i].type) & cd_mask_all_attr) {
+ l1 = &c1->layers[i];
+ if (CD_TYPE_AS_MASK(l1->type) & cd_mask_all_attr && l1->anonymous_id != nullptr) {
layer_count1++;
}
}
for (int i = 0; i < c2->totlayer; i++) {
- if (CD_TYPE_AS_MASK(c2->layers[i].type) & cd_mask_all_attr) {
+ l2 = &c2->layers[i];
+ if (CD_TYPE_AS_MASK(l1->type) & cd_mask_all_attr && l2->anonymous_id != nullptr) {
layer_count2++;
}
}
@@ -460,7 +476,8 @@ static int customdata_compare(
l1 = c1->layers + i1;
for (int i2 = 0; i2 < c2->totlayer; i2++) {
l2 = c2->layers + i2;
- if (l1->type != l2->type || !STREQ(l1->name, l2->name)) {
+ if (l1->type != l2->type || !STREQ(l1->name, l2->name) || l1->anonymous_id != nullptr ||
+ l2->anonymous_id != nullptr) {
continue;
}
/* At this point `l1` and `l2` have the same name and type, so they should be compared. */
@@ -673,12 +690,6 @@ static int customdata_compare(
return 0;
}
-/**
- * Used for unit testing; compares two meshes, checking only
- * differences we care about. should be usable with leaf's
- * testing framework I get RNA work done, will use hackish
- * testing code for now.
- */
const char *BKE_mesh_cmp(Mesh *me1, Mesh *me2, float thresh)
{
int c;
@@ -879,10 +890,6 @@ bool BKE_mesh_has_custom_loop_normals(Mesh *me)
return CustomData_has_layer(&me->ldata, CD_CUSTOMLOOPNORMAL);
}
-/**
- * Free (or release) any data used by this mesh (does not free the mesh itself).
- * Only use for undo, in most cases `BKE_id_free(nullptr, me)` should be used.
- */
void BKE_mesh_free_data_for_undo(Mesh *me)
{
mesh_free_data(&me->id);
@@ -997,10 +1004,6 @@ Mesh *BKE_mesh_new_nomain(
return mesh;
}
-/**
- * Copy user editable settings that we want to preserve
- * when a new mesh is based on an existing mesh.
- */
void BKE_mesh_copy_parameters(Mesh *me_dst, const Mesh *me_src)
{
/* Copy general settings. */
@@ -1023,12 +1026,6 @@ void BKE_mesh_copy_parameters(Mesh *me_dst, const Mesh *me_src)
me_dst->vertex_group_active_index = me_src->vertex_group_active_index;
}
-/**
- * A version of #BKE_mesh_copy_parameters that is intended for evaluated output
- * (the modifier stack for example).
- *
- * \warning User counts are not handled for ID's.
- */
void BKE_mesh_copy_parameters_for_eval(Mesh *me_dst, const Mesh *me_src)
{
/* User counts aren't handled, don't copy into a mesh from #G_MAIN. */
@@ -1249,7 +1246,7 @@ void BKE_mesh_texspace_get(Mesh *me, float r_loc[3], float r_size[3])
}
}
-void BKE_mesh_texspace_get_reference(Mesh *me, short **r_texflag, float **r_loc, float **r_size)
+void BKE_mesh_texspace_get_reference(Mesh *me, char **r_texflag, float **r_loc, float **r_size)
{
BKE_mesh_texspace_ensure(me);
@@ -1267,7 +1264,7 @@ void BKE_mesh_texspace_get_reference(Mesh *me, short **r_texflag, float **r_loc,
void BKE_mesh_texspace_copy_from_object(Mesh *me, Object *ob)
{
float *texloc, *texsize;
- short *texflag;
+ char *texflag;
if (BKE_object_obdata_texspace_get(ob, &texflag, &texloc, &texsize)) {
me->texflag = *texflag;
@@ -1315,10 +1312,18 @@ void BKE_mesh_orco_verts_transform(Mesh *me, float (*orco)[3], int totvert, int
}
}
-/**
- * Rotates the vertices of a face in case v[2] or v[3] (vertex index) is = 0.
- * this is necessary to make the if #MFace.v4 check for quads work.
- */
+void BKE_mesh_orco_ensure(Object *ob, Mesh *mesh)
+{
+ if (CustomData_has_layer(&mesh->vdata, CD_ORCO)) {
+ return;
+ }
+
+ /* Orcos are stored in normalized 0..1 range by convention. */
+ float(*orcodata)[3] = BKE_mesh_orco_verts_get(ob);
+ BKE_mesh_orco_verts_transform(mesh, orcodata, mesh->totvert, false);
+ CustomData_add_layer(&mesh->vdata, CD_ORCO, CD_ASSIGN, orcodata, mesh->totvert);
+}
+
int BKE_mesh_mface_index_validate(MFace *mface, CustomData *fdata, int mfindex, int nr)
{
/* first test if the face is legal */
@@ -1522,10 +1527,6 @@ void BKE_mesh_smooth_flag_set(Mesh *me, const bool use_smooth)
}
}
-/**
- * Find the index of the loop in 'poly' which references vertex,
- * returns -1 if not found
- */
int poly_find_loop_from_vert(const MPoly *poly, const MLoop *loopstart, uint vert)
{
for (int j = 0; j < poly->totloop; j++, loopstart++) {
@@ -1537,11 +1538,6 @@ int poly_find_loop_from_vert(const MPoly *poly, const MLoop *loopstart, uint ver
return -1;
}
-/**
- * Fill \a r_adj with the loop indices in \a poly adjacent to the
- * vertex. Returns the index of the loop matching vertex, or -1 if the
- * vertex is not in \a poly
- */
int poly_get_adj_loops_from_vert(const MPoly *poly, const MLoop *mloop, uint vert, uint r_adj[2])
{
int corner = poly_find_loop_from_vert(poly, &mloop[poly->loopstart], vert);
@@ -1555,10 +1551,6 @@ int poly_get_adj_loops_from_vert(const MPoly *poly, const MLoop *mloop, uint ver
return corner;
}
-/**
- * Return the index of the edge vert that is not equal to \a v. If
- * neither edge vertex is equal to \a v, returns -1.
- */
int BKE_mesh_edge_other_vert(const MEdge *e, int v)
{
if (e->v1 == v) {
@@ -1571,9 +1563,6 @@ int BKE_mesh_edge_other_vert(const MEdge *e, int v)
return -1;
}
-/**
- * Sets each output array element to the edge index if it is a real edge, or -1.
- */
void BKE_mesh_looptri_get_real_edges(const Mesh *mesh, const MLoopTri *looptri, int r_edges[3])
{
for (int i = 2, i_next = 0; i_next < 3; i = i_next++) {
@@ -1586,7 +1575,6 @@ void BKE_mesh_looptri_get_real_edges(const Mesh *mesh, const MLoopTri *looptri,
}
}
-/* basic vertex data functions */
bool BKE_mesh_minmax(const Mesh *me, float r_min[3], float r_max[3])
{
int i = me->totvert;
@@ -1768,9 +1756,6 @@ void BKE_mesh_mselect_validate(Mesh *me)
me->mselect = mselect_dst;
}
-/**
- * Return the index within me->mselect, or -1
- */
int BKE_mesh_mselect_find(Mesh *me, int index, int type)
{
BLI_assert(ELEM(type, ME_VSEL, ME_ESEL, ME_FSEL));
@@ -1784,9 +1769,6 @@ int BKE_mesh_mselect_find(Mesh *me, int index, int type)
return -1;
}
-/**
- * Return The index of the active element.
- */
int BKE_mesh_mselect_active_get(Mesh *me, int type)
{
BLI_assert(ELEM(type, ME_VSEL, ME_ESEL, ME_FSEL));
@@ -1887,13 +1869,6 @@ void BKE_mesh_vert_normals_apply(Mesh *mesh, const short (*vert_normals)[3])
mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
}
-/**
- * Compute 'split' (aka loop, or per face corner's) normals.
- *
- * \param r_lnors_spacearr: Allows to get computed loop normal space array.
- * That data, among other things, contains 'smooth fan' info, useful e.g.
- * to split geometry along sharp edges...
- */
void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spacearr)
{
float(*r_loopnors)[3];
@@ -2169,12 +2144,6 @@ static void split_faces_split_new_edges(Mesh *mesh,
}
}
-/* Split faces based on the edge angle and loop normals.
- * Matches behavior of face splitting in render engines.
- *
- * NOTE: Will leave CD_NORMAL loop data layer which is
- * used by render engines to set shading up.
- */
void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals)
{
const int num_polys = mesh->totpoly;
diff --git a/source/blender/blenkernel/intern/mesh_boolean_convert.cc b/source/blender/blenkernel/intern/mesh_boolean_convert.cc
index 3086f117707..771d79a0445 100644
--- a/source/blender/blenkernel/intern/mesh_boolean_convert.cc
+++ b/source/blender/blenkernel/intern/mesh_boolean_convert.cc
@@ -807,16 +807,6 @@ static Mesh *imesh_to_mesh(IMesh *im, MeshesToIMeshInfo &mim)
#endif // WITH_GMP
-/**
- * Do a mesh boolean operation directly on meshes (without going back and forth to BMesh).
- * \param meshes: An array of Mesh pointers.
- * \param obmats: An array of pointers to the obmat matrices that transform local
- * coordinates to global ones. It is allowed for the pointers to be null, meaning the
- * transformation is the identity.
- * \param material_remaps: An array of pointers to arrays of maps from material slot numbers in the
- * corresponding mesh to the material slot in the first mesh. It is OK for material_remaps or any
- * of its constituent arrays to be empty.
- */
Mesh *direct_mesh_boolean(Span<const Mesh *> meshes,
Span<const float4x4 *> obmats,
const float4x4 &target_transform,
diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc
index 1769be54211..e8054884f26 100644
--- a/source/blender/blenkernel/intern/mesh_convert.cc
+++ b/source/blender/blenkernel/intern/mesh_convert.cc
@@ -1277,11 +1277,6 @@ static void add_shapekey_layers(Mesh *mesh_dest, Mesh *mesh_src)
}
}
-/**
- * \param use_virtual_modifiers: When enabled calculate virtual-modifiers before applying `md_eval`
- * support this since virtual-modifiers are not modifiers from a user perspective,
- * allowing shape keys to be included with the modifier being applied, see: T91923.
- */
Mesh *BKE_mesh_create_derived_for_modifier(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob_eval,
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.cc b/source/blender/blenkernel/intern/mesh_evaluate.cc
index 91fd022a316..5cc1b4e4860 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.cc
+++ b/source/blender/blenkernel/intern/mesh_evaluate.cc
@@ -191,7 +191,6 @@ void BKE_mesh_calc_poly_center(const MPoly *mpoly,
}
}
-/* NOTE: passing poly-normal is only a speedup so we can skip calculating it. */
float BKE_mesh_calc_poly_area(const MPoly *mpoly, const MLoop *loopstart, const MVert *mvarray)
{
if (mpoly->totloop == 3) {
@@ -249,23 +248,6 @@ float BKE_mesh_calc_poly_uv_area(const MPoly *mpoly, const MLoopUV *uv_array)
return area;
}
-/**
- * Calculate the volume and volume-weighted centroid of the volume
- * formed by the polygon and the origin.
- * Results will be negative if the origin is "outside" the polygon
- * (+ve normal side), but the polygon may be non-planar with no effect.
- *
- * Method from:
- * - http://forums.cgsociety.org/archive/index.php?t-756235.html
- * - http://www.globalspec.com/reference/52702/203279/4-8-the-centroid-of-a-tetrahedron
- *
- * \note
- * - Volume is 6x actual volume, and centroid is 4x actual volume-weighted centroid
- * (so division can be done once at the end).
- * - Results will have bias if polygon is non-planar.
- * - The resulting volume will only be correct if the mesh is manifold and has consistent
- * face winding (non-contiguous face normals or holes in the mesh surface).
- */
static float UNUSED_FUNCTION(mesh_calc_poly_volume_centroid)(const MPoly *mpoly,
const MLoop *loopstart,
const MVert *mvarray,
@@ -445,10 +427,6 @@ bool BKE_mesh_center_median(const Mesh *me, float r_cent[3])
return (me->totvert != 0);
}
-/**
- * Calculate the center from polygons,
- * use when we want to ignore vertex locations that don't have connected faces.
- */
bool BKE_mesh_center_median_from_polys(const Mesh *me, float r_cent[3])
{
int i = me->totpoly;
@@ -514,10 +492,6 @@ bool BKE_mesh_center_of_surface(const Mesh *me, float r_cent[3])
return (me->totpoly != 0);
}
-/**
- * \note Mesh must be manifold with consistent face-winding,
- * see #mesh_calc_poly_volume_centroid for details.
- */
bool BKE_mesh_center_of_volume(const Mesh *me, float r_cent[3])
{
int i = me->totpoly;
@@ -602,12 +576,6 @@ static bool mesh_calc_center_centroid_ex(const MVert *mverts,
return true;
}
-/**
- * Calculate the volume and center.
- *
- * \param r_volume: Volume (unsigned).
- * \param r_center: Center of mass.
- */
void BKE_mesh_calc_volume(const MVert *mverts,
const int mverts_num,
const MLoopTri *looptri,
@@ -800,19 +768,6 @@ void BKE_mesh_convert_mfaces_to_mpolys(Mesh *mesh)
BKE_mesh_update_customdata_pointers(mesh, true);
}
-/**
- * The same as #BKE_mesh_convert_mfaces_to_mpolys
- * but oriented to be used in #do_versions from `readfile.c`
- * the difference is how active/render/clone/stencil indices are handled here.
- *
- * normally they're being set from `pdata` which totally makes sense for meshes which are already
- * converted to #BMesh structures, but when loading older files indices shall be updated in other
- * way around, so newly added `pdata` and `ldata` would have this indices set
- * based on `fdata` layer.
- *
- * this is normally only needed when reading older files,
- * in all other cases #BKE_mesh_convert_mfaces_to_mpolys shall be always used.
- */
void BKE_mesh_do_versions_convert_mfaces_to_mpolys(Mesh *mesh)
{
BKE_mesh_convert_mfaces_to_mpolys_ex(&mesh->id,
@@ -957,12 +912,9 @@ void BKE_mesh_convert_mfaces_to_mpolys_ex(ID *id,
#undef ME_FGON
}
+
/** \} */
-/**
- * Flip a single MLoop's #MDisps structure,
- * low level function to be called from face-flipping code which re-arranged the mdisps themselves.
- */
void BKE_mesh_mdisp_flip(MDisps *md, const bool use_loop_mdisp_flip)
{
if (UNLIKELY(!md->totdisp || !md->disps)) {
@@ -999,14 +951,6 @@ void BKE_mesh_mdisp_flip(MDisps *md, const bool use_loop_mdisp_flip)
}
}
-/**
- * Flip (invert winding of) the given \a mpoly, i.e. reverse order of its loops
- * (keeping the same vertex as 'start point').
- *
- * \param mpoly: the polygon to flip.
- * \param mloop: the full loops array.
- * \param ldata: the loops custom data.
- */
void BKE_mesh_polygon_flip_ex(MPoly *mpoly,
MLoop *mloop,
CustomData *ldata,
@@ -1056,11 +1000,6 @@ void BKE_mesh_polygon_flip(MPoly *mpoly, MLoop *mloop, CustomData *ldata)
BKE_mesh_polygon_flip_ex(mpoly, mloop, ldata, nullptr, mdisp, true);
}
-/**
- * Flip (invert winding of) all polygons (used to inverse their normals).
- *
- * \note Invalidates tessellation, caller must handle that.
- */
void BKE_mesh_polygons_flip(MPoly *mpoly, MLoop *mloop, CustomData *ldata, int totpoly)
{
MDisps *mdisp = (MDisps *)CustomData_get_layer(ldata, CD_MDISPS);
@@ -1076,8 +1015,6 @@ void BKE_mesh_polygons_flip(MPoly *mpoly, MLoop *mloop, CustomData *ldata, int t
/** \name Mesh Flag Flushing
* \{ */
-/* update the hide flag for edges and faces from the corresponding
- * flag in verts */
void BKE_mesh_flush_hidden_from_verts_ex(const MVert *mvert,
const MLoop *mloop,
MEdge *medge,
@@ -1149,9 +1086,6 @@ void BKE_mesh_flush_hidden_from_polys(Mesh *me)
me->mvert, me->mloop, me->medge, me->totedge, me->mpoly, me->totpoly);
}
-/**
- * simple poly -> vert/edge selection.
- */
void BKE_mesh_flush_select_from_polys_ex(MVert *mvert,
const int totvert,
const MLoop *mloop,
@@ -1248,23 +1182,13 @@ void BKE_mesh_flush_select_from_verts(Mesh *me)
BKE_mesh_flush_select_from_verts_ex(
me->mvert, me->totvert, me->mloop, me->medge, me->totedge, me->mpoly, me->totpoly);
}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name Mesh Spatial Calculation
* \{ */
-/**
- * This function takes the difference between 2 vertex-coord-arrays
- * (\a vert_cos_src, \a vert_cos_dst),
- * and applies the difference to \a vert_cos_new relative to \a vert_cos_org.
- *
- * \param vert_cos_src: reference deform source.
- * \param vert_cos_dst: reference deform destination.
- *
- * \param vert_cos_org: reference for the output location.
- * \param vert_cos_new: resulting coords.
- */
void BKE_mesh_calc_relative_deform(const MPoly *mpoly,
const int totpoly,
const MLoop *mloop,
@@ -1318,4 +1242,5 @@ void BKE_mesh_calc_relative_deform(const MPoly *mpoly,
MEM_freeN(vert_accum);
}
+
/** \} */
diff --git a/source/blender/blenkernel/intern/mesh_iterators.c b/source/blender/blenkernel/intern/mesh_iterators.c
index 7a776b0ecb7..3b6afc1f47a 100644
--- a/source/blender/blenkernel/intern/mesh_iterators.c
+++ b/source/blender/blenkernel/intern/mesh_iterators.c
@@ -34,7 +34,6 @@
#include "MEM_guardedalloc.h"
-/* Copied from cdDM_foreachMappedVert */
void BKE_mesh_foreach_mapped_vert(Mesh *mesh,
void (*func)(void *userData,
int index,
@@ -95,11 +94,6 @@ void BKE_mesh_foreach_mapped_vert(Mesh *mesh,
}
}
-/**
- * Copied from #cdDM_foreachMappedEdge.
- * \param tot_edges: Number of original edges. Used to avoid calling the callback with invalid
- * edge indices.
- */
void BKE_mesh_foreach_mapped_edge(
Mesh *mesh,
const int tot_edges,
@@ -151,7 +145,6 @@ void BKE_mesh_foreach_mapped_edge(
}
}
-/* Copied from cdDM_foreachMappedLoop */
void BKE_mesh_foreach_mapped_loop(Mesh *mesh,
void (*func)(void *userData,
int vertex_index,
@@ -232,7 +225,6 @@ void BKE_mesh_foreach_mapped_loop(Mesh *mesh,
}
}
-/* Copied from cdDM_foreachMappedFaceCenter */
void BKE_mesh_foreach_mapped_face_center(
Mesh *mesh,
void (*func)(void *userData, int index, const float cent[3], const float no[3]),
@@ -309,7 +301,6 @@ void BKE_mesh_foreach_mapped_face_center(
}
}
-/* Copied from cdDM_foreachMappedFaceCenter */
void BKE_mesh_foreach_mapped_subdiv_face_center(
Mesh *mesh,
void (*func)(void *userData, int index, const float cent[3], const float no[3]),
diff --git a/source/blender/blenkernel/intern/mesh_mapping.c b/source/blender/blenkernel/intern/mesh_mapping.c
index d28bb9c0744..415cce95d38 100644
--- a/source/blender/blenkernel/intern/mesh_mapping.c
+++ b/source/blender/blenkernel/intern/mesh_mapping.c
@@ -42,9 +42,6 @@
* \{ */
/* ngon version wip, based on BM_uv_vert_map_create */
-/* this replaces the non bmesh function (in trunk) which takes MTFace's,
- * if we ever need it back we could but for now this replaces it because its unused. */
-
UvVertMap *BKE_mesh_uv_vert_map_create(const MPoly *mpoly,
const MLoop *mloop,
const MLoopUV *mloopuv,
@@ -250,11 +247,6 @@ static void mesh_vert_poly_or_loop_map_create(MeshElemMap **r_map,
*r_mem = indices;
}
-/**
- * Generates a map where the key is the vertex and the value
- * is a list of polys that use that vertex as a corner.
- * The lists are allocated from one memory pool.
- */
void BKE_mesh_vert_poly_map_create(MeshElemMap **r_map,
int **r_mem,
const MPoly *mpoly,
@@ -266,11 +258,6 @@ void BKE_mesh_vert_poly_map_create(MeshElemMap **r_map,
mesh_vert_poly_or_loop_map_create(r_map, r_mem, mpoly, mloop, totvert, totpoly, totloop, false);
}
-/**
- * Generates a map where the key is the vertex and the value
- * is a list of loops that use that vertex as a corner.
- * The lists are allocated from one memory pool.
- */
void BKE_mesh_vert_loop_map_create(MeshElemMap **r_map,
int **r_mem,
const MPoly *mpoly,
@@ -282,11 +269,6 @@ void BKE_mesh_vert_loop_map_create(MeshElemMap **r_map,
mesh_vert_poly_or_loop_map_create(r_map, r_mem, mpoly, mloop, totvert, totpoly, totloop, true);
}
-/**
- * Generates a map where the key is the edge and the value
- * is a list of looptris that use that edge.
- * The lists are allocated from one memory pool.
- */
void BKE_mesh_vert_looptri_map_create(MeshElemMap **r_map,
int **r_mem,
const MVert *UNUSED(mvert),
@@ -331,11 +313,6 @@ void BKE_mesh_vert_looptri_map_create(MeshElemMap **r_map,
*r_mem = indices;
}
-/**
- * Generates a map where the key is the vertex and the value
- * is a list of edges that use that vertex as an endpoint.
- * The lists are allocated from one memory pool.
- */
void BKE_mesh_vert_edge_map_create(
MeshElemMap **r_map, int **r_mem, const MEdge *medge, int totvert, int totedge)
{
@@ -375,10 +352,6 @@ void BKE_mesh_vert_edge_map_create(
*r_mem = indices;
}
-/**
- * A version of #BKE_mesh_vert_edge_map_create that references connected vertices directly
- * (not their edges).
- */
void BKE_mesh_vert_edge_vert_map_create(
MeshElemMap **r_map, int **r_mem, const MEdge *medge, int totvert, int totedge)
{
@@ -418,11 +391,6 @@ void BKE_mesh_vert_edge_vert_map_create(
*r_mem = indices;
}
-/**
- * Generates a map where the key is the edge and the value is a list of loops that use that edge.
- * Loops indices of a same poly are contiguous and in winding order.
- * The lists are allocated from one memory pool.
- */
void BKE_mesh_edge_loop_map_create(MeshElemMap **r_map,
int **r_mem,
const MEdge *UNUSED(medge),
@@ -476,11 +444,6 @@ void BKE_mesh_edge_loop_map_create(MeshElemMap **r_map,
*r_mem = indices;
}
-/**
- * Generates a map where the key is the edge and the value
- * is a list of polygons that use that edge.
- * The lists are allocated from one memory pool.
- */
void BKE_mesh_edge_poly_map_create(MeshElemMap **r_map,
int **r_mem,
const MEdge *UNUSED(medge),
@@ -529,20 +492,6 @@ void BKE_mesh_edge_poly_map_create(MeshElemMap **r_map,
*r_mem = indices;
}
-/**
- * This function creates a map so the source-data (vert/edge/loop/poly)
- * can loop over the destination data (using the destination arrays origindex).
- *
- * This has the advantage that it can operate on any data-types.
- *
- * \param totsource: The total number of elements that \a final_origindex points to.
- * \param totfinal: The size of \a final_origindex
- * \param final_origindex: The size of the final array.
- *
- * \note `totsource` could be `totpoly`,
- * `totfinal` could be `tottessface` and `final_origindex` its ORIGINDEX custom-data.
- * This would allow an MPoly to loop over its tessfaces.
- */
void BKE_mesh_origindex_map_create(MeshElemMap **r_map,
int **r_mem,
const int totsource,
@@ -584,10 +533,6 @@ void BKE_mesh_origindex_map_create(MeshElemMap **r_map,
*r_mem = indices;
}
-/**
- * A version of #BKE_mesh_origindex_map_create that takes a looptri array.
- * Making a poly -> looptri map.
- */
void BKE_mesh_origindex_map_create_looptri(MeshElemMap **r_map,
int **r_mem,
const MPoly *mpoly,
@@ -630,7 +575,7 @@ void BKE_mesh_origindex_map_create_looptri(MeshElemMap **r_map,
typedef bool (*MeshRemap_CheckIslandBoundary)(const struct MPoly *mpoly,
const struct MLoop *mloop,
const struct MEdge *medge,
- const int nbr_egde_users,
+ const int nbr_edge_users,
const struct MPoly *mpoly_array,
const struct MeshElemMap *edge_poly_map,
void *user_data);
@@ -833,14 +778,14 @@ static void poly_edge_loop_islands_calc(const MEdge *medge,
static bool poly_is_island_boundary_smooth_cb(const MPoly *mp,
const MLoop *UNUSED(ml),
const MEdge *me,
- const int nbr_egde_users,
+ const int nbr_edge_users,
const MPoly *mpoly_array,
const MeshElemMap *edge_poly_map,
void *UNUSED(user_data))
{
/* Edge is sharp if one of its polys is flat, or edge itself is sharp,
* or edge is not used by exactly two polygons. */
- if ((mp->flag & ME_SMOOTH) && !(me->flag & ME_SHARP) && (nbr_egde_users == 2)) {
+ if ((mp->flag & ME_SMOOTH) && !(me->flag & ME_SHARP) && (nbr_edge_users == 2)) {
/* In that case, edge appears to be smooth, but we need to check its other poly too. */
const MPoly *mp_other = (mp == &mpoly_array[edge_poly_map->indices[0]]) ?
&mpoly_array[edge_poly_map->indices[1]] :
@@ -850,14 +795,6 @@ static bool poly_is_island_boundary_smooth_cb(const MPoly *mp,
return true;
}
-/**
- * Calculate smooth groups from sharp edges.
- *
- * \param r_totgroup: The total number of groups, 1 or more.
- * \return Polygon aligned array of group index values (bitflags if use_bitflags is true),
- * starting at 1 (0 being used as 'invalid' flag).
- * Note it's callers's responsibility to MEM_freeN returned array.
- */
int *BKE_mesh_calc_smoothgroups(const MEdge *medge,
const int totedge,
const MPoly *mpoly,
@@ -1012,7 +949,7 @@ typedef struct MeshCheckIslandBoundaryUv {
static bool mesh_check_island_boundary_uv(const MPoly *UNUSED(mp),
const MLoop *ml,
const MEdge *me,
- const int UNUSED(nbr_egde_users),
+ const int UNUSED(nbr_edge_users),
const MPoly *UNUSED(mpoly_array),
const MeshElemMap *UNUSED(edge_poly_map),
void *user_data)
@@ -1202,10 +1139,6 @@ static bool mesh_calc_islands_loop_poly_uv(MVert *UNUSED(verts),
return true;
}
-/**
- * Calculate 'generic' UV islands, i.e. based only on actual geometry data (edge seams),
- * not some UV layers coordinates.
- */
bool BKE_mesh_calc_islands_loop_poly_edgeseam(MVert *verts,
const int totvert,
MEdge *edges,
@@ -1220,19 +1153,6 @@ bool BKE_mesh_calc_islands_loop_poly_edgeseam(MVert *verts,
verts, totvert, edges, totedge, polys, totpoly, loops, totloop, NULL, r_island_store);
}
-/**
- * Calculate UV islands.
- *
- * \note If no MLoopUV layer is passed, we only consider edges tagged as seams as UV boundaries.
- * This has the advantages of simplicity, and being valid/common to all UV maps.
- * However, it means actual UV islands without matching UV seams will not be handled correctly...
- * If a valid UV layer is passed as \a luvs parameter,
- * UV coordinates are also used to detect islands boundaries.
- *
- * \note All this could be optimized...
- * Not sure it would be worth the more complex code, though,
- * those loops are supposed to be really quick to do...
- */
bool BKE_mesh_calc_islands_loop_poly_uvmap(MVert *verts,
const int totvert,
MEdge *edges,
diff --git a/source/blender/blenkernel/intern/mesh_merge.c b/source/blender/blenkernel/intern/mesh_merge.c
index d3d835378ca..0115a70a52a 100644
--- a/source/blender/blenkernel/intern/mesh_merge.c
+++ b/source/blender/blenkernel/intern/mesh_merge.c
@@ -204,38 +204,6 @@ static bool poly_gset_compare_fn(const void *k1, const void *k2)
return true;
}
-/**
- * Merge Verts
- *
- * This frees the given mesh and returns a new mesh.
- *
- * \param vtargetmap: The table that maps vertices to target vertices. a value of -1
- * indicates a vertex is a target, and is to be kept.
- * This array is aligned with 'mesh->totvert'
- * \warning \a vtargetmap must **not** contain any chained mapping (v1 -> v2 -> v3 etc.),
- * this is not supported and will likely generate corrupted geometry.
- *
- * \param tot_vtargetmap: The number of non '-1' values in vtargetmap. (not the size)
- *
- * \param merge_mode: enum with two modes.
- * - #MESH_MERGE_VERTS_DUMP_IF_MAPPED
- * When called by the Mirror Modifier,
- * In this mode it skips any faces that have all vertices merged (to avoid creating pairs
- * of faces sharing the same set of vertices)
- * - #MESH_MERGE_VERTS_DUMP_IF_EQUAL
- * When called by the Array Modifier,
- * In this mode, faces where all vertices are merged are double-checked,
- * to see whether all target vertices actually make up a poly already.
- * Indeed it could be that all of a poly's vertices are merged,
- * but merged to vertices that do not make up a single poly,
- * in which case the original poly should not be dumped.
- * Actually this later behavior could apply to the Mirror Modifier as well,
- * but the additional checks are costly and not necessary in the case of mirror,
- * because each vertex is only merged to its own mirror.
- *
- * \note #BKE_mesh_tessface_calc_ex has to run on the returned DM
- * if you want to access tessfaces.
- */
Mesh *BKE_mesh_merge_verts(Mesh *mesh,
const int *vtargetmap,
const int tot_vtargetmap,
diff --git a/source/blender/blenkernel/intern/mesh_mirror.c b/source/blender/blenkernel/intern/mesh_mirror.c
index 6df13e71e72..2d4308945fc 100644
--- a/source/blender/blenkernel/intern/mesh_mirror.c
+++ b/source/blender/blenkernel/intern/mesh_mirror.c
@@ -130,14 +130,11 @@ void BKE_mesh_mirror_apply_mirror_on_axis(struct Main *bmain,
BM_mesh_free(bm);
}
-/**
- * \warning This should _not_ be used to modify original meshes since
- * it doesn't handle shape-keys, use #BKE_mesh_mirror_apply_mirror_on_axis instead.
- */
Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd,
Object *ob,
const Mesh *mesh,
- const int axis)
+ const int axis,
+ const bool use_correct_order_on_merge)
{
const float tolerance_sq = mmd->tolerance * mmd->tolerance;
const bool do_vtargetmap = (mmd->flag & MOD_MIR_NO_MERGE) == 0;
@@ -266,23 +263,46 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd,
* Always merge from the copied into the original vertices so it's possible to
* generate a 1:1 mapping by scanning vertices from the beginning of the array
* as is done in #BKE_editmesh_vert_coords_when_deformed. Without this,
- * the coordinates returned will sometimes point to the copied vertex locations, see: T91444.
+ * the coordinates returned will sometimes point to the copied vertex locations, see:
+ * T91444.
+ *
+ * However, such a change also affects non-versionable things like some modifiers binding, so
+ * we cannot enforce that behavior on existing modifiers, in which case we keep using the
+ * old, incorrect behavior of merging the source vertex into its copy.
*/
- if (UNLIKELY(len_squared_v3v3(mv_prev->co, mv->co) < tolerance_sq)) {
- *vtmap_b = i;
- tot_vtargetmap++;
+ if (use_correct_order_on_merge) {
+ if (UNLIKELY(len_squared_v3v3(mv_prev->co, mv->co) < tolerance_sq)) {
+ *vtmap_b = i;
+ tot_vtargetmap++;
+
+ /* average location */
+ mid_v3_v3v3(mv->co, mv_prev->co, mv->co);
+ copy_v3_v3(mv_prev->co, mv->co);
+ }
+ else {
+ *vtmap_b = -1;
+ }
- /* average location */
- mid_v3_v3v3(mv->co, mv_prev->co, mv->co);
- copy_v3_v3(mv_prev->co, mv->co);
+ /* Fill here to avoid 2x loops. */
+ *vtmap_a = -1;
}
else {
+ if (UNLIKELY(len_squared_v3v3(mv_prev->co, mv->co) < tolerance_sq)) {
+ *vtmap_a = maxVerts + i;
+ tot_vtargetmap++;
+
+ /* average location */
+ mid_v3_v3v3(mv->co, mv_prev->co, mv->co);
+ copy_v3_v3(mv_prev->co, mv->co);
+ }
+ else {
+ *vtmap_a = -1;
+ }
+
+ /* Fill here to avoid 2x loops. */
*vtmap_b = -1;
}
- /* Fill here to avoid 2x loops. */
- *vtmap_a = -1;
-
vtmap_a++;
vtmap_b++;
}
diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc
index 9a761c6fa11..da5b4ccc764 100644
--- a/source/blender/blenkernel/intern/mesh_normals.cc
+++ b/source/blender/blenkernel/intern/mesh_normals.cc
@@ -316,9 +316,6 @@ void BKE_mesh_ensure_normals(Mesh *mesh)
BLI_assert((mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) == 0);
}
-/**
- * Called after calculating all modifiers.
- */
void BKE_mesh_ensure_normals_for_display(Mesh *mesh)
{
switch ((eMeshWrapperType)mesh->runtime.wrapper_type) {
@@ -378,10 +375,6 @@ void BKE_mesh_ensure_normals_for_display(Mesh *mesh)
}
}
-/**
- * NOTE: this does not update the #CD_NORMAL layer,
- * but does update the normals in the #CD_MVERT layer.
- */
void BKE_mesh_calc_normals(Mesh *mesh)
{
#ifdef DEBUG_TIME
@@ -479,13 +472,6 @@ void BKE_lnor_spacearr_init(MLoopNorSpaceArray *lnors_spacearr,
lnors_spacearr->data_type = data_type;
}
-/**
- * Utility for multi-threaded calculation that ensures
- * `lnors_spacearr_tls` doesn't share memory with `lnors_spacearr`
- * that would cause it not to be thread safe.
- *
- * \note This works as long as threads never operate on the same loops at once.
- */
void BKE_lnor_spacearr_tls_init(MLoopNorSpaceArray *lnors_spacearr,
MLoopNorSpaceArray *lnors_spacearr_tls)
{
@@ -493,10 +479,6 @@ void BKE_lnor_spacearr_tls_init(MLoopNorSpaceArray *lnors_spacearr,
lnors_spacearr_tls->mem = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
}
-/**
- * Utility for multi-threaded calculation
- * that merges `lnors_spacearr_tls` into `lnors_spacearr`.
- */
void BKE_lnor_spacearr_tls_join(MLoopNorSpaceArray *lnors_spacearr,
MLoopNorSpaceArray *lnors_spacearr_tls)
{
@@ -537,11 +519,6 @@ MLoopNorSpace *BKE_lnor_space_create(MLoopNorSpaceArray *lnors_spacearr)
/* This threshold is a bit touchy (usual float precision issue), this value seems OK. */
#define LNOR_SPACE_TRIGO_THRESHOLD (1.0f - 1e-4f)
-/* Should only be called once.
- * Beware, this modifies ref_vec and other_vec in place!
- * In case no valid space can be generated, ref_alpha and ref_beta are set to zero
- * (which means 'use auto lnors').
- */
void BKE_lnor_space_define(MLoopNorSpace *lnor_space,
const float lnor[3],
float vec_ref[3],
@@ -614,14 +591,6 @@ void BKE_lnor_space_define(MLoopNorSpace *lnor_space,
}
}
-/**
- * Add a new given loop to given lnor_space.
- * Depending on \a lnor_space->data_type, we expect \a bm_loop to be a pointer to BMLoop struct
- * (in case of BMLOOP_PTR), or nullptr (in case of LOOP_INDEX), loop index is then stored in
- * pointer. If \a is_single is set, the BMLoop or loop index is directly stored in \a
- * lnor_space->loops pointer (since there is only one loop in this fan), else it is added to the
- * linked list of loops in the fan.
- */
void BKE_lnor_space_add_loop(MLoopNorSpaceArray *lnors_spacearr,
MLoopNorSpace *lnor_space,
const int ml_index,
@@ -901,12 +870,6 @@ static void mesh_edges_sharp_tag(LoopSplitTaskDataCommon *data,
}
}
-/**
- * Define sharp edges as needed to mimic 'autosmooth' from angle threshold.
- *
- * Used when defining an empty custom loop normals data layer,
- * to keep same shading as with auto-smooth!
- */
void BKE_edges_sharp_from_angle_set(const struct MVert *mverts,
const int UNUSED(numVerts),
struct MEdge *medges,
@@ -1568,11 +1531,6 @@ static void loop_split_generator(TaskPool *pool, LoopSplitTaskDataCommon *common
#endif
}
-/**
- * Compute split normals, i.e. vertex normals associated with each poly (hence 'loop normals').
- * Useful to materialize sharp edges (or non-smooth faces) without actually modifying the geometry
- * (splitting edges).
- */
void BKE_mesh_normals_loop_split(const MVert *mverts,
const int UNUSED(numVerts),
MEdge *medges,
@@ -2057,36 +2015,16 @@ static void mesh_set_custom_normals(Mesh *mesh, float (*r_custom_nors)[3], const
}
}
-/**
- * Higher level functions hiding most of the code needed around call to
- * #BKE_mesh_normals_loop_custom_set().
- *
- * \param r_custom_loopnors: is not const, since code will replace zero_v3 normals there
- * with automatically computed vectors.
- */
void BKE_mesh_set_custom_normals(Mesh *mesh, float (*r_custom_loopnors)[3])
{
mesh_set_custom_normals(mesh, r_custom_loopnors, false);
}
-/**
- * Higher level functions hiding most of the code needed around call to
- * #BKE_mesh_normals_loop_custom_from_vertices_set().
- *
- * \param r_custom_vertnors: is not const, since code will replace zero_v3 normals there
- * with automatically computed vectors.
- */
void BKE_mesh_set_custom_normals_from_vertices(Mesh *mesh, float (*r_custom_vertnors)[3])
{
mesh_set_custom_normals(mesh, r_custom_vertnors, true);
}
-/**
- * Computes average per-vertex normals from given custom loop normals.
- *
- * \param clnors: The computed custom loop normals.
- * \param r_vert_clnors: The (already allocated) array where to store averaged per-vertex normals.
- */
void BKE_mesh_normals_loop_to_vertex(const int numVerts,
const MLoop *mloops,
const int numLoops,
diff --git a/source/blender/blenkernel/intern/mesh_remap.c b/source/blender/blenkernel/intern/mesh_remap.c
index 53a31cbbc7a..5b5378bd829 100644
--- a/source/blender/blenkernel/intern/mesh_remap.c
+++ b/source/blender/blenkernel/intern/mesh_remap.c
@@ -50,7 +50,7 @@
static CLG_LogRef LOG = {"bke.mesh"};
/* -------------------------------------------------------------------- */
-/** \name Some generic helpers.
+/** \name Some Generic Helpers
* \{ */
static bool mesh_remap_bvhtree_query_nearest(BVHTreeFromMesh *treedata,
@@ -117,22 +117,12 @@ static bool mesh_remap_bvhtree_query_raycast(BVHTreeFromMesh *treedata,
/** \} */
-/**
- * \name Auto-match.
+/* -------------------------------------------------------------------- */
+/** \name Auto-match.
*
* Find transform of a mesh to get best match with another.
* \{ */
-/**
- * Compute a value of the difference between both given meshes.
- * The smaller the result, the better the match.
- *
- * We return the inverse of the average of the inversed
- * shortest distance from each dst vertex to src ones.
- * In other words, beyond a certain (relatively small) distance, all differences have more or less
- * the same weight in final result, which allows to reduce influence of a few high differences,
- * in favor of a global good matching.
- */
float BKE_mesh_remap_calc_difference_from_mesh(const SpaceTransform *space_transform,
const MVert *verts_dst,
const int numverts_dst,
@@ -268,9 +258,6 @@ static void mesh_calc_eigen_matrix(const MVert *verts,
copy_v3_v3(r_mat[3], center);
}
-/**
- * Set r_space_transform so that best bbox of dst matches best bbox of src.
- */
void BKE_mesh_remap_find_best_match_from_mesh(const MVert *verts_dst,
const int numverts_dst,
Mesh *me_src,
@@ -328,7 +315,7 @@ void BKE_mesh_remap_find_best_match_from_mesh(const MVert *verts_dst,
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Mesh to mesh mapping
+/** \name Mesh to Mesh Mapping
* \{ */
void BKE_mesh_remap_calc_source_cddata_masks_from_map_modes(const int UNUSED(vert_mode),
diff --git a/source/blender/blenkernel/intern/mesh_runtime.c b/source/blender/blenkernel/intern/mesh_runtime.c
index 7b1d5140421..45c84ed0862 100644
--- a/source/blender/blenkernel/intern/mesh_runtime.c
+++ b/source/blender/blenkernel/intern/mesh_runtime.c
@@ -74,28 +74,17 @@ static void mesh_runtime_free_mutexes(Mesh *mesh)
}
}
-/**
- * \brief Initialize the runtime of the given mesh.
- *
- * Function expects that the runtime is already cleared.
- */
void BKE_mesh_runtime_init_data(Mesh *mesh)
{
mesh_runtime_init_mutexes(mesh);
}
-/**
- * \brief Free all data (and mutexes) inside the runtime of the given mesh.
- */
void BKE_mesh_runtime_free_data(Mesh *mesh)
{
BKE_mesh_runtime_clear_cache(mesh);
mesh_runtime_free_mutexes(mesh);
}
-/* Clear all pointers which we don't want to be shared on copying the datablock.
- * However, keep all the flags which defines what the mesh is (for example, that
- * it's deformed only, or that its custom data layers are out of date.) */
void BKE_mesh_runtime_reset_on_copy(Mesh *mesh, const int UNUSED(flag))
{
Mesh_Runtime *runtime = &mesh->runtime;
@@ -111,11 +100,6 @@ void BKE_mesh_runtime_reset_on_copy(Mesh *mesh, const int UNUSED(flag))
mesh_runtime_init_mutexes(mesh);
}
-/**
- * \brief This function clears runtime cache of the given mesh.
- *
- * Call this function to recalculate runtime data when used.
- */
void BKE_mesh_runtime_clear_cache(Mesh *mesh)
{
if (mesh->runtime.mesh_eval != NULL) {
@@ -128,7 +112,6 @@ void BKE_mesh_runtime_clear_cache(Mesh *mesh)
BKE_mesh_runtime_clear_edit_data(mesh);
}
-/* This is a ported copy of DM_ensure_looptri_data(dm) */
/**
* Ensure the array is large enough
*
@@ -137,6 +120,7 @@ void BKE_mesh_runtime_clear_cache(Mesh *mesh)
*/
static void mesh_ensure_looptri_data(Mesh *mesh)
{
+ /* This is a ported copy of `DM_ensure_looptri_data(dm)`. */
const uint totpoly = mesh->totpoly;
const int looptris_len = poly_to_tri_count(totpoly, mesh->totloop);
@@ -162,7 +146,6 @@ static void mesh_ensure_looptri_data(Mesh *mesh)
}
}
-/* This is a ported copy of CDDM_recalc_looptri(dm). */
void BKE_mesh_runtime_looptri_recalc(Mesh *mesh)
{
mesh_ensure_looptri_data(mesh);
@@ -182,9 +165,9 @@ void BKE_mesh_runtime_looptri_recalc(Mesh *mesh)
mesh->runtime.looptris.array_wip = NULL;
}
-/* This is a ported copy of dm_getNumLoopTri(dm). */
int BKE_mesh_runtime_looptri_len(const Mesh *mesh)
{
+ /* This is a ported copy of `dm_getNumLoopTri(dm)`. */
const int looptri_len = poly_to_tri_count(mesh->totpoly, mesh->totloop);
BLI_assert(ELEM(mesh->runtime.looptris.len, 0, looptri_len));
return looptri_len;
@@ -196,11 +179,6 @@ static void mesh_runtime_looptri_recalc_isolated(void *userdata)
BKE_mesh_runtime_looptri_recalc(mesh);
}
-/**
- * \note This function only fills a cache, and therefore the mesh argument can
- * be considered logically const. Concurrent access is protected by a mutex.
- * \note This is a ported copy of dm_getLoopTriArray(dm).
- */
const MLoopTri *BKE_mesh_runtime_looptri_ensure(const Mesh *mesh)
{
ThreadMutex *mesh_eval_mutex = (ThreadMutex *)mesh->runtime.eval_mutex;
@@ -222,7 +200,6 @@ const MLoopTri *BKE_mesh_runtime_looptri_ensure(const Mesh *mesh)
return looptri;
}
-/* This is a copy of DM_verttri_from_looptri(). */
void BKE_mesh_runtime_verttri_from_looptri(MVertTri *r_verttri,
const MLoop *mloop,
const MLoopTri *looptri,
@@ -314,10 +291,10 @@ void BKE_mesh_batch_cache_free(Mesh *me)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Mesh runtime debug helpers.
+/** \name Mesh Runtime Debug Helpers
* \{ */
-/* evaluated mesh info printing function,
- * to help track down differences output */
+
+/* Evaluated mesh info printing function, to help track down differences output. */
#ifndef NDEBUG
# include "BLI_dynstr.h"
@@ -412,7 +389,6 @@ void BKE_mesh_runtime_debug_print(Mesh *me_eval)
MEM_freeN(str);
}
-/* XXX Should go in customdata file? */
void BKE_mesh_runtime_debug_print_cdlayers(CustomData *data)
{
int i;
diff --git a/source/blender/blenkernel/intern/mesh_tangent.c b/source/blender/blenkernel/intern/mesh_tangent.c
index e5e971fd574..c7a1b22dad1 100644
--- a/source/blender/blenkernel/intern/mesh_tangent.c
+++ b/source/blender/blenkernel/intern/mesh_tangent.c
@@ -115,12 +115,6 @@ static void set_tspace(const SMikkTSpaceContext *pContext,
p_res[3] = face_sign;
}
-/**
- * Compute simplified tangent space normals, i.e.
- * tangent vector + sign of bi-tangent one, which combined with
- * split normals can be used to recreate the full tangent space.
- * NOTE: * The mesh should be made of only tris and quads!
- */
void BKE_mesh_calc_loop_tangent_single_ex(const MVert *mverts,
const int UNUSED(numVerts),
const MLoop *mloops,
@@ -172,12 +166,6 @@ void BKE_mesh_calc_loop_tangent_single_ex(const MVert *mverts,
}
}
-/**
- * Wrapper around BKE_mesh_calc_loop_tangent_single_ex, which takes care of most boiling code.
- * \note
- * - There must be a valid loop's CD_NORMALS available.
- * - The mesh should be made of only tris and quads!
- */
void BKE_mesh_calc_loop_tangent_single(Mesh *mesh,
const char *uvmap,
float (*r_looptangents)[4],
@@ -485,12 +473,6 @@ void BKE_mesh_add_loop_tangent_named_layer_for_uv(CustomData *uv_data,
}
}
-/**
- * Here we get some useful information such as active uv layer name and
- * search if it is already in tangent_names.
- * Also, we calculate tangent_mask that works as a descriptor of tangents state.
- * If tangent_mask has changed, then recalculate tangents.
- */
void BKE_mesh_calc_loop_tangent_step_0(const CustomData *loopData,
bool calc_active_tangent,
const char (*tangent_names)[MAX_NAME],
@@ -564,9 +546,6 @@ void BKE_mesh_calc_loop_tangent_step_0(const CustomData *loopData,
}
}
-/**
- * See: #BKE_editmesh_loop_tangent_calc (matching logic).
- */
void BKE_mesh_calc_loop_tangent_ex(const MVert *mvert,
const MPoly *mpoly,
const uint mpoly_len,
diff --git a/source/blender/blenkernel/intern/mesh_tessellate.c b/source/blender/blenkernel/intern/mesh_tessellate.c
index 213f2929d63..241aefc418c 100644
--- a/source/blender/blenkernel/intern/mesh_tessellate.c
+++ b/source/blender/blenkernel/intern/mesh_tessellate.c
@@ -154,17 +154,6 @@ static void mesh_loops_to_tessdata(CustomData *fdata,
}
}
-/**
- * Recreate #MFace Tessellation.
- *
- * \param do_face_nor_copy: Controls whether the normals from the poly
- * are copied to the tessellated faces.
- *
- * \return number of tessellation faces.
- *
- * \note This doesn't use multi-threading like #BKE_mesh_recalc_looptri since
- * it's not used in many places and #MFace should be phased out.
- */
int BKE_mesh_tessface_calc_ex(CustomData *fdata,
CustomData *ldata,
CustomData *pdata,
@@ -712,9 +701,6 @@ static void mesh_recalc_looptri__multi_threaded(const MLoop *mloop,
&settings);
}
-/**
- * Calculate tessellation into #MLoopTri which exist only for this purpose.
- */
void BKE_mesh_recalc_looptri(const MLoop *mloop,
const MPoly *mpoly,
const MVert *mvert,
@@ -730,14 +716,6 @@ void BKE_mesh_recalc_looptri(const MLoop *mloop,
}
}
-/**
- * A version of #BKE_mesh_recalc_looptri which takes pre-calculated polygon normals
- * (used to avoid having to calculate the face normal for NGON tessellation).
- *
- * \note Only use this function if normals have already been calculated, there is no need
- * to calculate normals just to use this function as it will cause the normals for triangles
- * to be calculated which aren't needed for tessellation.
- */
void BKE_mesh_recalc_looptri_with_normals(const MLoop *mloop,
const MPoly *mpoly,
const MVert *mvert,
diff --git a/source/blender/blenkernel/intern/mesh_validate.c b/source/blender/blenkernel/intern/mesh_validate.c
index 08668d55cf4..ba86c0fd449 100644
--- a/source/blender/blenkernel/intern/mesh_validate.c
+++ b/source/blender/blenkernel/intern/mesh_validate.c
@@ -193,6 +193,7 @@ static int search_polyloop_cmp(const void *v1, const void *v2)
/* Else, sort on loopstart. */
return sp1->loopstart > sp2->loopstart ? 1 : sp1->loopstart < sp2->loopstart ? -1 : 0;
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -213,21 +214,6 @@ static int search_polyloop_cmp(const void *v1, const void *v2)
} \
} while (0)
-/**
- * Validate the mesh, \a do_fixes requires \a mesh to be non-null.
- *
- * \return false if no changes needed to be made.
- *
- * Vertex Normals
- * ==============
- *
- * While zeroed normals are checked, these checks aren't comprehensive.
- * Technically, to detect errors here a normal recalculation and comparison is necessary.
- * However this function is mainly to prevent severe errors in geometry
- * (invalid data that will crash Blender, or cause some features to behave incorrectly),
- * not to detect subtle differences in the resulting normals which could be caused
- * by importers that load normals (for example).
- */
/* NOLINTNEXTLINE: readability-function-size */
bool BKE_mesh_validate_arrays(Mesh *mesh,
MVert *mverts,
@@ -997,9 +983,6 @@ static bool mesh_validate_customdata(CustomData *data,
return is_valid;
}
-/**
- * \returns is_valid.
- */
bool BKE_mesh_validate_all_customdata(CustomData *vdata,
const uint totvert,
CustomData *edata,
@@ -1061,11 +1044,6 @@ bool BKE_mesh_validate_all_customdata(CustomData *vdata,
return is_valid;
}
-/**
- * Validates and corrects a Mesh.
- *
- * \returns true if a change is made.
- */
bool BKE_mesh_validate(Mesh *me, const bool do_verbose, const bool cddata_check_mask)
{
bool is_valid = true;
@@ -1112,13 +1090,6 @@ bool BKE_mesh_validate(Mesh *me, const bool do_verbose, const bool cddata_check_
return false;
}
-/**
- * Checks if a Mesh is valid without any modification. This is always verbose.
- *
- * \see #DM_is_valid to call on derived meshes
- *
- * \returns is_valid.
- */
bool BKE_mesh_is_valid(Mesh *me)
{
const bool do_verbose = true;
@@ -1162,10 +1133,6 @@ bool BKE_mesh_is_valid(Mesh *me)
return is_valid;
}
-/**
- * Check all material indices of polygons are valid, invalid ones are set to 0.
- * \returns is_valid.
- */
bool BKE_mesh_validate_material_indices(Mesh *me)
{
/* Cast to unsigned to catch negative indices too. */
@@ -1196,9 +1163,9 @@ bool BKE_mesh_validate_material_indices(Mesh *me)
/** \name Mesh Stripping (removing invalid data)
* \{ */
-/* We need to keep this for edge creation (for now?), and some old readfile code... */
void BKE_mesh_strip_loose_faces(Mesh *me)
{
+ /* NOTE: We need to keep this for edge creation (for now?), and some old `readfile.c` code. */
MFace *f;
int a, b;
@@ -1217,13 +1184,6 @@ void BKE_mesh_strip_loose_faces(Mesh *me)
}
}
-/**
- * Works on both loops and polys!
- *
- * \note It won't try to guess which loops of an invalid poly to remove!
- * this is the work of the caller, to mark those loops...
- * See e.g. #BKE_mesh_validate_arrays().
- */
void BKE_mesh_strip_loose_polysloops(Mesh *me)
{
MPoly *p;
@@ -1329,6 +1289,7 @@ void BKE_mesh_strip_loose_edges(Mesh *me)
MEM_freeN(new_idx);
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1512,10 +1473,6 @@ static void mesh_calc_edges_mdata(MVert *UNUSED(allvert),
*r_totedge = totedge_final;
}
-/**
- * If the mesh is from a very old blender version,
- * convert mface->edcode to edge drawflags
- */
void BKE_mesh_calc_edges_legacy(Mesh *me, const bool use_old)
{
MEdge *medge;
@@ -1565,12 +1522,6 @@ void BKE_mesh_calc_edges_loose(Mesh *mesh)
}
}
-/**
- * Calculate/create edges from tessface data
- *
- * \param mesh: The mesh to add edges into
- */
-
void BKE_mesh_calc_edges_tessface(Mesh *mesh)
{
const int numFaces = mesh->totface;
diff --git a/source/blender/blenkernel/intern/mesh_validate.cc b/source/blender/blenkernel/intern/mesh_validate.cc
index 574ab785445..c8fae3cf880 100644
--- a/source/blender/blenkernel/intern/mesh_validate.cc
+++ b/source/blender/blenkernel/intern/mesh_validate.cc
@@ -220,9 +220,6 @@ static void clear_hash_tables(MutableSpan<EdgeMap> edge_maps)
} // namespace blender::bke::calc_edges
-/**
- * Calculate edges from polygons.
- */
void BKE_mesh_calc_edges(Mesh *mesh, bool keep_existing_edges, const bool select_new_edges)
{
using namespace blender;
diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c
index 6f6cf12f023..e1d201d7806 100644
--- a/source/blender/blenkernel/intern/modifier.c
+++ b/source/blender/blenkernel/intern/modifier.c
@@ -133,9 +133,6 @@ const ModifierTypeInfo *BKE_modifier_get_info(ModifierType type)
return NULL;
}
-/**
- * Get the idname of the modifier type's panel, which was defined in the #panelRegister callback.
- */
void BKE_modifier_type_panel_id(ModifierType type, char *r_idname)
{
const ModifierTypeInfo *mti = BKE_modifier_get_info(type);
@@ -213,9 +210,6 @@ void BKE_modifier_free(ModifierData *md)
BKE_modifier_free_ex(md, 0);
}
-/**
- * Use instead of `BLI_remlink` when the object's active modifier should change.
- */
void BKE_modifier_remove_from_list(Object *ob, ModifierData *md)
{
BLI_assert(BLI_findindex(&ob->modifiers, md) != -1);
@@ -328,9 +322,6 @@ void BKE_modifiers_foreach_tex_link(Object *ob, TexWalkFunc walk, void *userData
}
}
-/* callback's can use this
- * to avoid copying every member.
- */
void BKE_modifier_copydata_generic(const ModifierData *md_src,
ModifierData *md_dst,
const int UNUSED(flag))
@@ -457,13 +448,6 @@ void BKE_modifier_set_error(const Object *ob, ModifierData *md, const char *_for
CLOG_ERROR(&LOG, "Object: \"%s\", Modifier: \"%s\", %s", ob->id.name + 2, md->name, md->error);
}
-/* used for buttons, to find out if the 'draw deformed in editmode' option is
- * there
- *
- * also used in transform_conversion.c, to detect CrazySpace [tm] (2nd arg
- * then is NULL)
- * also used for some mesh tools to give warnings
- */
int BKE_modifiers_get_cage_index(const Scene *scene,
Object *ob,
int *r_lastPossibleCageIndex,
@@ -547,12 +531,6 @@ bool BKE_modifiers_is_particle_enabled(Object *ob)
return (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render));
}
-/**
- * Check whether is enabled.
- *
- * \param scene: Current scene, may be NULL,
- * in which case isDisabled callback of the modifier is never called.
- */
bool BKE_modifier_is_enabled(const struct Scene *scene, ModifierData *md, int required_mode)
{
const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
@@ -575,12 +553,6 @@ bool BKE_modifier_is_enabled(const struct Scene *scene, ModifierData *md, int re
return true;
}
-/**
- * Check whether given modifier is not local (i.e. from linked data) when the object is a library
- * override.
- *
- * \param md: May be NULL, in which case we consider it as a non-local modifier case.
- */
bool BKE_modifier_is_nonlocal_in_liboverride(const Object *ob, const ModifierData *md)
{
return (ID_IS_OVERRIDE_LIBRARY(ob) &&
@@ -674,8 +646,6 @@ ModifierData *BKE_modifier_get_last_preview(const struct Scene *scene,
return tmp_md;
}
-/* This is to include things that are not modifiers in the evaluation of the modifier stack, for
- * example parenting to an armature. */
ModifierData *BKE_modifiers_get_virtual_modifierlist(const Object *ob,
VirtualModifierData *virtualModifierData)
{
@@ -719,9 +689,6 @@ ModifierData *BKE_modifiers_get_virtual_modifierlist(const Object *ob,
return md;
}
-/* Takes an object and returns its first selected armature, else just its armature
- * This should work for multiple armatures per object
- */
Object *BKE_modifiers_is_deformed_by_armature(Object *ob)
{
if (ob->type == OB_GPENCIL) {
@@ -790,9 +757,6 @@ Object *BKE_modifiers_is_deformed_by_meshdeform(Object *ob)
return NULL;
}
-/* Takes an object and returns its first selected lattice, else just its lattice
- * This should work for multiple lattices per object
- */
Object *BKE_modifiers_is_deformed_by_lattice(Object *ob)
{
VirtualModifierData virtualModifierData;
@@ -816,9 +780,6 @@ Object *BKE_modifiers_is_deformed_by_lattice(Object *ob)
return NULL;
}
-/* Takes an object and returns its first selected curve, else just its curve
- * This should work for multiple curves per object
- */
Object *BKE_modifiers_is_deformed_by_curve(Object *ob)
{
VirtualModifierData virtualModifierData;
@@ -946,7 +907,6 @@ void BKE_modifier_free_temporary_data(ModifierData *md)
}
}
-/* ensure modifier correctness when changing ob->data */
void BKE_modifiers_test_object(Object *ob)
{
ModifierData *md;
@@ -967,45 +927,29 @@ void BKE_modifiers_test_object(Object *ob)
}
}
-/* where should this go?, it doesn't fit well anywhere :S - campbell */
-
-/* elubie: changed this to default to the same dir as the render output
- * to prevent saving to C:\ on Windows */
-
-/* campbell: logic behind this...
- *
- * - if the ID is from a library, return library path
- * - else if the file has been saved return the blend file path.
- * - else if the file isn't saved and the ID isn't from a library, return the temp dir.
- */
const char *BKE_modifier_path_relbase(Main *bmain, Object *ob)
{
- if (G.relbase_valid || ID_IS_LINKED(ob)) {
+ /* - If the ID is from a library, return library path.
+ * - Else if the file has been saved return the blend file path.
+ * - Else if the file isn't saved and the ID isn't from a library, return the temp dir.
+ */
+ if ((bmain->filepath[0] != '\0') || ID_IS_LINKED(ob)) {
return ID_BLEND_PATH(bmain, &ob->id);
}
- /* last resort, better than using "" which resolves to the current
- * working directory */
+ /* Last resort, better than using "" which resolves to the current working directory. */
return BKE_tempdir_session();
}
const char *BKE_modifier_path_relbase_from_global(Object *ob)
{
- if (G.relbase_valid || ID_IS_LINKED(ob)) {
- return ID_BLEND_PATH_FROM_GLOBAL(&ob->id);
- }
-
- /* last resort, better than using "" which resolves to the current
- * working directory */
- return BKE_tempdir_session();
+ return BKE_modifier_path_relbase(G_MAIN, ob);
}
-/* initializes the path with either */
void BKE_modifier_path_init(char *path, int path_maxlen, const char *name)
{
- /* elubie: changed this to default to the same dir as the render output
- * to prevent saving to C:\ on Windows */
- BLI_join_dirfile(path, path_maxlen, G.relbase_valid ? "//" : BKE_tempdir_session(), name);
+ const char *blendfile_path = BKE_main_blendfile_path_from_global();
+ BLI_join_dirfile(path, path_maxlen, blendfile_path[0] ? "//" : BKE_tempdir_session(), name);
}
/**
@@ -1086,15 +1030,6 @@ void BKE_modifier_deform_vertsEM(ModifierData *md,
/* end modifier callback wrappers */
-/**
- * Get evaluated mesh for other evaluated object, which is used as an operand for the modifier,
- * e.g. second operand for boolean modifier.
- * Note that modifiers in stack always get fully evaluated COW ID pointers,
- * never original ones. Makes things simpler.
- *
- * \param get_cage_mesh: Return evaluated mesh with only deforming modifiers applied
- * (i.e. mesh topology remains the same as original one, a.k.a. 'cage' mesh).
- */
Mesh *BKE_modifier_get_evaluated_mesh_from_evaluated_object(Object *ob_eval,
const bool get_cage_mesh)
{
diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c
index 34fb9f71bd9..fc2e7d0a6a3 100644
--- a/source/blender/blenkernel/intern/movieclip.c
+++ b/source/blender/blenkernel/intern/movieclip.c
@@ -60,6 +60,7 @@
#include "BLT_translation.h"
#include "BKE_anim_data.h"
+#include "BKE_bpath.h"
#include "BKE_colortools.h"
#include "BKE_global.h"
#include "BKE_idtype.h"
@@ -165,6 +166,12 @@ static void movie_clip_foreach_cache(ID *id,
function_callback(id, &key, (void **)&movie_clip->tracking.camera.intrinsics, 0, user_data);
}
+static void movie_clip_foreach_path(ID *id, BPathForeachPathData *bpath_data)
+{
+ MovieClip *movie_clip = (MovieClip *)id;
+ BKE_bpath_foreach_path_fixed_process(bpath_data, movie_clip->filepath);
+}
+
static void write_movieTracks(BlendWriter *writer, ListBase *tracks)
{
MovieTrackingTrack *track;
@@ -347,6 +354,7 @@ IDTypeInfo IDType_ID_MC = {
.name_plural = "movieclips",
.translation_context = BLT_I18NCONTEXT_ID_MOVIECLIP,
.flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = movie_clip_init_data,
.copy_data = movie_clip_copy_data,
@@ -354,6 +362,7 @@ IDTypeInfo IDType_ID_MC = {
.make_local = NULL,
.foreach_id = movie_clip_foreach_id,
.foreach_cache = movie_clip_foreach_cache,
+ .foreach_path = movie_clip_foreach_path,
.owner_get = NULL,
.blend_write = movieclip_blend_write,
@@ -535,10 +544,6 @@ static void movieclip_convert_multilayer_add_pass(void *UNUSED(layer),
#endif /* WITH_OPENEXR */
-/* Will try to make image buffer usable when originating from the multi-layer
- * source.
- * Internally finds a first combined pass and uses that as a buffer. Not ideal,
- * but is better than a complete empty buffer. */
void BKE_movieclip_convert_multilayer_ibuf(struct ImBuf *ibuf)
{
if (ibuf == NULL) {
@@ -979,10 +984,6 @@ static void detect_clip_source(Main *bmain, MovieClip *clip)
}
}
-/* checks if image was already loaded, then returns same image
- * otherwise creates new.
- * does not load ibuf itself
- * pass on optional frame for #name images */
MovieClip *BKE_movieclip_file_add(Main *bmain, const char *name)
{
MovieClip *clip;
@@ -1612,7 +1613,6 @@ void BKE_movieclip_get_aspect(MovieClip *clip, float *aspx, float *aspy)
*aspy = clip->aspy / clip->aspx / clip->tracking.camera.pixel_aspect;
}
-/* get segments of cached frames. useful for debugging cache policies */
void BKE_movieclip_get_cache_segments(MovieClip *clip,
MovieClipUser *user,
int *r_totseg,
@@ -1848,9 +1848,6 @@ static void movieclip_build_proxy_ibuf(
IMB_freeImBuf(scaleibuf);
}
-/* NOTE: currently used by proxy job for movies, threading happens within single frame
- * (meaning scaling shall be threaded)
- */
void BKE_movieclip_build_proxy_frame(MovieClip *clip,
int clip_flag,
struct MovieDistortion *distortion,
@@ -1892,9 +1889,6 @@ void BKE_movieclip_build_proxy_frame(MovieClip *clip,
}
}
-/* NOTE: currently used by proxy job for sequences, threading happens within sequence
- * (different threads handles different frames, no threading within frame is needed)
- */
void BKE_movieclip_build_proxy_frame_for_ibuf(MovieClip *clip,
ImBuf *ibuf,
struct MovieDistortion *distortion,
@@ -2150,4 +2144,5 @@ void BKE_movieclip_free_gputexture(struct MovieClip *clip)
MEM_freeN(tex);
}
}
+
/** \} */
diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c
index dc418545e23..fbad7d98630 100644
--- a/source/blender/blenkernel/intern/multires.c
+++ b/source/blender/blenkernel/intern/multires.c
@@ -330,9 +330,6 @@ MultiresModifierData *find_multires_modifier_before(Scene *scene, ModifierData *
return NULL;
}
-/* used for applying scale on mdisps layer and syncing subdivide levels when joining objects
- * use_first - return first multires modifier if all multires'es are disabled
- */
MultiresModifierData *get_multires_modifier(Scene *scene, Object *ob, bool use_first)
{
ModifierData *md;
@@ -519,7 +516,6 @@ static int get_levels_from_disps(Object *ob)
return totlvl;
}
-/* reset the multires levels to match the number of mdisps */
void multiresModifier_set_levels_from_disps(MultiresModifierData *mmd, Object *ob)
{
Mesh *me = ob->data;
@@ -712,7 +708,6 @@ static void multires_del_higher(MultiresModifierData *mmd, Object *ob, int lvl)
multires_set_tot_level(ob, mmd, lvl);
}
-/* (direction = 1) for delete higher, (direction = 0) for lower (not implemented yet) */
void multiresModifier_del_levels(MultiresModifierData *mmd,
Scene *scene,
Object *ob,
@@ -1295,7 +1290,6 @@ DerivedMesh *multires_make_derived_from_derived(
return result;
}
-/* Adapted from sculptmode.c */
void old_mdisps_bilinear(float out[3], float (*disps)[3], const int st, float u, float v)
{
int x, y, x2, y2;
@@ -1349,8 +1343,6 @@ void old_mdisps_bilinear(float out[3], float (*disps)[3], const int st, float u,
add_v3_v3v3(out, d2[0], d2[1]);
}
-/* If 'ob_src' and 'ob_dst' both have multires modifiers, synchronize them
- * such that 'ob_dst' has the same total number of levels as 'ob_src'. */
void multiresModifier_sync_levels_ex(Object *ob_dst,
MultiresModifierData *mmd_src,
MultiresModifierData *mmd_dst)
@@ -1469,7 +1461,6 @@ void multiresModifier_prepare_join(struct Depsgraph *depsgraph,
multires_apply_smat(depsgraph, scene, ob, mat);
}
-/* update multires data after topology changing */
void multires_topology_changed(Mesh *me)
{
MDisps *mdisp = NULL, *cur = NULL;
@@ -1504,11 +1495,6 @@ void multires_topology_changed(Mesh *me)
}
}
-/* Makes sure data from an external file is fully read.
- *
- * Since the multires data files only contain displacement vectors without knowledge about
- * subdivision level some extra work is needed. Namely make is to all displacement grids have
- * proper level and number of displacement vectors set. */
void multires_ensure_external_read(struct Mesh *mesh, int top_level)
{
if (!CustomData_external_test(&mesh->ldata, CD_MDISPS)) {
@@ -1544,7 +1530,6 @@ void multiresModifier_ensure_external_read(struct Mesh *mesh, const MultiresModi
/***************** Multires interpolation stuff *****************/
-/* Find per-corner coordinate with given per-face UV coord */
int mdisp_rot_face_to_crn(struct MVert *UNUSED(mvert),
struct MPoly *mpoly,
struct MLoop *UNUSED(mloop),
diff --git a/source/blender/blenkernel/intern/multires_reshape.c b/source/blender/blenkernel/intern/multires_reshape.c
index bd52d70b223..e0bb3cf792c 100644
--- a/source/blender/blenkernel/intern/multires_reshape.c
+++ b/source/blender/blenkernel/intern/multires_reshape.c
@@ -69,10 +69,6 @@ bool multiresModifier_reshapeFromVertcos(struct Depsgraph *depsgraph,
return true;
}
-/* Returns truth on success, false otherwise.
- *
- * This function might fail in cases like source and destination not having
- * matched amount of vertices. */
bool multiresModifier_reshapeFromObject(struct Depsgraph *depsgraph,
struct MultiresModifierData *mmd,
struct Object *dst,
diff --git a/source/blender/blenkernel/intern/multires_reshape.h b/source/blender/blenkernel/intern/multires_reshape.h
index 36ecf1a6395..db419418998 100644
--- a/source/blender/blenkernel/intern/multires_reshape.h
+++ b/source/blender/blenkernel/intern/multires_reshape.h
@@ -143,15 +143,19 @@ typedef struct ReshapeConstGridElement {
* Construct/destruct reshape context.
*/
-/* Create subdivision surface descriptor which is configured for surface evaluation at a given
- * multires modifier. */
+/**
+ * Create subdivision surface descriptor which is configured for surface evaluation at a given
+ * multi-res modifier.
+ */
struct Subdiv *multires_reshape_create_subdiv(struct Depsgraph *depsgraph,
struct Object *object,
const struct MultiresModifierData *mmd);
-/* NOTE: Initialized base mesh to object's mesh, the Subdiv is created from the deformed
- * mesh prior to the multires modifier if depsgraph is not NULL. If the depsgraph is NULL
- * then Subdiv is created from base mesh (without any deformation applied). */
+/**
+ * \note Initialized base mesh to object's mesh, the Subdivision is created from the deformed
+ * mesh prior to the multi-res modifier if depsgraph is not NULL. If the depsgraph is NULL
+ * then Subdivision is created from base mesh (without any deformation applied).
+ */
bool multires_reshape_context_create_from_object(MultiresReshapeContext *reshape_context,
struct Depsgraph *depsgraph,
struct Object *object,
@@ -185,29 +189,41 @@ void multires_reshape_context_free(MultiresReshapeContext *reshape_context);
* Helper accessors.
*/
-/* For the given grid index get index of face it was created for. */
+/**
+ * For the given grid index get index of face it was created for.
+ */
int multires_reshape_grid_to_face_index(const MultiresReshapeContext *reshape_context,
int grid_index);
-/* For the given grid index get corner of a face it was created for. */
+/**
+ * For the given grid index get corner of a face it was created for.
+ */
int multires_reshape_grid_to_corner(const MultiresReshapeContext *reshape_context, int grid_index);
bool multires_reshape_is_quad_face(const MultiresReshapeContext *reshape_context, int face_index);
-/* For the given grid index get index of corresponding ptex face. */
+/**
+ * For the given grid index get index of corresponding PTEX face.
+ */
int multires_reshape_grid_to_ptex_index(const MultiresReshapeContext *reshape_context,
int grid_index);
-/* Convert normalized coordinate within a grid to a normalized coordinate within a ptex face. */
+/**
+ * Convert normalized coordinate within a grid to a normalized coordinate within a PTEX face.
+ */
PTexCoord multires_reshape_grid_coord_to_ptex(const MultiresReshapeContext *reshape_context,
const GridCoord *grid_coord);
-/* Convert a normalized coordinate within a ptex face to a normalized coordinate within a grid. */
+/**
+ * Convert a normalized coordinate within a PTEX face to a normalized coordinate within a grid.
+ */
GridCoord multires_reshape_ptex_coord_to_grid(const MultiresReshapeContext *reshape_context,
const PTexCoord *ptex_coord);
-/* Calculate tangent matrix which converts displacement to a object vector.
- * Is calculated for the given surface derivatives at a given base face corner. */
+/**
+ * Calculate tangent matrix which converts displacement to a object vector.
+ * Is calculated for the given surface derivatives at a given base face corner.
+ */
void multires_reshape_tangent_matrix_for_corner(const MultiresReshapeContext *reshape_context,
const int face_index,
const int corner,
@@ -215,14 +231,18 @@ void multires_reshape_tangent_matrix_for_corner(const MultiresReshapeContext *re
const float dPdv[3],
float r_tangent_matrix[3][3]);
-/* Get grid elements which are to be reshaped at a given or ptex coordinate.
- * The data is coming from final custom mdata layers. */
+/**
+ * Get grid elements which are to be reshaped at a given or PTEX coordinate.
+ * The data is coming from final custom mdata layers.
+ */
ReshapeGridElement multires_reshape_grid_element_for_grid_coord(
const MultiresReshapeContext *reshape_context, const GridCoord *grid_coord);
ReshapeGridElement multires_reshape_grid_element_for_ptex_coord(
const MultiresReshapeContext *reshape_context, const PTexCoord *ptex_coord);
-/* Get original grid element for the given coordinate. */
+/**
+ * Get original grid element for the given coordinate.
+ */
ReshapeConstGridElement multires_reshape_orig_grid_element_for_grid_coord(
const MultiresReshapeContext *reshape_context, const GridCoord *grid_coord);
@@ -230,8 +250,10 @@ ReshapeConstGridElement multires_reshape_orig_grid_element_for_grid_coord(
* Sample limit surface of the base mesh.
*/
-/* Evaluate limit surface created from base mesh.
- * This is the limit surface which defines tangent space for MDisps. */
+/**
+ * Evaluate limit surface created from base mesh.
+ * This is the limit surface which defines tangent space for MDisps.
+ */
void multires_reshape_evaluate_limit_at_grid(const MultiresReshapeContext *reshape_context,
const GridCoord *grid_coord,
float r_P[3],
@@ -241,17 +263,23 @@ void multires_reshape_evaluate_limit_at_grid(const MultiresReshapeContext *resha
* Custom data preparation.
*/
-/* Make sure custom data is allocated for the given level. */
+/**
+ * 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.
*/
-/* Returns truth if all coordinates were assigned.
+/**
+ * Set displacement grids values at a reshape level to a object coordinates of the given source.
+ *
+ * \returns truth if all coordinates were assigned.
*
* False will be returned if the number of vertex coordinates did not match required number of
- * vertices at a reshape level. */
+ * vertices at a reshape level.
+ */
bool multires_reshape_assign_final_coords_from_vertcos(
const MultiresReshapeContext *reshape_context,
const float (*vert_coords)[3],
@@ -261,13 +289,15 @@ bool multires_reshape_assign_final_coords_from_vertcos(
* Functions specific to reshaping from CCG.
*/
-/* Store final object-space coordinates in the displacement grids.
+/**
+ * Store final object-space coordinates in the displacement grids.
* The reason why displacement grids are used for storage is based on memory
* footprint optimization.
*
- * NOTE: Displacement grids to be at least at a reshape level.
+ * \note Displacement grids to be at least at a reshape level.
*
- * Return truth if all coordinates have been updated. */
+ * \return truth if all coordinates have been updated.
+ */
bool multires_reshape_assign_final_coords_from_ccg(const MultiresReshapeContext *reshape_context,
struct SubdivCCG *subdiv_ccg);
@@ -275,11 +305,15 @@ bool multires_reshape_assign_final_coords_from_ccg(const MultiresReshapeContext
* Functions specific to reshaping from MDISPS.
*/
-/* Reads and writes to the current mesh CD_MDISPS. */
+/**
+ * Reads and writes to the current mesh #CD_MDISPS.
+ */
void multires_reshape_assign_final_coords_from_mdisps(
const MultiresReshapeContext *reshape_context);
-/* Reads from original CD_MIDTSPS, writes to the current mesh CD_MDISPS. */
+/**
+ * Reads from original #CD_MIDTSPS, writes to the current mesh #CD_MDISPS.
+ */
void multires_reshape_assign_final_elements_from_orig_mdisps(
const MultiresReshapeContext *reshape_context);
@@ -287,15 +321,18 @@ void multires_reshape_assign_final_elements_from_orig_mdisps(
* Displacement smooth.
*/
-/* Operates on a displacement grids (CD_MDISPS) which contains object space coordinates stored for
+/**
+ * Operates on a displacement grids (CD_MDISPS) which contains object space coordinates stored for
* the reshape level.
*
* The result is grids which are defining mesh with a smooth surface and details starting from
- * reshape level up to top level added back from original displacement grids. */
+ * reshape level up to top level added back from original displacement grids.
+ */
void multires_reshape_smooth_object_grids_with_details(
const MultiresReshapeContext *reshape_context);
-/* Operates on a displacement grids (CD_MDISPS) which contains object space-coordinates stored for
+/**
+ * Operates on a displacement grids (CD_MDISPS) which contains object space-coordinates stored for
* the reshape level.
*
* Makes it so surface on top level looks smooth. Details are not preserved
@@ -307,8 +344,10 @@ void multires_reshape_smooth_object_grids(const MultiresReshapeContext *reshape_
* Displacement, space conversion.
*/
-/* Store original grid data, so then it's possible to calculate delta from it and add
- * high-frequency content on top of reshaped grids. */
+/**
+ * Store original grid data, so then it's possible to calculate delta from it and add
+ * high-frequency content on top of reshaped grids.
+ */
void multires_reshape_store_original_grids(MultiresReshapeContext *reshape_context);
void multires_reshape_object_grids_to_tangent_displacement(
@@ -318,21 +357,29 @@ void multires_reshape_object_grids_to_tangent_displacement(
* Apply base.
*/
-/* Update mesh coordinates to the final positions of displacement in object space.
+/**
+ * Update mesh coordinates to the final positions of displacement in object space.
* This is effectively desired position of base mesh vertices after canceling out displacement.
*
- * NOTE: Expects that mesh's CD_MDISPS has been set to object space positions. */
+ * \note Expects that mesh's CD_MDISPS has been set to object space positions.
+ */
void multires_reshape_apply_base_update_mesh_coords(MultiresReshapeContext *reshape_context);
-/* Perform better fitting of the base mesh so its subdivided version brings vertices to their
- * desired locations. */
+/**
+ * Perform better fitting of the base mesh so its subdivided version brings vertices to their
+ * desired locations.
+ */
void multires_reshape_apply_base_refit_base_mesh(MultiresReshapeContext *reshape_context);
-/* Refine subdivision surface to the new positions of the base mesh. */
+/**
+ * Refine subdivision surface to the new positions of the base mesh.
+ */
void multires_reshape_apply_base_refine_from_base(MultiresReshapeContext *reshape_context);
-/* Refine subdivision surface to the new positions of the deformed mesh (base mesh with all
- * modifiers leading the multires applied).
+/**
+ * Refine subdivision surface to the new positions of the deformed mesh (base mesh with all
+ * modifiers leading the multi-res applied).
*
- * NOTE: Will re-evaluate all leading modifiers, so it's not cheap. */
+ * \note Will re-evaluate all leading modifiers, so it's not cheap.
+ */
void multires_reshape_apply_base_refine_from_deform(MultiresReshapeContext *reshape_context);
diff --git a/source/blender/blenkernel/intern/multires_reshape_util.c b/source/blender/blenkernel/intern/multires_reshape_util.c
index 79a2b9eb002..b7572204182 100644
--- a/source/blender/blenkernel/intern/multires_reshape_util.c
+++ b/source/blender/blenkernel/intern/multires_reshape_util.c
@@ -47,8 +47,6 @@
/** \name Construct/destruct reshape context
* \{ */
-/* Create subdivision surface descriptor which is configured for surface evaluation at a given
- * multires modifier. */
Subdiv *multires_reshape_create_subdiv(Depsgraph *depsgraph,
/*const*/ Object *object,
const MultiresModifierData *mmd)
@@ -332,7 +330,6 @@ void multires_reshape_context_free(MultiresReshapeContext *reshape_context)
/** \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,
int grid_index)
{
@@ -345,7 +342,6 @@ int multires_reshape_grid_to_face_index(const MultiresReshapeContext *reshape_co
return reshape_context->grid_to_face_index[grid_index];
}
-/* For the given grid index get corner of a face it was created for. */
int multires_reshape_grid_to_corner(const MultiresReshapeContext *reshape_context, int grid_index)
{
BLI_assert(grid_index >= 0);
@@ -364,7 +360,6 @@ bool multires_reshape_is_quad_face(const MultiresReshapeContext *reshape_context
return (base_poly->totloop == 4);
}
-/* For the given grid index get index of corresponding ptex face. */
int multires_reshape_grid_to_ptex_index(const MultiresReshapeContext *reshape_context,
int grid_index)
{
@@ -374,7 +369,6 @@ int multires_reshape_grid_to_ptex_index(const MultiresReshapeContext *reshape_co
return reshape_context->face_ptex_offset[face_index] + (is_quad ? 0 : corner);
}
-/* Convert normalized coordinate within a grid to a normalized coordinate within a ptex face. */
PTexCoord multires_reshape_grid_coord_to_ptex(const MultiresReshapeContext *reshape_context,
const GridCoord *grid_coord)
{
@@ -402,7 +396,6 @@ PTexCoord multires_reshape_grid_coord_to_ptex(const MultiresReshapeContext *resh
return ptex_coord;
}
-/* Convert a normalized coordinate within a ptex face to a normalized coordinate within a grid. */
GridCoord multires_reshape_ptex_coord_to_grid(const MultiresReshapeContext *reshape_context,
const PTexCoord *ptex_coord)
{
diff --git a/source/blender/blenkernel/intern/multires_reshape_vertcos.c b/source/blender/blenkernel/intern/multires_reshape_vertcos.c
index 04df5698cf9..ed2df1ba8c5 100644
--- a/source/blender/blenkernel/intern/multires_reshape_vertcos.c
+++ b/source/blender/blenkernel/intern/multires_reshape_vertcos.c
@@ -182,7 +182,6 @@ static void multires_reshape_vertcos_foreach_vertex_every_edge(
multires_reshape_vertcos_foreach_vertex(foreach_context, &ptex_coord, subdiv_vertex_index);
}
-/* Set displacement grids values at a reshape level to a object coordinates of the given source. */
bool multires_reshape_assign_final_coords_from_vertcos(
const MultiresReshapeContext *reshape_context,
const float (*vert_coords)[3],
diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c
index 124db07298d..84484a63291 100644
--- a/source/blender/blenkernel/intern/nla.c
+++ b/source/blender/blenkernel/intern/nla.c
@@ -61,14 +61,20 @@
static CLG_LogRef LOG = {"bke.nla"};
+/**
+ * Find the active track and strip.
+ *
+ * The active strip may or may not be on the active track.
+ */
+static void nla_tweakmode_find_active(const ListBase /* NlaTrack */ *nla_tracks,
+ NlaTrack **r_track_of_active_strip,
+ NlaStrip **r_active_strip);
+
/* *************************************************** */
/* Data Management */
/* Freeing ------------------------------------------- */
-/* Remove the given NLA strip from the NLA track it occupies, free the strip's data,
- * and the strip itself.
- */
void BKE_nlastrip_free(ListBase *strips, NlaStrip *strip, bool do_id_user)
{
NlaStrip *cs, *csn;
@@ -108,9 +114,6 @@ void BKE_nlastrip_free(ListBase *strips, NlaStrip *strip, bool do_id_user)
}
}
-/* Remove the given NLA track from the set of NLA tracks, free the track's data,
- * and the track itself.
- */
void BKE_nlatrack_free(ListBase *tracks, NlaTrack *nlt, bool do_id_user)
{
NlaStrip *strip, *stripn;
@@ -135,9 +138,6 @@ void BKE_nlatrack_free(ListBase *tracks, NlaTrack *nlt, bool do_id_user)
}
}
-/* Free the elements of type NLA Tracks provided in the given list, but do not free
- * the list itself since that is not free-standing
- */
void BKE_nla_tracks_free(ListBase *tracks, bool do_id_user)
{
NlaTrack *nlt, *nltn;
@@ -159,13 +159,6 @@ void BKE_nla_tracks_free(ListBase *tracks, bool do_id_user)
/* Copying ------------------------------------------- */
-/**
- * Copy NLA strip
- *
- * \param use_same_action: When true, the existing action is used (instead of being duplicated)
- * \param flag: Control ID pointers management, see LIB_ID_CREATE_.../LIB_ID_COPY_...
- * flags in BKE_lib_id.h
- */
NlaStrip *BKE_nlastrip_copy(Main *bmain,
NlaStrip *strip,
const bool use_same_action,
@@ -215,11 +208,6 @@ NlaStrip *BKE_nlastrip_copy(Main *bmain,
return strip_d;
}
-/**
- * Copy a single NLA Track.
- * \param flag: Control ID pointers management, see LIB_ID_CREATE_.../LIB_ID_COPY_...
- * flags in BKE_lib_id.h
- */
NlaTrack *BKE_nlatrack_copy(Main *bmain,
NlaTrack *nlt,
const bool use_same_actions,
@@ -249,11 +237,6 @@ NlaTrack *BKE_nlatrack_copy(Main *bmain,
return nlt_d;
}
-/**
- * Copy all NLA data.
- * \param flag: Control ID pointers management, see LIB_ID_CREATE_.../LIB_ID_COPY_...
- * flags in BKE_lib_id.h
- */
void BKE_nla_tracks_copy(Main *bmain, ListBase *dst, const ListBase *src, const int flag)
{
NlaTrack *nlt, *nlt_d;
@@ -309,6 +292,14 @@ static void update_active_track(AnimData *adt_dest, const AnimData *adt_source)
track_dest = track_dest->next;
}
+
+ /* If the above assumption failed to hold, do a more thorough search for the active strip. */
+ if (adt_source->actstrip != NULL && adt_dest->actstrip == NULL) {
+ nla_tweakmode_find_active(&adt_source->nla_tracks, &track_dest, &adt_dest->actstrip);
+ }
+
+ BLI_assert_msg((adt_source->actstrip == NULL) == (adt_dest->actstrip == NULL),
+ "Active strip did not copy correctly");
}
void BKE_nla_tracks_copy_from_adt(Main *bmain,
@@ -325,9 +316,6 @@ void BKE_nla_tracks_copy_from_adt(Main *bmain,
/* Adding ------------------------------------------- */
-/* Add a NLA Track to the given AnimData
- * - prev: NLA-Track to add the new one after
- */
NlaTrack *BKE_nlatrack_add(AnimData *adt, NlaTrack *prev, const bool is_liboverride)
{
NlaTrack *nlt;
@@ -371,7 +359,6 @@ NlaTrack *BKE_nlatrack_add(AnimData *adt, NlaTrack *prev, const bool is_liboverr
return nlt;
}
-/* Create a NLA Strip referencing the given Action */
NlaStrip *BKE_nlastrip_new(bAction *act)
{
NlaStrip *strip;
@@ -390,6 +377,16 @@ NlaStrip *BKE_nlastrip_new(bAction *act)
*/
strip->flag = NLASTRIP_FLAG_SELECT | NLASTRIP_FLAG_SYNC_LENGTH;
+ /* Disable sync for actions with a manual frame range, since it only syncs to range anyway. */
+ if (act->flag & ACT_FRAME_RANGE) {
+ strip->flag &= ~NLASTRIP_FLAG_SYNC_LENGTH;
+ }
+
+ /* Enable cyclic time for known cyclic actions. */
+ if (BKE_action_is_cyclic(act)) {
+ strip->flag |= NLASTRIP_FLAG_USR_TIME_CYCLIC;
+ }
+
/* assign the action reference */
strip->act = act;
id_us_plus(&act->id);
@@ -397,7 +394,7 @@ NlaStrip *BKE_nlastrip_new(bAction *act)
/* determine initial range
* - strip length cannot be 0... ever...
*/
- calc_action_range(strip->act, &strip->actstart, &strip->actend, 0);
+ BKE_action_get_frame_range(strip->act, &strip->actstart, &strip->actend);
strip->start = strip->actstart;
strip->end = (IS_EQF(strip->actstart, strip->actend)) ? (strip->actstart + 1.0f) :
@@ -411,8 +408,6 @@ NlaStrip *BKE_nlastrip_new(bAction *act)
return strip;
}
-/* Add new NLA-strip to the top of the NLA stack - i.e.
- * into the last track if space, or a new one otherwise. */
NlaStrip *BKE_nlastack_add_strip(AnimData *adt, bAction *act, const bool is_liboverride)
{
NlaStrip *strip;
@@ -445,7 +440,6 @@ NlaStrip *BKE_nlastack_add_strip(AnimData *adt, bAction *act, const bool is_libo
return strip;
}
-/* Add a NLA Strip referencing the given speaker's sound */
NlaStrip *BKE_nla_add_soundstrip(Main *bmain, Scene *scene, Speaker *speaker)
{
NlaStrip *strip = MEM_callocN(sizeof(NlaStrip), "NlaSoundStrip");
@@ -482,10 +476,6 @@ NlaStrip *BKE_nla_add_soundstrip(Main *bmain, Scene *scene, Speaker *speaker)
return strip;
}
-/**
- * Callback used by lib_query to walk over all ID usages (mimics `foreach_id` callback of
- * `IDTypeInfo` structure).
- */
void BKE_nla_strip_foreach_id(NlaStrip *strip, LibraryForeachIDData *data)
{
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, strip->act, IDWALK_CB_USER);
@@ -601,12 +591,6 @@ static float nlastrip_get_frame_transition(NlaStrip *strip, float cframe, short
return (cframe - strip->start) / length;
}
-/* non clipped mapping for strip-time <-> global time
- * mode = eNlaTime_ConvertModes[] -> NLATIME_CONVERT_*
- *
- * only secure for 'internal' (i.e. within AnimSys evaluation) operations,
- * but should not be directly relied on for stuff which interacts with editors
- */
float nlastrip_get_frame(NlaStrip *strip, float cframe, short mode)
{
switch (strip->type) {
@@ -621,12 +605,6 @@ float nlastrip_get_frame(NlaStrip *strip, float cframe, short mode)
}
}
-/* Non clipped mapping for strip-time <-> global time
- * mode = eNlaTime_ConvertModes -> NLATIME_CONVERT_*
- *
- * Public API method - perform this mapping using the given AnimData block
- * and perform any necessary sanity checks on the value
- */
float BKE_nla_tweakedit_remap(AnimData *adt, float cframe, short mode)
{
NlaStrip *strip;
@@ -675,7 +653,6 @@ float BKE_nla_tweakedit_remap(AnimData *adt, float cframe, short mode)
/* List of Strips ------------------------------------ */
/* (these functions are used for NLA-Tracks and also for nested/meta-strips) */
-/* Check if there is any space in the given list to add the given strip */
bool BKE_nlastrips_has_space(ListBase *strips, float start, float end)
{
NlaStrip *strip;
@@ -710,9 +687,6 @@ bool BKE_nlastrips_has_space(ListBase *strips, float start, float end)
return true;
}
-/* Rearrange the strips in the track so that they are always in order
- * (usually only needed after a strip has been moved)
- */
void BKE_nlastrips_sort_strips(ListBase *strips)
{
ListBase tmp = {NULL, NULL};
@@ -756,9 +730,6 @@ void BKE_nlastrips_sort_strips(ListBase *strips)
strips->last = tmp.last;
}
-/* Add the given NLA-Strip to the given list of strips, assuming that it
- * isn't currently a member of another list
- */
bool BKE_nlastrips_add_strip(ListBase *strips, NlaStrip *strip)
{
NlaStrip *ns;
@@ -794,10 +765,6 @@ bool BKE_nlastrips_add_strip(ListBase *strips, NlaStrip *strip)
/* Meta-Strips ------------------------------------ */
-/* Convert 'islands' (i.e. continuous string of) selected strips to be
- * contained within 'Meta-Strips' which act as strips which contain strips.
- * temp: are the meta-strips to be created 'temporary' ones used for transforms?
- */
void BKE_nlastrips_make_metas(ListBase *strips, bool is_temp)
{
NlaStrip *mstrip = NULL;
@@ -851,7 +818,6 @@ void BKE_nlastrips_make_metas(ListBase *strips, bool is_temp)
}
}
-/* Split a meta-strip into a set of normal strips */
void BKE_nlastrips_clear_metastrip(ListBase *strips, NlaStrip *strip)
{
NlaStrip *cs, *csn;
@@ -874,10 +840,6 @@ void BKE_nlastrips_clear_metastrip(ListBase *strips, NlaStrip *strip)
BKE_nlastrip_free(strips, strip, true);
}
-/* Remove meta-strips (i.e. flatten the list of strips) from the top-level of the list of strips
- * sel: only consider selected meta-strips, otherwise all meta-strips are removed
- * onlyTemp: only remove the 'temporary' meta-strips used for transforms
- */
void BKE_nlastrips_clear_metas(ListBase *strips, bool only_sel, bool only_temp)
{
NlaStrip *strip, *stripn;
@@ -903,9 +865,6 @@ void BKE_nlastrips_clear_metas(ListBase *strips, bool only_sel, bool only_temp)
}
}
-/* Add the given NLA-Strip to the given Meta-Strip, assuming that the
- * strip isn't attached to any list of strips
- */
bool BKE_nlameta_add_strip(NlaStrip *mstrip, NlaStrip *strip)
{
/* sanity checks */
@@ -954,9 +913,6 @@ bool BKE_nlameta_add_strip(NlaStrip *mstrip, NlaStrip *strip)
return BKE_nlastrips_add_strip(&mstrip->strips, strip);
}
-/* Adjust the settings of NLA-Strips contained within a Meta-Strip (recursively),
- * until the Meta-Strips children all fit within the Meta-Strip's new dimensions
- */
void BKE_nlameta_flush_transforms(NlaStrip *mstrip)
{
NlaStrip *strip;
@@ -1039,7 +995,6 @@ void BKE_nlameta_flush_transforms(NlaStrip *mstrip)
/* NLA-Tracks ---------------------------------------- */
-/* Find the active NLA-track for the given stack */
NlaTrack *BKE_nlatrack_find_active(ListBase *tracks)
{
NlaTrack *nlt;
@@ -1060,11 +1015,6 @@ NlaTrack *BKE_nlatrack_find_active(ListBase *tracks)
return NULL;
}
-/* Get the NLA Track that the active action/action strip comes from,
- * since this info is not stored in AnimData. It also isn't as simple
- * as just using the active track, since multiple tracks may have been
- * entered at the same time.
- */
NlaTrack *BKE_nlatrack_find_tweaked(AnimData *adt)
{
NlaTrack *nlt;
@@ -1096,9 +1046,6 @@ NlaTrack *BKE_nlatrack_find_tweaked(AnimData *adt)
return NULL;
}
-/* Toggle the 'solo' setting for the given NLA-track, making sure that it is the only one
- * that has this status in its AnimData block.
- */
void BKE_nlatrack_solo_toggle(AnimData *adt, NlaTrack *nlt)
{
NlaTrack *nt;
@@ -1133,9 +1080,6 @@ void BKE_nlatrack_solo_toggle(AnimData *adt, NlaTrack *nlt)
}
}
-/* Make the given NLA-track the active one for the given stack. If no track is provided,
- * this function can be used to simply deactivate all the NLA tracks in the given stack too.
- */
void BKE_nlatrack_set_active(ListBase *tracks, NlaTrack *nlt_a)
{
NlaTrack *nlt;
@@ -1156,7 +1100,6 @@ void BKE_nlatrack_set_active(ListBase *tracks, NlaTrack *nlt_a)
}
}
-/* Check if there is any space in the given track to add a strip of the given length */
bool BKE_nlatrack_has_space(NlaTrack *nlt, float start, float end)
{
/* sanity checks
@@ -1177,9 +1120,6 @@ bool BKE_nlatrack_has_space(NlaTrack *nlt, float start, float end)
return BKE_nlastrips_has_space(&nlt->strips, start, end);
}
-/* Rearrange the strips in the track so that they are always in order
- * (usually only needed after a strip has been moved)
- */
void BKE_nlatrack_sort_strips(NlaTrack *nlt)
{
/* sanity checks */
@@ -1191,9 +1131,6 @@ void BKE_nlatrack_sort_strips(NlaTrack *nlt)
BKE_nlastrips_sort_strips(&nlt->strips);
}
-/* Add the given NLA-Strip to the given NLA-Track, assuming that it
- * isn't currently attached to another one
- */
bool BKE_nlatrack_add_strip(NlaTrack *nlt, NlaStrip *strip, const bool is_liboverride)
{
/* sanity checks */
@@ -1211,9 +1148,6 @@ bool BKE_nlatrack_add_strip(NlaTrack *nlt, NlaStrip *strip, const bool is_libove
return BKE_nlastrips_add_strip(&nlt->strips, strip);
}
-/* Get the extents of the given NLA-Track including gaps between strips,
- * returning whether this succeeded or not
- */
bool BKE_nlatrack_get_bounds(NlaTrack *nlt, float bounds[2])
{
NlaStrip *strip;
@@ -1243,12 +1177,6 @@ bool BKE_nlatrack_get_bounds(NlaTrack *nlt, float bounds[2])
return true;
}
-/**
- * Check whether given NLA track is not local (i.e. from linked data) when the object is a library
- * override.
- *
- * \param nlt: May be NULL, in which case we consider it as a non-local track case.
- */
bool BKE_nlatrack_is_nonlocal_in_liboverride(const ID *id, const NlaTrack *nlt)
{
return (ID_IS_OVERRIDE_LIBRARY(id) &&
@@ -1257,7 +1185,6 @@ bool BKE_nlatrack_is_nonlocal_in_liboverride(const ID *id, const NlaTrack *nlt)
/* NLA Strips -------------------------------------- */
-/* Find the active NLA-strip within the given track */
NlaStrip *BKE_nlastrip_find_active(NlaTrack *nlt)
{
NlaStrip *strip;
@@ -1278,7 +1205,6 @@ NlaStrip *BKE_nlastrip_find_active(NlaTrack *nlt)
return NULL;
}
-/* Make the given NLA-Strip the active one within the given block */
void BKE_nlastrip_set_active(AnimData *adt, NlaStrip *strip)
{
NlaTrack *nlt;
@@ -1302,7 +1228,6 @@ void BKE_nlastrip_set_active(AnimData *adt, NlaStrip *strip)
}
}
-/* Does the given NLA-strip fall within the given bounds (times)? */
bool BKE_nlastrip_within_bounds(NlaStrip *strip, float min, float max)
{
const float stripLen = (strip) ? strip->end - strip->start : 0.0f;
@@ -1430,10 +1355,6 @@ static void nlastrip_fix_resize_overlaps(NlaStrip *strip)
}
}
-/**
- * Recalculate the start and end frames for the strip to match the bounds of its action such that
- * the overall NLA animation result is unchanged.
- */
void BKE_nlastrip_recalculate_bounds_sync_action(NlaStrip *strip)
{
float prev_actstart;
@@ -1444,16 +1365,13 @@ void BKE_nlastrip_recalculate_bounds_sync_action(NlaStrip *strip)
prev_actstart = strip->actstart;
- calc_action_range(strip->act, &strip->actstart, &strip->actend, 0);
+ BKE_action_get_frame_range(strip->act, &strip->actstart, &strip->actend);
/* Set start such that key's do not visually move, to preserve the overall animation result. */
strip->start += (strip->actstart - prev_actstart) * strip->scale;
BKE_nlastrip_recalculate_bounds(strip);
}
-/* Recalculate the start and end frames for the current strip, after changing
- * the extents of the action or the mapping (repeats or scale factor) info
- */
void BKE_nlastrip_recalculate_bounds(NlaStrip *strip)
{
float actlen, mapping;
@@ -1518,7 +1436,6 @@ static bool nlastrip_is_first(AnimData *adt, NlaStrip *strip)
/* Animated Strips ------------------------------------------- */
-/* Check if the given NLA-Track has any strips with own F-Curves */
bool BKE_nlatrack_has_animated_strips(NlaTrack *nlt)
{
NlaStrip *strip;
@@ -1539,7 +1456,6 @@ bool BKE_nlatrack_has_animated_strips(NlaTrack *nlt)
return false;
}
-/* Check if given NLA-Tracks have any strips with own F-Curves */
bool BKE_nlatracks_have_animated_strips(ListBase *tracks)
{
NlaTrack *nlt;
@@ -1560,7 +1476,6 @@ bool BKE_nlatracks_have_animated_strips(ListBase *tracks)
return false;
}
-/* Validate the NLA-Strips 'control' F-Curves based on the flags set. */
void BKE_nlastrip_validate_fcurves(NlaStrip *strip)
{
FCurve *fcu;
@@ -1624,9 +1539,6 @@ void BKE_nlastrip_validate_fcurves(NlaStrip *strip)
}
}
-/* Check if the given RNA pointer + property combo should be handled by
- * NLA strip curves or not.
- */
bool BKE_nlastrip_has_curves_for_property(const PointerRNA *ptr, const PropertyRNA *prop)
{
/* sanity checks */
@@ -1666,11 +1578,6 @@ static bool nla_editbone_name_check(void *arg, const char *name)
return BLI_ghash_haskey((GHash *)arg, (const void *)name);
}
-/* Find (and set) a unique name for a strip from the whole AnimData block
- * Uses a similar method to the BLI method, but is implemented differently
- * as we need to ensure that the name is unique over several lists of tracks,
- * not just a single track.
- */
void BKE_nlastrip_validate_name(AnimData *adt, NlaStrip *strip)
{
GHash *gh;
@@ -1844,7 +1751,6 @@ static void BKE_nlastrip_validate_autoblends(NlaTrack *nlt, NlaStrip *nls)
}
}
-/* Ensure that auto-blending and other settings are set correctly */
void BKE_nla_validate_state(AnimData *adt)
{
NlaStrip *strip, *fstrip = NULL;
@@ -1901,12 +1807,6 @@ void BKE_nla_validate_state(AnimData *adt)
/* name of stashed tracks - the translation stuff is included here to save extra work */
#define STASH_TRACK_NAME DATA_("[Action Stash]")
-/* Check if an action is "stashed" in the NLA already
- *
- * The criteria for this are:
- * 1) The action in question lives in a "stash" track
- * 2) We only check first-level strips. That is, we will not check inside meta strips.
- */
bool BKE_nla_action_is_stashed(AnimData *adt, bAction *act)
{
NlaTrack *nlt;
@@ -1925,9 +1825,6 @@ bool BKE_nla_action_is_stashed(AnimData *adt, bAction *act)
return false;
}
-/* "Stash" an action (i.e. store it as a track/layer in the NLA, but non-contributing)
- * to retain it in the file for future uses
- */
bool BKE_nla_action_stash(AnimData *adt, const bool is_liboverride)
{
NlaTrack *prev_track = NULL;
@@ -1996,12 +1893,6 @@ bool BKE_nla_action_stash(AnimData *adt, const bool is_liboverride)
/* Core Tools ------------------------------------------- */
-/* For the given AnimData block, add the active action to the NLA
- * stack (i.e. 'push-down' action). The UI should only allow this
- * for normal editing only (i.e. not in editmode for some strip's action),
- * so no checks for this are performed.
- */
-/* TODO: maybe we should have checks for this too... */
void BKE_nla_action_pushdown(AnimData *adt, const bool is_liboverride)
{
NlaStrip *strip;
@@ -2076,29 +1967,17 @@ void BKE_nla_action_pushdown(AnimData *adt, const bool is_liboverride)
BKE_nlastrip_set_active(adt, strip);
}
-/* Find the active strip + track combo, and set them up as the tweaking track,
- * and return if successful or not.
- */
-bool BKE_nla_tweakmode_enter(AnimData *adt)
+static void nla_tweakmode_find_active(const ListBase /* NlaTrack */ *nla_tracks,
+ NlaTrack **r_track_of_active_strip,
+ NlaStrip **r_active_strip)
{
NlaTrack *nlt, *activeTrack = NULL;
NlaStrip *strip, *activeStrip = NULL;
- /* verify that data is valid */
- if (ELEM(NULL, adt, adt->nla_tracks.first)) {
- return false;
- }
-
- /* If block is already in tweak-mode, just leave, but we should report
- * that this block is in tweak-mode (as our returncode). */
- if (adt->flag & ADT_NLA_EDIT_ON) {
- return true;
- }
-
/* go over the tracks, finding the active one, and its active strip
* - if we cannot find both, then there's nothing to do
*/
- for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
+ for (nlt = nla_tracks->first; nlt; nlt = nlt->next) {
/* check if active */
if (nlt->flag & NLATRACK_ACTIVE) {
/* store reference to this active track */
@@ -2117,7 +1996,7 @@ bool BKE_nla_tweakmode_enter(AnimData *adt)
*/
if (activeTrack == NULL) {
/* try last selected track for active strip */
- for (nlt = adt->nla_tracks.last; nlt; nlt = nlt->prev) {
+ for (nlt = nla_tracks->last; nlt; nlt = nlt->prev) {
if (nlt->flag & NLATRACK_SELECTED) {
/* assume this is the active track */
activeTrack = nlt;
@@ -2139,6 +2018,28 @@ bool BKE_nla_tweakmode_enter(AnimData *adt)
}
}
+ *r_track_of_active_strip = activeTrack;
+ *r_active_strip = activeStrip;
+}
+
+bool BKE_nla_tweakmode_enter(AnimData *adt)
+{
+ NlaTrack *nlt, *activeTrack = NULL;
+ NlaStrip *strip, *activeStrip = NULL;
+
+ /* verify that data is valid */
+ if (ELEM(NULL, adt, adt->nla_tracks.first)) {
+ return false;
+ }
+
+ /* If block is already in tweak-mode, just leave, but we should report
+ * that this block is in tweak-mode (as our returncode). */
+ if (adt->flag & ADT_NLA_EDIT_ON) {
+ return true;
+ }
+
+ nla_tweakmode_find_active(&adt->nla_tracks, &activeTrack, &activeStrip);
+
if (ELEM(NULL, activeTrack, activeStrip, activeStrip->act)) {
if (G.debug & G_DEBUG) {
printf("NLA tweak-mode enter - neither active requirement found\n");
@@ -2191,7 +2092,6 @@ bool BKE_nla_tweakmode_enter(AnimData *adt)
return true;
}
-/* Exit tweak-mode for this AnimData block. */
void BKE_nla_tweakmode_exit(AnimData *adt)
{
NlaStrip *strip;
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index e02ea3f7e37..be458ed036e 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -47,22 +47,23 @@
#include "DNA_texture_types.h"
#include "DNA_world_types.h"
+#include "BLI_color.hh"
#include "BLI_ghash.h"
#include "BLI_listbase.h"
#include "BLI_map.hh"
-#include "BLI_math.h"
#include "BLI_path_util.h"
#include "BLI_set.hh"
#include "BLI_stack.hh"
#include "BLI_string.h"
#include "BLI_string_utils.h"
+#include "BLI_threads.h"
#include "BLI_utildefines.h"
#include "BLI_vector_set.hh"
-
#include "BLT_translation.h"
#include "BKE_anim_data.h"
#include "BKE_animsys.h"
+#include "BKE_bpath.h"
#include "BKE_colortools.h"
#include "BKE_cryptomatte.h"
#include "BKE_global.h"
@@ -74,8 +75,6 @@
#include "BKE_main.h"
#include "BKE_node.h"
-#include "BLI_ghash.h"
-#include "BLI_threads.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -103,6 +102,7 @@ using blender::MutableSpan;
using blender::Set;
using blender::Span;
using blender::Stack;
+using blender::StringRef;
using blender::Vector;
using blender::VectorSet;
using blender::nodes::FieldInferencingInterface;
@@ -416,6 +416,29 @@ static void node_foreach_cache(ID *id,
}
}
+static void node_foreach_path(ID *id, BPathForeachPathData *bpath_data)
+{
+ bNodeTree *ntree = reinterpret_cast<bNodeTree *>(id);
+
+ switch (ntree->type) {
+ case NTREE_SHADER: {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type == SH_NODE_SCRIPT) {
+ NodeShaderScript *nss = reinterpret_cast<NodeShaderScript *>(node->storage);
+ BKE_bpath_foreach_path_fixed_process(bpath_data, nss->filepath);
+ }
+ else if (node->type == SH_NODE_TEX_IES) {
+ NodeShaderTexIES *ies = reinterpret_cast<NodeShaderTexIES *>(node->storage);
+ BKE_bpath_foreach_path_fixed_process(bpath_data, ies->filepath);
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+}
+
static ID *node_owner_get(Main *bmain, ID *id)
{
if ((id->flag & LIB_EMBEDDED_DATA) == 0) {
@@ -520,7 +543,6 @@ static void write_node_socket_interface(BlendWriter *writer, bNodeSocket *sock)
write_node_socket_default_value(writer, sock);
}
-/* this is only direct data, tree itself should have been written */
void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree)
{
BKE_id_blend_write(writer, &ntree->id);
@@ -682,7 +704,6 @@ static void direct_link_node_socket(BlendDataReader *reader, bNodeSocket *sock)
sock->declaration = nullptr;
}
-/* ntree itself has been read! */
void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree)
{
/* NOTE: writing and reading goes in sync, for speed. */
@@ -1047,6 +1068,7 @@ IDTypeInfo IDType_ID_NT = {
/* name_plural */ "node_groups",
/* translation_context */ BLT_I18NCONTEXT_ID_NODETREE,
/* flags */ IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ /* asset_type_info */ nullptr,
/* init_data */ ntree_init_data,
/* copy_data */ ntree_copy_data,
@@ -1054,6 +1076,7 @@ IDTypeInfo IDType_ID_NT = {
/* make_local */ nullptr,
/* foreach_id */ node_foreach_id,
/* foreach_cache */ node_foreach_cache,
+ /* foreach_path */ node_foreach_path,
/* owner_get */ node_owner_get,
/* blend_write */ ntree_blend_write,
@@ -1272,14 +1295,6 @@ static void update_typeinfo(Main *bmain,
FOREACH_NODETREE_END;
}
-/**
- * Try to initialize all type-info in a node tree.
- *
- * \note In general undefined type-info is a perfectly valid case,
- * the type may just be registered later.
- * In that case the update_typeinfo function will set type-info on registration
- * and do necessary updates.
- */
void ntreeSetTypes(const struct bContext *C, bNodeTree *ntree)
{
ntree->init |= NTREE_TYPE_INIT;
@@ -1351,7 +1366,7 @@ bool ntreeIsRegistered(bNodeTree *ntree)
return (ntree->typeinfo != &NodeTreeTypeUndefined);
}
-GHashIterator *ntreeTypeGetIterator(void)
+GHashIterator *ntreeTypeGetIterator()
{
return BLI_ghashIterator_new(nodetreetypes_hash);
}
@@ -1429,14 +1444,14 @@ void nodeUnregisterType(bNodeType *nt)
BLI_ghash_remove(nodetypes_hash, nt->idname, nullptr, node_free_type);
}
-bool nodeTypeUndefined(bNode *node)
+bool nodeTypeUndefined(const bNode *node)
{
return (node->typeinfo == &NodeTypeUndefined) ||
((ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) && node->id &&
ID_IS_LINKED(node->id) && (node->id->tag & LIB_TAG_MISSING));
}
-GHashIterator *nodeTypeGetIterator(void)
+GHashIterator *nodeTypeGetIterator()
{
return BLI_ghashIterator_new(nodetypes_hash);
}
@@ -1484,7 +1499,7 @@ bool nodeSocketIsRegistered(bNodeSocket *sock)
return (sock->typeinfo != &NodeSocketTypeUndefined);
}
-GHashIterator *nodeSocketTypeGetIterator(void)
+GHashIterator *nodeSocketTypeGetIterator()
{
return BLI_ghashIterator_new(nodesockettypes_hash);
}
@@ -1508,6 +1523,33 @@ struct bNodeSocket *nodeFindSocket(const bNode *node,
return nullptr;
}
+namespace blender::bke {
+
+bNodeSocket *node_find_enabled_socket(bNode &node,
+ const eNodeSocketInOut in_out,
+ const StringRef name)
+{
+ ListBase *sockets = (in_out == SOCK_IN) ? &node.inputs : &node.outputs;
+ LISTBASE_FOREACH (bNodeSocket *, socket, sockets) {
+ if (!(socket->flag & SOCK_UNAVAIL) && socket->name == name) {
+ return socket;
+ }
+ }
+ return nullptr;
+}
+
+bNodeSocket *node_find_enabled_input_socket(bNode &node, StringRef name)
+{
+ return node_find_enabled_socket(node, SOCK_IN, name);
+}
+
+bNodeSocket *node_find_enabled_output_socket(bNode &node, StringRef name)
+{
+ return node_find_enabled_socket(node, SOCK_OUT, name);
+}
+
+} // namespace blender::bke
+
/* find unique socket identifier */
static bool unique_identifier_check(void *arg, const char *identifier)
{
@@ -2035,13 +2077,11 @@ void nodeRemoveAllSockets(bNodeTree *ntree, bNode *node)
node->update |= NODE_UPDATE;
}
-/* finds a node based on its name */
bNode *nodeFindNodebyName(bNodeTree *ntree, const char *name)
{
return (bNode *)BLI_findstring(&ntree->nodes, name, offsetof(bNode, name));
}
-/* Finds a node based on given socket and returns true on success. */
bool nodeFindNode(bNodeTree *ntree, bNodeSocket *sock, bNode **r_node, int *r_sockindex)
{
*r_node = nullptr;
@@ -2065,9 +2105,6 @@ bool nodeFindNode(bNodeTree *ntree, bNodeSocket *sock, bNode **r_node, int *r_so
return false;
}
-/**
- * \note Recursive
- */
bNode *nodeFindRootParent(bNode *node)
{
if (node->parent) {
@@ -2076,10 +2113,6 @@ bNode *nodeFindRootParent(bNode *node)
return node->type == NODE_FRAME ? node : nullptr;
}
-/**
- * \returns true if \a child has \a parent as a parent/grandparent/...
- * \note Recursive
- */
bool nodeIsChildOf(const bNode *parent, const bNode *child)
{
if (parent == child) {
@@ -2091,13 +2124,6 @@ bool nodeIsChildOf(const bNode *parent, const bNode *child)
return false;
}
-/**
- * Iterate over a chain of nodes, starting with \a node_start, executing
- * \a callback for each node (which can return false to end iterator).
- *
- * \param reversed: for backwards iteration
- * \note Recursive
- */
void nodeChainIter(const bNodeTree *ntree,
const bNode *node_start,
bool (*callback)(bNode *, bNode *, void *, const bool),
@@ -2152,17 +2178,6 @@ static void iter_backwards_ex(const bNodeTree *ntree,
}
}
-/**
- * Iterate over a chain of nodes, starting with \a node_start, executing
- * \a callback for each node (which can return false to end iterator).
- *
- * Faster than nodeChainIter. Iter only once per node.
- * Can be called recursively (using another nodeChainIterBackwards) by
- * setting the recursion_lvl accordingly.
- *
- * \note Needs updated socket links (ntreeUpdateTree).
- * \note Recursive
- */
void nodeChainIterBackwards(const bNodeTree *ntree,
const bNode *node_start,
bool (*callback)(bNode *, bNode *, void *),
@@ -2185,12 +2200,6 @@ void nodeChainIterBackwards(const bNodeTree *ntree,
iter_backwards_ex(ntree, node_start, callback, userdata, recursion_mask);
}
-/**
- * Iterate over all parents of \a node, executing \a callback for each parent
- * (which can return false to end iterator)
- *
- * \note Recursive
- */
void nodeParentsIter(bNode *node, bool (*callback)(bNode *, void *), void *userdata)
{
if (node->parent) {
@@ -2203,7 +2212,6 @@ void nodeParentsIter(bNode *node, bool (*callback)(bNode *, void *), void *userd
/* ************** Add stuff ********** */
-/* Find the first available, non-duplicate name for a given node */
void nodeUniqueName(bNodeTree *ntree, bNode *node)
{
BLI_uniquename(
@@ -2266,9 +2274,6 @@ static void node_socket_copy(bNodeSocket *sock_dst, const bNodeSocket *sock_src,
sock_dst->cache = nullptr;
}
-/* keep socket listorder identical, for copying links */
-/* ntree is the target tree */
-/* unique_name needs to be true. It's only disabled for speed when doing GPUnodetrees. */
bNode *BKE_node_copy_ex(bNodeTree *ntree,
const bNode *node_src,
const int flag,
@@ -2412,7 +2417,6 @@ static int node_count_links(const bNodeTree *ntree, const bNodeSocket *socket)
return count;
}
-/* also used via rna api, so we check for proper input output direction */
bNodeLink *nodeAddLink(
bNodeTree *ntree, bNode *fromnode, bNodeSocket *fromsock, bNode *tonode, bNodeSocket *tosock)
{
@@ -2831,8 +2835,8 @@ bNodeTree *ntreeCopyTree(Main *bmain, const bNodeTree *ntree)
/* XXX this should be removed eventually ...
* Currently BKE functions are modeled closely on previous code,
* using BKE_node_preview_init_tree to set up previews for a whole node tree in advance.
- * This should be left more to the individual node tree implementations.
- */
+ * This should be left more to the individual node tree implementations. */
+
bool BKE_node_preview_used(const bNode *node)
{
/* XXX check for closed nodes? */
@@ -3065,9 +3069,6 @@ void BKE_node_preview_merge_tree(bNodeTree *to_ntree, bNodeTree *from_ntree, boo
}
}
-/* hack warning! this function is only used for shader previews, and
- * since it gets called multiple times per pixel for Ztransp we only
- * add the color once. Preview gets cleared before it starts render though */
void BKE_node_preview_set_pixel(
bNodePreview *preview, const float col[4], int x, int y, bool do_manage)
{
@@ -3091,7 +3092,6 @@ void BKE_node_preview_set_pixel(
/* ************** Free stuff ********** */
-/* goes over entire tree */
void nodeUnlinkNode(bNodeTree *ntree, bNode *node)
{
LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) {
@@ -3281,8 +3281,6 @@ static void free_localized_node_groups(bNodeTree *ntree)
}
}
-/* Free (or release) any data used by this nodetree. Does not free the
- * nodetree itself and does no ID user counting. */
void ntreeFreeTree(bNodeTree *ntree)
{
ntree_free_data(&ntree->id);
@@ -3386,12 +3384,6 @@ void ntreeSetOutput(bNodeTree *ntree)
* might be different for editor or for "real" use... */
}
-/**
- * Get address of potential node-tree pointer of given ID.
- *
- * \warning Using this function directly is potentially dangerous, if you don't know or are not
- * sure, please use `ntreeFromID()` instead.
- */
bNodeTree **BKE_ntree_ptr_from_id(ID *id)
{
switch (GS(id->name)) {
@@ -3414,7 +3406,6 @@ bNodeTree **BKE_ntree_ptr_from_id(ID *id)
}
}
-/* Returns the private NodeTree object of the datablock, if it has one. */
bNodeTree *ntreeFromID(ID *id)
{
bNodeTree **nodetree = BKE_ntree_ptr_from_id(id);
@@ -3453,48 +3444,43 @@ void ntreeNodeFlagSet(const bNodeTree *ntree, const int flag, const bool enable)
}
}
-/* returns localized tree for execution in threads */
bNodeTree *ntreeLocalize(bNodeTree *ntree)
{
- if (ntree) {
- /* Make full copy outside of Main database.
- * NOTE: previews are not copied here.
- */
- bNodeTree *ltree = (bNodeTree *)BKE_id_copy_ex(
- nullptr, &ntree->id, nullptr, (LIB_ID_COPY_LOCALIZE | LIB_ID_COPY_NO_ANIMDATA));
-
- ltree->id.tag |= LIB_TAG_LOCALIZED;
+ if (ntree == nullptr) {
+ return nullptr;
+ }
- LISTBASE_FOREACH (bNode *, node, &ltree->nodes) {
- if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && node->id) {
- node->id = (ID *)ntreeLocalize((bNodeTree *)node->id);
- }
- }
+ /* Make full copy outside of Main database.
+ * NOTE: previews are not copied here. */
+ bNodeTree *ltree = (bNodeTree *)BKE_id_copy_ex(
+ nullptr, &ntree->id, nullptr, (LIB_ID_COPY_LOCALIZE | LIB_ID_COPY_NO_ANIMDATA));
- /* ensures only a single output node is enabled */
- ntreeSetOutput(ntree);
+ ltree->id.tag |= LIB_TAG_LOCALIZED;
- bNode *node_src = (bNode *)ntree->nodes.first;
- bNode *node_local = (bNode *)ltree->nodes.first;
- while (node_src != nullptr) {
- node_local->original = node_src;
- node_src = node_src->next;
- node_local = node_local->next;
+ LISTBASE_FOREACH (bNode *, node, &ltree->nodes) {
+ if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && node->id) {
+ node->id = (ID *)ntreeLocalize((bNodeTree *)node->id);
}
+ }
- if (ntree->typeinfo->localize) {
- ntree->typeinfo->localize(ltree, ntree);
- }
+ /* ensures only a single output node is enabled */
+ ntreeSetOutput(ntree);
- return ltree;
+ bNode *node_src = (bNode *)ntree->nodes.first;
+ bNode *node_local = (bNode *)ltree->nodes.first;
+ while (node_src != nullptr) {
+ node_local->original = node_src;
+ node_src = node_src->next;
+ node_local = node_local->next;
}
- return nullptr;
+ if (ntree->typeinfo->localize) {
+ ntree->typeinfo->localize(ltree, ntree);
+ }
+
+ return ltree;
}
-/* sync local composite with real tree */
-/* local tree is supposed to be running, be careful moving previews! */
-/* is called by jobs manager, outside threads, so it doesn't happen during draw */
void ntreeLocalSync(bNodeTree *localtree, bNodeTree *ntree)
{
if (localtree && ntree) {
@@ -3504,8 +3490,6 @@ void ntreeLocalSync(bNodeTree *localtree, bNodeTree *ntree)
}
}
-/* merge local tree results back, and free local tree */
-/* we have to assume the editor already changed completely */
void ntreeLocalMerge(Main *bmain, bNodeTree *localtree, bNodeTree *ntree)
{
if (ntree && localtree) {
@@ -3873,7 +3857,6 @@ static bNode *node_get_active_id_recursive(bNodeInstanceKey active_key,
return nullptr;
}
-/* two active flags, ID nodes have special flag for buttons display */
bNode *nodeGetActiveID(bNodeTree *ntree, short idtype)
{
if (ntree) {
@@ -3916,7 +3899,6 @@ bool nodeSetActiveID(bNodeTree *ntree, short idtype, ID *id)
return ok;
}
-/* two active flags, ID nodes have special flag for buttons display */
void nodeClearActiveID(bNodeTree *ntree, short idtype)
{
if (ntree == nullptr) {
@@ -3959,7 +3941,6 @@ void nodeClearActive(bNodeTree *ntree)
}
}
-/* two active flags, ID nodes have special flag for buttons display */
void nodeSetActive(bNodeTree *ntree, bNode *node)
{
/* make sure only one node is active, and only one per ID type */
@@ -4028,10 +4009,6 @@ static void update_socket_declarations(ListBase *sockets,
}
}
-/**
- * Update `socket->declaration` for all sockets in the node. This assumes that the node declaration
- * and sockets are up to date already.
- */
void nodeSocketDeclarationsUpdate(bNode *node)
{
BLI_assert(node->declaration != nullptr);
@@ -4039,10 +4016,6 @@ void nodeSocketDeclarationsUpdate(bNode *node)
update_socket_declarations(&node->outputs, node->declaration->outputs());
}
-/**
- * Just update `node->declaration` if necessary. This can also be called on nodes that may not be
- * up to date (e.g. because the need versioning or are dynamic).
- */
bool nodeDeclarationEnsureOnOutdatedNode(bNodeTree *UNUSED(ntree), bNode *node)
{
if (node->declaration != nullptr) {
@@ -4064,10 +4037,6 @@ bool nodeDeclarationEnsureOnOutdatedNode(bNodeTree *UNUSED(ntree), bNode *node)
return true;
}
-/**
- * If the node implements a `declare` function, this function makes sure that `node->declaration`
- * is up to date. It is expected that the sockets of the node are up to date already.
- */
bool nodeDeclarationEnsure(bNodeTree *ntree, bNode *node)
{
if (nodeDeclarationEnsureOnOutdatedNode(ntree, node)) {
@@ -4115,7 +4084,7 @@ void BKE_node_clipboard_init(const struct bNodeTree *ntree)
node_clipboard.type = ntree->type;
}
-void BKE_node_clipboard_clear(void)
+void BKE_node_clipboard_clear()
{
LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &node_clipboard.links) {
nodeRemLink(nullptr, link);
@@ -4132,8 +4101,7 @@ void BKE_node_clipboard_clear(void)
#endif
}
-/* return false when one or more ID's are lost */
-bool BKE_node_clipboard_validate(void)
+bool BKE_node_clipboard_validate()
{
bool ok = true;
@@ -4211,22 +4179,22 @@ void BKE_node_clipboard_add_link(bNodeLink *link)
BLI_addtail(&node_clipboard.links, link);
}
-const ListBase *BKE_node_clipboard_get_nodes(void)
+const ListBase *BKE_node_clipboard_get_nodes()
{
return &node_clipboard.nodes;
}
-const ListBase *BKE_node_clipboard_get_links(void)
+const ListBase *BKE_node_clipboard_get_links()
{
return &node_clipboard.links;
}
-int BKE_node_clipboard_get_type(void)
+int BKE_node_clipboard_get_type()
{
return node_clipboard.type;
}
-void BKE_node_clipboard_free(void)
+void BKE_node_clipboard_free()
{
BKE_node_clipboard_validate();
BKE_node_clipboard_clear();
@@ -4234,7 +4202,6 @@ void BKE_node_clipboard_free(void)
/* Node Instance Hash */
-/* magic number for initial hash key */
const bNodeInstanceKey NODE_INSTANCE_KEY_BASE = {5381};
const bNodeInstanceKey NODE_INSTANCE_KEY_NONE = {0};
@@ -4520,7 +4487,8 @@ static void ntree_validate_links(bNodeTree *ntree)
link->flag &= ~NODE_LINK_VALID;
}
else if (ntree->typeinfo->validate_link) {
- if (!ntree->typeinfo->validate_link(ntree, link)) {
+ if (!ntree->typeinfo->validate_link((eNodeSocketDatatype)link->fromsock->type,
+ (eNodeSocketDatatype)link->tosock->type)) {
link->flag &= ~NODE_LINK_VALID;
}
}
@@ -4809,7 +4777,9 @@ static void propagate_data_requirements_from_right_to_left(
/* The output is required to be a single value when it is connected to any input that does
* not support fields. */
for (const InputSocketRef *target_socket : output_socket->directly_linked_sockets()) {
- state.requires_single |= field_state_by_socket_id[target_socket->id()].requires_single;
+ if (target_socket->is_available()) {
+ state.requires_single |= field_state_by_socket_id[target_socket->id()].requires_single;
+ }
}
if (state.requires_single) {
@@ -5059,9 +5029,6 @@ static bool update_field_inferencing(bNodeTree &btree)
} // namespace blender::bke::node_field_inferencing
-/**
- * \param tree_update_flag: #eNodeTreeUpdate enum.
- */
void ntreeUpdateAllUsers(Main *main, ID *id, const int tree_update_flag)
{
if (id == nullptr) {
@@ -5244,7 +5211,7 @@ void nodeUpdateInternalLinks(bNodeTree *ntree, bNode *node)
/* ************* node type access ********** */
-void nodeLabel(bNodeTree *ntree, bNode *node, char *label, int maxlen)
+void nodeLabel(const bNodeTree *ntree, const bNode *node, char *label, int maxlen)
{
label[0] = '\0';
@@ -5266,7 +5233,6 @@ void nodeLabel(bNodeTree *ntree, bNode *node, char *label, int maxlen)
}
}
-/* Get node socket label if it is set */
const char *nodeSocketLabel(const bNodeSocket *sock)
{
return (sock->label[0] != '\0') ? sock->label : sock->name;
@@ -5448,10 +5414,6 @@ void node_type_size_preset(struct bNodeType *ntype, eNodeSizePreset size)
}
}
-/**
- * \warning Nodes defining a storage type _must_ allocate this for new nodes.
- * Otherwise nodes will reload as undefined (T46619).
- */
void node_type_storage(bNodeType *ntype,
const char *storagename,
void (*freefunc)(struct bNode *node),
@@ -5469,13 +5431,6 @@ void node_type_storage(bNodeType *ntype,
ntype->freefunc = freefunc;
}
-void node_type_label(
- struct bNodeType *ntype,
- void (*labelfunc)(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen))
-{
- ntype->labelfunc = labelfunc;
-}
-
void node_type_update(struct bNodeType *ntype,
void (*updatefunc)(struct bNodeTree *ntree, struct bNode *node))
{
@@ -5827,6 +5782,7 @@ static void registerGeometryNodes()
register_node_type_geo_attribute_compare();
register_node_type_geo_attribute_convert();
register_node_type_geo_attribute_curve_map();
+ register_node_type_geo_attribute_domain_size();
register_node_type_geo_attribute_fill();
register_node_type_geo_attribute_map_range();
register_node_type_geo_attribute_math();
@@ -5845,7 +5801,6 @@ static void registerGeometryNodes()
register_node_type_geo_curve_fillet();
register_node_type_geo_curve_handle_type_selection();
register_node_type_geo_curve_length();
- register_node_type_geo_curve_parameter();
register_node_type_geo_curve_primitive_bezier_segment();
register_node_type_geo_curve_primitive_circle();
register_node_type_geo_curve_primitive_line();
@@ -5857,6 +5812,7 @@ static void registerGeometryNodes()
register_node_type_geo_curve_reverse();
register_node_type_geo_curve_sample();
register_node_type_geo_curve_set_handles();
+ register_node_type_geo_curve_spline_parameter();
register_node_type_geo_curve_spline_type();
register_node_type_geo_curve_subdivide();
register_node_type_geo_curve_to_mesh();
@@ -5864,7 +5820,9 @@ static void registerGeometryNodes()
register_node_type_geo_curve_trim();
register_node_type_geo_delete_geometry();
register_node_type_geo_distribute_points_on_faces();
+ register_node_type_geo_dual_mesh();
register_node_type_geo_edge_split();
+ register_node_type_geo_geometry_to_instance();
register_node_type_geo_image_texture();
register_node_type_geo_input_curve_handles();
register_node_type_geo_input_curve_tilt();
@@ -5872,9 +5830,16 @@ static void registerGeometryNodes()
register_node_type_geo_input_index();
register_node_type_geo_input_material_index();
register_node_type_geo_input_material();
+ register_node_type_geo_input_mesh_edge_neighbors();
+ register_node_type_geo_input_mesh_edge_vertices();
+ register_node_type_geo_input_mesh_face_area();
+ register_node_type_geo_input_mesh_face_neighbors();
+ register_node_type_geo_input_mesh_island();
+ register_node_type_geo_input_mesh_vertex_neighbors();
register_node_type_geo_input_normal();
register_node_type_geo_input_position();
register_node_type_geo_input_radius();
+ register_node_type_geo_input_scene_time();
register_node_type_geo_input_shade_smooth();
register_node_type_geo_input_spline_cyclic();
register_node_type_geo_input_spline_length();
@@ -5943,7 +5908,7 @@ static void registerFunctionNodes()
register_node_type_fn_align_euler_to_vector();
register_node_type_fn_boolean_math();
- register_node_type_fn_float_compare();
+ register_node_type_fn_compare();
register_node_type_fn_float_to_int();
register_node_type_fn_input_bool();
register_node_type_fn_input_color();
@@ -5959,7 +5924,7 @@ static void registerFunctionNodes()
register_node_type_fn_value_to_string();
}
-void BKE_node_system_init(void)
+void BKE_node_system_init()
{
nodetreetypes_hash = BLI_ghash_str_new("nodetreetypes_hash gh");
nodetypes_hash = BLI_ghash_str_new("nodetypes_hash gh");
@@ -5986,7 +5951,7 @@ void BKE_node_system_init(void)
registerFunctionNodes();
}
-void BKE_node_system_exit(void)
+void BKE_node_system_exit()
{
if (nodetypes_hash) {
NODE_TYPES_BEGIN (nt) {
diff --git a/source/blender/blenkernel/intern/object.cc b/source/blender/blenkernel/intern/object.cc
index d650003afe2..7fec91ed65a 100644
--- a/source/blender/blenkernel/intern/object.cc
+++ b/source/blender/blenkernel/intern/object.cc
@@ -83,6 +83,7 @@
#include "BKE_animsys.h"
#include "BKE_armature.h"
#include "BKE_asset.h"
+#include "BKE_bpath.h"
#include "BKE_camera.h"
#include "BKE_collection.h"
#include "BKE_constraint.h"
@@ -548,6 +549,67 @@ static void object_foreach_id(ID *id, LibraryForeachIDData *data)
}
}
+static void object_foreach_path_pointcache(ListBase *ptcache_list,
+ BPathForeachPathData *bpath_data)
+{
+ for (PointCache *cache = (PointCache *)ptcache_list->first; cache != nullptr;
+ cache = cache->next) {
+ if (cache->flag & PTCACHE_DISK_CACHE) {
+ BKE_bpath_foreach_path_fixed_process(bpath_data, cache->path);
+ }
+ }
+}
+
+static void object_foreach_path(ID *id, BPathForeachPathData *bpath_data)
+{
+ Object *ob = reinterpret_cast<Object *>(id);
+
+ LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
+ /* TODO: Move that to #ModifierTypeInfo. */
+ switch (md->type) {
+ case eModifierType_Fluidsim: {
+ FluidsimModifierData *fluidmd = reinterpret_cast<FluidsimModifierData *>(md);
+ if (fluidmd->fss) {
+ BKE_bpath_foreach_path_fixed_process(bpath_data, fluidmd->fss->surfdataPath);
+ }
+ break;
+ }
+ case eModifierType_Fluid: {
+ FluidModifierData *fmd = reinterpret_cast<FluidModifierData *>(md);
+ if (fmd->type & MOD_FLUID_TYPE_DOMAIN && fmd->domain) {
+ BKE_bpath_foreach_path_fixed_process(bpath_data, fmd->domain->cache_directory);
+ }
+ break;
+ }
+ case eModifierType_Cloth: {
+ ClothModifierData *clmd = reinterpret_cast<ClothModifierData *>(md);
+ object_foreach_path_pointcache(&clmd->ptcaches, bpath_data);
+ break;
+ }
+ case eModifierType_Ocean: {
+ OceanModifierData *omd = reinterpret_cast<OceanModifierData *>(md);
+ BKE_bpath_foreach_path_fixed_process(bpath_data, omd->cachepath);
+ break;
+ }
+ case eModifierType_MeshCache: {
+ MeshCacheModifierData *mcmd = reinterpret_cast<MeshCacheModifierData *>(md);
+ BKE_bpath_foreach_path_fixed_process(bpath_data, mcmd->filepath);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ if (ob->soft != nullptr) {
+ object_foreach_path_pointcache(&ob->soft->shared->ptcaches, bpath_data);
+ }
+
+ LISTBASE_FOREACH (ParticleSystem *, psys, &ob->particlesystem) {
+ object_foreach_path_pointcache(&psys->ptcaches, bpath_data);
+ }
+}
+
static void write_fmaps(BlendWriter *writer, ListBase *fbase)
{
LISTBASE_FOREACH (bFaceMap *, fmap, fbase) {
@@ -1258,6 +1320,7 @@ IDTypeInfo IDType_ID_OB = {
/* name_plural */ "objects",
/* translation_context */ BLT_I18NCONTEXT_ID_OBJECT,
/* flags */ 0,
+ /* asset_type_info */ &AssetType_OB,
/* init_data */ object_init_data,
/* copy_data */ object_copy_data,
@@ -1265,6 +1328,7 @@ IDTypeInfo IDType_ID_OB = {
/* make_local */ object_make_local,
/* foreach_id */ object_foreach_id,
/* foreach_cache */ nullptr,
+ /* foreach_path */ object_foreach_path,
/* owner_get */ nullptr,
/* blend_write */ object_blend_write,
@@ -1275,8 +1339,6 @@ IDTypeInfo IDType_ID_OB = {
/* blend_read_undo_preserve */ nullptr,
/* lib_override_apply_post */ object_lib_override_apply_post,
-
- /* asset_type_info */ &AssetType_OB,
};
void BKE_object_workob_clear(Object *workob)
@@ -1394,12 +1456,6 @@ void BKE_object_modifier_gpencil_hook_reset(Object *ob, HookGpencilModifierData
}
}
-/**
- * Set the object's active modifier.
- *
- * \param md: If nullptr, only clear the active modifier, otherwise
- * it must be in the #Object.modifiers list.
- */
void BKE_object_modifier_set_active(Object *ob, ModifierData *md)
{
LISTBASE_FOREACH (ModifierData *, md_iter, &ob->modifiers) {
@@ -1434,9 +1490,6 @@ ModifierData *BKE_object_active_modifier(const Object *ob)
return nullptr;
}
-/**
- * \return True if the object's type supports regular modifiers (not grease pencil modifiers).
- */
bool BKE_object_supports_modifiers(const Object *ob)
{
return (
@@ -1514,17 +1567,6 @@ static ParticleSystem *object_copy_modifier_particle_system_ensure(Main *bmain,
return psys_dst;
}
-/**
- * Copy a single modifier.
- *
- * \note **Do not** use this function to copy a whole modifier stack (see note below too). Use
- * `BKE_object_modifier_stack_copy` instead.
- *
- * \note Complex modifiers relaying on other data (like e.g. dynamic paint or fluid using particle
- * systems) are not always 100% 'correctly' copied here, since we have to use heuristics to decide
- * which particle system to use or add in `ob_dst`, and it's placement in the stack, etc. If used
- * more than once, this function should preferably be called in stack order.
- */
bool BKE_object_copy_modifier(
Main *bmain, Scene *scene, Object *ob_dst, const Object *ob_src, ModifierData *md_src)
{
@@ -1624,12 +1666,6 @@ bool BKE_object_copy_modifier(
return true;
}
-/**
- * Copy a single GPencil modifier.
- *
- * \note **Do not** use this function to copy a whole modifier stack. Use
- * `BKE_object_modifier_stack_copy` instead.
- */
bool BKE_object_copy_gpencil_modifier(struct Object *ob_dst, GpencilModifierData *gmd_src)
{
BLI_assert(ob_dst->type == OB_GPENCIL);
@@ -1647,15 +1683,6 @@ bool BKE_object_copy_gpencil_modifier(struct Object *ob_dst, GpencilModifierData
return true;
}
-/**
- * Copy the whole stack of modifiers from one object into another.
- *
- * \warning **Does not** clear modifier stack and related data (particle systems, soft-body,
- * etc.) in `ob_dst`, if needed calling code must do it.
- *
- * \param do_copy_all: If true, even modifiers that should not support copying (like Hook one)
- * will be duplicated.
- */
bool BKE_object_modifier_stack_copy(Object *ob_dst,
const Object *ob_src,
const bool do_copy_all,
@@ -1804,9 +1831,6 @@ static void object_update_from_subsurf_ccg(Object *object)
subdiv_ccg->dirty.hidden = false;
}
-/**
- * Assign #Object.data after modifier stack evaluation.
- */
void BKE_object_eval_assign_data(Object *object_eval, ID *data_eval, bool is_owned)
{
BLI_assert(object_eval->id.tag & LIB_TAG_COPIED_ON_WRITE);
@@ -1836,9 +1860,6 @@ void BKE_object_eval_assign_data(Object *object_eval, ID *data_eval, bool is_own
object_eval->runtime.geometry_set_eval = nullptr;
}
-/**
- * Free data derived from mesh, called when mesh changes or is freed.
- */
void BKE_object_free_derived_caches(Object *ob)
{
MEM_SAFE_FREE(ob->runtime.bb);
@@ -1933,9 +1954,6 @@ void BKE_object_free_caches(Object *object)
}
}
-/**
- * Actual check for internal data, not context or flags.
- */
bool BKE_object_is_in_editmode(const Object *ob)
{
if (ob->data == nullptr) {
@@ -2085,9 +2103,6 @@ bool BKE_object_is_mode_compat(const struct Object *ob, eObjectMode object_mode)
return ((ob->mode == object_mode) || (ob->mode & object_mode) != 0);
}
-/**
- * Return which parts of the object are visible, as evaluated by depsgraph
- */
int BKE_object_visibility(const Object *ob, const int dag_eval_mode)
{
if ((ob->base_flag & BASE_VISIBLE_DEPSGRAPH) == 0) {
@@ -2255,9 +2270,6 @@ void *BKE_object_obdata_add_from_type(Main *bmain, int type, const char *name)
}
}
-/**
- * Return -1 on failure.
- */
int BKE_object_obdata_to_type(const ID *id)
{
/* Keep in sync with #OB_DATA_SUPPORT_ID macro. */
@@ -2293,9 +2305,6 @@ int BKE_object_obdata_to_type(const ID *id)
}
}
-/**
- * More general add: creates minimum required data, but without vertices etc.
- */
Object *BKE_object_add_only_object(Main *bmain, int type, const char *name)
{
if (!name) {
@@ -2325,14 +2334,6 @@ static Object *object_add_common(Main *bmain, ViewLayer *view_layer, int type, c
return ob;
}
-/**
- * General add: to scene, with layer from area and default name
- *
- * Object is added to the active #Collection.
- * If there is no linked collection to the active #ViewLayer we create a new one.
- *
- * \note Creates minimum required data, but without vertices etc.
- */
Object *BKE_object_add(Main *bmain, ViewLayer *view_layer, int type, const char *name)
{
Object *ob = object_add_common(bmain, view_layer, type, name);
@@ -2346,11 +2347,6 @@ Object *BKE_object_add(Main *bmain, ViewLayer *view_layer, int type, const char
return ob;
}
-/**
- * Add a new object, using another one as a reference
- *
- * \param ob_src: object to use to determine the collections of the new object.
- */
Object *BKE_object_add_from(
Main *bmain, Scene *scene, ViewLayer *view_layer, int type, const char *name, Object *ob_src)
{
@@ -2363,15 +2359,6 @@ Object *BKE_object_add_from(
return ob;
}
-/**
- * Add a new object, but assign the given data-block as the `ob->data`
- * for the newly created object.
- *
- * \param data: The data-block to assign as `ob->data` for the new object.
- * This is assumed to be of the correct type.
- * \param do_id_user: If true, #id_us_plus() will be called on data when
- * assigning it to the object.
- */
Object *BKE_object_add_for_data(
Main *bmain, ViewLayer *view_layer, int type, const char *name, ID *data, bool do_id_user)
{
@@ -2623,9 +2610,6 @@ Object *BKE_object_pose_armature_get_visible(Object *ob, ViewLayer *view_layer,
return nullptr;
}
-/**
- * Access pose array with special check to get pose object when in weight paint mode.
- */
Object **BKE_object_pose_array_get_ex(ViewLayer *view_layer,
View3D *v3d,
uint *r_objects_len,
@@ -2720,17 +2704,6 @@ void BKE_object_transform_copy(Object *ob_tar, const Object *ob_src)
copy_v3_v3(ob_tar->scale, ob_src->scale);
}
-/**
- * Perform deep-copy of object and its 'children' data-blocks (obdata, materials, actions, etc.).
- *
- * \param dupflag: Controls which sub-data are also duplicated
- * (see #eDupli_ID_Flags in DNA_userdef_types.h).
- *
- * \note This function does not do any remapping to new IDs, caller must do it
- * (\a #BKE_libblock_relink_to_newid()).
- * \note Caller MUST free \a newid pointers itself (#BKE_main_id_newptr_and_tag_clear()) and call
- * updates of DEG too (#DAG_relations_tag_update()).
- */
Object *BKE_object_duplicate(Main *bmain, Object *ob, uint dupflag, uint duplicate_options)
{
const bool is_subprocess = (duplicate_options & LIB_ID_DUPLICATE_IS_SUBPROCESS) != 0;
@@ -2900,17 +2873,11 @@ Object *BKE_object_duplicate(Main *bmain, Object *ob, uint dupflag, uint duplica
return obn;
}
-/**
- * Returns true if the Object is from an external blend file (libdata).
- */
bool BKE_object_is_libdata(const Object *ob)
{
return (ob && ID_IS_LINKED(ob));
}
-/**
- * Returns true if the Object data is from an external blend file (libdata).
- */
bool BKE_object_obdata_is_libdata(const Object *ob)
{
/* Linked objects with local obdata are forbidden! */
@@ -2974,12 +2941,6 @@ void BKE_object_copy_proxy_drivers(Object *ob, Object *target)
}
}
-/**
- * Proxy rule:
- * - lib_object->proxy_from == the one we borrow from, set temporally while object_update.
- * - local_object->proxy == pointer to library object, saved in files and read.
- * - local_object->proxy_group == pointer to collection dupli-object, saved in files and read.
- */
void BKE_object_make_proxy(Main *bmain, Object *ob, Object *target, Object *cob)
{
/* paranoia checks */
@@ -3079,10 +3040,6 @@ void BKE_object_make_proxy(Main *bmain, Object *ob, Object *target, Object *cob)
ob->dt = target->dt;
}
-/**
- * Use with newly created objects to set their size
- * (used to apply scene-scale).
- */
void BKE_object_obdata_size_init(struct Object *ob, const float size)
{
/* apply radius as a scale to types that support it */
@@ -3721,12 +3678,6 @@ void BKE_object_where_is_calc_time(Depsgraph *depsgraph, Scene *scene, Object *o
object_where_is_calc_ex(depsgraph, scene, ob, ctime, nullptr, nullptr);
}
-/**
- * Calculate object transformation matrix without recalculating dependencies and
- * constraints -- assume dependencies are already solved by depsgraph.
- * No changes to object and its parent would be done.
- * Used for bundles orientation in 3d space relative to parented blender camera.
- */
void BKE_object_where_is_calc_mat4(Object *ob, float r_obmat[4][4])
{
if (ob->parent) {
@@ -3750,14 +3701,6 @@ void BKE_object_where_is_calc(Depsgraph *depsgraph, Scene *scene, Object *ob)
object_where_is_calc_ex(depsgraph, scene, ob, ctime, nullptr, nullptr);
}
-/**
- * For calculation of the inverse parent transform, only used for editor.
- *
- * It assumes the object parent is already in the depsgraph.
- * Otherwise, after changing ob->parent you need to call:
- * - #DEG_relations_tag_update(bmain);
- * - #BKE_scene_graph_update_tagged(depsgraph, bmain);
- */
void BKE_object_workob_calc_parent(Depsgraph *depsgraph, Scene *scene, Object *ob, Object *workob)
{
BKE_object_workob_clear(workob);
@@ -3789,16 +3732,6 @@ void BKE_object_workob_calc_parent(Depsgraph *depsgraph, Scene *scene, Object *o
BKE_object_where_is_calc(depsgraph, scene, workob);
}
-/**
- * Applies the global transformation \a mat to the \a ob using a relative parent space if
- * supplied.
- *
- * \param mat: the global transformation mat that the object should be set object to.
- * \param parent: the parent space in which this object will be set relative to
- * (should probably always be parent_eval).
- * \param use_compat: true to ensure that rotations are set using the
- * min difference between the old and new orientation.
- */
void BKE_object_apply_mat4_ex(Object *ob,
const float mat[4][4],
Object *parent,
@@ -3842,9 +3775,6 @@ void BKE_object_apply_mat4_ex(Object *ob,
/* BKE_object_mat3_to_rot handles delta rotations */
}
-/**
- * XXX: should be removed after COW operators port to use BKE_object_apply_mat4_ex directly.
- */
void BKE_object_apply_mat4(Object *ob,
const float mat[4][4],
const bool use_compat,
@@ -3859,7 +3789,7 @@ void BKE_object_apply_mat4(Object *ob,
/** \name Object Bounding Box API
* \{ */
-BoundBox *BKE_boundbox_alloc_unit(void)
+BoundBox *BKE_boundbox_alloc_unit()
{
const float min[3] = {-1.0f, -1.0f, -1.0f}, max[3] = {1.0f, 1.0f, 1.0f};
@@ -3948,9 +3878,6 @@ BoundBox *BKE_object_boundbox_get(Object *ob)
return bb;
}
-/**
- * Use this to temporally disable/enable bound-box.
- */
void BKE_object_boundbox_flag(Object *ob, int flag, const bool set)
{
BoundBox *bb = BKE_object_boundbox_get(ob);
@@ -3984,6 +3911,37 @@ void BKE_object_boundbox_calc_from_mesh(Object *ob, const Mesh *me_eval)
ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY;
}
+bool BKE_object_boundbox_calc_from_evaluated_geometry(Object *ob)
+{
+ blender::float3 min, max;
+ INIT_MINMAX(min, max);
+
+ if (ob->runtime.geometry_set_eval) {
+ ob->runtime.geometry_set_eval->compute_boundbox_without_instances(&min, &max);
+ }
+ else if (const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob)) {
+ if (!BKE_mesh_wrapper_minmax(mesh_eval, min, max)) {
+ return false;
+ }
+ }
+ else if (ob->runtime.curve_cache) {
+ BKE_displist_minmax(&ob->runtime.curve_cache->disp, min, max);
+ }
+ else {
+ return false;
+ }
+
+ if (ob->runtime.bb == nullptr) {
+ ob->runtime.bb = (BoundBox *)MEM_callocN(sizeof(BoundBox), __func__);
+ }
+
+ BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
+
+ ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY;
+
+ return true;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -4009,14 +3967,6 @@ void BKE_object_dimensions_get(Object *ob, float r_vec[3])
}
}
-/**
- * The original scale and object matrix can be passed in so any difference
- * of the objects matrix and the final matrix can be accounted for,
- * typically this caused by parenting, constraints or delta-scale.
- *
- * Re-using these values from the object causes a feedback loop
- * when multiple values are modified at once in some situations. see: T69536.
- */
void BKE_object_dimensions_set_ex(Object *ob,
const float value[3],
int axis_mask,
@@ -4341,6 +4291,12 @@ void BKE_scene_foreach_display_point(Depsgraph *depsgraph,
DEG_OBJECT_ITER_END;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Transform Channels (Backup/Restore)
+ * \{ */
+
/**
* See struct members from #Object in DNA_object_types.h
*/
@@ -4401,17 +4357,11 @@ void BKE_object_tfm_restore(Object *ob, void *obtfm_pt)
copy_m4_m4(ob->imat, obtfm->imat);
}
-bool BKE_object_parent_loop_check(const Object *par, const Object *ob)
-{
- /* test if 'ob' is a parent somewhere in par's parents */
- if (par == nullptr) {
- return false;
- }
- if (ob == par) {
- return true;
- }
- return BKE_object_parent_loop_check(par->parent, ob);
-}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Evaluation/Update API
+ * \{ */
static void object_handle_update_proxy(Depsgraph *depsgraph,
Scene *scene,
@@ -4435,19 +4385,6 @@ static void object_handle_update_proxy(Depsgraph *depsgraph,
}
}
-/**
- * Proxy rule:
- * - lib_object->proxy_from == the one we borrow from, only set temporal and cleared here.
- * - local_object->proxy == pointer to library object, saved in files and read.
- *
- * Function below is polluted with proxy exceptions, cleanup will follow!
- *
- * The main object update call, for object matrix, constraints, keys and displist (modifiers)
- * requires flags to be set!
- *
- * Ideally we shouldn't have to pass the rigid body world,
- * but need bigger restructuring to avoid id.
- */
void BKE_object_handle_update_ex(Depsgraph *depsgraph,
Scene *scene,
Object *ob,
@@ -4502,13 +4439,6 @@ void BKE_object_handle_update_ex(Depsgraph *depsgraph,
object_handle_update_proxy(depsgraph, scene, ob, do_proxy_update);
}
-/**
- * \warning "scene" here may not be the scene object actually resides in.
- * When dealing with background-sets, "scene" is actually the active scene.
- * e.g. "scene" <-- set 1 <-- set 2 ("ob" lives here) <-- set 3 <-- ... <-- set n
- * rigid bodies depend on their world so use #BKE_object_handle_update_ex()
- * to also pass along the current rigid body world.
- */
void BKE_object_handle_update(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
BKE_object_handle_update_ex(depsgraph, scene, ob, nullptr, true);
@@ -4521,7 +4451,7 @@ void BKE_object_sculpt_data_create(Object *ob)
ob->sculpt->mode_type = (eObjectMode)ob->mode;
}
-bool BKE_object_obdata_texspace_get(Object *ob, short **r_texflag, float **r_loc, float **r_size)
+bool BKE_object_obdata_texspace_get(Object *ob, char **r_texflag, float **r_loc, float **r_size)
{
if (ob->data == nullptr) {
@@ -4566,17 +4496,17 @@ bool BKE_object_obdata_texspace_get(Object *ob, short **r_texflag, float **r_loc
return true;
}
-/** Get evaluated mesh for given object. */
Mesh *BKE_object_get_evaluated_mesh(const Object *object)
{
/* First attempt to retrieve the evaluated mesh from the evaluated geometry set. Most
* object types either store it there or add a reference to it if it's owned elsewhere. */
GeometrySet *geometry_set_eval = object->runtime.geometry_set_eval;
if (geometry_set_eval) {
- /* Some areas expect to be able to modify the evaluated mesh. Theoretically this should be
- * avoided, or at least protected with a lock, so a const mesh could be returned from this
- * function. */
- Mesh *mesh = geometry_set_eval->get_mesh_for_write();
+ /* Some areas expect to be able to modify the evaluated mesh in limited ways. Theoretically
+ * this should be avoided, or at least protected with a lock, so a const mesh could be returned
+ * from this function. We use a const_cast instead of #get_mesh_for_write, because that might
+ * result in a copy of the mesh when it is shared. */
+ Mesh *mesh = const_cast<Mesh *>(geometry_set_eval->get_mesh_for_read());
if (mesh) {
return mesh;
}
@@ -4593,13 +4523,6 @@ Mesh *BKE_object_get_evaluated_mesh(const Object *object)
return nullptr;
}
-/**
- * Get mesh which is not affected by modifiers:
- * - For original objects it will be same as `object->data`, and it is a mesh
- * which is in the corresponding #Main.
- * - For copied-on-write objects it will give pointer to a copied-on-write
- * mesh which corresponds to original object's mesh.
- */
Mesh *BKE_object_get_pre_modified_mesh(const Object *object)
{
if (object->type == OB_MESH && object->runtime.data_orig != nullptr) {
@@ -4615,12 +4538,6 @@ Mesh *BKE_object_get_pre_modified_mesh(const Object *object)
return (Mesh *)object->data;
}
-/**
- * Get a mesh which corresponds to the very original mesh from #Main.
- * - For original objects it will be object->data.
- * - For evaluated objects it will be same mesh as corresponding original
- * object uses as data.
- */
Mesh *BKE_object_get_original_mesh(const Object *object)
{
Mesh *result = nullptr;
@@ -4669,6 +4586,12 @@ Lattice *BKE_object_get_evaluated_lattice(const Object *object)
return lt_eval;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Point Cache
+ * \{ */
+
static int pc_cmp(const void *a, const void *b)
{
const LinkData *ad = (const LinkData *)a, *bd = (const LinkData *)b;
@@ -4733,6 +4656,8 @@ void BKE_object_delete_ptcache(Object *ob, int index)
BLI_freelinkN(&ob->pc_ids, link);
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Object Data Shape Key Insert
* \{ */
@@ -4971,6 +4896,22 @@ bool BKE_object_shapekey_remove(Main *bmain, Object *ob, KeyBlock *kb)
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Object Query API
+ * \{ */
+
+bool BKE_object_parent_loop_check(const Object *par, const Object *ob)
+{
+ /* test if 'ob' is a parent somewhere in par's parents */
+ if (par == nullptr) {
+ return false;
+ }
+ if (ob == par) {
+ return true;
+ }
+ return BKE_object_parent_loop_check(par->parent, ob);
+}
+
bool BKE_object_flag_test_recursive(const Object *ob, short flag)
{
if (ob->flag & flag) {
@@ -4993,10 +4934,6 @@ bool BKE_object_is_child_recursive(const Object *ob_parent, const Object *ob_chi
return false;
}
-/**
- * Most important if this is modified it should _always_ return true, in certain
- * cases false positives are hard to avoid (shape keys for example).
- */
int BKE_object_is_modified(Scene *scene, Object *ob)
{
/* Always test on original object since evaluated object may no longer
@@ -5030,21 +4967,6 @@ int BKE_object_is_modified(Scene *scene, Object *ob)
return flag;
}
-/**
- * Check of objects moves in time.
- *
- * \note This function is currently optimized for usage in combination
- * with modifier deformation checks (#eModifierTypeType_OnlyDeform),
- * so modifiers can quickly check if their target objects moves
- * (causing deformation motion blur) or not.
- *
- * This makes it possible to give some degree of false-positives here,
- * but it's currently an acceptable tradeoff between complexity and check
- * speed. In combination with checks of modifier stack and real life usage
- * percentage of false-positives shouldn't be that high.
- *
- * \note This function does not consider physics systems.
- */
bool BKE_object_moves_in_time(const Object *object, bool recurse_parent)
{
/* If object has any sort of animation data assume it is moving. */
@@ -5140,11 +5062,6 @@ static bool modifiers_has_animation_check(const Object *ob)
return false;
}
-/**
- * Test if object is affected by deforming modifiers (for motion blur). again
- * most important is to avoid false positives, this is to skip computations
- * and we can still if there was actual deformation afterwards.
- */
int BKE_object_is_deform_modified(Scene *scene, Object *ob)
{
/* Always test on original object since evaluated object may no longer
@@ -5194,7 +5111,6 @@ int BKE_object_is_deform_modified(Scene *scene, Object *ob)
return flag;
}
-/** Return the number of scenes using (instantiating) that object in their collections. */
int BKE_object_scenes_users_get(Main *bmain, Object *ob)
{
int num_scenes = 0;
@@ -5234,14 +5150,31 @@ MovieClip *BKE_object_movieclip_get(Scene *scene, Object *ob, bool use_default)
return clip;
}
+bool BKE_object_supports_material_slots(struct Object *ob)
+{
+ return ELEM(ob->type,
+ OB_MESH,
+ OB_CURVE,
+ OB_SURF,
+ OB_FONT,
+ OB_MBALL,
+ OB_HAIR,
+ OB_POINTCLOUD,
+ OB_VOLUME,
+ OB_GPENCIL);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Runtime
+ * \{ */
+
void BKE_object_runtime_reset(Object *object)
{
memset(&object->runtime, 0, sizeof(object->runtime));
}
-/**
- * Reset all pointers which we don't want to be shared when copying the object.
- */
void BKE_object_runtime_reset_on_copy(Object *object, const int UNUSED(flag))
{
Object_Runtime *runtime = &object->runtime;
@@ -5254,12 +5187,6 @@ void BKE_object_runtime_reset_on_copy(Object *object, const int UNUSED(flag))
runtime->geometry_set_eval = nullptr;
}
-/**
- * The function frees memory used by the runtime data, but not the runtime field itself.
- *
- * All runtime data is cleared to ensure it's not used again,
- * in keeping with other `_free_data(..)` functions.
- */
void BKE_object_runtime_free_data(Object *object)
{
/* Currently this is all that's needed. */
@@ -5268,6 +5195,12 @@ void BKE_object_runtime_free_data(Object *object)
BKE_object_runtime_reset(object);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Relationships
+ * \{ */
+
/**
* Find an associated armature object.
*/
@@ -5301,13 +5234,6 @@ static void obrel_list_add(LinkNode **links, Object *ob)
ob->id.tag |= LIB_TAG_DOIT;
}
-/**
- * Iterates over all objects of the given scene layer.
- * Depending on the #eObjectSet flag:
- * collect either #OB_SET_ALL, #OB_SET_VISIBLE or #OB_SET_SELECTED objects.
- * If #OB_SET_VISIBLE or#OB_SET_SELECTED are collected,
- * then also add related objects according to the given \a includeFilter.
- */
LinkNode *BKE_object_relational_superset(struct ViewLayer *view_layer,
eObjectSet objectSet,
eObRelationTypes includeFilter)
@@ -5385,9 +5311,6 @@ LinkNode *BKE_object_relational_superset(struct ViewLayer *view_layer,
return links;
}
-/**
- * return all groups this object is a part of, caller must free.
- */
struct LinkNode *BKE_object_groups(Main *bmain, Scene *scene, Object *ob)
{
LinkNode *collection_linknode = nullptr;
@@ -5408,15 +5331,12 @@ void BKE_object_groups_clear(Main *bmain, Scene *scene, Object *ob)
}
}
-/**
- * Return a KDTree_3d from the deformed object (in world-space).
- *
- * \note Only mesh objects currently support deforming, others are TODO.
- *
- * \param ob:
- * \param r_tot:
- * \return The kdtree or nullptr if it can't be created.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object KD-Tree
+ * \{ */
+
KDTree_3d *BKE_object_as_kdtree(Object *ob, int *r_tot)
{
KDTree_3d *tree = nullptr;
@@ -5534,6 +5454,12 @@ KDTree_3d *BKE_object_as_kdtree(Object *ob, int *r_tot)
return tree;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Modifier Utilities
+ * \{ */
+
bool BKE_object_modifier_use_time(Scene *scene,
Object *ob,
ModifierData *md,
@@ -5679,10 +5605,6 @@ static void object_cacheIgnoreClear(Object *ob, int state)
BLI_freelistN(&pidlist);
}
-/**
- * \note this function should eventually be replaced by depsgraph functionality.
- * Avoid calling this in new code unless there is a very good reason for it!
- */
bool BKE_object_modifier_update_subframe(Depsgraph *depsgraph,
Scene *scene,
Object *ob,
@@ -5786,9 +5708,6 @@ bool BKE_object_modifier_update_subframe(Depsgraph *depsgraph,
return false;
}
-/**
- * Updates select_id of all objects in the given \a bmain.
- */
void BKE_object_update_select_id(struct Main *bmain)
{
Object *ob = (Object *)bmain->objects.first;
@@ -5799,6 +5718,12 @@ void BKE_object_update_select_id(struct Main *bmain)
}
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Conversion
+ * \{ */
+
Mesh *BKE_object_to_mesh(Depsgraph *depsgraph, Object *object, bool preserve_all_data_layers)
{
BKE_object_to_mesh_clear(object);
@@ -5866,16 +5791,4 @@ void BKE_object_replace_data_on_shallow_copy(Object *ob, ID *new_data)
ob->id.py_instance = nullptr;
}
-bool BKE_object_supports_material_slots(struct Object *ob)
-{
- return ELEM(ob->type,
- OB_MESH,
- OB_CURVE,
- OB_SURF,
- OB_FONT,
- OB_MBALL,
- OB_HAIR,
- OB_POINTCLOUD,
- OB_VOLUME,
- OB_GPENCIL);
-}
+/** \} */
diff --git a/source/blender/blenkernel/intern/object_deform.c b/source/blender/blenkernel/intern/object_deform.c
index 511f5d4ae66..fb4f4a14265 100644
--- a/source/blender/blenkernel/intern/object_deform.c
+++ b/source/blender/blenkernel/intern/object_deform.c
@@ -63,13 +63,6 @@ static Lattice *object_defgroup_lattice_get(ID *id)
return (lt->editlatt) ? lt->editlatt->latt : lt;
}
-/**
- * Update users of vgroups from this object, according to given map.
- *
- * Use it when you remove or reorder vgroups in the object.
- *
- * \param map: an array mapping old indices to new indices.
- */
void BKE_object_defgroup_remap_update_users(Object *ob, const int *map)
{
ModifierData *md;
@@ -106,15 +99,13 @@ void BKE_object_defgroup_remap_update_users(Object *ob, const int *map)
}
}
}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name Group creation
* \{ */
-/**
- * Add a vgroup of given name to object. *Does not* handle MDeformVert data at all!
- */
bDeformGroup *BKE_object_defgroup_add_name(Object *ob, const char *name)
{
bDeformGroup *defgroup;
@@ -129,17 +120,11 @@ bDeformGroup *BKE_object_defgroup_add_name(Object *ob, const char *name)
return defgroup;
}
-/**
- * Add a vgroup of default name to object. *Does not* handle MDeformVert data at all!
- */
bDeformGroup *BKE_object_defgroup_add(Object *ob)
{
return BKE_object_defgroup_add_name(ob, DATA_("Group"));
}
-/**
- * Create MDeformVert data for given ID. Work in Object mode only.
- */
MDeformVert *BKE_object_defgroup_data_create(ID *id)
{
if (GS(id->name) == ID_ME) {
@@ -156,18 +141,13 @@ MDeformVert *BKE_object_defgroup_data_create(ID *id)
return NULL;
}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name Group clearing
* \{ */
-/**
- * Remove all verts (or only selected ones) from given vgroup. Work in Object and Edit modes.
- *
- * \param use_selection: Only operate on selection.
- * \return True if any vertex was removed, false otherwise.
- */
bool BKE_object_defgroup_clear(Object *ob, bDeformGroup *dg, const bool use_selection)
{
MDeformVert *dv;
@@ -239,12 +219,6 @@ bool BKE_object_defgroup_clear(Object *ob, bDeformGroup *dg, const bool use_sele
return changed;
}
-/**
- * Remove all verts (or only selected ones) from all vgroups. Work in Object and Edit modes.
- *
- * \param use_selection: Only operate on selection.
- * \return True if any vertex was removed, false otherwise.
- */
bool BKE_object_defgroup_clear_all(Object *ob, const bool use_selection)
{
bDeformGroup *dg;
@@ -260,6 +234,7 @@ bool BKE_object_defgroup_clear_all(Object *ob, const bool use_selection)
return changed;
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -406,9 +381,6 @@ static void object_defgroup_remove_edit_mode(Object *ob, bDeformGroup *dg)
object_defgroup_remove_common(ob, dg, def_nr);
}
-/**
- * Remove given vgroup from object. Work in Object and Edit modes.
- */
void BKE_object_defgroup_remove(Object *ob, bDeformGroup *defgroup)
{
if (ob->type == OB_GPENCIL) {
@@ -426,10 +398,6 @@ void BKE_object_defgroup_remove(Object *ob, bDeformGroup *defgroup)
}
}
-/**
- * Remove all vgroups from object. Work in Object and Edit modes.
- * When only_unlocked=true, locked vertex groups are not removed.
- */
void BKE_object_defgroup_remove_all_ex(struct Object *ob, bool only_unlocked)
{
ListBase *defbase = BKE_object_defgroup_list_mutable(ob);
@@ -469,19 +437,11 @@ void BKE_object_defgroup_remove_all_ex(struct Object *ob, bool only_unlocked)
}
}
-/**
- * Remove all vgroups from object. Work in Object and Edit modes.
- */
void BKE_object_defgroup_remove_all(struct Object *ob)
{
BKE_object_defgroup_remove_all_ex(ob, false);
}
-/**
- * Compute mapping for vertex groups with matching name, -1 is used for no remapping.
- * Returns null if no remapping is required.
- * The returned array has to be freed.
- */
int *BKE_object_defgroup_index_map_create(Object *ob_src, Object *ob_dst, int *r_map_len)
{
const ListBase *src_defbase = BKE_object_defgroup_list(ob_src);
@@ -549,11 +509,6 @@ void BKE_object_defgroup_index_map_apply(MDeformVert *dvert,
}
}
-/**
- * Get MDeformVert vgroup data from given object. Should only be used in Object mode.
- *
- * \return True if the id type supports weights.
- */
bool BKE_object_defgroup_array_get(ID *id, MDeformVert **dvert_arr, int *dvert_tot)
{
if (id) {
@@ -579,14 +534,11 @@ bool BKE_object_defgroup_array_get(ID *id, MDeformVert **dvert_arr, int *dvert_t
*dvert_tot = 0;
return false;
}
+
/** \} */
/* --- functions for getting vgroup aligned maps --- */
-/**
- * gets the status of "flag" for each bDeformGroup
- * in the object data's vertex group list and returns an array containing them
- */
bool *BKE_object_defgroup_lock_flags_get(Object *ob, const int defbase_tot)
{
bool is_locked = false;
@@ -675,8 +627,6 @@ bool *BKE_object_defgroup_validmap_get(Object *ob, const int defbase_tot)
return defgroup_validmap;
}
-/* Returns total selected vgroups,
- * wpi.defbase_sel is assumed malloc'd, all values are set */
bool *BKE_object_defgroup_selected_get(Object *ob, int defbase_tot, int *r_dg_flags_sel_tot)
{
bool *dg_selection = MEM_mallocN(defbase_tot * sizeof(bool), __func__);
@@ -708,11 +658,6 @@ bool *BKE_object_defgroup_selected_get(Object *ob, int defbase_tot, int *r_dg_fl
return dg_selection;
}
-/**
- * Checks if the lock relative mode is applicable.
- *
- * \return true if an unlocked deform group is active.
- */
bool BKE_object_defgroup_check_lock_relative(const bool *lock_flags,
const bool *validmap,
int index)
@@ -720,11 +665,6 @@ bool BKE_object_defgroup_check_lock_relative(const bool *lock_flags,
return validmap && validmap[index] && !(lock_flags && lock_flags[index]);
}
-/**
- * Additional check for whether the lock relative mode is applicable in multi-paint mode.
- *
- * \return true if none of the selected groups are locked.
- */
bool BKE_object_defgroup_check_lock_relative_multi(int defbase_tot,
const bool *lock_flags,
const bool *selected,
@@ -747,11 +687,6 @@ bool BKE_object_defgroup_check_lock_relative_multi(int defbase_tot,
return true;
}
-/**
- * Takes a pair of boolean masks of all locked and all deform groups, and computes
- * a pair of masks for locked deform and unlocked deform groups. Output buffers may
- * reuse the input ones.
- */
void BKE_object_defgroup_split_locked_validmap(
int defbase_tot, const bool *locked, const bool *deform, bool *r_locked, bool *r_unlocked)
{
@@ -774,11 +709,6 @@ void BKE_object_defgroup_split_locked_validmap(
}
}
-/**
- * Marks mirror vgroups in output and counts them.
- * Output and counter assumed to be already initialized.
- * Designed to be usable after BKE_object_defgroup_selected_get to extend selection to mirror.
- */
void BKE_object_defgroup_mirror_selection(struct Object *ob,
int defbase_tot,
const bool *dg_selection,
@@ -808,9 +738,6 @@ void BKE_object_defgroup_mirror_selection(struct Object *ob,
}
}
-/**
- * Return the subset type of the Vertex Group Selection
- */
bool *BKE_object_defgroup_subset_from_select_type(Object *ob,
eVGroupSelect subset_type,
int *r_defgroup_tot,
@@ -873,9 +800,6 @@ bool *BKE_object_defgroup_subset_from_select_type(Object *ob,
return defgroup_validmap;
}
-/**
- * store indices from the defgroup_validmap (faster lookups in some cases)
- */
void BKE_object_defgroup_subset_to_index_array(const bool *defgroup_validmap,
const int defgroup_tot,
int *r_defgroup_subset_map)
diff --git a/source/blender/blenkernel/intern/object_dupli.cc b/source/blender/blenkernel/intern/object_dupli.cc
index 442755be15d..9f998b746a2 100644
--- a/source/blender/blenkernel/intern/object_dupli.cc
+++ b/source/blender/blenkernel/intern/object_dupli.cc
@@ -147,7 +147,7 @@ static void init_context(DupliContext *r_ctx,
/**
* Create sub-context for recursive duplis.
*/
-static void copy_dupli_context(
+static bool copy_dupli_context(
DupliContext *r_ctx, const DupliContext *ctx, Object *ob, const float mat[4][4], int index)
{
*r_ctx = *ctx;
@@ -168,9 +168,11 @@ static void copy_dupli_context(
if (r_ctx->level == MAX_DUPLI_RECUR - 1) {
std::cerr << "Warning: Maximum instance recursion level reached.\n";
+ return false;
}
r_ctx->gen = get_dupli_generator(r_ctx);
+ return true;
}
/**
@@ -258,7 +260,9 @@ static void make_recursive_duplis(const DupliContext *ctx,
/* Simple preventing of too deep nested collections with #MAX_DUPLI_RECUR. */
if (ctx->level < MAX_DUPLI_RECUR) {
DupliContext rctx;
- copy_dupli_context(&rctx, ctx, ob, space_mat, index);
+ if (!copy_dupli_context(&rctx, ctx, ob, space_mat, index)) {
+ return;
+ }
if (rctx.gen) {
ctx->instance_stack->append(ob);
rctx.gen->make_duplis(&rctx);
@@ -301,13 +305,13 @@ static void make_child_duplis(const DupliContext *ctx,
FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN (ctx->collection, ob, mode) {
if ((ob != ctx->obedit) && is_child(ob, parent)) {
DupliContext pctx;
- copy_dupli_context(&pctx, ctx, ctx->object, nullptr, _base_id);
-
- /* Meta-balls have a different dupli handling. */
- if (ob->type != OB_MBALL) {
- ob->flag |= OB_DONE; /* Doesn't render. */
+ if (copy_dupli_context(&pctx, ctx, ctx->object, nullptr, _base_id)) {
+ /* Meta-balls have a different dupli handling. */
+ if (ob->type != OB_MBALL) {
+ ob->flag |= OB_DONE; /* Doesn't render. */
+ }
+ make_child_duplis_cb(&pctx, userdata, ob);
}
- make_child_duplis_cb(&pctx, userdata, ob);
}
}
FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END;
@@ -324,14 +328,14 @@ static void make_child_duplis(const DupliContext *ctx,
DEG_OBJECT_ITER_BEGIN (ctx->depsgraph, ob, deg_objects_visibility_flags) {
if ((ob != ctx->obedit) && is_child(ob, parent)) {
DupliContext pctx;
- copy_dupli_context(&pctx, ctx, ctx->object, nullptr, persistent_dupli_id);
+ if (copy_dupli_context(&pctx, ctx, ctx->object, nullptr, persistent_dupli_id)) {
+ /* Meta-balls have a different dupli-handling. */
+ if (ob->type != OB_MBALL) {
+ ob->flag |= OB_DONE; /* Doesn't render. */
+ }
- /* Meta-balls have a different dupli-handling. */
- if (ob->type != OB_MBALL) {
- ob->flag |= OB_DONE; /* Doesn't render. */
+ make_child_duplis_cb(&pctx, userdata, ob);
}
-
- make_child_duplis_cb(&pctx, userdata, ob);
}
persistent_dupli_id++;
}
@@ -893,7 +897,9 @@ static void make_duplis_geometry_set_impl(const DupliContext *ctx,
* between the instances component below and the other components above. */
DupliContext new_instances_ctx;
if (creates_duplis_for_components) {
- copy_dupli_context(&new_instances_ctx, ctx, ctx->object, nullptr, component_index);
+ if (!copy_dupli_context(&new_instances_ctx, ctx, ctx->object, nullptr, component_index)) {
+ return;
+ }
instances_ctx = &new_instances_ctx;
}
@@ -928,7 +934,9 @@ static void make_duplis_geometry_set_impl(const DupliContext *ctx,
mul_m4_m4_pre(collection_matrix, parent_transform);
DupliContext sub_ctx;
- copy_dupli_context(&sub_ctx, instances_ctx, instances_ctx->object, nullptr, id);
+ if (!copy_dupli_context(&sub_ctx, instances_ctx, instances_ctx->object, nullptr, id)) {
+ break;
+ }
eEvaluationMode mode = DEG_get_mode(instances_ctx->depsgraph);
int object_id = 0;
@@ -951,8 +959,9 @@ static void make_duplis_geometry_set_impl(const DupliContext *ctx,
mul_m4_m4m4(new_transform, parent_transform, instance_offset_matrices[i].values);
DupliContext sub_ctx;
- copy_dupli_context(&sub_ctx, instances_ctx, instances_ctx->object, nullptr, id);
- make_duplis_geometry_set_impl(&sub_ctx, reference.geometry_set(), new_transform, true);
+ if (copy_dupli_context(&sub_ctx, instances_ctx, instances_ctx->object, nullptr, id)) {
+ make_duplis_geometry_set_impl(&sub_ctx, reference.geometry_set(), new_transform, true);
+ }
break;
}
case InstanceReference::Type::None: {
@@ -1499,7 +1508,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
else {
/* First key. */
state.time = ctime;
- if (psys_get_particle_state(&sim, a, &state, 0) == 0) {
+ if (psys_get_particle_state(&sim, a, &state, false) == 0) {
continue;
}
@@ -1609,8 +1618,9 @@ static void make_duplis_particles(const DupliContext *ctx)
LISTBASE_FOREACH_INDEX (ParticleSystem *, psys, &ctx->object->particlesystem, psysid) {
/* Particles create one more level for persistent `psys` index. */
DupliContext pctx;
- copy_dupli_context(&pctx, ctx, ctx->object, nullptr, psysid);
- make_duplis_particle_system(&pctx, psys);
+ if (copy_dupli_context(&pctx, ctx, ctx->object, nullptr, psysid)) {
+ make_duplis_particle_system(&pctx, psys);
+ }
}
}
@@ -1678,9 +1688,6 @@ static const DupliGenerator *get_dupli_generator(const DupliContext *ctx)
/** \name Dupli-Container Implementation
* \{ */
-/**
- * \return a #ListBase of #DupliObject.
- */
ListBase *object_duplilist(Depsgraph *depsgraph, Scene *sce, Object *ob)
{
ListBase *duplilist = (ListBase *)MEM_callocN(sizeof(ListBase), "duplilist");
diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c
index 7e15ac5de5d..4c0d0303c1f 100644
--- a/source/blender/blenkernel/intern/object_update.c
+++ b/source/blender/blenkernel/intern/object_update.c
@@ -67,14 +67,6 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
-/**
- * Restore the object->data to a non-modifier evaluated state.
- *
- * Some changes done directly in evaluated object require them to be reset
- * before being re-evaluated.
- * For example, we need to call this before #BKE_mesh_new_from_object(),
- * in case we removed/added modifiers in the evaluated object.
- */
void BKE_object_eval_reset(Object *ob_eval)
{
BKE_object_free_derived_caches(ob_eval);
@@ -88,10 +80,10 @@ void BKE_object_eval_local_transform(Depsgraph *depsgraph, Object *ob)
BKE_object_to_mat4(ob, ob->obmat);
}
-/* Evaluate parent */
-/* NOTE: based on solve_parenting(), but with the cruft stripped out */
void BKE_object_eval_parent(Depsgraph *depsgraph, Object *ob)
{
+ /* NOTE: based on `solve_parenting()`, but with the cruft stripped out. */
+
Object *par = ob->parent;
float totmat[4][4];
@@ -282,7 +274,12 @@ void BKE_object_handle_data_update(Depsgraph *depsgraph, Scene *scene, Object *o
/** Bounding box from evaluated geometry. */
static void object_sync_boundbox_to_original(Object *object_orig, Object *object_eval)
{
- BoundBox *bb = BKE_object_boundbox_get(object_eval);
+ BoundBox *bb = object_eval->runtime.bb;
+ if (!bb || (bb->flag & BOUNDBOX_DIRTY)) {
+ BKE_object_boundbox_calc_from_evaluated_geometry(object_eval);
+ }
+
+ bb = BKE_object_boundbox_get(object_eval);
if (bb != NULL) {
if (object_orig->runtime.bb == NULL) {
object_orig->runtime.bb = MEM_mallocN(sizeof(*object_orig->runtime.bb), __func__);
diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c
index e9683d3b52c..97326c24a61 100644
--- a/source/blender/blenkernel/intern/ocean.c
+++ b/source/blender/blenkernel/intern/ocean.c
@@ -270,7 +270,6 @@ void BKE_ocean_eval_uv(struct Ocean *oc, struct OceanResult *ocr, float u, float
BLI_rw_mutex_unlock(&oc->oceanmutex);
}
-/* use catmullrom interpolation rather than linear */
void BKE_ocean_eval_uv_catrom(struct Ocean *oc, struct OceanResult *ocr, float u, float v)
{
int i0, i1, i2, i3, j0, j1, j2, j3;
@@ -378,8 +377,6 @@ void BKE_ocean_eval_xz_catrom(struct Ocean *oc, struct OceanResult *ocr, float x
BKE_ocean_eval_uv_catrom(oc, ocr, x / oc->_Lx, z / oc->_Lz);
}
-/* note that this doesn't wrap properly for i, j < 0, but its not really meant for that being
- * just a way to get the raw data out to save in some image format. */
void BKE_ocean_eval_ij(struct Ocean *oc, struct OceanResult *ocr, int i, int j)
{
BLI_rw_mutex_lock(&oc->oceanmutex, THREAD_LOCK_READ);
@@ -650,9 +647,6 @@ static void ocean_compute_normal_z(TaskPool *__restrict pool, void *UNUSED(taskd
fftw_execute(o->_N_z_plan);
}
-/**
- * Return true if the ocean is valid and can be used.
- */
bool BKE_ocean_is_valid(const struct Ocean *o)
{
return o->_k != NULL;
@@ -777,9 +771,6 @@ bool BKE_ocean_ensure(struct OceanModifierData *omd, const int resolution)
return true;
}
-/**
- * Return true if the ocean data is valid and can be used.
- */
bool BKE_ocean_init_from_modifier(struct Ocean *ocean,
struct OceanModifierData const *omd,
const int resolution)
@@ -818,9 +809,6 @@ bool BKE_ocean_init_from_modifier(struct Ocean *ocean,
omd->seed);
}
-/**
- * Return true if the ocean data is valid and can be used.
- */
bool BKE_ocean_init(struct Ocean *o,
int M,
int N,
diff --git a/source/blender/blenkernel/intern/ocean_spectrum.c b/source/blender/blenkernel/intern/ocean_spectrum.c
index c5504b22b43..43e0f399213 100644
--- a/source/blender/blenkernel/intern/ocean_spectrum.c
+++ b/source/blender/blenkernel/intern/ocean_spectrum.c
@@ -128,11 +128,6 @@ static float jonswap(const Ocean *oc, const float k2)
return val;
}
-/**
- * Pierson-Moskowitz model, 1964, assumes waves reach equilibrium with wind.
- * Model is intended for large area 'fully developed' sea, where winds have been steadily blowing
- * for days over an area that includes hundreds of wavelengths on a side.
- */
float BLI_ocean_spectrum_piersonmoskowitz(const Ocean *oc, const float kx, const float kz)
{
const float k2 = kx * kx + kz * kz;
@@ -159,10 +154,6 @@ float BLI_ocean_spectrum_piersonmoskowitz(const Ocean *oc, const float kx, const
return val;
}
-/**
- * TMA extends the JONSWAP spectrum.
- * This spectral model is best suited to shallow water.
- */
float BLI_ocean_spectrum_texelmarsenarsloe(const Ocean *oc, const float kx, const float kz)
{
const float k2 = kx * kx + kz * kz;
@@ -195,14 +186,6 @@ float BLI_ocean_spectrum_texelmarsenarsloe(const Ocean *oc, const float kx, cons
return val;
}
-/**
- * Hasselmann et al, 1973. This model extends the Pierson-Moskowitz model with a peak sharpening
- * function This enhancement is an artificial construct to address the problem that the wave
- * spectrum is never fully developed.
- *
- * The fetch parameter represents the distance from a lee shore,
- * called the fetch, or the distance over which the wind blows with constant velocity.
- */
float BLI_ocean_spectrum_jonswap(const Ocean *oc, const float kx, const float kz)
{
const float k2 = kx * kx + kz * kz;
diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c
index f0f8343420d..8989450e41b 100644
--- a/source/blender/blenkernel/intern/packedFile.c
+++ b/source/blender/blenkernel/intern/packedFile.c
@@ -242,7 +242,6 @@ PackedFile *BKE_packedfile_new(ReportList *reports, const char *filename, const
return pf;
}
-/* no libraries for now */
void BKE_packedfile_pack_all(Main *bmain, ReportList *reports, bool verbose)
{
Image *ima;
@@ -373,14 +372,6 @@ int BKE_packedfile_write_to_file(ReportList *reports,
return ret_value;
}
-/**
- * This function compares a packed file to a 'real' file.
- * It returns an integer indicating if:
- *
- * - PF_EQUAL: the packed file and original file are identical
- * - PF_DIFFERENT: the packed file and original file differ
- * - PF_NOFILE: the original file doesn't exist
- */
enum ePF_FileCompare BKE_packedfile_compare_to_file(const char *ref_file_name,
const char *filename,
PackedFile *pf)
@@ -434,16 +425,6 @@ enum ePF_FileCompare BKE_packedfile_compare_to_file(const char *ref_file_name,
return ret_val;
}
-/**
- * #BKE_packedfile_unpack_to_file() looks at the existing files (abs_name, local_name)
- * and a packed file.
- *
- * It returns a char *to the existing file name / new file name or NULL when
- * there was an error or when the user decides to cancel the operation.
- *
- * \warning 'abs_name' may be relative still! (use a "//" prefix)
- * be sure to run #BLI_path_abs on it first.
- */
char *BKE_packedfile_unpack_to_file(ReportList *reports,
const char *ref_file_name,
const char *abs_name,
@@ -804,7 +785,6 @@ void BKE_packedfile_unpack_all(Main *bmain, ReportList *reports, enum ePF_FileSt
}
}
-/* ID should be not NULL, return 1 if there's a packed file */
bool BKE_packedfile_id_check(const ID *id)
{
switch (GS(id->name)) {
@@ -834,7 +814,6 @@ bool BKE_packedfile_id_check(const ID *id)
return false;
}
-/* ID should be not NULL */
void BKE_packedfile_id_unpack(Main *bmain, ID *id, ReportList *reports, enum ePF_FileStatus how)
{
switch (GS(id->name)) {
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index d6030941c6d..72210eea71d 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -143,6 +143,7 @@ IDTypeInfo IDType_ID_PAL = {
.name_plural = "palettes",
.translation_context = BLT_I18NCONTEXT_ID_PALETTE,
.flags = IDTYPE_FLAGS_NO_ANIMDATA,
+ .asset_type_info = NULL,
.init_data = palette_init_data,
.copy_data = palette_copy_data,
@@ -150,6 +151,7 @@ IDTypeInfo IDType_ID_PAL = {
.make_local = NULL,
.foreach_id = NULL,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = palette_blend_write,
@@ -208,6 +210,7 @@ IDTypeInfo IDType_ID_PC = {
.name_plural = "paint_curves",
.translation_context = BLT_I18NCONTEXT_ID_PAINTCURVE,
.flags = IDTYPE_FLAGS_NO_ANIMDATA,
+ .asset_type_info = NULL,
.init_data = NULL,
.copy_data = paint_curve_copy_data,
@@ -215,6 +218,7 @@ IDTypeInfo IDType_ID_PC = {
.make_local = NULL,
.foreach_id = NULL,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = paint_curve_blend_write,
@@ -723,7 +727,6 @@ void BKE_paint_curve_clamp_endpoint_add_index(PaintCurve *pc, const int add_inde
pc->add_index = (add_index || pc->tot_points == 1) ? (add_index + 1) : 0;
}
-/** Remove color from palette. Must be certain color is inside the palette! */
void BKE_palette_color_remove(Palette *palette, PaletteColor *color)
{
if (BLI_listbase_count_at_most(&palette->colors, palette->active_color) ==
@@ -962,7 +965,6 @@ bool BKE_palette_from_hash(Main *bmain, GHash *color_table, const char *name, co
return done;
}
-/* are we in vertex paint or weight paint face select mode? */
bool BKE_paint_select_face_test(Object *ob)
{
return ((ob != NULL) && (ob->type == OB_MESH) && (ob->data != NULL) &&
@@ -970,7 +972,6 @@ bool BKE_paint_select_face_test(Object *ob)
(ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT)));
}
-/* are we in weight paint vertex select mode? */
bool BKE_paint_select_vert_test(Object *ob)
{
return ((ob != NULL) && (ob->type == OB_MESH) && (ob->data != NULL) &&
@@ -978,10 +979,6 @@ bool BKE_paint_select_vert_test(Object *ob)
(ob->mode & OB_MODE_WEIGHT_PAINT || ob->mode & OB_MODE_VERTEX_PAINT));
}
-/**
- * used to check if selection is possible
- * (when we don't care if its face or vert)
- */
bool BKE_paint_select_elem_test(Object *ob)
{
return (BKE_paint_select_vert_test(ob) || BKE_paint_select_face_test(ob));
@@ -1024,9 +1021,6 @@ eObjectMode BKE_paint_object_mode_from_paintmode(ePaintMode mode)
}
}
-/**
- * Call when entering each respective paint mode.
- */
bool BKE_paint_ensure(ToolSettings *ts, struct Paint **r_paint)
{
Paint *paint = NULL;
@@ -1147,10 +1141,6 @@ void BKE_paint_free(Paint *paint)
MEM_SAFE_FREE(paint->tool_slots);
}
-/* called when copying scene settings, so even if 'src' and 'tar' are the same
- * still do a id_us_plus(), rather than if we were copying between 2 existing
- * scenes where a matching value should decrease the existing user count as
- * with paint_brush_set() */
void BKE_paint_copy(Paint *src, Paint *tar, const int flag)
{
tar->brush = src->brush;
@@ -1230,8 +1220,6 @@ void BKE_paint_blend_read_lib(BlendLibReader *reader, Scene *sce, Paint *p)
}
}
-/* returns non-zero if any of the face's vertices
- * are hidden, zero otherwise */
bool paint_is_face_hidden(const MLoopTri *lt, const MVert *mvert, const MLoop *mloop)
{
return ((mvert[mloop[lt->tri[0]].v].flag & ME_HIDE) ||
@@ -1239,9 +1227,6 @@ bool paint_is_face_hidden(const MLoopTri *lt, const MVert *mvert, const MLoop *m
(mvert[mloop[lt->tri[2]].v].flag & ME_HIDE));
}
-/* returns non-zero if any of the corners of the grid
- * face whose inner corner is at (x, y) are hidden,
- * zero otherwise */
bool paint_is_grid_face_hidden(const uint *grid_hidden, int gridsize, int x, int y)
{
/* skip face if any of its corners are hidden */
@@ -1251,7 +1236,6 @@ bool paint_is_grid_face_hidden(const uint *grid_hidden, int gridsize, int x, int
BLI_BITMAP_TEST(grid_hidden, (y + 1) * gridsize + x));
}
-/* Return true if all vertices in the face are visible, false otherwise */
bool paint_is_bmesh_face_hidden(BMFace *f)
{
BMLoop *l_iter;
@@ -1520,8 +1504,6 @@ void BKE_sculptsession_free(Object *ob)
}
}
-/* Sculpt mode handles multires differently from regular meshes, but only if
- * it's the last modifier on the stack and it is not on the first level */
MultiresModifierData *BKE_sculpt_multires_active(Scene *scene, Object *ob)
{
Mesh *me = (Mesh *)ob->data;
@@ -1811,7 +1793,6 @@ void BKE_sculpt_color_layer_create_if_needed(struct Object *object)
DEG_id_tag_update(&orig_me->id, ID_RECALC_GEOMETRY_ALL_MODES);
}
-/** \warning Expects a fully evaluated depsgraph. */
void BKE_sculpt_update_object_for_edit(
Depsgraph *depsgraph, Object *ob_orig, bool need_pmap, bool need_mask, bool need_colors)
{
@@ -1941,10 +1922,6 @@ static bool check_sculpt_object_deformed(Object *object, const bool for_construc
return deformed;
}
-/**
- * Ensures that a Face Set data-layers exists. If it does not, it creates one respecting the
- * visibility stored in the vertices of the mesh. If it does, it copies the visibility from the
- * mesh to the Face Sets. */
void BKE_sculpt_face_sets_ensure_from_base_mesh_visibility(Mesh *mesh)
{
const int face_sets_default_visible_id = 1;
@@ -2046,12 +2023,6 @@ void BKE_sculpt_sync_face_set_visibility(struct Mesh *mesh, struct SubdivCCG *su
BKE_sculpt_sync_face_sets_visibility_to_grids(mesh, subdiv_ccg);
}
-/**
- * Ensures we do have expected mesh data in original mesh for the sculpt mode.
- *
- * \note IDs are expected to be original ones here, and calling code should ensure it updates its
- * depsgraph properly after calling this function if it needs up-to-date evaluated data.
- */
void BKE_sculpt_ensure_orig_mesh_data(Scene *scene, Object *object)
{
Mesh *mesh = BKE_mesh_from_object(object);
@@ -2223,8 +2194,6 @@ void BKE_sculpt_bvh_update_from_ccg(PBVH *pbvh, SubdivCCG *subdiv_ccg)
subdiv_ccg->grid_hidden);
}
-/* Test if PBVH can be used directly for drawing, which is faster than
- * drawing the mesh and all updates that come with it. */
bool BKE_sculptsession_use_pbvh_draw(const Object *ob, const View3D *v3d)
{
SculptSession *ss = ob->sculpt;
diff --git a/source/blender/blenkernel/intern/paint_toolslots.c b/source/blender/blenkernel/intern/paint_toolslots.c
index 0ea0173f8a3..bdb7b483997 100644
--- a/source/blender/blenkernel/intern/paint_toolslots.c
+++ b/source/blender/blenkernel/intern/paint_toolslots.c
@@ -140,10 +140,6 @@ void BKE_paint_toolslots_brush_update(Paint *paint)
BKE_paint_toolslots_brush_update_ex(paint, paint->brush);
}
-/**
- * Run this to ensure brush types are set for each slot on entering modes
- * (for new scenes for example).
- */
void BKE_paint_toolslots_brush_validate(Main *bmain, Paint *paint)
{
/* Clear slots with invalid slots or mode (unlikely but possible). */
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index b158633294e..674f264feb7 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -500,6 +500,7 @@ IDTypeInfo IDType_ID_PA = {
.name_plural = "particles",
.translation_context = BLT_I18NCONTEXT_ID_PARTICLESETTINGS,
.flags = 0,
+ .asset_type_info = NULL,
.init_data = particle_settings_init,
.copy_data = particle_settings_copy_data,
@@ -507,6 +508,7 @@ IDTypeInfo IDType_ID_PA = {
.make_local = NULL,
.foreach_id = particle_settings_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = particle_settings_blend_write,
@@ -554,7 +556,6 @@ static void get_cpa_texture(Mesh *mesh,
int event,
float cfra);
-/* few helpers for countall etc. */
int count_particles(ParticleSystem *psys)
{
ParticleSettings *part = psys->part;
@@ -644,7 +645,7 @@ static void psys_free_path_cache_buffers(ParticleCacheKey **cache, ListBase *buf
/************************************************/
/* Getting stuff */
/************************************************/
-/* get object's active particle system safely */
+
ParticleSystem *psys_get_current(Object *ob)
{
ParticleSystem *psys;
@@ -912,9 +913,11 @@ int psys_uses_gravity(ParticleSimulationData *sim)
return sim->scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY && sim->psys->part &&
sim->psys->part->effector_weights->global_gravity != 0.0f;
}
+
/************************************************/
/* Freeing stuff */
/************************************************/
+
static void fluid_free_settings(SPHFluidSettings *fluid)
{
if (fluid) {
@@ -1054,7 +1057,6 @@ void psys_free_pdd(ParticleSystem *psys)
psys->pdd->partsize = 0;
}
}
-/* free everything */
void psys_free(Object *ob, ParticleSystem *psys)
{
if (psys) {
@@ -1202,6 +1204,7 @@ void psys_copy_particles(ParticleSystem *psys_dst, ParticleSystem *psys_src)
/************************************************/
/* Interpolation */
/************************************************/
+
static float interpolate_particle_value(
float v1, float v2, float v3, float v4, const float w[4], int four)
{
@@ -1669,7 +1672,7 @@ static void interpolate_pathcache(ParticleCacheKey *first, float t, ParticleCach
/************************************************/
/* Particles on a dm */
/************************************************/
-/* interpolate a location on a face based on face coordinates */
+
void psys_interpolate_face(MVert *mvert,
MFace *mface,
MTFace *tface,
@@ -1901,18 +1904,6 @@ static void psys_origspace_to_w(OrigSpaceFace *osface, int quad, const float w[4
}
}
-/**
- * Find the final derived mesh tessface for a particle, from its original tessface index.
- * This is slow and can be optimized but only for many lookups.
- *
- * \param mesh_final: Final mesh, it may not have the same topology as original mesh.
- * \param mesh_original: Original mesh, use for accessing #MPoly to #MFace mapping.
- * \param findex_orig: The input tessface index.
- * \param fw: Face weights (position of the particle inside the \a findex_orig tessface).
- * \param poly_nodes: May be NULL, otherwise an array of linked list,
- * one for each final \a mesh_final polygon, containing all its tessfaces indices.
- * \return The \a mesh_final tessface index.
- */
int psys_particle_dm_face_lookup(Mesh *mesh_final,
Mesh *mesh_original,
int findex_orig,
@@ -2094,7 +2085,6 @@ static int psys_map_index_on_dm(Mesh *mesh,
return 1;
}
-/* interprets particle data to get a point on a mesh in object space */
void psys_particle_on_dm(Mesh *mesh_final,
int from,
int index,
@@ -2216,9 +2206,11 @@ ParticleSystemModifierData *psys_get_modifier(Object *ob, ParticleSystem *psys)
}
return NULL;
}
+
/************************************************/
/* Particles on a shape */
/************************************************/
+
/* ready for future use */
static void psys_particle_on_shape(int UNUSED(distr),
int UNUSED(index),
@@ -2247,6 +2239,7 @@ static void psys_particle_on_shape(int UNUSED(distr),
copy_v3_v3(orco, zerovec);
}
}
+
/************************************************/
/* Particles on emitter */
/************************************************/
@@ -2321,6 +2314,7 @@ void psys_particle_on_emitter(ParticleSystemModifierData *psmd,
psys_particle_on_shape(from, index, fuv, vec, nor, utan, vtan, orco);
}
}
+
/************************************************/
/* Path Cache */
/************************************************/
@@ -3273,11 +3267,6 @@ static void cache_key_incremental_rotation(ParticleCacheKey *key0,
}
}
-/**
- * Calculates paths ready for drawing/rendering
- * - Useful for making use of opengl vertex arrays for super fast strand drawing.
- * - Makes child strands possible and creates them too into the cache.
- * - Cached path data is also used to determine cut position for the editmode tool. */
void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_render_params)
{
PARTICLE_PSMD;
@@ -3760,9 +3749,11 @@ void psys_cache_edit_paths(Depsgraph *depsgraph,
}
}
}
+
/************************************************/
/* Particle Key handling */
/************************************************/
+
void copy_particle_key(ParticleKey *to, ParticleKey *from, int time)
{
if (time) {
@@ -3922,6 +3913,7 @@ void psys_mat_hair_to_global(
/************************************************/
/* ParticleSettings handling */
/************************************************/
+
static ModifierData *object_add_or_copy_particle_system(
Main *bmain, Scene *scene, Object *ob, const char *name, const ParticleSystem *psys_orig)
{
@@ -4458,9 +4450,11 @@ void psys_get_texture(
CLAMP_WARP_PARTICLE_TEXTURE_POS(PAMAP_DAMP, ptex->damp);
CLAMP_PARTICLE_TEXTURE_POS(PAMAP_LENGTH, ptex->length);
}
+
/************************************************/
/* Particle State */
/************************************************/
+
float psys_get_timestep(ParticleSimulationData *sim)
{
return 0.04f * sim->psys->part->timetweak;
@@ -4586,7 +4580,6 @@ static void get_child_modifier_parameters(ParticleSettings *part,
ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_twist);
}
}
-/* gets hair (or keyed) particles state at the "path time" specified in state->time */
void psys_get_particle_on_path(ParticleSimulationData *sim,
int p,
ParticleKey *state,
@@ -4855,8 +4848,10 @@ void psys_get_particle_on_path(ParticleSimulationData *sim,
}
}
}
-/* gets particle's state at a time, returns 1 if particle exists and can be seen and 0 if not */
-int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *state, int always)
+bool psys_get_particle_state(ParticleSimulationData *sim,
+ int p,
+ ParticleKey *state,
+ const bool always)
{
ParticleSystem *psys = sim->psys;
ParticleSettings *part = psys->part;
@@ -4871,12 +4866,12 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta
if (p >= totpart) {
if (!psys->totchild) {
- return 0;
+ return false;
}
if (part->childtype == PART_CHILD_FACES) {
if (!(psys->flag & PSYS_KEYED)) {
- return 0;
+ return false;
}
cpa = psys->child + p - totpart;
@@ -4886,7 +4881,7 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta
if (!always) {
if ((state->time < 0.0f && !(part->flag & PART_UNBORN)) ||
(state->time > 1.0f && !(part->flag & PART_DIED))) {
- return 0;
+ return false;
}
}
@@ -4894,7 +4889,7 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta
(part->lifetime * psys_frand(psys, p + 24));
psys_get_particle_on_path(sim, p, state, 1);
- return 1;
+ return true;
}
cpa = sim->psys->child + p - totpart;
@@ -4908,7 +4903,7 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta
if (!always) {
if ((cfra < pa->time && (part->flag & PART_UNBORN) == 0) ||
(cfra >= pa->dietime && (part->flag & PART_DIED) == 0)) {
- return 0;
+ return false;
}
}
@@ -4918,7 +4913,7 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta
if (sim->psys->flag & PSYS_KEYED) {
state->time = -cfra;
psys_get_particle_on_path(sim, p, state, 1);
- return 1;
+ return true;
}
if (cpa) {
@@ -5018,7 +5013,7 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta
}
}
- return 1;
+ return true;
}
void psys_get_dupli_texture(ParticleSystem *psys,
diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c
index 863476c6638..fd4f89e3f6d 100644
--- a/source/blender/blenkernel/intern/particle_distribute.c
+++ b/source/blender/blenkernel/intern/particle_distribute.c
@@ -997,12 +997,7 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx,
BKE_mesh_tessface_ensure(mesh);
/* we need orco for consistent distributions */
- if (!CustomData_has_layer(&mesh->vdata, CD_ORCO)) {
- /* Orcos are stored in normalized 0..1 range by convention. */
- float(*orcodata)[3] = BKE_mesh_orco_verts_get(ob);
- BKE_mesh_orco_verts_transform(mesh, orcodata, mesh->totvert, false);
- CustomData_add_layer(&mesh->vdata, CD_ORCO, CD_ASSIGN, orcodata, mesh->totvert);
- }
+ BKE_mesh_orco_ensure(ob, mesh);
if (from == PART_FROM_VERT) {
MVert *mv = mesh->mvert;
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index 8986847a034..e489f9e2bac 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -452,7 +452,6 @@ void psys_calc_dmcache(Object *ob, Mesh *mesh_final, Mesh *mesh_original, Partic
}
}
-/* threaded child particle distribution and path caching */
void psys_thread_context_init(ParticleThreadContext *ctx, ParticleSimulationData *sim)
{
memset(ctx, 0, sizeof(ParticleThreadContext));
@@ -591,7 +590,6 @@ static void init_particle_texture(ParticleSimulationData *sim, ParticleData *pa,
}
}
-/* set particle parameters that don't change during particle's life */
void init_particle(ParticleSimulationData *sim, ParticleData *pa)
{
ParticleSettings *part = sim->psys->part;
@@ -1066,7 +1064,6 @@ static void evaluate_emitter_anim(struct Depsgraph *depsgraph,
BKE_object_where_is_calc_time(depsgraph, scene, ob, cfra);
}
-/* sets particle to the emitter surface with initial velocity & rotation */
void reset_particle(ParticleSimulationData *sim, ParticleData *pa, float dtime, float cfra)
{
ParticleSystem *psys = sim->psys;
@@ -1157,9 +1154,11 @@ static void reset_all_particles(ParticleSimulationData *sim, float dtime, float
reset_particle(sim, pa, dtime, cfra);
}
}
+
/************************************************/
/* Particle targets */
/************************************************/
+
ParticleSystem *psys_get_target_system(Object *ob, ParticleTarget *pt)
{
ParticleSystem *psys = NULL;
@@ -1180,10 +1179,11 @@ ParticleSystem *psys_get_target_system(Object *ob, ParticleTarget *pt)
return psys;
}
+
/************************************************/
/* Keyed particles */
/************************************************/
-/* Counts valid keyed targets */
+
void psys_count_keyed_targets(ParticleSimulationData *sim)
{
ParticleSystem *psys = sim->psys, *kpsys;
@@ -1288,6 +1288,7 @@ static void set_keyed_keys(ParticleSimulationData *sim)
/************************************************/
/* Point Cache */
/************************************************/
+
void psys_make_temp_pointcache(Object *ob, ParticleSystem *psys)
{
PointCache *cache = psys->pointcache;
@@ -1325,6 +1326,7 @@ static void bvhtree_balance_isolated(void *userdata)
/************************************************/
/* Effectors */
/************************************************/
+
static void psys_update_particle_bvhtree(ParticleSystem *psys, float cfra)
{
if (psys) {
@@ -2181,7 +2183,6 @@ void psys_sph_finalize(SPHData *sphdata)
}
}
-/* Sample the density field at a point in space. */
void psys_sph_density(BVHTree *tree, SPHData *sphdata, float co[3], float vars[2])
{
ParticleSystem **psys = sphdata->psys;
@@ -2234,6 +2235,7 @@ static void sph_integrate(ParticleSimulationData *sim,
/************************************************/
/* Basic physics */
/************************************************/
+
typedef struct EfData {
ParticleTexture ptex;
ParticleSimulationData *sim;
@@ -2787,7 +2789,6 @@ static int collision_sphere_to_verts(ParticleCollision *col,
return hit != NULL;
}
-/* Callback for BVHTree near test */
void BKE_psys_collision_neartest_cb(void *userdata,
int index,
const BVHTreeRay *ray,
@@ -3179,10 +3180,14 @@ static void collision_check(ParticleSimulationData *sim, int p, float dfra, floa
}
}
}
+
/************************************************/
/* Hair */
/************************************************/
-/* check if path cache or children need updating and do it if needed */
+
+/**
+ * Check if path cache or children need updating and do it if needed.
+ */
static void psys_update_path_cache(ParticleSimulationData *sim,
float cfra,
const bool use_render_params)
@@ -4627,7 +4632,6 @@ static void system_step(ParticleSimulationData *sim, float cfra, const bool use_
}
}
-/* system type has changed so set sensible defaults and clear non applicable flags */
void psys_changed_type(Object *ob, ParticleSystem *psys)
{
ParticleSettings *part = psys->part;
@@ -4765,8 +4769,6 @@ static void particle_settings_free_local(ParticleSettings *particle_settings)
MEM_freeN(particle_settings);
}
-/* main particle update call, checks that things are ok on the large scale and
- * then advances in to actual particle calculations depending on particle type */
void particle_system_update(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob,
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index 2318a05e635..2f22f94d142 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -78,7 +78,6 @@ void BB_reset(BB *bb)
bb->bmax[0] = bb->bmax[1] = bb->bmax[2] = -FLT_MAX;
}
-/* Expand the bounding box to include a new coordinate */
void BB_expand(BB *bb, const float co[3])
{
for (int i = 0; i < 3; i++) {
@@ -87,7 +86,6 @@ void BB_expand(BB *bb, const float co[3])
}
}
-/* Expand the bounding box to include another bounding box */
void BB_expand_with_bb(BB *bb, BB *bb2)
{
for (int i = 0; i < 3; i++) {
@@ -96,7 +94,6 @@ void BB_expand_with_bb(BB *bb, BB *bb2)
}
}
-/* Return 0, 1, or 2 to indicate the widest axis of the bounding box */
int BB_widest_axis(const BB *bb)
{
float dim[3];
@@ -351,7 +348,6 @@ static void update_vb(PBVH *pbvh, PBVHNode *node, BBC *prim_bbc, int offset, int
node->orig_vb = node->vb;
}
-/* Returns the number of visible quads in the nodes' grids. */
int BKE_pbvh_count_grid_quads(BLI_bitmap **grid_hidden,
const int *grid_indices,
int totgrid,
@@ -555,12 +551,6 @@ static void pbvh_build(PBVH *pbvh, BB *cb, BBC *prim_bbc, int totprim)
build_sub(pbvh, 0, cb, prim_bbc, 0, totprim);
}
-/**
- * Do a full rebuild with on Mesh data structure.
- *
- * \note Unlike mpoly/mloop/verts, looptri is **totally owned** by PBVH
- * (which means it may rewrite it if needed, see #BKE_pbvh_vert_coords_apply().
- */
void BKE_pbvh_build_mesh(PBVH *pbvh,
const Mesh *mesh,
const MPoly *mpoly,
@@ -621,7 +611,6 @@ void BKE_pbvh_build_mesh(PBVH *pbvh,
MEM_freeN(pbvh->vert_bitmap);
}
-/* Do a full rebuild with on Grids data structure */
void BKE_pbvh_build_grids(PBVH *pbvh,
CCGElem **grids,
int totgrid,
@@ -1954,11 +1943,6 @@ void BKE_pbvh_node_get_bm_orco_data(PBVHNode *node,
*r_orco_coords = node->bm_orco;
}
-/**
- * \note doing a full search on all vertices here seems expensive,
- * however this is important to avoid having to recalculate bound-box & sync the buffers to the
- * GPU (which is far more expensive!) See: T47232.
- */
bool BKE_pbvh_node_vert_update_check_any(PBVH *pbvh, PBVHNode *node)
{
BLI_assert(pbvh->type == PBVH_FACES);
diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c
index 679a8b378b9..6f57448b0ab 100644
--- a/source/blender/blenkernel/intern/pbvh_bmesh.c
+++ b/source/blender/blenkernel/intern/pbvh_bmesh.c
@@ -1875,7 +1875,6 @@ static void pbvh_bmesh_create_nodes_fast_recursive(
/***************************** Public API *****************************/
-/* Build a PBVH from a BMesh */
void BKE_pbvh_build_bmesh(PBVH *pbvh,
BMesh *bm,
bool smooth_shading,
@@ -1953,7 +1952,6 @@ void BKE_pbvh_build_bmesh(PBVH *pbvh,
MEM_freeN(nodeinfo);
}
-/* Collapse short edges, subdivide long edges */
bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
PBVHTopologyUpdateMode mode,
const float center[3],
@@ -2031,10 +2029,6 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
return modified;
}
-/* In order to perform operations on the original node coordinates
- * (currently just raycast), store the node's triangles and vertices.
- *
- * Skips triangles that are hidden. */
void BKE_pbvh_bmesh_node_save_orig(BMesh *bm, PBVHNode *node)
{
/* Skip if original coords/triangles are already saved */
diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h
index 79b25c027ba..12c2d7aac78 100644
--- a/source/blender/blenkernel/intern/pbvh_intern.h
+++ b/source/blender/blenkernel/intern/pbvh_intern.h
@@ -180,9 +180,18 @@ struct PBVH {
/* pbvh.c */
void BB_reset(BB *bb);
+/**
+ * Expand the bounding box to include a new coordinate.
+ */
void BB_expand(BB *bb, const float co[3]);
+/**
+ * Expand the bounding box to include another bounding box.
+ */
void BB_expand_with_bb(BB *bb, BB *bb2);
void BBC_update_centroid(BBC *bbc);
+/**
+ * Return 0, 1, or 2 to indicate the widest axis of the bounding box.
+ */
int BB_widest_axis(const BB *bb);
void pbvh_grow_nodes(PBVH *bvh, int totnode);
bool ray_face_intersection_quad(const float ray_start[3],
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index 57225872c7e..df76f003498 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -266,7 +266,8 @@ static void ptcache_softbody_error(const ID *UNUSED(owner_id),
/* ignored for now */
}
-/* Particle functions */
+/* Particle functions. */
+
void BKE_ptcache_make_particle_key(ParticleKey *key, int index, void **data, float time)
{
PTCACHE_DATA_TO(data, BPHYS_DATA_LOCATION, index, key->co);
@@ -873,6 +874,7 @@ static void ptcache_rigidbody_error(const struct ID *UNUSED(owner_id),
}
/* Creating ID's */
+
void BKE_ptcache_id_from_softbody(PTCacheID *pid, Object *ob, SoftBody *sb)
{
memset(pid, 0, sizeof(PTCacheID));
@@ -1008,9 +1010,6 @@ void BKE_ptcache_id_from_cloth(PTCacheID *pid, Object *ob, ClothModifierData *cl
pid->file_type = PTCACHE_FILE_PTCACHE;
}
-/* The fluid modifier does not actually use this anymore, but some parts of Blender expect that it
- * still has a point cache currently. For example, the fluid modifier uses
- * #DEG_add_collision_relations, which internally creates relations with the point cache. */
void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct FluidModifierData *fmd)
{
FluidDomainSettings *fds = fmd->domain;
@@ -1104,10 +1103,6 @@ void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, Object *ob, RigidBodyWorld *r
pid->file_type = PTCACHE_FILE_PTCACHE;
}
-/**
- * \param ob: Optional, may be NULL.
- * \param scene: Optional may be NULL.
- */
PTCacheID BKE_ptcache_id_find(Object *ob, Scene *scene, PointCache *cache)
{
PTCacheID result = {0};
@@ -1327,10 +1322,11 @@ static int ptcache_frame_from_filename(const char *filename, const char *ext)
static int ptcache_path(PTCacheID *pid, char *filename)
{
+ const char *blendfile_path = BKE_main_blendfile_path_from_global();
Library *lib = (pid->owner_id) ? pid->owner_id->lib : NULL;
const char *blendfilename = (lib && (pid->cache->flag & PTCACHE_IGNORE_LIBPATH) == 0) ?
lib->filepath_abs :
- BKE_main_blendfile_path_from_global();
+ blendfile_path;
size_t i;
if (pid->cache->flag & PTCACHE_EXTERNAL) {
@@ -1342,7 +1338,7 @@ static int ptcache_path(PTCacheID *pid, char *filename)
return BLI_path_slash_ensure(filename); /* new strlen() */
}
- if (G.relbase_valid || lib) {
+ if ((blendfile_path[0] != '\0') || lib) {
char file[MAX_PTCACHE_PATH]; /* we don't want the dir, only the file */
BLI_split_file_part(blendfilename, file, sizeof(file));
@@ -1427,8 +1423,11 @@ static int ptcache_filename(PTCacheID *pid, char *filename, int cfra, short do_p
filename[0] = '\0';
newname = filename;
- if (!G.relbase_valid && (pid->cache->flag & PTCACHE_EXTERNAL) == 0) {
- return 0; /* save blend file before using disk pointcache */
+ if ((pid->cache->flag & PTCACHE_EXTERNAL) == 0) {
+ const char *blendfile_path = BKE_main_blendfile_path_from_global();
+ if (blendfile_path[0] == '\0') {
+ return 0; /* save blend file before using disk pointcache */
+ }
}
/* start with temp dir */
@@ -1474,8 +1473,11 @@ static PTCacheFile *ptcache_file_open(PTCacheID *pid, int mode, int cfra)
return NULL;
}
#endif
- if (!G.relbase_valid && (pid->cache->flag & PTCACHE_EXTERNAL) == 0) {
- return NULL; /* save blend file before using disk pointcache */
+ if ((pid->cache->flag & PTCACHE_EXTERNAL) == 0) {
+ const char *blendfile_path = BKE_main_blendfile_path_from_global();
+ if (blendfile_path[0] == '\0') {
+ return NULL; /* save blend file before using disk pointcache */
+ }
}
ptcache_filename(pid, filename, cfra, 1, 1);
@@ -1713,7 +1715,8 @@ static int ptcache_file_header_begin_write(PTCacheFile *pf)
return 1;
}
-/* Data pointer handling */
+/* Data pointer handling. */
+
int BKE_ptcache_data_size(int data_type)
{
return ptcache_data_size[data_type];
@@ -1734,7 +1737,6 @@ static void ptcache_file_pointers_init(PTCacheFile *pf)
pf->cur[BPHYS_DATA_BOIDS] = (data_types & (1 << BPHYS_DATA_BOIDS)) ? &pf->data.boids : NULL;
}
-/* Check to see if point number "index" is in pm, uses binary search for index data. */
int BKE_ptcache_mem_index_find(PTCacheMem *pm, unsigned int index)
{
if (pm->totpoint > 0 && pm->data[BPHYS_DATA_INDEX]) {
@@ -2288,7 +2290,6 @@ static int ptcache_interpolate(PTCacheID *pid, float cfra, int cfra1, int cfra2)
return 1;
}
/* reads cache from disk or memory */
-/* possible to get old or interpolated result */
int BKE_ptcache_read(PTCacheID *pid, float cfra, bool no_extrapolate_old)
{
int cfrai = (int)floor(cfra), cfra1 = 0, cfra2 = 0;
@@ -2549,7 +2550,6 @@ static int ptcache_write_needed(PTCacheID *pid, int cfra, int *overwrite)
return 0;
}
-/* writes cache to disk or memory */
int BKE_ptcache_write(PTCacheID *pid, unsigned int cfra)
{
PointCache *cache = pid->cache;
@@ -2600,7 +2600,8 @@ int BKE_ptcache_write(PTCacheID *pid, unsigned int cfra)
* mode - PTCACHE_CLEAR_ALL,
*/
-/* Clears & resets */
+/* Clears & resets. */
+
void BKE_ptcache_id_clear(PTCacheID *pid, int mode, unsigned int cfra)
{
unsigned int len; /* store the length of the string */
@@ -2632,8 +2633,6 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, unsigned int cfra)
}
#endif
- // if (!G.relbase_valid) return; /* Save blend file before using pointcache. */
-
/* clear all files in the temp dir with the prefix of the ID and the ".bphys" suffix */
switch (mode) {
case PTCACHE_CLEAR_ALL:
@@ -3014,50 +3013,6 @@ int BKE_ptcache_object_reset(Scene *scene, Object *ob, int mode)
return reset;
}
-/* Use this when quitting blender, with unsaved files */
-void BKE_ptcache_remove(void)
-{
- char path[MAX_PTCACHE_PATH];
- char path_full[MAX_PTCACHE_PATH];
- int rmdir = 1;
-
- ptcache_path(NULL, path);
-
- if (BLI_exists(path)) {
- /* The pointcache dir exists? - remove all pointcache */
-
- DIR *dir;
- struct dirent *de;
-
- dir = opendir(path);
- if (dir == NULL) {
- return;
- }
-
- while ((de = readdir(dir)) != NULL) {
- if (FILENAME_IS_CURRPAR(de->d_name)) {
- /* do nothing */
- }
- else if (strstr(de->d_name, PTCACHE_EXT)) { /* Do we have the right extension? */
- BLI_join_dirfile(path_full, sizeof(path_full), path, de->d_name);
- BLI_delete(path_full, false, false);
- }
- else {
- rmdir = 0; /* unknown file, don't remove the dir */
- }
- }
-
- closedir(dir);
- }
- else {
- rmdir = 0; /* Path doesn't exist. */
- }
-
- if (rmdir) {
- BLI_delete(path, true, false);
- }
-}
-
/* Point Cache handling */
PointCache *BKE_ptcache_add(ListBase *ptcaches)
@@ -3150,7 +3105,6 @@ static PointCache *ptcache_copy(PointCache *cache, const bool copy_data)
return ncache;
}
-/* returns first point cache */
PointCache *BKE_ptcache_copy_list(ListBase *ptcaches_new,
const ListBase *ptcaches_old,
const int flag)
@@ -3170,6 +3124,7 @@ PointCache *BKE_ptcache_copy_list(ListBase *ptcaches_new,
* every user action changing stuff, and then it runs a complete bake??? (ton) */
/* Baking */
+
void BKE_ptcache_quick_cache_all(Main *bmain, Scene *scene, ViewLayer *view_layer)
{
PTCacheBaker baker;
@@ -3202,7 +3157,6 @@ static void ptcache_dt_to_str(char *str, double dtime)
}
}
-/* if bake is not given run simulations to current frame */
void BKE_ptcache_bake(PTCacheBaker *baker)
{
Scene *scene = baker->scene;
@@ -3439,7 +3393,9 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
/* TODO: call redraw all windows somehow */
}
+
/* Helpers */
+
void BKE_ptcache_disk_to_mem(PTCacheID *pid)
{
PointCache *cache = pid->cache;
@@ -3495,8 +3451,9 @@ void BKE_ptcache_toggle_disk_cache(PTCacheID *pid)
{
PointCache *cache = pid->cache;
int last_exact = cache->last_exact;
+ const char *blendfile_path = BKE_main_blendfile_path_from_global();
- if (!G.relbase_valid) {
+ if (blendfile_path[0] == '\0') {
cache->flag &= ~PTCACHE_DISK_CACHE;
if (G.debug & G_DEBUG) {
printf("File must be saved before using disk cache!\n");
diff --git a/source/blender/blenkernel/intern/pointcloud.cc b/source/blender/blenkernel/intern/pointcloud.cc
index 15c5a809118..82dde79cff6 100644
--- a/source/blender/blenkernel/intern/pointcloud.cc
+++ b/source/blender/blenkernel/intern/pointcloud.cc
@@ -79,7 +79,7 @@ static void pointcloud_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_s
{
PointCloud *pointcloud_dst = (PointCloud *)id_dst;
const PointCloud *pointcloud_src = (const PointCloud *)id_src;
- pointcloud_dst->mat = static_cast<Material **>(MEM_dupallocN(pointcloud_dst->mat));
+ pointcloud_dst->mat = static_cast<Material **>(MEM_dupallocN(pointcloud_src->mat));
const eCDAllocType alloc_type = (flag & LIB_ID_COPY_CD_REFERENCE) ? CD_REFERENCE : CD_DUPLICATE;
CustomData_copy(&pointcloud_src->pdata,
@@ -175,6 +175,7 @@ IDTypeInfo IDType_ID_PT = {
/* name_plural */ "pointclouds",
/* translation_context */ BLT_I18NCONTEXT_ID_POINTCLOUD,
/* flags */ IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ /* asset_type_info */ nullptr,
/* init_data */ pointcloud_init_data,
/* copy_data */ pointcloud_copy_data,
@@ -182,6 +183,7 @@ IDTypeInfo IDType_ID_PT = {
/* make_local */ nullptr,
/* foreach_id */ pointcloud_foreach_id,
/* foreach_cache */ nullptr,
+ /* foreach_path */ nullptr,
/* owner_get */ nullptr,
/* blend_write */ pointcloud_blend_write,
@@ -417,6 +419,7 @@ void BKE_pointcloud_data_update(struct Depsgraph *depsgraph, struct Scene *scene
}
/* Draw Cache */
+
void (*BKE_pointcloud_batch_cache_dirty_tag_cb)(PointCloud *pointcloud, int mode) = nullptr;
void (*BKE_pointcloud_batch_cache_free_cb)(PointCloud *pointcloud) = nullptr;
diff --git a/source/blender/blenkernel/intern/preferences.c b/source/blender/blenkernel/intern/preferences.c
index 41046563f98..4bb2231bbb1 100644
--- a/source/blender/blenkernel/intern/preferences.c
+++ b/source/blender/blenkernel/intern/preferences.c
@@ -62,10 +62,6 @@ bUserAssetLibrary *BKE_preferences_asset_library_add(UserDef *userdef,
return library;
}
-/**
- * Unlink and free a library preference member.
- * \note Free's \a library itself.
- */
void BKE_preferences_asset_library_remove(UserDef *userdef, bUserAssetLibrary *library)
{
BLI_freelinkN(&userdef->asset_libraries, library);
@@ -84,13 +80,9 @@ void BKE_preferences_asset_library_name_set(UserDef *userdef,
sizeof(library->name));
}
-/* Set the library path, ensuring it is pointing to a directory.
- * Single blend files can only act as "Current File" library; libraries on disk
- * should always be directories. If the path does not exist, that's fine; it can
- * created as directory if necessary later. */
void BKE_preferences_asset_library_path_set(bUserAssetLibrary *library, const char *path)
{
- BLI_strncpy_utf8(library->path, path, sizeof(library->path));
+ BLI_strncpy(library->path, path, sizeof(library->path));
if (BLI_is_file(library->path)) {
BLI_path_parent_dir(library->path);
}
diff --git a/source/blender/blenkernel/intern/report.c b/source/blender/blenkernel/intern/report.c
index 90e7ca3f11a..bc11861f2c8 100644
--- a/source/blender/blenkernel/intern/report.c
+++ b/source/blender/blenkernel/intern/report.c
@@ -76,11 +76,6 @@ void BKE_reports_init(ReportList *reports, int flag)
reports->flag = flag;
}
-/**
- * Only frees the list \a reports.
- * To make displayed reports disappear, either remove window-manager reports
- * (wmWindowManager.reports, or CTX_wm_reports()), or use #WM_report_banners_cancel().
- */
void BKE_reports_clear(ReportList *reports)
{
Report *report, *report_next;
diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c
index 4482285c271..75e9bc2fbee 100644
--- a/source/blender/blenkernel/intern/rigidbody.c
+++ b/source/blender/blenkernel/intern/rigidbody.c
@@ -103,7 +103,6 @@ static void RB_constraint_delete(void *UNUSED(con))
#endif
-/* Free rigidbody world */
void BKE_rigidbody_free_world(Scene *scene)
{
bool is_orig = (scene->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0;
@@ -160,7 +159,6 @@ void BKE_rigidbody_free_world(Scene *scene)
MEM_freeN(rbw);
}
-/* Free RigidBody settings and sim instances */
void BKE_rigidbody_free_object(Object *ob, RigidBodyWorld *rbw)
{
bool is_orig = (ob->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0;
@@ -208,7 +206,6 @@ void BKE_rigidbody_free_object(Object *ob, RigidBodyWorld *rbw)
ob->rigidbody_object = NULL;
}
-/* Free RigidBody constraint and sim instance */
void BKE_rigidbody_free_constraint(Object *ob)
{
RigidBodyCon *rbc = (ob) ? ob->rigidbody_constraint : NULL;
@@ -637,8 +634,6 @@ static void rigidbody_validate_sim_shape(RigidBodyWorld *rbw, Object *ob, bool r
/* --------------------- */
-/* helper function to calculate volume of rigidbody object */
-/* TODO: allow a parameter to specify method used to calculate this? */
void BKE_rigidbody_calc_volume(Object *ob, float *r_vol)
{
RigidBodyOb *rbo = ob->rigidbody_object;
@@ -1133,12 +1128,6 @@ static void rigidbody_validate_sim_constraint(RigidBodyWorld *rbw, Object *ob, b
/* --------------------- */
-/**
- * Create physics sim world given RigidBody world settings
- *
- * \note this does NOT update object references that the scene uses,
- * in case those aren't ready yet!
- */
void BKE_rigidbody_validate_sim_world(Scene *scene, RigidBodyWorld *rbw, bool rebuild)
{
/* sanity checks */
@@ -1161,7 +1150,6 @@ void BKE_rigidbody_validate_sim_world(Scene *scene, RigidBodyWorld *rbw, bool re
/* ************************************** */
/* Setup Utilities - Create Settings Blocks */
-/* Set up RigidBody world */
RigidBodyWorld *BKE_rigidbody_create_world(Scene *scene)
{
/* try to get whatever RigidBody world that might be representing this already */
@@ -1246,7 +1234,6 @@ void BKE_rigidbody_world_id_loop(RigidBodyWorld *rbw, RigidbodyWorldIDFunc func,
}
}
-/* Add rigid body settings to the specified object */
RigidBodyOb *BKE_rigidbody_create_object(Scene *scene, Object *ob, short type)
{
RigidBodyOb *rbo;
@@ -1309,7 +1296,6 @@ RigidBodyOb *BKE_rigidbody_create_object(Scene *scene, Object *ob, short type)
return rbo;
}
-/* Add rigid body constraint to the specified object */
RigidBodyCon *BKE_rigidbody_create_constraint(Scene *scene, Object *ob, short type)
{
RigidBodyCon *rbc;
@@ -1429,11 +1415,6 @@ void BKE_rigidbody_main_collection_object_add(Main *bmain, Collection *collectio
/* ************************************** */
/* Utilities API */
-/**
- * Get RigidBody world for the given scene, creating one if needed
- *
- * \param scene: Scene to find active Rigid Body world for.
- */
RigidBodyWorld *BKE_rigidbody_get_world(Scene *scene)
{
/* sanity check */
@@ -2058,7 +2039,6 @@ bool BKE_rigidbody_check_sim_running(RigidBodyWorld *rbw, float ctime)
return (rbw && (rbw->flag & RBW_FLAG_MUTED) == 0 && ctime > rbw->shared->pointcache->startframe);
}
-/* Sync rigid body and object transformations */
void BKE_rigidbody_sync_transforms(RigidBodyWorld *rbw, Object *ob, float ctime)
{
if (!BKE_rigidbody_is_affected_by_simulation(ob)) {
@@ -2089,7 +2069,6 @@ void BKE_rigidbody_sync_transforms(RigidBodyWorld *rbw, Object *ob, float ctime)
}
}
-/* Used when canceling transforms - return rigidbody and object to initial states */
void BKE_rigidbody_aftertrans_update(
Object *ob, float loc[3], float rot[3], float quat[4], float rotAxis[3], float rotAngle)
{
@@ -2168,8 +2147,6 @@ void BKE_rigidbody_cache_reset(RigidBodyWorld *rbw)
/* ------------------ */
-/* Rebuild rigid body world */
-/* NOTE: this needs to be called before frame update to work correctly */
void BKE_rigidbody_rebuild_world(Depsgraph *depsgraph, Scene *scene, float ctime)
{
RigidBodyWorld *rbw = scene->rigidbody_world;
@@ -2209,7 +2186,6 @@ void BKE_rigidbody_rebuild_world(Depsgraph *depsgraph, Scene *scene, float ctime
}
}
-/* Run RigidBody simulation for the specified physics world */
void BKE_rigidbody_do_simulation(Depsgraph *depsgraph, Scene *scene, float ctime)
{
RigidBodyWorld *rbw = scene->rigidbody_world;
@@ -2307,6 +2283,7 @@ void BKE_rigidbody_object_copy(Main *bmain, Object *ob_dst, const Object *ob_src
void BKE_rigidbody_validate_sim_world(Scene *scene, RigidBodyWorld *rbw, bool rebuild)
{
}
+
void BKE_rigidbody_calc_volume(Object *ob, float *r_vol)
{
if (r_vol) {
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index a0bd3abbc1a..916a2786a98 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -71,6 +71,7 @@
#include "BKE_anim_data.h"
#include "BKE_animsys.h"
#include "BKE_armature.h"
+#include "BKE_bpath.h"
#include "BKE_cachefile.h"
#include "BKE_collection.h"
#include "BKE_colortools.h"
@@ -891,6 +892,45 @@ static void scene_foreach_cache(ID *id,
user_data);
}
+static bool seq_foreach_path_callback(Sequence *seq, void *user_data)
+{
+ if (SEQ_HAS_PATH(seq)) {
+ StripElem *se = seq->strip->stripdata;
+ BPathForeachPathData *bpath_data = (BPathForeachPathData *)user_data;
+
+ if (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_SOUND_RAM) && se) {
+ BKE_bpath_foreach_path_dirfile_fixed_process(bpath_data, seq->strip->dir, se->name);
+ }
+ else if ((seq->type == SEQ_TYPE_IMAGE) && se) {
+ /* NOTE: An option not to loop over all strips could be useful? */
+ unsigned int len = (unsigned int)MEM_allocN_len(se) / (unsigned int)sizeof(*se);
+ unsigned int i;
+
+ if (bpath_data->flag & BKE_BPATH_FOREACH_PATH_SKIP_MULTIFILE) {
+ /* only operate on one path */
+ len = MIN2(1u, len);
+ }
+
+ for (i = 0; i < len; i++, se++) {
+ BKE_bpath_foreach_path_dirfile_fixed_process(bpath_data, seq->strip->dir, se->name);
+ }
+ }
+ else {
+ /* simple case */
+ BKE_bpath_foreach_path_fixed_process(bpath_data, seq->strip->dir);
+ }
+ }
+ return true;
+}
+
+static void scene_foreach_path(ID *id, BPathForeachPathData *bpath_data)
+{
+ Scene *scene = (Scene *)id;
+ if (scene->ed != NULL) {
+ SEQ_for_each_callback(&scene->ed->seqbase, seq_foreach_path_callback, bpath_data);
+ }
+}
+
static void scene_blend_write(BlendWriter *writer, ID *id, const void *id_address)
{
Scene *sce = (Scene *)id;
@@ -1600,6 +1640,7 @@ IDTypeInfo IDType_ID_SCE = {
.name_plural = "scenes",
.translation_context = BLT_I18NCONTEXT_ID_SCENE,
.flags = 0,
+ .asset_type_info = NULL,
.init_data = scene_init_data,
.copy_data = scene_copy_data,
@@ -1609,6 +1650,7 @@ IDTypeInfo IDType_ID_SCE = {
.make_local = NULL,
.foreach_id = scene_foreach_id,
.foreach_cache = scene_foreach_cache,
+ .foreach_path = scene_foreach_path,
.owner_get = NULL,
.blend_write = scene_blend_write,
@@ -1659,7 +1701,6 @@ static void remove_sequencer_fcurves(Scene *sce)
}
}
-/* flag -- copying options (see BKE_lib_id.h's LIB_ID_COPY_... flags for more). */
ToolSettings *BKE_toolsettings_copy(ToolSettings *toolsettings, const int flag)
{
if (toolsettings == NULL) {
@@ -1986,9 +2027,6 @@ Scene *BKE_scene_add(Main *bmain, const char *name)
return sce;
}
-/**
- * Check if there is any instance of the object in the scene
- */
bool BKE_scene_object_find(Scene *scene, Object *ob)
{
LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
@@ -2011,12 +2049,6 @@ Object *BKE_scene_object_find_by_name(const Scene *scene, const char *name)
return NULL;
}
-/**
- * Sets the active scene, mainly used when running in background mode
- * (`--scene` command line argument).
- * This is also called to set the scene directly, bypassing windowing code.
- * Otherwise #WM_window_set_active_scene is used when changing scenes by the user.
- */
void BKE_scene_set_background(Main *bmain, Scene *scene)
{
Object *ob;
@@ -2041,7 +2073,6 @@ void BKE_scene_set_background(Main *bmain, Scene *scene)
* (render code calls own animation updates). */
}
-/* called from creator_args.c */
Scene *BKE_scene_set_name(Main *bmain, const char *name)
{
Scene *sce = (Scene *)BKE_libblock_find_name(bmain, ID_SCE, name);
@@ -2055,8 +2086,6 @@ Scene *BKE_scene_set_name(Main *bmain, const char *name)
return NULL;
}
-/* Used by meta-balls, return *all* objects (including duplis)
- * existing in the scene (including scene's sets). */
int BKE_scene_base_iter_next(
Depsgraph *depsgraph, SceneBaseIter *iter, Scene **scene, int val, Base **base, Object **ob)
{
@@ -2281,8 +2310,6 @@ const char *BKE_scene_find_marker_name(const Scene *scene, int frame)
return NULL;
}
-/* return the current marker for this frame,
- * we can have more than 1 marker per frame, this just returns the first :/ */
const char *BKE_scene_find_last_marker_name(const Scene *scene, int frame)
{
const TimeMarker *marker, *best_marker = NULL;
@@ -2326,7 +2353,6 @@ void BKE_scene_remove_rigidbody_object(struct Main *bmain,
}
}
-/* checks for cycle, returns 1 if it's all OK */
bool BKE_scene_validate_setscene(Main *bmain, Scene *sce)
{
Scene *sce_iter;
@@ -2349,16 +2375,11 @@ bool BKE_scene_validate_setscene(Main *bmain, Scene *sce)
return true;
}
-/* Return fractional frame number taking into account subframes and time
- * remapping. This the time value used by animation, modifiers and physics
- * evaluation. */
float BKE_scene_ctime_get(const Scene *scene)
{
return BKE_scene_frame_to_ctime(scene, scene->r.cfra);
}
-/* Convert integer frame number to fractional frame number taking into account
- * subframes and time remapping. */
float BKE_scene_frame_to_ctime(const Scene *scene, const int frame)
{
float ctime = frame;
@@ -2368,13 +2389,11 @@ float BKE_scene_frame_to_ctime(const Scene *scene, const int frame)
return ctime;
}
-/* Get current fractional frame based on frame and subframe. */
float BKE_scene_frame_get(const Scene *scene)
{
return scene->r.cfra + scene->r.subframe;
}
-/* Set current frame and subframe based on a fractional frame. */
void BKE_scene_frame_set(Scene *scene, float frame)
{
double intpart;
@@ -2411,12 +2430,6 @@ TransformOrientationSlot *BKE_scene_orientation_slot_get_from_flag(Scene *scene,
return BKE_scene_orientation_slot_get(scene, slot_index);
}
-/**
- * Activate a transform orientation in a 3D view based on an enum value.
- *
- * \param orientation: If this is #V3D_ORIENT_CUSTOM or greater, the custom transform orientation
- * with index \a orientation - #V3D_ORIENT_CUSTOM gets activated.
- */
void BKE_scene_orientation_slot_set_index(TransformOrientationSlot *orient_slot, int orientation)
{
const bool is_custom = orientation >= V3D_ORIENT_CUSTOM;
@@ -2623,7 +2636,6 @@ void BKE_scene_graph_evaluated_ensure(Depsgraph *depsgraph, Main *bmain)
scene_graph_update_tagged(depsgraph, bmain, true);
}
-/* applies changes right away, does all sets too */
void BKE_scene_graph_update_for_newframe_ex(Depsgraph *depsgraph, const bool clear_recalc)
{
Scene *scene = DEG_get_input_scene(depsgraph);
@@ -2699,12 +2711,6 @@ void BKE_scene_graph_update_for_newframe(Depsgraph *depsgraph)
BKE_scene_graph_update_for_newframe_ex(depsgraph, true);
}
-/**
- * Ensures given scene/view_layer pair has a valid, up-to-date depsgraph.
- *
- * \warning Sets matching depsgraph as active,
- * so should only be called from the active editing context (usually, from operators).
- */
void BKE_scene_view_layer_graph_evaluated_ensure(Main *bmain, Scene *scene, ViewLayer *view_layer)
{
Depsgraph *depsgraph = BKE_scene_ensure_depsgraph(bmain, scene, view_layer);
@@ -2712,7 +2718,6 @@ void BKE_scene_view_layer_graph_evaluated_ensure(Main *bmain, Scene *scene, View
BKE_scene_graph_update_tagged(depsgraph, bmain);
}
-/* return default view */
SceneRenderView *BKE_scene_add_render_view(Scene *sce, const char *name)
{
SceneRenderView *srv;
@@ -2782,12 +2787,6 @@ int get_render_child_particle_number(const RenderData *r, int num, bool for_rend
return num;
}
-/**
- * Helper function for the SETLOOPER and SETLOOPER_VIEW_LAYER macros
- *
- * It iterates over the bases of the active layer and then the bases
- * of the active layer of the background (set) scenes recursively.
- */
Base *_setlooper_base_step(Scene **sce_iter, ViewLayer *view_layer, Base *base)
{
if (base && base->next) {
@@ -2852,7 +2851,6 @@ typedef enum eCyclesFeatureSet {
CYCLES_FEATURES_EXPERIMENTAL = 1,
} eCyclesFeatureSet;
-/* We cannot use const as RNA_id_pointer_create is not using a const ID. */
bool BKE_scene_uses_cycles_experimental_features(Scene *scene)
{
BLI_assert(BKE_scene_uses_cycles(scene));
@@ -2878,16 +2876,6 @@ void BKE_scene_base_flag_to_objects(ViewLayer *view_layer)
}
}
-/**
- * Synchronize object base flags
- *
- * This is usually handled by the depsgraph.
- * However, in rare occasions we need to use the latest object flags
- * before depsgraph is fully updated.
- *
- * It should (ideally) only run for copy-on-written objects since this is
- * runtime data generated per-viewlayer.
- */
void BKE_scene_object_base_flag_sync_from_base(Base *base)
{
Object *ob = base->object;
@@ -2960,10 +2948,6 @@ int BKE_render_preview_pixel_size(const RenderData *r)
return r->preview_pixel_size;
}
-/**
- * Apply the needed correction factor to value, based on unit_type
- * (only length-related are affected currently) and unit->scale_length.
- */
double BKE_scene_unit_scale(const UnitSettings *unit, const int unit_type, double value)
{
if (unit->system == USER_UNIT_NONE) {
@@ -3038,7 +3022,6 @@ bool BKE_scene_multiview_is_stereo3d(const RenderData *rd)
((srv[1]->viewflag & SCE_VIEW_DISABLE) == 0));
}
-/* return whether to render this SceneRenderView */
bool BKE_scene_multiview_is_render_view_active(const RenderData *rd, const SceneRenderView *srv)
{
if (srv == NULL) {
@@ -3065,7 +3048,6 @@ bool BKE_scene_multiview_is_render_view_active(const RenderData *rd, const Scene
return false;
}
-/* return true if viewname is the first or if the name is NULL or not found */
bool BKE_scene_multiview_is_render_view_first(const RenderData *rd, const char *viewname)
{
SceneRenderView *srv;
@@ -3087,7 +3069,6 @@ bool BKE_scene_multiview_is_render_view_first(const RenderData *rd, const char *
return true;
}
-/* return true if viewname is the last or if the name is NULL or not found */
bool BKE_scene_multiview_is_render_view_last(const RenderData *rd, const char *viewname)
{
SceneRenderView *srv;
@@ -3171,12 +3152,6 @@ void BKE_scene_multiview_filepath_get(SceneRenderView *srv, const char *filepath
BLI_path_suffix(r_filepath, FILE_MAX, srv->suffix, "");
}
-/**
- * When multiview is not used the filepath is as usual (e.g., `Image.jpg`).
- * When multiview is on, even if only one view is enabled the view is incorporated
- * into the file name (e.g., `Image_L.jpg`). That allows for the user to re-render
- * individual views.
- */
void BKE_scene_multiview_view_filepath_get(const RenderData *rd,
const char *filepath,
const char *viewname,
@@ -3564,10 +3539,6 @@ TransformOrientation *BKE_scene_transform_orientation_find(const Scene *scene, c
return BLI_findlink(&scene->transform_spaces, index);
}
-/**
- * \return the index that \a orientation has within \a scene's transform-orientation list
- * or -1 if not found.
- */
int BKE_scene_transform_orientation_get_index(const Scene *scene,
const TransformOrientation *orientation)
{
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index 6352e08ec4b..cd8493ee559 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -45,6 +45,7 @@
#include "DNA_view3d_types.h"
#include "DNA_workspace_types.h"
+#include "BLI_ghash.h"
#include "BLI_listbase.h"
#include "BLI_math_vector.h"
#include "BLI_mempool.h"
@@ -97,10 +98,6 @@ static void screen_foreach_id_dopesheet(LibraryForeachIDData *data, bDopeSheet *
}
}
-/**
- * Callback used by lib_query to walk over all ID usages (mimics `foreach_id` callback of
- * `IDTypeInfo` structure).
- */
void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area)
{
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, area->full, IDWALK_CB_NOP);
@@ -258,7 +255,6 @@ static void screen_blend_write(BlendWriter *writer, ID *id, const void *id_addre
BKE_screen_area_map_blend_write(writer, AREAMAP_FROM_SCREEN(screen));
}
-/* Cannot use IDTypeInfo callback yet, because of the return value. */
bool BKE_screen_blend_read_data(BlendDataReader *reader, bScreen *screen)
{
bool success = true;
@@ -304,6 +300,7 @@ IDTypeInfo IDType_ID_SCR = {
.name_plural = "screens",
.translation_context = BLT_I18NCONTEXT_ID_SCREEN,
.flags = IDTYPE_FLAGS_NO_COPY | IDTYPE_FLAGS_ONLY_APPEND | IDTYPE_FLAGS_NO_ANIMDATA,
+ .asset_type_info = NULL,
.init_data = NULL,
.copy_data = NULL,
@@ -311,6 +308,7 @@ IDTypeInfo IDType_ID_SCR = {
.make_local = NULL,
.foreach_id = screen_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = screen_blend_write,
@@ -502,39 +500,35 @@ ARegion *BKE_area_region_copy(const SpaceType *st, const ARegion *region)
return newar;
}
-/* from lb2 to lb1, lb1 is supposed to be freed */
-static void region_copylist(SpaceType *st, ListBase *lb1, ListBase *lb2)
+/* from lb_src to lb_dst, lb_dst is supposed to be freed */
+static void region_copylist(SpaceType *st, ListBase *lb_dst, ListBase *lb_src)
{
/* to be sure */
- BLI_listbase_clear(lb1);
+ BLI_listbase_clear(lb_dst);
- LISTBASE_FOREACH (ARegion *, region, lb2) {
+ LISTBASE_FOREACH (ARegion *, region, lb_src) {
ARegion *region_new = BKE_area_region_copy(st, region);
- BLI_addtail(lb1, region_new);
+ BLI_addtail(lb_dst, region_new);
}
}
-/* lb1 should be empty */
-void BKE_spacedata_copylist(ListBase *lb1, ListBase *lb2)
+void BKE_spacedata_copylist(ListBase *lb_dst, ListBase *lb_src)
{
- BLI_listbase_clear(lb1); /* to be sure */
+ BLI_listbase_clear(lb_dst); /* to be sure */
- LISTBASE_FOREACH (SpaceLink *, sl, lb2) {
+ LISTBASE_FOREACH (SpaceLink *, sl, lb_src) {
SpaceType *st = BKE_spacetype_from_id(sl->spacetype);
if (st && st->duplicate) {
SpaceLink *slnew = st->duplicate(sl);
- BLI_addtail(lb1, slnew);
+ BLI_addtail(lb_dst, slnew);
region_copylist(st, &slnew->regionbase, &sl->regionbase);
}
}
}
-/* facility to set locks for drawing to survive (render) threads accessing drawing data */
-/* lock can become bitflag too */
-/* should be replaced in future by better local data handling for threads */
void BKE_spacedata_draw_locks(bool set)
{
LISTBASE_FOREACH (SpaceType *, st, &spacetypes) {
@@ -549,10 +543,6 @@ void BKE_spacedata_draw_locks(bool set)
}
}
-/**
- * Version of #BKE_area_find_region_type that also works if \a slink
- * is not the active space of \a area.
- */
ARegion *BKE_spacedata_find_region_type(const SpaceLink *slink,
const ScrArea *area,
int region_type)
@@ -586,7 +576,6 @@ void BKE_spacedata_callback_id_remap_set(void (*func)(ScrArea *area, SpaceLink *
spacedata_id_remap_cb = func;
}
-/* UNUSED!!! */
void BKE_spacedata_id_unref(struct ScrArea *area, struct SpaceLink *sl, struct ID *id)
{
if (spacedata_id_remap_cb) {
@@ -650,7 +639,6 @@ void BKE_area_region_panels_free(ListBase *panels)
BLI_listbase_clear(panels);
}
-/* not region itself */
void BKE_area_region_free(SpaceType *st, ARegion *region)
{
if (st) {
@@ -684,13 +672,17 @@ void BKE_area_region_free(SpaceType *st, ARegion *region)
region_free_gizmomap_callback(region->gizmo_map);
}
+ if (region->runtime.block_name_map != NULL) {
+ BLI_ghash_free(region->runtime.block_name_map, NULL, NULL);
+ region->runtime.block_name_map = NULL;
+ }
+
BLI_freelistN(&region->ui_lists);
BLI_freelistN(&region->ui_previews);
BLI_freelistN(&region->panels_category);
BLI_freelistN(&region->panels_category_active);
}
-/* not area itself */
void BKE_screen_area_free(ScrArea *area)
{
SpaceType *st = BKE_spacetype_from_id(area->spacetype);
@@ -718,7 +710,6 @@ void BKE_screen_area_map_free(ScrAreaMap *area_map)
BLI_freelistN(&area_map->areabase);
}
-/** Free (or release) any data used by this screen (does not free the screen itself). */
void BKE_screen_free_data(bScreen *screen)
{
screen_free_data(&screen->id);
@@ -881,12 +872,6 @@ void BKE_screen_remove_unused_scrverts(bScreen *screen)
/* ***************** Utilities ********************** */
-/**
- * Find a region of type \a region_type in the currently active space of \a area.
- *
- * \note This does _not_ work if the region to look up is not in the active
- * space. Use #BKE_spacedata_find_region_type if that may be the case.
- */
ARegion *BKE_area_find_region_type(const ScrArea *area, int region_type)
{
if (area) {
@@ -931,9 +916,6 @@ ARegion *BKE_area_find_region_xy(ScrArea *area, const int regiontype, int x, int
return NULL;
}
-/**
- * \note This is only for screen level regions (typically menus/popups).
- */
ARegion *BKE_screen_find_region_xy(bScreen *screen, const int regiontype, int x, int y)
{
LISTBASE_FOREACH (ARegion *, region, &screen->regionbase) {
@@ -946,10 +928,6 @@ ARegion *BKE_screen_find_region_xy(bScreen *screen, const int regiontype, int x,
return NULL;
}
-/**
- * \note Ideally we can get the area from the context,
- * there are a few places however where this isn't practical.
- */
ScrArea *BKE_screen_find_area_from_space(struct bScreen *screen, SpaceLink *sl)
{
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
@@ -961,10 +939,6 @@ ScrArea *BKE_screen_find_area_from_space(struct bScreen *screen, SpaceLink *sl)
return NULL;
}
-/**
- * \note Using this function is generally a last resort, you really want to be
- * using the context when you can - campbell
- */
ScrArea *BKE_screen_find_big_area(bScreen *screen, const int spacetype, const short min)
{
ScrArea *big = NULL;
@@ -1054,14 +1028,11 @@ ARegion *BKE_screen_find_main_region_at_xy(bScreen *screen,
return BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, x, y);
}
-/* magic zoom calculation, no idea what
- * it signifies, if you find out, tell me! -zr
- */
+/* Magic zoom calculation, no idea what it signifies, if you find out, tell me! -zr
+ *
+ * Simple, its magic dude! Well, to be honest,
+ * this gives a natural feeling zooming with multiple keypad presses (ton). */
-/* simple, its magic dude!
- * well, to be honest, this gives a natural feeling zooming
- * with multiple keypad presses (ton)
- */
float BKE_screen_view3d_zoom_to_fac(float camzoom)
{
return powf(((float)M_SQRT2 + camzoom / 50.0f), 2.0f) / 4.0f;
@@ -1476,7 +1447,6 @@ static void direct_link_region(BlendDataReader *reader, ARegion *region, int spa
}
/* for the saved 2.50 files without regiondata */
-/* and as patch for 2.48 and older */
void BKE_screen_view3d_do_versions_250(View3D *v3d, ListBase *regions)
{
LISTBASE_FOREACH (ARegion *, region, regions) {
@@ -1783,9 +1753,6 @@ static void direct_link_area(BlendDataReader *reader, ScrArea *area)
BLO_read_data_address(reader, &area->v4);
}
-/**
- * \return false on error.
- */
bool BKE_screen_area_map_blend_read_data(BlendDataReader *reader, ScrAreaMap *area_map)
{
BLO_read_list(reader, &area_map->vertbase);
diff --git a/source/blender/blenkernel/intern/shader_fx.c b/source/blender/blenkernel/intern/shader_fx.c
index 12017907038..a0d67a78d0f 100644
--- a/source/blender/blenkernel/intern/shader_fx.c
+++ b/source/blender/blenkernel/intern/shader_fx.c
@@ -57,7 +57,6 @@ static ShaderFxTypeInfo *shader_fx_types[NUM_SHADER_FX_TYPES] = {NULL};
/* *************************************************** */
/* Methods - Evaluation Loops, etc. */
-/* check if exist grease pencil effects */
bool BKE_shaderfx_has_gpencil(const Object *ob)
{
const ShaderFxData *fx;
@@ -136,7 +135,6 @@ void BKE_shaderfx_free(ShaderFxData *fx)
BKE_shaderfx_free_ex(fx, 0);
}
-/* check unique name */
bool BKE_shaderfx_unique_name(ListBase *shaders, ShaderFxData *fx)
{
if (shaders && fx) {
@@ -164,24 +162,12 @@ const ShaderFxTypeInfo *BKE_shaderfx_get_info(ShaderFxType type)
return NULL;
}
-/**
- * Check whether given shaderfx is not local (i.e. from linked data) when the object is a library
- * override.
- *
- * \param shaderfx: May be NULL, in which case we consider it as a non-local shaderfx case.
- */
bool BKE_shaderfx_is_nonlocal_in_liboverride(const Object *ob, const ShaderFxData *shaderfx)
{
return (ID_IS_OVERRIDE_LIBRARY(ob) &&
((shaderfx == NULL) || (shaderfx->flag & eShaderFxFlag_OverrideLibrary_Local) == 0));
}
-/**
- * Get an effect's panel type, which was defined in the #panelRegister callback.
- *
- * \note ShaderFx panel types are assumed to be named with the struct name field concatenated to
- * the defined prefix.
- */
void BKE_shaderfxType_panel_id(ShaderFxType type, char *r_idname)
{
const ShaderFxTypeInfo *fxi = BKE_shaderfx_get_info(type);
diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c
index dd863f1ce06..7618323f488 100644
--- a/source/blender/blenkernel/intern/shrinkwrap.c
+++ b/source/blender/blenkernel/intern/shrinkwrap.c
@@ -28,6 +28,7 @@
#include <string.h>
#include <time.h>
+#include "DNA_gpencil_modifier_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
@@ -101,7 +102,6 @@ typedef struct ShrinkwrapCalcCBData {
SpaceTransform *local2aux;
} ShrinkwrapCalcCBData;
-/* Checks if the modifier needs target normals with these settings. */
bool BKE_shrinkwrap_needs_normals(int shrinkType, int shrinkMode)
{
return (shrinkType == MOD_SHRINKWRAP_TARGET_PROJECT) ||
@@ -109,7 +109,6 @@ bool BKE_shrinkwrap_needs_normals(int shrinkType, int shrinkMode)
shrinkMode == MOD_SHRINKWRAP_ABOVE_SURFACE);
}
-/* Initializes the mesh data structure from the given mesh and settings. */
bool BKE_shrinkwrap_init_tree(
ShrinkwrapTreeData *data, Mesh *mesh, int shrinkType, int shrinkMode, bool force_normals)
{
@@ -160,13 +159,11 @@ bool BKE_shrinkwrap_init_tree(
return true;
}
-/* Frees the tree data if necessary. */
void BKE_shrinkwrap_free_tree(ShrinkwrapTreeData *data)
{
free_bvhtree_from_mesh(&data->treeData);
}
-/* Free boundary data for target project */
void BKE_shrinkwrap_discard_boundary_data(struct Mesh *mesh)
{
struct ShrinkwrapBoundaryData *data = mesh->runtime.shrinkwrap_data;
@@ -434,14 +431,6 @@ static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc)
0, calc->numVerts, &data, shrinkwrap_calc_nearest_vertex_cb_ex, &settings);
}
-/*
- * This function raycast a single vertex and updates the hit if the "hit" is considered valid.
- * Returns true if "hit" was updated.
- * Opts control whether an hit is valid or not
- * Supported options are:
- * - MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE (front faces hits are ignored)
- * - MOD_SHRINKWRAP_CULL_TARGET_BACKFACE (back faces hits are ignored)
- */
bool BKE_shrinkwrap_project_normal(char options,
const float vert[3],
const float dir[3],
@@ -1089,9 +1078,6 @@ static void mesh_looptri_target_project(void *userdata,
}
}
-/*
- * Maps the point to the nearest surface, either by simple nearest, or by target normal projection.
- */
void BKE_shrinkwrap_find_nearest_surface(struct ShrinkwrapTreeData *tree,
BVHTreeNearest *nearest,
float co[3],
@@ -1196,13 +1182,6 @@ static void shrinkwrap_calc_nearest_surface_point_cb_ex(void *__restrict userdat
}
}
-/**
- * Compute a smooth normal of the target (if applicable) at the hit location.
- *
- * \param tree: information about the mesh
- * \param transform: transform from the hit coordinate space to the object space; may be null
- * \param r_no: output in hit coordinate space; may be shared with inputs
- */
void BKE_shrinkwrap_compute_smooth_normal(const struct ShrinkwrapTreeData *tree,
const struct SpaceTransform *transform,
int looptri_idx,
@@ -1318,13 +1297,6 @@ static void shrinkwrap_snap_with_side(float r_point_co[3],
}
}
-/**
- * Apply the shrink to surface modes to the given original coordinates and nearest point.
- *
- * \param tree: mesh data for smooth normals
- * \param transform: transform from the hit coordinate space to the object space; may be null
- * \param r_point_co: may be the same memory location as point_co, hit_co, or hit_no.
- */
void BKE_shrinkwrap_snap_point_to_surface(const struct ShrinkwrapTreeData *tree,
const struct SpaceTransform *transform,
int mode,
@@ -1404,7 +1376,6 @@ static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc)
0, calc->numVerts, &data, shrinkwrap_calc_nearest_surface_point_cb_ex, &settings);
}
-/* Main shrinkwrap function */
void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd,
const ModifierEvalContext *ctx,
struct Scene *scene,
@@ -1513,6 +1484,55 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd,
}
}
+void shrinkwrapGpencilModifier_deform(ShrinkwrapGpencilModifierData *mmd,
+ Object *ob,
+ MDeformVert *dvert,
+ const int defgrp_index,
+ float (*vertexCos)[3],
+ int numVerts)
+{
+
+ ShrinkwrapCalcData calc = NULL_ShrinkwrapCalcData;
+ /* Convert gpencil struct to use the same struct and function used with meshes. */
+ ShrinkwrapModifierData smd;
+ smd.target = mmd->target;
+ smd.auxTarget = mmd->aux_target;
+ smd.keepDist = mmd->keep_dist;
+ smd.shrinkType = mmd->shrink_type;
+ smd.shrinkOpts = mmd->shrink_opts;
+ smd.shrinkMode = mmd->shrink_mode;
+ smd.projLimit = mmd->proj_limit;
+ smd.projAxis = mmd->proj_axis;
+
+ /* Configure Shrinkwrap calc data. */
+ calc.smd = &smd;
+ calc.ob = ob;
+ calc.numVerts = numVerts;
+ calc.vertexCos = vertexCos;
+ calc.dvert = dvert;
+ calc.vgroup = defgrp_index;
+ calc.invert_vgroup = (mmd->flag & GP_SHRINKWRAP_INVERT_VGROUP) != 0;
+
+ BLI_SPACE_TRANSFORM_SETUP(&calc.local2target, ob, mmd->target);
+ calc.keepDist = mmd->keep_dist;
+ calc.tree = mmd->cache_data;
+
+ switch (mmd->shrink_type) {
+ case MOD_SHRINKWRAP_NEAREST_SURFACE:
+ case MOD_SHRINKWRAP_TARGET_PROJECT:
+ TIMEIT_BENCH(shrinkwrap_calc_nearest_surface_point(&calc), gpdeform_surface);
+ break;
+
+ case MOD_SHRINKWRAP_PROJECT:
+ TIMEIT_BENCH(shrinkwrap_calc_normal_projection(&calc), gpdeform_project);
+ break;
+
+ case MOD_SHRINKWRAP_NEAREST_VERTEX:
+ TIMEIT_BENCH(shrinkwrap_calc_nearest_vertex(&calc), gpdeform_vertex);
+ break;
+ }
+}
+
void BKE_shrinkwrap_mesh_nearest_surface_deform(struct bContext *C,
Object *ob_source,
Object *ob_target)
diff --git a/source/blender/blenkernel/intern/simulation.cc b/source/blender/blenkernel/intern/simulation.cc
index 98e7405bde6..b0f9de5963a 100644
--- a/source/blender/blenkernel/intern/simulation.cc
+++ b/source/blender/blenkernel/intern/simulation.cc
@@ -154,6 +154,7 @@ IDTypeInfo IDType_ID_SIM = {
/* name_plural */ "simulations",
/* translation_context */ BLT_I18NCONTEXT_ID_SIMULATION,
/* flags */ IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ /* asset_type_info */ nullptr,
/* init_data */ simulation_init_data,
/* copy_data */ simulation_copy_data,
@@ -161,6 +162,7 @@ IDTypeInfo IDType_ID_SIM = {
/* make_local */ nullptr,
/* foreach_id */ simulation_foreach_id,
/* foreach_cache */ nullptr,
+ /* foreach_path */ nullptr,
/* owner_get */ nullptr,
/* blend_write */ simulation_blend_write,
diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c
index a008edd038a..b811c17a3bc 100644
--- a/source/blender/blenkernel/intern/softbody.c
+++ b/source/blender/blenkernel/intern/softbody.c
@@ -3112,7 +3112,6 @@ static void sb_new_scratch(SoftBody *sb)
/* ************ Object level, exported functions *************** */
-/* allocates and initializes general main data */
SoftBody *sbNew(void)
{
SoftBody *sb;
@@ -3162,7 +3161,6 @@ SoftBody *sbNew(void)
return sb;
}
-/* frees all */
void sbFree(Object *ob)
{
SoftBody *sb = ob->soft;
@@ -3193,7 +3191,6 @@ void sbFreeSimulation(SoftBody *sb)
free_softbody_intern(sb);
}
-/* makes totally fresh start situation */
void sbObjectToSoftbody(Object *ob)
{
// ob->softflag |= OB_SB_REDO;
@@ -3213,7 +3210,6 @@ static bool object_has_edges(const Object *ob)
return false;
}
-/* SB global visible functions */
void sbSetInterruptCallBack(int (*f)(void))
{
SB_localInterruptCallBack = f;
@@ -3244,20 +3240,6 @@ static void softbody_update_positions(Object *ob,
}
}
-/* void SB_estimate_transform */
-/* input Object *ob out (says any object that can do SB like mesh, lattice, curve )
- * output float lloc[3], float lrot[3][3], float lscale[3][3]
- * that is:
- * a precise position vector denoting the motion of the center of mass
- * give a rotation/scale matrix using averaging method, that's why estimate and not calculate
- * see: this is kind of reverse engineering: having to states of a point cloud and recover what
- * happened our advantage here we know the identity of the vertex there are others methods giving
- * other results. lloc, lrot, lscale are allowed to be NULL, just in case you don't need it.
- * should be pretty useful for pythoneers :)
- * not! velocity .. 2nd order stuff
- * vcloud_estimate_transform_v3 see
- */
-
void SB_estimate_transform(Object *ob, float lloc[3], float lrot[3][3], float lscale[3][3])
{
BodyPoint *bp;
@@ -3523,7 +3505,6 @@ static void sbStoreLastFrame(struct Depsgraph *depsgraph, Object *object, float
object_orig->soft->last_frame = framenr;
}
-/* simulates one step. framenr is in frames */
void sbObjectStep(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob,
diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c
index f523c5e02bd..b27231e6a17 100644
--- a/source/blender/blenkernel/intern/sound.c
+++ b/source/blender/blenkernel/intern/sound.c
@@ -54,6 +54,7 @@
# include <AUD_Special.h>
#endif
+#include "BKE_bpath.h"
#include "BKE_global.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
@@ -133,6 +134,17 @@ static void sound_foreach_cache(ID *id,
function_callback(id, &key, &sound->waveform, 0, user_data);
}
+static void sound_foreach_path(ID *id, BPathForeachPathData *bpath_data)
+{
+ bSound *sound = (bSound *)id;
+ if (sound->packedfile != NULL && (bpath_data->flag & BKE_BPATH_FOREACH_PATH_SKIP_PACKED) != 0) {
+ return;
+ }
+
+ /* FIXME: This does not check for empty path... */
+ BKE_bpath_foreach_path_fixed_process(bpath_data, sound->filepath);
+}
+
static void sound_blend_write(BlendWriter *writer, ID *id, const void *id_address)
{
bSound *sound = (bSound *)id;
@@ -205,6 +217,7 @@ IDTypeInfo IDType_ID_SO = {
.name_plural = "sounds",
.translation_context = BLT_I18NCONTEXT_ID_SOUND,
.flags = IDTYPE_FLAGS_NO_ANIMDATA | IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
/* A fuzzy case, think NULLified content is OK here... */
.init_data = NULL,
@@ -213,6 +226,7 @@ IDTypeInfo IDType_ID_SO = {
.make_local = NULL,
.foreach_id = NULL,
.foreach_cache = sound_foreach_cache,
+ .foreach_path = sound_foreach_path,
.owner_get = NULL,
.blend_write = sound_blend_write,
@@ -257,14 +271,11 @@ BLI_INLINE void sound_verify_evaluated_id(const ID *id)
bSound *BKE_sound_new_file(Main *bmain, const char *filepath)
{
bSound *sound;
- const char *path;
+ const char *blendfile_path = BKE_main_blendfile_path(bmain);
char str[FILE_MAX];
BLI_strncpy(str, filepath, sizeof(str));
-
- path = BKE_main_blendfile_path(bmain);
-
- BLI_path_abs(str, path);
+ BLI_path_abs(str, blendfile_path);
sound = BKE_libblock_alloc(bmain, ID_SO, BLI_path_basename(filepath), 0);
BLI_strncpy(sound->filepath, filepath, FILE_MAX);
@@ -1235,15 +1246,14 @@ bool BKE_sound_stream_info_get(struct Main *main,
int stream,
SoundStreamInfo *sound_info)
{
- const char *path;
+ const char *blendfile_path = BKE_main_blendfile_path(main);
char str[FILE_MAX];
AUD_Sound *sound;
AUD_StreamInfo *stream_infos;
int stream_count;
BLI_strncpy(str, filepath, sizeof(str));
- path = BKE_main_blendfile_path(main);
- BLI_path_abs(str, path);
+ BLI_path_abs(str, blendfile_path);
sound = AUD_Sound_file(str);
if (!sound) {
diff --git a/source/blender/blenkernel/intern/speaker.c b/source/blender/blenkernel/intern/speaker.c
index 230ff9d6da0..b7199dc1e20 100644
--- a/source/blender/blenkernel/intern/speaker.c
+++ b/source/blender/blenkernel/intern/speaker.c
@@ -99,6 +99,7 @@ IDTypeInfo IDType_ID_SPK = {
.name_plural = "speakers",
.translation_context = BLT_I18NCONTEXT_ID_SPEAKER,
.flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = speaker_init_data,
.copy_data = NULL,
@@ -106,6 +107,7 @@ IDTypeInfo IDType_ID_SPK = {
.make_local = NULL,
.foreach_id = speaker_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = speaker_blend_write,
diff --git a/source/blender/blenkernel/intern/spline_base.cc b/source/blender/blenkernel/intern/spline_base.cc
index 52bbd2bec57..4ff392a5ddb 100644
--- a/source/blender/blenkernel/intern/spline_base.cc
+++ b/source/blender/blenkernel/intern/spline_base.cc
@@ -62,9 +62,6 @@ static SplinePtr create_spline(const Spline::Type type)
return {};
}
-/**
- * Return a new spline with the same data, settings, and attributes.
- */
SplinePtr Spline::copy() const
{
SplinePtr dst = this->copy_without_attributes();
@@ -72,9 +69,6 @@ SplinePtr Spline::copy() const
return dst;
}
-/**
- * Return a new spline with the same type and settings like "cyclic", but without any data.
- */
SplinePtr Spline::copy_only_settings() const
{
SplinePtr dst = create_spline(type_);
@@ -83,9 +77,6 @@ SplinePtr Spline::copy_only_settings() const
return dst;
}
-/**
- * The same as #copy, but skips copying dynamic attributes to the new spline.
- */
SplinePtr Spline::copy_without_attributes() const
{
SplinePtr dst = this->copy_only_settings();
@@ -185,12 +176,6 @@ static void accumulate_lengths(Span<float3> positions,
}
}
-/**
- * Return non-owning access to the cache of accumulated lengths along the spline. Each item is the
- * length of the subsequent segment, i.e. the first value is the length of the first segment rather
- * than 0. This calculation is rather trivial, and only depends on the evaluated positions.
- * However, the results are used often, and it is necessarily single threaded, so it is cached.
- */
Span<float> Spline::evaluated_lengths() const
{
if (!length_cache_dirty_) {
@@ -252,9 +237,6 @@ static void calculate_tangents(Span<float3> positions,
}
}
-/**
- * Return non-owning access to the direction of the curve at each evaluated point.
- */
Span<float3> Spline::evaluated_tangents() const
{
if (!tangent_cache_dirty_) {
@@ -375,10 +357,6 @@ static void calculate_normals_minimum(Span<float3> tangents,
}
}
-/**
- * Return non-owning access to the direction vectors perpendicular to the tangents at every
- * evaluated point. The method used to generate the normal vectors depends on Spline.normal_mode.
- */
Span<float3> Spline::evaluated_normals() const
{
if (!normal_cache_dirty_) {
@@ -428,9 +406,6 @@ Spline::LookupResult Spline::lookup_evaluated_factor(const float factor) const
return this->lookup_evaluated_length(this->length() * factor);
}
-/**
- * \note This does not support extrapolation currently.
- */
Spline::LookupResult Spline::lookup_evaluated_length(const float length) const
{
BLI_assert(length >= 0.0f && length <= this->length());
@@ -447,11 +422,6 @@ Spline::LookupResult Spline::lookup_evaluated_length(const float length) const
return LookupResult{index, next_index, factor};
}
-/**
- * Return an array of evenly spaced samples along the length of the spline. The samples are indices
- * and factors to the next index encoded in floats. The logic for converting from the float values
- * to interpolation data is in #lookup_data_from_index_factor.
- */
Array<float> Spline::sample_uniform_index_factors(const int samples_size) const
{
const Span<float> lengths = this->evaluated_lengths();
@@ -532,11 +502,6 @@ GVArray Spline::interpolate_to_evaluated(GSpan data) const
return this->interpolate_to_evaluated(GVArray::ForSpan(data));
}
-/**
- * Sample any input data with a value for each evaluated point (already interpolated to evaluated
- * points) to arbitrary parameters in between the evaluated points. The interpolation is quite
- * simple, but this handles the cyclic and end point special cases.
- */
void Spline::sample_with_index_factors(const GVArray &src,
Span<float> index_factors,
GMutableSpan dst) const
diff --git a/source/blender/blenkernel/intern/spline_bezier.cc b/source/blender/blenkernel/intern/spline_bezier.cc
index 0cadab998f5..9ce285cebb8 100644
--- a/source/blender/blenkernel/intern/spline_bezier.cc
+++ b/source/blender/blenkernel/intern/spline_bezier.cc
@@ -70,9 +70,6 @@ void BezierSpline::set_resolution(const int value)
this->mark_cache_invalid();
}
-/**
- * \warning Call #reallocate on the spline's attributes after adding all points.
- */
void BezierSpline::add_point(const float3 position,
const HandleType handle_type_left,
const float3 handle_position_left,
@@ -203,10 +200,6 @@ static float3 next_position(Span<float3> positions, const bool cyclic, const int
return positions[i + 1];
}
-/**
- * Recalculate all #Auto and #Vector handles with positions automatically
- * derived from the neighboring control points.
- */
void BezierSpline::ensure_auto_handles() const
{
if (!auto_handles_dirty_) {
@@ -315,10 +308,6 @@ static void set_handle_position(const float3 &position,
}
}
-/**
- * Set positions for the right handle of the control point, ensuring that
- * aligned handles stay aligned. Has no effect for auto and vector type handles.
- */
void BezierSpline::set_handle_position_right(const int index, const blender::float3 &value)
{
set_handle_position(positions_[index],
@@ -329,10 +318,6 @@ void BezierSpline::set_handle_position_right(const int index, const blender::flo
handle_positions_left_[index]);
}
-/**
- * Set positions for the left handle of the control point, ensuring that
- * aligned handles stay aligned. Has no effect for auto and vector type handles.
- */
void BezierSpline::set_handle_position_left(const int index, const blender::float3 &value)
{
set_handle_position(positions_[index],
@@ -349,9 +334,6 @@ bool BezierSpline::point_is_sharp(const int index) const
ELEM(handle_types_right_[index], HandleType::Vector, HandleType::Free);
}
-/**
- * \warning This functional assumes that the spline has more than one point.
- */
bool BezierSpline::segment_is_vector(const int index) const
{
/* Two control points are necessary to form a segment, that should be checked by the caller. */
@@ -387,12 +369,6 @@ int BezierSpline::evaluated_points_size() const
return this->control_point_offsets().last();
}
-/**
- * If the spline is not cyclic, the direction for the first and last points is just the
- * direction formed by the corresponding handles and control points. In the unlikely situation
- * that the handles define a zero direction, fallback to using the direction defined by the
- * first and last evaluated segments already calculated in #Spline::evaluated_tangents().
- */
void BezierSpline::correct_end_tangents() const
{
if (is_cyclic_) {
@@ -409,25 +385,6 @@ void BezierSpline::correct_end_tangents() const
}
}
-/**
- * De Casteljau Bezier subdivision.
- * \param index: The index of the segment's start control point.
- * \param next_index: The index of the control point at the end of the segment. Could be 0,
- * if the spline is cyclic.
- * \param parameter: The factor along the segment, between 0 and 1. Note that this is used
- * directly by the calculation, it doesn't correspond to a portion of the evaluated length.
- *
- * <pre>
- * handle_prev handle_next
- * x----------------x
- * / \
- * / x---O---x \
- * / result \
- * / \
- * O O
- * point_prev point_next
- * </pre>
- */
BezierSpline::InsertResult BezierSpline::calculate_segment_insertion(const int index,
const int next_index,
const float parameter)
@@ -493,15 +450,6 @@ void BezierSpline::evaluate_segment(const int index,
}
}
-/**
- * Returns access to a cache of offsets into the evaluated point array for each control point.
- * While most control point edges generate the number of edges specified by the resolution, vector
- * segments only generate one edge.
- *
- * \note The length of the result is one greater than the number of points, so that the last item
- * is the total number of evaluated points. This is useful to avoid recalculating the size of the
- * last segment everywhere.
- */
Span<int> BezierSpline::control_point_offsets() const
{
if (!offset_cache_dirty_) {
@@ -568,12 +516,6 @@ static void calculate_mappings_linear_resolution(Span<int> offsets,
}
}
-/**
- * Returns non-owning access to an array of values containing the information necessary to
- * interpolate values from the original control points to evaluated points. The control point
- * index is the integer part of each value, and the factor used for interpolating to the next
- * control point is the remaining factional part.
- */
Span<float> BezierSpline::evaluated_mappings() const
{
if (!mapping_cache_dirty_) {
@@ -659,11 +601,6 @@ Span<float3> BezierSpline::evaluated_positions() const
return positions;
}
-/**
- * Convert the data encoded in #evaulated_mappings into its parts-- the information necessary
- * to interpolate data from control points to evaluated points between them. The next control
- * point index result will not overflow the size of the control point vectors.
- */
BezierSpline::InterpolationData BezierSpline::interpolation_data_from_index_factor(
const float index_factor) const
{
diff --git a/source/blender/blenkernel/intern/spline_nurbs.cc b/source/blender/blenkernel/intern/spline_nurbs.cc
index 7fa332a0330..69afb82baa8 100644
--- a/source/blender/blenkernel/intern/spline_nurbs.cc
+++ b/source/blender/blenkernel/intern/spline_nurbs.cc
@@ -81,9 +81,6 @@ void NURBSpline::set_order(const uint8_t value)
this->mark_cache_invalid();
}
-/**
- * \warning Call #reallocate on the spline's attributes after adding all points.
- */
void NURBSpline::add_point(const float3 position,
const float radius,
const float tilt,
diff --git a/source/blender/blenkernel/intern/spline_poly.cc b/source/blender/blenkernel/intern/spline_poly.cc
index d495c977285..4af68b5f270 100644
--- a/source/blender/blenkernel/intern/spline_poly.cc
+++ b/source/blender/blenkernel/intern/spline_poly.cc
@@ -45,9 +45,6 @@ int PolySpline::size() const
return size;
}
-/**
- * \warning Call #reallocate on the spline's attributes after adding all points.
- */
void PolySpline::add_point(const float3 position, const float radius, const float tilt)
{
positions_.append(position);
@@ -115,12 +112,6 @@ Span<float3> PolySpline::evaluated_positions() const
return this->positions();
}
-/**
- * Poly spline interpolation from control points to evaluated points is a special case, since
- * the result data is the same as the input data. This function returns a GVArray that points to
- * the original data. Therefore the lifetime of the returned virtual array must not be longer than
- * the source data.
- */
GVArray PolySpline::interpolate_to_evaluated(const GVArray &src) const
{
BLI_assert(src.size() == this->size());
diff --git a/source/blender/blenkernel/intern/studiolight.c b/source/blender/blenkernel/intern/studiolight.c
index 29f726ece71..b7690e69aa1 100644
--- a/source/blender/blenkernel/intern/studiolight.c
+++ b/source/blender/blenkernel/intern/studiolight.c
@@ -1402,7 +1402,6 @@ void BKE_studiolight_default(SolidLight lights[4], float light_ambient[3])
lights[3].vec[2] = -0.542269f;
}
-/* API */
void BKE_studiolight_init(void)
{
/* Add default studio light */
@@ -1532,7 +1531,6 @@ void BKE_studiolight_preview(uint *icon_buffer, StudioLight *sl, int icon_id_typ
}
}
-/* Ensure state of Studiolights */
void BKE_studiolight_ensure_flag(StudioLight *sl, int flag)
{
if ((sl->flag & flag) == flag) {
@@ -1570,8 +1568,9 @@ void BKE_studiolight_ensure_flag(StudioLight *sl, int flag)
}
/*
- * Python API Functions
+ * Python API Functions.
*/
+
void BKE_studiolight_remove(StudioLight *sl)
{
if (sl->flag & STUDIOLIGHT_USER_DEFINED) {
@@ -1608,7 +1607,6 @@ StudioLight *BKE_studiolight_create(const char *path,
return sl;
}
-/* Only useful for workbench while editing the userprefs. */
StudioLight *BKE_studiolight_studio_edit_get(void)
{
static StudioLight sl = {0};
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index 6796b1ac397..2669da98488 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -717,7 +717,6 @@ static void minmax_v3_v3v3(const float vec[3], float min[3], float max[3])
}
}
-/* UNUSED, keep since this functionality may be useful in the future. */
static void UNUSED_FUNCTION(ccgDM_getMinMax)(DerivedMesh *dm, float r_min[3], float r_max[3])
{
CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
@@ -912,8 +911,6 @@ static void ccgDM_getFinalVertNo(DerivedMesh *dm, int vertNum, float r_no[3])
normal_short_to_float_v3(r_no, mvert.no);
}
-/* Translate GridHidden into the ME_HIDE flag for MVerts. Assumes
- * vertices are in the order output by ccgDM_copyFinalVertArray. */
void subsurf_copy_grid_hidden(DerivedMesh *dm,
const MPoly *mpoly,
MVert *mvert,
@@ -955,8 +952,6 @@ void subsurf_copy_grid_hidden(DerivedMesh *dm,
}
}
-/* Translate GridPaintMask into vertex paint masks. Assumes vertices
- * are in the order output by ccgDM_copyFinalVertArray. */
void subsurf_copy_grid_paint_mask(DerivedMesh *dm,
const MPoly *mpoly,
float *paint_mask,
diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c
index 7ac9e20d1a7..4406647bd2c 100644
--- a/source/blender/blenkernel/intern/text.c
+++ b/source/blender/blenkernel/intern/text.c
@@ -49,6 +49,7 @@
#include "DNA_text_types.h"
#include "DNA_userdef_types.h"
+#include "BKE_bpath.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
@@ -169,6 +170,15 @@ static void text_free_data(ID *id)
#endif
}
+static void text_foreach_path(ID *id, BPathForeachPathData *bpath_data)
+{
+ Text *text = (Text *)id;
+
+ if (text->filepath != NULL) {
+ BKE_bpath_foreach_path_allocated_process(bpath_data, &text->filepath);
+ }
+}
+
static void text_blend_write(BlendWriter *writer, ID *id, const void *id_address)
{
Text *text = (Text *)id;
@@ -242,6 +252,7 @@ IDTypeInfo IDType_ID_TXT = {
.name_plural = "texts",
.translation_context = BLT_I18NCONTEXT_ID_TEXT,
.flags = IDTYPE_FLAGS_NO_ANIMDATA | IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = text_init_data,
.copy_data = text_copy_data,
@@ -249,6 +260,7 @@ IDTypeInfo IDType_ID_TXT = {
.make_local = NULL,
.foreach_id = NULL,
.foreach_cache = NULL,
+ .foreach_path = text_foreach_path,
.owner_get = NULL,
.blend_write = text_blend_write,
@@ -267,9 +279,6 @@ IDTypeInfo IDType_ID_TXT = {
/** \name Text Add, Free, Validation
* \{ */
-/**
- * \note caller must handle `compiled` member.
- */
void BKE_text_free_lines(Text *text)
{
for (TextLine *tmp = text->lines.first, *tmp_next; tmp; tmp = tmp_next) {
@@ -299,8 +308,6 @@ Text *BKE_text_add(Main *bmain, const char *name)
return ta;
}
-/* this function replaces extended ascii characters */
-/* to a valid utf-8 sequences */
int txt_extended_ascii_as_utf8(char **str)
{
ptrdiff_t bad_char, i = 0;
@@ -463,14 +470,6 @@ bool BKE_text_reload(Text *text)
return true;
}
-/**
- * Load a text file.
- *
- * \param is_internal: If \a true, this text data-block only exists in memory,
- * not as a file on disk.
- *
- * \note text data-blocks have no real user but have 'fake user' enabled by default
- */
Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const bool is_internal)
{
unsigned char *buffer;
@@ -523,11 +522,6 @@ Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const
return ta;
}
-/**
- * Load a text file.
- *
- * \note Text data-blocks have no user by default, only the 'real user' flag.
- */
Text *BKE_text_load(Main *bmain, const char *file, const char *relpath)
{
return BKE_text_load_ex(bmain, file, relpath, false);
@@ -547,11 +541,6 @@ void BKE_text_write(Text *text, const char *str) /* called directly from rna */
txt_make_dirty(text);
}
-/* returns 0 if file on disk is the same or Text is in memory only
- * returns 1 if file has been modified on disk since last local edit
- * returns 2 if file on disk has been deleted
- * -1 is returned if an error occurs */
-
int BKE_text_file_modified_check(Text *text)
{
BLI_stat_t st;
@@ -1131,7 +1120,6 @@ void txt_move_toline(Text *text, unsigned int line, const bool sel)
txt_move_to(text, line, 0, sel);
}
-/* Moves to a certain byte in a line, not a certain utf8-character! */
void txt_move_to(Text *text, unsigned int line, unsigned int ch, const bool sel)
{
TextLine **linep;
@@ -1291,11 +1279,6 @@ void txt_sel_all(Text *text)
text->selc = text->sell->len;
}
-/**
- * Reverse of #txt_pop_sel
- * Clears the selection and ensures the cursor is located
- * at the selection (where the cursor is visually while editing).
- */
void txt_sel_clear(Text *text)
{
if (text->sell) {
@@ -1382,9 +1365,6 @@ void txt_sel_set(Text *text, int startl, int startc, int endl, int endc)
* - Are not null terminated.
* \{ */
-/**
- * Create a buffer, the only requirement is #txt_from_buf_for_undo can decode it.
- */
char *txt_to_buf_for_undo(Text *text, int *r_buf_len)
{
int buf_len = 0;
@@ -1402,9 +1382,6 @@ char *txt_to_buf_for_undo(Text *text, int *r_buf_len)
return buf;
}
-/**
- * Decode a buffer from #txt_to_buf_for_undo.
- */
void txt_from_buf_for_undo(Text *text, const char *buf, int buf_len)
{
const char *buf_end = buf + buf_len;
@@ -2401,10 +2378,11 @@ int text_check_bracket(const char ch)
return 0;
}
-/* TODO: have a function for operators -
- * http://docs.python.org/py3k/reference/lexical_analysis.html#operators */
bool text_check_delim(const char ch)
{
+ /* TODO: have a function for operators:
+ * http://docs.python.org/py3k/reference/lexical_analysis.html#operators */
+
int a;
char delims[] = "():\"\' ~!%^&*-+=[]{};/<>|.#\t,@";
diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c
index a8c8eaa6a1c..ee9247e6e60 100644
--- a/source/blender/blenkernel/intern/texture.c
+++ b/source/blender/blenkernel/intern/texture.c
@@ -211,6 +211,7 @@ IDTypeInfo IDType_ID_TE = {
.name_plural = "textures",
.translation_context = BLT_I18NCONTEXT_ID_TEXTURE,
.flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = texture_init_data,
.copy_data = texture_copy_data,
@@ -218,6 +219,7 @@ IDTypeInfo IDType_ID_TE = {
.make_local = NULL,
.foreach_id = texture_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = texture_blend_write,
@@ -230,7 +232,6 @@ IDTypeInfo IDType_ID_TE = {
.lib_override_apply_post = NULL,
};
-/* Utils for all IDs using those texture slots. */
void BKE_texture_mtex_foreach_id(LibraryForeachIDData *data, MTex *mtex)
{
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, mtex->object, IDWALK_CB_NOP);
@@ -412,7 +413,6 @@ MTex *BKE_texture_mtex_add(void)
return mtex;
}
-/* slot -1 for first free ID */
MTex *BKE_texture_mtex_add_id(ID *id, int slot)
{
MTex **mtex_ar;
@@ -670,9 +670,6 @@ void BKE_texture_pointdensity_free(PointDensity *pd)
}
/* ------------------------------------------------------------------------- */
-/**
- * \returns true if this texture can use its #Texture.ima (even if its NULL)
- */
bool BKE_texture_is_image_user(const struct Tex *tex)
{
switch (tex->type) {
@@ -684,7 +681,6 @@ bool BKE_texture_is_image_user(const struct Tex *tex)
return false;
}
-/* ------------------------------------------------------------------------- */
bool BKE_texture_dependsOnTime(const struct Tex *texture)
{
if (texture->ima && BKE_image_is_animated(texture->ima)) {
@@ -758,7 +754,6 @@ static void texture_nodes_fetch_images_for_pool(Tex *texture,
}
}
-/* Make sure all images used by texture are loaded into pool. */
void BKE_texture_fetch_images_for_pool(Tex *texture, struct ImagePool *pool)
{
if (texture->nodetree != NULL) {
diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c
index 3cdb8e927a6..3878d3b1c98 100644
--- a/source/blender/blenkernel/intern/tracking.c
+++ b/source/blender/blenkernel/intern/tracking.c
@@ -160,11 +160,6 @@ static void tracking_dopesheet_free(MovieTrackingDopesheet *dopesheet)
dopesheet->tot_channel = 0;
}
-/* Free tracking structure, only frees structure contents
- * (if structure is allocated in heap, it shall be handled outside).
- *
- * All the pointers inside structure becomes invalid after this call.
- */
void BKE_tracking_free(MovieTracking *tracking)
{
tracking_tracks_free(&tracking->tracks);
@@ -276,7 +271,6 @@ static void tracking_objects_copy(ListBase *objects_dst,
}
}
-/* Copy tracking structure content. */
void BKE_tracking_copy(MovieTracking *tracking_dst,
const MovieTracking *tracking_src,
const int flag)
@@ -321,9 +315,6 @@ void BKE_tracking_copy(MovieTracking *tracking_dst,
BLI_ghash_free(tracks_mapping, NULL, NULL);
}
-/* Initialize motion tracking settings to default values,
- * used when new movie clip datablock is created.
- */
void BKE_tracking_settings_init(MovieTracking *tracking)
{
tracking->camera.sensor_width = 35.0f;
@@ -361,7 +352,6 @@ void BKE_tracking_settings_init(MovieTracking *tracking)
BKE_tracking_object_add(tracking, "Camera");
}
-/* Get list base of active object's tracks. */
ListBase *BKE_tracking_get_active_tracks(MovieTracking *tracking)
{
MovieTrackingObject *object = BKE_tracking_object_get_active(tracking);
@@ -373,7 +363,6 @@ ListBase *BKE_tracking_get_active_tracks(MovieTracking *tracking)
return &tracking->tracks;
}
-/* Get list base of active object's plane tracks. */
ListBase *BKE_tracking_get_active_plane_tracks(MovieTracking *tracking)
{
MovieTrackingObject *object = BKE_tracking_object_get_active(tracking);
@@ -385,7 +374,6 @@ ListBase *BKE_tracking_get_active_plane_tracks(MovieTracking *tracking)
return &tracking->plane_tracks;
}
-/* Get reconstruction data of active object. */
MovieTrackingReconstruction *BKE_tracking_get_active_reconstruction(MovieTracking *tracking)
{
MovieTrackingObject *object = BKE_tracking_object_get_active(tracking);
@@ -393,9 +381,6 @@ MovieTrackingReconstruction *BKE_tracking_get_active_reconstruction(MovieTrackin
return BKE_tracking_object_get_reconstruction(tracking, object);
}
-/* Get transformation matrix for a given object which is used
- * for parenting motion tracker reconstruction to 3D world.
- */
void BKE_tracking_get_camera_object_matrix(Object *camera_object, float mat[4][4])
{
BLI_assert(camera_object != NULL);
@@ -412,11 +397,6 @@ void BKE_tracking_get_camera_object_matrix(Object *camera_object, float mat[4][4
BKE_object_where_is_calc_mat4(camera_object, mat);
}
-/* Get projection matrix for camera specified by given tracking object
- * and frame number.
- *
- * NOTE: frame number should be in clip space, not scene space
- */
void BKE_tracking_get_projection_matrix(MovieTracking *tracking,
MovieTrackingObject *object,
int framenr,
@@ -472,7 +452,6 @@ void BKE_tracking_get_projection_matrix(MovieTracking *tracking,
/*********************** clipboard *************************/
-/* Free clipboard by freeing memory used by all tracks in it. */
void BKE_tracking_clipboard_free(void)
{
MovieTrackingTrack *track = tracking_clipboard.tracks.first, *next_track;
@@ -489,7 +468,6 @@ void BKE_tracking_clipboard_free(void)
BLI_listbase_clear(&tracking_clipboard.tracks);
}
-/* Copy selected tracks from specified object to the clipboard. */
void BKE_tracking_clipboard_copy_tracks(MovieTracking *tracking, MovieTrackingObject *object)
{
ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
@@ -510,17 +488,11 @@ void BKE_tracking_clipboard_copy_tracks(MovieTracking *tracking, MovieTrackingOb
}
}
-/* Check whether there are any tracks in the clipboard. */
bool BKE_tracking_clipboard_has_tracks(void)
{
return (BLI_listbase_is_empty(&tracking_clipboard.tracks) == false);
}
-/* Paste tracks from clipboard to specified object.
- *
- * Names of new tracks in object are guaranteed to
- * be unique here.
- */
void BKE_tracking_clipboard_paste_tracks(MovieTracking *tracking, MovieTrackingObject *object)
{
ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
@@ -541,10 +513,6 @@ void BKE_tracking_clipboard_paste_tracks(MovieTracking *tracking, MovieTrackingO
/*********************** Tracks *************************/
-/* Add new empty track to the given list of tracks.
- *
- * It is required that caller will append at least one marker to avoid degenerate tracks.
- */
MovieTrackingTrack *BKE_tracking_track_add_empty(MovieTracking *tracking, ListBase *tracks_list)
{
const MovieTrackingSettings *settings = &tracking->settings;
@@ -569,14 +537,6 @@ MovieTrackingTrack *BKE_tracking_track_add_empty(MovieTracking *tracking, ListBa
return track;
}
-/* Add new track to a specified tracks base.
- *
- * Coordinates are expected to be in normalized 0..1 space,
- * frame number is expected to be in clip space.
- *
- * Width and height are clip's dimension used to scale track's
- * pattern and search regions.
- */
MovieTrackingTrack *BKE_tracking_track_add(MovieTracking *tracking,
ListBase *tracksbase,
float x,
@@ -618,7 +578,6 @@ MovieTrackingTrack *BKE_tracking_track_add(MovieTracking *tracking,
return track;
}
-/* Duplicate the specified track, result will no belong to any list. */
MovieTrackingTrack *BKE_tracking_track_duplicate(MovieTrackingTrack *track)
{
MovieTrackingTrack *new_track;
@@ -639,10 +598,6 @@ MovieTrackingTrack *BKE_tracking_track_duplicate(MovieTrackingTrack *track)
return new_track;
}
-/* Ensure specified track has got unique name,
- * if it's not name of specified track will be changed
- * keeping names of all other tracks unchanged.
- */
void BKE_tracking_track_unique_name(ListBase *tracksbase, MovieTrackingTrack *track)
{
BLI_uniquename(tracksbase,
@@ -653,11 +608,6 @@ void BKE_tracking_track_unique_name(ListBase *tracksbase, MovieTrackingTrack *tr
sizeof(track->name));
}
-/* Free specified track, only frees contents of a structure
- * (if track is allocated in heap, it shall be handled outside).
- *
- * All the pointers inside track becomes invalid after this call.
- */
void BKE_tracking_track_free(MovieTrackingTrack *track)
{
if (track->markers) {
@@ -665,8 +615,6 @@ void BKE_tracking_track_free(MovieTrackingTrack *track)
}
}
-/* Get frame numbers of the very first and last markers.
- * There is no check on whether the marker is enabled or not. */
void BKE_tracking_track_first_last_frame_get(const MovieTrackingTrack *track,
int *r_first_frame,
int *r_last_frame)
@@ -677,9 +625,6 @@ void BKE_tracking_track_first_last_frame_get(const MovieTrackingTrack *track,
*r_last_frame = track->markers[last_marker_index].framenr;
}
-/* Find the minimum starting frame and maximum ending frame within given set of
- * tracks.
- */
void BKE_tracking_tracks_first_last_frame_minmax(/*const*/ MovieTrackingTrack **tracks,
const int num_tracks,
int *r_first_frame,
@@ -745,11 +690,6 @@ MovieTrackingTrack **BKE_tracking_selected_tracks_in_active_object(MovieTracking
return source_tracks;
}
-/* Set flag for all specified track's areas.
- *
- * area - which part of marker should be selected. see TRACK_AREA_* constants.
- * flag - flag to be set for areas.
- */
void BKE_tracking_track_flag_set(MovieTrackingTrack *track, int area, int flag)
{
if (area == TRACK_AREA_NONE) {
@@ -767,11 +707,6 @@ void BKE_tracking_track_flag_set(MovieTrackingTrack *track, int area, int flag)
}
}
-/* Clear flag from all specified track's areas.
- *
- * area - which part of marker should be selected. see TRACK_AREA_* constants.
- * flag - flag to be cleared for areas.
- */
void BKE_tracking_track_flag_clear(MovieTrackingTrack *track, int area, int flag)
{
if (area == TRACK_AREA_NONE) {
@@ -789,19 +724,11 @@ void BKE_tracking_track_flag_clear(MovieTrackingTrack *track, int area, int flag
}
}
-/* Check whether track has got marker at specified frame.
- *
- * NOTE: frame number should be in clip space, not scene space.
- */
bool BKE_tracking_track_has_marker_at_frame(MovieTrackingTrack *track, int framenr)
{
return BKE_tracking_marker_get_exact(track, framenr) != NULL;
}
-/* Check whether track has got enabled marker at specified frame.
- *
- * NOTE: frame number should be in clip space, not scene space.
- */
bool BKE_tracking_track_has_enabled_marker_at_frame(MovieTrackingTrack *track, int framenr)
{
MovieTrackingMarker *marker = BKE_tracking_marker_get_exact(track, framenr);
@@ -809,18 +736,6 @@ bool BKE_tracking_track_has_enabled_marker_at_frame(MovieTrackingTrack *track, i
return marker && (marker->flag & MARKER_DISABLED) == 0;
}
-/* Clear track's path:
- *
- * - If action is TRACK_CLEAR_REMAINED path from ref_frame+1 up to
- * end will be clear.
- *
- * - If action is TRACK_CLEAR_UPTO path from the beginning up to
- * ref_frame-1 will be clear.
- *
- * - If action is TRACK_CLEAR_ALL only marker at frame ref_frame will remain.
- *
- * NOTE: frame number should be in clip space, not scene space
- */
void BKE_tracking_track_path_clear(MovieTrackingTrack *track, int ref_frame, int action)
{
int a;
@@ -1281,7 +1196,6 @@ static void track_mask_gpencil_layer_rasterize(int frame_width,
}
}
-/* Region is in pixel space, relative to marker's center. */
float *tracking_track_get_mask_for_region(int frame_width,
int frame_height,
const float region_min[2],
@@ -1336,7 +1250,6 @@ float BKE_tracking_track_get_weight_for_marker(MovieClip *clip,
return weight;
}
-/* area - which part of marker should be selected. see TRACK_AREA_* constants */
void BKE_tracking_track_select(ListBase *tracksbase,
MovieTrackingTrack *track,
int area,
@@ -1510,16 +1423,6 @@ void BKE_tracking_marker_clamp(MovieTrackingMarker *marker, int event)
}
}
-/**
- * Get marker closest to the given frame number.
- *
- * If there is maker with exact frame number it returned.
- * Otherwise, marker with highest frame number but lower than the requested
- * frame is returned if such marker exists. Otherwise, the marker with lowest
- * frame number greater than the requested frame number is returned.
- *
- * This function has complexity of `O(log number_of_markers)`.
- */
MovieTrackingMarker *BKE_tracking_marker_get(MovieTrackingTrack *track, int framenr)
{
const int num_markers = track->markersnr;
@@ -1705,7 +1608,6 @@ void BKE_tracking_marker_get_subframe_position(MovieTrackingTrack *track,
/*********************** Plane Track *************************/
-/* Creates new plane track out of selected point tracks */
MovieTrackingPlaneTrack *BKE_tracking_plane_track_add(MovieTracking *tracking,
ListBase *plane_tracks_base,
ListBase *tracks,
@@ -1789,11 +1691,6 @@ void BKE_tracking_plane_track_unique_name(ListBase *plane_tracks_base,
sizeof(plane_track->name));
}
-/* Free specified plane track, only frees contents of a structure
- * (if track is allocated in heap, it shall be handled outside).
- *
- * All the pointers inside track becomes invalid after this call.
- */
void BKE_tracking_plane_track_free(MovieTrackingPlaneTrack *plane_track)
{
if (plane_track->markers) {
@@ -1988,9 +1885,6 @@ void BKE_tracking_plane_marker_delete(MovieTrackingPlaneTrack *plane_track, int
* would be nice to de-duplicate them somehow..
*/
-/* Get a plane marker at given frame,
- * If there's no such marker, closest one from the left side will be returned.
- */
MovieTrackingPlaneMarker *BKE_tracking_plane_marker_get(MovieTrackingPlaneTrack *plane_track,
int framenr)
{
@@ -2039,9 +1933,6 @@ MovieTrackingPlaneMarker *BKE_tracking_plane_marker_get(MovieTrackingPlaneTrack
return NULL;
}
-/* Get a plane marker at exact given frame, if there's no marker at the frame,
- * NULL will be returned.
- */
MovieTrackingPlaneMarker *BKE_tracking_plane_marker_get_exact(MovieTrackingPlaneTrack *plane_track,
int framenr)
{
@@ -2054,7 +1945,6 @@ MovieTrackingPlaneMarker *BKE_tracking_plane_marker_get_exact(MovieTrackingPlane
return plane_marker;
}
-/* Ensure there's a marker for the given frame. */
MovieTrackingPlaneMarker *BKE_tracking_plane_marker_ensure(MovieTrackingPlaneTrack *plane_track,
int framenr)
{
@@ -2326,7 +2216,6 @@ static void reconstructed_camera_scale_set(MovieTrackingObject *object, float ma
}
}
-/* converts principal offset from center to offset of blender's camera */
void BKE_tracking_camera_shift_get(
MovieTracking *tracking, int winx, int winy, float *shiftx, float *shifty)
{
@@ -2899,10 +2788,6 @@ ImBuf *BKE_tracking_get_search_imbuf(ImBuf *ibuf,
return searchibuf;
}
-/* zap channels from the imbuf that are disabled by the user. this can lead to
- * better tracks sometimes. however, instead of simply zeroing the channels
- * out, do a partial grayscale conversion so the display is better.
- */
void BKE_tracking_disable_channels(
ImBuf *ibuf, bool disable_red, bool disable_green, bool disable_blue, bool grayscale)
{
@@ -3417,9 +3302,6 @@ static void tracking_dopesheet_calc_coverage(MovieTracking *tracking)
MEM_freeN(per_frame_counter);
}
-/* Tag dopesheet for update, actual update will happen later
- * when it'll be actually needed.
- */
void BKE_tracking_dopesheet_tag_update(MovieTracking *tracking)
{
MovieTrackingDopesheet *dopesheet = &tracking->dopesheet;
@@ -3427,7 +3309,6 @@ void BKE_tracking_dopesheet_tag_update(MovieTracking *tracking)
dopesheet->ok = false;
}
-/* Do dopesheet update, if update is not needed nothing will happen. */
void BKE_tracking_dopesheet_update(MovieTracking *tracking)
{
MovieTrackingDopesheet *dopesheet = &tracking->dopesheet;
@@ -3451,7 +3332,6 @@ void BKE_tracking_dopesheet_update(MovieTracking *tracking)
dopesheet->ok = true;
}
-/* NOTE: Returns NULL if the track comes from camera object, */
MovieTrackingObject *BKE_tracking_find_object_for_track(const MovieTracking *tracking,
const MovieTrackingTrack *track)
{
@@ -3479,7 +3359,6 @@ ListBase *BKE_tracking_find_tracks_list_for_track(MovieTracking *tracking,
return &tracking->tracks;
}
-/* NOTE: Returns NULL if the track comes from camera object, */
MovieTrackingObject *BKE_tracking_find_object_for_plane_track(
const MovieTracking *tracking, const MovieTrackingPlaneTrack *plane_track)
{
diff --git a/source/blender/blenkernel/intern/tracking_auto.c b/source/blender/blenkernel/intern/tracking_auto.c
index e2a29d7858d..c83e595c611 100644
--- a/source/blender/blenkernel/intern/tracking_auto.c
+++ b/source/blender/blenkernel/intern/tracking_auto.c
@@ -775,7 +775,7 @@ void BKE_autotrack_context_sync(AutoTrackContext *context)
}
/* TODO(sergey): Find a way to avoid this, somehow making all needed logic in
- * BKE_autotrack_context_sync(). */
+ * #BKE_autotrack_context_sync(). */
void BKE_autotrack_context_sync_user(AutoTrackContext *context, MovieClipUser *user)
{
user->framenr = context->synchronized_scene_frame;
diff --git a/source/blender/blenkernel/intern/tracking_detect.c b/source/blender/blenkernel/intern/tracking_detect.c
index 08719161e1a..be680ef8a8b 100644
--- a/source/blender/blenkernel/intern/tracking_detect.c
+++ b/source/blender/blenkernel/intern/tracking_detect.c
@@ -148,7 +148,6 @@ static void run_configured_detector(MovieTracking *tracking,
}
}
-/* Detect features using FAST detector */
void BKE_tracking_detect_fast(MovieTracking *tracking,
ListBase *tracksbase,
ImBuf *ibuf,
@@ -170,7 +169,6 @@ void BKE_tracking_detect_fast(MovieTracking *tracking,
tracking, tracksbase, ibuf, framenr, layer, place_outside_layer, &options);
}
-/* Detect features using Harris detector */
void BKE_tracking_detect_harris(MovieTracking *tracking,
ListBase *tracksbase,
ImBuf *ibuf,
diff --git a/source/blender/blenkernel/intern/tracking_plane_tracker.c b/source/blender/blenkernel/intern/tracking_plane_tracker.c
index b787cd366c5..d4a5bb2aa9d 100644
--- a/source/blender/blenkernel/intern/tracking_plane_tracker.c
+++ b/source/blender/blenkernel/intern/tracking_plane_tracker.c
@@ -167,7 +167,6 @@ static void track_plane_from_existing_motion(MovieTrackingPlaneTrack *plane_trac
}
}
-/* NOTE: frame number should be in clip space, not scene space */
void BKE_tracking_track_plane_from_existing_motion(MovieTrackingPlaneTrack *plane_track,
int start_frame)
{
diff --git a/source/blender/blenkernel/intern/tracking_region_tracker.c b/source/blender/blenkernel/intern/tracking_region_tracker.c
index 179def0a6f2..ad3f226fa92 100644
--- a/source/blender/blenkernel/intern/tracking_region_tracker.c
+++ b/source/blender/blenkernel/intern/tracking_region_tracker.c
@@ -180,7 +180,6 @@ static ImBuf *tracking_context_get_reference_ibuf(MovieClip *clip,
return ibuf;
}
-/* Fill in libmv tracker options structure with settings need to be used to perform track. */
void tracking_configure_tracker(const MovieTrackingTrack *track,
float *mask,
const bool is_backwards,
@@ -311,11 +310,6 @@ static bool refine_marker_reference_frame_get(MovieTrackingTrack *track,
return (reference->flag & MARKER_DISABLED) == 0;
}
-/* Refine marker's position using previously known keyframe.
- * Direction of searching for a keyframe depends on backwards flag,
- * which means if backwards is false, previous keyframe will be as
- * reference.
- */
void BKE_tracking_refine_marker(MovieClip *clip,
MovieTrackingTrack *track,
MovieTrackingMarker *marker,
diff --git a/source/blender/blenkernel/intern/tracking_solver.c b/source/blender/blenkernel/intern/tracking_solver.c
index d89d36f85ea..47a955c9d93 100644
--- a/source/blender/blenkernel/intern/tracking_solver.c
+++ b/source/blender/blenkernel/intern/tracking_solver.c
@@ -325,7 +325,6 @@ static int reconstruct_count_tracks_on_both_keyframes(MovieTracking *tracking,
return tot;
}
-/* Perform early check on whether everything is fine to start reconstruction. */
bool BKE_tracking_reconstruction_check(MovieTracking *tracking,
MovieTrackingObject *object,
char *error_msg,
@@ -354,11 +353,6 @@ bool BKE_tracking_reconstruction_check(MovieTracking *tracking,
return true;
}
-/* Create context for camera/object motion reconstruction.
- * Copies all data needed for reconstruction from movie
- * clip datablock, so editing this clip is safe during
- * reconstruction job is in progress.
- */
MovieReconstructContext *BKE_tracking_reconstruction_context_new(MovieClip *clip,
MovieTrackingObject *object,
int keyframe1,
@@ -446,7 +440,6 @@ const char *BKE_tracking_reconstruction_error_message_get(const MovieReconstruct
return context->error_message;
}
-/* Free memory used by a reconstruction process. */
void BKE_tracking_reconstruction_context_free(MovieReconstructContext *context)
{
if (context->reconstruction) {
@@ -486,15 +479,6 @@ static void reconstructionOptionsFromContext(libmv_ReconstructionOptions *recons
reconstruction_options->refine_intrinsics = context->refine_flags;
}
-/* Solve camera/object motion and reconstruct 3D markers position
- * from a prepared reconstruction context.
- *
- * stop is not actually used at this moment, so reconstruction
- * job could not be stopped.
- *
- * do_update, progress and stat_message are set by reconstruction
- * callback in libmv side and passing to an interface.
- */
void BKE_tracking_reconstruction_solve(MovieReconstructContext *context,
short *stop,
short *do_update,
@@ -542,9 +526,6 @@ void BKE_tracking_reconstruction_solve(MovieReconstructContext *context,
context->reprojection_error = error;
}
-/* Finish reconstruction process by copying reconstructed data
- * to an actual movie clip datablock.
- */
bool BKE_tracking_reconstruction_finish(MovieReconstructContext *context, MovieTracking *tracking)
{
MovieTrackingReconstruction *reconstruction;
@@ -608,9 +589,6 @@ static void tracking_scale_reconstruction(ListBase *tracksbase,
}
}
-/* Apply scale on all reconstructed cameras and bundles,
- * used by camera scale apply operator.
- */
void BKE_tracking_reconstruction_scale(MovieTracking *tracking, float scale[3])
{
LISTBASE_FOREACH (MovieTrackingObject *, object, &tracking->objects) {
diff --git a/source/blender/blenkernel/intern/tracking_stabilize.c b/source/blender/blenkernel/intern/tracking_stabilize.c
index d5585116f7e..fe9a2f2268a 100644
--- a/source/blender/blenkernel/intern/tracking_stabilize.c
+++ b/source/blender/blenkernel/intern/tracking_stabilize.c
@@ -1252,24 +1252,6 @@ static StabContext *init_stabilizer(MovieClip *clip, int size, float aspect)
/* === public interface functions === */
-/* Get stabilization data (translation, scaling and angle) for a given frame.
- * Returned data describes how to compensate the detected movement, but with any
- * chosen scale factor already applied and any target frame position already
- * compensated. In case stabilization fails or is disabled, neutral values are
- * returned.
- *
- * framenr is a frame number, relative to the clip (not relative to the scene
- * timeline)
- * width is an effective width of the canvas (square pixels), used to scale the
- * determined translation
- *
- * Outputs:
- * - translation of the lateral shift, absolute canvas coordinates
- * (square pixels).
- * - scale of the scaling to apply
- * - angle of the rotation angle, relative to the frame center
- */
-/* TODO(sergey): Use r_ prefix for output parameters here. */
void BKE_tracking_stabilization_data_get(MovieClip *clip,
int framenr,
int width,
@@ -1307,7 +1289,7 @@ void BKE_tracking_stabilization_data_get(MovieClip *clip,
discard_stabilization_working_context(ctx);
}
-typedef void (*interpolation_func)(struct ImBuf *, struct ImBuf *, float, float, int, int);
+typedef void (*interpolation_func)(const struct ImBuf *, struct ImBuf *, float, float, int, int);
typedef struct TrackingStabilizeFrameInterpolationData {
ImBuf *ibuf;
@@ -1336,12 +1318,6 @@ static void tracking_stabilize_frame_interpolation_cb(
}
}
-/* Stabilize given image buffer using stabilization data for a specified
- * frame number.
- *
- * NOTE: frame number should be in clip space, not scene space.
- */
-/* TODO(sergey): Use r_ prefix for output parameters here. */
ImBuf *BKE_tracking_stabilize_frame(
MovieClip *clip, int framenr, ImBuf *ibuf, float translation[2], float *scale, float *angle)
{
@@ -1449,16 +1425,6 @@ ImBuf *BKE_tracking_stabilize_frame(
return tmpibuf;
}
-/* Build a 4x4 transformation matrix based on the given 2D stabilization data.
- * mat is a 4x4 matrix in homogeneous coordinates, adapted to the
- * final image buffer size and compensated for pixel aspect ratio,
- * ready for direct OpenGL drawing.
- *
- * TODO(sergey): The signature of this function should be changed. we actually
- * don't need the dimensions of the image buffer. Instead we
- * should consider to provide the pivot point of the rotation as a
- * further stabilization data parameter.
- */
void BKE_tracking_stabilization_data_to_mat4(int buffer_width,
int buffer_height,
float pixel_aspect,
diff --git a/source/blender/blenkernel/intern/tracking_util.c b/source/blender/blenkernel/intern/tracking_util.c
index 16b36e94328..f1fd3a13e0e 100644
--- a/source/blender/blenkernel/intern/tracking_util.c
+++ b/source/blender/blenkernel/intern/tracking_util.c
@@ -338,11 +338,6 @@ static void search_pixel_to_marker_unified(int frame_width,
sub_v2_v2v2(marker_unified, frame_unified, marker->pos);
}
-/* Each marker has 5 coordinates associated with it that get warped with
- * tracking: the four corners ("pattern_corners"), and the center ("pos").
- * This function puts those 5 points into the appropriate frame for tracking
- * (the "search" coordinate frame).
- */
void tracking_get_marker_coords_for_tracking(int frame_width,
int frame_height,
const MovieTrackingMarker *marker,
@@ -369,7 +364,6 @@ void tracking_get_marker_coords_for_tracking(int frame_width,
search_pixel_y[4] = pixel_coords[1] - 0.5f;
}
-/* Inverse of above. */
void tracking_set_marker_coords_from_tracking(int frame_width,
int frame_height,
MovieTrackingMarker *marker,
@@ -411,15 +405,6 @@ void tracking_set_marker_coords_from_tracking(int frame_width,
/** \name General Purpose Utility Functions
* \{ */
-/* Place a disabled marker before or after specified ref_marker.
- *
- * If before is truth, disabled marker is placed before reference
- * one, and it's placed after it otherwise.
- *
- * If there's already a marker at the frame where disabled one
- * is expected to be placed, nothing will happen if overwrite
- * is false.
- */
void tracking_marker_insert_disabled(MovieTrackingTrack *track,
const MovieTrackingMarker *ref_marker,
bool before,
@@ -526,7 +511,6 @@ static void distortion_model_parameters_from_options(
BLI_assert_msg(0, "Unknown distortion model");
}
-/* Fill in Libmv C-API camera intrinsics options from tracking structure. */
void tracking_cameraIntrinscisOptionsFromTracking(
MovieTracking *tracking,
int calibration_width,
@@ -563,7 +547,6 @@ void tracking_trackingCameraFromIntrinscisOptions(
distortion_model_parameters_from_options(camera_intrinsics_options, camera);
}
-/* Get previous keyframed marker. */
MovieTrackingMarker *tracking_get_keyframed_marker(MovieTrackingTrack *track,
int current_frame,
bool backwards)
diff --git a/source/blender/nodes/intern/type_conversions.cc b/source/blender/blenkernel/intern/type_conversions.cc
index b1611679ced..b23220286e6 100644
--- a/source/blender/nodes/intern/type_conversions.cc
+++ b/source/blender/blenkernel/intern/type_conversions.cc
@@ -14,7 +14,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#include "NOD_type_conversions.hh"
+#include "BKE_type_conversions.hh"
#include "FN_multi_function_builder.hh"
@@ -22,18 +22,18 @@
#include "BLI_float2.hh"
#include "BLI_float3.hh"
-namespace blender::nodes {
+namespace blender::bke {
using fn::MFDataType;
template<typename From, typename To, To (*ConversionF)(const From &)>
static void add_implicit_conversion(DataTypeConversions &conversions)
{
- const CPPType &from_type = CPPType::get<From>();
- const CPPType &to_type = CPPType::get<To>();
- const std::string conversion_name = from_type.name() + " to " + to_type.name();
+ static const CPPType &from_type = CPPType::get<From>();
+ static const CPPType &to_type = CPPType::get<To>();
+ static const std::string conversion_name = from_type.name() + " to " + to_type.name();
- static fn::CustomMF_SI_SO<From, To> multi_function{conversion_name, ConversionF};
+ static fn::CustomMF_SI_SO<From, To> multi_function{conversion_name.c_str(), ConversionF};
static auto convert_single_to_initialized = [](const void *src, void *dst) {
*(To *)dst = ConversionF(*(const From *)src);
};
@@ -239,6 +239,23 @@ void DataTypeConversions::convert_to_uninitialized(const CPPType &from_type,
functions->convert_single_to_uninitialized(from_value, to_value);
}
+void DataTypeConversions::convert_to_initialized_n(fn::GSpan from_span,
+ fn::GMutableSpan to_span) const
+{
+ const CPPType &from_type = from_span.type();
+ const CPPType &to_type = to_span.type();
+ BLI_assert(from_span.size() == to_span.size());
+ BLI_assert(this->is_convertible(from_type, to_type));
+ const fn::MultiFunction *fn = this->get_conversion_multi_function(
+ MFDataType::ForSingle(from_type), MFDataType::ForSingle(to_type));
+ fn::MFParamsBuilder params{*fn, from_span.size()};
+ params.add_readonly_single_input(from_span);
+ to_type.destruct_n(to_span.data(), to_span.size());
+ params.add_uninitialized_single_output(to_span);
+ fn::MFContextBuilder context;
+ fn->call_auto(IndexRange(from_span.size()), params, context);
+}
+
class GVArray_For_ConvertedGVArray : public fn::GVArrayImpl {
private:
fn::GVArray varray_;
@@ -344,4 +361,4 @@ fn::GVMutableArray DataTypeConversions::try_convert(fn::GVMutableArray varray,
std::move(varray), to_type, *this);
}
-} // namespace blender::nodes
+} // namespace blender::bke
diff --git a/source/blender/blenkernel/intern/undo_system.c b/source/blender/blenkernel/intern/undo_system.c
index 26d37489e35..3e263fafe28 100644
--- a/source/blender/blenkernel/intern/undo_system.c
+++ b/source/blender/blenkernel/intern/undo_system.c
@@ -61,13 +61,39 @@
static CLG_LogRef LOG = {"bke.undosys"};
/* -------------------------------------------------------------------- */
+/** \name Undo Types
+ * \{ */
+
+const UndoType *BKE_UNDOSYS_TYPE_IMAGE = NULL;
+const UndoType *BKE_UNDOSYS_TYPE_MEMFILE = NULL;
+const UndoType *BKE_UNDOSYS_TYPE_PAINTCURVE = NULL;
+const UndoType *BKE_UNDOSYS_TYPE_PARTICLE = NULL;
+const UndoType *BKE_UNDOSYS_TYPE_SCULPT = NULL;
+const UndoType *BKE_UNDOSYS_TYPE_TEXT = NULL;
+
+static ListBase g_undo_types = {NULL, NULL};
+
+static const UndoType *BKE_undosys_type_from_context(bContext *C)
+{
+ LISTBASE_FOREACH (const UndoType *, ut, &g_undo_types) {
+ /* No poll means we don't check context. */
+ if (ut->poll && ut->poll(C)) {
+ return ut;
+ }
+ }
+ return NULL;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Internal Nested Undo Checks
*
* Make sure we're not running undo operations from 'step_encode', 'step_decode' callbacks.
* bugs caused by this situation aren't _that_ hard to spot but aren't always so obvious.
* Best we have a check which shows the problem immediately.
- *
* \{ */
+
#define WITH_NESTED_UNDO_CHECK
#ifdef WITH_NESTED_UNDO_CHECK
@@ -90,36 +116,9 @@ static bool g_undo_callback_running = false;
# define UNDO_NESTED_CHECK_BEGIN ((void)0)
# define UNDO_NESTED_CHECK_END ((void)0)
#endif
-/** \} */
-/* -------------------------------------------------------------------- */
-/** \name Public Undo Types
- *
- * Unfortunately we need this for a handful of places.
- * \{ */
-const UndoType *BKE_UNDOSYS_TYPE_IMAGE = NULL;
-const UndoType *BKE_UNDOSYS_TYPE_MEMFILE = NULL;
-const UndoType *BKE_UNDOSYS_TYPE_PAINTCURVE = NULL;
-const UndoType *BKE_UNDOSYS_TYPE_PARTICLE = NULL;
-const UndoType *BKE_UNDOSYS_TYPE_SCULPT = NULL;
-const UndoType *BKE_UNDOSYS_TYPE_TEXT = NULL;
/** \} */
-/* UndoType */
-
-static ListBase g_undo_types = {NULL, NULL};
-
-static const UndoType *BKE_undosys_type_from_context(bContext *C)
-{
- LISTBASE_FOREACH (const UndoType *, ut, &g_undo_types) {
- /* No poll means we don't check context. */
- if (ut->poll && ut->poll(C)) {
- return ut;
- }
- }
- return NULL;
-}
-
/* -------------------------------------------------------------------- */
/** \name Internal Callback Wrappers
*
@@ -358,7 +357,6 @@ void BKE_undosys_stack_init_from_main(UndoStack *ustack, struct Main *bmain)
undosys_stack_push_main(ustack, IFACE_("Original"), bmain);
}
-/* called after 'BKE_undosys_stack_init_from_main' */
void BKE_undosys_stack_init_from_context(UndoStack *ustack, bContext *C)
{
const UndoType *ut = BKE_undosys_type_from_context(C);
@@ -367,7 +365,6 @@ void BKE_undosys_stack_init_from_context(UndoStack *ustack, bContext *C)
}
}
-/* name optional */
bool BKE_undosys_stack_has_undo(const UndoStack *ustack, const char *name)
{
if (name) {
@@ -397,10 +394,6 @@ UndoStep *BKE_undosys_stack_init_or_active_with_type(UndoStack *ustack, const Un
return BKE_undosys_stack_active_with_type(ustack, ut);
}
-/**
- * \param steps: Limit the number of undo steps.
- * \param memory_limit: Limit the amount of memory used by the undo stack.
- */
void BKE_undosys_stack_limit_steps_and_memory(UndoStack *ustack, int steps, size_t memory_limit)
{
UNDO_NESTED_ASSERT(false);
@@ -455,6 +448,10 @@ void BKE_undosys_stack_limit_steps_and_memory(UndoStack *ustack, int steps, size
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Undo Step
+ * \{ */
+
UndoStep *BKE_undosys_step_push_init_with_type(UndoStack *ustack,
bContext *C,
const char *name,
@@ -497,9 +494,6 @@ UndoStep *BKE_undosys_step_push_init(UndoStack *ustack, bContext *C, const char
return BKE_undosys_step_push_init_with_type(ustack, C, name, ut);
}
-/**
- * \param C: Can be NULL from some callers if their encoding function doesn't need it
- */
eUndoPushReturn BKE_undosys_step_push_with_type(UndoStack *ustack,
bContext *C,
const char *name,
@@ -613,9 +607,6 @@ eUndoPushReturn BKE_undosys_step_push(UndoStack *ustack, bContext *C, const char
return BKE_undosys_step_push_with_type(ustack, C, name, ut);
}
-/**
- * Useful when we want to diff against previous undo data but can't be sure the types match.
- */
UndoStep *BKE_undosys_step_same_type_next(UndoStep *us)
{
if (us) {
@@ -629,9 +620,6 @@ UndoStep *BKE_undosys_step_same_type_next(UndoStep *us)
return us;
}
-/**
- * Useful when we want to diff against previous undo data but can't be sure the types match.
- */
UndoStep *BKE_undosys_step_same_type_prev(UndoStep *us)
{
if (us) {
@@ -674,14 +662,6 @@ UndoStep *BKE_undosys_step_find_by_type(UndoStack *ustack, const UndoType *ut)
return NULL;
}
-/**
- * Return direction of the undo/redo from `us_reference` (or `ustack->step_active` if NULL), and
- * `us_target`.
- *
- * \note If `us_reference` and `us_target` are the same, we consider this is an undo.
- *
- * \return -1 for undo, 1 for redo, 0 in case of error.
- */
eUndoStepDir BKE_undosys_step_calc_direction(const UndoStack *ustack,
const UndoStep *us_target,
const UndoStep *us_reference)
@@ -741,19 +721,6 @@ static UndoStep *undosys_step_iter_first(UndoStep *us_reference, const eUndoStep
return (undo_dir == -1) ? us_reference->prev : us_reference->next;
}
-/**
- * Undo/Redo until the given `us_target` step becomes the active (currently loaded) one.
- *
- * \note Unless `us_target` is a 'skipped' one and `use_skip` is true, `us_target`
- * will become the active step.
- *
- * \note In case `use_skip` is true, the final target will always be **beyond** the given one
- * (if the given one has to be skipped).
- *
- * \param us_reference: If NULL, will be set to current active step in the undo stack. Otherwise,
- * it is assumed to match the current state, and will be used as basis for the undo/redo process
- * (i.e. all steps in-between `us_reference` and `us_target` will be processed).
- */
bool BKE_undosys_step_load_data_ex(UndoStack *ustack,
bContext *C,
UndoStep *us_target,
@@ -842,37 +809,22 @@ bool BKE_undosys_step_load_data_ex(UndoStack *ustack,
return false;
}
-/**
- * Undo/Redo until the given `us_target` step becomes the active (currently loaded) one.
- */
bool BKE_undosys_step_load_data(UndoStack *ustack, bContext *C, UndoStep *us_target)
{
/* Note that here we do not skip 'skipped' steps by default. */
return BKE_undosys_step_load_data_ex(ustack, C, us_target, NULL, false);
}
-/**
- * Undo/Redo until the step matching given `index` in the undo stack becomes the active (currently
- * loaded) one.
- */
void BKE_undosys_step_load_from_index(UndoStack *ustack, bContext *C, const int index)
{
UndoStep *us_target = BLI_findlink(&ustack->steps, index);
BLI_assert(us_target->skip == false);
+ if (us_target == ustack->step_active) {
+ return;
+ }
BKE_undosys_step_load_data(ustack, C, us_target);
}
-/**
- * Undo until `us_target` step becomes the active (currently loaded) one.
- *
- * \warning This function assumes that the given target step is _before_ current active one.
- *
- * \note Unless `us_target` is a 'skipped' one and `use_skip` is true, `us_target` will become the
- * active step.
- *
- * \note In case `use_skip` is true, the final target will always be **before** the given one (if
- * the given one has to be skipped).
- */
bool BKE_undosys_step_undo_with_data_ex(UndoStack *ustack,
bContext *C,
UndoStep *us_target,
@@ -888,19 +840,11 @@ bool BKE_undosys_step_undo_with_data_ex(UndoStack *ustack,
return BKE_undosys_step_load_data_ex(ustack, C, us_target, us_reference, use_skip);
}
-/**
- * Undo until `us_target` step becomes the active (currently loaded) one.
- *
- * \note See #BKE_undosys_step_undo_with_data_ex for details.
- */
bool BKE_undosys_step_undo_with_data(UndoStack *ustack, bContext *C, UndoStep *us_target)
{
return BKE_undosys_step_undo_with_data_ex(ustack, C, us_target, true);
}
-/**
- * Undo one step from current active (currently loaded) one.
- */
bool BKE_undosys_step_undo(UndoStack *ustack, bContext *C)
{
if (ustack->step_active != NULL) {
@@ -909,17 +853,6 @@ bool BKE_undosys_step_undo(UndoStack *ustack, bContext *C)
return false;
}
-/**
- * Redo until `us_target` step becomes the active (currently loaded) one.
- *
- * \warning This function assumes that the given target step is _after_ current active one.
- *
- * \note Unless `us_target` is a 'skipped' one and `use_skip` is true, `us_target` will become the
- * active step.
- *
- * \note In case `use_skip` is true, the final target will always be **after** the given one (if
- * the given one has to be skipped).
- */
bool BKE_undosys_step_redo_with_data_ex(UndoStack *ustack,
bContext *C,
UndoStep *us_target,
@@ -934,19 +867,11 @@ bool BKE_undosys_step_redo_with_data_ex(UndoStack *ustack,
return BKE_undosys_step_load_data_ex(ustack, C, us_target, us_reference, use_skip);
}
-/**
- * Redo until `us_target` step becomes the active (currently loaded) one.
- *
- * \note See #BKE_undosys_step_redo_with_data_ex for details.
- */
bool BKE_undosys_step_redo_with_data(UndoStack *ustack, bContext *C, UndoStep *us_target)
{
return BKE_undosys_step_redo_with_data_ex(ustack, C, us_target, true);
}
-/**
- * Redo one step from current active one.
- */
bool BKE_undosys_step_redo(UndoStack *ustack, bContext *C)
{
if (ustack->step_active != NULL) {
@@ -955,9 +880,6 @@ bool BKE_undosys_step_redo(UndoStack *ustack, bContext *C)
return false;
}
-/**
- * Similar to #WM_operatortype_append
- */
UndoType *BKE_undosys_type_append(void (*undosys_fn)(UndoType *))
{
UndoType *ut;
diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c
index 4e9a3c9fb2e..fde3ac13ceb 100644
--- a/source/blender/blenkernel/intern/unit.c
+++ b/source/blender/blenkernel/intern/unit.c
@@ -1091,22 +1091,6 @@ double BKE_unit_apply_preferred_unit(const struct UnitSettings *settings, int ty
return value * scalar + bias;
}
-/**
- * Make a copy of the string that replaces the units with numbers.
- *
- * This is only used when evaluating user input and can afford to be a bit slower
- *
- * This is to be used before python evaluation so..
- * 10.1km -> 10.1*1000.0
- * ...will be resolved by python.
- *
- * Values will be split by an add sign.
- * 5'2" -> 5*0.3048 + 2*0.0254
- *
- * \param str_prev: is optional, when valid it is used to get a base unit when none is set.
- *
- * \return True of a change was made.
- */
bool BKE_unit_replace_string(
char *str, int len_max, const char *str_prev, double scale_pref, int system, int type)
{
@@ -1196,7 +1180,6 @@ bool BKE_unit_replace_string(
return changed;
}
-/* 45µm --> 45um */
void BKE_unit_name_to_alt(char *str, int len_max, const char *orig_str, int system, int type)
{
const bUnitCollection *usys = unit_get_system(system, type);
diff --git a/source/blender/blenkernel/intern/vfont.c b/source/blender/blenkernel/intern/vfont.c
index 43c8a59baad..4a598288ee6 100644
--- a/source/blender/blenkernel/intern/vfont.c
+++ b/source/blender/blenkernel/intern/vfont.c
@@ -49,6 +49,7 @@
#include "DNA_vfont_types.h"
#include "BKE_anim_path.h"
+#include "BKE_bpath.h"
#include "BKE_curve.h"
#include "BKE_global.h"
#include "BKE_idtype.h"
@@ -123,6 +124,21 @@ static void vfont_free_data(ID *id)
}
}
+static void vfont_foreach_path(ID *id, BPathForeachPathData *bpath_data)
+{
+ VFont *vfont = (VFont *)id;
+
+ if (vfont->packedfile != NULL && (bpath_data->flag & BKE_BPATH_FOREACH_PATH_SKIP_PACKED) != 0) {
+ return;
+ }
+
+ if (BKE_vfont_is_builtin(vfont)) {
+ return;
+ }
+
+ BKE_bpath_foreach_path_fixed_process(bpath_data, vfont->filepath);
+}
+
static void vfont_blend_write(BlendWriter *writer, ID *id, const void *id_address)
{
VFont *vf = (VFont *)id;
@@ -162,6 +178,7 @@ IDTypeInfo IDType_ID_VF = {
.name_plural = "fonts",
.translation_context = BLT_I18NCONTEXT_ID_VFONT,
.flags = IDTYPE_FLAGS_NO_ANIMDATA | IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = vfont_init_data,
.copy_data = vfont_copy_data,
@@ -169,6 +186,7 @@ IDTypeInfo IDType_ID_VF = {
.make_local = NULL,
.foreach_id = NULL,
.foreach_cache = NULL,
+ .foreach_path = vfont_foreach_path,
.owner_get = NULL,
.blend_write = vfont_blend_write,
@@ -183,7 +201,6 @@ IDTypeInfo IDType_ID_VF = {
/***************************** VFont *******************************/
-/* The vfont code */
void BKE_vfont_free_data(struct VFont *vfont)
{
if (vfont->data) {
@@ -1743,10 +1760,6 @@ bool BKE_vfont_to_curve_nubase(Object *ob, int mode, ListBase *r_nubase)
return BKE_vfont_to_curve_ex(ob, ob->data, mode, r_nubase, NULL, NULL, NULL, NULL);
}
-/**
- * Warning: expects to have access to evaluated data
- * (i.e. passed object should be evaluated one...).
- */
bool BKE_vfont_to_curve(Object *ob, int mode)
{
Curve *cu = ob->data;
diff --git a/source/blender/blenkernel/intern/vfontdata_freetype.c b/source/blender/blenkernel/intern/vfontdata_freetype.c
index bd58d156d06..9b79d5635d1 100644
--- a/source/blender/blenkernel/intern/vfontdata_freetype.c
+++ b/source/blender/blenkernel/intern/vfontdata_freetype.c
@@ -396,14 +396,6 @@ static bool check_freetypefont(PackedFile *pf)
return success;
}
-/**
- * Construct a new VFontData structure from
- * Freetype font data in a PackedFile.
- *
- * \param pf: The font data.
- * \retval A new VFontData structure, or NULL
- * if unable to load.
- */
VFontData *BKE_vfontdata_from_freetypefont(PackedFile *pf)
{
VFontData *vfd = NULL;
diff --git a/source/blender/blenkernel/intern/volume.cc b/source/blender/blenkernel/intern/volume.cc
index a72b5268e1d..130aa957491 100644
--- a/source/blender/blenkernel/intern/volume.cc
+++ b/source/blender/blenkernel/intern/volume.cc
@@ -41,6 +41,7 @@
#include "BLI_utildefines.h"
#include "BKE_anim_data.h"
+#include "BKE_bpath.h"
#include "BKE_geometry_set.hh"
#include "BKE_global.h"
#include "BKE_idtype.h"
@@ -576,6 +577,18 @@ static void volume_foreach_cache(ID *id,
function_callback(id, &key, (void **)&volume->runtime.grids, 0, user_data);
}
+static void volume_foreach_path(ID *id, BPathForeachPathData *bpath_data)
+{
+ Volume *volume = reinterpret_cast<Volume *>(id);
+
+ if (volume->packedfile != nullptr &&
+ (bpath_data->flag & BKE_BPATH_FOREACH_PATH_SKIP_PACKED) != 0) {
+ return;
+ }
+
+ BKE_bpath_foreach_path_fixed_process(bpath_data, volume->filepath);
+}
+
static void volume_blend_write(BlendWriter *writer, ID *id, const void *id_address)
{
Volume *volume = (Volume *)id;
@@ -645,6 +658,7 @@ IDTypeInfo IDType_ID_VO = {
/* name_plural */ "volumes",
/* translation_context */ BLT_I18NCONTEXT_ID_VOLUME,
/* flags */ IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ /* asset_type_info */ nullptr,
/* init_data */ volume_init_data,
/* copy_data */ volume_copy_data,
@@ -652,6 +666,7 @@ IDTypeInfo IDType_ID_VO = {
/* make_local */ nullptr,
/* foreach_id */ volume_foreach_id,
/* foreach_cache */ volume_foreach_cache,
+ /* foreach_path */ volume_foreach_path,
/* owner_get */ nullptr,
/* blend_write */ volume_blend_write,
@@ -1225,7 +1240,6 @@ const VolumeGrid *BKE_volume_grid_active_get_for_read(const Volume *volume)
return BKE_volume_grid_get_for_read(volume, index);
}
-/* Tries to find a grid with the given name. Make sure that the volume has been loaded. */
const VolumeGrid *BKE_volume_grid_find_for_read(const Volume *volume, const char *name)
{
int num_grids = BKE_volume_num_grids(volume);
@@ -1365,7 +1379,6 @@ int BKE_volume_grid_channels(const VolumeGrid *grid)
return 0;
}
-/* Transformation from index space to object space. */
void BKE_volume_grid_transform_matrix(const VolumeGrid *volume_grid, float mat[4][4])
{
#ifdef WITH_OPENVDB
diff --git a/source/blender/blenkernel/intern/workspace.c b/source/blender/blenkernel/intern/workspace.c
index 6269cfc4349..e3fe1e04368 100644
--- a/source/blender/blenkernel/intern/workspace.c
+++ b/source/blender/blenkernel/intern/workspace.c
@@ -187,6 +187,7 @@ IDTypeInfo IDType_ID_WS = {
.name_plural = "workspaces",
.translation_context = BLT_I18NCONTEXT_ID_WORKSPACE,
.flags = IDTYPE_FLAGS_NO_COPY | IDTYPE_FLAGS_ONLY_APPEND | IDTYPE_FLAGS_NO_ANIMDATA,
+ .asset_type_info = NULL,
.init_data = workspace_init_data,
.copy_data = NULL,
@@ -194,6 +195,7 @@ IDTypeInfo IDType_ID_WS = {
.make_local = NULL,
.foreach_id = workspace_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = workspace_blend_write,
@@ -319,13 +321,6 @@ WorkSpace *BKE_workspace_add(Main *bmain, const char *name)
return new_workspace;
}
-/**
- * Remove \a workspace by freeing itself and its data. This is a higher-level wrapper that
- * calls #workspace_free_data (through #BKE_id_free) to free the workspace data, and frees
- * other data-blocks owned by \a workspace and its layouts (currently that is screens only).
- *
- * Always use this to remove (and free) workspaces. Don't free non-ID workspace members here.
- */
void BKE_workspace_remove(Main *bmain, WorkSpace *workspace)
{
for (WorkSpaceLayout *layout = workspace->layouts.first, *layout_next; layout;
@@ -369,9 +364,6 @@ void BKE_workspace_instance_hook_free(const Main *bmain, WorkSpaceInstanceHook *
MEM_freeN(hook);
}
-/**
- * Add a new layout to \a workspace for \a screen.
- */
WorkSpaceLayout *BKE_workspace_layout_add(Main *bmain,
WorkSpace *workspace,
bScreen *screen,
@@ -434,13 +426,6 @@ WorkSpaceLayout *BKE_workspace_layout_find(const WorkSpace *workspace, const bSc
return NULL;
}
-/**
- * Find the layout for \a screen without knowing which workspace to look in.
- * Can also be used to find the workspace that contains \a screen.
- *
- * \param r_workspace: Optionally return the workspace that contains the
- * looked up layout (if found).
- */
WorkSpaceLayout *BKE_workspace_layout_find_global(const Main *bmain,
const bScreen *screen,
WorkSpace **r_workspace)
@@ -464,15 +449,6 @@ WorkSpaceLayout *BKE_workspace_layout_find_global(const Main *bmain,
return NULL;
}
-/**
- * Circular workspace layout iterator.
- *
- * \param callback: Custom function which gets executed for each layout.
- * Can return false to stop iterating.
- * \param arg: Custom data passed to each \a callback call.
- *
- * \return the layout at which \a callback returned false.
- */
WorkSpaceLayout *BKE_workspace_layout_iter_circular(const WorkSpace *workspace,
WorkSpaceLayout *start,
bool (*callback)(const WorkSpaceLayout *layout,
@@ -564,18 +540,11 @@ void BKE_workspace_active_set(WorkSpaceInstanceHook *hook, WorkSpace *workspace)
}
}
-/**
- * Get the layout that is active for \a hook (which is the visible layout for the active workspace
- * in \a hook).
- */
WorkSpaceLayout *BKE_workspace_active_layout_get(const WorkSpaceInstanceHook *hook)
{
return hook->act_layout;
}
-/**
- * Get the layout to be activated should \a workspace become or be the active workspace in \a hook.
- */
WorkSpaceLayout *BKE_workspace_active_layout_for_workspace_get(const WorkSpaceInstanceHook *hook,
const WorkSpace *workspace)
{
@@ -588,17 +557,6 @@ WorkSpaceLayout *BKE_workspace_active_layout_for_workspace_get(const WorkSpaceIn
return workspace_relation_get_data_matching_parent(&workspace->hook_layout_relations, hook);
}
-/**
- * \brief Activate a layout
- *
- * Sets \a layout as active for \a workspace when activated through or already active in \a hook.
- * So when the active workspace of \a hook is \a workspace, \a layout becomes the active layout of
- * \a hook too. See #BKE_workspace_active_set().
- *
- * \a workspace does not need to be active for this.
- *
- * WorkSpaceInstanceHook.act_layout should only be modified directly to update the layout pointer.
- */
void BKE_workspace_active_layout_set(WorkSpaceInstanceHook *hook,
const int winid,
WorkSpace *workspace,
diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c
index 2f0a282a298..b2e90b7ba12 100644
--- a/source/blender/blenkernel/intern/world.c
+++ b/source/blender/blenkernel/intern/world.c
@@ -192,6 +192,7 @@ IDTypeInfo IDType_ID_WO = {
.name_plural = "worlds",
.translation_context = BLT_I18NCONTEXT_ID_WORLD,
.flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = world_init_data,
.copy_data = world_copy_data,
@@ -199,6 +200,7 @@ IDTypeInfo IDType_ID_WO = {
.make_local = NULL,
.foreach_id = world_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = world_blend_write,
diff --git a/source/blender/blenkernel/intern/writeavi.c b/source/blender/blenkernel/intern/writeavi.c
index 4635db98514..a4f20f980b4 100644
--- a/source/blender/blenkernel/intern/writeavi.c
+++ b/source/blender/blenkernel/intern/writeavi.c
@@ -315,7 +315,6 @@ static void context_free_avi(void *context_v)
#endif /* WITH_AVI */
-/* similar to BKE_image_path_from_imformat() */
void BKE_movie_filepath_get(char *string, const RenderData *rd, bool preview, const char *suffix)
{
bMovieHandle *mh = BKE_movie_handle_get(rd->im_format.imtype);
diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c
index a20c918c517..035e56993f9 100644
--- a/source/blender/blenkernel/intern/writeffmpeg.c
+++ b/source/blender/blenkernel/intern/writeffmpeg.c
@@ -87,6 +87,7 @@ typedef struct FFMpegContext {
AVStream *video_stream;
AVStream *audio_stream;
AVFrame *current_frame; /* Image frame in output pixel format. */
+ int video_time;
/* Image frame in Blender's own pixel format, may need conversion to the output pixel format. */
AVFrame *img_convert_frame;
@@ -96,6 +97,7 @@ typedef struct FFMpegContext {
uint8_t *audio_deinterleave_buffer;
int audio_input_samples;
double audio_time;
+ double audio_time_total;
bool audio_deinterleave;
int audio_sample_size;
@@ -318,14 +320,15 @@ static const char **get_file_extensions(int format)
}
/* Write a frame to the output file */
-static int write_video_frame(FFMpegContext *context, int cfra, AVFrame *frame, ReportList *reports)
+static int write_video_frame(FFMpegContext *context, AVFrame *frame, ReportList *reports)
{
int ret, success = 1;
AVPacket *packet = av_packet_alloc();
AVCodecContext *c = context->video_codec;
- frame->pts = cfra;
+ frame->pts = context->video_time;
+ context->video_time++;
ret = avcodec_send_frame(c, frame);
if (ret < 0) {
@@ -804,6 +807,8 @@ static AVStream *alloc_video_stream(FFMpegContext *context,
avcodec_parameters_from_context(st->codecpar, c);
+ context->video_time = 0.0f;
+
return st;
}
@@ -1397,9 +1402,10 @@ static void write_audio_frames(FFMpegContext *context, double to_pts)
AVCodecContext *c = context->audio_codec;
while (context->audio_stream) {
- if ((context->audio_time >= to_pts) || !write_audio_frame(context)) {
+ if ((context->audio_time_total >= to_pts) || !write_audio_frame(context)) {
break;
}
+ context->audio_time_total += (double)context->audio_input_samples / (double)c->sample_rate;
context->audio_time += (double)context->audio_input_samples / (double)c->sample_rate;
}
}
@@ -1423,22 +1429,23 @@ int BKE_ffmpeg_append(void *context_v,
if (context->video_stream) {
avframe = generate_video_frame(context, (unsigned char *)pixels);
- success = (avframe && write_video_frame(context, frame - start_frame, avframe, reports));
+ success = (avframe && write_video_frame(context, avframe, reports));
+# ifdef WITH_AUDASPACE
+ /* Add +1 frame because we want to encode audio up until the next video frame. */
+ write_audio_frames(
+ context, (frame - start_frame + 1) / (((double)rd->frs_sec) / (double)rd->frs_sec_base));
+# endif
if (context->ffmpeg_autosplit) {
if (avio_tell(context->outfile->pb) > FFMPEG_AUTOSPLIT_SIZE) {
end_ffmpeg_impl(context, true);
context->ffmpeg_autosplit_count++;
+
success &= start_ffmpeg_impl(context, rd, rectx, recty, suffix, reports);
}
}
}
-# ifdef WITH_AUDASPACE
- /* Add +1 frame because we want to encode audio up until the next video frame. */
- write_audio_frames(
- context, (frame - start_frame + 1) / (((double)rd->frs_sec) / (double)rd->frs_sec_base));
-# endif
return success;
}
@@ -1881,6 +1888,7 @@ void *BKE_ffmpeg_context_create(void)
context->ffmpeg_autosplit_count = 0;
context->ffmpeg_preview = false;
context->stamp_data = NULL;
+ context->audio_time_total = 0.0;
return context;
}
diff --git a/source/blender/blenkernel/nla_private.h b/source/blender/blenkernel/nla_private.h
index 3e13ba602a4..93014c1b859 100644
--- a/source/blender/blenkernel/nla_private.h
+++ b/source/blender/blenkernel/nla_private.h
@@ -165,18 +165,30 @@ typedef struct NlaKeyframingContext {
/* --------------- NLA Functions (not to be used as a proper API) ----------------------- */
-/* convert from strip time <-> global time */
+/**
+ * Convert non clipped mapping for strip-time <-> global time:
+ * `mode = eNlaTime_ConvertModes[] -> NLATIME_CONVERT_*`
+ *
+ * Only secure for 'internal' (i.e. within AnimSys evaluation) operations,
+ * but should not be directly relied on for stuff which interacts with editors.
+ */
float nlastrip_get_frame(NlaStrip *strip, float cframe, short mode);
/* --------------- NLA Evaluation (very-private stuff) ----------------------- */
/* these functions are only defined here to avoid problems with the order
* in which they get defined. */
+/**
+ * Gets the strip active at the current time for a list of strips for evaluation purposes.
+ */
NlaEvalStrip *nlastrips_ctime_get_strip(ListBase *list,
ListBase *strips,
short index,
const struct AnimationEvalContext *anim_eval_context,
const bool flush_to_original);
+/**
+ * Evaluates the given evaluation strip.
+ */
void nlastrip_evaluate(PointerRNA *ptr,
NlaEvalData *channels,
ListBase *modifiers,
@@ -184,6 +196,9 @@ void nlastrip_evaluate(PointerRNA *ptr,
NlaEvalSnapshot *snapshot,
const struct AnimationEvalContext *anim_eval_context,
const bool flush_to_original);
+/**
+ * write the accumulated settings to.
+ */
void nladata_flush_channels(PointerRNA *ptr,
NlaEvalData *channels,
NlaEvalSnapshot *snapshot,
@@ -193,6 +208,14 @@ void nlasnapshot_enable_all_blend_domain(NlaEvalSnapshot *snapshot);
void nlasnapshot_ensure_channels(NlaEvalData *eval_data, NlaEvalSnapshot *snapshot);
+/**
+ * Blends the \a lower_snapshot with the \a upper_snapshot into \a r_blended_snapshot according
+ * to the given \a upper_blendmode and \a upper_influence.
+ *
+ * For \a upper_snapshot, blending limited to values in the \a blend_domain.
+ * For Replace blend-mode, this allows the upper snapshot to have a location XYZ channel
+ * where only a subset of values are blended.
+ */
void nlasnapshot_blend(NlaEvalData *eval_data,
NlaEvalSnapshot *lower_snapshot,
NlaEvalSnapshot *upper_snapshot,
@@ -200,6 +223,14 @@ void nlasnapshot_blend(NlaEvalData *eval_data,
const float upper_influence,
NlaEvalSnapshot *r_blended_snapshot);
+/**
+ * Using \a blended_snapshot and \a lower_snapshot, we can solve for the \a r_upper_snapshot.
+ *
+ * Only channels that exist within \a blended_snapshot are inverted.
+ *
+ * For \a r_upper_snapshot, disables \a NlaEvalChannelSnapshot->remap_domain for failed inversions.
+ * Only values within the \a remap_domain are processed.
+ */
void nlasnapshot_blend_get_inverted_upper_snapshot(NlaEvalData *eval_data,
NlaEvalSnapshot *lower_snapshot,
NlaEvalSnapshot *blended_snapshot,
diff --git a/source/blender/blenkernel/tracking_private.h b/source/blender/blenkernel/tracking_private.h
index 8de6ec93a7c..0c1f73fa4b6 100644
--- a/source/blender/blenkernel/tracking_private.h
+++ b/source/blender/blenkernel/tracking_private.h
@@ -78,12 +78,21 @@ void tracking_get_search_origin_frame_pixel(int frame_width,
const struct MovieTrackingMarker *marker,
float frame_pixel[2]);
+/**
+ * Each marker has 5 coordinates associated with it that get warped with
+ * tracking: the four corners ("pattern_corners"), and the center ("pos").
+ * This function puts those 5 points into the appropriate frame for tracking
+ * (the "search" coordinate frame).
+ */
void tracking_get_marker_coords_for_tracking(int frame_width,
int frame_height,
const struct MovieTrackingMarker *marker,
double search_pixel_x[5],
double search_pixel_y[5]);
+/**
+ * Inverse of #tracking_get_marker_coords_for_tracking.
+ */
void tracking_set_marker_coords_from_tracking(int frame_width,
int frame_height,
struct MovieTrackingMarker *marker,
@@ -92,11 +101,23 @@ void tracking_set_marker_coords_from_tracking(int frame_width,
/*********************** General purpose utility functions *************************/
+/**
+ * Place a disabled marker before or after specified ref_marker.
+ *
+ * If before is truth, disabled marker is placed before reference
+ * one, and it's placed after it otherwise.
+ *
+ * If there's already a marker at the frame where disabled one is expected to be placed,
+ * nothing will happen if overwrite is false.
+ */
void tracking_marker_insert_disabled(struct MovieTrackingTrack *track,
const struct MovieTrackingMarker *ref_marker,
bool before,
bool overwrite);
+/**
+ * Fill in Libmv C-API camera intrinsics options from tracking structure.
+ */
void tracking_cameraIntrinscisOptionsFromTracking(
struct MovieTracking *tracking,
int calibration_width,
@@ -109,17 +130,26 @@ void tracking_trackingCameraFromIntrinscisOptions(
struct libmv_TrackRegionOptions;
+/**
+ * Fill in libmv tracker options structure with settings need to be used to perform track.
+ */
void tracking_configure_tracker(const MovieTrackingTrack *track,
float *mask,
bool is_backwards,
struct libmv_TrackRegionOptions *options);
+/**
+ * Get previous keyframed marker.
+ */
struct MovieTrackingMarker *tracking_get_keyframed_marker(struct MovieTrackingTrack *track,
int current_frame,
bool backwards);
/*********************** Masking *************************/
+/**
+ * Region is in pixel space, relative to marker's center.
+ */
float *tracking_track_get_mask_for_region(int frame_width,
int frame_height,
const float region_min[2],
@@ -145,11 +175,13 @@ typedef struct TrackingImageAccessor {
SpinLock cache_lock;
} TrackingImageAccessor;
-/* Clips are used to access images of an actual footage.
+/**
+ * Clips are used to access images of an actual footage.
* Tracks are used to access masks associated with the tracks.
*
- * NOTE: Both clips and tracks arrays are copied into the image accessor. It means that the caller
- * is allowed to pass temporary arrays which are only valid during initialization. */
+ * \note Both clips and tracks arrays are copied into the image accessor. It means that the caller
+ * is allowed to pass temporary arrays which are only valid during initialization.
+ */
TrackingImageAccessor *tracking_image_accessor_new(MovieClip *clips[MAX_ACCESSOR_CLIP],
int num_clips,
MovieTrackingTrack **tracks,
diff --git a/source/blender/blenlib/BLI_array.h b/source/blender/blenlib/BLI_array.h
index 084f573e8c7..5b15bb979f5 100644
--- a/source/blender/blenlib/BLI_array.h
+++ b/source/blender/blenlib/BLI_array.h
@@ -28,7 +28,7 @@
/** \name Internal defines
* \{ */
-/** this returns the entire size of the array, including any buffering. */
+/** This returns the entire size of the array, including any buffering. */
#define _bli_array_totalsize_dynamic(arr) \
(((arr) == NULL) ? 0 : MEM_allocN_len(arr) / sizeof(*(arr)))
@@ -44,8 +44,12 @@
/**
* BLI_array.c
*
- * Doing the realloc in a macro isn't so simple,
+ * Doing the reallocation in a macro isn't so simple,
* so use a function the macros can use.
+ *
+ * This function is only to be called via macros.
+ *
+ * \note The caller must adjust \a arr_len
*/
void _bli_array_grow_func(void **arr_p,
const void *arr_static,
@@ -64,8 +68,9 @@ void _bli_array_grow_func(void **arr_p,
void *_##arr##_static = NULL
/**
- * this will use stack space, up to maxstatic array elements, before
- * switching to dynamic heap allocation */
+ * This will use stack space, up to `maxstatic` array elements,
+ * before switching to dynamic heap allocation.
+ */
#define BLI_array_staticdeclare(arr, maxstatic) \
int _##arr##_len = 0; \
char _##arr##_static[maxstatic * sizeof(*(arr))]
@@ -77,7 +82,8 @@ void _bli_array_grow_func(void **arr_p,
* Grow the array by a fixed number of items.
*
* Allow for a large 'num' value when the new size is more than double
- * to allocate the exact sized array. */
+ * to allocate the exact sized array.
+ */
#define BLI_array_reserve(arr, num) \
(void)((((void *)(arr) == NULL) && \
((void *)(_##arr##_static) != \
@@ -95,12 +101,16 @@ void _bli_array_grow_func(void **arr_p,
num, \
"BLI_array." #arr)))
-/** returns length of array */
+/**
+ * Returns length of array.
+ */
#define BLI_array_grow_items(arr, num) (BLI_array_reserve(arr, num), (_##arr##_len += num))
#define BLI_array_grow_one(arr) BLI_array_grow_items(arr, 1)
-/** appends an item to the array. */
+/**
+ * Appends an item to the array.
+ */
#define BLI_array_append(arr, item) \
((void)BLI_array_grow_one(arr), (void)(arr[_##arr##_len - 1] = item))
@@ -111,7 +121,9 @@ void _bli_array_grow_func(void **arr_p,
#define BLI_array_append_r(arr, item) \
((void)BLI_array_grow_one(arr), (void)(arr[_##arr##_len - 1] = item), (&arr[_##arr##_len - 1]))
-/** appends (grows) & returns a pointer to the uninitialized memory */
+/**
+ * Appends (grows) & returns a pointer to the uninitialized memory.
+ */
#define BLI_array_append_ret(arr) (BLI_array_reserve(arr, 1), &arr[(_##arr##_len++)])
#define BLI_array_free(arr) \
@@ -127,7 +139,8 @@ void _bli_array_grow_func(void **arr_p,
/**
* Resets the logical size of an array to zero, but doesn't
- * free the memory. */
+ * free the memory.
+ */
#define BLI_array_clear(arr) \
{ \
_##arr##_len = 0; \
@@ -135,30 +148,32 @@ void _bli_array_grow_func(void **arr_p,
((void)0)
/**
- * Set the length of the array, doesn't actually increase the allocated array
- * size. don't use this unless you know what you're doing. */
+ * Set the length of the array, doesn't actually increase the allocated array size.
+ * Don't use this unless you know what you're doing.
+ */
#define BLI_array_len_set(arr, len) \
{ \
_##arr##_len = (len); \
} \
((void)0)
-/** only to prevent unused warnings */
+/**
+ * Only to prevent unused warnings.
+ */
#define BLI_array_fake_user(arr) ((void)_##arr##_len, (void)_##arr##_static)
/** \} */
/* -------------------------------------------------------------------- */
/** \name Generic Array Utils
- * other useful defines
- * (unrelated to the main array macros)
*
+ * Other useful defines (unrelated to the main array macros).
* \{ */
/**
- * Not part of the 'API' but handy functions,
- * same purpose as #BLI_array_staticdeclare()
- * but use when the max size is known ahead of time */
+ * Not part of the 'API' but handy functions, same purpose as #BLI_array_staticdeclare()
+ * but use when the max size is known ahead of time.
+ */
#define BLI_array_fixedstack_declare(arr, maxstatic, realsize, allocstr) \
char _##arr##_static[maxstatic * sizeof(*(arr))]; \
const bool _##arr##_is_static = ((void *)_##arr##_static) != \
diff --git a/source/blender/blenlib/BLI_array_store.h b/source/blender/blenlib/BLI_array_store.h
index 78d718117ba..0be361d4ab9 100644
--- a/source/blender/blenlib/BLI_array_store.h
+++ b/source/blender/blenlib/BLI_array_store.h
@@ -28,25 +28,88 @@ extern "C" {
typedef struct BArrayState BArrayState;
typedef struct BArrayStore BArrayStore;
+/**
+ * Create a new array store, which can store any number of arrays
+ * as long as their stride matches.
+ *
+ * \param stride: `sizeof()` each element,
+ *
+ * \note while a stride of `1` will always work,
+ * its less efficient since duplicate chunks of memory will be searched
+ * at positions unaligned with the array data.
+ *
+ * \param chunk_count: Number of elements to split each chunk into.
+ * - A small value increases the ability to de-duplicate chunks,
+ * but adds overhead by increasing the number of chunks to look up when searching for duplicates,
+ * as well as some overhead constructing the original array again, with more calls to `memcpy`.
+ * - Larger values reduce the *book keeping* overhead,
+ * but increase the chance a small,
+ * isolated change will cause a larger amount of data to be duplicated.
+ *
+ * \return A new array store, to be freed with #BLI_array_store_destroy.
+ */
BArrayStore *BLI_array_store_create(unsigned int stride, unsigned int chunk_count);
+/**
+ * Free the #BArrayStore, including all states and chunks.
+ */
void BLI_array_store_destroy(BArrayStore *bs);
+/**
+ * Clear all contents, allowing reuse of \a bs.
+ */
void BLI_array_store_clear(BArrayStore *bs);
-/* find the memory used by all states (expanded & real) */
+/**
+ * Find the memory used by all states (expanded & real).
+ *
+ * \return the total amount of memory that would be used by getting the arrays for all states.
+ */
size_t BLI_array_store_calc_size_expanded_get(const BArrayStore *bs);
+/**
+ * \return the amount of memory used by all #BChunk.data
+ * (duplicate chunks are only counted once).
+ */
size_t BLI_array_store_calc_size_compacted_get(const BArrayStore *bs);
+/**
+ *
+ * \param data: Data used to create
+ * \param state_reference: The state to use as a reference when adding the new state,
+ * typically this is the previous state,
+ * however it can be any previously created state from this \a bs.
+ *
+ * \return The new state,
+ * which is used by the caller as a handle to get back the contents of \a data.
+ * This may be removed using #BLI_array_store_state_remove,
+ * otherwise it will be removed with #BLI_array_store_destroy.
+ */
BArrayState *BLI_array_store_state_add(BArrayStore *bs,
const void *data,
const size_t data_len,
const BArrayState *state_reference);
+/**
+ * Remove a state and free any unused #BChunk data.
+ *
+ * The states can be freed in any order.
+ */
void BLI_array_store_state_remove(BArrayStore *bs, BArrayState *state);
+/**
+ * \return the expanded size of the array,
+ * use this to know how much memory to allocate #BLI_array_store_state_data_get's argument.
+ */
size_t BLI_array_store_state_size_get(BArrayState *state);
+/**
+ * Fill in existing allocated memory with the contents of \a state.
+ */
void BLI_array_store_state_data_get(BArrayState *state, void *data);
+/**
+ * Allocate an array for \a state and return it.
+ */
void *BLI_array_store_state_data_get_alloc(BArrayState *state, size_t *r_data_len);
-/* only for tests */
+/**
+ * \note Only for tests.
+ */
bool BLI_array_store_is_valid(BArrayStore *bs);
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_array_utils.h b/source/blender/blenlib/BLI_array_utils.h
index 52d41173a0e..eb14b030bf9 100644
--- a/source/blender/blenlib/BLI_array_utils.h
+++ b/source/blender/blenlib/BLI_array_utils.h
@@ -28,12 +28,29 @@
extern "C" {
#endif
+/**
+ * In-place array reverse.
+ *
+ * Access via #BLI_array_reverse
+ */
void _bli_array_reverse(void *arr, uint arr_len, size_t arr_stride);
#define BLI_array_reverse(arr, arr_len) _bli_array_reverse(arr, arr_len, sizeof(*(arr)))
+/**
+ * In-place array wrap.
+ * (rotate the array one step forward or backwards).
+ *
+ * Access via #BLI_array_wrap
+ */
void _bli_array_wrap(void *arr, uint arr_len, size_t arr_stride, int dir);
#define BLI_array_wrap(arr, arr_len, dir) _bli_array_wrap(arr, arr_len, sizeof(*(arr)), dir)
+/**
+ *In-place array permute.
+ * (re-arrange elements based on an array of indices).
+ *
+ * Access via #BLI_array_wrap
+ */
void _bli_array_permute(
void *arr, const uint arr_len, const size_t arr_stride, const uint *order, void *arr_temp);
#define BLI_array_permute(arr, arr_len, order) \
@@ -41,13 +58,30 @@ void _bli_array_permute(
#define BLI_array_permute_ex(arr, arr_len, order, arr_temp) \
_bli_array_permute(arr, arr_len, sizeof(*(arr)), order, arr_temp)
+/**
+ * In-place array de-duplication of an ordered array.
+ *
+ * \return The new length of the array.
+ *
+ * Access via #BLI_array_deduplicate_ordered
+ */
uint _bli_array_deduplicate_ordered(void *arr, uint arr_len, size_t arr_stride);
#define BLI_array_deduplicate_ordered(arr, arr_len) \
_bli_array_deduplicate_ordered(arr, arr_len, sizeof(*(arr)))
+/**
+ * Find the first index of an item in an array.
+ *
+ * Access via #BLI_array_findindex
+ *
+ * \note Not efficient, use for error checks/asserts.
+ */
int _bli_array_findindex(const void *arr, uint arr_len, size_t arr_stride, const void *p);
#define BLI_array_findindex(arr, arr_len, p) _bli_array_findindex(arr, arr_len, sizeof(*(arr)), p)
+/**
+ * A version of #BLI_array_findindex that searches from the end of the list.
+ */
int _bli_array_rfindindex(const void *arr, uint arr_len, size_t arr_stride, const void *p);
#define BLI_array_rfindindex(arr, arr_len, p) \
_bli_array_rfindindex(arr, arr_len, sizeof(*(arr)), p)
@@ -66,6 +100,22 @@ void _bli_array_binary_or(
CHECK_TYPE_PAIR_INLINE(*(arr), *(arr_b)), \
_bli_array_binary_or(arr, arr_a, arr_b, arr_len, sizeof(*(arr))))
+/**
+ * Utility function to iterate over contiguous items in an array.
+ *
+ * \param use_wrap: Detect contiguous ranges across the first/last points.
+ * In this case the second index of \a span_step may be lower than the first,
+ * which indicates the values are wrapped.
+ * \param use_delimit_bounds: When false,
+ * ranges that defined by the start/end indices are excluded.
+ * This option has no effect when \a use_wrap is enabled.
+ * \param test_fn: Function to test if the item should be included in the range.
+ * \param user_data: User data for \a test_fn.
+ * \param span_step: Indices to iterate over,
+ * initialize both values to the array length to initialize iteration.
+ * \param r_span_len: The length of the span, useful when \a use_wrap is enabled,
+ * where calculating the length isn't a simple subtraction.
+ */
bool _bli_array_iter_span(const void *arr,
uint arr_len,
size_t arr_stride,
@@ -87,9 +137,19 @@ bool _bli_array_iter_span(const void *arr,
span_step, \
r_span_len)
+/**
+ * Simple utility to check memory is zeroed.
+ */
bool _bli_array_is_zeroed(const void *arr, uint arr_len, size_t arr_stride);
#define BLI_array_is_zeroed(arr, arr_len) _bli_array_is_zeroed(arr, arr_len, sizeof(*(arr)))
+/**
+ * Smart function to sample a rectangle spiraling outside.
+ * Nice for selection ID.
+ *
+ * \param arr_shape: dimensions [w, h].
+ * \param center: coordinates [x, y] indicating where to start traversing.
+ */
bool _bli_array_iter_spiral_square(const void *arr_v,
const int arr_shape[2],
const size_t elem_size,
diff --git a/source/blender/blenlib/BLI_astar.h b/source/blender/blenlib/BLI_astar.h
index fe5c4ddad69..a1d4e28dad9 100644
--- a/source/blender/blenlib/BLI_astar.h
+++ b/source/blender/blenlib/BLI_astar.h
@@ -76,18 +76,52 @@ typedef struct BLI_AStarGraph {
struct MemArena *mem; /* Memory arena. */
} BLI_AStarGraph;
+/**
+ * Initialize a node in A* graph.
+ *
+ * \param custom_data: an opaque pointer attached to this link,
+ * available e.g. to cost callback function.
+ */
void BLI_astar_node_init(BLI_AStarGraph *as_graph, const int node_index, void *custom_data);
+/**
+ * Add a link between two nodes of our A* graph.
+ *
+ * \param cost: The 'length' of the link
+ * (actual distance between two vertices or face centers e.g.).
+ * \param custom_data: An opaque pointer attached to this link,
+ * available e.g. to cost callback function.
+ */
void BLI_astar_node_link_add(BLI_AStarGraph *as_graph,
const int node1_index,
const int node2_index,
const float cost,
void *custom_data);
+/**
+ * \return The index of the other node of given link.
+ */
int BLI_astar_node_link_other_node(BLI_AStarGNLink *lnk, const int idx);
+/**
+ * Initialize a solution data for given A* graph. Does not compute anything!
+ *
+ * \param custom_data: an opaque pointer attached to this link, available e.g
+ * . to cost callback function.
+ *
+ * \note BLI_AStarSolution stores nearly all data needed during solution compute.
+ */
void BLI_astar_solution_init(BLI_AStarGraph *as_graph,
BLI_AStarSolution *as_solution,
void *custom_data);
+/**
+ * Clear given solution's data, but does not release its memory.
+ * Avoids having to recreate/allocate a memarena in loops, e.g.
+ *
+ * \note This *has to be called* between each path solving.
+ */
void BLI_astar_solution_clear(BLI_AStarSolution *as_solution);
+/**
+ * Release the memory allocated for this solution.
+ */
void BLI_astar_solution_free(BLI_AStarSolution *as_solution);
/**
@@ -108,8 +142,24 @@ typedef float (*astar_f_cost)(BLI_AStarGraph *as_graph,
const int node_idx_next,
const int node_idx_dst);
+/**
+ * Initialize an A* graph. Total number of nodes must be known.
+ *
+ * Nodes might be e.g. vertices, faces, ... etc.
+ *
+ * \param custom_data: an opaque pointer attached to this link,
+ * available e.g. to cost callback function.
+ */
void BLI_astar_graph_init(BLI_AStarGraph *as_graph, const int node_num, void *custom_data);
void BLI_astar_graph_free(BLI_AStarGraph *as_graph);
+/**
+ * Solve a path in given graph, using given 'cost' callback function.
+ *
+ * \param max_steps: maximum number of nodes the found path may have.
+ * Useful in performance-critical usages.
+ * If no path is found within given steps, returns false too.
+ * \return true if a path was found, false otherwise.
+ */
bool BLI_astar_graph_solve(BLI_AStarGraph *as_graph,
const int node_index_src,
const int node_index_dst,
diff --git a/source/blender/blenlib/BLI_bitmap.h b/source/blender/blenlib/BLI_bitmap.h
index c97be6eed3c..b5ef08e9e60 100644
--- a/source/blender/blenlib/BLI_bitmap.h
+++ b/source/blender/blenlib/BLI_bitmap.h
@@ -40,26 +40,38 @@ typedef unsigned int BLI_bitmap;
/* 0b11111 */
#define _BITMAP_MASK 31
-/* number of blocks needed to hold '_tot' bits */
+/**
+ * Number of blocks needed to hold '_tot' bits.
+ */
#define _BITMAP_NUM_BLOCKS(_tot) (((_tot) >> _BITMAP_POWER) + 1)
-/* size (in bytes) used to hold '_tot' bits */
+/**
+ * Size (in bytes) used to hold '_tot' bits.
+ */
#define BLI_BITMAP_SIZE(_tot) ((size_t)(_BITMAP_NUM_BLOCKS(_tot)) * sizeof(BLI_bitmap))
-/* allocate memory for a bitmap with '_tot' bits; free with MEM_freeN() */
+/**
+ * Allocate memory for a bitmap with '_tot' bits; free with MEM_freeN().
+ */
#define BLI_BITMAP_NEW(_tot, _alloc_string) \
((BLI_bitmap *)MEM_callocN(BLI_BITMAP_SIZE(_tot), _alloc_string))
-/* allocate a bitmap on the stack */
+/**
+ * Allocate a bitmap on the stack.
+ */
#define BLI_BITMAP_NEW_ALLOCA(_tot) \
((BLI_bitmap *)memset(alloca(BLI_BITMAP_SIZE(_tot)), 0, BLI_BITMAP_SIZE(_tot)))
-/* Allocate using given MemArena */
+/**
+ * Allocate using given MemArena.
+ */
#define BLI_BITMAP_NEW_MEMARENA(_mem, _tot) \
(CHECK_TYPE_INLINE(_mem, MemArena *), \
((BLI_bitmap *)BLI_memarena_calloc(_mem, BLI_BITMAP_SIZE(_tot))))
-/* get the value of a single bit at '_index' */
+/**
+ * Get the value of a single bit at '_index'.
+ */
#define BLI_BITMAP_TEST(_bitmap, _index) \
(CHECK_TYPE_ANY(_bitmap, BLI_bitmap *, const BLI_bitmap *), \
((_bitmap)[(_index) >> _BITMAP_POWER] & (1u << ((_index)&_BITMAP_MASK))))
@@ -74,22 +86,30 @@ typedef unsigned int BLI_bitmap;
(CHECK_TYPE_ANY(_bitmap, BLI_bitmap *, const BLI_bitmap *), \
(BLI_BITMAP_TEST(_bitmap, _index) != 0))
-/* set the value of a single bit at '_index' */
+/**
+ * Set the value of a single bit at '_index'.
+ */
#define BLI_BITMAP_ENABLE(_bitmap, _index) \
(CHECK_TYPE_ANY(_bitmap, BLI_bitmap *, const BLI_bitmap *), \
((_bitmap)[(_index) >> _BITMAP_POWER] |= (1u << ((_index)&_BITMAP_MASK))))
-/* clear the value of a single bit at '_index' */
+/**
+ * Clear the value of a single bit at '_index'.
+ */
#define BLI_BITMAP_DISABLE(_bitmap, _index) \
(CHECK_TYPE_ANY(_bitmap, BLI_bitmap *, const BLI_bitmap *), \
((_bitmap)[(_index) >> _BITMAP_POWER] &= ~(1u << ((_index)&_BITMAP_MASK))))
-/* flip the value of a single bit at '_index' */
+/**
+ * Flip the value of a single bit at '_index'.
+ */
#define BLI_BITMAP_FLIP(_bitmap, _index) \
(CHECK_TYPE_ANY(_bitmap, BLI_bitmap *, const BLI_bitmap *), \
((_bitmap)[(_index) >> _BITMAP_POWER] ^= (1u << ((_index)&_BITMAP_MASK))))
-/* set or clear the value of a single bit at '_index' */
+/**
+ * Set or clear the value of a single bit at '_index'.
+ */
#define BLI_BITMAP_SET(_bitmap, _index, _set) \
{ \
CHECK_TYPE(_bitmap, BLI_bitmap *); \
@@ -102,7 +122,9 @@ typedef unsigned int BLI_bitmap;
} \
(void)0
-/* resize bitmap to have space for '_tot' bits */
+/**
+ * Resize bitmap to have space for '_tot' bits.
+ */
#define BLI_BITMAP_RESIZE(_bitmap, _tot) \
{ \
CHECK_TYPE(_bitmap, BLI_bitmap *); \
@@ -110,10 +132,25 @@ typedef unsigned int BLI_bitmap;
} \
(void)0
+/**
+ * Set or clear all bits in the bitmap.
+ */
void BLI_bitmap_set_all(BLI_bitmap *bitmap, bool set, size_t bits);
+/**
+ * Invert all bits in the bitmap.
+ */
void BLI_bitmap_flip_all(BLI_bitmap *bitmap, size_t bits);
+/**
+ * Copy all bits from one bitmap to another.
+ */
void BLI_bitmap_copy_all(BLI_bitmap *dst, const BLI_bitmap *src, size_t bits);
+/**
+ * Combine two bitmaps with boolean AND.
+ */
void BLI_bitmap_and_all(BLI_bitmap *dst, const BLI_bitmap *src, size_t bits);
+/**
+ * Combine two bitmaps with boolean OR.
+ */
void BLI_bitmap_or_all(BLI_bitmap *dst, const BLI_bitmap *src, size_t bits);
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_bitmap_draw_2d.h b/source/blender/blenlib/BLI_bitmap_draw_2d.h
index 8331d8fac08..1b9ff2162e3 100644
--- a/source/blender/blenlib/BLI_bitmap_draw_2d.h
+++ b/source/blender/blenlib/BLI_bitmap_draw_2d.h
@@ -24,17 +24,37 @@
extern "C" {
#endif
+/**
+ * Plot a line from \a p1 to \a p2 (inclusive).
+ *
+ * \note For clipped line drawing, see: http://stackoverflow.com/a/40902741/432509
+ */
void BLI_bitmap_draw_2d_line_v2v2i(const int p1[2],
const int p2[2],
bool (*callback)(int, int, void *),
void *user_data);
+/**
+ * \note Unclipped (clipped version can be added if needed).
+ */
void BLI_bitmap_draw_2d_tri_v2i(const int p1[2],
const int p2[2],
const int p3[2],
void (*callback)(int x, int x_end, int y, void *),
void *user_data);
+/**
+ * Draws a filled polygon with support for self intersections.
+ *
+ * \param callback: Takes the x, y coords and x-span (\a x_end is not inclusive),
+ * note that \a x_end will always be greater than \a x, so we can use:
+ *
+ * \code{.c}
+ * do {
+ * func(x, y);
+ * } while (++x != x_end);
+ * \endcode
+ */
void BLI_bitmap_draw_2d_poly_v2i_n(const int xmin,
const int ymin,
const int xmax,
diff --git a/source/blender/blenlib/BLI_boxpack_2d.h b/source/blender/blenlib/BLI_boxpack_2d.h
index 7e347d0b0d7..e743424db59 100644
--- a/source/blender/blenlib/BLI_boxpack_2d.h
+++ b/source/blender/blenlib/BLI_boxpack_2d.h
@@ -44,6 +44,20 @@ typedef struct BoxPack {
int index;
} BoxPack;
+/**
+ * Main box-packing function accessed from other functions
+ * This sets boxes x,y to positive values, sorting from 0,0 outwards.
+ * There is no limit to the space boxes may take, only that they will be packed
+ * tightly into the lower left hand corner (0,0)
+ *
+ * \param boxarray: a pre-allocated array of boxes.
+ * only the 'box->x' and 'box->y' are set, 'box->w' and 'box->h' are used,
+ * 'box->index' is not used at all, the only reason its there
+ * is that the box array is sorted by area and programs need to be able
+ * to have some way of writing the boxes back to the original data.
+ * \param len: the number of boxes in the array.
+ * \param r_tot_x, r_tot_y: set so you can normalize the data.
+ */
void BLI_box_pack_2d(BoxPack *boxarray, const unsigned int len, float *r_tot_x, float *r_tot_y);
typedef struct FixedSizeBoxPack {
@@ -52,6 +66,21 @@ typedef struct FixedSizeBoxPack {
int w, h;
} FixedSizeBoxPack;
+/**
+ * Packs boxes into a fixed area.
+ *
+ * Boxes and packed are linked lists containing structs that can be cast to
+ * #FixedSizeBoxPack (i.e. contains a #FixedSizeBoxPack as its first element).
+ * Boxes that were packed successfully are placed into *packed and removed from *boxes.
+ *
+ * The algorithm is a simplified version of https://github.com/TeamHypersomnia/rectpack2D.
+ * Better ones could be used, but for the current use case (packing Image tiles into GPU
+ * textures) this is fine.
+ *
+ * Note that packing efficiency depends on the order of the input boxes. Generally speaking,
+ * larger boxes should come first, though how exactly size is best defined (e.g. area, perimeter)
+ * depends on the particular application.
+ */
void BLI_box_pack_2d_fixedarea(struct ListBase *boxes,
int width,
int height,
diff --git a/source/blender/blenlib/BLI_buffer.h b/source/blender/blenlib/BLI_buffer.h
index 9d66fe9a14e..7f577443cf7 100644
--- a/source/blender/blenlib/BLI_buffer.h
+++ b/source/blender/blenlib/BLI_buffer.h
@@ -71,13 +71,25 @@ enum {
} \
(void)0
-/* Never decreases the amount of memory allocated */
+/**
+ * \note Never decreases the amount of memory allocated.
+ */
void BLI_buffer_resize(BLI_Buffer *buffer, const size_t new_count);
-/* Ensure size, throwing away old data, respecting BLI_BUFFER_USE_CALLOC */
+/**
+ * Ensure size, throwing away old data, respecting #BLI_BUFFER_USE_CALLOC.
+ *
+ * Similar to #BLI_buffer_resize, but use when the existing data can be:
+ * - Ignored (malloc'd).
+ * - Cleared (when #BLI_BUFFER_USE_CALLOC is set).
+ */
void BLI_buffer_reinit(BLI_Buffer *buffer, const size_t new_count);
-/* Append an array of elements. */
+/**
+ * Append an array of elements.
+ *
+ * Callers use #BLI_buffer_append_array.
+ */
void _bli_buffer_append_array(BLI_Buffer *buffer, void *data, size_t count);
#define BLI_buffer_append_array(buffer_, type_, data_, count_) \
{ \
@@ -87,7 +99,11 @@ void _bli_buffer_append_array(BLI_Buffer *buffer, void *data, size_t count);
} \
(void)0
-/* Does not free the buffer structure itself */
+/**
+ * Does not free the buffer structure itself.
+ *
+ * Callers use #BLI_buffer_free.
+ */
void _bli_buffer_free(BLI_Buffer *buffer);
#define BLI_buffer_free(name_) \
{ \
@@ -96,7 +112,9 @@ void _bli_buffer_free(BLI_Buffer *buffer);
} \
(void)0
-/* A buffer embedded in a struct. Using memcpy is allowed until first resize. */
+/**
+ * A buffer embedded in a struct. Using #memcpy is allowed until first resize.
+ */
#define BLI_buffer_field_init(name_, type_) \
{ \
memset(name_, 0, sizeof(*name_)); \
diff --git a/source/blender/blenlib/BLI_convexhull_2d.h b/source/blender/blenlib/BLI_convexhull_2d.h
index e930117822f..44758fb3880 100644
--- a/source/blender/blenlib/BLI_convexhull_2d.h
+++ b/source/blender/blenlib/BLI_convexhull_2d.h
@@ -24,10 +24,43 @@
extern "C" {
#endif
+/**
+ * A.M. Andrew's monotone chain 2D convex hull algorithm.
+ *
+ * \param points: An array of 2D points presorted by increasing x and y-coords.
+ * \param n: The number of points in points.
+ * \param r_points: An array of the convex hull vertex indices (max is n).
+ * \returns the number of points in r_points.
+ */
int BLI_convexhull_2d_sorted(const float (*points)[2], const int n, int r_points[]);
+/**
+ * A.M. Andrew's monotone chain 2D convex hull algorithm.
+ *
+ * \param points: An array of 2D points.
+ * \param n: The number of points in points.
+ * \param r_points: An array of the convex hull vertex indices (max is n).
+ * _must_ be allocated as `n * 2` because of how its used internally,
+ * even though the final result will be no more than \a n in size.
+ * \returns the number of points in r_points.
+ */
int BLI_convexhull_2d(const float (*points)[2], const int n, int r_points[]);
+/**
+ * \return The best angle for fitting the convex hull to an axis aligned bounding box.
+ *
+ * Intended to be used with #BLI_convexhull_2d
+ *
+ * \param points_hull: Ordered hull points
+ * (result of #BLI_convexhull_2d mapped to a contiguous array).
+ *
+ * \note we could return the index of the best edge too if its needed.
+ */
float BLI_convexhull_aabb_fit_hull_2d(const float (*points_hull)[2], unsigned int n);
+/**
+ * Wrap #BLI_convexhull_aabb_fit_hull_2d and do the convex hull calculation.
+ *
+ * \param points: arbitrary 2d points.
+ */
float BLI_convexhull_aabb_fit_points_2d(const float (*points)[2], unsigned int n);
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_dlrbTree.h b/source/blender/blenlib/BLI_dlrbTree.h
index 03aab8d2895..72f18244d5b 100644
--- a/source/blender/blenlib/BLI_dlrbTree.h
+++ b/source/blender/blenlib/BLI_dlrbTree.h
@@ -21,23 +21,24 @@
/** \file
* \ingroup bli
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Double-Linked Red-Black Tree Implementation:
+ *
+ * Double-Linked Red-Black Tree Implementation:
*
* This is simply a Red-Black Tree implementation whose nodes can later
* be arranged + retrieved as elements in a Double-Linked list (i.e. ListBase).
* The Red-Black Tree implementation is based on the methods defined by Wikipedia.
*/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* ********************************************** */
/* Data Types and Type Defines */
-/* Base Structs --------------------------------- */
+/* -------------------------------------------------------------------- */
+/** \name Base Structs
+ * \{ */
/* Basic Layout for a Node */
typedef struct DLRBT_Node {
@@ -69,101 +70,150 @@ typedef struct DLRBT_Tree {
void *root; /* this should be based on DLRBT_Node-s */
} DLRBT_Tree;
-/* Callback Types --------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Callback Types
+ * \{ */
-/* Return -1, 0, 1 for whether the given data is less than,
+/**
+ * Return -1, 0, 1 for whether the given data is less than,
* equal to, or greater than the given node.
- * - node: <DLRBT_Node> the node to compare to.
- * - data: pointer to the relevant data or values stored in the bit-pattern.
- * dependent on the function.
+ * \param node: <DLRBT_Node> the node to compare to.
+ * \param data: pointer to the relevant data or values stored in the bit-pattern.
+ * Dependent on the function.
*/
typedef short (*DLRBT_Comparator_FP)(void *node, void *data);
-/* Return a new node instance wrapping the given data
- * - data: Pointer to the relevant data to create a subclass of node from
+/**
+ * Return a new node instance wrapping the given data
+ * - data: Pointer to the relevant data to create a subclass of node from.
*/
typedef DLRBT_Node *(*DLRBT_NAlloc_FP)(void *data);
-/* Update an existing node instance accordingly to be in sync with the given data.
- * - node: <DLRBT_Node> the node to update.
- * - data: Pointer to the relevant data or values stored in the bit-pattern.
- * dependent on the function.
+/**
+ * Update an existing node instance accordingly to be in sync with the given data.
+ * \param node: <DLRBT_Node> the node to update.
+ * \param data: Pointer to the relevant data or values stored in the bit-pattern.
+ * Dependent on the function.
*/
typedef void (*DLRBT_NUpdate_FP)(void *node, void *data);
/* ********************************************** */
/* Public API */
-/* ADT Management ------------------------------- */
+/** \} */
-/* Create a new tree, and initialize as necessary */
+/* -------------------------------------------------------------------- */
+/** \name ADT Management
+ * \{ */
+
+/**
+ * Create a new tree, and initialize as necessary.
+ */
DLRBT_Tree *BLI_dlrbTree_new(void);
-/* Initializes some given trees */
+/**
+ * Initializes some given trees.
+ * Just zero out the pointers used.
+ */
void BLI_dlrbTree_init(DLRBT_Tree *tree);
-/* Free some tree */
+/**
+ * Free the given tree's data but not the tree itself.
+ */
void BLI_dlrbTree_free(DLRBT_Tree *tree);
-/* Make sure the tree's Double-Linked list representation is valid */
+/**
+ * Make sure the tree's Double-Linked list representation is valid.
+ */
void BLI_dlrbTree_linkedlist_sync(DLRBT_Tree *tree);
-/* Searching ------------------------------------ */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Tree Searching Utilities
+ * \{ */
-/* Find the node which matches or is the closest to the requested node */
+/**
+ * Find the node which matches or is the closest to the requested node.
+ */
DLRBT_Node *BLI_dlrbTree_search(const DLRBT_Tree *tree,
DLRBT_Comparator_FP cmp_cb,
void *search_data);
-/* Find the node which exactly matches the required data */
+/**
+ * Find the node which exactly matches the required data.
+ */
DLRBT_Node *BLI_dlrbTree_search_exact(const DLRBT_Tree *tree,
DLRBT_Comparator_FP cmp_cb,
void *search_data);
-/* Find the node which occurs immediately before the best matching node */
+/**
+ * Find the node which occurs immediately before the best matching node.
+ */
DLRBT_Node *BLI_dlrbTree_search_prev(const DLRBT_Tree *tree,
DLRBT_Comparator_FP cmp_cb,
void *search_data);
-/* Find the node which occurs immediately after the best matching node */
+/**
+ * Find the node which occurs immediately after the best matching node.
+ */
DLRBT_Node *BLI_dlrbTree_search_next(const DLRBT_Tree *tree,
DLRBT_Comparator_FP cmp_cb,
void *search_data);
-/* Check whether there is a node matching the requested node */
+/**
+ * Check whether there is a node matching the requested node.
+ */
short BLI_dlrbTree_contains(DLRBT_Tree *tree, DLRBT_Comparator_FP cmp_cb, void *search_data);
-/* Node Operations (Managed) --------------------- */
-/* These methods automate the process of adding/removing nodes from the BST,
- * using the supplied data and callbacks
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Node Operations (Managed)
+ * \{ */
+
+/**
+ * These methods automate the process of adding/removing nodes from the BST,
+ * using the supplied data and callbacks.
*/
-/* Add the given data to the tree, and return the node added */
-/* NOTE: for duplicates, the update_cb is called (if available),
- * and the existing node is returned. */
+/**
+ * Add the given data to the tree, and return the node added.
+ * \note for duplicates, the update_cb is called (if available),
+ * and the existing node is returned.
+ */
DLRBT_Node *BLI_dlrbTree_add(DLRBT_Tree *tree,
DLRBT_Comparator_FP cmp_cb,
DLRBT_NAlloc_FP new_cb,
DLRBT_NUpdate_FP update_cb,
void *data);
-/* Remove the given element from the tree and balance again */
-/* FIXME: this is not implemented yet... */
+/* FIXME: this is not implemented yet. */
+/**
+ * Remove the given element from the tree and balance again.
+ */
// void BLI_dlrbTree_remove(DLRBT_Tree *tree, DLRBT_Node *node);
-/* Node Operations (Manual) --------------------- */
-/* These methods require custom code for creating BST nodes and adding them to the
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Node Operations (Manual)
+ *
+ * These methods require custom code for creating BST nodes and adding them to the
* tree in special ways, such that the node can then be balanced.
*
- * It is recommended that these methods are only used where the other method is too cumbersome...
- */
+ * It is recommended that these methods are only used where the other method is too cumbersome.
+ * \{ */
-/* Balance the tree after the given node has been added to it
+/**
+ * Balance the tree after the given node has been added to it
* (using custom code, in the Binary Tree way).
*/
void BLI_dlrbTree_insert(DLRBT_Tree *tree, DLRBT_Node *node);
-/* ********************************************** */
+/** \} */
#ifdef __cplusplus
}
diff --git a/source/blender/blenlib/BLI_dynstr.h b/source/blender/blenlib/BLI_dynstr.h
index 4df773c7cc6..90d93f29bcb 100644
--- a/source/blender/blenlib/BLI_dynstr.h
+++ b/source/blender/blenlib/BLI_dynstr.h
@@ -39,25 +39,85 @@ extern "C" {
struct DynStr;
-/** The abstract DynStr type */
+/** The abstract DynStr type. */
typedef struct DynStr DynStr;
+/**
+ * Create a new #DynStr.
+ *
+ * \return Pointer to a new #DynStr.
+ */
DynStr *BLI_dynstr_new(void) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+/**
+ * Create a new #DynStr.
+ *
+ * \return Pointer to a new #DynStr.
+ */
DynStr *BLI_dynstr_new_memarena(void) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+/**
+ * Append a c-string to a #DynStr.
+ *
+ * \param ds: The #DynStr to append to.
+ * \param cstr: The c-string to append.
+ */
void BLI_dynstr_append(DynStr *__restrict ds, const char *cstr) ATTR_NONNULL();
+/**
+ * Append a length clamped c-string to a #DynStr.
+ *
+ * \param ds: The #DynStr to append to.
+ * \param cstr: The c-string to append.
+ * \param len: The maximum length of the c-string to copy.
+ */
void BLI_dynstr_nappend(DynStr *__restrict ds, const char *cstr, int len) ATTR_NONNULL();
+/**
+ * Append a c-string to a #DynStr, but with formatting like `printf`.
+ *
+ * \param ds: The #DynStr to append to.
+ * \param format: The `printf` format string to use.
+ */
void BLI_dynstr_appendf(DynStr *__restrict ds, const char *__restrict format, ...)
ATTR_PRINTF_FORMAT(2, 3) ATTR_NONNULL(1, 2);
void BLI_dynstr_vappendf(DynStr *__restrict ds, const char *__restrict format, va_list args)
ATTR_PRINTF_FORMAT(2, 0) ATTR_NONNULL(1, 2);
+/**
+ * Find the length of a #DynStr.
+ *
+ * \param ds: The #DynStr of interest.
+ * \return The length of \a ds.
+ */
int BLI_dynstr_get_len(const DynStr *ds) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Get a #DynStr's contents as a c-string.
+ * \return The c-string which must be freed using #MEM_freeN.
+ *
+ * \param ds: The #DynStr of interest.
+ * \return The contents of \a ds as a c-string.
+ */
char *BLI_dynstr_get_cstring(const DynStr *ds) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Get a #DynStr's contents as a c-string.
+ * The \a rets argument must be allocated to be at
+ * least the size of `BLI_dynstr_get_len(ds) + 1`.
+ *
+ * \param ds: The DynStr of interest.
+ * \param rets: The string to fill.
+ */
void BLI_dynstr_get_cstring_ex(const DynStr *__restrict ds, char *__restrict rets) ATTR_NONNULL();
+/**
+ * Clear the #DynStr
+ *
+ * \param ds: The DynStr to clear.
+ */
void BLI_dynstr_clear(DynStr *ds) ATTR_NONNULL();
+/**
+ * Free the #DynStr
+ *
+ * \param ds: The DynStr to free.
+ */
void BLI_dynstr_free(DynStr *ds) ATTR_NONNULL();
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_edgehash.h b/source/blender/blenlib/BLI_edgehash.h
index 41f0d41d1e0..b0f71655c19 100644
--- a/source/blender/blenlib/BLI_edgehash.h
+++ b/source/blender/blenlib/BLI_edgehash.h
@@ -48,42 +48,120 @@ typedef struct EdgeHashIterator {
typedef void (*EdgeHashFreeFP)(void *key);
enum {
- EDGEHASH_FLAG_ALLOW_DUPES = (1 << 0), /* only checked for in debug mode */
+ /**
+ * Only checked for in debug mode.
+ */
+ EDGEHASH_FLAG_ALLOW_DUPES = (1 << 0),
};
EdgeHash *BLI_edgehash_new_ex(const char *info, const unsigned int nentries_reserve);
EdgeHash *BLI_edgehash_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
void BLI_edgehash_free(EdgeHash *eh, EdgeHashFreeFP free_value);
void BLI_edgehash_print(EdgeHash *eh);
+/**
+ * Insert edge (\a v0, \a v1) into hash with given value, does
+ * not check for duplicates.
+ */
void BLI_edgehash_insert(EdgeHash *eh, unsigned int v0, unsigned int v1, void *val);
+/**
+ * Assign a new value to a key that may already be in edgehash.
+ */
bool BLI_edgehash_reinsert(EdgeHash *eh, unsigned int v0, unsigned int v1, void *val);
+/**
+ * Return value for given edge (\a v0, \a v1), or NULL if
+ * if key does not exist in hash. (If need exists
+ * to differentiate between key-value being NULL and
+ * lack of key then see #BLI_edgehash_lookup_p().
+ */
void *BLI_edgehash_lookup(const EdgeHash *eh,
unsigned int v0,
unsigned int v1) ATTR_WARN_UNUSED_RESULT;
+/**
+ * A version of #BLI_edgehash_lookup which accepts a fallback argument.
+ */
void *BLI_edgehash_lookup_default(const EdgeHash *eh,
unsigned int v0,
unsigned int v1,
void *default_value) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Return pointer to value for given edge (\a v0, \a v1),
+ * or NULL if key does not exist in hash.
+ */
void **BLI_edgehash_lookup_p(EdgeHash *eh,
unsigned int v0,
unsigned int v1) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Ensure \a (v0, v1) is exists in \a eh.
+ *
+ * This handles the common situation where the caller needs ensure a key is added to \a eh,
+ * constructing a new value in the case the key isn't found.
+ * Otherwise use the existing value.
+ *
+ * Such situations typically incur multiple lookups, however this function
+ * avoids them by ensuring the key is added,
+ * returning a pointer to the value so it can be used or initialized by the caller.
+ *
+ * \return true when the value didn't need to be added.
+ * (when false, the caller _must_ initialize the value).
+ */
bool BLI_edgehash_ensure_p(EdgeHash *eh, unsigned int v0, unsigned int v1, void ***r_val)
ATTR_WARN_UNUSED_RESULT;
+/**
+ * Remove \a key (v0, v1) from \a eh, or return false if the key wasn't found.
+ *
+ * \param v0, v1: The key to remove.
+ * \param free_value: Optional callback to free the value.
+ * \return true if \a key was removed from \a eh.
+ */
bool BLI_edgehash_remove(EdgeHash *eh,
unsigned int v0,
unsigned int v1,
EdgeHashFreeFP free_value);
+/**
+ * Remove \a key (v0, v1) from \a eh, returning the value or NULL if the key wasn't found.
+ *
+ * \param v0, v1: The key to remove.
+ * \return the value of \a key int \a eh or NULL.
+ */
void *BLI_edgehash_popkey(EdgeHash *eh, unsigned int v0, unsigned int v1) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Return boolean true/false if edge (v0,v1) in hash.
+ */
bool BLI_edgehash_haskey(const EdgeHash *eh,
unsigned int v0,
unsigned int v1) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Return number of keys in hash.
+ */
int BLI_edgehash_len(const EdgeHash *eh) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Remove all edges from hash.
+ */
void BLI_edgehash_clear_ex(EdgeHash *eh, EdgeHashFreeFP free_value, const uint reserve);
+/**
+ * Wraps #BLI_edgehash_clear_ex with zero entries reserved.
+ */
void BLI_edgehash_clear(EdgeHash *eh, EdgeHashFreeFP free_value);
+/**
+ * Create a new #EdgeHashIterator. The hash table must not be mutated
+ * while the iterator is in use, and the iterator will step exactly
+ * #BLI_edgehash_len(eh) times before becoming done.
+ */
EdgeHashIterator *BLI_edgehashIterator_new(EdgeHash *eh) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+/**
+ * Initialize an already allocated #EdgeHashIterator. The hash table must not
+ * be mutated while the iterator is in use, and the iterator will
+ * step exactly BLI_edgehash_len(eh) times before becoming done.
+ *
+ * \param ehi: The #EdgeHashIterator to initialize.
+ * \param eh: The #EdgeHash to iterate over.
+ */
void BLI_edgehashIterator_init(EdgeHashIterator *ehi, EdgeHash *eh);
+/**
+ * Free an #EdgeHashIterator.
+ */
void BLI_edgehashIterator_free(EdgeHashIterator *ehi);
BLI_INLINE void BLI_edgehashIterator_step(EdgeHashIterator *ehi)
@@ -133,7 +211,17 @@ EdgeSet *BLI_edgeset_new_ex(const char *info, const unsigned int nentries_reserv
ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
EdgeSet *BLI_edgeset_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
int BLI_edgeset_len(const EdgeSet *es) ATTR_WARN_UNUSED_RESULT;
+/**
+ * A version of BLI_edgeset_insert which checks first if the key is in the set.
+ * \returns true if a new key has been added.
+ *
+ * \note #EdgeHash has no equivalent to this because typically the value would be different.
+ */
bool BLI_edgeset_add(EdgeSet *es, unsigned int v0, unsigned int v1);
+/**
+ * Adds the key to the set (no checks for unique keys!).
+ * Matching #BLI_edgehash_insert
+ */
void BLI_edgeset_insert(EdgeSet *es, unsigned int v0, unsigned int v1);
bool BLI_edgeset_haskey(const EdgeSet *es,
unsigned int v0,
@@ -141,6 +229,7 @@ bool BLI_edgeset_haskey(const EdgeSet *es,
void BLI_edgeset_free(EdgeSet *es);
/* rely on inline api for now */
+
EdgeSetIterator *BLI_edgesetIterator_new(EdgeSet *es);
void BLI_edgesetIterator_free(EdgeSetIterator *esi);
diff --git a/source/blender/blenlib/BLI_expr_pylike_eval.h b/source/blender/blenlib/BLI_expr_pylike_eval.h
index c074b5d8130..dccb1863b4b 100644
--- a/source/blender/blenlib/BLI_expr_pylike_eval.h
+++ b/source/blender/blenlib/BLI_expr_pylike_eval.h
@@ -41,13 +41,35 @@ typedef enum eExprPyLike_EvalStatus {
EXPR_PYLIKE_FATAL_ERROR,
} eExprPyLike_EvalStatus;
+/**
+ * Free the parsed data; NULL argument is ok.
+ */
void BLI_expr_pylike_free(struct ExprPyLike_Parsed *expr);
+/**
+ * Check if the parsing result is valid for evaluation.
+ */
bool BLI_expr_pylike_is_valid(struct ExprPyLike_Parsed *expr);
+/**
+ * Check if the parsed expression always evaluates to the same value.
+ */
bool BLI_expr_pylike_is_constant(struct ExprPyLike_Parsed *expr);
+/**
+ * Check if the parsed expression uses the parameter with the given index.
+ */
bool BLI_expr_pylike_is_using_param(struct ExprPyLike_Parsed *expr, int index);
+/**
+ * Compile the expression and return the result.
+ *
+ * Parse the expression for evaluation later.
+ * Returns non-NULL even on failure; use is_valid to check.
+ */
ExprPyLike_Parsed *BLI_expr_pylike_parse(const char *expression,
const char **param_names,
int param_names_len);
+/**
+ * Evaluate the expression with the given parameters.
+ * The order and number of parameters must match the names given to parse.
+ */
eExprPyLike_EvalStatus BLI_expr_pylike_eval(struct ExprPyLike_Parsed *expr,
const double *param_values,
int param_values_len,
diff --git a/source/blender/blenlib/BLI_fileops.h b/source/blender/blenlib/BLI_fileops.h
index 906a56ce909..2ef9b8f6c36 100644
--- a/source/blender/blenlib/BLI_fileops.h
+++ b/source/blender/blenlib/BLI_fileops.h
@@ -45,19 +45,40 @@ extern "C" {
# define PATH_MAX 4096
#endif
-/* Common */
+/* -------------------------------------------------------------------- */
+/** \name Common
+ * \{ */
+/**
+ * Returns the st_mode from stat-ing the specified path name, or 0 if stat fails
+ * (most likely doesn't exist or no access).
+ */
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int BLI_copy(const char *file, const char *to) ATTR_NONNULL();
+/**
+ * \return zero on success (matching 'rename' behavior).
+ */
int BLI_rename(const char *from, const char *to) ATTR_NONNULL();
+/**
+ * Deletes the specified file or directory (depending on dir), optionally
+ * doing recursive delete of directory contents.
+ *
+ * \return zero on success (matching 'remove' behavior).
+ */
int BLI_delete(const char *file, bool dir, bool recursive) ATTR_NONNULL();
+/**
+ * Soft deletes the specified file or directory (depending on dir) by moving the files to the
+ * recycling bin, optionally doing recursive delete of directory contents.
+ *
+ * \return zero on success (matching 'remove' behavior).
+ */
int BLI_delete_soft(const char *file, const char **error_message) ATTR_NONNULL();
#if 0 /* Unused */
int BLI_move(const char *path, const char *to) ATTR_NONNULL();
int BLI_create_symlink(const char *path, const char *to) ATTR_NONNULL();
#endif
-/* keep in sync with the definition of struct direntry in BLI_fileops_types.h */
+/* Keep in sync with the definition of struct `direntry` in `BLI_fileops_types.h`. */
#ifdef WIN32
# if defined(_MSC_VER)
typedef struct _stat64 BLI_stat_t;
@@ -101,40 +122,102 @@ typedef enum eFileAttributes {
(FILE_ATTR_ALIAS | FILE_ATTR_REPARSE_POINT | FILE_ATTR_SYMLINK | FILE_ATTR_JUNCTION_POINT | \
FILE_ATTR_MOUNT_POINT | FILE_ATTR_HARDLINK)
-/* Directories */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Directories
+ * \{ */
struct direntry;
+/**
+ * Does the specified path point to a directory?
+ * \note Would be better in `fileops.c` except that it needs `stat.h` so add here.
+ */
bool BLI_is_dir(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Does the specified path point to a non-directory?
+ */
bool BLI_is_file(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * \return true on success (i.e. given path now exists on FS), false otherwise.
+ */
bool BLI_dir_create_recursive(const char *dir) ATTR_NONNULL();
+/**
+ * Returns the number of free bytes on the volume containing the specified pathname.
+ *
+ * \note Not actually used anywhere.
+ */
double BLI_dir_free_space(const char *dir) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Copies the current working directory into *dir (max size maxncpy), and
+ * returns a pointer to same.
+ *
+ * \note can return NULL when the size is not big enough
+ */
char *BLI_current_working_dir(char *dir, const size_t maxncpy) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
eFileAttributes BLI_file_attributes(const char *path);
-/* Filelist */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name File-List
+ * \{ */
+/**
+ * Scans the contents of the directory named *dirname, and allocates and fills in an
+ * array of entries describing them in *filelist.
+ *
+ * \return The length of filelist array.
+ */
unsigned int BLI_filelist_dir_contents(const char *dir, struct direntry **r_filelist);
+/**
+ * Deep-duplicate of a single direntry.
+ */
void BLI_filelist_entry_duplicate(struct direntry *dst, const struct direntry *src);
+/**
+ * Deep-duplicate of a #direntry array including the array itself.
+ */
void BLI_filelist_duplicate(struct direntry **dest_filelist,
struct direntry *const src_filelist,
const unsigned int nrentries);
+/**
+ * Frees storage for a single direntry, not the direntry itself.
+ */
void BLI_filelist_entry_free(struct direntry *entry);
+/**
+ * Frees storage for an array of #direntry, including the array itself.
+ */
void BLI_filelist_free(struct direntry *filelist, const unsigned int nrentries);
+/**
+ * Convert given entry's size into human-readable strings.
+ */
void BLI_filelist_entry_size_to_string(const struct stat *st,
const uint64_t sz,
const bool compact,
char r_size[FILELIST_DIRENTRY_SIZE_LEN]);
+/**
+ * Convert given entry's modes into human-readable strings.
+ */
void BLI_filelist_entry_mode_to_string(const struct stat *st,
const bool compact,
char r_mode1[FILELIST_DIRENTRY_MODE_LEN],
char r_mode2[FILELIST_DIRENTRY_MODE_LEN],
char r_mode3[FILELIST_DIRENTRY_MODE_LEN]);
+/**
+ * Convert given entry's owner into human-readable strings.
+ */
void BLI_filelist_entry_owner_to_string(const struct stat *st,
const bool compact,
char r_owner[FILELIST_DIRENTRY_OWNER_LEN]);
+/**
+ * Convert given entry's time into human-readable strings.
+ *
+ * \param r_is_today: optional, returns true if the date matches today's.
+ * \param r_is_yesterday: optional, returns true if the date matches yesterday's.
+ */
void BLI_filelist_entry_datetime_to_string(const struct stat *st,
const int64_t ts,
const bool compact,
@@ -143,14 +226,28 @@ void BLI_filelist_entry_datetime_to_string(const struct stat *st,
bool *r_is_today,
bool *r_is_yesterday);
-/* Files */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Files
+ * \{ */
FILE *BLI_fopen(const char *filename, const char *mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
void *BLI_gzopen(const char *filename, const char *mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int BLI_open(const char *filename, int oflag, int pmode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int BLI_access(const char *filename, int mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Returns true if the file with the specified name can be written.
+ * This implementation uses access(2), which makes the check according
+ * to the real UID and GID of the process, not its effective UID and GID.
+ * This shouldn't matter for Blender, which is not going to run privileged anyway.
+ */
bool BLI_file_is_writable(const char *file) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Creates the file with nothing in it, or updates its last-modified date if it already exists.
+ * Returns true if successful (like the unix touch command).
+ */
bool BLI_file_touch(const char *file) ATTR_NONNULL();
bool BLI_file_alias_target(const char *filepath, char *r_targetpath) ATTR_WARN_UNUSED_RESULT;
@@ -165,23 +262,75 @@ size_t BLI_file_unzstd_to_mem_at_pos(void *buf, size_t len, FILE *file, size_t f
ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BLI_file_magic_is_zstd(const char header[4]);
+/**
+ * Returns the file size of an opened file descriptor.
+ */
size_t BLI_file_descriptor_size(int file) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Returns the size of a file.
+ */
size_t BLI_file_size(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-/* compare if one was last modified before the other */
+/**
+ * Compare if one was last modified before the other.
+ *
+ * \return true when is `file1` older than `file2`.
+ */
bool BLI_file_older(const char *file1, const char *file2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-/* read ascii file as lines, empty list if reading fails */
+/**
+ * Reads the contents of a text file.
+ *
+ * \return the lines in a linked list (an empty list when file reading fails).
+ */
struct LinkNode *BLI_file_read_as_lines(const char *file) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
void *BLI_file_read_text_as_mem(const char *filepath, size_t pad_bytes, size_t *r_size);
+/**
+ * Return the text file data with:
+
+ * - Newlines replaced with '\0'.
+ * - Optionally trim white-space, replacing trailing <space> & <tab> with '\0'.
+ *
+ * This is an alternative to using #BLI_file_read_as_lines,
+ * allowing us to loop over lines without converting it into a linked list
+ * with individual allocations.
+ *
+ * \param trim_trailing_space: Replace trailing spaces & tabs with nil.
+ * This arguments prevents the caller from counting blank lines (if that's important).
+ * \param pad_bytes: When this is non-zero, the first byte is set to nil,
+ * to simplify parsing the file.
+ * It's recommended to pass in 1, so all text is nil terminated.
+ *
+ * Example looping over lines:
+ *
+ * \code{.c}
+ * size_t data_len;
+ * char *data = BLI_file_read_text_as_mem_with_newline_as_nil(filepath, true, 1, &data_len);
+ * char *data_end = data + data_len;
+ * for (char *line = data; line != data_end; line = strlen(line) + 1) {
+ * printf("line='%s'\n", line);
+ * }
+ * \endcode
+ */
void *BLI_file_read_text_as_mem_with_newline_as_nil(const char *filepath,
bool trim_trailing_space,
size_t pad_bytes,
size_t *r_size);
void *BLI_file_read_binary_as_mem(const char *filepath, size_t pad_bytes, size_t *r_size);
+/**
+ * Frees memory from a previous call to #BLI_file_read_as_lines.
+ */
void BLI_file_free_lines(struct LinkNode *lines);
-/* this weirdo pops up in two places ... */
+#ifdef __APPLE__
+/**
+ * Expand the leading `~` in the given path to `/Users/$USER`.
+ * This doesn't preserve the trailing path separator.
+ * Giving a path without leading `~` is not an error.
+ */
+const char *BLI_expand_tilde(const char *path_with_tilde);
+#endif
+/* This weirdo pops up in two places. */
#if !defined(WIN32)
# ifndef O_BINARY
# define O_BINARY 0
@@ -190,6 +339,8 @@ void BLI_file_free_lines(struct LinkNode *lines);
void BLI_get_short_name(char short_name[256], const char *filename);
#endif
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_ghash.h b/source/blender/blenlib/BLI_ghash.h
index a2c5c6349a5..0194f9aad40 100644
--- a/source/blender/blenlib/BLI_ghash.h
+++ b/source/blender/blenlib/BLI_ghash.h
@@ -43,6 +43,10 @@ extern "C" {
# endif
#endif
+/* -------------------------------------------------------------------- */
+/** \name GHash Types
+ * \{ */
+
typedef unsigned int (*GHashHashFP)(const void *key);
/** returns false when equal */
typedef bool (*GHashCmpFP)(const void *a, const void *b);
@@ -74,53 +78,191 @@ enum {
#endif
};
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name GHash API
*
* Defined in `BLI_ghash.c`
* \{ */
+/**
+ * Creates a new, empty GHash.
+ *
+ * \param hashfp: Hash callback.
+ * \param cmpfp: Comparison callback.
+ * \param info: Identifier string for the GHash.
+ * \param nentries_reserve: Optionally reserve the number of members that the hash will hold.
+ * Use this to avoid resizing buckets if the size is known or can be closely approximated.
+ * \return An empty GHash.
+ */
GHash *BLI_ghash_new_ex(GHashHashFP hashfp,
GHashCmpFP cmpfp,
const char *info,
const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+/**
+ * Wraps #BLI_ghash_new_ex with zero entries reserved.
+ */
GHash *BLI_ghash_new(GHashHashFP hashfp,
GHashCmpFP cmpfp,
const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+/**
+ * Copy given GHash. Keys and values are also copied if relevant callback is provided,
+ * else pointers remain the same.
+ */
GHash *BLI_ghash_copy(const GHash *gh,
GHashKeyCopyFP keycopyfp,
GHashValCopyFP valcopyfp) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+/**
+ * Frees the GHash and its members.
+ *
+ * \param gh: The GHash to free.
+ * \param keyfreefp: Optional callback to free the key.
+ * \param valfreefp: Optional callback to free the value.
+ */
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp);
+/**
+ * Reserve given amount of entries (resize \a gh accordingly if needed).
+ */
void BLI_ghash_reserve(GHash *gh, const unsigned int nentries_reserve);
+/**
+ * Insert a key/value pair into the \a gh.
+ *
+ * \note Duplicates are not checked,
+ * the caller is expected to ensure elements are unique unless
+ * GHASH_FLAG_ALLOW_DUPES flag is set.
+ */
void BLI_ghash_insert(GHash *gh, void *key, void *val);
+/**
+ * Inserts a new value to a key that may already be in ghash.
+ *
+ * Avoids #BLI_ghash_remove, #BLI_ghash_insert calls (double lookups)
+ *
+ * \returns true if a new key has been added.
+ */
bool BLI_ghash_reinsert(
GHash *gh, void *key, void *val, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp);
+/**
+ * Replaces the key of an item in the \a gh.
+ *
+ * Use when a key is re-allocated or its memory location is changed.
+ *
+ * \returns The previous key or NULL if not found, the caller may free if it's needed.
+ */
void *BLI_ghash_replace_key(GHash *gh, void *key);
+/**
+ * Lookup the value of \a key in \a gh.
+ *
+ * \param key: The key to lookup.
+ * \returns the value for \a key or NULL.
+ *
+ * \note When NULL is a valid value, use #BLI_ghash_lookup_p to differentiate a missing key
+ * from a key with a NULL value. (Avoids calling #BLI_ghash_haskey before #BLI_ghash_lookup)
+ */
void *BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT;
+/**
+ * A version of #BLI_ghash_lookup which accepts a fallback argument.
+ */
void *BLI_ghash_lookup_default(const GHash *gh,
const void *key,
void *val_default) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Lookup a pointer to the value of \a key in \a gh.
+ *
+ * \param key: The key to lookup.
+ * \returns the pointer to value for \a key or NULL.
+ *
+ * \note This has 2 main benefits over #BLI_ghash_lookup.
+ * - A NULL return always means that \a key isn't in \a gh.
+ * - The value can be modified in-place without further function calls (faster).
+ */
void **BLI_ghash_lookup_p(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Ensure \a key is exists in \a gh.
+ *
+ * This handles the common situation where the caller needs ensure a key is added to \a gh,
+ * constructing a new value in the case the key isn't found.
+ * Otherwise use the existing value.
+ *
+ * Such situations typically incur multiple lookups, however this function
+ * avoids them by ensuring the key is added,
+ * returning a pointer to the value so it can be used or initialized by the caller.
+ *
+ * \returns true when the value didn't need to be added.
+ * (when false, the caller _must_ initialize the value).
+ */
bool BLI_ghash_ensure_p(GHash *gh, void *key, void ***r_val) ATTR_WARN_UNUSED_RESULT;
+/**
+ * A version of #BLI_ghash_ensure_p that allows caller to re-assign the key.
+ * Typically used when the key is to be duplicated.
+ *
+ * \warning Caller _must_ write to \a r_key when returning false.
+ */
bool BLI_ghash_ensure_p_ex(GHash *gh, const void *key, void ***r_key, void ***r_val)
ATTR_WARN_UNUSED_RESULT;
+/**
+ * Remove \a key from \a gh, or return false if the key wasn't found.
+ *
+ * \param key: The key to remove.
+ * \param keyfreefp: Optional callback to free the key.
+ * \param valfreefp: Optional callback to free the value.
+ * \return true if \a key was removed from \a gh.
+ */
bool BLI_ghash_remove(GHash *gh,
const void *key,
GHashKeyFreeFP keyfreefp,
GHashValFreeFP valfreefp);
+/**
+ * Wraps #BLI_ghash_clear_ex with zero entries reserved.
+ */
void BLI_ghash_clear(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp);
+/**
+ * Reset \a gh clearing all entries.
+ *
+ * \param keyfreefp: Optional callback to free the key.
+ * \param valfreefp: Optional callback to free the value.
+ * \param nentries_reserve: Optionally reserve the number of members that the hash will hold.
+ */
void BLI_ghash_clear_ex(GHash *gh,
GHashKeyFreeFP keyfreefp,
GHashValFreeFP valfreefp,
const unsigned int nentries_reserve);
+/**
+ * Remove \a key from \a gh, returning the value or NULL if the key wasn't found.
+ *
+ * \param key: The key to remove.
+ * \param keyfreefp: Optional callback to free the key.
+ * \return the value of \a key int \a gh or NULL.
+ */
void *BLI_ghash_popkey(GHash *gh,
const void *key,
GHashKeyFreeFP keyfreefp) ATTR_WARN_UNUSED_RESULT;
+/**
+ * \return true if the \a key is in \a gh.
+ */
bool BLI_ghash_haskey(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Remove a random entry from \a gh, returning true
+ * if a key/value pair could be removed, false otherwise.
+ *
+ * \param r_key: The removed key.
+ * \param r_val: The removed value.
+ * \param state: Used for efficient removal.
+ * \return true if there was something to pop, false if ghash was already empty.
+ */
bool BLI_ghash_pop(GHash *gh, GHashIterState *state, void **r_key, void **r_val)
ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * \return size of the GHash.
+ */
unsigned int BLI_ghash_len(const GHash *gh) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Sets a GHash flag.
+ */
void BLI_ghash_flag_set(GHash *gh, unsigned int flag);
+/**
+ * Clear a GHash flag.
+ */
void BLI_ghash_flag_clear(GHash *gh, unsigned int flag);
/** \} */
@@ -129,10 +271,36 @@ void BLI_ghash_flag_clear(GHash *gh, unsigned int flag);
/** \name GHash Iterator
* \{ */
+/**
+ * Create a new GHashIterator. The hash table must not be mutated
+ * while the iterator is in use, and the iterator will step exactly
+ * #BLI_ghash_len(gh) times before becoming done.
+ *
+ * \param gh: The GHash to iterate over.
+ * \return Pointer to a new iterator.
+ */
GHashIterator *BLI_ghashIterator_new(GHash *gh) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+/**
+ * Init an already allocated GHashIterator. The hash table must not
+ * be mutated while the iterator is in use, and the iterator will
+ * step exactly #BLI_ghash_len(gh) times before becoming done.
+ *
+ * \param ghi: The GHashIterator to initialize.
+ * \param gh: The GHash to iterate over.
+ */
void BLI_ghashIterator_init(GHashIterator *ghi, GHash *gh);
+/**
+ * Free a GHashIterator.
+ *
+ * \param ghi: The iterator to free.
+ */
void BLI_ghashIterator_free(GHashIterator *ghi);
+/**
+ * Steps the iterator to the next index.
+ *
+ * \param ghi: The iterator.
+ */
void BLI_ghashIterator_step(GHashIterator *ghi);
BLI_INLINE void *BLI_ghashIterator_getKey(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT;
@@ -178,12 +346,11 @@ BLI_INLINE bool BLI_ghashIterator_done(const GHashIterator *ghi)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name GSet API
+/** \name GSet Types
* A 'set' implementation (unordered collection of unique elements).
*
* Internally this is a 'GHash' without any keys,
* which is why this API's are in the same header & source file.
- *
* \{ */
typedef struct GSet GSet;
@@ -195,6 +362,13 @@ typedef GHashKeyCopyFP GSetKeyCopyFP;
typedef GHashIterState GSetIterState;
+/** \} */
+
+/** \name GSet Public API
+ *
+ * Use ghash API to give 'set' functionality
+ * \{ */
+
GSet *BLI_gset_new_ex(GSetHashFP hashfp,
GSetCmpFP cmpfp,
const char *info,
@@ -202,17 +376,55 @@ GSet *BLI_gset_new_ex(GSetHashFP hashfp,
GSet *BLI_gset_new(GSetHashFP hashfp,
GSetCmpFP cmpfp,
const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+/**
+ * Copy given GSet. Keys are also copied if callback is provided, else pointers remain the same.
+ */
GSet *BLI_gset_copy(const GSet *gs, GSetKeyCopyFP keycopyfp) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
unsigned int BLI_gset_len(const GSet *gs) ATTR_WARN_UNUSED_RESULT;
void BLI_gset_flag_set(GSet *gs, unsigned int flag);
void BLI_gset_flag_clear(GSet *gs, unsigned int flag);
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp);
+/**
+ * Adds the key to the set (no checks for unique keys!).
+ * Matching #BLI_ghash_insert
+ */
void BLI_gset_insert(GSet *gs, void *key);
+/**
+ * A version of BLI_gset_insert which checks first if the key is in the set.
+ * \returns true if a new key has been added.
+ *
+ * \note GHash has no equivalent to this because typically the value would be different.
+ */
bool BLI_gset_add(GSet *gs, void *key);
+/**
+ * Set counterpart to #BLI_ghash_ensure_p_ex.
+ * similar to BLI_gset_add, except it returns the key pointer.
+ *
+ * \warning Caller _must_ write to \a r_key when returning false.
+ */
bool BLI_gset_ensure_p_ex(GSet *gs, const void *key, void ***r_key);
+/**
+ * Adds the key to the set (duplicates are managed).
+ * Matching #BLI_ghash_reinsert
+ *
+ * \returns true if a new key has been added.
+ */
bool BLI_gset_reinsert(GSet *gh, void *key, GSetKeyFreeFP keyfreefp);
+/**
+ * Replaces the key to the set if it's found.
+ * Matching #BLI_ghash_replace_key
+ *
+ * \returns The old key or NULL if not found.
+ */
void *BLI_gset_replace_key(GSet *gs, void *key);
bool BLI_gset_haskey(const GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Remove a random entry from \a gs, returning true if a key could be removed, false otherwise.
+ *
+ * \param r_key: The removed key.
+ * \param state: Used for efficient removal.
+ * \return true if there was something to pop, false if gset was already empty.
+ */
bool BLI_gset_pop(GSet *gs, GSetIterState *state, void **r_key) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
bool BLI_gset_remove(GSet *gs, const void *key, GSetKeyFreeFP keyfreefp);
@@ -220,7 +432,14 @@ void BLI_gset_clear_ex(GSet *gs, GSetKeyFreeFP keyfreefp, const unsigned int nen
void BLI_gset_clear(GSet *gs, GSetKeyFreeFP keyfreefp);
/* When set's are used for key & value. */
+/**
+ * Returns the pointer to the key if it's found.
+ */
void *BLI_gset_lookup(const GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Returns the pointer to the key if it's found, removing it from the GSet.
+ * \note Caller must handle freeing.
+ */
void *BLI_gset_pop_key(GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT;
/** \} */
@@ -282,9 +501,19 @@ BLI_INLINE bool BLI_gsetIterator_done(const GSetIterator *gsi)
/* For testing, debugging only */
#ifdef GHASH_INTERNAL_API
+/**
+ * \return number of buckets in the GHash.
+ */
int BLI_ghash_buckets_len(const GHash *gh);
int BLI_gset_buckets_len(const GSet *gs);
+/**
+ * Measure how well the hash function performs (1.0 is approx as good as random distribution),
+ * and return a few other stats like load,
+ * variance of the distribution of the entries in the buckets, etc.
+ *
+ * Smaller is better!
+ */
double BLI_ghash_calc_quality_ex(GHash *gh,
double *r_load,
double *r_variance,
@@ -300,6 +529,7 @@ double BLI_gset_calc_quality_ex(GSet *gs,
double BLI_ghash_calc_quality(GHash *gh);
double BLI_gset_calc_quality(GSet *gs);
#endif /* GHASH_INTERNAL_API */
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -346,6 +576,15 @@ double BLI_gset_calc_quality(GSet *gs);
unsigned int BLI_ghashutil_ptrhash(const void *key);
bool BLI_ghashutil_ptrcmp(const void *a, const void *b);
+/**
+ * This function implements the widely used `djb` hash apparently posted
+ * by Daniel Bernstein to `comp.lang.c` some time ago. The 32 bit
+ * unsigned hash value starts at 5381 and for each byte 'c' in the
+ * string, is updated: `hash = hash * 33 + c`.
+ * This function uses the signed value of each byte.
+ *
+ * NOTE: this is the same hash method that glib 2.34.0 uses.
+ */
unsigned int BLI_ghashutil_strhash_n(const char *key, size_t n);
#define BLI_ghashutil_strhash(key) \
(CHECK_TYPE_ANY(key, char *, const char *, const char *const), BLI_ghashutil_strhash_p(key))
diff --git a/source/blender/blenlib/BLI_gsqueue.h b/source/blender/blenlib/BLI_gsqueue.h
index 9cc61bc8059..8b32c09b56b 100644
--- a/source/blender/blenlib/BLI_gsqueue.h
+++ b/source/blender/blenlib/BLI_gsqueue.h
@@ -32,10 +32,30 @@ extern "C" {
typedef struct _GSQueue GSQueue;
GSQueue *BLI_gsqueue_new(const size_t elem_size);
+/**
+ * Returns true if the queue is empty, false otherwise.
+ */
bool BLI_gsqueue_is_empty(const GSQueue *queue);
size_t BLI_gsqueue_len(const GSQueue *queue);
+/**
+ * Retrieves and removes the first element from the queue.
+ * The value is copies to \a r_item, which must be at least \a elem_size bytes.
+ *
+ * Does not reduce amount of allocated memory.
+ */
void BLI_gsqueue_pop(GSQueue *queue, void *r_item);
+/**
+ * Copies the source value onto the end of the queue
+ *
+ * \note This copies #GSQueue.elem_size bytes from \a item,
+ * (the pointer itself is not stored).
+ *
+ * \param item: source data to be copied to the queue.
+ */
void BLI_gsqueue_push(GSQueue *queue, const void *item);
+/**
+ * Free the queue's data and the queue itself.
+ */
void BLI_gsqueue_free(GSQueue *queue);
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_hash_md5.h b/source/blender/blenlib/BLI_hash_md5.h
index 227cfcc8876..7b5868d7ffc 100644
--- a/source/blender/blenlib/BLI_hash_md5.h
+++ b/source/blender/blenlib/BLI_hash_md5.h
@@ -24,17 +24,18 @@
extern "C" {
#endif
-/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The
- * result is always in little endian byte order, so that a byte-wise
- * output yields to the wanted ASCII representation of the message
- * digest. */
-
+/**
+ * Compute MD5 message digest for 'len' bytes beginning at 'buffer'.
+ * The result is always in little endian byte order,
+ * so that a byte-wise output yields to the wanted ASCII representation of the message digest.
+ */
void *BLI_hash_md5_buffer(const char *buffer, size_t len, void *resblock);
-/* Compute MD5 message digest for bytes read from STREAM. The
- * resulting message digest number will be written into the 16 bytes
- * beginning at RESBLOCK. */
-
+/**
+ * Compute MD5 message digest for bytes read from 'stream'.
+ * The resulting message digest number will be written into the 16 bytes beginning at 'resblock'.
+ * \return Non-zero if an error occurred.
+ */
int BLI_hash_md5_stream(FILE *stream, void *resblock);
char *BLI_hash_md5_to_hexdigest(void *resblock, char r_hex_digest[33]);
diff --git a/source/blender/blenlib/BLI_hash_mm2a.h b/source/blender/blenlib/BLI_hash_mm2a.h
index 193a78e6293..2619e516861 100644
--- a/source/blender/blenlib/BLI_hash_mm2a.h
+++ b/source/blender/blenlib/BLI_hash_mm2a.h
@@ -41,6 +41,9 @@ void BLI_hash_mm2a_add_int(BLI_HashMurmur2A *mm2, int data);
uint32_t BLI_hash_mm2a_end(BLI_HashMurmur2A *mm2);
+/**
+ * Non-incremental version, quicker for small keys.
+ */
uint32_t BLI_hash_mm2(const unsigned char *data, size_t len, uint32_t seed);
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_heap.h b/source/blender/blenlib/BLI_heap.h
index 4cfb7945303..b6a12521fff 100644
--- a/source/blender/blenlib/BLI_heap.h
+++ b/source/blender/blenlib/BLI_heap.h
@@ -34,27 +34,59 @@ typedef struct HeapNode HeapNode;
typedef void (*HeapFreeFP)(void *ptr);
+/**
+ * Creates a new heap. Removed nodes are recycled, so memory usage will not shrink.
+ *
+ * \note Use when the size of the heap is known in advance.
+ */
Heap *BLI_heap_new_ex(unsigned int tot_reserve) ATTR_WARN_UNUSED_RESULT;
Heap *BLI_heap_new(void) ATTR_WARN_UNUSED_RESULT;
void BLI_heap_clear(Heap *heap, HeapFreeFP ptrfreefp) ATTR_NONNULL(1);
void BLI_heap_free(Heap *heap, HeapFreeFP ptrfreefp) ATTR_NONNULL(1);
+/**
+ * Insert heap node with a value (often a 'cost') and pointer into the heap,
+ * duplicate values are allowed.
+ */
HeapNode *BLI_heap_insert(Heap *heap, float value, void *ptr) ATTR_NONNULL(1);
+/**
+ * Convenience function since this is a common pattern.
+ */
void BLI_heap_insert_or_update(Heap *heap, HeapNode **node_p, float value, void *ptr)
ATTR_NONNULL(1, 2);
void BLI_heap_remove(Heap *heap, HeapNode *node) ATTR_NONNULL(1, 2);
bool BLI_heap_is_empty(const Heap *heap) ATTR_NONNULL(1);
unsigned int BLI_heap_len(const Heap *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Return the top node of the heap.
+ * This is the node with the lowest value.
+ */
HeapNode *BLI_heap_top(const Heap *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Return the value of top node of the heap.
+ * This is the node with the lowest value.
+ */
float BLI_heap_top_value(const Heap *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Pop the top node off the heap and return its pointer.
+ */
void *BLI_heap_pop_min(Heap *heap) ATTR_NONNULL(1);
+/**
+ * Can be used to avoid #BLI_heap_remove, #BLI_heap_insert calls,
+ * balancing the tree still has a performance cost,
+ * but is often much less than remove/insert, difference is most noticeable with large heaps.
+ */
void BLI_heap_node_value_update(Heap *heap, HeapNode *node, float value) ATTR_NONNULL(1, 2);
void BLI_heap_node_value_update_ptr(Heap *heap, HeapNode *node, float value, void *ptr)
ATTR_NONNULL(1, 2);
-/* Return the value or pointer of a heap node. */
+/**
+ * Return the value or pointer of a heap node.
+ */
float BLI_heap_node_value(const HeapNode *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
void *BLI_heap_node_ptr(const HeapNode *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
-/* only for gtest */
+/**
+ * Only for checking internal errors (gtest).
+ */
bool BLI_heap_is_valid(const Heap *heap);
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_heap_simple.h b/source/blender/blenlib/BLI_heap_simple.h
index b2a1b5582e5..5583f209de0 100644
--- a/source/blender/blenlib/BLI_heap_simple.h
+++ b/source/blender/blenlib/BLI_heap_simple.h
@@ -30,14 +30,29 @@ typedef struct HeapSimple HeapSimple;
typedef void (*HeapSimpleFreeFP)(void *ptr);
+/**
+ * Creates a new simple heap, which only supports insertion and removal from top.
+ *
+ * \note Use when the size of the heap is known in advance.
+ */
HeapSimple *BLI_heapsimple_new_ex(unsigned int tot_reserve) ATTR_WARN_UNUSED_RESULT;
HeapSimple *BLI_heapsimple_new(void) ATTR_WARN_UNUSED_RESULT;
void BLI_heapsimple_clear(HeapSimple *heap, HeapSimpleFreeFP ptrfreefp) ATTR_NONNULL(1);
void BLI_heapsimple_free(HeapSimple *heap, HeapSimpleFreeFP ptrfreefp) ATTR_NONNULL(1);
+/**
+ * Insert heap node with a value (often a 'cost') and pointer into the heap,
+ * duplicate values are allowed.
+ */
void BLI_heapsimple_insert(HeapSimple *heap, float value, void *ptr) ATTR_NONNULL(1);
bool BLI_heapsimple_is_empty(const HeapSimple *heap) ATTR_NONNULL(1);
uint BLI_heapsimple_len(const HeapSimple *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Return the lowest value of the heap.
+ */
float BLI_heapsimple_top_value(const HeapSimple *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Pop the top node off the heap and return its pointer.
+ */
void *BLI_heapsimple_pop_min(HeapSimple *heap) ATTR_NONNULL(1);
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_index_mask.hh b/source/blender/blenlib/BLI_index_mask.hh
index ad030e127fe..2dca3689cb1 100644
--- a/source/blender/blenlib/BLI_index_mask.hh
+++ b/source/blender/blenlib/BLI_index_mask.hh
@@ -45,11 +45,11 @@ namespace blender {
class IndexMask {
private:
- /* The underlying reference to sorted integers. */
+ /** The underlying reference to sorted integers. */
Span<int64_t> indices_;
public:
- /* Creates an IndexMask that contains no indices. */
+ /** Creates an IndexMask that contains no indices. */
IndexMask() = default;
/**
@@ -223,6 +223,25 @@ class IndexMask {
return indices_.is_empty();
}
+ IndexMask slice(IndexRange slice) const;
+ /**
+ * Create a sub-mask that is also shifted to the beginning.
+ * The shifting to the beginning allows code to work with smaller indices,
+ * which is more memory efficient.
+ *
+ * \return New index mask with the size of #slice. It is either empty or starts with 0.
+ * It might reference indices that have been appended to #r_new_indices.
+ *
+ * Example:
+ * \code{.unparsed}
+ * this: [2, 3, 5, 7, 8, 9, 10]
+ * slice: ^--------^
+ * output: [0, 2, 4, 5]
+ * \endcode
+ *
+ * All the indices in the sub-mask are shifted by 3 towards zero,
+ * so that the first index in the output is zero.
+ */
IndexMask slice_and_offset(IndexRange slice, Vector<int64_t> &r_new_indices) const;
};
diff --git a/source/blender/blenlib/BLI_kdopbvh.h b/source/blender/blenlib/BLI_kdopbvh.h
index 5e0ea4f2a99..2f41be369c1 100644
--- a/source/blender/blenlib/BLI_kdopbvh.h
+++ b/source/blender/blenlib/BLI_kdopbvh.h
@@ -104,25 +104,35 @@ enum {
#define BVH_RAYCAST_DEFAULT (BVH_RAYCAST_WATERTIGHT)
#define BVH_RAYCAST_DIST_MAX (FLT_MAX / 2.0f)
-/* callback must update nearest in case it finds a nearest result */
+/**
+ * Callback must update nearest in case it finds a nearest result.
+ */
typedef void (*BVHTree_NearestPointCallback)(void *userdata,
int index,
const float co[3],
BVHTreeNearest *nearest);
-/* callback must update hit in case it finds a nearest successful hit */
+/**
+ * Callback must update hit in case it finds a nearest successful hit.
+ */
typedef void (*BVHTree_RayCastCallback)(void *userdata,
int index,
const BVHTreeRay *ray,
BVHTreeRayHit *hit);
-/* callback to check if 2 nodes overlap (use thread if intersection results need to be stored) */
+/**
+ * Callback to check if 2 nodes overlap (use thread if intersection results need to be stored).
+ */
typedef bool (*BVHTree_OverlapCallback)(void *userdata, int index_a, int index_b, int thread);
-/* callback to range search query */
+/**
+ * Callback to range search query.
+ */
typedef void (*BVHTree_RangeQuery)(void *userdata, int index, const float co[3], float dist_sq);
-/* callback to find nearest projected */
+/**
+ * Callback to find nearest projected.
+ */
typedef void (*BVHTree_NearestProjectedCallback)(void *userdata,
int index,
const struct DistProjectedAABBPrecalc *precalc,
@@ -131,42 +141,67 @@ typedef void (*BVHTree_NearestProjectedCallback)(void *userdata,
BVHTreeNearest *nearest);
/* callbacks to BLI_bvhtree_walk_dfs */
-/* return true to traverse into this nodes children, else skip. */
+
+/**
+ * Return true to traverse into this nodes children, else skip.
+ */
typedef bool (*BVHTree_WalkParentCallback)(const BVHTreeAxisRange *bounds, void *userdata);
-/* return true to keep walking, else early-exit the search. */
+/**
+ * Return true to keep walking, else early-exit the search.
+ */
typedef bool (*BVHTree_WalkLeafCallback)(const BVHTreeAxisRange *bounds,
int index,
void *userdata);
-/* return true to search (min, max) else (max, min). */
+/**
+ * Return true to search (min, max) else (max, min).
+ */
typedef bool (*BVHTree_WalkOrderCallback)(const BVHTreeAxisRange *bounds,
char axis,
void *userdata);
+/**
+ * \note many callers don't check for `NULL` return.
+ */
BVHTree *BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis);
void BLI_bvhtree_free(BVHTree *tree);
-/* construct: first insert points, then call balance */
+/**
+ * Construct: first insert points, then call balance.
+ */
void BLI_bvhtree_insert(BVHTree *tree, int index, const float co[3], int numpoints);
void BLI_bvhtree_balance(BVHTree *tree);
-/* update: first update points/nodes, then call update_tree to refit the bounding volumes */
+/**
+ * Update: first update points/nodes, then call update_tree to refit the bounding volumes.
+ * \note call before #BLI_bvhtree_update_tree().
+ */
bool BLI_bvhtree_update_node(
BVHTree *tree, int index, const float co[3], const float co_moving[3], int numpoints);
+/**
+ * Call #BLI_bvhtree_update_node() first for every node/point/triangle.
+ */
void BLI_bvhtree_update_tree(BVHTree *tree);
+/**
+ * Use to check the total number of threads #BLI_bvhtree_overlap will use.
+ *
+ * \warning Must be the first tree passed to #BLI_bvhtree_overlap!
+ */
int BLI_bvhtree_overlap_thread_num(const BVHTree *tree);
-/* collision/overlap: check two trees if they overlap,
- * alloc's *overlap with length of the int return value */
-BVHTreeOverlap *BLI_bvhtree_overlap_ex(
- const BVHTree *tree1,
- const BVHTree *tree2,
- uint *r_overlap_tot,
- /* optional callback to test the overlap before adding (must be thread-safe!) */
- BVHTree_OverlapCallback callback,
- void *userdata,
- const uint max_interactions,
- const int flag);
+/**
+ * Collision/overlap: check two trees if they overlap,
+ * alloc's *overlap with length of the int return value.
+ *
+ * \param callback: optional, to test the overlap before adding (must be thread-safe!).
+ */
+BVHTreeOverlap *BLI_bvhtree_overlap_ex(const BVHTree *tree1,
+ const BVHTree *tree2,
+ uint *r_overlap_tot,
+ BVHTree_OverlapCallback callback,
+ void *userdata,
+ const uint max_interactions,
+ const int flag);
BVHTreeOverlap *BLI_bvhtree_overlap(const BVHTree *tree1,
const BVHTree *tree2,
unsigned int *r_overlap_tot,
@@ -175,14 +210,26 @@ BVHTreeOverlap *BLI_bvhtree_overlap(const BVHTree *tree1,
int *BLI_bvhtree_intersect_plane(BVHTree *tree, float plane[4], uint *r_intersect_tot);
+/**
+ * Number of times #BLI_bvhtree_insert has been called.
+ * mainly useful for asserts functions to check we added the correct number.
+ */
int BLI_bvhtree_get_len(const BVHTree *tree);
+/**
+ * Maximum number of children that a node can have.
+ */
int BLI_bvhtree_get_tree_type(const BVHTree *tree);
float BLI_bvhtree_get_epsilon(const BVHTree *tree);
+/**
+ * This function returns the bounding box of the BVH tree.
+ */
void BLI_bvhtree_get_bounding_box(BVHTree *tree, float r_bb_min[3], float r_bb_max[3]);
-/* find nearest node to the given coordinates
+/**
+ * Find nearest node to the given coordinates
* (if nearest is given it will only search nodes where
- * square distance is smaller than nearest->dist) */
+ * square distance is smaller than nearest->dist).
+ */
int BLI_bvhtree_find_nearest_ex(BVHTree *tree,
const float co[3],
BVHTreeNearest *nearest,
@@ -195,6 +242,10 @@ int BLI_bvhtree_find_nearest(BVHTree *tree,
BVHTree_NearestPointCallback callback,
void *userdata);
+/**
+ * Find the first node nearby.
+ * Favors speed over quality since it doesn't find the best target node.
+ */
int BLI_bvhtree_find_nearest_first(BVHTree *tree,
const float co[3],
const float dist_sq,
@@ -217,6 +268,15 @@ int BLI_bvhtree_ray_cast(BVHTree *tree,
BVHTree_RayCastCallback callback,
void *userdata);
+/**
+ * Calls the callback for every ray intersection
+ *
+ * \note Using a \a callback which resets or never sets the #BVHTreeRayHit index & dist works too,
+ * however using this function means existing generic callbacks can be used from custom callbacks
+ * without having to handle resetting the hit beforehand.
+ * It also avoid redundant argument and return value which aren't meaningful
+ * when collecting multiple hits.
+ */
void BLI_bvhtree_ray_cast_all_ex(BVHTree *tree,
const float co[3],
const float dir[3],
@@ -238,7 +298,9 @@ float BLI_bvhtree_bb_raycast(const float bv[6],
const float light_end[3],
float pos[3]);
-/* range query */
+/**
+ * Range query.
+ */
int BLI_bvhtree_range_query(
BVHTree *tree, const float co[3], float radius, BVHTree_RangeQuery callback, void *userdata);
@@ -252,13 +314,27 @@ int BLI_bvhtree_find_nearest_projected(BVHTree *tree,
BVHTree_NearestProjectedCallback callback,
void *userdata);
+/**
+ * This is a generic function to perform a depth first search on the #BVHTree
+ * where the search order and nodes traversed depend on callbacks passed in.
+ *
+ * \param tree: Tree to walk.
+ * \param walk_parent_cb: Callback on a parents bound-box to test if it should be traversed.
+ * \param walk_leaf_cb: Callback to test leaf nodes, callback must store its own result,
+ * returning false exits early.
+ * \param walk_order_cb: Callback that indicates which direction to search,
+ * either from the node with the lower or higher K-DOP axis value.
+ * \param userdata: Argument passed to all callbacks.
+ */
void BLI_bvhtree_walk_dfs(BVHTree *tree,
BVHTree_WalkParentCallback walk_parent_cb,
BVHTree_WalkLeafCallback walk_leaf_cb,
BVHTree_WalkOrderCallback walk_order_cb,
void *userdata);
-/* expose for bvh callbacks to use */
+/**
+ * Expose for BVH callbacks to use.
+ */
extern const float bvhtree_kdop_axes[13][3];
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_lasso_2d.h b/source/blender/blenlib/BLI_lasso_2d.h
index e920d1189a2..5f034bfdc1d 100644
--- a/source/blender/blenlib/BLI_lasso_2d.h
+++ b/source/blender/blenlib/BLI_lasso_2d.h
@@ -35,6 +35,9 @@ bool BLI_lasso_is_point_inside(const int mcoords[][2],
const int sx,
const int sy,
const int error_value);
+/**
+ * Edge version for lasso select. We assume bound-box check was done.
+ */
bool BLI_lasso_is_edge_inside(const int mcoords[][2],
const unsigned int mcoords_len,
int x0,
diff --git a/source/blender/blenlib/BLI_linklist.h b/source/blender/blenlib/BLI_linklist.h
index 25d58a3050c..d872921defc 100644
--- a/source/blender/blenlib/BLI_linklist.h
+++ b/source/blender/blenlib/BLI_linklist.h
@@ -58,8 +58,15 @@ LinkNode *BLI_linklist_find_last(LinkNode *list) ATTR_WARN_UNUSED_RESULT;
void BLI_linklist_reverse(LinkNode **listp) ATTR_NONNULL(1);
+/**
+ * Move an item from its current position to a new one inside a single-linked list.
+ * \note `*listp` may be modified.
+ */
void BLI_linklist_move_item(LinkNode **listp, int curr_index, int new_index) ATTR_NONNULL(1);
+/**
+ * A version of #BLI_linklist_prepend that takes the allocated link.
+ */
void BLI_linklist_prepend_nlink(LinkNode **listp, void *ptr, LinkNode *nlink) ATTR_NONNULL(1, 3);
void BLI_linklist_prepend(LinkNode **listp, void *ptr) ATTR_NONNULL(1);
void BLI_linklist_prepend_arena(LinkNode **listp, void *ptr, struct MemArena *ma)
@@ -67,7 +74,11 @@ void BLI_linklist_prepend_arena(LinkNode **listp, void *ptr, struct MemArena *ma
void BLI_linklist_prepend_pool(LinkNode **listp, void *ptr, struct BLI_mempool *mempool)
ATTR_NONNULL(1, 3);
-/* use LinkNodePair to avoid full search */
+/* Use #LinkNodePair to avoid full search. */
+
+/**
+ * A version of append that takes the allocated link.
+ */
void BLI_linklist_append_nlink(LinkNodePair *list_pair, void *ptr, LinkNode *nlink)
ATTR_NONNULL(1, 3);
void BLI_linklist_append(LinkNodePair *list_pair, void *ptr) ATTR_NONNULL(1);
diff --git a/source/blender/blenlib/BLI_listbase.h b/source/blender/blenlib/BLI_listbase.h
index cf525d1c2af..7d808d339e9 100644
--- a/source/blender/blenlib/BLI_listbase.h
+++ b/source/blender/blenlib/BLI_listbase.h
@@ -33,89 +33,233 @@
extern "C" {
#endif
+/**
+ * Returns the position of \a vlink within \a listbase, numbering from 0, or -1 if not found.
+ */
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1);
+/**
+ * Returns the 0-based index of the first element of listbase which contains the specified
+ * null-terminated string at the specified offset, or -1 if not found.
+ */
int BLI_findstringindex(const struct ListBase *listbase,
const char *id,
const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
-/* find forwards */
+/* Find forwards. */
+
+/**
+ * Returns the nth element of \a listbase, numbering from 0.
+ */
void *BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1);
+/**
+ * Finds the first element of \a listbase which contains the null-terminated
+ * string \a id at the specified offset, returning NULL if not found.
+ */
void *BLI_findstring(const struct ListBase *listbase,
const char *id,
const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Finds the first element of \a listbase which contains a pointer to the
+ * null-terminated string \a id at the specified offset, returning NULL if not found.
+ */
void *BLI_findstring_ptr(const struct ListBase *listbase,
const char *id,
const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Finds the first element of listbase which contains the specified pointer value
+ * at the specified offset, returning NULL if not found.
+ */
void *BLI_findptr(const struct ListBase *listbase,
const void *ptr,
const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Finds the first element of listbase which contains the specified bytes
+ * at the specified offset, returning NULL if not found.
+ */
void *BLI_listbase_bytes_find(const ListBase *listbase,
const void *bytes,
const size_t bytes_size,
const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2);
+/**
+ * Find the first item in the list that matches the given string, or the given index as fallback.
+ *
+ * \note The string is only used is non-NULL and non-empty.
+ *
+ * \return The found item, or NULL.
+ */
void *BLI_listbase_string_or_index_find(const struct ListBase *listbase,
const char *string,
const size_t string_offset,
const int index) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
-/* find backwards */
+/* Find backwards. */
+
+/**
+ * Returns the nth-last element of \a listbase, numbering from 0.
+ */
void *BLI_rfindlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1);
+/**
+ * Finds the last element of \a listbase which contains the
+ * null-terminated string \a id at the specified offset, returning NULL if not found.
+ */
void *BLI_rfindstring(const struct ListBase *listbase,
const char *id,
const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Finds the last element of \a listbase which contains a pointer to the
+ * null-terminated string \a id at the specified offset, returning NULL if not found.
+ */
void *BLI_rfindstring_ptr(const struct ListBase *listbase,
const char *id,
const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Finds the last element of listbase which contains the specified pointer value
+ * at the specified offset, returning NULL if not found.
+ */
void *BLI_rfindptr(const struct ListBase *listbase,
const void *ptr,
const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Finds the last element of listbase which contains the specified bytes
+ * at the specified offset, returning NULL if not found.
+ */
void *BLI_listbase_bytes_rfind(const ListBase *listbase,
const void *bytes,
const size_t bytes_size,
const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2);
+/**
+ * Removes and disposes of the entire contents of \a listbase using guardedalloc.
+ */
void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1);
+/**
+ * Appends \a vlink (assumed to begin with a Link) onto listbase.
+ */
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1);
+/**
+ * Removes \a vlink from \a listbase. Assumes it is linked into there!
+ */
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1);
+/**
+ * Checks that \a vlink is linked into listbase, removing it from there if so.
+ */
bool BLI_remlink_safe(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1);
+/**
+ * Removes the head from \a listbase and returns it.
+ */
void *BLI_pophead(ListBase *listbase) ATTR_NONNULL(1);
+/**
+ * Removes the tail from \a listbase and returns it.
+ */
void *BLI_poptail(ListBase *listbase) ATTR_NONNULL(1);
+/**
+ * Prepends \a vlink (assumed to begin with a Link) onto listbase.
+ */
void BLI_addhead(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1);
+/**
+ * Inserts \a vnewlink immediately preceding \a vnextlink in listbase.
+ * Or, if \a vnextlink is NULL, puts \a vnewlink at the end of the list.
+ */
void BLI_insertlinkbefore(struct ListBase *listbase, void *vnextlink, void *vnewlink)
ATTR_NONNULL(1);
+/**
+ * Inserts \a vnewlink immediately following \a vprevlink in \a listbase.
+ * Or, if \a vprevlink is NULL, puts \a vnewlink at the front of the list.
+ */
void BLI_insertlinkafter(struct ListBase *listbase, void *vprevlink, void *vnewlink)
ATTR_NONNULL(1);
+/**
+ * Insert a link in place of another, without changing its position in the list.
+ *
+ * Puts `vnewlink` in the position of `vreplacelink`, removing `vreplacelink`.
+ * - `vreplacelink` *must* be in the list.
+ * - `vnewlink` *must not* be in the list.
+ */
void BLI_insertlinkreplace(ListBase *listbase, void *vreplacelink, void *vnewlink)
ATTR_NONNULL(1, 2, 3);
+/**
+ * Sorts the elements of listbase into the order defined by cmp
+ * (which should return 1 if its first arg should come after its second arg).
+ * This uses insertion sort, so NOT ok for large list.
+ */
void BLI_listbase_sort(struct ListBase *listbase, int (*cmp)(const void *, const void *))
ATTR_NONNULL(1, 2);
void BLI_listbase_sort_r(ListBase *listbase,
int (*cmp)(void *, const void *, const void *),
void *thunk) ATTR_NONNULL(1, 2);
+/**
+ * Reinsert \a vlink relative to its current position but offset by \a step. Doesn't move
+ * item if new position would exceed list (could optionally move to head/tail).
+ *
+ * \param step: Absolute value defines step size, sign defines direction. E.g pass -1
+ * to move \a vlink before previous, or 1 to move behind next.
+ * \return If position of \a vlink has changed.
+ */
bool BLI_listbase_link_move(ListBase *listbase, void *vlink, int step) ATTR_NONNULL();
+/**
+ * Move the link at the index \a from to the position at index \a to.
+ *
+ * \return If the move was successful.
+ */
bool BLI_listbase_move_index(ListBase *listbase, int from, int to) ATTR_NONNULL();
+/**
+ * Removes and disposes of the entire contents of listbase using direct free(3).
+ */
void BLI_freelist(struct ListBase *listbase) ATTR_NONNULL(1);
+/**
+ * Returns the number of elements in \a listbase, up until (and including count_max)
+ *
+ * \note Use to avoid redundant looping.
+ */
int BLI_listbase_count_at_most(const struct ListBase *listbase,
const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Returns the number of elements in \a listbase.
+ */
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Removes \a vlink from listbase and disposes of it. Assumes it is linked into there!
+ */
void BLI_freelinkN(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1);
+/**
+ * Swaps \a vlinka and \a vlinkb in the list. Assumes they are both already in the list!
+ */
void BLI_listbase_swaplinks(struct ListBase *listbase, void *vlinka, void *vlinkb)
ATTR_NONNULL(1, 2);
+/**
+ * Swaps \a vlinka and \a vlinkb from their respective lists.
+ * Assumes they are both already in their \a listbasea!
+ */
void BLI_listbases_swaplinks(struct ListBase *listbasea,
struct ListBase *listbaseb,
void *vlinka,
void *vlinkb) ATTR_NONNULL(2, 3);
+/**
+ * Moves the entire contents of \a src onto the end of \a dst.
+ */
void BLI_movelisttolist(struct ListBase *dst, struct ListBase *src) ATTR_NONNULL(1, 2);
+/**
+ * Moves the entire contents of \a src at the beginning of \a dst.
+ */
void BLI_movelisttolist_reverse(struct ListBase *dst, struct ListBase *src) ATTR_NONNULL(1, 2);
+/**
+ * Sets dst to a duplicate of the entire contents of src. dst may be the same as src.
+ */
void BLI_duplicatelist(struct ListBase *dst, const struct ListBase *src) ATTR_NONNULL(1, 2);
void BLI_listbase_reverse(struct ListBase *lb) ATTR_NONNULL(1);
+/**
+ * \param vlink: Link to make first.
+ */
void BLI_listbase_rotate_first(struct ListBase *lb, void *vlink) ATTR_NONNULL(1, 2);
+/**
+ * \param vlink: Link to make last.
+ */
void BLI_listbase_rotate_last(struct ListBase *lb, void *vlink) ATTR_NONNULL(1, 2);
/**
@@ -134,7 +278,9 @@ BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
lb->first = lb->last = (void *)0;
}
-/* create a generic list node containing link to provided data */
+/**
+ * Create a generic list node containing link to provided data.
+ */
struct LinkData *BLI_genericNodeN(void *data);
/**
@@ -188,13 +334,17 @@ struct LinkData *BLI_genericNodeN(void *data);
#define LISTBASE_FOREACH_BACKWARD(type, var, list) \
for (type var = (type)((list)->last); var != NULL; var = (type)(((Link *)(var))->prev))
-/** A version of #LISTBASE_FOREACH that supports removing the item we're looping over. */
+/**
+ * A version of #LISTBASE_FOREACH that supports removing the item we're looping over.
+ */
#define LISTBASE_FOREACH_MUTABLE(type, var, list) \
for (type var = (type)((list)->first), *var##_iter_next; \
((var != NULL) ? ((void)(var##_iter_next = (type)(((Link *)(var))->next)), 1) : 0); \
var = var##_iter_next)
-/** A version of #LISTBASE_FOREACH_BACKWARD that supports removing the item we're looping over. */
+/**
+ * A version of #LISTBASE_FOREACH_BACKWARD that supports removing the item we're looping over.
+ */
#define LISTBASE_FOREACH_BACKWARD_MUTABLE(type, var, list) \
for (type var = (type)((list)->last), *var##_iter_prev; \
((var != NULL) ? ((void)(var##_iter_prev = (type)(((Link *)(var))->prev)), 1) : 0); \
diff --git a/source/blender/blenlib/BLI_math_base.h b/source/blender/blenlib/BLI_math_base.h
index 9b54f780296..83822481112 100644
--- a/source/blender/blenlib/BLI_math_base.h
+++ b/source/blender/blenlib/BLI_math_base.h
@@ -97,6 +97,7 @@ extern "C" {
/******************************* Float ******************************/
+/* powf is really slow for raising to integer powers. */
MINLINE float pow2f(float x);
MINLINE float pow3f(float x);
MINLINE float pow4f(float x);
@@ -120,11 +121,18 @@ MINLINE double interpd(double a, double b, double t);
MINLINE float ratiof(float min, float max, float pos);
MINLINE double ratiod(double min, double max, double pos);
+/**
+ * Map a normalized value, i.e. from interval [0, 1] to interval [a, b].
+ */
MINLINE float scalenorm(float a, float b, float x);
+/**
+ * Map a normalized value, i.e. from interval [0, 1] to interval [a, b].
+ */
MINLINE double scalenormd(double a, double b, double x);
/* NOTE: Compilers will upcast all types smaller than int to int when performing arithmetic
* operation. */
+
MINLINE int square_s(short a);
MINLINE int square_uchar(unsigned char a);
MINLINE int cube_s(short a);
@@ -170,7 +178,23 @@ MINLINE int clamp_i(int value, int min, int max);
MINLINE float clamp_f(float value, float min, float max);
MINLINE size_t clamp_z(size_t value, size_t min, size_t max);
+/**
+ * Almost-equal for IEEE floats, using absolute difference method.
+ *
+ * \param max_diff: the maximum absolute difference.
+ */
MINLINE int compare_ff(float a, float b, const float max_diff);
+/**
+ * Almost-equal for IEEE floats, using their integer representation
+ * (mixing ULP and absolute difference methods).
+ *
+ * \param max_diff: is the maximum absolute difference (allows to take care of the near-zero area,
+ * where relative difference methods cannot really work).
+ * \param max_ulps: is the 'maximum number of floats + 1'
+ * allowed between \a a and \a b to consider them equal.
+ *
+ * \see https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
+ */
MINLINE int compare_ff_relative(float a, float b, const float max_diff, const int max_ulps);
MINLINE bool compare_threshold_relative(const float value1,
const float value2,
@@ -180,13 +204,25 @@ MINLINE float signf(float f);
MINLINE int signum_i_ex(float a, float eps);
MINLINE int signum_i(float a);
+/**
+ * Used for zoom values.
+ */
MINLINE float power_of_2(float f);
+/**
+ * Returns number of (base ten) *significant* digits of integer part of given float
+ * (negative in case of decimal-only floats, 0.01 returns -1 e.g.).
+ */
MINLINE int integer_digits_f(const float f);
+/**
+ * Returns number of (base ten) *significant* digits of integer part of given double
+ * (negative in case of decimal-only floats, 0.01 returns -1 e.g.).
+ */
MINLINE int integer_digits_d(const double d);
MINLINE int integer_digits_i(const int i);
-/* these don't really fit anywhere but were being copied about a lot */
+/* These don't really fit anywhere but were being copied about a lot. */
+
MINLINE int is_power_of_2_i(int n);
MINLINE int power_of_2_max_i(int n);
MINLINE int power_of_2_min_i(int n);
@@ -196,9 +232,19 @@ MINLINE unsigned int power_of_2_min_u(unsigned int x);
MINLINE unsigned int log2_floor_u(unsigned int x);
MINLINE unsigned int log2_ceil_u(unsigned int x);
+/**
+ * Integer division that rounds 0.5 up, particularly useful for color blending
+ * with integers, to avoid gradual darkening when rounding down.
+ */
MINLINE int divide_round_i(int a, int b);
+/**
+ * modulo that handles negative numbers, works the same as Python's.
+ */
MINLINE int mod_i(int i, int n);
+/**
+ * Round to closest even number, halfway cases are rounded away from zero.
+ */
MINLINE float round_to_even(float f);
MINLINE signed char round_fl_to_char(float a);
@@ -230,18 +276,40 @@ MINLINE int round_db_to_int_clamp(double a);
MINLINE unsigned int round_db_to_uint_clamp(double a);
int pow_i(int base, int exp);
+
+/**
+ * \param ndigits: must be between 0 and 21.
+ */
double double_round(double x, int ndigits);
+/**
+ * Floor to the nearest power of 10, e.g.:
+ * - 15.0 -> 10.0
+ * - 0.015 -> 0.01
+ * - 1.0 -> 1.0
+ *
+ * \param f: Value to floor, must be over 0.0.
+ * \note If we wanted to support signed values we could if this becomes necessary.
+ */
float floor_power_of_10(float f);
+/**
+ * Ceiling to the nearest power of 10, e.g.:
+ * - 15.0 -> 100.0
+ * - 0.015 -> 0.1
+ * - 1.0 -> 1.0
+ *
+ * \param f: Value to ceiling, must be over 0.0.
+ * \note If we wanted to support signed values we could if this becomes necessary.
+ */
float ceil_power_of_10(float f);
#ifdef BLI_MATH_GCC_WARN_PRAGMA
# pragma GCC diagnostic pop
#endif
-/* asserts, some math functions expect normalized inputs
- * check the vector is unit length, or zero length (which can't be helped in some cases).
- */
+/* Asserts, some math functions expect normalized inputs
+ * check the vector is unit length, or zero length (which can't be helped in some cases). */
+
#ifndef NDEBUG
/** \note 0.0001 is too small because normals may be converted from short's: see T34322. */
# define BLI_ASSERT_UNIT_EPSILON 0.0002f
diff --git a/source/blender/blenlib/BLI_math_boolean.hh b/source/blender/blenlib/BLI_math_boolean.hh
index 79b1483bfb8..20fd00b2aa4 100644
--- a/source/blender/blenlib/BLI_math_boolean.hh
+++ b/source/blender/blenlib/BLI_math_boolean.hh
@@ -32,20 +32,24 @@
namespace blender {
-/* #orient2d gives the exact result, using multi-precision arithmetic when result
+/**
+ * #orient2d gives the exact result, using multi-precision arithmetic when result
* is close to zero. orient3d_fast just uses double arithmetic, so may be
* wrong if the answer is very close to zero.
- * Similarly, for #incircle and #incircle_fast. */
+ * Similarly, for #incircle and #incircle_fast.
+ */
int orient2d(const double2 &a, const double2 &b, const double2 &c);
int orient2d_fast(const double2 &a, const double2 &b, const double2 &c);
int incircle(const double2 &a, const double2 &b, const double2 &c, const double2 &d);
int incircle_fast(const double2 &a, const double2 &b, const double2 &c, const double2 &d);
-/* #orient3d gives the exact result, using multi-precision arithmetic when result
+/**
+ * #orient3d gives the exact result, using multi-precision arithmetic when result
* is close to zero. orient3d_fast just uses double arithmetic, so may be
* wrong if the answer is very close to zero.
- * Similarly, for #insphere and #insphere_fast. */
+ * Similarly, for #insphere and #insphere_fast.
+ */
int orient3d(const double3 &a, const double3 &b, const double3 &c, const double3 &d);
int orient3d_fast(const double3 &a, const double3 &b, const double3 &c, const double3 &d);
@@ -55,8 +59,23 @@ int insphere_fast(
const double3 &a, const double3 &b, const double3 &c, const double3 &d, const double3 &e);
#ifdef WITH_GMP
+/**
+ * Return +1 if a, b, c are in CCW order around a circle in the plane.
+ * Return -1 if they are in CW order, and 0 if they are in line.
+ */
int orient2d(const mpq2 &a, const mpq2 &b, const mpq2 &c);
+/**
+ * Return +1 if d is in the oriented circle through a, b, and c.
+ * The oriented circle goes CCW through a, b, and c.
+ * Return -1 if d is outside, and 0 if it is on the circle.
+ */
int incircle(const mpq2 &a, const mpq2 &b, const mpq2 &c, const mpq2 &d);
+/**
+ * Return +1 if d is below the plane containing a, b, c (which appear
+ * CCW when viewed from above the plane).
+ * Return -1 if d is above the plane.
+ * Return 0 if it is on the plane.
+ */
int orient3d(const mpq3 &a, const mpq3 &b, const mpq3 &c, const mpq3 &d);
#endif
} // namespace blender
diff --git a/source/blender/blenlib/BLI_math_color.h b/source/blender/blenlib/BLI_math_color.h
index 28257ba418a..32424f37676 100644
--- a/source/blender/blenlib/BLI_math_color.h
+++ b/source/blender/blenlib/BLI_math_color.h
@@ -31,6 +31,10 @@
extern "C" {
#endif
+/* -------------------------------------------------------------------- */
+/** \name Defines
+ * \{ */
+
/* YCbCr */
#define BLI_YCC_ITU_BT601 0
#define BLI_YCC_ITU_BT709 1
@@ -40,7 +44,11 @@ extern "C" {
#define BLI_YUV_ITU_BT601 0
#define BLI_YUV_ITU_BT709 1
-/******************* Conversion to RGB ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Conversion to RGB
+ * \{ */
void hsv_to_rgb(float h, float s, float v, float *r_r, float *r_g, float *r_b);
void hsv_to_rgb_v(const float hsv[3], float r_rgb[3]);
@@ -51,9 +59,18 @@ void yuv_to_rgb(float y, float u, float v, float *r_r, float *r_g, float *r_b, i
void ycc_to_rgb(float y, float cb, float cr, float *r_r, float *r_g, float *r_b, int colorspace);
void cpack_to_rgb(unsigned int col, float *r_r, float *r_g, float *r_b);
-/***************** Conversion from RGB ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Conversion from RGB
+ * \{ */
void rgb_to_yuv(float r, float g, float b, float *r_y, float *r_u, float *r_v, int colorspace);
+/**
+ * The RGB inputs are supposed gamma corrected and in the range 0 - 1.0f
+ *
+ * Output YCC have a range of 16-235 and 16-240 except with JFIF_0_255 where the range is 0-255.
+ */
void rgb_to_ycc(float r, float g, float b, float *r_y, float *r_cb, float *r_cr, int colorspace);
void rgb_to_hsv(float r, float g, float b, float *r_h, float *r_s, float *r_v);
void rgb_to_hsv_v(const float rgb[3], float r_hsv[3]);
@@ -64,9 +81,19 @@ void rgb_to_hsl_compat_v(const float rgb[3], float r_hsl[3]);
void rgb_to_hsv_compat(float r, float g, float b, float *r_h, float *r_s, float *r_v);
void rgb_to_hsv_compat_v(const float rgb[3], float r_hsv[3]);
unsigned int rgb_to_cpack(float r, float g, float b);
+/**
+ * We define a 'cpack' here as a (3 byte color code)
+ * number that can be expressed like 0xFFAA66 or so.
+ * For that reason it is sensitive for endianness... with this function it works correctly.
+ * \see #imm_cpack
+ */
unsigned int hsv_to_cpack(float h, float s, float v);
-/**************** Profile Transformations *****************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Profile Transformations
+ * \{ */
float srgb_to_linearrgb(float c);
float linearrgb_to_srgb(float c);
@@ -90,7 +117,11 @@ MINLINE void linearrgb_to_srgb_uchar4(unsigned char srgb[4], const float linear[
void BLI_init_srgb_conversion(void);
-/**************** Alpha Transformations *****************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Alpha Transformations
+ * \{ */
MINLINE void premul_to_straight_v4_v4(float straight[4], const float premul[4]);
MINLINE void premul_to_straight_v4(float color[4]);
@@ -99,13 +130,34 @@ MINLINE void straight_to_premul_v4(float color[4]);
MINLINE void straight_uchar_to_premul_float(float result[4], const unsigned char color[4]);
MINLINE void premul_float_to_straight_uchar(unsigned char *result, const float color[4]);
-/************************** Other *************************/
+/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Other
+ * \{ */
+
+/**
+ * If the requested RGB shade contains a negative weight for
+ * one of the primaries, it lies outside the color gamut
+ * accessible from the given triple of primaries. Desaturate
+ * it by adding white, equal quantities of R, G, and B, enough
+ * to make RGB all positive. The function returns 1 if the
+ * components were modified, zero otherwise.
+ */
int constrain_rgb(float *r, float *g, float *b);
void minmax_rgb(short c[3]);
+/**
+ * Clamp `hsv` to usable values.
+ */
void hsv_clamp_v(float hsv[3], float v_max);
+/**
+ * Applies an HUE offset to a float RGB color.
+ */
void rgb_float_set_hue_float_offset(float rgb[3], float hue_offset);
+/**
+ * Applies an HUE offset to a byte RGB color.
+ */
void rgb_byte_set_hue_float_offset(unsigned char rgb[3], float hue_offset);
void rgb_uchar_to_float(float r_col[3], const unsigned char col_ub[3]);
@@ -113,11 +165,28 @@ void rgba_uchar_to_float(float r_col[4], const unsigned char col_ub[4]);
void rgb_float_to_uchar(unsigned char r_col[3], const float col_f[3]);
void rgba_float_to_uchar(unsigned char r_col[4], const float col_f[4]);
+/**
+ * ITU-R BT.709 primaries
+ * https://en.wikipedia.org/wiki/Relative_luminance
+ *
+ * Real values are:
+ * `Y = 0.2126390059(R) + 0.7151686788(G) + 0.0721923154(B)`
+ * according to: "Derivation of Basic Television Color Equations", RP 177-1993
+ *
+ * As this sums slightly above 1.0, the document recommends to use:
+ * `0.2126(R) + 0.7152(G) + 0.0722(B)`, as used here.
+ *
+ * The high precision values are used to calculate the rounded byte weights so they add up to 255:
+ * `54(R) + 182(G) + 19(B)`
+ */
MINLINE float rgb_to_grayscale(const float rgb[3]);
MINLINE unsigned char rgb_to_grayscale_byte(const unsigned char rgb[3]);
MINLINE int compare_rgb_uchar(const unsigned char a[3], const unsigned char b[3], const int limit);
+/**
+ * Return triangle noise in [-0.5..1.5] range.
+ */
MINLINE float dither_random_value(float s, float t);
MINLINE void float_to_byte_dither_v3(
unsigned char b[3], const float f[3], float dither, float s, float t);
@@ -145,7 +214,11 @@ MINLINE void cpack_cpy_3ub(unsigned char r_col[3], const unsigned int pack);
void blackbody_temperature_to_rgb_table(float *r_table, int width, float min, float max);
void wavelength_to_xyz_table(float *r_table, int width);
-/********* lift/gamma/gain / ASC-CDL conversion ***********/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name lift/gamma/gain / ASC-CDL conversion
+ * \{ */
void lift_gamma_gain_to_asc_cdl(const float *lift,
const float *gamma,
@@ -158,6 +231,8 @@ void lift_gamma_gain_to_asc_cdl(const float *lift,
# include "intern/math_color_inline.c"
#endif
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h
index be10b302144..55d118d17de 100644
--- a/source/blender/blenlib/BLI_math_geom.h
+++ b/source/blender/blenlib/BLI_math_geom.h
@@ -37,16 +37,24 @@
extern "C" {
#endif
-/********************************** Polygons *********************************/
+/* -------------------------------------------------------------------- */
+/** \name Polygons
+ * \{ */
float normal_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3]);
float normal_quad_v3(
float n[3], const float v1[3], const float v2[3], const float v3[3], const float v4[3]);
+/**
+ * Computes the normal of a planar polygon See Graphics Gems for computing newell normal.
+ */
float normal_poly_v3(float n[3], const float verts[][3], unsigned int nr);
MINLINE float area_tri_v2(const float v1[2], const float v2[2], const float v3[2]);
MINLINE float area_squared_tri_v2(const float v1[2], const float v2[2], const float v3[2]);
MINLINE float area_tri_signed_v2(const float v1[2], const float v2[2], const float v3[2]);
+
+/* Triangles */
+
float area_tri_v3(const float v1[3], const float v2[3], const float v3[3]);
float area_squared_tri_v3(const float v1[3], const float v2[3], const float v3[3]);
float area_tri_signed_v3(const float v1[3],
@@ -68,38 +76,88 @@ float cotangent_tri_weight_v3(const float v1[3], const float v2[3], const float
void cross_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3]);
MINLINE float cross_tri_v2(const float v1[2], const float v2[2], const float v3[2]);
void cross_poly_v3(float n[3], const float verts[][3], unsigned int nr);
+/**
+ * Scalar cross product of a 2d polygon.
+ *
+ * - equivalent to `area * 2`
+ * - useful for checking polygon winding (a positive value is clockwise).
+ */
float cross_poly_v2(const float verts[][2], unsigned int nr);
-/********************************* Planes **********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Planes
+ * \{ */
+/**
+ * Calculate a plane from a point and a direction,
+ * \note \a point_no isn't required to be normalized.
+ */
void plane_from_point_normal_v3(float r_plane[4],
const float plane_co[3],
const float plane_no[3]);
+/**
+ * Get a point and a direction from a plane.
+ */
void plane_to_point_vector_v3(const float plane[4], float r_plane_co[3], float r_plane_no[3]);
+/**
+ * Version of #plane_to_point_vector_v3 that gets a unit length vector.
+ */
void plane_to_point_vector_v3_normalized(const float plane[4],
float r_plane_co[3],
float r_plane_no[3]);
MINLINE float plane_point_side_v3(const float plane[4], const float co[3]);
-/********************************* Volume **********************************/
+/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Volume
+ * \{ */
+
+/**
+ * The volume from a tetrahedron, points can be in any order
+ */
float volume_tetrahedron_v3(const float v1[3],
const float v2[3],
const float v3[3],
const float v4[3]);
+/**
+ * The volume from a tetrahedron, normal pointing inside gives negative volume
+ */
float volume_tetrahedron_signed_v3(const float v1[3],
const float v2[3],
const float v3[3],
const float v4[3]);
+/**
+ * The volume from a triangle that is made into a tetrahedron.
+ * This uses a simplified formula where the tip of the tetrahedron is in the world origin.
+ * Using this method, the total volume of a closed triangle mesh can be calculated.
+ * Note that you need to divide the result by 6 to get the actual volume.
+ */
float volume_tri_tetrahedron_signed_v3_6x(const float v1[3], const float v2[3], const float v3[3]);
float volume_tri_tetrahedron_signed_v3(const float v1[3], const float v2[3], const float v3[3]);
+/**
+ * Check if the edge is convex or concave
+ * (depends on face winding)
+ * Copied from BM_edge_is_convex().
+ */
bool is_edge_convex_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3]);
+/**
+ * Evaluate if entire quad is a proper convex quad
+ */
bool is_quad_convex_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3]);
bool is_quad_convex_v2(const float v1[2], const float v2[2], const float v3[2], const float v4[2]);
bool is_poly_convex_v2(const float verts[][2], unsigned int nr);
+/**
+ * Check if either of the diagonals along this quad create flipped triangles
+ * (normals pointing away from eachother).
+ * - (1 << 0): (v1-v3) is flipped.
+ * - (1 << 1): (v2-v4) is flipped.
+ */
int is_quad_flip_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3]);
bool is_quad_flip_v3_first_third_fast(const float v1[3],
const float v2[3],
@@ -111,36 +169,88 @@ bool is_quad_flip_v3_first_third_fast_with_normal(const float v1[3],
const float v4[3],
const float normal[3]);
-/********************************* Distance **********************************/
+/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Distance
+ * \{ */
+
+/**
+ * Distance p to line v1-v2 using Hesse formula (NO LINE PIECE!)
+ */
float dist_squared_to_line_v2(const float p[2], const float l1[2], const float l2[2]);
float dist_to_line_v2(const float p[2], const float l1[2], const float l2[2]);
+/**
+ * Distance p to line-piece v1-v2.
+ */
float dist_squared_to_line_segment_v2(const float p[2], const float l1[2], const float l2[2]);
float dist_to_line_segment_v2(const float p[2], const float l1[2], const float l2[2]);
float dist_signed_squared_to_plane_v3(const float p[3], const float plane[4]);
float dist_squared_to_plane_v3(const float p[3], const float plane[4]);
+/**
+ * Return the signed distance from the point to the plane.
+ */
float dist_signed_to_plane_v3(const float p[3], const float plane[4]);
float dist_to_plane_v3(const float p[3], const float plane[4]);
-/* plane3 versions */
+/* Plane3 versions. */
+
float dist_signed_squared_to_plane3_v3(const float p[3], const float plane[3]);
float dist_squared_to_plane3_v3(const float p[3], const float plane[3]);
float dist_signed_to_plane3_v3(const float p[3], const float plane[3]);
float dist_to_plane3_v3(const float p[3], const float plane[3]);
+/**
+ * Distance v1 to line-piece l1-l2 in 3D.
+ */
float dist_squared_to_line_segment_v3(const float p[3], const float l1[3], const float l2[3]);
float dist_to_line_segment_v3(const float p[3], const float l1[3], const float l2[3]);
float dist_squared_to_line_v3(const float p[3], const float l1[3], const float l2[3]);
float dist_to_line_v3(const float p[3], const float l1[3], const float l2[3]);
+/**
+ * Check if \a p is inside the 2x planes defined by `(v1, v2, v3)`
+ * where the 3x points define 2x planes.
+ *
+ * \param axis_ref: used when v1,v2,v3 form a line and to check if the corner is concave/convex.
+ *
+ * \note the distance from \a v1 & \a v3 to \a v2 doesn't matter
+ * (it just defines the planes).
+ *
+ * \return the lowest squared distance to either of the planes.
+ * where `(return < 0.0)` is outside.
+ *
+ * <pre>
+ * v1
+ * +
+ * /
+ * x - out / x - inside
+ * /
+ * +----+
+ * v2 v3
+ * x - also outside
+ * </pre>
+ */
float dist_signed_squared_to_corner_v3v3v3(const float p[3],
const float v1[3],
const float v2[3],
const float v3[3],
const float axis_ref[3]);
+/**
+ * Compute the squared distance of a point to a line (defined as ray).
+ * \param ray_origin: A point on the line.
+ * \param ray_direction: Normalized direction of the line.
+ * \param co: Point to which the distance is to be calculated.
+ */
float dist_squared_to_ray_v3_normalized(const float ray_origin[3],
const float ray_direction[3],
const float co[3]);
+/**
+ * Find the closest point in a seg to a ray and return the distance squared.
+ * \param r_point: Is the point on segment closest to ray
+ * (or to ray_origin if the ray and the segment are parallel).
+ * \param r_depth: the distance of r_point projection on ray to the ray_origin.
+ */
float dist_squared_ray_to_seg_v3(const float ray_origin[3],
const float ray_direction[3],
const float v0[3],
@@ -148,6 +258,9 @@ float dist_squared_ray_to_seg_v3(const float ray_origin[3],
float r_point[3],
float *r_depth);
+/**
+ * Returns the coordinates of the nearest vertex and the farthest vertex from a plane (or normal).
+ */
void aabb_get_near_far_from_plane(const float plane_no[3],
const float bbmin[3],
const float bbmax[3],
@@ -162,12 +275,17 @@ struct DistRayAABB_Precalc {
void dist_squared_ray_to_aabb_v3_precalc(struct DistRayAABB_Precalc *neasrest_precalc,
const float ray_origin[3],
const float ray_direction[3]);
+/**
+ * Returns the distance from a ray to a bound-box (projected on ray)
+ */
float dist_squared_ray_to_aabb_v3(const struct DistRayAABB_Precalc *data,
const float bb_min[3],
const float bb_max[3],
float r_point[3],
float *r_depth);
-/* when there is no advantage to precalc. */
+/**
+ * Use when there is no advantage to pre-calculation.
+ */
float dist_squared_ray_to_aabb_v3_simple(const float ray_origin[3],
const float ray_direction[3],
const float bb_min[3],
@@ -182,10 +300,17 @@ struct DistProjectedAABBPrecalc {
float pmat[4][4];
float mval[2];
};
+/**
+ * \param projmat: Projection Matrix (usually perspective
+ * matrix multiplied by object matrix).
+ */
void dist_squared_to_projected_aabb_precalc(struct DistProjectedAABBPrecalc *precalc,
const float projmat[4][4],
const float winsize[2],
const float mval[2]);
+/**
+ * Returns the distance from a 2D coordinate to a bound-box (projected).
+ */
float dist_squared_to_projected_aabb(struct DistProjectedAABBPrecalc *data,
const float bbmin[3],
const float bbmax[3],
@@ -205,21 +330,42 @@ double closest_to_line_v2_db(double r_close[2],
const double p[2],
const double l1[2],
const double l2[2]);
+/**
+ * Find closest point to p on line through (`l1`, `l2`) and return lambda,
+ * where (0 <= lambda <= 1) when `p` is in the line segment (`l1`, `l2`).
+ */
float closest_to_line_v3(float r_close[3], const float p[3], const float l1[3], const float l2[3]);
+/**
+ * Point closest to v1 on line v2-v3 in 2D.
+ */
void closest_to_line_segment_v2(float r_close[2],
const float p[2],
const float l1[2],
const float l2[2]);
+/**
+ * Point closest to v1 on line v2-v3 in 3D.
+ */
void closest_to_line_segment_v3(float r_close[3],
const float p[3],
const float l1[3],
const float l2[3]);
void closest_to_plane_normalized_v3(float r_close[3], const float plane[4], const float pt[3]);
+/**
+ * Find the closest point on a plane.
+ *
+ * \param r_close: Return coordinate
+ * \param plane: The plane to test against.
+ * \param pt: The point to find the nearest of
+ *
+ * \note non-unit-length planes are supported.
+ */
void closest_to_plane_v3(float r_close[3], const float plane[4], const float pt[3]);
void closest_to_plane3_normalized_v3(float r_close[3], const float plane[3], const float pt[3]);
void closest_to_plane3_v3(float r_close[3], const float plane[3], const float pt[3]);
-/* Set 'r' to the point in triangle (v1, v2, v3) closest to point 'p' */
+/**
+ * Set 'r' to the point in triangle (v1, v2, v3) closest to point 'p'.
+ */
void closest_on_tri_to_point_v3(
float r[3], const float p[3], const float v1[3], const float v2[3], const float v3[3]);
@@ -232,6 +378,13 @@ float ray_point_factor_v3(const float p[3],
const float ray_origin[3],
const float ray_direction[3]);
+/**
+ * A simplified version of #closest_to_line_v3
+ * we only need to return the `lambda`
+ *
+ * \param epsilon: avoid approaching divide-by-zero.
+ * Passing a zero will just check for nonzero division.
+ */
float line_point_factor_v3_ex(const float p[3],
const float l1[3],
const float l2[3],
@@ -246,14 +399,25 @@ float line_point_factor_v2_ex(const float p[2],
const float fallback);
float line_point_factor_v2(const float p[2], const float l1[2], const float l2[2]);
+/**
+ * \note #isect_line_plane_v3() shares logic.
+ */
float line_plane_factor_v3(const float plane_co[3],
const float plane_no[3],
const float l1[3],
const float l2[3]);
+/**
+ * Ensure the distance between these points is no greater than 'dist'.
+ * If it is, scale them both into the center.
+ */
void limit_dist_v3(float v1[3], float v2[3], const float dist);
-/******************************* Intersection ********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Intersection
+ * \{ */
/* TODO: int return value consistency. */
@@ -263,7 +427,13 @@ void limit_dist_v3(float v1[3], float v2[3], const float dist);
#define ISECT_LINE_LINE_EXACT 1
#define ISECT_LINE_LINE_CROSS 2
+/**
+ * Intersect Line-Line, floats.
+ */
int isect_seg_seg_v2(const float v1[2], const float v2[2], const float v3[2], const float v4[2]);
+/**
+ * Returns a point on each segment that is closest to the other.
+ */
void isect_seg_seg_v3(const float a0[3],
const float a1[3],
const float b0[3],
@@ -271,7 +441,21 @@ void isect_seg_seg_v3(const float a0[3],
float r_a[3],
float r_b[3]);
+/* intersect Line-Line, shorts */
int isect_seg_seg_v2_int(const int v1[2], const int v2[2], const int v3[2], const int v4[2]);
+/**
+ * Get intersection point of two 2D segments.
+ *
+ * \param endpoint_bias: Bias to use when testing for end-point overlap.
+ * A positive value considers intersections that extend past the endpoints,
+ * negative values contract the endpoints.
+ * Note the bias is applied to a 0-1 factor, not scaled to the length of segments.
+ *
+ * \returns intersection type:
+ * - -1: collinear.
+ * - 1: intersection.
+ * - 0: no intersection.
+ */
int isect_seg_seg_v2_point_ex(const float v0[2],
const float v1[2],
const float v2[2],
@@ -284,12 +468,37 @@ bool isect_seg_seg_v2_simple(const float v1[2],
const float v2[2],
const float v3[2],
const float v4[2]);
+/**
+ * If intersection == ISECT_LINE_LINE_CROSS or ISECT_LINE_LINE_NONE:
+ * <pre>
+ * pt = v1 + lambda * (v2 - v1) = v3 + mu * (v4 - v3)
+ * </pre>
+ * \returns intersection type:
+ * - ISECT_LINE_LINE_COLINEAR: collinear.
+ * - ISECT_LINE_LINE_EXACT: intersection at an endpoint of either.
+ * - ISECT_LINE_LINE_CROSS: interaction, not at an endpoint.
+ * - ISECT_LINE_LINE_NONE: no intersection.
+ * Also returns lambda and mu in r_lambda and r_mu.
+ */
int isect_seg_seg_v2_lambda_mu_db(const double v1[2],
const double v2[2],
const double v3[2],
const double v4[2],
double *r_lambda,
double *r_mu);
+/**
+ * \param l1, l2: Coordinates (point of line).
+ * \param sp, r: Coordinate and radius (sphere).
+ * \return r_p1, r_p2: Intersection coordinates.
+ *
+ * \note The order of assignment for intersection points (\a r_p1, \a r_p2) is predictable,
+ * based on the direction defined by `l2 - l1`,
+ * this direction compared with the normal of each point on the sphere:
+ * \a r_p1 always has a >= 0.0 dot product.
+ * \a r_p2 always has a <= 0.0 dot product.
+ * For example, when \a l1 is inside the sphere and \a l2 is outside,
+ * \a r_p1 will always be between \a l1 and \a l2.
+ */
int isect_line_sphere_v3(const float l1[3],
const float l2[3],
const float sp[3],
@@ -303,8 +512,17 @@ int isect_line_sphere_v2(const float l1[2],
float r_p1[2],
float r_p2[2]);
+/**
+ * Intersect Line-Line, floats - gives intersection point.
+ */
int isect_line_line_v2_point(
const float v0[2], const float v1[2], const float v2[2], const float v3[2], float r_vi[2]);
+/**
+ * \return The number of point of interests
+ * 0 - lines are collinear
+ * 1 - lines are coplanar, i1 is set to intersection
+ * 2 - i1 and i2 are the nearest points on line 1 (v1, v2) and line 2 (v3, v4) respectively
+ */
int isect_line_line_epsilon_v3(const float v1[3],
const float v2[3],
const float v3[3],
@@ -318,12 +536,22 @@ int isect_line_line_v3(const float v1[3],
const float v4[3],
float r_i1[3],
float r_i2[3]);
+/**
+ * Intersection point strictly between the two lines
+ * \return false when no intersection is found.
+ */
bool isect_line_line_strict_v3(const float v1[3],
const float v2[3],
const float v3[3],
const float v4[3],
float vi[3],
float *r_lambda);
+/**
+ * Check if two rays are not parallel and returns a factor that indicates
+ * the distance from \a ray_origin_b to the closest point on ray-a to ray-b.
+ *
+ * \note Neither directions need to be normalized.
+ */
bool isect_ray_ray_epsilon_v3(const float ray_origin_a[3],
const float ray_direction_a[3],
const float ray_origin_b[3],
@@ -338,30 +566,85 @@ bool isect_ray_ray_v3(const float ray_origin_a[3],
float *r_lambda_a,
float *r_lambda_b);
+/**
+ * if clip is nonzero, will only return true if lambda is >= 0.0
+ * (i.e. intersection point is along positive \a ray_direction)
+ *
+ * \note #line_plane_factor_v3() shares logic.
+ */
bool isect_ray_plane_v3(const float ray_origin[3],
const float ray_direction[3],
const float plane[4],
float *r_lambda,
const bool clip);
+/**
+ * Check if a point is behind all planes.
+ */
bool isect_point_planes_v3(float (*planes)[4], int totplane, const float p[3]);
+/**
+ * Check if a point is in front all planes.
+ * Same as isect_point_planes_v3 but with planes facing the opposite direction.
+ */
bool isect_point_planes_v3_negated(const float (*planes)[4], const int totplane, const float p[3]);
+/**
+ * Intersect line/plane.
+ *
+ * \param r_isect_co: The intersection point.
+ * \param l1: The first point of the line.
+ * \param l2: The second point of the line.
+ * \param plane_co: A point on the plane to intersect with.
+ * \param plane_no: The direction of the plane (does not need to be normalized).
+ *
+ * \note #line_plane_factor_v3() shares logic.
+ */
bool isect_line_plane_v3(float r_isect_co[3],
const float l1[3],
const float l2[3],
const float plane_co[3],
const float plane_no[3]) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Intersect three planes, return the point where all 3 meet.
+ * See Graphics Gems 1 pg 305
+ *
+ * \param plane_a, plane_b, plane_c: Planes.
+ * \param r_isect_co: The resulting intersection point.
+ */
bool isect_plane_plane_plane_v3(const float plane_a[4],
const float plane_b[4],
const float plane_c[4],
float r_isect_co[3]) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Intersect two planes, return a point on the intersection and a vector
+ * that runs on the direction of the intersection.
+ * \note this is a slightly reduced version of #isect_plane_plane_plane_v3
+ *
+ * \param plane_a, plane_b: Planes.
+ * \param r_isect_co: The resulting intersection point.
+ * \param r_isect_no: The resulting vector of the intersection.
+ *
+ * \note \a r_isect_no isn't unit length.
+ */
bool isect_plane_plane_v3(const float plane_a[4],
const float plane_b[4],
float r_isect_co[3],
float r_isect_no[3]) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Intersect all planes, calling `callback_fn` for each point that intersects
+ * 3 of the planes that isn't outside any of the other planes.
+ *
+ * This can be thought of as calculating a convex-hull from an array of planes.
+ *
+ * \param eps_coplanar: Epsilon for testing if two planes are aligned (co-planar).
+ * \param eps_isect: Epsilon for testing of a point is behind any of the planes.
+ *
+ * \warning As complexity is a little under `O(N^3)`, this is only suitable for small arrays.
+ *
+ * \note This function could be optimized by some spatial structure.
+ */
bool isect_planes_v3_fn(
const float planes[][4],
const int planes_len,
@@ -371,6 +654,11 @@ bool isect_planes_v3_fn(
void *user_data);
/* line/ray triangle */
+
+/**
+ * Test if the line starting at p1 ending at p2 intersects the triangle v0..v2
+ * return non zero if it does.
+ */
bool isect_line_segment_tri_v3(const float p1[3],
const float p2[3],
const float v0[3],
@@ -378,6 +666,9 @@ bool isect_line_segment_tri_v3(const float p1[3],
const float v2[3],
float *r_lambda,
float r_uv[2]);
+/**
+ * Like #isect_line_segment_tri_v3, but allows epsilon tolerance around triangle.
+ */
bool isect_line_segment_tri_epsilon_v3(const float p1[3],
const float p2[3],
const float v0[3],
@@ -394,6 +685,10 @@ bool isect_axial_line_segment_tri_v3(const int axis,
const float v2[3],
float *r_lambda);
+/**
+ * Test if the ray starting at p1 going in d direction intersects the triangle v0..v2
+ * return non zero if it does.
+ */
bool isect_ray_tri_v3(const float ray_origin[3],
const float ray_direction[3],
const float v0[3],
@@ -417,6 +712,16 @@ bool isect_ray_tri_epsilon_v3(const float ray_origin[3],
float *r_lambda,
float r_uv[2],
const float epsilon);
+/**
+ * Intersect two triangles.
+ *
+ * \param r_i1, r_i2: Retrieve the overlapping edge between the 2 triangles.
+ * \param r_tri_a_edge_isect_count: Indicates how many edges in the first triangle are intersected.
+ * \return true when the triangles intersect.
+ *
+ * \note If it exists, \a r_i1 will be a point on the edge of the 1st triangle.
+ * \note intersections between coplanar triangles are currently undetected.
+ */
bool isect_tri_tri_v3_ex(const float tri_a[3][3],
const float tri_b[3][3],
float r_i1[3],
@@ -438,7 +743,9 @@ bool isect_tri_tri_v2(const float p1[2],
const float q2[2],
const float r2[2]);
-/* water-tight ray-cast (requires pre-calculation). */
+/**
+ * Water-tight ray-cast (requires pre-calculation).
+ */
struct IsectRayPrecalc {
/* Maximal dimension `kz`, and orthogonal dimensions. */
int kx, ky, kz;
@@ -456,7 +763,9 @@ bool isect_ray_tri_watertight_v3(const float ray_origin[3],
const float v2[3],
float *r_dist,
float r_uv[2]);
-/* slower version which calculates IsectRayPrecalc each time */
+/**
+ * Slower version which calculates #IsectRayPrecalc each time.
+ */
bool isect_ray_tri_watertight_v3_simple(const float ray_origin[3],
const float ray_direction[3],
const float v0[3],
@@ -478,7 +787,8 @@ bool isect_ray_line_v3(const float ray_origin[3],
const float v1[3],
float *r_lambda);
-/* point in polygon */
+/* Point in polygon. */
+
bool isect_point_poly_v2(const float pt[2],
const float verts[][2],
const unsigned int nr,
@@ -488,27 +798,50 @@ bool isect_point_poly_v2_int(const int pt[2],
const unsigned int nr,
const bool use_holes);
+/**
+ * Point in quad - only convex quads.
+ */
int isect_point_quad_v2(
const float p[2], const float v1[2], const float v2[2], const float v3[2], const float v4[2]);
int isect_point_tri_v2(const float pt[2], const float v1[2], const float v2[2], const float v3[2]);
+/**
+ * Only single direction.
+ */
bool isect_point_tri_v2_cw(const float pt[2],
const float v1[2],
const float v2[2],
const float v3[2]);
+/**
+ * \code{.unparsed}
+ * x1,y2
+ * | \
+ * | \ .(a,b)
+ * | \
+ * x1,y1-- x2,y1
+ * \endcode
+ */
int isect_point_tri_v2_int(
const int x1, const int y1, const int x2, const int y2, const int a, const int b);
bool isect_point_tri_prism_v3(const float p[3],
const float v1[3],
const float v2[3],
const float v3[3]);
+/**
+ * \param r_isect_co: The point \a p projected onto the triangle.
+ * \return True when \a p is inside the triangle.
+ * \note Its up to the caller to check the distance between \a p and \a r_vi
+ * against an error margin.
+ */
bool isect_point_tri_v3(const float p[3],
const float v1[3],
const float v2[3],
const float v3[3],
float r_isect_co[3]);
-/* axis-aligned bounding box */
+/**
+ * Axis-aligned bounding box.
+ */
bool isect_aabb_aabb_v3(const float min1[3],
const float max1[3],
const float min2[3],
@@ -527,6 +860,13 @@ bool isect_ray_aabb_v3(const struct IsectRayAABB_Precalc *data,
const float bb_min[3],
const float bb_max[3],
float *tmin);
+/**
+ * Test a bounding box (AABB) for ray intersection.
+ * Assumes the ray is already local to the boundbox space.
+ *
+ * \note \a direction should be normalized
+ * if you intend to use the \a tmin or \a tmax distance results!
+ */
bool isect_ray_aabb_v3_simple(const float orig[3],
const float dir[3],
const float bb_min[3],
@@ -539,6 +879,14 @@ bool isect_ray_aabb_v3_simple(const float orig[3],
#define ISECT_AABB_PLANE_CROSS_ANY 1
#define ISECT_AABB_PLANE_IN_FRONT_ALL 2
+/**
+ * Checks status of an AABB in relation to a list of planes.
+ *
+ * \returns intersection type:
+ * - ISECT_AABB_PLANE_BEHIND_ONE (0): AABB is completely behind at least 1 plane;
+ * - ISECT_AABB_PLANE_CROSS_ANY (1): AABB intersects at least 1 plane;
+ * - ISECT_AABB_PLANE_IN_FRONT_ALL (2): AABB is completely in front of all planes;
+ */
int isect_aabb_planes_v3(const float (*planes)[4],
const int totplane,
const float bbmin[3],
@@ -564,7 +912,12 @@ bool clip_segment_v3_plane_n(const float p1[3],
bool point_in_slice_seg(float p[3], float l1[3], float l2[3]);
-/****************************** Interpolation ********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Interpolation
+ * \{ */
+
void interp_weights_tri_v3(
float w[3], const float v1[3], const float v2[3], const float v3[3], const float co[3]);
void interp_weights_quad_v3(float w[4],
@@ -576,6 +929,7 @@ void interp_weights_quad_v3(float w[4],
void interp_weights_poly_v3(float w[], float v[][3], const int n, const float co[3]);
void interp_weights_poly_v2(float w[], float v[][2], const int n, const float co[2]);
+/* (x1, v1)(t1=0)------(x2, v2)(t2=1), 0<t<1 --> (x, v)(t) */
void interp_cubic_v3(float x[3],
float v[3],
const float x1[3],
@@ -584,8 +938,17 @@ void interp_cubic_v3(float x[3],
const float v2[3],
const float t);
+/**
+ * Given an array with some invalid values this function interpolates valid values
+ * replacing the invalid ones.
+ */
int interp_sparse_array(float *array, const int list_size, const float skipval);
+/**
+ * Given 2 triangles in 3D space, and a point in relation to the first triangle.
+ * calculate the location of a point in relation to the second triangle.
+ * Useful for finding relative positions with geometry.
+ */
void transform_point_by_tri_v3(float pt_tar[3],
float const pt_src[3],
const float tri_tar_p1[3],
@@ -594,6 +957,10 @@ void transform_point_by_tri_v3(float pt_tar[3],
const float tri_src_p1[3],
const float tri_src_p2[3],
const float tri_src_p3[3]);
+/**
+ * Simply re-interpolates,
+ * assumes p_src is between \a l_src_p1-l_src_p2
+ */
void transform_point_by_seg_v3(float p_dst[3],
const float p_src[3],
const float l_dst_p1[3],
@@ -601,12 +968,32 @@ void transform_point_by_seg_v3(float p_dst[3],
const float l_src_p1[3],
const float l_src_p2[3]);
+/**
+ * \note Using #cross_tri_v2 means locations outside the triangle are correctly weighted.
+ *
+ * \note This is *exactly* the same calculation as #resolve_tri_uv_v2,
+ * although it has double precision and is used for texture baking, so keep both.
+ */
void barycentric_weights_v2(
const float v1[2], const float v2[2], const float v3[2], const float co[2], float w[3]);
+/**
+ * A version of #barycentric_weights_v2 that doesn't allow negative weights.
+ * Useful when negative values cause problems and points are only
+ * ever slightly outside of the triangle.
+ */
void barycentric_weights_v2_clamped(
const float v1[2], const float v2[2], const float v3[2], const float co[2], float w[3]);
+/**
+ * still use 2D X,Y space but this works for verts transformed by a perspective matrix,
+ * using their 4th component as a weight
+ */
void barycentric_weights_v2_persp(
const float v1[4], const float v2[4], const float v3[4], const float co[2], float w[3]);
+/**
+ * same as #barycentric_weights_v2 but works with a quad,
+ * NOTE: untested for values outside the quad's bounds
+ * this is #interp_weights_poly_v2 expanded for quads only
+ */
void barycentric_weights_v2_quad(const float v1[2],
const float v2[2],
const float v3[2],
@@ -614,20 +1001,47 @@ void barycentric_weights_v2_quad(const float v1[2],
const float co[2],
float w[4]);
+/**
+ * \return false for degenerated triangles.
+ */
bool barycentric_coords_v2(
const float v1[2], const float v2[2], const float v3[2], const float co[2], float w[3]);
+/**
+ * \return
+ * - 0 if the point is outside of triangle.
+ * - 1 if the point is inside triangle.
+ * - 2 if it's on the edge.
+ */
int barycentric_inside_triangle_v2(const float w[3]);
+/**
+ * Barycentric reverse
+ *
+ * Compute coordinates (u, v) for point \a st with respect to triangle (\a st0, \a st1, \a st2)
+ *
+ * \note same basic result as #barycentric_weights_v2, see its comment for details.
+ */
void resolve_tri_uv_v2(
float r_uv[2], const float st[2], const float st0[2], const float st1[2], const float st2[2]);
+/**
+ * Barycentric reverse 3d
+ *
+ * Compute coordinates (u, v) for point \a st with respect to triangle (\a st0, \a st1, \a st2)
+ */
void resolve_tri_uv_v3(
float r_uv[2], const float st[3], const float st0[3], const float st1[3], const float st2[3]);
+/**
+ * Bilinear reverse.
+ */
void resolve_quad_uv_v2(float r_uv[2],
const float st[2],
const float st0[2],
const float st1[2],
const float st2[2],
const float st3[2]);
+/**
+ * Bilinear reverse with derivatives.
+ */
void resolve_quad_uv_v2_deriv(float r_uv[2],
float r_deriv[2][2],
const float st[2],
@@ -635,22 +1049,35 @@ void resolve_quad_uv_v2_deriv(float r_uv[2],
const float st1[2],
const float st2[2],
const float st3[2]);
+/**
+ * A version of resolve_quad_uv_v2 that only calculates the 'u'.
+ */
float resolve_quad_u_v2(const float st[2],
const float st0[2],
const float st1[2],
const float st2[2],
const float st3[2]);
-/* use to find the point of a UV on a face */
+/**
+ * Use to find the point of a UV on a face.
+ * Reverse of `resolve_*` functions.
+ */
void interp_bilinear_quad_v3(float data[4][3], float u, float v, float res[3]);
void interp_barycentric_tri_v3(float data[3][3], float u, float v, float res[3]);
-/***************************** View & Projection *****************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View & Projection
+ * \{ */
void lookat_m4(
float mat[4][4], float vx, float vy, float vz, float px, float py, float pz, float twist);
void polarview_m4(float mat[4][4], float dist, float azimuth, float incidence, float twist);
+/**
+ * Matches `glFrustum` result.
+ */
void perspective_m4(float mat[4][4],
const float left,
const float right,
@@ -665,6 +1092,9 @@ void perspective_m4_fov(float mat[4][4],
const float angle_down,
const float nearClip,
const float farClip);
+/**
+ * Matches `glOrtho` result.
+ */
void orthographic_m4(float mat[4][4],
const float left,
const float right,
@@ -672,8 +1102,18 @@ void orthographic_m4(float mat[4][4],
const float top,
const float nearClip,
const float farClip);
+/**
+ * Translate a matrix created by orthographic_m4 or perspective_m4 in XY coords
+ * (used to jitter the view).
+ */
void window_translate_m4(float winmat[4][4], float perspmat[4][4], const float x, const float y);
+/**
+ * Frustum planes extraction from a projection matrix
+ * (homogeneous 4d vector representations of planes).
+ *
+ * plane parameters can be NULL if you do not need them.
+ */
void planes_from_projmat(const float mat[4][4],
float left[4],
float right[4],
@@ -697,6 +1137,14 @@ void projmat_dimensions_db(const float winmat[4][4],
double *r_near,
double *r_far);
+/**
+ * Creates a projection matrix for a small region of the viewport.
+ *
+ * \param projmat: Projection Matrix.
+ * \param win_size: Viewport Size.
+ * \param x_min, x_max, y_min, y_max: Coordinates of the subregion.
+ * \return r_projmat: Resulting Projection Matrix.
+ */
void projmat_from_subregion(const float projmat[4][4],
const int win_size[2],
const int x_min,
@@ -708,7 +1156,11 @@ void projmat_from_subregion(const float projmat[4][4],
int box_clip_bounds_m4(float boundbox[2][3], const float bounds[4], float winmat[4][4]);
void box_minmax_bounds_m4(float min[3], float max[3], float boundbox[2][3], float mat[4][4]);
-/********************************** Mapping **********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Mapping
+ * \{ */
void map_to_tube(float *r_u, float *r_v, const float x, const float y, const float z);
void map_to_sphere(float *r_u, float *r_v, const float x, const float y, const float z);
@@ -718,7 +1170,11 @@ void map_to_plane_axis_angle_v2_v3v3fl(float r_co[2],
const float axis[3],
const float angle);
-/********************************** Normals **********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Normals
+ * \{ */
void accumulate_vertex_normals_tri_v3(float n1[3],
float n2[3],
@@ -738,13 +1194,21 @@ void accumulate_vertex_normals_v3(float n1[3],
const float co3[3],
const float co4[3]);
+/**
+ * Add weighted face normal component into normals of the face vertices.
+ * Caller must pass pre-allocated vdiffs of nverts length.
+ */
void accumulate_vertex_normals_poly_v3(float **vertnos,
const float polyno[3],
const float **vertcos,
float vdiffs[][3],
const int nverts);
-/********************************* Tangents **********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Tangents
+ * \{ */
void tangent_from_uv_v3(const float uv1[2],
const float uv2[2],
@@ -755,8 +1219,31 @@ void tangent_from_uv_v3(const float uv1[2],
const float n[3],
float r_tang[3]);
-/******************************** Vector Clouds ******************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Clouds
+ * \{ */
+/**
+ * Input:
+ *
+ * \param list_size: 4 lists as pointer to array[list_size]
+ * \param pos: current pos array of 'new' positions
+ * \param weight: current weight array of 'new'weights (may be NULL pointer if you have no weights)
+ * \param rpos: Reference rpos array of 'old' positions
+ * \param rweight: Reference rweight array of 'old'weights
+ * (may be NULL pointer if you have no weights).
+ *
+ * Output:
+ *
+ * \param lloc: Center of mass pos.
+ * \param rloc: Center of mass rpos.
+ * \param lrot: Rotation matrix.
+ * \param lscale: Scale matrix.
+ *
+ * pointers may be NULL if not needed
+ */
void vcloud_estimate_transform_v3(const int list_size,
const float (*pos)[3],
const float *weight,
@@ -767,12 +1254,16 @@ void vcloud_estimate_transform_v3(const int list_size,
float lrot[3][3],
float lscale[3][3]);
-/****************************** Spherical Harmonics *************************/
+/** \} */
-/* Uses 2nd order SH => 9 coefficients, stored in this order:
- * 0 = (0, 0),
- * 1 = (1, -1), 2 = (1, 0), 3 = (1, 1),
- * 4 = (2, -2), 5 = (2, -1), 6 = (2, 0), 7 = (2, 1), 8 = (2, 2) */
+/* -------------------------------------------------------------------- */
+/** \name Spherical Harmonics
+ *
+ * Uses 2nd order SH => 9 coefficients, stored in this order:
+ * - 0 = `(0, 0)`
+ * - 1 = `(1, -1), 2 = (1, 0), 3 = (1, 1)`
+ * - 4 = `(2, -2), 5 = (2, -1), 6 = (2, 0), 7 = (2, 1), 8 = (2, 2)`
+ * \{ */
MINLINE void zero_sh(float r[9]);
MINLINE void copy_sh_sh(float r[9], const float a[9]);
@@ -785,7 +1276,11 @@ MINLINE float diffuse_shv3(const float r[9], const float v[3]);
MINLINE void vec_fac_to_sh(float r[9], const float v[3], const float f);
MINLINE void madd_sh_shfl(float r[9], const float sh[9], const float f);
-/********************************* Form Factor *******************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Form Factor
+ * \{ */
float form_factor_quad(const float p[3],
const float n[3],
@@ -805,37 +1300,117 @@ bool form_factor_visible_quad(const float p[3],
float form_factor_hemi_poly(
float p[3], float n[3], float v1[3], float v2[3], float v3[3], float v4[3]);
+/**
+ * Same as axis_dominant_v3_to_m3, but flips the normal
+ */
void axis_dominant_v3_to_m3_negate(float r_mat[3][3], const float normal[3]);
+/**
+ * \brief Normal to x,y matrix
+ *
+ * Creates a 3x3 matrix from a normal.
+ * This matrix can be applied to vectors so their 'z' axis runs along \a normal.
+ * In practice it means you can use x,y as 2d coords. \see
+ *
+ * \param r_mat: The matrix to return.
+ * \param normal: A unit length vector.
+ */
void axis_dominant_v3_to_m3(float r_mat[3][3], const float normal[3]);
+/**
+ * Get the 2 dominant axis values, 0==X, 1==Y, 2==Z.
+ */
MINLINE void axis_dominant_v3(int *r_axis_a, int *r_axis_b, const float axis[3]);
+/**
+ * Same as #axis_dominant_v3 but return the max value.
+ */
MINLINE float axis_dominant_v3_max(int *r_axis_a,
int *r_axis_b,
const float axis[3]) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Get the single dominant axis value, 0==X, 1==Y, 2==Z.
+ */
MINLINE int axis_dominant_v3_single(const float vec[3]);
+/**
+ * The dominant axis of an orthogonal vector.
+ */
MINLINE int axis_dominant_v3_ortho_single(const float vec[3]);
MINLINE int max_axis_v3(const float vec[3]);
MINLINE int min_axis_v3(const float vec[3]);
+/**
+ * Simple function to either:
+ * - Calculate how many triangles needed from the total number of polygons + loops.
+ * - Calculate the first triangle index from the polygon index & that polygons loop-start.
+ *
+ * \param poly_count: The number of polygons or polygon-index
+ * (3+ sided faces, 1-2 sided give incorrect results).
+ * \param corner_count: The number of corners (also called loop-index).
+ */
MINLINE int poly_to_tri_count(const int poly_count, const int corner_count);
+/**
+ * Useful to calculate an even width shell, by taking the angle between 2 planes.
+ * The return value is a scale on the offset.
+ * no angle between planes is 1.0, as the angle between the 2 planes approaches 180d
+ * the distance gets very high, 180d would be inf, but this case isn't valid.
+ */
MINLINE float shell_angle_to_dist(const float angle);
+/**
+ * Equivalent to `shell_angle_to_dist(angle_normalized_v3v3(a, b))`.
+ */
MINLINE float shell_v3v3_normalized_to_dist(const float a[3], const float b[3]);
+/**
+ * Equivalent to `shell_angle_to_dist(angle_normalized_v2v2(a, b))`.
+ */
MINLINE float shell_v2v2_normalized_to_dist(const float a[2], const float b[2]);
+/**
+ * Equivalent to `shell_angle_to_dist(angle_normalized_v3v3(a, b) / 2)`.
+ */
MINLINE float shell_v3v3_mid_normalized_to_dist(const float a[3], const float b[3]);
+/**
+ * Equivalent to `shell_angle_to_dist(angle_normalized_v2v2(a, b) / 2)`.
+ */
MINLINE float shell_v2v2_mid_normalized_to_dist(const float a[2], const float b[2]);
-/********************************* Cubic (Bezier) *******************************/
+/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Cubic (Bezier)
+ * \{ */
+
+/**
+ * Return the value which the distance between points will need to be scaled by,
+ * to define a handle, given both points are on a perfect circle.
+ *
+ * Use when we want a bezier curve to match a circle as closely as possible.
+ *
+ * \note the return value will need to be divided by 0.75 for correct results.
+ */
float cubic_tangent_factor_circle_v3(const float tan_l[3], const float tan_r[3]);
-/********************************** Geodesics *********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Geodesics
+ * \{ */
+/**
+ * Utility for computing approximate geodesic distances on triangle meshes.
+ *
+ * Given triangle with vertex coordinates v0, v1, v2, and known geodesic distances
+ * dist1 and dist2 at v1 and v2, estimate a geodesic distance at vertex v0.
+ *
+ * From "Dart Throwing on Surfaces", EGSR 2009. Section 7, Geodesic Dart Throwing.
+ */
float geodesic_distance_propagate_across_triangle(
const float v0[3], const float v1[3], const float v2[3], const float dist1, const float dist2);
-/**************************** Inline Definitions ******************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Inline Definitions
+ * \{ */
#if BLI_MATH_DO_INLINE
# include "intern/math_geom_inline.c"
@@ -845,6 +1420,8 @@ float geodesic_distance_propagate_across_triangle(
# pragma GCC diagnostic pop
#endif
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_math_interp.h b/source/blender/blenlib/BLI_math_interp.h
index cc025b469e3..7179de12066 100644
--- a/source/blender/blenlib/BLI_math_interp.h
+++ b/source/blender/blenlib/BLI_math_interp.h
@@ -77,7 +77,8 @@ typedef void (*ewa_filter_read_pixel_cb)(void *userdata, int x, int y, float res
void BLI_ewa_imp2radangle(
float A, float B, float C, float F, float *a, float *b, float *th, float *ecc);
-/* TODO(sergey): Consider making this function inlined, so the pixel read callback
+/**
+ * TODO(sergey): Consider making this function inlined, so the pixel read callback
* could also be inlined in order to avoid per-pixel function calls.
*/
void BLI_ewa_filter(const int width,
diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h
index 241acebffa3..3d8fe6f564a 100644
--- a/source/blender/blenlib/BLI_math_matrix.h
+++ b/source/blender/blenlib/BLI_math_matrix.h
@@ -32,7 +32,9 @@
extern "C" {
#endif
-/********************************* Init **************************************/
+/* -------------------------------------------------------------------- */
+/** \name Init
+ * \{ */
void zero_m2(float m[2][2]);
void zero_m3(float m[3][3]);
@@ -66,7 +68,11 @@ void swap_m4m4(float m1[4][4], float m2[4][4]);
/* Build index shuffle matrix */
void shuffle_m4(float R[4][4], const int index[4]);
-/******************************** Arithmetic *********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Arithmetic
+ * \{ */
void add_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3]);
void add_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4]);
@@ -81,14 +87,21 @@ void mul_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3]);
void mul_m4_m3m4(float R[4][4], const float A[3][3], const float B[4][4]);
void mul_m4_m4m3(float R[4][4], const float A[4][4], const float B[3][3]);
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4]);
+/**
+ * `R = A * B`, ignore the elements on the 4th row/column of A.
+ */
void mul_m3_m3m4(float R[3][3], const float A[3][3], const float B[4][4]);
+/**
+ * `R = A * B`, ignore the elements on the 4th row/column of B.
+ */
void mul_m3_m4m3(float R[3][3], const float A[4][4], const float B[3][3]);
void mul_m3_m4m4(float R[3][3], const float A[4][4], const float B[4][4]);
-/* special matrix multiplies
- * uniq: R <-- AB, R is neither A nor B
- * pre: R <-- AR
- * post: R <-- RB
+/**
+ * Special matrix multiplies
+ * - uniq: `R <-- AB`, R is neither A nor B
+ * - pre: `R <-- AR`
+ * - post: `R <-- RB`.
*/
void mul_m3_m3m3_uniq(float R[3][3], const float A[3][3], const float B[3][3]);
void mul_m3_m3_pre(float R[3][3], const float A[3][3]);
@@ -192,6 +205,7 @@ void mul_v4_m4v3_db(double r[4], const double mat[4][4], const double vec[3]);
void mul_v2_m4v3(float r[2], const float M[4][4], const float v[3]);
void mul_v2_m2v2(float r[2], const float M[2][2], const float v[2]);
void mul_m2_v2(const float M[2][2], float v[2]);
+/** Same as #mul_m4_v3() but doesn't apply translation component. */
void mul_mat3_m4_v3(const float M[4][4], float r[3]);
void mul_v3_mat3_m4v3(float r[3], const float M[4][4], const float v[3]);
void mul_v3_mat3_m4v3_db(double r[3], const double M[4][4], const double v[3]);
@@ -211,7 +225,18 @@ void mul_transposed_m3_v3(const float M[3][3], float r[3]);
void mul_transposed_mat3_m4_v3(const float M[4][4], float r[3]);
void mul_m3_v3_double(const float M[3][3], double r[3]);
+/**
+ * Combines transformations, handling scale separately in a manner equivalent
+ * to the Aligned Inherit Scale mode, in order to avoid creating shear.
+ * If A scale is uniform, the result is equivalent to ordinary multiplication.
+ *
+ * NOTE: this effectively takes output location from simple multiplication,
+ * and uses mul_m4_m4m4_split_channels for rotation and scale.
+ */
void mul_m4_m4m4_aligned_scale(float R[4][4], const float A[4][4], const float B[4][4]);
+/**
+ * Separately combines location, rotation and scale of the input matrices.
+ */
void mul_m4_m4m4_split_channels(float R[4][4], const float A[4][4], const float B[4][4]);
void mul_m3_fl(float R[3][3], float f);
@@ -229,6 +254,16 @@ bool invert_m3(float R[3][3]);
bool invert_m3_m3(float R[3][3], const float A[3][3]);
bool invert_m4(float R[4][4]);
bool invert_m4_m4(float R[4][4], const float A[4][4]);
+/**
+ * Computes the inverse of mat and puts it in inverse.
+ * Uses Gaussian Elimination with partial (maximal column) pivoting.
+ * \return true on success (i.e. can always find a pivot) and false on failure.
+ * Mark Segal - 1992.
+ *
+ * \note this has worse performance than #EIG_invert_m4_m4 (Eigen), but e.g.
+ * for non-invertible scale matrices, finding a partial solution can
+ * be useful to have a valid local transform center, see T57767.
+ */
bool invert_m4_m4_fallback(float R[4][4], const float A[4][4]);
/* double arithmetic (mixed float/double) */
@@ -239,10 +274,15 @@ void mul_v4d_m4v4d(double r[4], const float M[4][4], const double v[4]);
void mul_v3_m3v3_db(double r[3], const double M[3][3], const double a[3]);
void mul_m3_v3_db(const double M[3][3], double r[3]);
-/****************************** Linear Algebra *******************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Linear Algebra
+ * \{ */
void transpose_m3(float R[3][3]);
void transpose_m3_m3(float R[3][3], const float M[3][3]);
+/* seems obscure but in-fact a common operation */
void transpose_m3_m4(float R[3][3], const float M[4][4]);
void transpose_m4(float R[4][4]);
void transpose_m4_m4(float R[4][4], const float M[4][4]);
@@ -262,10 +302,36 @@ void normalize_m4(float R[4][4]) ATTR_NONNULL();
void normalize_m4_m4_ex(float R[4][4], const float M[4][4], float r_scale[3]) ATTR_NONNULL();
void normalize_m4_m4(float R[4][4], const float M[4][4]) ATTR_NONNULL();
+/**
+ * Make an orthonormal matrix around the selected axis of the given matrix.
+ *
+ * \param axis: Axis to build the orthonormal basis around.
+ */
void orthogonalize_m3(float R[3][3], int axis);
+/**
+ * Make an orthonormal matrix around the selected axis of the given matrix.
+ *
+ * \param axis: Axis to build the orthonormal basis around.
+ */
void orthogonalize_m4(float R[4][4], int axis);
+/**
+ * Make an orthonormal matrix around the selected axis of the given matrix,
+ * in a way that is symmetric and stable to variations in the input, and
+ * preserving the value of the determinant, i.e. the overall volume change.
+ *
+ * \param axis: Axis to build the orthonormal basis around.
+ * \param normalize: Normalize the matrix instead of preserving volume.
+ */
void orthogonalize_m3_stable(float R[3][3], int axis, bool normalize);
+/**
+ * Make an orthonormal matrix around the selected axis of the given matrix,
+ * in a way that is symmetric and stable to variations in the input, and
+ * preserving the value of the determinant, i.e. the overall volume change.
+ *
+ * \param axis: Axis to build the orthonormal basis around.
+ * \param normalize: Normalize the matrix instead of preserving volume.
+ */
void orthogonalize_m4_stable(float R[4][4], int axis, bool normalize);
bool orthogonalize_m3_zero_axes(float R[3][3], const float unit_length);
@@ -281,8 +347,8 @@ bool is_uniform_scaled_m4(const float m[4][4]);
/* NOTE: 'adjoint' here means the adjugate (adjunct, "classical adjoint") matrix!
* Nowadays 'adjoint' usually refers to the conjugate transpose,
- * which for real-valued matrices is simply the transpose.
- */
+ * which for real-valued matrices is simply the transpose. */
+
void adjoint_m2_m2(float R[2][2], const float M[2][2]);
void adjoint_m3_m3(float R[3][3], const float M[3][3]);
void adjoint_m4_m4(float R[4][4], const float M[4][4]);
@@ -297,6 +363,13 @@ float determinant_m4(const float m[4][4]);
#define PSEUDOINVERSE_EPSILON 1e-8f
+/**
+ * Compute the Single Value Decomposition of an arbitrary matrix A
+ * That is compute the 3 matrices U,W,V with U column orthogonal (m,n)
+ * ,W a diagonal matrix and V an orthogonal square matrix `s.t.A = U.W.Vt`.
+ * From this decomposition it is trivial to compute the (pseudo-inverse)
+ * of `A` as `Ainv = V.Winv.transpose(U)`.
+ */
void svd_m4(float U[4][4], float s[4], float V[4][4], float A[4][4]);
void pseudoinverse_m4_m4(float Ainv[4][4], const float A[4][4], float epsilon);
void pseudoinverse_m3_m3(float Ainv[3][3], const float A[3][3], float epsilon);
@@ -306,18 +379,39 @@ bool has_zero_axis_m4(const float matrix[4][4]);
void invert_m4_m4_safe(float Ainv[4][4], const float A[4][4]);
void invert_m3_m3_safe_ortho(float Ainv[3][3], const float A[3][3]);
+/**
+ * A safe version of invert that uses valid axes, calculating the zero'd axis
+ * based on the non-zero ones.
+ *
+ * This works well for transformation matrices, when a single axis is zerod.
+ */
void invert_m4_m4_safe_ortho(float Ainv[4][4], const float A[4][4]);
-/****************************** Transformations ******************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Transformations
+ * \{ */
void scale_m3_fl(float R[3][3], float scale);
void scale_m4_fl(float R[4][4], float scale);
+/**
+ * This computes the overall volume scale factor of a transformation matrix.
+ * For an orthogonal matrix, it is the product of all three scale values.
+ * Returns a negative value if the transform is flipped by negative scale.
+ */
float mat3_to_volume_scale(const float M[3][3]);
float mat4_to_volume_scale(const float M[4][4]);
+/**
+ * This gets the average scale of a matrix, only use when your scaling
+ * data that has no idea of scale axis, examples are bone-envelope-radius
+ * and curve radius.
+ */
float mat3_to_scale(const float M[3][3]);
float mat4_to_scale(const float M[4][4]);
+/** Return 2D scale (in XY plane) of given mat4. */
float mat4_to_xy_scale(const float M[4][4]);
void size_to_mat3(float R[3][3], const float size[3]);
@@ -326,11 +420,31 @@ void size_to_mat4(float R[4][4], const float size[3]);
void mat3_to_size(float size[3], const float M[3][3]);
void mat4_to_size(float size[3], const float M[4][4]);
+/**
+ * Extract scale factors from the matrix, with correction to ensure
+ * exact volume in case of a sheared matrix.
+ */
void mat4_to_size_fix_shear(float size[3], const float M[4][4]);
void translate_m4(float mat[4][4], float tx, float ty, float tz);
+/**
+ * Rotate a matrix in-place.
+ *
+ * \note To create a new rotation matrix see:
+ * #axis_angle_to_mat4_single, #axis_angle_to_mat3_single, #angle_to_mat2
+ * (axis & angle args are compatible).
+ */
void rotate_m4(float mat[4][4], const char axis, const float angle);
+/** Scale a matrix in-place. */
void rescale_m4(float mat[4][4], const float scale[3]);
+/**
+ * Scale or rotate around a pivot point,
+ * a convenience function to avoid having to do inline.
+ *
+ * Since its common to make a scale/rotation matrix that pivots around an arbitrary point.
+ *
+ * Typical use case is to make 3x3 matrix, copy to 4x4, then pass to this function.
+ */
void transform_pivot_set_m4(float mat[4][4], const float pivot[3]);
void mat4_to_rot(float rot[3][3], const float wmat[4][4]);
@@ -341,16 +455,34 @@ void mat4_decompose(float loc[3], float quat[4], float size[3], const float wmat
void mat3_polar_decompose(const float mat3[3][3], float r_U[3][3], float r_P[3][3]);
+/**
+ * Make a 4x4 matrix out of 3 transform components.
+ * Matrices are made in the order: `scale * rot * loc`
+ */
void loc_rot_size_to_mat4(float R[4][4],
const float loc[3],
const float rot[3][3],
const float size[3]);
+/**
+ * Make a 4x4 matrix out of 3 transform components.
+ * Matrices are made in the order: `scale * rot * loc`
+ *
+ * TODO: need to have a version that allows for rotation order.
+ */
void loc_eul_size_to_mat4(float R[4][4],
const float loc[3],
const float eul[3],
const float size[3]);
+/**
+ * Make a 4x4 matrix out of 3 transform components.
+ * Matrices are made in the order: `scale * rot * loc`
+ */
void loc_eulO_size_to_mat4(
float R[4][4], const float loc[3], const float eul[3], const float size[3], const short order);
+/**
+ * Make a 4x4 matrix out of 3 transform components.
+ * Matrices are made in the order: `scale * rot * loc`
+ */
void loc_quat_size_to_mat4(float R[4][4],
const float loc[3],
const float quat[4],
@@ -370,7 +502,32 @@ void blend_m4_m4m4(float out[4][4],
const float src[4][4],
const float srcweight);
+/**
+ * A polar-decomposition-based interpolation between matrix A and matrix B.
+ *
+ * \note This code is about five times slower as the 'naive' interpolation done by #blend_m3_m3m3
+ * (it typically remains below 2 usec on an average i74700,
+ * while #blend_m3_m3m3 remains below 0.4 usec).
+ * However, it gives expected results even with non-uniformly scaled matrices,
+ * see T46418 for an example.
+ *
+ * Based on "Matrix Animation and Polar Decomposition", by Ken Shoemake & Tom Duff
+ *
+ * \param R: Resulting interpolated matrix.
+ * \param A: Input matrix which is totally effective with `t = 0.0`.
+ * \param B: Input matrix which is totally effective with `t = 1.0`.
+ * \param t: Interpolation factor.
+ */
void interp_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3], const float t);
+/**
+ * Complete transform matrix interpolation,
+ * based on polar-decomposition-based interpolation from #interp_m3_m3m3.
+ *
+ * \param R: Resulting interpolated matrix.
+ * \param A: Input matrix which is totally effective with `t = 0.0`.
+ * \param B: Input matrix which is totally effective with `t = 1.0`.
+ * \param t: Interpolation factor.
+ */
void interp_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4], const float t);
bool is_negative_m3(const float mat[3][3]);
@@ -382,16 +539,57 @@ bool is_zero_m4(const float mat[4][4]);
bool equals_m3m3(const float mat1[3][3], const float mat2[3][3]);
bool equals_m4m4(const float mat1[4][4], const float mat2[4][4]);
-/* SpaceTransform helper */
+/**
+ * #SpaceTransform struct encapsulates all needed data to convert between two coordinate spaces
+ * (where conversion can be represented by a matrix multiplication).
+ *
+ * A #SpaceTransform is initialized using:
+ * - #BLI_SPACE_TRANSFORM_SETUP(&data, ob1, ob2)
+ *
+ * After that the following calls can be used:
+ * - Converts a coordinate in ob1 space to the corresponding ob2 space:
+ * #BLI_space_transform_apply(&data, co);
+ * - Converts a coordinate in ob2 space to the corresponding ob1 space:
+ * #BLI_space_transform_invert(&data, co);
+ *
+ * Same concept as #BLI_space_transform_apply and #BLI_space_transform_invert,
+ * but no is normalized after conversion (and not translated at all!):
+ * - #BLI_space_transform_apply_normal(&data, no);
+ * - #BLI_space_transform_invert_normal(&data, no);
+ */
typedef struct SpaceTransform {
float local2target[4][4];
float target2local[4][4];
} SpaceTransform;
+/**
+ * Global-invariant transform.
+ *
+ * This defines a matrix transforming a point in local space to a point in target space
+ * such that its global coordinates remain unchanged.
+ *
+ * In other words, if we have a global point P with local coordinates (x, y, z)
+ * and global coordinates (X, Y, Z),
+ * this defines a transform matrix TM such that (x', y', z') = TM * (x, y, z)
+ * where (x', y', z') are the coordinates of P' in target space
+ * such that it keeps (X, Y, Z) coordinates in global space.
+ */
void BLI_space_transform_from_matrices(struct SpaceTransform *data,
const float local[4][4],
const float target[4][4]);
+/**
+ * Local-invariant transform.
+ *
+ * This defines a matrix transforming a point in global space
+ * such that its local coordinates (from local space to target space) remain unchanged.
+ *
+ * In other words, if we have a local point p with local coordinates (x, y, z)
+ * and global coordinates (X, Y, Z),
+ * this defines a transform matrix TM such that (X', Y', Z') = TM * (X, Y, Z)
+ * where (X', Y', Z') are the coordinates of p' in global space
+ * such that it keeps (x, y, z) coordinates in target space.
+ */
void BLI_space_transform_global_from_matrices(struct SpaceTransform *data,
const float local[4][4],
const float target[4][4]);
@@ -403,7 +601,11 @@ void BLI_space_transform_invert_normal(const struct SpaceTransform *data, float
#define BLI_SPACE_TRANSFORM_SETUP(data, local, target) \
BLI_space_transform_from_matrices((data), (local)->obmat, (target)->obmat)
-/*********************************** Other ***********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Other
+ * \{ */
void print_m3(const char *str, const float M[3][3]);
void print_m4(const char *str, const float M[4][4]);
@@ -411,6 +613,8 @@ void print_m4(const char *str, const float M[4][4]);
#define print_m3_id(M) print_m3(STRINGIFY(M), M)
#define print_m4_id(M) print_m4(STRINGIFY(M), M)
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_math_rotation.h b/source/blender/blenlib/BLI_math_rotation.h
index 461b5a60c9d..5e72d502262 100644
--- a/source/blender/blenlib/BLI_math_rotation.h
+++ b/source/blender/blenlib/BLI_math_rotation.h
@@ -32,31 +32,72 @@
extern "C" {
#endif
+/* -------------------------------------------------------------------- */
+/** \name Conversion Defines
+ * \{ */
+
#define RAD2DEG(_rad) ((_rad) * (180.0 / M_PI))
#define DEG2RAD(_deg) ((_deg) * (M_PI / 180.0))
#define RAD2DEGF(_rad) ((_rad) * (float)(180.0 / M_PI))
#define DEG2RADF(_deg) ((_deg) * (float)(M_PI / 180.0))
-/******************************** Quaternions ********************************/
-/* stored in (w, x, y, z) order */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternions
+ * Stored in (w, x, y, z) order.
+ * \{ */
+
+/* Initialize */
+
+/* Convenience, avoids setting Y axis everywhere. */
-/* init */
void unit_axis_angle(float axis[3], float *angle);
void unit_qt(float q[4]);
void copy_qt_qt(float q[4], const float a[4]);
/* arithmetic */
void mul_qt_qtqt(float q[4], const float a[4], const float b[4]);
+/**
+ * \note
+ * Assumes a unit quaternion?
+ *
+ * in fact not, but you may want to use a unit quaternion read on...
+ *
+ * Shortcut for 'q v q*' when \a v is actually a quaternion.
+ * This removes the need for converting a vector to a quaternion,
+ * calculating q's conjugate and converting back to a vector.
+ * It also happens to be faster (17+,24* vs * 24+,32*).
+ * If \a q is not a unit quaternion, then \a v will be both rotated by
+ * the same amount as if q was a unit quaternion, and scaled by the square of
+ * the length of q.
+ *
+ * For people used to python mathutils, its like:
+ * def mul_qt_v3(q, v): (q * Quaternion((0.0, v[0], v[1], v[2])) * q.conjugated())[1:]
+ *
+ * \note Multiplying by 3x3 matrix is ~25% faster.
+ */
void mul_qt_v3(const float q[4], float r[3]);
+/**
+ * Simple multiply.
+ */
void mul_qt_fl(float q[4], const float f);
+/**
+ * Raise a unit quaternion to the specified power.
+ */
void pow_qt_fl_normalized(float q[4], const float f);
void sub_qt_qtqt(float q[4], const float a[4], const float b[4]);
void invert_qt(float q[4]);
void invert_qt_qt(float q1[4], const float q2[4]);
+/**
+ * This is just conjugate_qt for cases we know \a q is unit-length.
+ * we could use #conjugate_qt directly, but use this function to show intent,
+ * and assert if its ever becomes non-unit-length.
+ */
void invert_qt_normalized(float q[4]);
void invert_qt_qt_normalized(float q1[4], const float q2[4]);
void conjugate_qt(float q[4]);
@@ -69,7 +110,15 @@ float normalize_qt_qt(float r[4], const float q[4]);
bool is_zero_qt(const float q[4]);
/* interpolation */
-void interp_dot_slerp(const float t, const float cosom, float w[2]);
+/**
+ * Generic function for implementing slerp
+ * (quaternions and spherical vector coords).
+ *
+ * \param t: factor in [0..1]
+ * \param cosom: dot product from normalized vectors/quats.
+ * \param r_w: calculated weights.
+ */
+void interp_dot_slerp(const float t, const float cosom, float r_w[2]);
void interp_qt_qtqt(float q[4], const float a[4], const float b[4], const float t);
void add_qt_qtqt(float q[4], const float a[4], const float b[4], const float t);
@@ -77,24 +126,51 @@ void add_qt_qtqt(float q[4], const float a[4], const float b[4], const float t);
void quat_to_mat3(float mat[3][3], const float q[4]);
void quat_to_mat4(float mat[4][4], const float q[4]);
+/**
+ * Apply the rotation of \a a to \a q keeping the values compatible with \a old.
+ * Avoid axis flipping for animated f-curves for eg.
+ */
void quat_to_compatible_quat(float q[4], const float a[4], const float old[4]);
void mat3_normalized_to_quat(float q[4], const float mat[3][3]);
void mat4_normalized_to_quat(float q[4], const float mat[4][4]);
void mat3_to_quat(float q[4], const float mat[3][3]);
void mat4_to_quat(float q[4], const float mat[4][4]);
+/**
+ * Same as tri_to_quat() but takes pre-computed normal from the triangle
+ * used for ngons when we know their normal.
+ */
void tri_to_quat_ex(float quat[4],
const float v1[3],
const float v2[3],
const float v3[3],
const float no_orig[3]);
+/**
+ * \return the length of the normal, use to test for degenerate triangles.
+ */
float tri_to_quat(float q[4], const float a[3], const float b[3], const float c[3]);
void vec_to_quat(float q[4], const float vec[3], short axis, const short upflag);
-/* NOTE: v1 and v2 must be normalized. */
+/**
+ * Calculate a rotation matrix from 2 normalized vectors.
+ * \note `v1` and `v2` must be normalized.
+ */
void rotation_between_vecs_to_mat3(float m[3][3], const float v1[3], const float v2[3]);
+/**
+ * \note Expects vectors to be normalized.
+ */
void rotation_between_vecs_to_quat(float q[4], const float v1[3], const float v2[3]);
void rotation_between_quats_to_quat(float q[4], const float q1[4], const float q2[4]);
+/**
+ * Decompose a quaternion into a swing rotation (quaternion with the selected
+ * axis component locked at zero), followed by a twist rotation around the axis.
+ *
+ * \param q: input quaternion.
+ * \param axis: twist axis in [0,1,2]
+ * \param r_swing: if not NULL, receives the swing quaternion.
+ * \param r_twist: if not NULL, receives the twist quaternion.
+ * \returns twist angle.
+ */
float quat_split_swing_and_twist(const float q[4], int axis, float r_swing[4], float r_twist[4]);
float angle_normalized_qt(const float q[4]);
@@ -107,7 +183,9 @@ float angle_signed_normalized_qtqt(const float q1[4], const float q2[4]);
float angle_signed_qt(const float q[4]);
float angle_signed_qtqt(const float q1[4], const float q2[4]);
-/* TODO: don't what this is, but it's not the same as mat3_to_quat */
+/**
+ * TODO: don't what this is, but it's not the same as #mat3_to_quat.
+ */
void mat3_to_quat_is_ok(float q[4], const float mat[3][3]);
/* other */
@@ -115,61 +193,120 @@ void print_qt(const char *str, const float q[4]);
#define print_qt_id(q) print_qt(STRINGIFY(q), q)
-/******************************** Axis Angle *********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Axis Angle
+ * \{ */
/* conversion */
void axis_angle_normalized_to_quat(float r[4], const float axis[3], const float angle);
void axis_angle_to_quat(float r[4], const float axis[3], const float angle);
+/**
+ * Axis angle to 3x3 matrix - safer version (normalization of axis performed).
+ */
void axis_angle_to_mat3(float R[3][3], const float axis[3], const float angle);
+/**
+ * axis angle to 3x3 matrix
+ *
+ * This takes the angle with sin/cos applied so we can avoid calculating it in some cases.
+ *
+ * \param axis: rotation axis (must be normalized).
+ * \param angle_sin: sin(angle)
+ * \param angle_cos: cos(angle)
+ */
void axis_angle_normalized_to_mat3_ex(float mat[3][3],
const float axis[3],
const float angle_sin,
const float angle_cos);
void axis_angle_normalized_to_mat3(float R[3][3], const float axis[3], const float angle);
+/**
+ * Axis angle to 4x4 matrix - safer version (normalization of axis performed).
+ */
void axis_angle_to_mat4(float R[4][4], const float axis[3], const float angle);
+/**
+ * 3x3 matrix to axis angle.
+ */
void mat3_normalized_to_axis_angle(float axis[3], float *angle, const float M[3][3]);
+/**
+ * 4x4 matrix to axis angle.
+ */
void mat4_normalized_to_axis_angle(float axis[3], float *angle, const float M[4][4]);
void mat3_to_axis_angle(float axis[3], float *angle, const float M[3][3]);
+/**
+ * 4x4 matrix to axis angle.
+ */
void mat4_to_axis_angle(float axis[3], float *angle, const float M[4][4]);
+/**
+ * Quaternions to Axis Angle.
+ */
void quat_to_axis_angle(float axis[3], float *angle, const float q[4]);
void angle_to_mat2(float R[2][2], const float angle);
+/**
+ * Create a 3x3 rotation matrix from a single axis.
+ */
void axis_angle_to_mat3_single(float R[3][3], const char axis, const float angle);
+/**
+ * Create a 4x4 rotation matrix from a single axis.
+ */
void axis_angle_to_mat4_single(float R[4][4], const char axis, const float angle);
void axis_angle_to_quat_single(float q[4], const char axis, const float angle);
-/****************************** Exponential Map ******************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Exponential Map
+ * \{ */
+
void quat_to_expmap(float expmap[3], const float q[4]);
void quat_normalized_to_expmap(float expmap[3], const float q[4]);
void expmap_to_quat(float r[4], const float expmap[3]);
-/******************************** XYZ Eulers *********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name XYZ Eulers
+ * \{ */
+/* XYZ order. */
void eul_to_quat(float quat[4], const float eul[3]);
+/* XYZ order */
void eul_to_mat3(float mat[3][3], const float eul[3]);
+/* XYZ order */
void eul_to_mat4(float mat[4][4], const float eul[3]);
+/* XYZ order */
void mat3_normalized_to_eul(float eul[3], const float mat[3][3]);
+/* XYZ order */
void mat4_normalized_to_eul(float eul[3], const float mat[4][4]);
void mat3_to_eul(float eul[3], const float mat[3][3]);
void mat4_to_eul(float eul[3], const float mat[4][4]);
+/* XYZ order */
void quat_to_eul(float eul[3], const float quat[4]);
+/* XYZ order */
void mat3_normalized_to_compatible_eul(float eul[3], const float old[3], float mat[3][3]);
void mat3_to_compatible_eul(float eul[3], const float old[3], float mat[3][3]);
void quat_to_compatible_eul(float eul[3], const float oldrot[3], const float quat[4]);
+/* order independent! */
void compatible_eul(float eul[3], const float old[3]);
+/* XYZ order */
void rotate_eul(float eul[3], const char axis, const float angle);
void add_eul_euleul(float r_eul[3], float a[3], float b[3], const short order);
void sub_eul_euleul(float r_eul[3], float a[3], float b[3], const short order);
-/************************** Arbitrary Order Eulers ***************************/
+/** \} */
-/* warning: must match the eRotationModes in DNA_action_types.h
+/* -------------------------------------------------------------------- */
+/** \name Arbitrary Order Eulers
+ * \{ */
+
+/* WARNING: must match the #eRotationModes in `DNA_action_types.h`
* order matters - types are saved to file. */
typedef enum eEulerRotationOrders {
@@ -183,19 +320,48 @@ typedef enum eEulerRotationOrders {
/* There are 6 more entries with duplicate entries included. */
} eEulerRotationOrders;
+/**
+ * Construct quaternion from Euler angles (in radians).
+ */
void eulO_to_quat(float quat[4], const float eul[3], const short order);
+/**
+ * Construct 3x3 matrix from Euler angles (in radians).
+ */
void eulO_to_mat3(float mat[3][3], const float eul[3], const short order);
+/**
+ * Construct 4x4 matrix from Euler angles (in radians).
+ */
void eulO_to_mat4(float mat[4][4], const float eul[3], const short order);
+/**
+ * Euler Rotation to Axis Angle.
+ */
void eulO_to_axis_angle(float axis[3], float *angle, const float eul[3], const short order);
+/**
+ * The matrix is written to as 3 axis vectors.
+ */
void eulO_to_gimbal_axis(float gmat[3][3], const float eul[3], const short order);
+/**
+ * Convert 3x3 matrix to Euler angles (in radians).
+ */
void mat3_normalized_to_eulO(float eul[3], const short order, const float mat[3][3]);
+/**
+ * Convert 4x4 matrix to Euler angles (in radians).
+ */
void mat4_normalized_to_eulO(float eul[3], const short order, const float mat[4][4]);
void mat3_to_eulO(float eul[3], const short order, const float mat[3][3]);
void mat4_to_eulO(float eul[3], const short order, const float mat[4][4]);
+/**
+ * Convert quaternion to Euler angles (in radians).
+ */
void quat_to_eulO(float eul[3], const short order, const float quat[4]);
+/**
+ * Axis Angle to Euler Rotation.
+ */
void axis_angle_to_eulO(float eul[3], const short order, const float axis[3], const float angle);
+/* Uses 2 methods to retrieve eulers, and picks the closest. */
+
void mat3_normalized_to_compatible_eulO(float eul[3],
const float old[3],
const short order,
@@ -219,7 +385,11 @@ void quat_to_compatible_eulO(float eul[3],
void rotate_eulO(float eul[3], const short order, char axis, float angle);
-/******************************* Dual Quaternions ****************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Dual Quaternions
+ * \{ */
void copy_dq_dq(DualQuat *r, const DualQuat *dq);
void normalize_dq(DualQuat *dq, float totw);
@@ -229,21 +399,39 @@ void mul_v3m3_dq(float r[3], float R[3][3], DualQuat *dq);
void mat4_to_dquat(DualQuat *dq, const float basemat[4][4], const float mat[4][4]);
void dquat_to_mat4(float R[4][4], const DualQuat *dq);
+/**
+ * Axis matches #eTrackToAxis_Modes.
+ */
void quat_apply_track(float quat[4], short axis, short upflag);
void vec_apply_track(float vec[3], short axis);
+/**
+ * Lens/angle conversion (radians).
+ */
float focallength_to_fov(float focal_length, float sensor);
float fov_to_focallength(float fov, float sensor);
float angle_wrap_rad(float angle);
float angle_wrap_deg(float angle);
+/**
+ * Returns an angle compatible with angle_compat.
+ */
float angle_compat_rad(float angle, float angle_compat);
+/**
+ * Each argument us an axis in ['X', 'Y', 'Z', '-X', '-Y', '-Z']
+ * where the first 2 are a source and the second 2 are the target.
+ */
bool mat3_from_axis_conversion(
int src_forward, int src_up, int dst_forward, int dst_up, float r_mat[3][3]);
+/**
+ * Use when the second axis can be guessed.
+ */
bool mat3_from_axis_conversion_single(int src_axis, int dst_axis, float r_mat[3][3]);
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_math_solvers.h b/source/blender/blenlib/BLI_math_solvers.h
index 39a79efc7e2..32d4577899c 100644
--- a/source/blender/blenlib/BLI_math_solvers.h
+++ b/source/blender/blenlib/BLI_math_solvers.h
@@ -35,22 +35,61 @@ extern "C" {
# pragma GCC diagnostic ignored "-Wredundant-decls"
#endif
-/********************************** Eigen Solvers *********************************/
+/* -------------------------------------------------------------------- */
+/** \name Eigen Solvers
+ * \{ */
+/**
+ * \brief Compute the eigen values and/or vectors of given 3D symmetric (aka adjoint) matrix.
+ *
+ * \param m3: the 3D symmetric matrix.
+ * \return r_eigen_values the computed eigen values (NULL if not needed).
+ * \return r_eigen_vectors the computed eigen vectors (NULL if not needed).
+ */
bool BLI_eigen_solve_selfadjoint_m3(const float m3[3][3],
float r_eigen_values[3],
float r_eigen_vectors[3][3]);
+/**
+ * \brief Compute the SVD (Singular Values Decomposition) of given 3D matrix (m3 = USV*).
+ *
+ * \param m3: the matrix to decompose.
+ * \return r_U the computed left singular vector of \a m3 (NULL if not needed).
+ * \return r_S the computed singular values of \a m3 (NULL if not needed).
+ * \return r_V the computed right singular vector of \a m3 (NULL if not needed).
+ */
void BLI_svd_m3(const float m3[3][3], float r_U[3][3], float r_S[3], float r_V[3][3]);
-/***************************** Simple Solvers ************************************/
+/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Simple Solvers
+ * \{ */
+
+/**
+ * \brief Solve a tridiagonal system of equations:
+ *
+ * a[i] * r_x[i-1] + b[i] * r_x[i] + c[i] * r_x[i+1] = d[i]
+ *
+ * Ignores a[0] and c[count-1]. Uses the Thomas algorithm, e.g. see wiki.
+ *
+ * \param r_x: output vector, may be shared with any of the input ones
+ * \return true if success
+ */
bool BLI_tridiagonal_solve(
const float *a, const float *b, const float *c, const float *d, float *r_x, const int count);
+/**
+ * \brief Solve a possibly cyclic tridiagonal system using the Sherman-Morrison formula.
+ *
+ * \param r_x: output vector, may be shared with any of the input ones
+ * \return true if success
+ */
bool BLI_tridiagonal_solve_cyclic(
const float *a, const float *b, const float *c, const float *d, float *r_x, const int count);
-/* Generic 3 variable Newton's method solver. */
+/**
+ * Generic 3 variable Newton's method solver.
+ */
typedef void (*Newton3D_DeltaFunc)(void *userdata, const float x[3], float r_delta[3]);
typedef void (*Newton3D_JacobianFunc)(void *userdata, const float x[3], float r_jacobian[3][3]);
typedef bool (*Newton3D_CorrectionFunc)(void *userdata,
@@ -58,6 +97,21 @@ typedef bool (*Newton3D_CorrectionFunc)(void *userdata,
float step[3],
float x_next[3]);
+/**
+ * \brief Solve a generic f(x) = 0 equation using Newton's method.
+ *
+ * \param func_delta: Callback computing the value of f(x).
+ * \param func_jacobian: Callback computing the Jacobian matrix of the function at x.
+ * \param func_correction: Callback for forcing the search into an arbitrary custom domain.
+ * May be NULL.
+ * \param userdata: Data for the callbacks.
+ * \param epsilon: Desired precision.
+ * \param max_iterations: Limit on the iterations.
+ * \param trace: Enables logging to console.
+ * \param x_init: Initial solution vector.
+ * \param result: Final result.
+ * \return true if success
+ */
bool BLI_newton3d_solve(Newton3D_DeltaFunc func_delta,
Newton3D_JacobianFunc func_jacobian,
Newton3D_CorrectionFunc func_correction,
@@ -72,6 +126,8 @@ bool BLI_newton3d_solve(Newton3D_DeltaFunc func_delta,
# pragma GCC diagnostic pop
#endif
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_math_statistics.h b/source/blender/blenlib/BLI_math_statistics.h
index 6e818f5c8df..e4524b49f3f 100644
--- a/source/blender/blenlib/BLI_math_statistics.h
+++ b/source/blender/blenlib/BLI_math_statistics.h
@@ -35,14 +35,36 @@ extern "C" {
# pragma GCC diagnostic ignored "-Wredundant-decls"
#endif
-/********************************** Covariance Matrices *********************************/
+/* -------------------------------------------------------------------- */
+/** \name Covariance Matrices
+ * \{ */
+/**
+ * \brief Compute the covariance matrix of given set of nD coordinates.
+ *
+ * \param n: the dimension of the vectors (and hence, of the covariance matrix to compute).
+ * \param cos_vn: the nD points to compute covariance from.
+ * \param nbr_cos_vn: the number of nD coordinates in cos_vn.
+ * \param center: the center (or mean point) of cos_vn. If NULL,
+ * it is assumed cos_vn is already centered.
+ * \param use_sample_correction: whether to apply sample correction
+ * (i.e. get 'sample variance' instead of 'population variance').
+ * \return r_covmat the computed covariance matrix.
+ */
void BLI_covariance_m_vn_ex(const int n,
const float *cos_vn,
const int nbr_cos_vn,
const float *center,
const bool use_sample_correction,
float *r_covmat);
+/**
+ * \brief Compute the covariance matrix of given set of 3D coordinates.
+ *
+ * \param cos_v3: the 3D points to compute covariance from.
+ * \param nbr_cos_v3: the number of 3D coordinates in cos_v3.
+ * \return r_covmat the computed covariance matrix.
+ * \return r_center the computed center (mean) of 3D points (may be NULL).
+ */
void BLI_covariance_m3_v3n(const float (*cos_v3)[3],
const int nbr_cos_v3,
const bool use_sample_correction,
@@ -53,6 +75,8 @@ void BLI_covariance_m3_v3n(const float (*cos_v3)[3],
# pragma GCC diagnostic pop
#endif
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_math_time.h b/source/blender/blenlib/BLI_math_time.h
index 671ec6f857f..52857773797 100644
--- a/source/blender/blenlib/BLI_math_time.h
+++ b/source/blender/blenlib/BLI_math_time.h
@@ -27,7 +27,10 @@
extern "C" {
#endif
-/************************ Time constants definitions***************************/
+/* -------------------------------------------------------------------- */
+/** \name Time Constants Definitions
+ * \{ */
+
#define SECONDS_IN_MILLISECONDS 0.001
#define SECONDS_IN_MINUTE 60.0
#define MINUTES_IN_HOUR 60.0
@@ -37,6 +40,20 @@ extern "C" {
#define SECONDS_IN_DAY (MINUTES_IN_DAY * SECONDS_IN_MINUTE)
#define SECONDS_IN_HOUR (MINUTES_IN_HOUR * SECONDS_IN_MINUTE)
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Time API
+ * \{ */
+
+/**
+ * Explode given time value expressed in seconds, into a set of days, hours, minutes, seconds
+ * and/or milliseconds (depending on which return parameters are not NULL).
+ *
+ * \note The smallest given return parameter will get the potential fractional remaining time
+ * value. E.g. if you give `seconds=90.0` and do not pass `r_seconds` and `r_milliseconds`,
+ * `r_minutes` will be set to `1.5`.
+ */
void BLI_math_time_seconds_decompose(double seconds,
double *r_days,
double *r_hours,
@@ -44,7 +61,15 @@ void BLI_math_time_seconds_decompose(double seconds,
double *r_seconds,
double *r_milliseconds);
-/**************************** Inline Definitions ******************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Inline Definitions
+ * \{ */
+
+/* None. */
+
+/** \} */
#ifdef __cplusplus
}
diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h
index 62fd4a835ef..8f955076baf 100644
--- a/source/blender/blenlib/BLI_math_vector.h
+++ b/source/blender/blenlib/BLI_math_vector.h
@@ -33,7 +33,9 @@
extern "C" {
#endif
-/************************************* Init ***********************************/
+/* -------------------------------------------------------------------- */
+/** \name Init
+ * \{ */
#ifdef BLI_MATH_GCC_WARN_PRAGMA
# pragma GCC diagnostic push
@@ -57,6 +59,7 @@ MINLINE void swap_v3_v3(float a[3], float b[3]);
MINLINE void swap_v4_v4(float a[4], float b[4]);
/* unsigned char */
+
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]);
@@ -66,10 +69,13 @@ 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]);
MINLINE void copy_v4_v4_char(char r[4], const char a[4]);
+
/* short */
+
MINLINE void copy_v2_v2_short(short r[2], const short a[2]);
MINLINE void copy_v3_v3_short(short r[3], const short a[3]);
MINLINE void copy_v4_v4_short(short r[4], const short a[4]);
@@ -78,30 +84,49 @@ MINLINE void zero_v3_int(int r[3]);
MINLINE void copy_v2_v2_int(int r[2], const int a[2]);
MINLINE void copy_v3_v3_int(int r[3], const int a[3]);
MINLINE void copy_v4_v4_int(int r[4], const int a[4]);
+
/* double */
+
MINLINE void zero_v3_db(double r[3]);
MINLINE void copy_v2_v2_db(double r[2], const double a[2]);
MINLINE void copy_v3_v3_db(double r[3], const double a[3]);
MINLINE void copy_v4_v4_db(double r[4], const double a[4]);
+
/* short -> float */
+
MINLINE void copy_v3fl_v3s(float r[3], const short a[3]);
+
/* int <-> float */
+
MINLINE void copy_v2fl_v2i(float r[2], const int a[2]);
+
+/* int <-> float */
+
MINLINE void round_v2i_v2fl(int r[2], const float a[2]);
+
/* double -> float */
+
MINLINE void copy_v2fl_v2db(float r[2], const double a[2]);
MINLINE void copy_v3fl_v3db(float r[3], const double a[3]);
MINLINE void copy_v4fl_v4db(float r[4], const double a[4]);
+
/* float -> double */
+
MINLINE void copy_v2db_v2fl(double r[2], const float a[2]);
MINLINE void copy_v3db_v3fl(double r[3], const float a[3]);
MINLINE void copy_v4db_v4fl(double r[4], const float a[4]);
+
/* float args -> vec */
+
MINLINE void copy_v2_fl2(float v[2], float x, float y);
MINLINE void copy_v3_fl3(float v[3], float x, float y, float z);
MINLINE void copy_v4_fl4(float v[4], float x, float y, float z, float w);
-/********************************* Arithmetic ********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Arithmetic
+ * \{ */
MINLINE void add_v2_fl(float r[2], float f);
MINLINE void add_v3_fl(float r[3], float f);
@@ -149,11 +174,30 @@ MINLINE void mul_v4_v4(float r[4], const float a[4]);
MINLINE void mul_v4_v4fl(float r[4], const float a[4], float f);
MINLINE void mul_v2_v2_cw(float r[2], const float mat[2], const float vec[2]);
MINLINE void mul_v2_v2_ccw(float r[2], const float mat[2], const float vec[2]);
+/**
+ * Convenience function to get the projected depth of a position.
+ * This avoids creating a temporary 4D vector and multiplying it - only for the 4th component.
+ *
+ * Matches logic for:
+ *
+ * \code{.c}
+ * float co_4d[4] = {co[0], co[1], co[2], 1.0};
+ * mul_m4_v4(mat, co_4d);
+ * return co_4d[3];
+ * \endcode
+ */
MINLINE float mul_project_m4_v3_zfac(const float mat[4][4],
const float co[3]) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Has the effect of #mul_m3_v3(), on a single axis.
+ */
MINLINE float dot_m3_v3_row_x(const float M[3][3], const float a[3]) ATTR_WARN_UNUSED_RESULT;
MINLINE float dot_m3_v3_row_y(const float M[3][3], const float a[3]) ATTR_WARN_UNUSED_RESULT;
MINLINE float dot_m3_v3_row_z(const float M[3][3], const float a[3]) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Has the effect of #mul_mat3_m4_v3(), on a single axis.
+ * (no adding translation)
+ */
MINLINE float dot_m4_v3_row_x(const float M[4][4], const float a[3]) ATTR_WARN_UNUSED_RESULT;
MINLINE float dot_m4_v3_row_y(const float M[4][4], const float a[3]) ATTR_WARN_UNUSED_RESULT;
MINLINE float dot_m4_v3_row_z(const float M[4][4], const float a[3]) ATTR_WARN_UNUSED_RESULT;
@@ -180,12 +224,17 @@ MINLINE void negate_v3_v3(float r[3], const float a[3]);
MINLINE void negate_v4(float r[4]);
MINLINE void negate_v4_v4(float r[4], const float a[4]);
+/* could add more... */
+
MINLINE void negate_v3_short(short r[3]);
MINLINE void negate_v3_db(double r[3]);
MINLINE void invert_v2(float r[2]);
MINLINE void invert_v3(float r[3]);
-MINLINE void invert_v3_safe(float r[3]); /* Invert the vector, but leaves zero values as zero. */
+/**
+ * Invert the vector, but leaves zero values as zero.
+ */
+MINLINE void invert_v3_safe(float r[3]);
MINLINE void abs_v2(float r[2]);
MINLINE void abs_v2_v2(float r[2], const float a[2]);
@@ -209,14 +258,26 @@ MINLINE double dot_v3v3_db(const double a[3], const double b[3]) ATTR_WARN_UNUSE
MINLINE float cross_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT;
MINLINE double cross_v2v2_db(const double a[2], const double b[2]) ATTR_WARN_UNUSED_RESULT;
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3]);
+/**
+ * Cross product suffers from severe precision loss when vectors are
+ * nearly parallel or opposite; doing the computation in double helps a lot.
+ */
MINLINE void cross_v3_v3v3_hi_prec(float r[3], const float a[3], const float b[3]);
MINLINE void cross_v3_v3v3_db(double r[3], const double a[3], const double b[3]);
+/**
+ * Excuse this fairly specific function, its used for polygon normals all over the place
+ * (could use a better name).
+ */
MINLINE void add_newell_cross_v3_v3v3(float n[3], const float v_prev[3], const float v_curr[3]);
MINLINE void star_m3_v3(float rmat[3][3], const float a[3]);
-/*********************************** Length **********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Length
+ * \{ */
MINLINE float len_squared_v2(const float v[2]) ATTR_WARN_UNUSED_RESULT;
MINLINE float len_squared_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT;
@@ -241,8 +302,14 @@ MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESU
MINLINE double len_v3_db(const double a[3]) ATTR_WARN_UNUSED_RESULT;
MINLINE double len_squared_v3_db(const double v[3]) ATTR_WARN_UNUSED_RESULT;
MINLINE float normalize_v2_length(float r[2], const float unit_scale);
+/**
+ * \note any vectors containing `nan` will be zeroed out.
+ */
MINLINE float normalize_v2_v2_length(float r[2], const float a[2], const float unit_scale);
MINLINE float normalize_v3_length(float r[3], const float unit_scale);
+/**
+ * \note any vectors containing `nan` will be zeroed out.
+ */
MINLINE float normalize_v3_v3_length(float r[3], const float a[3], const float unit_scale);
MINLINE double normalize_v3_length_db(double n[3], const double unit_scale);
MINLINE double normalize_v3_v3_length_db(double r[3], const double a[3], const double unit_scale);
@@ -254,16 +321,32 @@ MINLINE float normalize_v3_v3(float r[3], const float a[3]);
MINLINE double normalize_v3_v3_db(double r[3], const double a[3]);
MINLINE double normalize_v3_db(double n[3]);
-/******************************* Interpolation *******************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Interpolation
+ * \{ */
void interp_v2_v2v2(float r[2], const float a[2], const float b[2], const float t);
void interp_v2_v2v2_db(double target[2], const double a[2], const double b[2], const double t);
+/**
+ * Weight 3 2D vectors,
+ * 'w' must be unit length but is not a vector, just 3 weights.
+ */
void interp_v2_v2v2v2(
float r[2], const float a[2], const float b[2], const float c[2], const float t[3]);
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], const float t);
void interp_v3_v3v3_db(double target[3], const double a[3], const double b[3], const double t);
+/**
+ * Weight 3 vectors,
+ * 'w' must be unit length but is not a vector, just 3 weights.
+ */
void interp_v3_v3v3v3(
float p[3], const float v1[3], const float v2[3], const float v3[3], const float w[3]);
+/**
+ * Weight 3 vectors,
+ * 'w' must be unit length but is not a vector, just 4 weights.
+ */
void interp_v3_v3v3v3v3(float p[3],
const float v1[3],
const float v2[3],
@@ -282,11 +365,20 @@ void interp_v4_v4v4v4v4(float p[4],
void interp_v3_v3v3v3_uv(
float p[3], const float v1[3], const float v2[3], const float v3[3], const float uv[2]);
+/**
+ * slerp, treat vectors as spherical coordinates
+ * \see #interp_qt_qtqt
+ *
+ * \return success
+ */
bool interp_v3_v3v3_slerp(float target[3], const float a[3], const float b[3], const float t)
ATTR_WARN_UNUSED_RESULT;
bool interp_v2_v2v2_slerp(float target[2], const float a[2], const float b[2], const float t)
ATTR_WARN_UNUSED_RESULT;
+/**
+ * Same as #interp_v3_v3v3_slerp but uses fallback values for opposite vectors.
+ */
void interp_v3_v3v3_slerp_safe(float target[3], const float a[3], const float b[3], const float t);
void interp_v2_v2v2_slerp_safe(float target[2], const float a[2], const float b[2], const float t);
@@ -316,14 +408,34 @@ void mid_v3_v3v3v3v3(
float v[3], const float v1[3], const float v2[3], const float v3[3], const float v4[3]);
void mid_v3_v3_array(float r[3], const float (*vec_arr)[3], const unsigned int nbr);
+/**
+ * Specialized function for calculating normals.
+ * Fast-path for:
+ *
+ * \code{.c}
+ * add_v3_v3v3(r, a, b);
+ * normalize_v3(r)
+ * mul_v3_fl(r, angle_normalized_v3v3(a, b) / M_PI_2);
+ * \endcode
+ *
+ * We can use the length of (a + b) to calculate the angle.
+ */
void mid_v3_v3v3_angle_weighted(float r[3], const float a[3], const float b[3]);
+/**
+ * Same as mid_v3_v3v3_angle_weighted
+ * but \a r is assumed to be accumulated normals, divided by their total.
+ */
void mid_v3_angle_weighted(float r[3]);
void flip_v4_v4v4(float v[4], const float v1[4], const float v2[4]);
void flip_v3_v3v3(float v[3], const float v1[3], const float v2[3]);
void flip_v2_v2v2(float v[2], const float v1[2], const float v2[2]);
-/********************************* Comparison ********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Comparison
+ * \{ */
MINLINE bool is_zero_v2(const float a[2]) ATTR_WARN_UNUSED_RESULT;
MINLINE bool is_zero_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT;
@@ -378,24 +490,64 @@ MINLINE bool compare_size_v3v3(const float a[3],
const float b[3],
const float limit) ATTR_WARN_UNUSED_RESULT;
+/**
+ * <pre>
+ * + l1
+ * |
+ * neg <- | -> pos
+ * |
+ * + l2
+ * </pre>
+ *
+ * \return Positive value when 'pt' is left-of-line
+ * (looking from 'l1' -> 'l2').
+ */
MINLINE float line_point_side_v2(const float l1[2],
const float l2[2],
const float pt[2]) ATTR_WARN_UNUSED_RESULT;
-/********************************** Angles ***********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Angles
+ * \{ */
/* - angle with 2 arguments is angle between vector.
* - angle with 3 arguments is angle between 3 points at the middle point.
* - angle_normalized_* is faster equivalent if vectors are normalized.
*/
+
+/**
+ * Return the shortest angle in radians between the 2 vectors.
+ */
float angle_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT;
float angle_signed_v2v2(const float v1[2], const float v2[2]) ATTR_WARN_UNUSED_RESULT;
float angle_v2v2v2(const float a[2], const float b[2], const float c[2]) ATTR_WARN_UNUSED_RESULT;
float angle_normalized_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Return the shortest angle in radians between the 2 vectors.
+ */
float angle_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Return the angle in radians between vecs 1-2 and 2-3 in radians
+ * If v1 is a shoulder, v2 is the elbow and v3 is the hand,
+ * this would return the angle at the elbow.
+ *
+ * note that when v1/v2/v3 represent 3 points along a straight line
+ * that the angle returned will be pi (180deg), rather than 0.0.
+ */
float angle_v3v3v3(const float a[3], const float b[3], const float c[3]) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Quicker than full angle computation.
+ */
float cos_v3v3v3(const float p1[3], const float p2[3], const float p3[3]) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Quicker than full angle computation.
+ */
float cos_v2v2v2(const float p1[2], const float p2[2], const float p3[2]) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Angle between 2 vectors, about an axis (axis can be considered a plane).
+ */
float angle_on_axis_v3v3_v3(const float v1[3],
const float v2[3],
const float axis[3]) ATTR_WARN_UNUSED_RESULT;
@@ -403,6 +555,9 @@ float angle_signed_on_axis_v3v3_v3(const float v1[3],
const float v2[3],
const float axis[3]) ATTR_WARN_UNUSED_RESULT;
float angle_normalized_v3v3(const float v1[3], const float v2[3]) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Angle between 2 vectors defined by 3 coords, about an axis (axis can be considered a plane).
+ */
float angle_on_axis_v3v3v3_v3(const float v1[3],
const float v2[3],
const float v3[3],
@@ -416,32 +571,107 @@ void angle_quad_v3(
float angles[4], const float v1[3], const float v2[3], const float v3[3], const float v4[3]);
void angle_poly_v3(float *angles, const float *verts[3], int len);
-/********************************* Geometry **********************************/
+/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Geometry
+ * \{ */
+
+/**
+ * Project \a p onto \a v_proj
+ */
void project_v2_v2v2(float out[2], const float p[2], const float v_proj[2]);
+/**
+ * Project \a p onto \a v_proj
+ */
void project_v3_v3v3(float out[3], const float p[3], const float v_proj[3]);
void project_v3_v3v3_db(double out[3], const double p[3], const double v_proj[3]);
+/**
+ * Project \a p onto a unit length \a v_proj
+ */
void project_v2_v2v2_normalized(float out[2], const float p[2], const float v_proj[2]);
+/**
+ * Project \a p onto a unit length \a v_proj
+ */
void project_v3_v3v3_normalized(float out[3], const float p[3], const float v_proj[3]);
+/**
+ * In this case plane is a 3D vector only (no 4th component).
+ *
+ * Projecting will make \a out a copy of \a p orthogonal to \a v_plane.
+ *
+ * \note If \a p is exactly perpendicular to \a v_plane, \a out will just be a copy of \a p.
+ *
+ * \note This function is a convenience to call:
+ * \code{.c}
+ * project_v3_v3v3(out, p, v_plane);
+ * sub_v3_v3v3(out, p, out);
+ * \endcode
+ */
void project_plane_v3_v3v3(float out[3], const float p[3], const float v_plane[3]);
void project_plane_v2_v2v2(float out[2], const float p[2], const float v_plane[2]);
void project_plane_normalized_v3_v3v3(float out[3], const float p[3], const float v_plane[3]);
void project_plane_normalized_v2_v2v2(float out[2], const float p[2], const float v_plane[2]);
+/**
+ * Project a vector on a plane defined by normal and a plane point p.
+ */
void project_v3_plane(float out[3], const float plane_no[3], const float plane_co[3]);
+/**
+ * Returns a reflection vector from a vector and a normal vector
+ * reflect = vec - ((2 * dot(vec, mirror)) * mirror).
+ *
+ * <pre>
+ * v
+ * + ^
+ * \ |
+ * \|
+ * + normal: axis of reflection
+ * /
+ * /
+ * +
+ * out: result (negate for a 'bounce').
+ * </pre>
+ */
void reflect_v3_v3v3(float out[3], const float vec[3], const float normal[3]);
void reflect_v3_v3v3_db(double out[3], const double vec[3], const double normal[3]);
+/**
+ * Takes a vector and computes 2 orthogonal directions.
+ *
+ * \note if \a n is n unit length, computed values will be too.
+ */
void ortho_basis_v3v3_v3(float r_n1[3], float r_n2[3], const float n[3]);
+/**
+ * Calculates \a p - a perpendicular vector to \a v
+ *
+ * \note return vector won't maintain same length.
+ */
void ortho_v3_v3(float out[3], const float v[3]);
+/**
+ * no brainer compared to v3, just have for consistency.
+ */
void ortho_v2_v2(float out[2], const float v[2]);
+/**
+ * Returns a vector bisecting the angle at b formed by a, b and c.
+ */
void bisect_v3_v3v3v3(float r[3], const float a[3], const float b[3], const float c[3]);
+/**
+ * Rotate a point \a p by \a angle around origin (0, 0)
+ */
void rotate_v2_v2fl(float r[2], const float p[2], const float angle);
void rotate_v3_v3v3fl(float r[3], const float p[3], const float axis[3], const float angle);
+/**
+ * Rotate a point \a p by \a angle around an arbitrary unit length \a axis.
+ * http://local.wasp.uwa.edu.au/~pbourke/geometry/
+ */
void rotate_normalized_v3_v3v3fl(float out[3],
const float p[3],
const float axis[3],
const float angle);
-/*********************************** Other ***********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Other
+ * \{ */
void print_v2(const char *str, const float v[2]);
void print_v3(const char *str, const float v[3]);
@@ -464,6 +694,7 @@ void minmax_v2v2_v2(float min[2], float max[2], const float vec[2]);
void minmax_v3v3_v3_array(float r_min[3], float r_max[3], const float (*vec_arr)[3], int nbr);
+/** ensure \a v1 is \a dist from \a v2 */
void dist_ensure_v3_v3fl(float v1[3], const float v2[3], const float dist);
void dist_ensure_v2_v2fl(float v1[2], const float v2[2], const float dist);
@@ -476,8 +707,16 @@ MINLINE void clamp_v2_v2v2(float vec[2], const float min[2], const float max[2])
MINLINE void clamp_v3_v3v3(float vec[3], const float min[3], const float max[3]);
MINLINE void clamp_v4_v4v4(float vec[4], const float min[4], const float max[4]);
-/***************************** Array Functions *******************************/
-/* follow fixed length vector function conventions. */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Array Functions
+ * \{ */
+
+/**
+ * Follow fixed length vector function conventions.
+ */
+
double dot_vn_vn(const float *array_src_a,
const float *array_src_b,
const int size) ATTR_WARN_UNUSED_RESULT;
@@ -532,7 +771,11 @@ void add_vn_vnvn_d(double *array_tar,
const int size);
void mul_vn_db(double *array_tar, const int size, const double f);
-/**************************** Inline Definitions ******************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Inline Definitions
+ * \{ */
#if BLI_MATH_DO_INLINE
# include "intern/math_vector_inline.c"
@@ -542,6 +785,8 @@ void mul_vn_db(double *array_tar, const int size, const double f);
# pragma GCC diagnostic pop
#endif
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_memarena.h b/source/blender/blenlib/BLI_memarena.h
index b2e05b00735..4ac4712bc8c 100644
--- a/source/blender/blenlib/BLI_memarena.h
+++ b/source/blender/blenlib/BLI_memarena.h
@@ -29,8 +29,8 @@
extern "C" {
#endif
-/* A reasonable standard buffer size, big
- * enough to not cause much internal fragmentation,
+/**
+ * A reasonable standard buffer size, big enough to not cause much internal fragmentation,
* small enough not to waste resources
*/
#define BLI_MEMARENA_STD_BUFSIZE MEM_SIZE_OPTIMAL(1 << 14)
@@ -50,8 +50,22 @@ void *BLI_memarena_alloc(struct MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESU
void *BLI_memarena_calloc(struct MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1) ATTR_MALLOC ATTR_ALLOC_SIZE(2);
+/**
+ * Transfer ownership of allocated blocks from `ma_src` into `ma_dst`,
+ * cleaning the contents of `ma_src`.
+ *
+ * \note Useful for multi-threaded tasks that need a thread-local #MemArena
+ * that is kept after the multi-threaded operation is completed.
+ *
+ * \note Avoid accumulating memory pools where possible
+ * as any unused memory in `ma_src` is wasted every merge.
+ */
void BLI_memarena_merge(MemArena *ma_dst, MemArena *ma_src) ATTR_NONNULL(1, 2);
+/**
+ * Clear for reuse, avoids re-allocation when an arena may
+ * otherwise be free'd and recreated.
+ */
void BLI_memarena_clear(MemArena *ma) ATTR_NONNULL(1);
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_memblock.h b/source/blender/blenlib/BLI_memblock.h
index a9a3928394d..827ecc49739 100644
--- a/source/blender/blenlib/BLI_memblock.h
+++ b/source/blender/blenlib/BLI_memblock.h
@@ -38,6 +38,10 @@ typedef void (*MemblockValFreeFP)(void *val);
BLI_memblock *BLI_memblock_create_ex(uint elem_size, uint chunk_size) ATTR_WARN_UNUSED_RESULT;
void *BLI_memblock_alloc(BLI_memblock *mblk) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Reset elem count to 0 but keep as much memory allocated needed
+ * for at least the previous elem count.
+ */
void BLI_memblock_clear(BLI_memblock *mblk, MemblockValFreeFP free_callback) ATTR_NONNULL(1);
void BLI_memblock_destroy(BLI_memblock *mblk, MemblockValFreeFP free_callback) ATTR_NONNULL(1);
@@ -56,6 +60,11 @@ typedef struct BLI_memblock_iter {
void BLI_memblock_iternew(BLI_memblock *mblk, BLI_memblock_iter *iter) ATTR_NONNULL();
void *BLI_memblock_iterstep(BLI_memblock_iter *iter) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Direct access. elem is element index inside the chosen chunk.
+ * Double usage: You can set chunk to 0 and set the absolute elem index.
+ * The correct chunk will be retrieve.
+ */
void *BLI_memblock_elem_get(BLI_memblock *mblk, int chunk, int elem) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
diff --git a/source/blender/blenlib/BLI_memiter.h b/source/blender/blenlib/BLI_memiter.h
index abb1bec809d..231aa31fad9 100644
--- a/source/blender/blenlib/BLI_memiter.h
+++ b/source/blender/blenlib/BLI_memiter.h
@@ -35,10 +35,19 @@ struct BLI_memiter;
typedef struct BLI_memiter BLI_memiter;
-/* warning, ATTR_MALLOC flag on BLI_memiter_alloc causes crash, see: D2756 */
-BLI_memiter *BLI_memiter_create(unsigned int chunk_size)
+/**
+ * \param chunk_size_min: Should be a power of two and
+ * significantly larger than the average element size used.
+ *
+ * While allocations of any size are supported, they won't be efficient
+ * (effectively becoming a single-linked list).
+ *
+ * Its intended that many elements can be stored per chunk.
+ */
+BLI_memiter *BLI_memiter_create(unsigned int chunk_size_min)
ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL;
void *BLI_memiter_alloc(BLI_memiter *mi, unsigned int size)
+ /* WARNING: `ATTR_MALLOC` attribute on #BLI_memiter_alloc causes crash, see: D2756. */
ATTR_RETURNS_NONNULL ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1);
void BLI_memiter_alloc_from(BLI_memiter *mi, uint elem_size, const void *data_from)
ATTR_NONNULL(1, 3);
@@ -48,11 +57,15 @@ void BLI_memiter_destroy(BLI_memiter *mi) ATTR_NONNULL(1);
void BLI_memiter_clear(BLI_memiter *mi) ATTR_NONNULL(1);
unsigned int BLI_memiter_count(const BLI_memiter *mi) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
-/* utils */
+/* Utilities. */
+
+/**
+ * Support direct lookup for the first item.
+ */
void *BLI_memiter_elem_first(BLI_memiter *mi);
void *BLI_memiter_elem_first_size(BLI_memiter *mi, unsigned int *r_size);
-/* private structure */
+/** Private structure. */
typedef struct BLI_memiter_handle {
struct BLI_memiter_elem *elem;
uint elem_left;
diff --git a/source/blender/blenlib/BLI_mempool.h b/source/blender/blenlib/BLI_mempool.h
index 61b572a4943..d6abae36e00 100644
--- a/source/blender/blenlib/BLI_mempool.h
+++ b/source/blender/blenlib/BLI_mempool.h
@@ -44,19 +44,52 @@ void *BLI_mempool_alloc(BLI_mempool *pool) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT A
ATTR_NONNULL(1);
void *BLI_mempool_calloc(BLI_mempool *pool)
ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1);
+/**
+ * Free an element from the mempool.
+ *
+ * \note doesn't protect against double frees, take care!
+ */
void BLI_mempool_free(BLI_mempool *pool, void *addr) ATTR_NONNULL(1, 2);
+/**
+ * Empty the pool, as if it were just created.
+ *
+ * \param pool: The pool to clear.
+ * \param totelem_reserve: Optionally reserve how many items should be kept from clearing.
+ */
void BLI_mempool_clear_ex(BLI_mempool *pool, const int totelem_reserve) ATTR_NONNULL(1);
+/**
+ * Wrap #BLI_mempool_clear_ex with no reserve set.
+ */
void BLI_mempool_clear(BLI_mempool *pool) ATTR_NONNULL(1);
+/**
+ * Free the mempool its self (and all elements).
+ */
void BLI_mempool_destroy(BLI_mempool *pool) ATTR_NONNULL(1);
int BLI_mempool_len(const BLI_mempool *pool) ATTR_NONNULL(1);
void *BLI_mempool_findelem(BLI_mempool *pool, unsigned int index) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1);
+/**
+ * Fill in \a data with pointers to each element of the mempool,
+ * to create lookup table.
+ *
+ * \param pool: Pool to create a table from.
+ * \param data: array of pointers at least the size of 'pool->totused'
+ */
void BLI_mempool_as_table(BLI_mempool *pool, void **data) ATTR_NONNULL(1, 2);
+/**
+ * A version of #BLI_mempool_as_table that allocates and returns the data.
+ */
void **BLI_mempool_as_tableN(BLI_mempool *pool,
const char *allocstr) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1, 2);
+/**
+ * Fill in \a data with the contents of the mempool.
+ */
void BLI_mempool_as_array(BLI_mempool *pool, void *data) ATTR_NONNULL(1, 2);
+/**
+ * A version of #BLI_mempool_as_array that allocates and returns the data.
+ */
void *BLI_mempool_as_arrayN(BLI_mempool *pool,
const char *allocstr) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1, 2);
@@ -67,9 +100,10 @@ void BLI_mempool_set_memory_debug(void);
/**
* Iteration stuff.
- * NOTE: this may easy to produce bugs with.
+ * \note this may easy to produce bugs with.
*/
-/* private structure */
+
+/* Private structure. */
typedef struct BLI_mempool_iter {
BLI_mempool *pool;
struct BLI_mempool_chunk *curchunk;
@@ -89,7 +123,13 @@ enum {
BLI_MEMPOOL_ALLOW_ITER = (1 << 0),
};
+/**
+ * Initialize a new mempool iterator, #BLI_MEMPOOL_ALLOW_ITER flag must be set.
+ */
void BLI_mempool_iternew(BLI_mempool *pool, BLI_mempool_iter *iter) ATTR_NONNULL();
+/**
+ * Step over the iterator, returning the mempool item or NULL.
+ */
void *BLI_mempool_iterstep(BLI_mempool_iter *iter) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_mesh_intersect.hh b/source/blender/blenlib/BLI_mesh_intersect.hh
index f28be9bf59b..4aaed814bba 100644
--- a/source/blender/blenlib/BLI_mesh_intersect.hh
+++ b/source/blender/blenlib/BLI_mesh_intersect.hh
@@ -93,13 +93,16 @@ struct Plane {
Plane(const mpq3 &norm_exact, const mpq_class &d_exact);
Plane(const double3 &norm, const double d);
- /* Test equality on the exact fields. */
+ /** Test equality on the exact fields. */
bool operator==(const Plane &other) const;
- /* Hash on the exact fields. */
+ /** Hash on the exact fields. */
uint64_t hash() const;
void make_canonical();
+ /**
+ * This is wrong for degenerate planes, but we don't expect to call it on those.
+ */
bool exact_populated() const;
void populate_exact();
};
@@ -395,10 +398,16 @@ struct BoundingBox {
}
};
-/** Assume bounding boxes have been expanded by a sufficient epsilon. */
+/**
+ * Assume bounding boxes have been expanded by a sufficient epsilon on all sides
+ * so that the comparisons against the bb bounds are sufficient to guarantee that
+ * if an overlap or even touching could happen, this will return true.
+ */
bool bbs_might_intersect(const BoundingBox &bb_a, const BoundingBox &bb_b);
/**
+ * This is the main routine for calculating the self_intersection of a triangle mesh.
+ *
* The output will have duplicate vertices merged and degenerate triangles ignored.
* If the input has overlapping co-planar triangles, then there will be
* as many duplicates as there are overlaps in each overlapping triangular region.
@@ -406,7 +415,7 @@ bool bbs_might_intersect(const BoundingBox &bb_a, const BoundingBox &bb_b);
* that the output triangle was a part of (input can have -1 for that field and then
* the index in `tri[]` will be used as the original index).
* The orig structure of the output #IMesh gives the originals for vertices and edges.
- * NOTE: if the input tm_in has a non-empty orig structure, then it is ignored.
+ * \note if the input tm_in has a non-empty orig structure, then it is ignored.
*/
IMesh trimesh_self_intersect(const IMesh &tm_in, IMeshArena *arena);
@@ -416,10 +425,17 @@ IMesh trimesh_nary_intersect(const IMesh &tm_in,
bool use_self,
IMeshArena *arena);
-/** Return an IMesh that is a triangulation of a mesh with general polygonal faces. */
+/**
+ * Return an #IMesh that is a triangulation of a mesh with general
+ * polygonal faces, #IMesh.
+ * Added diagonals will be distinguishable by having edge original
+ * indices of #NO_INDEX.
+ */
IMesh triangulate_polymesh(IMesh &imesh, IMeshArena *arena);
-/** This has the side effect of populating verts in the #IMesh. */
+/**
+ * Writing the obj_mesh has the side effect of populating verts in the #IMesh.
+ */
void write_obj_mesh(IMesh &m, const std::string &objname);
} /* namespace blender::meshintersect */
diff --git a/source/blender/blenlib/BLI_noise.h b/source/blender/blenlib/BLI_noise.h
index 37afd8ee031..51aee9dc2ba 100644
--- a/source/blender/blenlib/BLI_noise.h
+++ b/source/blender/blenlib/BLI_noise.h
@@ -29,21 +29,65 @@ extern "C" {
float BLI_noise_hnoise(float noisesize, float x, float y, float z);
float BLI_noise_hnoisep(float noisesize, float x, float y, float z);
+/**
+ * Original turbulence functions.
+ */
float BLI_noise_turbulence(float noisesize, float x, float y, float z, int nr);
-/* newnoise: generic noise & turbulence functions
+/**
+ * newnoise: generic noise & turbulence functions
* to replace the above BLI_noise_hnoise/p & BLI_noise_turbulence/1.
- * This is done so different noise basis functions can be used */
+ * This is done so different noise basis functions can be used.
+ */
+/**
+ * newnoise: generic noise function for use with different `noisebasis`.
+ */
float BLI_noise_generic_noise(
float noisesize, float x, float y, float z, bool hard, int noisebasis);
+/**
+ * newnoise: generic turbulence function for use with different `noisebasis`.
+ */
float BLI_noise_generic_turbulence(
float noisesize, float x, float y, float z, int oct, bool hard, int noisebasis);
+
/* newnoise: musgrave functions */
+
+/**
+ * Procedural `fBm` evaluated at "point"; returns value stored in "value".
+ *
+ * \param H: is the fractal increment parameter.
+ * \param lacunarity: is the gap between successive frequencies.
+ * \param octaves: is the number of frequencies in the `fBm`.
+ */
float BLI_noise_mg_fbm(
float x, float y, float z, float H, float lacunarity, float octaves, int noisebasis);
+/**
+ * Procedural multi-fractal evaluated at "point";
+ * returns value stored in "value".
+ *
+ * \param H: determines the highest fractal dimension.
+ * \param lacunarity: is gap between successive frequencies.
+ * \param octaves: is the number of frequencies in the `fBm`.
+ *
+ * \note There used to be a parameter called `offset`, old docs read:
+ * is the zero offset, which determines multi-fractality.
+ */
float BLI_noise_mg_multi_fractal(
float x, float y, float z, float H, float lacunarity, float octaves, int noisebasis);
+/**
+ * "Variable Lacunarity Noise"
+ * A distorted variety of Perlin noise.
+ */
float BLI_noise_mg_variable_lacunarity(
float x, float y, float z, float distortion, int nbas1, int nbas2);
+/**
+ * Heterogeneous procedural terrain function: stats by altitude method.
+ * Evaluated at "point"; returns value stored in "value".
+ *
+ * \param H: Determines the fractal dimension of the roughest areas.
+ * \param lacunarity: Is the gap between successive frequencies.
+ * \param octaves: Is the number of frequencies in the `fBm`.
+ * \param offset: Raises the terrain from `sea level`.
+ */
float BLI_noise_mg_hetero_terrain(float x,
float y,
float z,
@@ -52,6 +96,14 @@ float BLI_noise_mg_hetero_terrain(float x,
float octaves,
float offset,
int noisebasis);
+/**
+ * Hybrid additive/multiplicative multi-fractal terrain model.
+ *
+ * Some good parameter values to start with:
+ *
+ * \param H: 0.25
+ * \param offset: 0.7
+ */
float BLI_noise_mg_hybrid_multi_fractal(float x,
float y,
float z,
@@ -61,6 +113,15 @@ float BLI_noise_mg_hybrid_multi_fractal(float x,
float offset,
float gain,
int noisebasis);
+/**
+ * Ridged multi-fractal terrain model.
+ *
+ * Some good parameter values to start with:
+ *
+ * \param H: 1.0
+ * \param offset: 1.0
+ * \param gain: 2.0
+ */
float BLI_noise_mg_ridged_multi_fractal(float x,
float y,
float z,
@@ -71,9 +132,20 @@ float BLI_noise_mg_ridged_multi_fractal(float x,
float gain,
int noisebasis);
/* newnoise: voronoi */
+
+/**
+ * Not 'pure' Worley, but the results are virtually the same.
+ * Returns distances in da and point coords in `pa`.
+ */
void BLI_noise_voronoi(float x, float y, float z, float *da, float *pa, float me, int dtype);
-/* newnoise: BLI_noise_cell & BLI_noise_cell_v3 (for vector/point/color) */
+/**
+ * newnoise: BLI_noise_cell & BLI_noise_cell_v3 (for vector/point/color).
+ * idem, signed.
+ */
float BLI_noise_cell(float x, float y, float z);
+/**
+ * Returns a vector/point/color in `r_ca`, using point hash-array directly.
+ */
void BLI_noise_cell_v3(float x, float y, float z, float r_ca[3]);
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_noise.hh b/source/blender/blenlib/BLI_noise.hh
index a7af69f42a9..44af2c44f00 100644
--- a/source/blender/blenlib/BLI_noise.hh
+++ b/source/blender/blenlib/BLI_noise.hh
@@ -30,24 +30,28 @@ namespace blender::noise {
* \{ */
/* Hash integers to `uint32_t`. */
+
uint32_t hash(uint32_t kx);
uint32_t hash(uint32_t kx, uint32_t ky);
uint32_t hash(uint32_t kx, uint32_t ky, uint32_t kz);
uint32_t hash(uint32_t kx, uint32_t ky, uint32_t kz, uint32_t kw);
/* Hash floats to `uint32_t`. */
+
uint32_t hash_float(float kx);
uint32_t hash_float(float2 k);
uint32_t hash_float(float3 k);
uint32_t hash_float(float4 k);
/* Hash integers to `float` between 0 and 1. */
+
float hash_to_float(uint32_t kx);
float hash_to_float(uint32_t kx, uint32_t ky);
float hash_to_float(uint32_t kx, uint32_t ky, uint32_t kz);
float hash_to_float(uint32_t kx, uint32_t ky, uint32_t kz, uint32_t kw);
/* Hash floats to `float` between 0 and 1. */
+
float hash_float_to_float(float k);
float hash_float_to_float(float2 k);
float hash_float_to_float(float3 k);
@@ -69,30 +73,35 @@ float4 hash_float_to_float4(float4 k);
* \{ */
/* Perlin noise in the range [-1, 1]. */
+
float perlin_signed(float position);
float perlin_signed(float2 position);
float perlin_signed(float3 position);
float perlin_signed(float4 position);
/* Perlin noise in the range [0, 1]. */
+
float perlin(float position);
float perlin(float2 position);
float perlin(float3 position);
float perlin(float4 position);
/* Fractal perlin noise in the range [0, 1]. */
+
float perlin_fractal(float position, float octaves, float roughness);
float perlin_fractal(float2 position, float octaves, float roughness);
float perlin_fractal(float3 position, float octaves, float roughness);
float perlin_fractal(float4 position, float octaves, float roughness);
/* Positive distorted fractal perlin noise. */
+
float perlin_fractal_distorted(float position, float octaves, float roughness, float distortion);
float perlin_fractal_distorted(float2 position, float octaves, float roughness, float distortion);
float perlin_fractal_distorted(float3 position, float octaves, float roughness, float distortion);
float perlin_fractal_distorted(float4 position, float octaves, float roughness, float distortion);
/* Positive distorted fractal perlin noise that outputs a float3. */
+
float3 perlin_float3_fractal_distorted(float position,
float octaves,
float roughness,
@@ -116,24 +125,56 @@ float3 perlin_float3_fractal_distorted(float4 position,
/** \name Musgrave Multi Fractal
* \{ */
+/**
+ * 1D Ridged Multi-fractal Terrain
+ *
+ * \param H: fractal dimension of the roughest area.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ * \param offset: raises the terrain from `sea level'.
+ */
float musgrave_ridged_multi_fractal(const float co,
const float H,
const float lacunarity,
const float octaves,
const float offset,
const float gain);
+/**
+ * 2D Ridged Multi-fractal Terrain
+ *
+ * \param H: fractal dimension of the roughest area.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ * \param offset: raises the terrain from `sea level'.
+ */
float musgrave_ridged_multi_fractal(const float2 co,
const float H,
const float lacunarity,
const float octaves,
const float offset,
const float gain);
+/**
+ * 3D Ridged Multi-fractal Terrain
+ *
+ * \param H: fractal dimension of the roughest area.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ * \param offset: raises the terrain from `sea level'.
+ */
float musgrave_ridged_multi_fractal(const float3 co,
const float H,
const float lacunarity,
const float octaves,
const float offset,
const float gain);
+/**
+ * 4D Ridged Multi-fractal Terrain
+ *
+ * \param H: fractal dimension of the roughest area.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ * \param offset: raises the terrain from `sea level'.
+ */
float musgrave_ridged_multi_fractal(const float4 co,
const float H,
const float lacunarity,
@@ -141,24 +182,56 @@ float musgrave_ridged_multi_fractal(const float4 co,
const float offset,
const float gain);
+/**
+ * 1D Hybrid Additive/Multiplicative Multi-fractal Terrain
+ *
+ * \param H: fractal dimension of the roughest area.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ * \param offset: raises the terrain from `sea level'.
+ */
float musgrave_hybrid_multi_fractal(const float co,
const float H,
const float lacunarity,
const float octaves,
const float offset,
const float gain);
+/**
+ * 2D Hybrid Additive/Multiplicative Multi-fractal Terrain
+ *
+ * \param H: fractal dimension of the roughest area.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ * \param offset: raises the terrain from `sea level'.
+ */
float musgrave_hybrid_multi_fractal(const float2 co,
const float H,
const float lacunarity,
const float octaves,
const float offset,
const float gain);
+/**
+ * 3D Hybrid Additive/Multiplicative Multi-fractal Terrain
+ *
+ * \param H: fractal dimension of the roughest area.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ * \param offset: raises the terrain from `sea level'.
+ */
float musgrave_hybrid_multi_fractal(const float3 co,
const float H,
const float lacunarity,
const float octaves,
const float offset,
const float gain);
+/**
+ * 4D Hybrid Additive/Multiplicative Multi-fractal Terrain
+ *
+ * \param H: fractal dimension of the roughest area.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ * \param offset: raises the terrain from `sea level'.
+ */
float musgrave_hybrid_multi_fractal(const float4 co,
const float H,
const float lacunarity,
@@ -166,43 +239,132 @@ float musgrave_hybrid_multi_fractal(const float4 co,
const float offset,
const float gain);
+/**
+ * 1D Musgrave fBm
+ *
+ * \param H: fractal increment parameter.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ */
float musgrave_fBm(const float co, const float H, const float lacunarity, const float octaves);
+
+/**
+ * 2D Musgrave fBm
+ *
+ * \param H: fractal increment parameter.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ */
float musgrave_fBm(const float2 co, const float H, const float lacunarity, const float octaves);
+/**
+ * 3D Musgrave fBm
+ *
+ * \param H: fractal increment parameter.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ */
float musgrave_fBm(const float3 co, const float H, const float lacunarity, const float octaves);
+/**
+ * 4D Musgrave fBm
+ *
+ * \param H: fractal increment parameter.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ */
float musgrave_fBm(const float4 co, const float H, const float lacunarity, const float octaves);
+/**
+ * 1D Musgrave Multi-fractal
+ *
+ * \param H: highest fractal dimension.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ */
float musgrave_multi_fractal(const float co,
const float H,
const float lacunarity,
const float octaves);
+/**
+ * 2D Musgrave Multi-fractal
+ *
+ * \param H: highest fractal dimension.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ */
float musgrave_multi_fractal(const float2 co,
const float H,
const float lacunarity,
const float octaves);
+/**
+ * 3D Musgrave Multi-fractal
+ *
+ * \param H: highest fractal dimension.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ */
float musgrave_multi_fractal(const float3 co,
const float H,
const float lacunarity,
const float octaves);
+/**
+ * 4D Musgrave Multi-fractal
+ *
+ * \param H: highest fractal dimension.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ */
float musgrave_multi_fractal(const float4 co,
const float H,
const float lacunarity,
const float octaves);
+/**
+ * 1D Musgrave Heterogeneous Terrain
+ *
+ * \param H: fractal dimension of the roughest area.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ * \param offset: raises the terrain from `sea level'.
+ */
float musgrave_hetero_terrain(const float co,
const float H,
const float lacunarity,
const float octaves,
const float offset);
+/**
+ * 2D Musgrave Heterogeneous Terrain
+ *
+ * \param H: fractal dimension of the roughest area.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ * \param offset: raises the terrain from `sea level'.
+ */
float musgrave_hetero_terrain(const float2 co,
const float H,
const float lacunarity,
const float octaves,
const float offset);
+/**
+ * 3D Musgrave Heterogeneous Terrain
+ *
+ * \param H: fractal dimension of the roughest area.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ * \param offset: raises the terrain from `sea level'.
+ */
float musgrave_hetero_terrain(const float3 co,
const float H,
const float lacunarity,
const float octaves,
const float offset);
+/**
+ * 4D Musgrave Heterogeneous Terrain
+ *
+ * \param H: fractal dimension of the roughest area.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ * \param offset: raises the terrain from `sea level'.
+ */
float musgrave_hetero_terrain(const float4 co,
const float H,
const float lacunarity,
diff --git a/source/blender/blenlib/BLI_path_util.h b/source/blender/blenlib/BLI_path_util.h
index e4774c58e84..8b54ee52322 100644
--- a/source/blender/blenlib/BLI_path_util.h
+++ b/source/blender/blenlib/BLI_path_util.h
@@ -29,27 +29,109 @@
extern "C" {
#endif
+/**
+ * Sets the specified environment variable to the specified value,
+ * and clears it if `val == NULL`.
+ */
void BLI_setenv(const char *env, const char *val) ATTR_NONNULL(1);
+/**
+ * Only set an environment variable if already not there.
+ * Like Unix `setenv(env, val, 0);`
+ *
+ * (not used anywhere).
+ */
void BLI_setenv_if_new(const char *env, const char *val) ATTR_NONNULL(1);
+/**
+ * Get an environment variable, result has to be used immediately.
+ *
+ * On windows #getenv gets its variables from a static copy of the environment variables taken at
+ * process start-up, causing it to not pick up on environment variables created during runtime.
+ * This function uses an alternative method to get environment variables that does pick up on
+ * runtime environment variables. The result will be UTF-8 encoded.
+ */
const char *BLI_getenv(const char *env) ATTR_NONNULL(1);
+/**
+ * Returns in `string` the concatenation of `dir` and `file` (also with `relabase` on the
+ * front if specified and `dir` begins with "//"). Normalizes all occurrences of path
+ * separators, including ensuring there is exactly one between the copies of `dir` and `file`,
+ * and between the copies of `relabase` and `dir`.
+ *
+ * \param relabase: Optional prefix to substitute for "//" on front of `dir`.
+ * \param string: Area to return result.
+ */
void BLI_make_file_string(const char *relabase, char *string, const char *dir, const char *file);
+/**
+ * Ensures that the parent directory of `name` exists.
+ *
+ * \return true on success (i.e. given path now exists on file-system), false otherwise.
+ */
bool BLI_make_existing_file(const char *name);
+/**
+ * Converts `/foo/bar.txt` to `/foo/` and `bar.txt`
+ *
+ * - Won't change \a string.
+ * - Won't create any directories.
+ * - Doesn't use CWD, or deal with relative paths.
+ * - Only fill's in \a dir and \a file when they are non NULL.
+ */
void BLI_split_dirfile(
const char *string, char *dir, char *file, const size_t dirlen, const size_t filelen);
+/**
+ * Copies the parent directory part of string into `dir`, max length `dirlen`.
+ */
void BLI_split_dir_part(const char *string, char *dir, const size_t dirlen);
+/**
+ * Copies the leaf filename part of string into `file`, max length `filelen`.
+ */
void BLI_split_file_part(const char *string, char *file, const size_t filelen);
+/**
+ * Returns a pointer to the last extension (e.g. the position of the last period).
+ * Returns NULL if there is no extension.
+ */
const char *BLI_path_extension(const char *filepath) ATTR_NONNULL();
+/**
+ * Append a filename to a dir, ensuring slash separates.
+ */
void BLI_path_append(char *__restrict dst, const size_t maxlen, const char *__restrict file)
ATTR_NONNULL();
+/**
+ * Simple appending of filename to dir, does not check for valid path!
+ * Puts result into `dst`, which may be same area as `dir`.
+ *
+ * \note Consider using #BLI_path_join for more general path joining
+ * that de-duplicates separators and can handle an arbitrary number of paths.
+ */
void BLI_join_dirfile(char *__restrict dst,
const size_t maxlen,
const char *__restrict dir,
const char *__restrict file) ATTR_NONNULL();
+/**
+ * Join multiple strings into a path, ensuring only a single path separator between each,
+ * and trailing slash is kept.
+ *
+ * \note If you want a trailing slash, add `SEP_STR` as the last path argument,
+ * duplicate slashes will be cleaned up.
+ */
size_t BLI_path_join(char *__restrict dst, const size_t dst_len, const char *path_first, ...)
ATTR_NONNULL(1, 3) ATTR_SENTINEL(0);
+/**
+ * Like Python's `os.path.basename()`
+ *
+ * \return The pointer into \a path string immediately after last slash,
+ * or start of \a path if none found.
+ */
const char *BLI_path_basename(const char *path) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+/**
+ * Get an element of the path at an index, eg:
+ * "/some/path/file.txt" where an index of:
+ * - 0 or -3: "some"
+ * - 1 or -2: "path"
+ * - 2 or -1: "file.txt"
+ *
+ * Ignores multiple slashes at any point in the path (including start/end).
+ */
bool BLI_path_name_at_index(const char *__restrict path,
const int index,
int *__restrict r_offset,
@@ -59,59 +141,233 @@ bool BLI_path_name_at_index(const char *__restrict path,
bool BLI_path_contains(const char *container_path,
const char *containee_path) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Returns pointer to the rightmost path separator in string.
+ */
const char *BLI_path_slash_rfind(const char *string) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+/**
+ * Appends a slash to string if there isn't one there already.
+ * Returns the new length of the string.
+ */
int BLI_path_slash_ensure(char *string) ATTR_NONNULL();
+/**
+ * Removes the last slash and everything after it to the end of string, if there is one.
+ */
void BLI_path_slash_rstrip(char *string) ATTR_NONNULL();
+/**
+ * Returns pointer to the leftmost path separator in string. Not actually used anywhere.
+ */
const char *BLI_path_slash_find(const char *string) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+/**
+ * Changes to the path separators to the native ones for this OS.
+ */
void BLI_path_slash_native(char *path) ATTR_NONNULL();
#ifdef _WIN32
bool BLI_path_program_extensions_add_win32(char *name, const size_t maxlen);
#endif
+/**
+ * Search for a binary (executable)
+ */
bool BLI_path_program_search(char *fullname, const size_t maxlen, const char *name);
+/**
+ * \return true when `str` end with `ext` (case insensitive).
+ */
bool BLI_path_extension_check(const char *str, const char *ext)
ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
bool BLI_path_extension_check_n(const char *str, ...) ATTR_NONNULL(1) ATTR_SENTINEL(0);
+/**
+ * \return true when `str` ends with any of the suffixes in `ext_array`.
+ */
bool BLI_path_extension_check_array(const char *str, const char **ext_array)
ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+/**
+ * Semicolon separated wildcards, eg: `*.zip;*.py;*.exe`
+ * does `str` match any of the semicolon-separated glob patterns in #fnmatch.
+ */
bool BLI_path_extension_check_glob(const char *str, const char *ext_fnmatch)
ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+/**
+ * Does basic validation of the given glob string, to prevent common issues from string
+ * truncation.
+ *
+ * For now, only forbids last group to be a wildcard-only one, if there are more than one group
+ * (i.e. things like `*.txt;*.cpp;*` are changed to `*.txt;*.cpp;`)
+ *
+ * \returns true if it had to modify given \a ext_fnmatch pattern.
+ */
bool BLI_path_extension_glob_validate(char *ext_fnmatch) ATTR_NONNULL();
+/**
+ * Removes any existing extension on the end of \a path and appends \a ext.
+ * \return false if there was no room.
+ */
bool BLI_path_extension_replace(char *path, size_t maxlen, const char *ext) ATTR_NONNULL();
+/**
+ * Strip's trailing '.'s and adds the extension only when needed
+ */
bool BLI_path_extension_ensure(char *path, size_t maxlen, const char *ext) ATTR_NONNULL();
+/**
+ * Ensure `filepath` has a file component, adding `filename` when it's empty or ends with a slash.
+ * \return true if the `filename` was appended to `filepath`.
+ */
bool BLI_path_filename_ensure(char *filepath, size_t maxlen, const char *filename) ATTR_NONNULL();
+/**
+ * Looks for a sequence of decimal digits in string, preceding any filename extension,
+ * returning the integer value if found, or 0 if not.
+ *
+ * \param string: String to scan.
+ * \param head: Optional area to return copy of part of string prior to digits,
+ * or before dot if no digits.
+ * \param tail: Optional area to return copy of part of string following digits,
+ * or from dot if no digits.
+ * \param r_num_len: Optional to return number of digits found.
+ */
int BLI_path_sequence_decode(const char *string,
char *head,
char *tail,
unsigned short *r_num_len);
+/**
+ * Returns in area pointed to by string a string of the form `<head><pic><tail>`,
+ * where pic is formatted as `numlen` digits with leading zeroes.
+ */
void BLI_path_sequence_encode(
char *string, const char *head, const char *tail, unsigned short numlen, int pic);
+/**
+ * Remove redundant characters from \a path and optionally make absolute.
+ *
+ * \param relabase: The path this is relative to, or ignored when NULL.
+ * \param path: Can be any input, and this function converts it to a regular full path.
+ * Also removes garbage from directory paths, like `/../` or double slashes etc.
+ *
+ * \note \a path isn't protected for max string names.
+ */
void BLI_path_normalize(const char *relabase, char *path) ATTR_NONNULL(2);
-/* Same as above but adds a trailing slash. */
+/**
+ * Cleanup file-path ensuring a trailing slash.
+ *
+ * \note Same as #BLI_path_normalize but adds a trailing slash.
+ */
void BLI_path_normalize_dir(const char *relabase, char *dir) ATTR_NONNULL(2);
+/**
+ * Make given name safe to be used in paths.
+ *
+ * \return true if \a fname was changed, false otherwise.
+ *
+ * For now, simply replaces reserved chars (as listed in
+ * https://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words )
+ * by underscores ('_').
+ *
+ * \note Space case ' ' is a bit of an edge case here - in theory it is allowed,
+ * but again can be an issue in some cases, so we simply replace it by an underscore too
+ * (good practice anyway).
+ * REMOVED based on popular demand (see T45900).
+ * Percent '%' char is a bit same case - not recommended to use it,
+ * but supported by all decent file-systems/operating-systems around.
+ *
+ * \note On Windows, it also ensures there is no '.' (dot char) at the end of the file,
+ * this can lead to issues.
+ *
+ * \note On Windows, it also checks for forbidden names
+ * (see https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx ).
+ */
bool BLI_filename_make_safe(char *fname) ATTR_NONNULL(1);
+/**
+ * Make given path OS-safe.
+ *
+ * \return true if \a path was changed, false otherwise.
+ */
bool BLI_path_make_safe(char *path) ATTR_NONNULL(1);
-/* Go back one directory. */
+/**
+ * Go back one directory.
+ *
+ * Replaces path with the path of its parent directory, returning true if
+ * it was able to find a parent directory within the path.
+ */
bool BLI_path_parent_dir(char *path) ATTR_NONNULL();
-/* Go back until the directory is found. */
+/**
+ * Go back until the directory is found.
+ *
+ * Strips off nonexistent (or non-accessible) sub-directories from the end of `dir`,
+ * leaving the path of the lowest-level directory that does exist and we can read.
+ */
bool BLI_path_parent_dir_until_exists(char *path) ATTR_NONNULL();
+/**
+ * If path begins with "//", strips that and replaces it with `basepath` directory.
+ *
+ * \note Also converts drive-letter prefix to something more sensible
+ * if this is a non-drive-letter-based system.
+ *
+ * \param path: The path to convert.
+ * \param basepath: The directory to base relative paths with.
+ * \return true if the path was relative (started with "//").
+ */
bool BLI_path_abs(char *path, const char *basepath) ATTR_NONNULL();
+/**
+ * Replaces "#" character sequence in last slash-separated component of `path`
+ * with frame as decimal integer, with leading zeroes as necessary, to make digits digits.
+ */
bool BLI_path_frame(char *path, int frame, int digits) ATTR_NONNULL();
+/**
+ * Replaces "#" character sequence in last slash-separated component of `path`
+ * with sta and end as decimal integers, with leading zeroes as necessary, to make digits
+ * digits each, with a hyphen in-between.
+ */
bool BLI_path_frame_range(char *path, int sta, int end, int digits) ATTR_NONNULL();
+/**
+ * Get the frame from a filename formatted by blender's frame scheme
+ */
bool BLI_path_frame_get(char *path, int *r_frame, int *numdigits) ATTR_NONNULL();
-void BLI_path_frame_strip(char *path, char *ext) ATTR_NONNULL();
+/**
+ * Given a `path` with digits representing frame numbers, replace the digits with the '#'
+ * character and extract the extension.
+ * So: `/some/path_123.jpeg`
+ * Becomes: `/some/path_###` with `r_ext` set to `.jpeg`.
+ */
+void BLI_path_frame_strip(char *path, char *r_ext) ATTR_NONNULL();
+/**
+ * Check if we have '#' chars, usable for #BLI_path_frame, #BLI_path_frame_range
+ */
bool BLI_path_frame_check_chars(const char *path) ATTR_NONNULL();
+/**
+ * Checks for a relative path (ignoring Blender's "//") prefix
+ * (unlike `!BLI_path_is_rel(path)`).
+ * When false, #BLI_path_abs_from_cwd would expand the absolute path.
+ */
+bool BLI_path_is_abs_from_cwd(const char *path) ATTR_NONNULL();
+/**
+ * Checks for relative path, expanding them relative to the current working directory.
+ * \returns true if the expansion was performed.
+ *
+ * \note Should only be called with command line paths.
+ * This is _not_ something Blender's internal paths support, instead they use the "//" prefix.
+ * In most cases #BLI_path_abs should be used instead.
+ */
bool BLI_path_abs_from_cwd(char *path, const size_t maxlen) ATTR_NONNULL();
+/**
+ * Replaces `file` with a relative version (prefixed by "//") such that #BLI_path_abs, given
+ * the same `relfile`, will convert it back to its original value.
+ */
void BLI_path_rel(char *file, const char *relfile) ATTR_NONNULL();
+/**
+ * Does path begin with the special "//" prefix that Blender uses to indicate
+ * a path relative to the .blend file.
+ */
bool BLI_path_is_rel(const char *path) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+/**
+ * Return true if the path is a UNC share.
+ */
bool BLI_path_is_unc(const char *path);
+/**
+ * Creates a display string from path to be used menus and the user interface.
+ * Like `bpy.path.display_name()`.
+ */
void BLI_path_to_display_name(char *display_name, int maxlen, const char *name) ATTR_NONNULL();
#if defined(WIN32)
@@ -119,10 +375,22 @@ void BLI_path_normalize_unc_16(wchar_t *path_16);
void BLI_path_normalize_unc(char *path_16, int maxlen);
#endif
+/**
+ * Appends a suffix to the string, fitting it before the extension
+ *
+ * string = Foo.png, suffix = 123, separator = _
+ * Foo.png -> Foo_123.png
+ *
+ * \param string: original (and final) string
+ * \param maxlen: Maximum length of string
+ * \param suffix: String to append to the original string
+ * \param sep: Optional separator character
+ * \return true if succeeded
+ */
bool BLI_path_suffix(char *string, size_t maxlen, const char *suffix, const char *sep)
ATTR_NONNULL();
-/* path string comparisons: case-insensitive for Windows, case-sensitive otherwise */
+/* Path string comparisons: case-insensitive for Windows, case-sensitive otherwise. */
#if defined(WIN32)
# define BLI_path_cmp BLI_strcasecmp
# define BLI_path_ncmp BLI_strncasecmp
@@ -131,8 +399,8 @@ bool BLI_path_suffix(char *string, size_t maxlen, const char *suffix, const char
# define BLI_path_ncmp strncmp
#endif
-/* these values need to be hardcoded in structs, dna does not recognize defines */
-/* also defined in DNA_space_types.h */
+/* These values need to be hard-coded in structs, dna does not recognize defines */
+/* also defined in `DNA_space_types.h`. */
#ifndef FILE_MAXDIR
# define FILE_MAXDIR 768
# define FILE_MAXFILE 256
@@ -155,7 +423,7 @@ bool BLI_path_suffix(char *string, size_t maxlen, const char *suffix, const char
#define FILENAME_PARENT ".."
#define FILENAME_CURRENT "."
-/* Avoid calling strcmp on one or two chars! */
+/* Avoid calling `strcmp` on one or two chars! */
#define FILENAME_IS_PARENT(_n) (((_n)[0] == '.') && ((_n)[1] == '.') && ((_n)[2] == '\0'))
#define FILENAME_IS_CURRENT(_n) (((_n)[0] == '.') && ((_n)[1] == '\0'))
#define FILENAME_IS_CURRPAR(_n) \
diff --git a/source/blender/blenlib/BLI_polyfill_2d.h b/source/blender/blenlib/BLI_polyfill_2d.h
index ca63ea5af87..d16c102ec86 100644
--- a/source/blender/blenlib/BLI_polyfill_2d.h
+++ b/source/blender/blenlib/BLI_polyfill_2d.h
@@ -26,6 +26,9 @@ extern "C" {
struct MemArena;
+/**
+ * A version of #BLI_polyfill_calc that uses a memory arena to avoid re-allocations.
+ */
void BLI_polyfill_calc_arena(const float (*coords)[2],
const unsigned int coords_tot,
const int coords_sign,
@@ -33,6 +36,19 @@ void BLI_polyfill_calc_arena(const float (*coords)[2],
struct MemArena *arena);
+/**
+ * Triangulates the given (convex or concave) simple polygon to a list of triangle vertices.
+ *
+ * \param coords: 2D coordinates describing vertices of the polygon,
+ * in either clockwise or counterclockwise order.
+ * \param coords_tot: Total points in the array.
+ * \param coords_sign: Pass this when we know the sign in advance to avoid extra calculations.
+ *
+ * \param r_tris: This array is filled in with triangle indices in clockwise order.
+ * The length of the array must be `coords_tot - 2`.
+ * Indices are guaranteed to be assigned to unique triangles, with valid indices,
+ * even in the case of degenerate input (self intersecting polygons, zero area ears... etc).
+ */
void BLI_polyfill_calc(const float (*coords)[2],
const unsigned int coords_tot,
const int coords_sign,
diff --git a/source/blender/blenlib/BLI_polyfill_2d_beautify.h b/source/blender/blenlib/BLI_polyfill_2d_beautify.h
index 2c5296269ae..b0b97336a3b 100644
--- a/source/blender/blenlib/BLI_polyfill_2d_beautify.h
+++ b/source/blender/blenlib/BLI_polyfill_2d_beautify.h
@@ -27,6 +27,12 @@ extern "C" {
struct Heap;
struct MemArena;
+/**
+ * The intention is that this calculates the output of #BLI_polyfill_calc
+ * \note assumes the \a coords form a boundary,
+ * so any edges running along contiguous (wrapped) indices,
+ * are ignored since the edges won't share 2 faces.
+ */
void BLI_polyfill_beautify(const float (*coords)[2],
const unsigned int coords_tot,
unsigned int (*tris)[3],
@@ -35,6 +41,21 @@ void BLI_polyfill_beautify(const float (*coords)[2],
struct MemArena *arena,
struct Heap *eheap);
+/**
+ * Assuming we have 2 triangles sharing an edge (2 - 4),
+ * check if the edge running from (1 - 3) gives better results.
+ *
+ * \param lock_degenerate: Use to avoid rotating out of a degenerate state:
+ * - When true, an existing zero area face on either side of the (2 - 4
+ * split will return a positive value.
+ * - When false, the check must be non-biased towards either split direction.
+ * \param r_area: Return the area of the quad,
+ * This can be useful when comparing the return value with near zero epsilons.
+ * In this case the epsilon can be scaled by the area to avoid the return value
+ * of very large faces not having a reliable way to detect near-zero output.
+ *
+ * \return (negative number means the edge can be rotated, lager == better).
+ */
float BLI_polyfill_beautify_quad_rotate_calc_ex(const float v1[2],
const float v2[2],
const float v3[2],
diff --git a/source/blender/blenlib/BLI_rand.h b/source/blender/blenlib/BLI_rand.h
index f8627952628..a1df6e1263e 100644
--- a/source/blender/blenlib/BLI_rand.h
+++ b/source/blender/blenlib/BLI_rand.h
@@ -31,7 +31,8 @@
extern "C" {
#endif
-/* RNG is an abstract random number generator type that avoids using globals.
+/**
+ * RNG is an abstract random number generator type that avoids using globals.
* Always use this instead of the global RNG unless you have a good reason,
* the global RNG is not thread safe and will not give repeatable results.
*/
@@ -42,19 +43,34 @@ struct RNG_THREAD_ARRAY;
typedef struct RNG_THREAD_ARRAY RNG_THREAD_ARRAY;
struct RNG *BLI_rng_new(unsigned int seed);
+/**
+ * A version of #BLI_rng_new that hashes the seed.
+ */
struct RNG *BLI_rng_new_srandom(unsigned int seed);
struct RNG *BLI_rng_copy(struct RNG *rng) ATTR_NONNULL(1);
void BLI_rng_free(struct RNG *rng) ATTR_NONNULL(1);
void BLI_rng_seed(struct RNG *rng, unsigned int seed) ATTR_NONNULL(1);
+/**
+ * Use a hash table to create better seed.
+ */
void BLI_rng_srandom(struct RNG *rng, unsigned int seed) ATTR_NONNULL(1);
void BLI_rng_get_char_n(RNG *rng, char *bytes, size_t bytes_len) ATTR_NONNULL(1, 2);
int BLI_rng_get_int(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
unsigned int BLI_rng_get_uint(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * \return Random value (0..1), but never 1.0.
+ */
double BLI_rng_get_double(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * \return Random value (0..1), but never 1.0.
+ */
float BLI_rng_get_float(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
void BLI_rng_get_float_unit_v2(struct RNG *rng, float v[2]) ATTR_NONNULL(1, 2);
void BLI_rng_get_float_unit_v3(struct RNG *rng, float v[3]) ATTR_NONNULL(1, 2);
+/**
+ * Generate a random point inside given tri.
+ */
void BLI_rng_get_tri_sample_float_v2(struct RNG *rng,
const float v1[2],
const float v2[2],
@@ -75,9 +91,16 @@ void BLI_rng_shuffle_bitmap(struct RNG *rng, unsigned int *bitmap, unsigned int
ATTR_NONNULL(1, 2);
/** Note that skipping is as slow as generating n numbers! */
+/**
+ * Simulate getting \a n random values.
+ *
+ * \note Useful when threaded code needs consistent values, independent of task division.
+ */
void BLI_rng_skip(struct RNG *rng, int n) ATTR_NONNULL(1);
-/* fill an array with random numbers */
+/**
+ * Fill an array with random numbers.
+ */
void BLI_array_frand(float *ar, int count, unsigned int seed);
/** Return a pseudo-random (hash) float from an integer value */
diff --git a/source/blender/blenlib/BLI_rand.hh b/source/blender/blenlib/BLI_rand.hh
index 0c0dd464d4d..cc9e9b374d7 100644
--- a/source/blender/blenlib/BLI_rand.hh
+++ b/source/blender/blenlib/BLI_rand.hh
@@ -47,6 +47,9 @@ class RandomNumberGenerator {
x_ = (static_cast<uint64_t>(seed) << 16) | lowseed;
}
+ /**
+ * Set a randomized hash of the value as seed.
+ */
void seed_random(uint32_t seed);
uint32_t get_uint32()
@@ -117,6 +120,9 @@ class RandomNumberGenerator {
float2 get_unit_float2();
float3 get_unit_float3();
+ /**
+ * Generate a random point inside the given triangle.
+ */
float2 get_triangle_sample(float2 v1, float2 v2, float2 v3);
float3 get_triangle_sample_3d(float3 v1, float3 v2, float3 v3);
void get_bytes(MutableSpan<char> r_bytes);
diff --git a/source/blender/blenlib/BLI_rect.h b/source/blender/blenlib/BLI_rect.h
index fb52436587f..f4b1d051d16 100644
--- a/source/blender/blenlib/BLI_rect.h
+++ b/source/blender/blenlib/BLI_rect.h
@@ -34,12 +34,28 @@ struct rcti;
extern "C" {
#endif
+/**
+ * Determine if a `rect` is empty.
+ * An empty `rect` is one with a zero (or negative) width or height.
+ *
+ * \return True if \a rect is empty.
+ */
bool BLI_rcti_is_empty(const struct rcti *rect);
bool BLI_rctf_is_empty(const struct rctf *rect);
void BLI_rctf_init(struct rctf *rect, float xmin, float xmax, float ymin, float ymax);
void BLI_rcti_init(struct rcti *rect, int xmin, int xmax, int ymin, int ymax);
+/**
+ * Check if X-min and Y-min are less than or equal to X-max and Y-max, respectively.
+ * If this returns false, #BLI_rctf_sanitize() can be called to address this.
+ *
+ * This is not a hard constraint or invariant for rectangles, in some cases it may be useful to
+ * have max < min. Usually this is what you'd want though.
+ */
bool BLI_rctf_is_valid(const struct rctf *rect);
bool BLI_rcti_is_valid(const struct rcti *rect);
+/**
+ * Ensure X-min and Y-min are less than or equal to X-max and Y-max, respectively.
+ */
void BLI_rctf_sanitize(struct rctf *rect);
void BLI_rcti_sanitize(struct rcti *rect);
void BLI_rctf_init_pt_radius(struct rctf *rect, const float xy[2], float size);
@@ -48,11 +64,21 @@ void BLI_rcti_init_minmax(struct rcti *rect);
void BLI_rctf_init_minmax(struct rctf *rect);
void BLI_rcti_do_minmax_v(struct rcti *rect, const int xy[2]);
void BLI_rctf_do_minmax_v(struct rctf *rect, const float xy[2]);
+void BLI_rcti_do_minmax_rcti(struct rcti *rect, const struct rcti *other);
+/**
+ * Given 2 rectangles, transform a point from one to another.
+ */
void BLI_rctf_transform_pt_v(const rctf *dst,
const rctf *src,
float xy_dst[2],
const float xy_src[2]);
+/**
+ * Calculate a 4x4 matrix representing the transformation between two rectangles.
+ *
+ * \note Multiplying a vector by this matrix does *not*
+ * give the same value as #BLI_rctf_transform_pt_v.
+ */
void BLI_rctf_transform_calc_m4_pivot_min_ex(
const rctf *dst, const rctf *src, float matrix[4][4], uint x, uint y);
void BLI_rctf_transform_calc_m4_pivot_min(const rctf *dst, const rctf *src, float matrix[4][4]);
@@ -62,7 +88,13 @@ void BLI_rcti_translate(struct rcti *rect, int x, int y);
void BLI_rcti_recenter(struct rcti *rect, int x, int y);
void BLI_rctf_recenter(struct rctf *rect, float x, float y);
void BLI_rcti_resize(struct rcti *rect, int x, int y);
+/**
+ * Change width & height around the central X location.
+ */
void BLI_rcti_resize_x(struct rcti *rect, int x);
+/**
+ * Change width & height around the central Y location.
+ */
void BLI_rcti_resize_y(struct rcti *rect, int y);
void BLI_rcti_pad(struct rcti *rect, int pad_x, int pad_y);
void BLI_rctf_pad(struct rctf *rect, float pad_x, float pad_y);
@@ -82,6 +114,14 @@ void BLI_rctf_interp(struct rctf *rect,
// void BLI_rcti_interp(struct rctf *rect, struct rctf *rect_a, struct rctf *rect_b, float fac);
bool BLI_rctf_clamp_pt_v(const struct rctf *rect, float xy[2]);
bool BLI_rcti_clamp_pt_v(const struct rcti *rect, int xy[2]);
+/**
+ * Clamp \a rect within \a rect_bounds, setting \a r_xy to the offset.
+ *
+ * Keeps the top left corner within the bounds, which for user interface
+ * elements is typically where the most important information is.
+ *
+ * \return true if a change is made.
+ */
bool BLI_rctf_clamp(struct rctf *rect, const struct rctf *rect_bounds, float r_xy[2]);
bool BLI_rcti_clamp(struct rcti *rect, const struct rcti *rect_bounds, int r_xy[2]);
bool BLI_rctf_compare(const struct rctf *rect_a, const struct rctf *rect_b, const float limit);
@@ -100,7 +140,13 @@ bool BLI_rctf_isect_x(const rctf *rect, const float x);
bool BLI_rctf_isect_y(const rctf *rect, const float y);
bool BLI_rctf_isect_pt(const struct rctf *rect, const float x, const float y);
bool BLI_rctf_isect_pt_v(const struct rctf *rect, const float xy[2]);
+/**
+ * \returns shortest distance from \a rect to x (0 if inside)
+ */
int BLI_rcti_length_x(const rcti *rect, const int x);
+/**
+ * \returns shortest distance from \a rect to y (0 if inside)
+ */
int BLI_rcti_length_y(const rcti *rect, const int y);
float BLI_rctf_length_x(const rctf *rect, const float x);
float BLI_rctf_length_y(const rctf *rect, const float y);
@@ -109,14 +155,20 @@ bool BLI_rctf_isect_segment(const struct rctf *rect, const float s1[2], const fl
bool BLI_rcti_isect_circle(const struct rcti *rect, const float xy[2], const float radius);
bool BLI_rctf_isect_circle(const struct rctf *rect, const float xy[2], const float radius);
bool BLI_rcti_inside_rcti(const rcti *rct_a, const rcti *rct_b);
+/**
+ * is \a rct_b inside \a rct_a
+ */
bool BLI_rctf_inside_rctf(const rctf *rct_a, const rctf *rct_b);
-void BLI_rcti_union(struct rcti *rct1, const struct rcti *rct2);
-void BLI_rctf_union(struct rctf *rct1, const struct rctf *rct2);
+void BLI_rcti_union(struct rcti *rct_a, const struct rcti *rct_b);
+void BLI_rctf_union(struct rctf *rct_a, const struct rctf *rct_b);
void BLI_rcti_rctf_copy(struct rcti *dst, const struct rctf *src);
void BLI_rctf_rcti_copy(struct rctf *dst, const struct rcti *src);
void BLI_rcti_rctf_copy_floor(struct rcti *dst, const struct rctf *src);
void BLI_rcti_rctf_copy_round(struct rcti *dst, const struct rctf *src);
+/**
+ * Expand the rectangle to fit a rotated \a src.
+ */
void BLI_rctf_rotate_expand(rctf *dst, const rctf *src, const float angle);
void print_rctf(const char *str, const struct rctf *rect);
diff --git a/source/blender/blenlib/BLI_scanfill.h b/source/blender/blenlib/BLI_scanfill.h
index 8f281023177..744d30397d4 100644
--- a/source/blender/blenlib/BLI_scanfill.h
+++ b/source/blender/blenlib/BLI_scanfill.h
@@ -123,6 +123,12 @@ void BLI_scanfill_begin_arena(ScanFillContext *sf_ctx, struct MemArena *arena);
void BLI_scanfill_end_arena(ScanFillContext *sf_ctx, struct MemArena *arena);
/* scanfill_utils.c */
+
+/**
+ * Call before scan-fill to remove self intersections.
+ *
+ * \return false if no changes were made.
+ */
bool BLI_scanfill_calc_self_isect(ScanFillContext *sf_ctx,
ListBase *fillvertbase,
ListBase *filledgebase);
diff --git a/source/blender/blenlib/BLI_smallhash.h b/source/blender/blenlib/BLI_smallhash.h
index f7aec716e9e..9492a252fed 100644
--- a/source/blender/blenlib/BLI_smallhash.h
+++ b/source/blender/blenlib/BLI_smallhash.h
@@ -34,8 +34,10 @@ typedef struct {
void *val;
} SmallHashEntry;
-/* How much stack space to use before dynamically allocating memory.
- * set to match one of the values in 'hashsizes' to avoid too many mallocs. */
+/**
+ * How much stack space to use before dynamically allocating memory.
+ * set to match one of the values in 'hashsizes' to avoid too many mallocs.
+ */
#define SMSTACKSIZE 131
typedef struct SmallHash {
unsigned int nbuckets;
@@ -53,8 +55,18 @@ typedef struct {
void BLI_smallhash_init_ex(SmallHash *sh, const unsigned int nentries_reserve) ATTR_NONNULL(1);
void BLI_smallhash_init(SmallHash *sh) ATTR_NONNULL(1);
+/**
+ * \note does *not* free *sh itself! only the direct data!
+ */
void BLI_smallhash_release(SmallHash *sh) ATTR_NONNULL(1);
void BLI_smallhash_insert(SmallHash *sh, uintptr_t key, void *item) ATTR_NONNULL(1);
+/**
+ * Inserts a new value to a key that may already be in ghash.
+ *
+ * Avoids #BLI_smallhash_remove, #BLI_smallhash_insert calls (double lookups)
+ *
+ * \returns true if a new key has been added.
+ */
bool BLI_smallhash_reinsert(SmallHash *sh, uintptr_t key, void *item) ATTR_NONNULL(1);
bool BLI_smallhash_remove(SmallHash *sh, uintptr_t key) ATTR_NONNULL(1);
void *BLI_smallhash_lookup(const SmallHash *sh, uintptr_t key)
@@ -74,6 +86,12 @@ void **BLI_smallhash_iternew_p(const SmallHash *sh, SmallHashIter *iter, uintptr
/* void BLI_smallhash_print(SmallHash *sh); */ /* UNUSED */
#ifdef DEBUG
+/**
+ * Measure how well the hash function performs
+ * (1.0 is perfect - no stepping needed).
+ *
+ * Smaller is better!
+ */
double BLI_smallhash_calc_quality(SmallHash *sh);
#endif
diff --git a/source/blender/blenlib/BLI_stack.h b/source/blender/blenlib/BLI_stack.h
index b00bc0a2e57..653f5f61c9e 100644
--- a/source/blender/blenlib/BLI_stack.h
+++ b/source/blender/blenlib/BLI_stack.h
@@ -31,24 +31,73 @@ typedef struct BLI_Stack BLI_Stack;
BLI_Stack *BLI_stack_new_ex(const size_t elem_size,
const char *description,
const size_t chunk_size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Create a new homogeneous stack with elements of 'elem_size' bytes.
+ */
BLI_Stack *BLI_stack_new(const size_t elem_size, const char *description) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Free the stack's data and the stack itself
+ */
void BLI_stack_free(BLI_Stack *stack) ATTR_NONNULL();
+/**
+ * Push a new item onto the stack.
+ *
+ * \return a pointer #BLI_Stack.elem_size
+ * bytes of uninitialized memory (caller must fill in).
+ */
void *BLI_stack_push_r(BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Copies the source value onto the stack
+ *
+ * \note This copies #BLI_Stack.elem_size bytes from \a src,
+ * (the pointer itself is not stored).
+ *
+ * \param src: source data to be copied to the stack.
+ */
void BLI_stack_push(BLI_Stack *stack, const void *src) ATTR_NONNULL();
+/**
+ * A version of #BLI_stack_pop which fills in an array.
+ *
+ * \param dst: The destination array,
+ * must be at least (#BLI_Stack.elem_size * \a n) bytes long.
+ * \param n: The number of items to pop.
+ *
+ * \note The first item in the array will be last item added to the stack.
+ */
void BLI_stack_pop_n(BLI_Stack *stack, void *dst, unsigned int n) ATTR_NONNULL();
+/**
+ * A version of #BLI_stack_pop_n which fills in an array (in the reverse order).
+ *
+ * \note The first item in the array will be first item added to the stack.
+ */
void BLI_stack_pop_n_reverse(BLI_Stack *stack, void *dst, unsigned int n) ATTR_NONNULL();
+/**
+ * Retrieves and removes the top element from the stack.
+ * The value is copies to \a dst, which must be at least \a elem_size bytes.
+ *
+ * Does not reduce amount of allocated memory.
+ */
void BLI_stack_pop(BLI_Stack *stack, void *dst) ATTR_NONNULL();
void *BLI_stack_peek(BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Removes the top element from the stack.
+ */
void BLI_stack_discard(BLI_Stack *stack) ATTR_NONNULL();
+/**
+ * Discards all elements without freeing.
+ */
void BLI_stack_clear(BLI_Stack *stack) ATTR_NONNULL();
size_t BLI_stack_count(const BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Returns true if the stack is empty, false otherwise
+ */
bool BLI_stack_is_empty(const BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_string.h b/source/blender/blenlib/BLI_string.h
index d3dc05edd9e..91cc7b23a5f 100644
--- a/source/blender/blenlib/BLI_string.h
+++ b/source/blender/blenlib/BLI_string.h
@@ -33,23 +33,78 @@
extern "C" {
#endif
+/**
+ * Duplicates the first \a len bytes of cstring \a str
+ * into a newly mallocN'd string and returns it. \a str
+ * is assumed to be at least len bytes long.
+ *
+ * \param str: The string to be duplicated
+ * \param len: The number of bytes to duplicate
+ * \retval Returns the duplicated string
+ */
char *BLI_strdupn(const char *str, const size_t len) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Duplicates the cstring \a str into a newly mallocN'd
+ * string and returns it.
+ *
+ * \param str: The string to be duplicated
+ * \retval Returns the duplicated string
+ */
char *BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL() ATTR_MALLOC;
+/**
+ * Appends the two strings, and returns new mallocN'ed string
+ * \param str1: first string for copy
+ * \param str2: second string for append
+ * \retval Returns dst
+ */
char *BLI_strdupcat(const char *__restrict str1,
const char *__restrict str2) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL() ATTR_MALLOC;
+/**
+ * Like strncpy but ensures dst is always
+ * '\0' terminated.
+ *
+ * \param dst: Destination for copy
+ * \param src: Source string to copy
+ * \param maxncpy: Maximum number of characters to copy (generally
+ * the size of dst)
+ * \retval Returns dst
+ */
char *BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t maxncpy)
ATTR_NONNULL();
+/**
+ * Like BLI_strncpy but ensures dst is always padded by given char,
+ * on both sides (unless src is empty).
+ *
+ * \param dst: Destination for copy
+ * \param src: Source string to copy
+ * \param pad: the char to use for padding
+ * \param maxncpy: Maximum number of characters to copy (generally the size of dst)
+ * \retval Returns dst
+ */
char *BLI_strncpy_ensure_pad(char *__restrict dst,
const char *__restrict src,
const char pad,
size_t maxncpy) ATTR_NONNULL();
+/**
+ * Like strncpy but ensures dst is always
+ * '\0' terminated.
+ *
+ * \note This is a duplicate of #BLI_strncpy that returns bytes copied.
+ * And is a drop in replacement for 'snprintf(str, sizeof(str), "%s", arg);'
+ *
+ * \param dst: Destination for copy
+ * \param src: Source string to copy
+ * \param maxncpy: Maximum number of characters to copy (generally
+ * the size of dst)
+ * \retval The number of bytes copied (The only difference from BLI_strncpy).
+ */
size_t BLI_strncpy_rlen(char *__restrict dst,
const char *__restrict src,
const size_t maxncpy) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
@@ -57,6 +112,18 @@ size_t BLI_strncpy_rlen(char *__restrict dst,
size_t BLI_strcpy_rlen(char *__restrict dst, const char *__restrict src) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Return the range of the quoted string (excluding quotes) `str` after `prefix`.
+ *
+ * A version of #BLI_str_quoted_substrN that calculates the range
+ * instead of un-escaping and allocating the result.
+ *
+ * \param str: String potentially including `prefix`.
+ * \param prefix: Quoted string prefix.
+ * \param r_start: The start of the quoted string (after the first quote).
+ * \param r_end: The end of the quoted string (before the last quote).
+ * \return True when a quoted string range could be found after `prefix`.
+ */
bool BLI_str_quoted_substr_range(const char *__restrict str,
const char *__restrict prefix,
int *__restrict r_start,
@@ -67,91 +134,328 @@ char *BLI_str_quoted_substrN(const char *__restrict str,
const char *__restrict prefix) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL() ATTR_MALLOC;
#endif
+/**
+ * Fills \a result with text within "" that appear after some the contents of \a prefix.
+ * i.e. for string `pose["apples"]` with prefix `pose[`, it will return `apples`.
+ *
+ * \param str: is the entire string to chop.
+ * \param prefix: is the part of the string to step over.
+ * \param result: The buffer to fill.
+ * \param result_maxlen: The maximum size of the buffer (including nil terminator).
+ * \return True if the prefix was found and the entire quoted string was copied into result.
+ *
+ * Assume that the strings returned must be freed afterwards,
+ * and that the inputs will contain data we want.
+ */
bool BLI_str_quoted_substr(const char *__restrict str,
const char *__restrict prefix,
char *result,
size_t result_maxlen);
+/**
+ * string with all instances of substr_old replaced with substr_new,
+ * Returns a copy of the c-string \a str into a newly #MEM_mallocN'd
+ * and returns it.
+ *
+ * \note A rather wasteful string-replacement utility, though this shall do for now.
+ * Feel free to replace this with an even safe + nicer alternative
+ *
+ * \param str: The string to replace occurrences of substr_old in
+ * \param substr_old: The text in the string to find and replace
+ * \param substr_new: The text in the string to find and replace
+ * \retval Returns the duplicated string
+ */
char *BLI_str_replaceN(const char *__restrict str,
const char *__restrict substr_old,
const char *__restrict substr_new) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL() ATTR_MALLOC;
-void BLI_str_replace_char(char *string, char src, char dst) ATTR_NONNULL();
+/**
+ * In-place replace every \a src to \a dst in \a str.
+ *
+ * \param str: The string to operate on.
+ * \param src: The character to replace.
+ * \param dst: The character to replace with.
+ */
+void BLI_str_replace_char(char *str, char src, char dst) ATTR_NONNULL();
+/**
+ * Simple exact-match string replacement.
+ *
+ * \param replace_table: Array of source, destination pairs.
+ *
+ * \note Larger tables should use a hash table.
+ */
bool BLI_str_replace_table_exact(char *string,
const size_t string_len,
const char *replace_table[][2],
int replace_table_len);
+/**
+ * Portable replacement for #snprintf
+ */
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format, ...)
ATTR_NONNULL(1, 3) ATTR_PRINTF_FORMAT(3, 4);
+/**
+ * A version of #BLI_snprintf that returns `strlen(dst)`
+ */
size_t BLI_snprintf_rlen(char *__restrict dst, size_t maxncpy, const char *__restrict format, ...)
ATTR_NONNULL(1, 3) ATTR_PRINTF_FORMAT(3, 4);
+/**
+ * Portable replacement for `vsnprintf`.
+ */
size_t BLI_vsnprintf(char *__restrict buffer,
size_t maxncpy,
const char *__restrict format,
va_list arg) ATTR_PRINTF_FORMAT(3, 0);
+/**
+ * A version of #BLI_vsnprintf that returns `strlen(buffer)`
+ */
size_t BLI_vsnprintf_rlen(char *__restrict buffer,
size_t maxncpy,
const char *__restrict format,
va_list arg) ATTR_PRINTF_FORMAT(3, 0);
+/**
+ * Print formatted string into a newly #MEM_mallocN'd string
+ * and return it.
+ */
char *BLI_sprintfN(const char *__restrict format, ...) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1) ATTR_MALLOC ATTR_PRINTF_FORMAT(1, 2);
+/**
+ * This roughly matches C and Python's string escaping with double quotes - `"`.
+ *
+ * Since every character may need escaping,
+ * it's common to create a buffer twice as large as the input.
+ *
+ * \param dst: The destination string, at least \a dst_maxncpy, typically `(strlen(src) * 2) + 1`.
+ * \param src: The un-escaped source string.
+ * \param dst_maxncpy: The maximum number of bytes allowable to copy.
+ *
+ * \note This is used for creating animation paths in blend files.
+ */
size_t BLI_str_escape(char *__restrict dst, const char *__restrict src, const size_t dst_maxncpy)
ATTR_NONNULL();
+/**
+ * This roughly matches C and Python's string escaping with double quotes - `"`.
+ *
+ * The destination will never be larger than the source, it will either be the same
+ * or up to half when all characters are escaped.
+ *
+ * \param dst: The destination string, at least the size of `strlen(src) + 1`.
+ * \param src: The escaped source string.
+ * \param src_maxncpy: The maximum number of bytes allowable to copy from `src`.
+ * \param dst_maxncpy: The maximum number of bytes allowable to copy into `dst`.
+ * \param r_is_complete: Set to true when
+ */
size_t BLI_str_unescape_ex(char *__restrict dst,
const char *__restrict src,
const size_t src_maxncpy,
/* Additional arguments. */
const size_t dst_maxncpy,
bool *r_is_complete) ATTR_NONNULL();
+/**
+ * See #BLI_str_unescape_ex doc-string.
+ *
+ * This function makes the assumption that `dst` always has
+ * at least `src_maxncpy` bytes available.
+ *
+ * Use #BLI_str_unescape_ex if `dst` has a smaller fixed size.
+ *
+ * \note This is used for parsing animation paths in blend files (runs often).
+ */
size_t BLI_str_unescape(char *__restrict dst, const char *__restrict src, const size_t src_maxncpy)
ATTR_NONNULL();
+/**
+ * Find the first un-escaped quote in the string (to find the end of the string).
+ *
+ * \param str: Typically this is the first character in a quoted string.
+ * Where the character before `*str` would be `"`.
+
+ * \return The pointer to the first un-escaped quote.
+ */
const char *BLI_str_escape_find_quote(const char *str) ATTR_NONNULL();
+/**
+ * Format ints with decimal grouping.
+ * 1000 -> 1,000
+ *
+ * \param dst: The resulting string
+ * \param num: Number to format
+ * \return The length of \a dst
+ */
size_t BLI_str_format_int_grouped(char dst[16], int num) ATTR_NONNULL();
+/**
+ * Format uint64_t with decimal grouping.
+ * 1000 -> 1,000
+ *
+ * \param dst: The resulting string
+ * \param num: Number to format
+ * \return The length of \a dst
+ */
size_t BLI_str_format_uint64_grouped(char dst[16], uint64_t num) ATTR_NONNULL();
+/**
+ * Format a size in bytes using binary units.
+ * 1000 -> 1 KB
+ * Number of decimal places grows with the used unit (e.g. 1.5 MB, 1.55 GB, 1.545 TB).
+ *
+ * \param dst: The resulting string.
+ * Dimension of 14 to support largest possible value for \a bytes (#LLONG_MAX).
+ * \param bytes: Number to format.
+ * \param base_10: Calculate using base 10 (GB, MB, ...) or 2 (GiB, MiB, ...).
+ */
void BLI_str_format_byte_unit(char dst[15], long long int bytes, const bool base_10)
ATTR_NONNULL();
+/**
+ * Format a count to up to 6 places (plus '\0' terminator) string using long number
+ * names abbreviations. Used to produce a compact representation of large numbers.
+ *
+ * 1 -> 1
+ * 15 -> 15
+ * 155 -> 155
+ * 1555 -> 1.6K
+ * 15555 -> 15.6K
+ * 155555 -> 156K
+ * 1555555 -> 1.6M
+ * 15555555 -> 15.6M
+ * 155555555 -> 156M
+ * 1000000000 -> 1B
+ * ...
+ *
+ * Length of 7 is the maximum of the resulting string, for example, `-15.5K\0`.
+ */
void BLI_str_format_attribute_domain_size(char dst[7], int number_to_format) ATTR_NONNULL();
+/**
+ * Compare two strings without regard to case.
+ *
+ * \retval True if the strings are equal, false otherwise.
+ */
int BLI_strcaseeq(const char *a, const char *b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Portable replacement for `strcasestr` (not available in MSVC)
+ */
char *BLI_strcasestr(const char *s, const char *find) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Variation of #BLI_strcasestr with string length limited to \a len
+ */
char *BLI_strncasestr(const char *s, const char *find, size_t len) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
int BLI_strcasecmp(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int BLI_strncasecmp(const char *s1, const char *s2, size_t len) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Case insensitive, *natural* string comparison,
+ * keeping numbers in order.
+ */
int BLI_strcasecmp_natural(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Like strcmp, but will ignore any heading/trailing pad char for comparison.
+ * So e.g. if pad is '*', '*world' and 'world*' will compare equal.
+ */
int BLI_strcmp_ignore_pad(const char *str1,
const char *str2,
const char pad) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Determine the length of a fixed-size string.
+ */
size_t BLI_strnlen(const char *str, const size_t maxlen) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
void BLI_str_tolower_ascii(char *str, const size_t len) ATTR_NONNULL();
void BLI_str_toupper_ascii(char *str, const size_t len) ATTR_NONNULL();
+/**
+ * Strip white-space from end of the string.
+ */
void BLI_str_rstrip(char *str) ATTR_NONNULL();
+/**
+ * Strip trailing zeros from a float, eg:
+ * 0.0000 -> 0.0
+ * 2.0010 -> 2.001
+ *
+ * \param str:
+ * \param pad:
+ * \return The number of zeros stripped.
+ */
int BLI_str_rstrip_float_zero(char *str, const char pad) ATTR_NONNULL();
+/**
+ * Return index of a string in a string array.
+ *
+ * \param str: The string to find.
+ * \param str_array: Array of strings.
+ * \param str_array_len: The length of the array, or -1 for a NULL-terminated array.
+ * \return The index of str in str_array or -1.
+ */
int BLI_str_index_in_array_n(const char *__restrict str,
const char **__restrict str_array,
const int str_array_len) ATTR_NONNULL();
+/**
+ * Return index of a string in a string array.
+ *
+ * \param str: The string to find.
+ * \param str_array: Array of strings, (must be NULL-terminated).
+ * \return The index of str in str_array or -1.
+ */
int BLI_str_index_in_array(const char *__restrict str, const char **__restrict str_array)
ATTR_NONNULL();
+/**
+ * Find if a string starts with another string.
+ *
+ * \param str: The string to search within.
+ * \param start: The string we look for at the start.
+ * \return If str starts with start.
+ */
bool BLI_str_startswith(const char *__restrict str, const char *__restrict start) ATTR_NONNULL();
+/**
+ * Find if a string ends with another string.
+ *
+ * \param str: The string to search within.
+ * \param end: The string we look for at the end.
+ * \return If str ends with end.
+ */
bool BLI_str_endswith(const char *__restrict str, const char *__restrict end) ATTR_NONNULL();
bool BLI_strn_endswith(const char *__restrict str, const char *__restrict end, size_t length)
ATTR_NONNULL();
+/**
+ * Find the first char matching one of the chars in \a delim, from left.
+ *
+ * \param str: The string to search within.
+ * \param delim: The set of delimiters to search for, as unicode values.
+ * \param sep: Return value, set to the first delimiter found (or NULL if none found).
+ * \param suf: Return value, set to next char after the first delimiter found
+ * (or NULL if none found).
+ * \return The length of the prefix (i.e. *sep - str).
+ */
size_t BLI_str_partition(const char *str, const char delim[], const char **sep, const char **suf)
ATTR_NONNULL();
+/**
+ * Find the first char matching one of the chars in \a delim, from right.
+ *
+ * \param str: The string to search within.
+ * \param delim: The set of delimiters to search for, as unicode values.
+ * \param sep: Return value, set to the first delimiter found (or NULL if none found).
+ * \param suf: Return value, set to next char after the first delimiter found
+ * (or NULL if none found).
+ * \return The length of the prefix (i.e. *sep - str).
+ */
size_t BLI_str_rpartition(const char *str, const char delim[], const char **sep, const char **suf)
ATTR_NONNULL();
+/**
+ * Find the first char matching one of the chars in \a delim, either from left or right.
+ *
+ * \param str: The string to search within.
+ * \param end: If non-NULL, the right delimiter of the string.
+ * \param delim: The set of delimiters to search for, as unicode values.
+ * \param sep: Return value, set to the first delimiter found (or NULL if none found).
+ * \param suf: Return value, set to next char after the first delimiter found
+ * (or NULL if none found).
+ * \param from_right: If %true, search from the right of \a str, else, search from its left.
+ * \return The length of the prefix (i.e. *sep - str).
+ */
size_t BLI_str_partition_ex(const char *str,
const char *end,
const char delim[],
@@ -166,6 +470,16 @@ bool BLI_string_all_words_matched(const char *name,
int (*words)[2],
const int words_len);
+/**
+ * Find the ranges needed to split \a str into its individual words.
+ *
+ * \param str: The string to search for words.
+ * \param len: Size of the string to search.
+ * \param delim: Character to use as a delimiter.
+ * \param r_words: Info about the words found. Set to [index, len] pairs.
+ * \param words_max: Max number of words to find
+ * \return The number of words found in \a str
+ */
int BLI_string_find_split_words(const char *str,
const size_t len,
const char delim,
@@ -177,6 +491,7 @@ int BLI_string_find_split_words(const char *str,
* Avoid repeating destination with `sizeof(..)`.
* \note `ARRAY_SIZE` allows pointers on some platforms.
* \{ */
+
#define STRNCPY(dst, src) BLI_strncpy(dst, src, ARRAY_SIZE(dst))
#define STRNCPY_RLEN(dst, src) BLI_strncpy_rlen(dst, src, ARRAY_SIZE(dst))
#define SNPRINTF(dst, format, ...) BLI_snprintf(dst, ARRAY_SIZE(dst), format, __VA_ARGS__)
@@ -186,6 +501,7 @@ int BLI_string_find_split_words(const char *str,
len += BLI_strncpy_rlen(dst + len, suffix, ARRAY_SIZE(dst) - len)
#define STR_CONCATF(dst, len, format, ...) \
len += BLI_snprintf_rlen(dst + len, ARRAY_SIZE(dst) - len, format, __VA_ARGS__)
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/blenlib/BLI_string_search.h b/source/blender/blenlib/BLI_string_search.h
index 8057e5b75cb..f0bf259d213 100644
--- a/source/blender/blenlib/BLI_string_search.h
+++ b/source/blender/blenlib/BLI_string_search.h
@@ -23,7 +23,19 @@ extern "C" {
typedef struct StringSearch StringSearch;
StringSearch *BLI_string_search_new(void);
-void BLI_string_search_add(StringSearch *search, const char *str, void *user_data);
+/**
+ * Add a new possible result to the search.
+ * The caller keeps ownership of all parameters.
+ *
+ * \param weight: Can be used to customize the order when multiple items have the same match score.
+ */
+void BLI_string_search_add(StringSearch *search, const char *str, void *user_data, int weight);
+
+/**
+ * Filter and sort all previously added search items.
+ * Returns an array containing the filtered user data.
+ * The caller has to free the returned array.
+ */
int BLI_string_search_query(StringSearch *search, const char *query, void ***r_data);
void BLI_string_search_free(StringSearch *search);
@@ -40,8 +52,24 @@ void BLI_string_search_free(StringSearch *search);
namespace blender::string_search {
+/**
+ * Computes the cost of transforming string a into b. The cost/distance is the minimal number of
+ * operations that need to be executed. Valid operations are deletion, insertion, substitution and
+ * transposition.
+ *
+ * This function is utf8 aware in the sense that it works at the level of individual code points
+ * (1-4 bytes long) instead of on individual bytes.
+ */
int damerau_levenshtein_distance(StringRef a, StringRef b);
+/**
+ * Returns -1 when this is no reasonably good match.
+ * Otherwise returns the number of errors in the match.
+ */
int get_fuzzy_match_errors(StringRef query, StringRef full);
+/**
+ * Splits a string into words and normalizes them (currently that just means converting to lower
+ * case). The returned strings are allocated in the given allocator.
+ */
void extract_normalized_words(StringRef str,
LinearAllocator<> &allocator,
Vector<StringRef, 64> &r_words);
diff --git a/source/blender/blenlib/BLI_string_utf8.h b/source/blender/blenlib/BLI_string_utf8.h
index bf7547cc90b..72bddb322db 100644
--- a/source/blender/blenlib/BLI_string_utf8.h
+++ b/source/blender/blenlib/BLI_string_utf8.h
@@ -32,23 +32,84 @@ char *BLI_strncpy_utf8(char *__restrict dst, const char *__restrict src, size_t
size_t BLI_strncpy_utf8_rlen(char *__restrict dst,
const char *__restrict src,
size_t maxncpy) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2);
+/**
+ * Find first UTF-8 invalid byte in given \a str, of \a length bytes.
+ *
+ * \return the offset of the first invalid byte.
+ */
ptrdiff_t BLI_str_utf8_invalid_byte(const char *str, size_t length) ATTR_NONNULL(1);
+/**
+ * Remove any invalid UTF-8 byte (taking into account multi-bytes sequence of course).
+ *
+ * \return number of stripped bytes.
+ */
int BLI_str_utf8_invalid_strip(char *str, size_t length) ATTR_NONNULL(1);
-/* warning, can return -1 on bad chars */
+/**
+ * \return The size (in bytes) of a single UTF-8 char.
+ * \warning Can return -1 on bad chars.
+ */
int BLI_str_utf8_size(const char *p) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Use when we want to skip errors.
+ */
int BLI_str_utf8_size_safe(const char *p) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
-/* copied from glib */
+/**
+ * \param p: a pointer to Unicode character encoded as UTF-8
+ *
+ * Converts a sequence of bytes encoded as UTF-8 to a Unicode character.
+ * If \a p does not point to a valid UTF-8 encoded character, results are
+ * undefined. If you are not sure that the bytes are complete
+ * valid Unicode characters, you should use g_utf8_get_char_validated()
+ * instead.
+ *
+ * Return value: the resulting character
+ */
unsigned int BLI_str_utf8_as_unicode(const char *p) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * UTF8 decoding that steps over the index (unless an error is encountered).
+ *
+ * \param p: The text to step over.
+ * \param p_len: The length of `p`.
+ * \param index: Index of `p` to step over.
+ * \return the code-point `(p + *index)` if there is a decoding error.
+ *
+ * \note Falls back to `LATIN1` for text drawing.
+ */
unsigned int BLI_str_utf8_as_unicode_step(const char *__restrict p,
size_t p_len,
size_t *__restrict index) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1, 3);
+/**
+ * UTF8 decoding that steps over the index (unless an error is encountered).
+ *
+ * \param p: The text to step over.
+ * \param p_len: The length of `p`.
+ * \param index: Index of `p` to step over.
+ * \return the code-point or #BLI_UTF8_ERR if there is a decoding error.
+ *
+ * \note The behavior for clipped text (where `p_len` limits decoding trailing bytes)
+ * must have the same behavior is encountering a nil byte,
+ * so functions that only use the first part of a string has matching behavior to functions
+ * that null terminate the text.
+ */
unsigned int BLI_str_utf8_as_unicode_step_or_error(
const char *__restrict p, size_t p_len, size_t *__restrict index) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1, 3);
size_t BLI_str_utf8_from_unicode_len(unsigned int c) ATTR_WARN_UNUSED_RESULT;
+/**
+ * BLI_str_utf8_from_unicode:
+ *
+ * \param c: a Unicode character code
+ * \param outbuf: output buffer, must have at least `outbuf_len` bytes of space.
+ * If the length required by `c` exceeds `outbuf_len`,
+ * the bytes available bytes will be zeroed and `outbuf_len` returned.
+ *
+ * Converts a single character to UTF-8.
+ *
+ * \return number of bytes written.
+ */
size_t BLI_str_utf8_from_unicode(unsigned int c, char *outbuf, const size_t outbuf_len)
ATTR_NONNULL(2);
size_t BLI_str_utf8_as_utf32(char32_t *__restrict dst_w,
@@ -57,19 +118,57 @@ size_t BLI_str_utf8_as_utf32(char32_t *__restrict dst_w,
size_t BLI_str_utf32_as_utf8(char *__restrict dst,
const char32_t *__restrict src,
const size_t maxncpy) ATTR_NONNULL(1, 2);
+/**
+ * \return The UTF-32 len in UTF-8.
+ */
size_t BLI_str_utf32_as_utf8_len(const char32_t *src) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * BLI_str_find_prev_char_utf8:
+ * \param p: pointer to some position within \a str
+ * \param str_start: pointer to the beginning of a UTF-8 encoded string
+ *
+ * Given a position \a p with a UTF-8 encoded string \a str, find the start
+ * of the previous UTF-8 character starting before. \a p Returns \a str_start if no
+ * UTF-8 characters are present in \a str_start before \a p.
+ *
+ * \a p does not have to be at the beginning of a UTF-8 character. No check
+ * is made to see if the character found is actually valid other than
+ * it starts with an appropriate byte.
+ *
+ * \return A pointer to the found character.
+ */
const char *BLI_str_find_prev_char_utf8(const char *p, const char *str_start)
ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1, 2);
+/**
+ * \param p: a pointer to a position within a UTF-8 encoded string
+ * \param str_end: a pointer to the byte following the end of the string.
+ *
+ * Finds the start of the next UTF-8 character in the string after \a p
+ *
+ * \a p does not have to be at the beginning of a UTF-8 character. No check
+ * is made to see if the character found is actually valid other than
+ * it starts with an appropriate byte.
+ *
+ * \return a pointer to the found character or a pointer to the null terminating character '\0'.
+ */
const char *BLI_str_find_next_char_utf8(const char *p, const char *str_end)
ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1, 2);
+/**
+ * \return the `wchar_t` length in UTF-8.
+ */
size_t BLI_wstrlen_utf8(const wchar_t *src) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
size_t BLI_strlen_utf8_ex(const char *strc, size_t *r_len_bytes)
ATTR_NONNULL(1, 2) ATTR_WARN_UNUSED_RESULT;
size_t BLI_strlen_utf8(const char *strc) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
size_t BLI_strnlen_utf8_ex(const char *strc, const size_t maxlen, size_t *r_len_bytes)
ATTR_NONNULL(1, 3);
+/**
+ * \param strc: the string to measure the length.
+ * \param maxlen: the string length (in bytes)
+ * \return the unicode length (not in bytes!)
+ */
size_t BLI_strnlen_utf8(const char *strc, const size_t maxlen)
ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
size_t BLI_strncpy_wchar_as_utf8(char *__restrict dst,
@@ -79,10 +178,14 @@ size_t BLI_strncpy_wchar_from_utf8(wchar_t *__restrict dst,
const char *__restrict src,
const size_t maxncpy) ATTR_NONNULL(1, 2);
-/* count columns that character/string occupies, based on wcwidth.c */
+/**
+ * Count columns that character/string occupies (based on `wcwidth.co`).
+ */
int BLI_wcwidth(char32_t ucs) ATTR_WARN_UNUSED_RESULT;
int BLI_wcswidth(const char32_t *pwcs, size_t n) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
-/* warning, can return -1 on bad chars */
+/**
+ * \warning can return -1 on bad chars.
+ */
int BLI_str_utf8_char_width(const char *p) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
int BLI_str_utf8_char_width_safe(const char *p) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
@@ -111,7 +214,8 @@ int BLI_str_utf8_offset_to_column(const char *str, int offset) ATTR_WARN_UNUSED_
int BLI_str_utf8_offset_from_column(const char *str, int column) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1);
-#define BLI_UTF8_MAX 6 /* mem */
+/** Size in bytes. */
+#define BLI_UTF8_MAX 6
#define BLI_UTF8_WIDTH_MAX 2 /* columns */
#define BLI_UTF8_ERR ((unsigned int)-1)
@@ -120,8 +224,10 @@ int BLI_str_utf8_offset_from_column(const char *str, int column) ATTR_WARN_UNUSE
* Avoid repeating destination with `sizeof(..)`.
* \note `ARRAY_SIZE` allows pointers on some platforms.
* \{ */
+
#define STRNCPY_UTF8(dst, src) BLI_strncpy_utf8(dst, src, ARRAY_SIZE(dst))
#define STRNCPY_UTF8_RLEN(dst, src) BLI_strncpy_utf8_rlen(dst, src, ARRAY_SIZE(dst))
+
/** \} */
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_string_utils.h b/source/blender/blenlib/BLI_string_utils.h
index 277bb6fac05..ce4d0afb933 100644
--- a/source/blender/blenlib/BLI_string_utils.h
+++ b/source/blender/blenlib/BLI_string_utils.h
@@ -36,33 +36,71 @@ struct ListBase;
typedef bool (*UniquenameCheckCallback)(void *arg, const char *name);
+/**
+ * Looks for a numeric suffix preceded by `delim` character on the end of
+ * name, puts preceding part into *left and value of suffix into *nr.
+ * Returns the length of *left.
+ *
+ * Foo.001 -> "Foo", 1
+ * Returning the length of "Foo"
+ *
+ * \param left: Where to return copy of part preceding `delim`.
+ * \param nr: Where to return value of numeric suffix`.
+ * \param name: String to split`.
+ * \param delim: Delimiter character`.
+ * \return Length of \a left.
+ */
size_t BLI_split_name_num(char *left, int *nr, const char *name, const char delim);
bool BLI_string_is_decimal(const char *string) ATTR_NONNULL();
+/**
+ * Based on `BLI_split_dirfile()` / `os.path.splitext()`,
+ * `"a.b.c"` -> (`"a.b"`, `".c"`).
+ */
void BLI_string_split_suffix(const char *string, char *r_body, char *r_suf, const size_t str_len);
+/**
+ * `"a.b.c"` -> (`"a."`, `"b.c"`).
+ */
void BLI_string_split_prefix(const char *string, char *r_pre, char *r_body, const size_t str_len);
-/* Join strings, return newly allocated string. */
+/**
+ * Join strings, return newly allocated string.
+ */
char *BLI_string_join_array(char *result,
size_t result_len,
const char *strings[],
uint strings_len) ATTR_NONNULL();
+/**
+ * A version of #BLI_string_join that takes a separator which can be any character including '\0'.
+ */
char *BLI_string_join_array_by_sep_char(char *result,
size_t result_len,
char sep,
const char *strings[],
uint strings_len) ATTR_NONNULL();
+/**
+ * Join an array of strings into a newly allocated, null terminated string.
+ */
char *BLI_string_join_arrayN(const char *strings[], uint strings_len) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * A version of #BLI_string_joinN that takes a separator which can be any character including '\0'.
+ */
char *BLI_string_join_array_by_sep_charN(char sep,
const char *strings[],
uint strings_len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * A version of #BLI_string_join_array_by_sep_charN that takes a table array.
+ * The new location of each string is written into this array.
+ */
char *BLI_string_join_array_by_sep_char_with_tableN(char sep,
char *table[],
const char *strings[],
uint strings_len) ATTR_NONNULL();
-/* Take multiple arguments, pass as (array, length). */
+/**
+ * Take multiple arguments, pass as (array, length).
+ */
#define BLI_string_join(result, result_len, ...) \
BLI_string_join_array( \
result, result_len, ((const char *[]){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__))
@@ -75,23 +113,57 @@ char *BLI_string_join_array_by_sep_char_with_tableN(char sep,
BLI_string_join_array_by_sep_char_with_tableN( \
sep, table, ((const char *[]){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__))
+/**
+ * Finds the best possible flipped (left/right) name.
+ * For renaming; check for unique names afterwards.
+ *
+ * \param r_name: flipped name,
+ * assumed to be a pointer to a string of at least \a name_len size.
+ * \param from_name: original name,
+ * assumed to be a pointer to a string of at least \a name_len size.
+ * \param strip_number: If set, remove number extensions.
+ * \return The number of bytes written into \a r_name.
+ */
size_t BLI_string_flip_side_name(char *r_name,
const char *from_name,
const bool strip_number,
const size_t name_len);
+/**
+ * Ensures name is unique (according to criteria specified by caller in unique_check callback),
+ * incrementing its numeric suffix as necessary. Returns true if name had to be adjusted.
+ *
+ * \param unique_check: Return true if name is not unique
+ * \param arg: Additional arg to unique_check--meaning is up to caller
+ * \param defname: To initialize name if latter is empty
+ * \param delim: Delimits numeric suffix in name
+ * \param name: Name to be ensured unique
+ * \param name_len: Maximum length of name area
+ * \return true if there if the name was changed
+ */
bool BLI_uniquename_cb(UniquenameCheckCallback unique_check,
void *arg,
const char *defname,
char delim,
char *name,
size_t name_len);
+/**
+ * Ensures that the specified block has a unique name within the containing list,
+ * incrementing its numeric suffix as necessary. Returns true if name had to be adjusted.
+ *
+ * \param list: List containing the block
+ * \param vlink: The block to check the name for
+ * \param defname: To initialize block name if latter is empty
+ * \param delim: Delimits numeric suffix in name
+ * \param name_offset: Offset of name within block structure
+ * \param name_len: Maximum length of name area
+ */
bool BLI_uniquename(struct ListBase *list,
void *vlink,
const char *defname,
char delim,
int name_offset,
- size_t len);
+ size_t name_len);
#ifdef __cplusplus
}
diff --git a/source/blender/blenlib/BLI_task.h b/source/blender/blenlib/BLI_task.h
index 53ac5f7047b..a67de2e2910 100644
--- a/source/blender/blenlib/BLI_task.h
+++ b/source/blender/blenlib/BLI_task.h
@@ -35,20 +35,24 @@ extern "C" {
struct BLI_mempool;
-/* Task Scheduler
+/* -------------------------------------------------------------------- */
+/** \name Task Scheduler
*
- * Central scheduler that holds running threads ready to execute tasks. A single
- * queue holds the task from all pools.
+ * Central scheduler that holds running threads ready to execute tasks.
+ * A single queue holds the task from all pools.
*
- * Init/exit must be called before/after any task pools are created/freed, and
- * must be called from the main threads. All other scheduler and pool functions
- * are thread-safe. */
+ * Initialize/exit must be called before/after any task pools are created/freed, and must
+ * be called from the main threads. All other scheduler and pool functions are thread-safe.
+ * \{ */
void BLI_task_scheduler_init(void);
void BLI_task_scheduler_exit(void);
int BLI_task_scheduler_num_threads(void);
-/* Task Pool
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Task Pool
*
* Pool of tasks that will be executed by the central task scheduler. For each
* pool, we can wait for all tasks to be done, or cancel them before they are
@@ -60,7 +64,7 @@ int BLI_task_scheduler_num_threads(void);
* pool with smaller tasks. When other threads are busy they will continue
* working on their own tasks, if not they will join in, no new threads will
* be launched.
- */
+ * \{ */
typedef enum eTaskPriority {
TASK_PRIORITY_LOW,
@@ -71,25 +75,34 @@ typedef struct TaskPool TaskPool;
typedef void (*TaskRunFunction)(TaskPool *__restrict pool, void *taskdata);
typedef void (*TaskFreeFunction)(TaskPool *__restrict pool, void *taskdata);
-/* Regular task pool that immediately starts executing tasks as soon as they
- * are pushed, either on the current or another thread. */
+/**
+ * Regular task pool that immediately starts executing tasks as soon as they
+ * are pushed, either on the current or another thread.
+ */
TaskPool *BLI_task_pool_create(void *userdata, eTaskPriority priority);
-/* Background: always run tasks in a background thread, never immediately
- * execute them. For running background jobs. */
+/**
+ * Background: always run tasks in a background thread, never immediately
+ * execute them. For running background jobs.
+ */
TaskPool *BLI_task_pool_create_background(void *userdata, eTaskPriority priority);
-/* Background Serial: run tasks one after the other in the background,
- * without parallelization between the tasks. */
+/**
+ * Background Serial: run tasks one after the other in the background,
+ * without parallelization between the tasks.
+ */
TaskPool *BLI_task_pool_create_background_serial(void *userdata, eTaskPriority priority);
-/* Suspended: don't execute tasks until work_and_wait is called. This is slower
+/**
+ * Suspended: don't execute tasks until work_and_wait is called. This is slower
* as threads can't immediately start working. But it can be used if the data
- * structures the threads operate on are not fully initialized until all tasks
- * are created. */
+ * structures the threads operate on are not fully initialized until all tasks are created.
+ */
TaskPool *BLI_task_pool_create_suspended(void *userdata, eTaskPriority priority);
-/* No threads: immediately executes tasks on the same thread. For debugging. */
+/**
+ * No threads: immediately executes tasks on the same thread. For debugging.
+ */
TaskPool *BLI_task_pool_create_no_threads(void *userdata);
void BLI_task_pool_free(TaskPool *pool);
@@ -100,28 +113,45 @@ void BLI_task_pool_push(TaskPool *pool,
bool free_taskdata,
TaskFreeFunction freedata);
-/* work and wait until all tasks are done */
+/**
+ * Work and wait until all tasks are done.
+ */
void BLI_task_pool_work_and_wait(TaskPool *pool);
-/* cancel all tasks, keep worker threads running */
+/**
+ * Cancel all tasks, keep worker threads running.
+ */
void BLI_task_pool_cancel(TaskPool *pool);
-/* for worker threads, test if current task pool canceled. this function may
+/**
+ * For worker threads, test if current task pool canceled. this function may
* only be called from worker threads and pool must be the task pool that the
- * thread is currently executing a task from. */
+ * thread is currently executing a task from.
+ */
bool BLI_task_pool_current_canceled(TaskPool *pool);
-/* optional userdata pointer to pass along to run function */
+/**
+ * Optional `userdata` pointer to pass along to run function.
+ */
void *BLI_task_pool_user_data(TaskPool *pool);
-/* optional mutex to use from run function */
+/**
+ * Optional mutex to use from run function.
+ */
ThreadMutex *BLI_task_pool_user_mutex(TaskPool *pool);
-/* Parallel for routines */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Parallel for Routines
+ * \{ */
-/* Per-thread specific data passed to the callback. */
+/**
+ * Per-thread specific data passed to the callback.
+ */
typedef struct TaskParallelTLS {
- /* Copy of user-specifier chunk, which is copied from original chunk to all
- * worker threads. This is similar to OpenMP's firstprivate.
+ /**
+ * Copy of user-specifier chunk, which is copied from original chunk to all worker threads.
+ * This is similar to OpenMP's `firstprivate`.
*/
void *userdata_chunk;
} TaskParallelTLS;
@@ -186,7 +216,8 @@ void BLI_task_parallel_range(const int start,
TaskParallelRangeFunc func,
const TaskParallelSettings *settings);
-/* This data is shared between all tasks, its access needs thread lock or similar protection.
+/**
+ * This data is shared between all tasks, its access needs thread lock or similar protection.
*/
typedef struct TaskParallelIteratorStateShared {
/* Maximum amount of items to acquire at once. */
@@ -214,6 +245,20 @@ typedef void (*TaskParallelIteratorFunc)(void *__restrict userdata,
int index,
const TaskParallelTLS *__restrict tls);
+/**
+ * This function allows to parallelize for loops using a generic iterator.
+ *
+ * \param userdata: Common userdata passed to all instances of \a func.
+ * \param iter_func: Callback function used to generate chunks of items.
+ * \param init_item: The initial item, if necessary (may be NULL if unused).
+ * \param init_index: The initial index.
+ * \param tot_items: The total amount of items to iterate over
+ * (if unknown, set it to a negative number).
+ * \param func: Callback function.
+ * \param settings: See public API doc of TaskParallelSettings for description of all settings.
+ *
+ * \note Static scheduling is only available when \a tot_items is >= 0.
+ */
void BLI_task_parallel_iterator(void *userdata,
TaskParallelIteratorIterFunc iter_func,
void *init_item,
@@ -222,6 +267,17 @@ void BLI_task_parallel_iterator(void *userdata,
TaskParallelIteratorFunc func,
const TaskParallelSettings *settings);
+/**
+ * This function allows to parallelize for loops over ListBase items.
+ *
+ * \param listbase: The double linked list to loop over.
+ * \param userdata: Common userdata passed to all instances of \a func.
+ * \param func: Callback function.
+ * \param settings: See public API doc of ParallelRangeSettings for description of all settings.
+ *
+ * \note There is no static scheduling here,
+ * since it would need another full loop over items to count them.
+ */
void BLI_task_parallel_listbase(struct ListBase *listbase,
void *userdata,
TaskParallelIteratorFunc func,
@@ -232,6 +288,16 @@ typedef struct MempoolIterData MempoolIterData;
typedef void (*TaskParallelMempoolFunc)(void *userdata,
MempoolIterData *iter,
const TaskParallelTLS *__restrict tls);
+/**
+ * This function allows to parallelize for loops over Mempool items.
+ *
+ * \param mempool: The iterable BLI_mempool to loop over.
+ * \param userdata: Common userdata passed to all instances of \a func.
+ * \param func: Callback function.
+ * \param settings: See public API doc of TaskParallelSettings for description of all settings.
+ *
+ * \note There is no static scheduling here.
+ */
void BLI_task_parallel_mempool(struct BLI_mempool *mempool,
void *userdata,
TaskParallelMempoolFunc func,
@@ -252,14 +318,21 @@ BLI_INLINE void BLI_parallel_mempool_settings_defaults(TaskParallelSettings *set
settings->use_threading = true;
}
-/* Don't use this, store any thread specific data in tls->userdata_chunk instead.
- * Only here for code to be removed. */
+/**
+ * Don't use this, store any thread specific data in `tls->userdata_chunk` instead.
+ * Only here for code to be removed.
+ */
int BLI_task_parallel_thread_id(const TaskParallelTLS *tls);
-/* Task Graph Scheduling */
-/* Task Graphs can be used to create a forest of directional trees and schedule work to any tree.
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Task Graph Scheduling
+ *
+ * Task Graphs can be used to create a forest of directional trees and schedule work to any tree.
* The nodes in the graph can be run in separate threads.
*
+ * \code{.unparsed}
* +---- [root] ----+
* | |
* v v
@@ -267,55 +340,61 @@ int BLI_task_parallel_thread_id(const TaskParallelTLS *tls);
* | |
* v v
* [node_3] [node_4]
+ * \endcode
*
- * TaskGraph *task_graph = BLI_task_graph_create();
- * TaskNode *root = BLI_task_graph_node_create(task_graph, root_exec, NULL, NULL);
- * TaskNode *node_1 = BLI_task_graph_node_create(task_graph, node_exec, NULL, NULL);
- * TaskNode *node_2 = BLI_task_graph_node_create(task_graph, node_exec, NULL, NULL);
- * TaskNode *node_3 = BLI_task_graph_node_create(task_graph, node_exec, NULL, NULL);
- * TaskNode *node_4 = BLI_task_graph_node_create(task_graph, node_exec, NULL, NULL);
+ * \code{.c}
+ * TaskGraph *task_graph = BLI_task_graph_create();
+ * TaskNode *root = BLI_task_graph_node_create(task_graph, root_exec, NULL, NULL);
+ * TaskNode *node_1 = BLI_task_graph_node_create(task_graph, node_exec, NULL, NULL);
+ * TaskNode *node_2 = BLI_task_graph_node_create(task_graph, node_exec, NULL, NULL);
+ * TaskNode *node_3 = BLI_task_graph_node_create(task_graph, node_exec, NULL, NULL);
+ * TaskNode *node_4 = BLI_task_graph_node_create(task_graph, node_exec, NULL, NULL);
*
- * BLI_task_graph_edge_create(root, node_1);
- * BLI_task_graph_edge_create(root, node_2);
- * BLI_task_graph_edge_create(node_2, node_3);
- * BLI_task_graph_edge_create(node_2, node_4);
+ * BLI_task_graph_edge_create(root, node_1);
+ * BLI_task_graph_edge_create(root, node_2);
+ * BLI_task_graph_edge_create(node_2, node_3);
+ * BLI_task_graph_edge_create(node_2, node_4);
+ * \endcode
*
* Any node can be triggered to start a chain of tasks. Normally you would trigger a root node but
* it is supported to start the chain of tasks anywhere in the forest or tree. When a node
* completes, the execution flow is forwarded via the created edges.
* When a child node has multiple parents the child node will be triggered once for each parent.
*
- * BLI_task_graph_node_push_work(root);
+ * `BLI_task_graph_node_push_work(root);`
*
* In this example After `root` is finished, `node_1` and `node_2` will be started.
* Only after `node_2` is finished `node_3` and `node_4` will be started.
*
* After scheduling work we need to wait until all the tasks have been finished.
*
- * BLI_task_graph_work_and_wait();
+ * `BLI_task_graph_work_and_wait();`
*
* When finished you can clean up all the resources by freeing the task_graph. Nodes are owned by
* the graph and are freed task_data will only be freed if a free_func was given.
*
- * BLI_task_graph_free(task_graph);
+ * `BLI_task_graph_free(task_graph);`
*
* Work can enter a tree on any node. Normally this would be the root_node.
* A `task_graph` can be reused, but the caller needs to make sure the task_data is reset.
*
- * ** Task-Data **
+ * Task-Data
+ * ---------
*
* Typically you want give a task data to work on.
* Task data can be shared with other nodes, but be careful not to free the data multiple times.
- * Task data is freed when calling `BLI_task_graph_free`.
- *
- * MyData *task_data = MEM_callocN(sizeof(MyData), __func__);
- * TaskNode *root = BLI_task_graph_node_create(task_graph, root_exec, task_data, MEM_freeN);
- * TaskNode *node_1 = BLI_task_graph_node_create(task_graph, node_exec, task_data, NULL);
- * TaskNode *node_2 = BLI_task_graph_node_create(task_graph, node_exec, task_data, NULL);
- * TaskNode *node_3 = BLI_task_graph_node_create(task_graph, node_exec, task_data, NULL);
- * TaskNode *node_4 = BLI_task_graph_node_create(task_graph, node_exec, task_data, NULL);
+ * Task data is freed when calling #BLI_task_graph_free.
*
- */
+ * \code{.c}
+ * MyData *task_data = MEM_callocN(sizeof(MyData), __func__);
+ * TaskNode *root = BLI_task_graph_node_create(task_graph, root_exec, task_data, MEM_freeN);
+ * TaskNode *node_1 = BLI_task_graph_node_create(task_graph, node_exec, task_data, NULL);
+ * TaskNode *node_2 = BLI_task_graph_node_create(task_graph, node_exec, task_data, NULL);
+ * TaskNode *node_3 = BLI_task_graph_node_create(task_graph, node_exec, task_data, NULL);
+ * TaskNode *node_4 = BLI_task_graph_node_create(task_graph, node_exec, task_data, NULL);
+ * \endcode
+ * \{ */
+
struct TaskGraph;
struct TaskNode;
@@ -332,7 +411,10 @@ struct TaskNode *BLI_task_graph_node_create(struct TaskGraph *task_graph,
bool BLI_task_graph_node_push_work(struct TaskNode *task_node);
void BLI_task_graph_edge_create(struct TaskNode *from_node, struct TaskNode *to_node);
-/* Task Isolation
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Task Isolation
*
* Task isolation helps avoid unexpected task scheduling decisions that can lead to bugs if wrong
* assumptions were made. Typically that happens when doing "nested threading", i.e. one thread
@@ -359,9 +441,12 @@ void BLI_task_graph_edge_create(struct TaskNode *from_node, struct TaskNode *to_
* multiple threads, another thread will typically run the task and avoid the deadlock. However, if
* this situation happens on all threads at the same time, all threads will deadlock. This happened
* in T88598.
- */
+ * \{ */
+
void BLI_task_isolate(void (*func)(void *userdata), void *userdata);
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_task.hh b/source/blender/blenlib/BLI_task.hh
index da7309837c8..84d5cd39bb4 100644
--- a/source/blender/blenlib/BLI_task.hh
+++ b/source/blender/blenlib/BLI_task.hh
@@ -67,14 +67,19 @@ void parallel_for(IndexRange range, int64_t grain_size, const Function &function
return;
}
#ifdef WITH_TBB
- tbb::parallel_for(tbb::blocked_range<int64_t>(range.first(), range.one_after_last(), grain_size),
- [&](const tbb::blocked_range<int64_t> &subrange) {
- function(IndexRange(subrange.begin(), subrange.size()));
- });
+ /* Invoking tbb for small workloads has a large overhead. */
+ if (range.size() >= grain_size) {
+ tbb::parallel_for(
+ tbb::blocked_range<int64_t>(range.first(), range.one_after_last(), grain_size),
+ [&](const tbb::blocked_range<int64_t> &subrange) {
+ function(IndexRange(subrange.begin(), subrange.size()));
+ });
+ return;
+ }
#else
UNUSED_VARS(grain_size);
- function(range);
#endif
+ function(range);
}
template<typename Value, typename Function, typename Reduction>
diff --git a/source/blender/blenlib/BLI_threads.h b/source/blender/blenlib/BLI_threads.h
index 4f71e3aa6e4..6e60430ea38 100644
--- a/source/blender/blenlib/BLI_threads.h
+++ b/source/blender/blenlib/BLI_threads.h
@@ -38,12 +38,24 @@ struct ListBase;
/* Threading API */
-/* This is run once at startup. */
+/**
+ * This is run once at startup.
+ */
void BLI_threadapi_init(void);
void BLI_threadapi_exit(void);
+/**
+ * \param tot: When 0 only initializes malloc mutex in a safe way (see sequence.c)
+ * problem otherwise: scene render will kill of the mutex!
+ */
void BLI_threadpool_init(struct ListBase *threadbase, void *(*do_thread)(void *), int tot);
+/**
+ * Amount of available threads.
+ */
int BLI_available_threads(struct ListBase *threadbase);
+/**
+ * Returns thread number, for sample patterns or threadsafe tables.
+ */
int BLI_threadpool_available_thread_index(struct ListBase *threadbase);
void BLI_threadpool_insert(struct ListBase *threadbase, void *callerdata);
void BLI_threadpool_remove(struct ListBase *threadbase, void *callerdata);
@@ -54,7 +66,10 @@ int BLI_thread_is_main(void);
/* System Information */
-int BLI_system_thread_count(void); /* gets the number of threads the system can make use of */
+/**
+ * \return the number of threads the system can make use of.
+ */
+int BLI_system_thread_count(void);
void BLI_system_num_threads_override_set(int num);
int BLI_system_num_threads_override_get(void);
@@ -198,6 +213,7 @@ void BLI_thread_queue_nowait(ThreadQueue *queue);
/* **** Special functions to help performance on crazy NUMA setups. **** */
/* Make sure process/thread is using NUMA node with fast memory access. */
+
void BLI_thread_put_process_on_fast_node(void);
void BLI_thread_put_thread_on_fast_node(void);
diff --git a/source/blender/blenlib/BLI_timecode.h b/source/blender/blenlib/BLI_timecode.h
index 5dfd9089598..4eec8aef245 100644
--- a/source/blender/blenlib/BLI_timecode.h
+++ b/source/blender/blenlib/BLI_timecode.h
@@ -29,17 +29,49 @@
extern "C" {
#endif
+/**
+ * Generate time-code/frame number string and store in \a str
+ *
+ * \param str: destination string
+ * \param maxncpy: maximum number of characters to copy `sizeof(str)`
+ * \param brevity_level: special setting for #View2D grid drawing,
+ * used to specify how detailed we need to be
+ * \param time_seconds: time total time in seconds
+ * \param fps: frames per second, typically from the #FPS macro
+ * \param timecode_style: enum from #eTimecodeStyles
+ * \return length of \a str
+ */
size_t BLI_timecode_string_from_time(char *str,
const size_t maxncpy,
const int brevity_level,
const float time_seconds,
- const double scene_fps,
+ const double fps,
const short timecode_style) ATTR_NONNULL();
+/**
+ * Generate time string and store in \a str
+ *
+ * \param str: destination string
+ * \param maxncpy: maximum number of characters to copy `sizeof(str)`
+ * \param time_seconds: time total time in seconds
+ * \return length of \a str
+ */
size_t BLI_timecode_string_from_time_simple(char *str,
const size_t maxncpy,
const double time_seconds) ATTR_NONNULL();
+/**
+ * Generate time string and store in \a str
+ *
+ * \param str: destination string
+ * \param maxncpy: maximum number of characters to copy `sizeof(str)`
+ * \param brevity_level: special setting for #View2D grid drawing,
+ * used to specify how detailed we need to be
+ * \param time_seconds: time total time in seconds
+ * \return length of \a str
+ *
+ * \note in some cases this is used to print non-seconds values.
+ */
size_t BLI_timecode_string_from_time_seconds(char *str,
const size_t maxncpy,
const int brevity_level,
diff --git a/source/blender/blenlib/BLI_utildefines.h b/source/blender/blenlib/BLI_utildefines.h
index dec8acd7549..1b9457496ef 100644
--- a/source/blender/blenlib/BLI_utildefines.h
+++ b/source/blender/blenlib/BLI_utildefines.h
@@ -635,6 +635,9 @@ extern "C" {
/* defined
* in memory_utils.c for now. I do not know where we should put it actually... */
#ifndef __BLI_MEMORY_UTILS_H__
+/**
+ * Check if memory is zeroed, as with `memset(arr, 0, arr_size)`.
+ */
extern bool BLI_memory_is_zero(const void *arr, const size_t arr_size);
#endif
diff --git a/source/blender/blenlib/BLI_uvproject.h b/source/blender/blenlib/BLI_uvproject.h
index 6028d95bda0..c1cc1cdbb51 100644
--- a/source/blender/blenlib/BLI_uvproject.h
+++ b/source/blender/blenlib/BLI_uvproject.h
@@ -26,16 +26,26 @@ extern "C" {
struct Object;
struct ProjCameraInfo;
-/* create uv info from the camera, needs to be freed */
+/**
+ * Create UV info from the camera, needs to be freed.
+ *
+ * \param rotmat: can be `obedit->obmat` when uv project is used.
+ * \param winx, winy: can be from `scene->r.xsch / ysch`.
+ */
struct ProjCameraInfo *BLI_uvproject_camera_info(struct Object *ob,
float rotmat[4][4],
float winx,
float winy);
-/* apply uv from uvinfo (camera) */
+/**
+ * Apply UV from uvinfo (camera).
+ */
void BLI_uvproject_from_camera(float target[2], float source[3], struct ProjCameraInfo *uci);
-/* apply uv from perspective matrix */
+/**
+ * Apply uv from perspective matrix.
+ * \param persmat: Can be `rv3d->persmat`.
+ */
void BLI_uvproject_from_view(float target[2],
float source[3],
float persmat[4][4],
@@ -43,10 +53,14 @@ void BLI_uvproject_from_view(float target[2],
float winx,
float winy);
-/* apply ortho uv's */
+/**
+ * Apply orthographic UV's.
+ */
void BLI_uvproject_from_view_ortho(float target[2], float source[3], const float rotmat[4][4]);
-/* so we can adjust scale with keeping the struct private */
+/**
+ * So we can adjust scale with keeping the struct private.
+ */
void BLI_uvproject_camera_info_scale(struct ProjCameraInfo *uci, float scale_x, float scale_y);
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_virtual_array.hh b/source/blender/blenlib/BLI_virtual_array.hh
index d9f83d3e1cb..5103ac4b668 100644
--- a/source/blender/blenlib/BLI_virtual_array.hh
+++ b/source/blender/blenlib/BLI_virtual_array.hh
@@ -183,6 +183,15 @@ template<typename T> class VArrayImpl {
* own anything can overwrite this with false. */
return true;
}
+
+ /**
+ * Return true when the other virtual array should be considered to be the same, e.g. because it
+ * shares the same underlying memory.
+ */
+ virtual bool is_same(const VArrayImpl<T> &UNUSED(other)) const
+ {
+ return false;
+ }
};
/* Similar to #VArrayImpl, but adds methods that allow modifying the referenced elements. */
@@ -223,69 +232,21 @@ template<typename T> class VMutableArrayImpl : public VArrayImpl<T> {
};
/**
- * A virtual array implementation for a span. Methods in this class are final so that it can be
- * devirtualized by the compiler in some cases (e.g. when #devirtualize_varray is used).
- */
-template<typename T> class VArrayImpl_For_Span : public VArrayImpl<T> {
- protected:
- const T *data_ = nullptr;
-
- public:
- VArrayImpl_For_Span(const Span<T> data) : VArrayImpl<T>(data.size()), data_(data.data())
- {
- }
-
- protected:
- VArrayImpl_For_Span(const int64_t size) : VArrayImpl<T>(size)
- {
- }
-
- T get(const int64_t index) const final
- {
- return data_[index];
- }
-
- bool is_span() const final
- {
- return true;
- }
-
- Span<T> get_internal_span() const final
- {
- return Span<T>(data_, this->size_);
- }
-};
-
-/**
- * A version of #VArrayImpl_For_Span that can not be subclassed. This allows safely overwriting the
- * #may_have_ownership method.
- */
-template<typename T> class VArrayImpl_For_Span_final final : public VArrayImpl_For_Span<T> {
- public:
- using VArrayImpl_For_Span<T>::VArrayImpl_For_Span;
-
- private:
- bool may_have_ownership() const override
- {
- return false;
- }
-};
-
-/**
- * Like #VArrayImpl_For_Span but for mutable data.
+ * A virtual array implementation that references that wraps a span. This implementation is used by
+ * mutable and immutable spans to avoid code duplication.
*/
-template<typename T> class VMutableArrayImpl_For_MutableSpan : public VMutableArrayImpl<T> {
+template<typename T> class VArrayImpl_For_Span : public VMutableArrayImpl<T> {
protected:
T *data_ = nullptr;
public:
- VMutableArrayImpl_For_MutableSpan(const MutableSpan<T> data)
+ VArrayImpl_For_Span(const MutableSpan<T> data)
: VMutableArrayImpl<T>(data.size()), data_(data.data())
{
}
protected:
- VMutableArrayImpl_For_MutableSpan(const int64_t size) : VMutableArrayImpl<T>(size)
+ VArrayImpl_For_Span(const int64_t size) : VMutableArrayImpl<T>(size)
{
}
@@ -308,15 +269,27 @@ template<typename T> class VMutableArrayImpl_For_MutableSpan : public VMutableAr
{
return Span<T>(data_, this->size_);
}
+
+ bool is_same(const VArrayImpl<T> &other) const final
+ {
+ if (other.size() != this->size_) {
+ return false;
+ }
+ if (!other.is_span()) {
+ return false;
+ }
+ const Span<T> other_span = other.get_internal_span();
+ return data_ == other_span.data();
+ }
};
/**
- * Like #VArrayImpl_For_Span_final but for mutable data.
+ * A version of #VArrayImpl_For_Span that can not be subclassed. This allows safely overwriting the
+ * #may_have_ownership method.
*/
-template<typename T>
-class VMutableArrayImpl_For_MutableSpan_final final : public VMutableArrayImpl_For_MutableSpan<T> {
+template<typename T> class VArrayImpl_For_Span_final final : public VArrayImpl_For_Span<T> {
public:
- using VMutableArrayImpl_For_MutableSpan<T>::VMutableArrayImpl_For_MutableSpan;
+ using VArrayImpl_For_Span<T>::VArrayImpl_For_Span;
private:
bool may_have_ownership() const override
@@ -340,7 +313,7 @@ class VArrayImpl_For_ArrayContainer : public VArrayImpl_For_Span<T> {
VArrayImpl_For_ArrayContainer(Container container)
: VArrayImpl_For_Span<T>((int64_t)container.size()), container_(std::move(container))
{
- this->data_ = container_.data();
+ this->data_ = const_cast<T *>(container_.data());
}
};
@@ -422,58 +395,26 @@ template<typename T, typename GetFunc> class VArrayImpl_For_Func final : public
/**
* \note: This is `final` so that #may_have_ownership can be implemented reliably.
*/
-template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)>
-class VArrayImpl_For_DerivedSpan final : public VArrayImpl<ElemT> {
- private:
- const StructT *data_;
-
- public:
- VArrayImpl_For_DerivedSpan(const Span<StructT> data)
- : VArrayImpl<ElemT>(data.size()), data_(data.data())
- {
- }
-
- private:
- ElemT get(const int64_t index) const override
- {
- return GetFunc(data_[index]);
- }
-
- void materialize(IndexMask mask, MutableSpan<ElemT> r_span) const override
- {
- ElemT *dst = r_span.data();
- mask.foreach_index([&](const int64_t i) { dst[i] = GetFunc(data_[i]); });
- }
-
- void materialize_to_uninitialized(IndexMask mask, MutableSpan<ElemT> r_span) const override
- {
- ElemT *dst = r_span.data();
- mask.foreach_index([&](const int64_t i) { new (dst + i) ElemT(GetFunc(data_[i])); });
- }
-
- bool may_have_ownership() const override
- {
- return false;
- }
-};
-
-/**
- * \note: This is `final` so that #may_have_ownership can be implemented reliably.
- */
template<typename StructT,
typename ElemT,
ElemT (*GetFunc)(const StructT &),
- void (*SetFunc)(StructT &, ElemT)>
-class VMutableArrayImpl_For_DerivedSpan final : public VMutableArrayImpl<ElemT> {
+ void (*SetFunc)(StructT &, ElemT) = nullptr>
+class VArrayImpl_For_DerivedSpan final : public VMutableArrayImpl<ElemT> {
private:
StructT *data_;
public:
- VMutableArrayImpl_For_DerivedSpan(const MutableSpan<StructT> data)
+ VArrayImpl_For_DerivedSpan(const MutableSpan<StructT> data)
: VMutableArrayImpl<ElemT>(data.size()), data_(data.data())
{
}
+ template<typename OtherStructT,
+ typename OtherElemT,
+ OtherElemT (*OtherGetFunc)(const OtherStructT &),
+ void (*OtherSetFunc)(OtherStructT &, OtherElemT)>
+ friend class VArrayImpl_For_DerivedSpan;
+
private:
ElemT get(const int64_t index) const override
{
@@ -501,6 +442,23 @@ class VMutableArrayImpl_For_DerivedSpan final : public VMutableArrayImpl<ElemT>
{
return false;
}
+
+ bool is_same(const VArrayImpl<ElemT> &other) const override
+ {
+ if (other.size() != this->size_) {
+ return false;
+ }
+ if (const VArrayImpl_For_DerivedSpan<StructT, ElemT, GetFunc> *other_typed =
+ dynamic_cast<const VArrayImpl_For_DerivedSpan<StructT, ElemT, GetFunc> *>(&other)) {
+ return other_typed->data_ == data_;
+ }
+ if (const VArrayImpl_For_DerivedSpan<StructT, ElemT, GetFunc, SetFunc> *other_typed =
+ dynamic_cast<const VArrayImpl_For_DerivedSpan<StructT, ElemT, GetFunc, SetFunc> *>(
+ &other)) {
+ return other_typed->data_ == data_;
+ }
+ return false;
+ }
};
namespace detail {
@@ -620,7 +578,7 @@ template<typename T> class VArrayCommon {
/* Make sure we are actually constructing a #VArrayImpl. */
static_assert(std::is_base_of_v<VArrayImpl<T>, ImplT>);
if constexpr (std::is_copy_constructible_v<ImplT> && Storage::template is_inline_v<ImplT>) {
- /* Only inline the implementatiton when it is copyable and when it fits into the inline
+ /* Only inline the implementation when it is copyable and when it fits into the inline
* buffer of the storage. */
impl_ = &storage_.template emplace<ImplT>(std::forward<Args>(args)...);
}
@@ -719,9 +677,6 @@ template<typename T> class VArrayCommon {
bool is_span() const
{
BLI_assert(*this);
- if (this->is_empty()) {
- return true;
- }
return impl_->is_span();
}
@@ -742,9 +697,6 @@ template<typename T> class VArrayCommon {
bool is_single() const
{
BLI_assert(*this);
- if (impl_->size() == 1) {
- return true;
- }
return impl_->is_single();
}
@@ -761,6 +713,25 @@ template<typename T> class VArrayCommon {
return impl_->get_internal_single();
}
+ /**
+ * Return true when the other virtual references the same underlying memory.
+ */
+ bool is_same(const VArrayCommon<T> &other) const
+ {
+ if (!*this || !other) {
+ return false;
+ }
+ /* Check in both directions in case one does not know how to compare to the other
+ * implementation. */
+ if (impl_->is_same(*other.impl_)) {
+ return true;
+ }
+ if (other.impl_->is_same(*impl_)) {
+ return true;
+ }
+ return false;
+ }
+
/** Copy the entire virtual array into a span. */
void materialize(MutableSpan<T> r_span) const
{
@@ -846,7 +817,10 @@ template<typename T> class VArray : public VArrayCommon<T> {
*/
static VArray ForSpan(Span<T> values)
{
- return VArray::For<VArrayImpl_For_Span_final<T>>(values);
+ /* Cast const away, because the virtual array implementation for const and non const spans is
+ * shared. */
+ MutableSpan<T> span{const_cast<T *>(values.data()), values.size()};
+ return VArray::For<VArrayImpl_For_Span_final<T>>(span);
}
/**
@@ -865,7 +839,10 @@ template<typename T> class VArray : public VArrayCommon<T> {
template<typename StructT, T (*GetFunc)(const StructT &)>
static VArray ForDerivedSpan(Span<StructT> values)
{
- return VArray::For<VArrayImpl_For_DerivedSpan<StructT, T, GetFunc>>(values);
+ /* Cast const away, because the virtual array implementation for const and non const derived
+ * spans is shared. */
+ MutableSpan<StructT> span{const_cast<StructT *>(values.data()), values.size()};
+ return VArray::For<VArrayImpl_For_DerivedSpan<StructT, T, GetFunc>>(span);
}
/**
@@ -925,7 +902,7 @@ template<typename T> class VMutableArray : public VArrayCommon<T> {
*/
static VMutableArray ForSpan(MutableSpan<T> values)
{
- return VMutableArray::For<VMutableArrayImpl_For_MutableSpan_final<T>>(values);
+ return VMutableArray::For<VArrayImpl_For_Span_final<T>>(values);
}
/**
@@ -935,8 +912,7 @@ template<typename T> class VMutableArray : public VArrayCommon<T> {
template<typename StructT, T (*GetFunc)(const StructT &), void (*SetFunc)(StructT &, T)>
static VMutableArray ForDerivedSpan(MutableSpan<StructT> values)
{
- return VMutableArray::For<VMutableArrayImpl_For_DerivedSpan<StructT, T, GetFunc, SetFunc>>(
- values);
+ return VMutableArray::For<VArrayImpl_For_DerivedSpan<StructT, T, GetFunc, SetFunc>>(values);
}
/** Convert to a #VArray by copying. */
@@ -1107,6 +1083,30 @@ template<typename T> class VMutableArray_Span final : public MutableSpan<T> {
}
};
+template<typename T> class SingleAsSpan {
+ private:
+ T value_;
+ int64_t size_;
+
+ public:
+ SingleAsSpan(T value, int64_t size) : value_(std::move(value)), size_(size)
+ {
+ BLI_assert(size_ >= 0);
+ }
+
+ SingleAsSpan(const VArray<T> &varray) : SingleAsSpan(varray.get_internal_single(), varray.size())
+ {
+ }
+
+ const T &operator[](const int64_t index) const
+ {
+ BLI_assert(index >= 0);
+ BLI_assert(index < size_);
+ UNUSED_VARS_NDEBUG(index);
+ return value_;
+ }
+};
+
/**
* Generate multiple versions of the given function optimized for different virtual arrays.
* One has to be careful with nesting multiple devirtualizations, because that results in an
@@ -1121,14 +1121,11 @@ inline void devirtualize_varray(const VArray<T> &varray, const Func &func, bool
/* Support disabling the devirtualization to simplify benchmarking. */
if (enable) {
if (varray.is_single()) {
- /* `VArrayImpl_For_Single` can be used for devirtualization, because it is declared `final`.
- */
- func(VArray<T>::ForSingle(varray.get_internal_single(), varray.size()));
+ func(SingleAsSpan<T>(varray));
return;
}
if (varray.is_span()) {
- /* `VArrayImpl_For_Span` can be used for devirtualization, because it is declared `final`. */
- func(VArray<T>::ForSpan(varray.get_internal_span()));
+ func(varray.get_internal_span());
return;
}
}
@@ -1153,23 +1150,19 @@ inline void devirtualize_varray2(const VArray<T1> &varray1,
const bool is_single1 = varray1.is_single();
const bool is_single2 = varray2.is_single();
if (is_span1 && is_span2) {
- func(VArray<T1>::ForSpan(varray1.get_internal_span()),
- VArray<T2>::ForSpan(varray2.get_internal_span()));
+ func(varray1.get_internal_span(), varray2.get_internal_span());
return;
}
if (is_span1 && is_single2) {
- func(VArray<T1>::ForSpan(varray1.get_internal_span()),
- VArray<T2>::ForSingle(varray2.get_internal_single(), varray2.size()));
+ func(varray1.get_internal_span(), SingleAsSpan(varray2));
return;
}
if (is_single1 && is_span2) {
- func(VArray<T1>::ForSingle(varray1.get_internal_single(), varray1.size()),
- VArray<T2>::ForSpan(varray2.get_internal_span()));
+ func(SingleAsSpan(varray1), varray2.get_internal_span());
return;
}
if (is_single1 && is_single2) {
- func(VArray<T1>::ForSingle(varray1.get_internal_single(), varray1.size()),
- VArray<T2>::ForSingle(varray2.get_internal_single(), varray2.size()));
+ func(SingleAsSpan(varray1), SingleAsSpan(varray2));
return;
}
}
diff --git a/source/blender/blenlib/BLI_voxel.h b/source/blender/blenlib/BLI_voxel.h
index eb84f0a27ee..83e4bdbdc10 100644
--- a/source/blender/blenlib/BLI_voxel.h
+++ b/source/blender/blenlib/BLI_voxel.h
@@ -27,13 +27,13 @@
extern "C" {
#endif
-/** Find the index number of a voxel, given x/y/z integer coords and resolution vector. */
-
+/** Calculate the index number of a voxel, given x/y/z integer coords and resolution vector. */
#define BLI_VOXEL_INDEX(x, y, z, res) \
((int64_t)(x) + (int64_t)(y) * (int64_t)(res)[0] + \
(int64_t)(z) * (int64_t)(res)[0] * (int64_t)(res)[1])
-/* all input coordinates must be in bounding box 0.0 - 1.0 */
+/* All input coordinates must be in bounding box 0.0 - 1.0. */
+
float BLI_voxel_sample_nearest(const float *data, const int res[3], const float co[3]);
float BLI_voxel_sample_trilinear(const float *data, const int res[3], const float co[3]);
float BLI_voxel_sample_triquadratic(const float *data, const int res[3], const float co[3]);
diff --git a/source/blender/blenlib/intern/BLI_array.c b/source/blender/blenlib/intern/BLI_array.c
index 7a9cf416d91..f4d60a9e047 100644
--- a/source/blender/blenlib/intern/BLI_array.c
+++ b/source/blender/blenlib/intern/BLI_array.c
@@ -54,11 +54,6 @@
#include "MEM_guardedalloc.h"
-/**
- * This function is only to be called via macros.
- *
- * \note The caller must adjust \a arr_len
- */
void _bli_array_grow_func(void **arr_p,
const void *arr_static,
const int sizeof_arr_p,
diff --git a/source/blender/blenlib/intern/BLI_assert.c b/source/blender/blenlib/intern/BLI_assert.c
index cebc6f8957f..e089ef149a0 100644
--- a/source/blender/blenlib/intern/BLI_assert.c
+++ b/source/blender/blenlib/intern/BLI_assert.c
@@ -49,14 +49,13 @@ void _BLI_assert_print_backtrace(void)
#endif
}
-/**
- * Wrap to remove 'noreturn' attribute since this suppresses missing return statements,
- * allowing changes to debug builds to accidentally to break release builds.
- *
- * For example `BLI_assert(0);` at the end of a function that returns a value,
- * will hide that it's missing a return.
- */
void _BLI_assert_abort(void)
{
+ /* Wrap to remove 'noreturn' attribute since this suppresses missing return statements,
+ * allowing changes to debug builds to accidentally to break release builds.
+ *
+ * For example `BLI_assert(0);` at the end of a function that returns a value,
+ * will hide that it's missing a return. */
+
abort();
}
diff --git a/source/blender/blenlib/intern/BLI_dynstr.c b/source/blender/blenlib/intern/BLI_dynstr.c
index 8f7f722c71b..262d112d914 100644
--- a/source/blender/blenlib/intern/BLI_dynstr.c
+++ b/source/blender/blenlib/intern/BLI_dynstr.c
@@ -63,11 +63,6 @@ struct DynStr {
/***/
-/**
- * Create a new DynStr.
- *
- * \return Pointer to a new DynStr.
- */
DynStr *BLI_dynstr_new(void)
{
DynStr *ds = MEM_mallocN(sizeof(*ds), "DynStr");
@@ -78,11 +73,6 @@ DynStr *BLI_dynstr_new(void)
return ds;
}
-/**
- * Create a new DynStr.
- *
- * \return Pointer to a new DynStr.
- */
DynStr *BLI_dynstr_new_memarena(void)
{
DynStr *ds = MEM_mallocN(sizeof(*ds), "DynStr");
@@ -98,12 +88,6 @@ BLI_INLINE void *dynstr_alloc(DynStr *__restrict ds, size_t size)
return ds->memarena ? BLI_memarena_alloc(ds->memarena, size) : malloc(size);
}
-/**
- * Append a c-string to a DynStr.
- *
- * \param ds: The DynStr to append to.
- * \param cstr: The c-string to append.
- */
void BLI_dynstr_append(DynStr *__restrict ds, const char *cstr)
{
DynStrElem *dse = dynstr_alloc(ds, sizeof(*dse));
@@ -123,13 +107,6 @@ void BLI_dynstr_append(DynStr *__restrict ds, const char *cstr)
ds->curlen += cstrlen;
}
-/**
- * Append a length clamped c-string to a DynStr.
- *
- * \param ds: The DynStr to append to.
- * \param cstr: The c-string to append.
- * \param len: The maximum length of the c-string to copy.
- */
void BLI_dynstr_nappend(DynStr *__restrict ds, const char *cstr, int len)
{
DynStrElem *dse = dynstr_alloc(ds, sizeof(*dse));
@@ -209,12 +186,6 @@ void BLI_dynstr_vappendf(DynStr *__restrict ds, const char *__restrict format, v
}
}
-/**
- * Append a c-string to a DynStr, but with formatting like printf.
- *
- * \param ds: The DynStr to append to.
- * \param format: The printf format string to use.
- */
void BLI_dynstr_appendf(DynStr *__restrict ds, const char *__restrict format, ...)
{
va_list args;
@@ -277,25 +248,11 @@ void BLI_dynstr_appendf(DynStr *__restrict ds, const char *__restrict format, ..
}
}
-/**
- * Find the length of a DynStr.
- *
- * \param ds: The DynStr of interest.
- * \return The length of \a ds.
- */
int BLI_dynstr_get_len(const DynStr *ds)
{
return ds->curlen;
}
-/**
- * Get a DynStr's contents as a c-string.
- * The \a rets argument must be allocated to be at
- * least the size of `BLI_dynstr_get_len(ds) + 1`.
- *
- * \param ds: The DynStr of interest.
- * \param rets: The string to fill.
- */
void BLI_dynstr_get_cstring_ex(const DynStr *__restrict ds, char *__restrict rets)
{
char *s;
@@ -312,14 +269,6 @@ void BLI_dynstr_get_cstring_ex(const DynStr *__restrict ds, char *__restrict ret
rets[ds->curlen] = '\0';
}
-/**
- * Get a DynStr's contents as a c-string.
- * <i> The returned c-string should be freed
- * using MEM_freeN. </i>
- *
- * \param ds: The DynStr of interest.
- * \return The contents of \a ds as a c-string.
- */
char *BLI_dynstr_get_cstring(const DynStr *ds)
{
char *rets = MEM_mallocN(ds->curlen + 1, "dynstr_cstring");
@@ -327,11 +276,6 @@ char *BLI_dynstr_get_cstring(const DynStr *ds)
return rets;
}
-/**
- * Clear the DynStr
- *
- * \param ds: The DynStr to clear.
- */
void BLI_dynstr_clear(DynStr *ds)
{
if (ds->memarena) {
@@ -350,11 +294,6 @@ void BLI_dynstr_clear(DynStr *ds)
ds->curlen = 0;
}
-/**
- * Free the DynStr
- *
- * \param ds: The DynStr to free.
- */
void BLI_dynstr_free(DynStr *ds)
{
if (ds->memarena) {
diff --git a/source/blender/blenlib/intern/BLI_filelist.c b/source/blender/blenlib/intern/BLI_filelist.c
index f05dea46dc8..169f34f52c3 100644
--- a/source/blender/blenlib/intern/BLI_filelist.c
+++ b/source/blender/blenlib/intern/BLI_filelist.c
@@ -229,12 +229,6 @@ static void bli_builddir(struct BuildDirCtx *dir_ctx, const char *dirname)
}
}
-/**
- * Scans the contents of the directory named *dirname, and allocates and fills in an
- * array of entries describing them in *filelist.
- *
- * \return The length of filelist array.
- */
unsigned int BLI_filelist_dir_contents(const char *dirname, struct direntry **r_filelist)
{
struct BuildDirCtx dir_ctx;
@@ -256,9 +250,6 @@ unsigned int BLI_filelist_dir_contents(const char *dirname, struct direntry **r_
return dir_ctx.nrfiles;
}
-/**
- * Convert given entry's size into human-readable strings.
- */
void BLI_filelist_entry_size_to_string(const struct stat *st,
const uint64_t sz,
/* Used to change MB -> M, etc. - is that really useful? */
@@ -278,9 +269,6 @@ void BLI_filelist_entry_size_to_string(const struct stat *st,
#endif
}
-/**
- * Convert given entry's modes into human-readable strings.
- */
void BLI_filelist_entry_mode_to_string(const struct stat *st,
const bool UNUSED(compact),
char r_mode1[FILELIST_DIRENTRY_MODE_LEN],
@@ -328,9 +316,6 @@ void BLI_filelist_entry_mode_to_string(const struct stat *st,
#endif
}
-/**
- * Convert given entry's owner into human-readable strings.
- */
void BLI_filelist_entry_owner_to_string(const struct stat *st,
const bool UNUSED(compact),
char r_owner[FILELIST_DIRENTRY_OWNER_LEN])
@@ -349,12 +334,6 @@ void BLI_filelist_entry_owner_to_string(const struct stat *st,
#endif
}
-/**
- * Convert given entry's time into human-readable strings.
- *
- * \param r_is_today: optional, returns true if the date matches today's.
- * \param r_is_yesterday: optional, returns true if the date matches yesterday's.
- */
void BLI_filelist_entry_datetime_to_string(const struct stat *st,
const int64_t ts,
const bool compact,
@@ -417,9 +396,6 @@ void BLI_filelist_entry_datetime_to_string(const struct stat *st,
}
}
-/**
- * Deep-duplicate of a single direntry.
- */
void BLI_filelist_entry_duplicate(struct direntry *dst, const struct direntry *src)
{
*dst = *src;
@@ -431,9 +407,6 @@ void BLI_filelist_entry_duplicate(struct direntry *dst, const struct direntry *s
}
}
-/**
- * Deep-duplicate of a #direntry array including the array itself.
- */
void BLI_filelist_duplicate(struct direntry **dest_filelist,
struct direntry *const src_filelist,
const unsigned int nrentries)
@@ -448,9 +421,6 @@ void BLI_filelist_duplicate(struct direntry **dest_filelist,
}
}
-/**
- * frees storage for a single direntry, not the direntry itself.
- */
void BLI_filelist_entry_free(struct direntry *entry)
{
if (entry->relname) {
@@ -461,9 +431,6 @@ void BLI_filelist_entry_free(struct direntry *entry)
}
}
-/**
- * Frees storage for an array of #direntry, including the array itself.
- */
void BLI_filelist_free(struct direntry *filelist, const unsigned int nrentries)
{
unsigned int i;
diff --git a/source/blender/blenlib/intern/BLI_ghash.c b/source/blender/blenlib/intern/BLI_ghash.c
index 2c9285e418a..8e2a8ab7639 100644
--- a/source/blender/blenlib/intern/BLI_ghash.c
+++ b/source/blender/blenlib/intern/BLI_ghash.c
@@ -694,16 +694,6 @@ static GHash *ghash_copy(const GHash *gh, GHashKeyCopyFP keycopyfp, GHashValCopy
/** \name GHash Public API
* \{ */
-/**
- * Creates a new, empty GHash.
- *
- * \param hashfp: Hash callback.
- * \param cmpfp: Comparison callback.
- * \param info: Identifier string for the GHash.
- * \param nentries_reserve: Optionally reserve the number of members that the hash will hold.
- * Use this to avoid resizing buckets if the size is known or can be closely approximated.
- * \return An empty GHash.
- */
GHash *BLI_ghash_new_ex(GHashHashFP hashfp,
GHashCmpFP cmpfp,
const char *info,
@@ -712,72 +702,38 @@ GHash *BLI_ghash_new_ex(GHashHashFP hashfp,
return ghash_new(hashfp, cmpfp, info, nentries_reserve, 0);
}
-/**
- * Wraps #BLI_ghash_new_ex with zero entries reserved.
- */
GHash *BLI_ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info)
{
return BLI_ghash_new_ex(hashfp, cmpfp, info, 0);
}
-/**
- * Copy given GHash. Keys and values are also copied if relevant callback is provided,
- * else pointers remain the same.
- */
GHash *BLI_ghash_copy(const GHash *gh, GHashKeyCopyFP keycopyfp, GHashValCopyFP valcopyfp)
{
return ghash_copy(gh, keycopyfp, valcopyfp);
}
-/**
- * Reserve given amount of entries (resize \a gh accordingly if needed).
- */
void BLI_ghash_reserve(GHash *gh, const uint nentries_reserve)
{
ghash_buckets_expand(gh, nentries_reserve, true);
ghash_buckets_contract(gh, nentries_reserve, true, false);
}
-/**
- * \return size of the GHash.
- */
uint BLI_ghash_len(const GHash *gh)
{
return gh->nentries;
}
-/**
- * Insert a key/value pair into the \a gh.
- *
- * \note Duplicates are not checked,
- * the caller is expected to ensure elements are unique unless
- * GHASH_FLAG_ALLOW_DUPES flag is set.
- */
void BLI_ghash_insert(GHash *gh, void *key, void *val)
{
ghash_insert(gh, key, val);
}
-/**
- * Inserts a new value to a key that may already be in ghash.
- *
- * Avoids #BLI_ghash_remove, #BLI_ghash_insert calls (double lookups)
- *
- * \returns true if a new key has been added.
- */
bool BLI_ghash_reinsert(
GHash *gh, void *key, void *val, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
{
return ghash_insert_safe(gh, key, val, true, keyfreefp, valfreefp);
}
-/**
- * Replaces the key of an item in the \a gh.
- *
- * Use when a key is re-allocated or its memory location is changed.
- *
- * \returns The previous key or NULL if not found, the caller may free if it's needed.
- */
void *BLI_ghash_replace_key(GHash *gh, void *key)
{
const uint hash = ghash_keyhash(gh, key);
@@ -791,15 +747,6 @@ void *BLI_ghash_replace_key(GHash *gh, void *key)
return NULL;
}
-/**
- * Lookup the value of \a key in \a gh.
- *
- * \param key: The key to lookup.
- * \returns the value for \a key or NULL.
- *
- * \note When NULL is a valid value, use #BLI_ghash_lookup_p to differentiate a missing key
- * from a key with a NULL value. (Avoids calling #BLI_ghash_haskey before #BLI_ghash_lookup)
- */
void *BLI_ghash_lookup(const GHash *gh, const void *key)
{
GHashEntry *e = (GHashEntry *)ghash_lookup_entry(gh, key);
@@ -807,9 +754,6 @@ void *BLI_ghash_lookup(const GHash *gh, const void *key)
return e ? e->val : NULL;
}
-/**
- * A version of #BLI_ghash_lookup which accepts a fallback argument.
- */
void *BLI_ghash_lookup_default(const GHash *gh, const void *key, void *val_default)
{
GHashEntry *e = (GHashEntry *)ghash_lookup_entry(gh, key);
@@ -817,16 +761,6 @@ void *BLI_ghash_lookup_default(const GHash *gh, const void *key, void *val_defau
return e ? e->val : val_default;
}
-/**
- * Lookup a pointer to the value of \a key in \a gh.
- *
- * \param key: The key to lookup.
- * \returns the pointer to value for \a key or NULL.
- *
- * \note This has 2 main benefits over #BLI_ghash_lookup.
- * - A NULL return always means that \a key isn't in \a gh.
- * - The value can be modified in-place without further function calls (faster).
- */
void **BLI_ghash_lookup_p(GHash *gh, const void *key)
{
GHashEntry *e = (GHashEntry *)ghash_lookup_entry(gh, key);
@@ -834,20 +768,6 @@ void **BLI_ghash_lookup_p(GHash *gh, const void *key)
return e ? &e->val : NULL;
}
-/**
- * Ensure \a key is exists in \a gh.
- *
- * This handles the common situation where the caller needs ensure a key is added to \a gh,
- * constructing a new value in the case the key isn't found.
- * Otherwise use the existing value.
- *
- * Such situations typically incur multiple lookups, however this function
- * avoids them by ensuring the key is added,
- * returning a pointer to the value so it can be used or initialized by the caller.
- *
- * \returns true when the value didn't need to be added.
- * (when false, the caller _must_ initialize the value).
- */
bool BLI_ghash_ensure_p(GHash *gh, void *key, void ***r_val)
{
const uint hash = ghash_keyhash(gh, key);
@@ -864,12 +784,6 @@ bool BLI_ghash_ensure_p(GHash *gh, void *key, void ***r_val)
return haskey;
}
-/**
- * A version of #BLI_ghash_ensure_p that allows caller to re-assign the key.
- * Typically used when the key is to be duplicated.
- *
- * \warning Caller _must_ write to \a r_key when returning false.
- */
bool BLI_ghash_ensure_p_ex(GHash *gh, const void *key, void ***r_key, void ***r_val)
{
const uint hash = ghash_keyhash(gh, key);
@@ -889,14 +803,6 @@ bool BLI_ghash_ensure_p_ex(GHash *gh, const void *key, void ***r_key, void ***r_
return haskey;
}
-/**
- * Remove \a key from \a gh, or return false if the key wasn't found.
- *
- * \param key: The key to remove.
- * \param keyfreefp: Optional callback to free the key.
- * \param valfreefp: Optional callback to free the value.
- * \return true if \a key was removed from \a gh.
- */
bool BLI_ghash_remove(GHash *gh,
const void *key,
GHashKeyFreeFP keyfreefp,
@@ -912,17 +818,11 @@ bool BLI_ghash_remove(GHash *gh,
return false;
}
-/* same as above but return the value,
- * no free value argument since it will be returned */
-/**
- * Remove \a key from \a gh, returning the value or NULL if the key wasn't found.
- *
- * \param key: The key to remove.
- * \param keyfreefp: Optional callback to free the key.
- * \return the value of \a key int \a gh or NULL.
- */
void *BLI_ghash_popkey(GHash *gh, const void *key, GHashKeyFreeFP keyfreefp)
{
+ /* Same as above but return the value,
+ * no free value argument since it will be returned. */
+
const uint hash = ghash_keyhash(gh, key);
const uint bucket_index = ghash_bucket_index(gh, hash);
GHashEntry *e = (GHashEntry *)ghash_remove_ex(gh, key, keyfreefp, NULL, bucket_index);
@@ -935,23 +835,11 @@ void *BLI_ghash_popkey(GHash *gh, const void *key, GHashKeyFreeFP keyfreefp)
return NULL;
}
-/**
- * \return true if the \a key is in \a gh.
- */
bool BLI_ghash_haskey(const GHash *gh, const void *key)
{
return (ghash_lookup_entry(gh, key) != NULL);
}
-/**
- * Remove a random entry from \a gh, returning true
- * if a key/value pair could be removed, false otherwise.
- *
- * \param r_key: The removed key.
- * \param r_val: The removed value.
- * \param state: Used for efficient removal.
- * \return true if there was something to pop, false if ghash was already empty.
- */
bool BLI_ghash_pop(GHash *gh, GHashIterState *state, void **r_key, void **r_val)
{
GHashEntry *e = (GHashEntry *)ghash_pop(gh, state);
@@ -970,13 +858,6 @@ bool BLI_ghash_pop(GHash *gh, GHashIterState *state, void **r_key, void **r_val)
return false;
}
-/**
- * Reset \a gh clearing all entries.
- *
- * \param keyfreefp: Optional callback to free the key.
- * \param valfreefp: Optional callback to free the value.
- * \param nentries_reserve: Optionally reserve the number of members that the hash will hold.
- */
void BLI_ghash_clear_ex(GHash *gh,
GHashKeyFreeFP keyfreefp,
GHashValFreeFP valfreefp,
@@ -990,21 +871,11 @@ void BLI_ghash_clear_ex(GHash *gh,
BLI_mempool_clear_ex(gh->entrypool, nentries_reserve ? (int)nentries_reserve : -1);
}
-/**
- * Wraps #BLI_ghash_clear_ex with zero entries reserved.
- */
void BLI_ghash_clear(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
{
BLI_ghash_clear_ex(gh, keyfreefp, valfreefp, 0);
}
-/**
- * Frees the GHash and its members.
- *
- * \param gh: The GHash to free.
- * \param keyfreefp: Optional callback to free the key.
- * \param valfreefp: Optional callback to free the value.
- */
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
{
BLI_assert((int)gh->nentries == BLI_mempool_len(gh->entrypool));
@@ -1017,17 +888,11 @@ void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreef
MEM_freeN(gh);
}
-/**
- * Sets a GHash flag.
- */
void BLI_ghash_flag_set(GHash *gh, uint flag)
{
gh->flag |= flag;
}
-/**
- * Clear a GHash flag.
- */
void BLI_ghash_flag_clear(GHash *gh, uint flag)
{
gh->flag &= ~flag;
@@ -1039,14 +904,6 @@ void BLI_ghash_flag_clear(GHash *gh, uint flag)
/** \name GHash Iterator API
* \{ */
-/**
- * Create a new GHashIterator. The hash table must not be mutated
- * while the iterator is in use, and the iterator will step exactly
- * #BLI_ghash_len(gh) times before becoming done.
- *
- * \param gh: The GHash to iterate over.
- * \return Pointer to a new iterator.
- */
GHashIterator *BLI_ghashIterator_new(GHash *gh)
{
GHashIterator *ghi = MEM_mallocN(sizeof(*ghi), "ghash iterator");
@@ -1054,14 +911,6 @@ GHashIterator *BLI_ghashIterator_new(GHash *gh)
return ghi;
}
-/**
- * Init an already allocated GHashIterator. The hash table must not
- * be mutated while the iterator is in use, and the iterator will
- * step exactly #BLI_ghash_len(gh) times before becoming done.
- *
- * \param ghi: The GHashIterator to initialize.
- * \param gh: The GHash to iterate over.
- */
void BLI_ghashIterator_init(GHashIterator *ghi, GHash *gh)
{
ghi->gh = gh;
@@ -1078,11 +927,6 @@ void BLI_ghashIterator_init(GHashIterator *ghi, GHash *gh)
}
}
-/**
- * Steps the iterator to the next index.
- *
- * \param ghi: The iterator.
- */
void BLI_ghashIterator_step(GHashIterator *ghi)
{
if (ghi->curEntry) {
@@ -1097,11 +941,6 @@ void BLI_ghashIterator_step(GHashIterator *ghi)
}
}
-/**
- * Free a GHashIterator.
- *
- * \param ghi: The iterator to free.
- */
void BLI_ghashIterator_free(GHashIterator *ghi)
{
MEM_freeN(ghi);
@@ -1111,9 +950,8 @@ void BLI_ghashIterator_free(GHashIterator *ghi)
/* -------------------------------------------------------------------- */
/** \name GSet Public API
- *
- * Use ghash API to give 'set' functionality
* \{ */
+
GSet *BLI_gset_new_ex(GSetHashFP hashfp,
GSetCmpFP cmpfp,
const char *info,
@@ -1127,9 +965,6 @@ GSet *BLI_gset_new(GSetHashFP hashfp, GSetCmpFP cmpfp, const char *info)
return BLI_gset_new_ex(hashfp, cmpfp, info, 0);
}
-/**
- * Copy given GSet. Keys are also copied if callback is provided, else pointers remain the same.
- */
GSet *BLI_gset_copy(const GSet *gs, GHashKeyCopyFP keycopyfp)
{
return (GSet *)ghash_copy((const GHash *)gs, keycopyfp, NULL);
@@ -1140,10 +975,6 @@ uint BLI_gset_len(const GSet *gs)
return ((GHash *)gs)->nentries;
}
-/**
- * Adds the key to the set (no checks for unique keys!).
- * Matching #BLI_ghash_insert
- */
void BLI_gset_insert(GSet *gs, void *key)
{
const uint hash = ghash_keyhash((GHash *)gs, key);
@@ -1151,23 +982,11 @@ void BLI_gset_insert(GSet *gs, void *key)
ghash_insert_ex_keyonly((GHash *)gs, key, bucket_index);
}
-/**
- * A version of BLI_gset_insert which checks first if the key is in the set.
- * \returns true if a new key has been added.
- *
- * \note GHash has no equivalent to this because typically the value would be different.
- */
bool BLI_gset_add(GSet *gs, void *key)
{
return ghash_insert_safe_keyonly((GHash *)gs, key, false, NULL);
}
-/**
- * Set counterpart to #BLI_ghash_ensure_p_ex.
- * similar to BLI_gset_add, except it returns the key pointer.
- *
- * \warning Caller _must_ write to \a r_key when returning false.
- */
bool BLI_gset_ensure_p_ex(GSet *gs, const void *key, void ***r_key)
{
const uint hash = ghash_keyhash((GHash *)gs, key);
@@ -1186,23 +1005,11 @@ bool BLI_gset_ensure_p_ex(GSet *gs, const void *key, void ***r_key)
return haskey;
}
-/**
- * Adds the key to the set (duplicates are managed).
- * Matching #BLI_ghash_reinsert
- *
- * \returns true if a new key has been added.
- */
bool BLI_gset_reinsert(GSet *gs, void *key, GSetKeyFreeFP keyfreefp)
{
return ghash_insert_safe_keyonly((GHash *)gs, key, true, keyfreefp);
}
-/**
- * Replaces the key to the set if it's found.
- * Matching #BLI_ghash_replace_key
- *
- * \returns The old key or NULL if not found.
- */
void *BLI_gset_replace_key(GSet *gs, void *key)
{
return BLI_ghash_replace_key((GHash *)gs, key);
@@ -1218,13 +1025,6 @@ bool BLI_gset_haskey(const GSet *gs, const void *key)
return (ghash_lookup_entry((const GHash *)gs, key) != NULL);
}
-/**
- * Remove a random entry from \a gs, returning true if a key could be removed, false otherwise.
- *
- * \param r_key: The removed key.
- * \param state: Used for efficient removal.
- * \return true if there was something to pop, false if gset was already empty.
- */
bool BLI_gset_pop(GSet *gs, GSetIterState *state, void **r_key)
{
GSetEntry *e = (GSetEntry *)ghash_pop((GHash *)gs, (GHashIterState *)state);
@@ -1274,19 +1074,12 @@ void BLI_gset_flag_clear(GSet *gs, uint flag)
* This can be useful when the key references data stored outside the GSet.
* \{ */
-/**
- * Returns the pointer to the key if it's found.
- */
void *BLI_gset_lookup(const GSet *gs, const void *key)
{
Entry *e = ghash_lookup_entry((const GHash *)gs, key);
return e ? e->key : NULL;
}
-/**
- * Returns the pointer to the key if it's found, removing it from the GSet.
- * \note Caller must handle freeing.
- */
void *BLI_gset_pop_key(GSet *gs, const void *key)
{
const uint hash = ghash_keyhash((GHash *)gs, key);
@@ -1308,9 +1101,6 @@ void *BLI_gset_pop_key(GSet *gs, const void *key)
#include "BLI_math.h"
-/**
- * \return number of buckets in the GHash.
- */
int BLI_ghash_buckets_len(const GHash *gh)
{
return (int)gh->nbuckets;
@@ -1320,13 +1110,6 @@ int BLI_gset_buckets_len(const GSet *gs)
return BLI_ghash_buckets_len((const GHash *)gs);
}
-/**
- * Measure how well the hash function performs (1.0 is approx as good as random distribution),
- * and return a few other stats like load,
- * variance of the distribution of the entries in the buckets, etc.
- *
- * Smaller is better!
- */
double BLI_ghash_calc_quality_ex(GHash *gh,
double *r_load,
double *r_variance,
diff --git a/source/blender/blenlib/intern/BLI_ghash_utils.c b/source/blender/blenlib/intern/BLI_ghash_utils.c
index b9144009304..f8e621e406c 100644
--- a/source/blender/blenlib/intern/BLI_ghash_utils.c
+++ b/source/blender/blenlib/intern/BLI_ghash_utils.c
@@ -46,9 +46,10 @@ uint BLI_ghashutil_ptrhash(const void *key)
return (uint)(intptr_t)key;
}
#else
-/* Based Python3.7's pointer hashing function. */
uint BLI_ghashutil_ptrhash(const void *key)
{
+ /* Based Python3.7's pointer hashing function. */
+
size_t y = (size_t)key;
/* bottom 3 or 4 bits are likely to be 0; rotate y by 4 to avoid
* excessive hash collisions for dicts and sets */
@@ -134,15 +135,6 @@ size_t BLI_ghashutil_combine_hash(size_t hash_a, size_t hash_b)
return hash_a ^ (hash_b + 0x9e3779b9 + (hash_a << 6) + (hash_a >> 2));
}
-/**
- * This function implements the widely used "djb" hash apparently posted
- * by Daniel Bernstein to comp.lang.c some time ago. The 32 bit
- * unsigned hash value starts at 5381 and for each byte 'c' in the
- * string, is updated: `hash = hash * 33 + c`.
- * This function uses the signed value of each byte.
- *
- * NOTE: this is the same hash method that glib 2.34.0 uses.
- */
uint BLI_ghashutil_strhash_n(const char *key, size_t n)
{
const signed char *p;
diff --git a/source/blender/blenlib/intern/BLI_heap.c b/source/blender/blenlib/intern/BLI_heap.c
index a221820d4c4..efa0110ed53 100644
--- a/source/blender/blenlib/intern/BLI_heap.c
+++ b/source/blender/blenlib/intern/BLI_heap.c
@@ -193,11 +193,6 @@ static void heap_node_free(Heap *heap, HeapNode *node)
/** \name Public Heap API
* \{ */
-/**
- * Creates a new heap. Removed nodes are recycled, so memory usage will not shrink.
- *
- * \note Use when the size of the heap is known in advance.
- */
Heap *BLI_heap_new_ex(uint tot_reserve)
{
Heap *heap = MEM_mallocN(sizeof(Heap), __func__);
@@ -261,10 +256,6 @@ void BLI_heap_clear(Heap *heap, HeapFreeFP ptrfreefp)
heap->nodes.free = NULL;
}
-/**
- * Insert heap node with a value (often a 'cost') and pointer into the heap,
- * duplicate values are allowed.
- */
HeapNode *BLI_heap_insert(Heap *heap, float value, void *ptr)
{
HeapNode *node;
@@ -289,9 +280,6 @@ HeapNode *BLI_heap_insert(Heap *heap, float value, void *ptr)
return node;
}
-/**
- * Convenience function since this is a common pattern.
- */
void BLI_heap_insert_or_update(Heap *heap, HeapNode **node_p, float value, void *ptr)
{
if (*node_p == NULL) {
@@ -312,19 +300,11 @@ uint BLI_heap_len(const Heap *heap)
return heap->size;
}
-/**
- * Return the top node of the heap.
- * This is the node with the lowest value.
- */
HeapNode *BLI_heap_top(const Heap *heap)
{
return heap->tree[0];
}
-/**
- * Return the value of top node of the heap.
- * This is the node with the lowest value.
- */
float BLI_heap_top_value(const Heap *heap)
{
BLI_assert(heap->size != 0);
@@ -332,9 +312,6 @@ float BLI_heap_top_value(const Heap *heap)
return heap->tree[0]->value;
}
-/**
- * Pop the top node off the heap and return its pointer.
- */
void *BLI_heap_pop_min(Heap *heap)
{
BLI_assert(heap->size != 0);
@@ -366,11 +343,6 @@ void BLI_heap_remove(Heap *heap, HeapNode *node)
BLI_heap_pop_min(heap);
}
-/**
- * Can be used to avoid #BLI_heap_remove, #BLI_heap_insert calls,
- * balancing the tree still has a performance cost,
- * but is often much less than remove/insert, difference is most noticeable with large heaps.
- */
void BLI_heap_node_value_update(Heap *heap, HeapNode *node, float value)
{
if (value < node->value) {
@@ -427,9 +399,6 @@ static bool heap_is_minheap(const Heap *heap, uint root)
}
return true;
}
-/**
- * Only for checking internal errors (gtest).
- */
bool BLI_heap_is_valid(const Heap *heap)
{
return heap_is_minheap(heap, 0);
diff --git a/source/blender/blenlib/intern/BLI_heap_simple.c b/source/blender/blenlib/intern/BLI_heap_simple.c
index c075a2f8643..f285dd074c3 100644
--- a/source/blender/blenlib/intern/BLI_heap_simple.c
+++ b/source/blender/blenlib/intern/BLI_heap_simple.c
@@ -147,11 +147,6 @@ static void heapsimple_up(HeapSimple *heap, uint i, float active_val, void *acti
/** \name Public HeapSimple API
* \{ */
-/**
- * Creates a new simple heap, which only supports insertion and removal from top.
- *
- * \note Use when the size of the heap is known in advance.
- */
HeapSimple *BLI_heapsimple_new_ex(uint tot_reserve)
{
HeapSimple *heap = MEM_mallocN(sizeof(HeapSimple), __func__);
@@ -190,10 +185,6 @@ void BLI_heapsimple_clear(HeapSimple *heap, HeapSimpleFreeFP ptrfreefp)
heap->size = 0;
}
-/**
- * Insert heap node with a value (often a 'cost') and pointer into the heap,
- * duplicate values are allowed.
- */
void BLI_heapsimple_insert(HeapSimple *heap, float value, void *ptr)
{
if (UNLIKELY(heap->size >= heap->bufsize)) {
@@ -214,9 +205,6 @@ uint BLI_heapsimple_len(const HeapSimple *heap)
return heap->size;
}
-/**
- * Return the lowest value of the heap.
- */
float BLI_heapsimple_top_value(const HeapSimple *heap)
{
BLI_assert(heap->size != 0);
@@ -224,9 +212,6 @@ float BLI_heapsimple_top_value(const HeapSimple *heap)
return heap->tree[0].value;
}
-/**
- * Pop the top node off the heap and return its pointer.
- */
void *BLI_heapsimple_pop_min(HeapSimple *heap)
{
BLI_assert(heap->size != 0);
diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c
index 674654c99a8..64c2ce2a4a3 100644
--- a/source/blender/blenlib/intern/BLI_kdopbvh.c
+++ b/source/blender/blenlib/intern/BLI_kdopbvh.c
@@ -867,9 +867,6 @@ static void non_recursive_bvh_div_nodes(const BVHTree *tree,
/** \name BLI_bvhtree API
* \{ */
-/**
- * \note many callers don't check for `NULL` return.
- */
BVHTree *BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis)
{
BVHTree *tree;
@@ -1013,7 +1010,6 @@ void BLI_bvhtree_insert(BVHTree *tree, int index, const float co[3], int numpoin
bvhtree_node_inflate(tree, node, tree->epsilon);
}
-/* call before BLI_bvhtree_update_tree() */
bool BLI_bvhtree_update_node(
BVHTree *tree, int index, const float co[3], const float co_moving[3], int numpoints)
{
@@ -1038,9 +1034,6 @@ bool BLI_bvhtree_update_node(
return true;
}
-/**
- * Call #BLI_bvhtree_update_node() first for every node/point/triangle.
- */
void BLI_bvhtree_update_tree(BVHTree *tree)
{
/* Update bottom=>top
@@ -1054,18 +1047,11 @@ void BLI_bvhtree_update_tree(BVHTree *tree)
node_join(tree, *index);
}
}
-/**
- * Number of times #BLI_bvhtree_insert has been called.
- * mainly useful for asserts functions to check we added the correct number.
- */
int BLI_bvhtree_get_len(const BVHTree *tree)
{
return tree->totleaf;
}
-/**
- * Maximum number of children that a node can have.
- */
int BLI_bvhtree_get_tree_type(const BVHTree *tree)
{
return tree->tree_type;
@@ -1076,9 +1062,6 @@ float BLI_bvhtree_get_epsilon(const BVHTree *tree)
return tree->epsilon;
}
-/**
- * This function returns the bounding box of the BVH tree.
- */
void BLI_bvhtree_get_bounding_box(BVHTree *tree, float r_bb_min[3], float r_bb_max[3])
{
BVHNode *root = tree->nodes[tree->totleaf];
@@ -1264,11 +1247,6 @@ static bool tree_overlap_traverse_num(BVHOverlapData_Thread *data_thread,
return false;
}
-/**
- * Use to check the total number of threads #BLI_bvhtree_overlap will use.
- *
- * \warning Must be the first tree passed to #BLI_bvhtree_overlap!
- */
int BLI_bvhtree_overlap_thread_num(const BVHTree *tree)
{
return (int)MIN2(tree->tree_type, tree->nodes[tree->totleaf]->totnode);
@@ -1717,10 +1695,6 @@ static bool dfs_find_duplicate_fast_dfs(BVHNearestData *data, BVHNode *node)
return false;
}
-/**
- * Find the first node nearby.
- * Favors speed over quality since it doesn't find the best target node.
- */
int BLI_bvhtree_find_nearest_first(BVHTree *tree,
const float co[3],
const float dist_sq,
@@ -2020,15 +1994,6 @@ float BLI_bvhtree_bb_raycast(const float bv[6],
return dist;
}
-/**
- * Calls the callback for every ray intersection
- *
- * \note Using a \a callback which resets or never sets the #BVHTreeRayHit index & dist works too,
- * however using this function means existing generic callbacks can be used from custom callbacks
- * without having to handle resetting the hit beforehand.
- * It also avoid redundant argument and return value which aren't meaningful
- * when collecting multiple hits.
- */
void BLI_bvhtree_ray_cast_all_ex(BVHTree *tree,
const float co[3],
const float dir[3],
@@ -2395,18 +2360,6 @@ static bool bvhtree_walk_dfs_recursive(BVHTree_WalkData *walk_data, const BVHNod
return true;
}
-/**
- * This is a generic function to perform a depth first search on the #BVHTree
- * where the search order and nodes traversed depend on callbacks passed in.
- *
- * \param tree: Tree to walk.
- * \param walk_parent_cb: Callback on a parents bound-box to test if it should be traversed.
- * \param walk_leaf_cb: Callback to test leaf nodes, callback must store its own result,
- * returning false exits early.
- * \param walk_order_cb: Callback that indicates which direction to search,
- * either from the node with the lower or higher K-DOP axis value.
- * \param userdata: Argument passed to all callbacks.
- */
void BLI_bvhtree_walk_dfs(BVHTree *tree,
BVHTree_WalkParentCallback walk_parent_cb,
BVHTree_WalkLeafCallback walk_leaf_cb,
diff --git a/source/blender/blenlib/intern/BLI_linklist.c b/source/blender/blenlib/intern/BLI_linklist.c
index 4cac526088b..765d2f0be55 100644
--- a/source/blender/blenlib/intern/BLI_linklist.c
+++ b/source/blender/blenlib/intern/BLI_linklist.c
@@ -100,10 +100,6 @@ void BLI_linklist_reverse(LinkNode **listp)
*listp = rhead;
}
-/**
- * Move an item from its current position to a new one inside a single-linked list.
- * Note *listp may be modified.
- */
void BLI_linklist_move_item(LinkNode **listp, int curr_index, int new_index)
{
LinkNode *lnk, *lnk_psrc = NULL, *lnk_pdst = NULL;
@@ -171,9 +167,6 @@ void BLI_linklist_move_item(LinkNode **listp, int curr_index, int new_index)
}
}
-/**
- * A version of prepend that takes the allocated link.
- */
void BLI_linklist_prepend_nlink(LinkNode **listp, void *ptr, LinkNode *nlink)
{
nlink->link = ptr;
@@ -199,9 +192,6 @@ void BLI_linklist_prepend_pool(LinkNode **listp, void *ptr, BLI_mempool *mempool
BLI_linklist_prepend_nlink(listp, ptr, nlink);
}
-/**
- * A version of append that takes the allocated link.
- */
void BLI_linklist_append_nlink(LinkNodePair *list_pair, void *ptr, LinkNode *nlink)
{
nlink->link = ptr;
diff --git a/source/blender/blenlib/intern/BLI_memarena.c b/source/blender/blenlib/intern/BLI_memarena.c
index 0ab27a5adad..f1fc3bba4ea 100644
--- a/source/blender/blenlib/intern/BLI_memarena.c
+++ b/source/blender/blenlib/intern/BLI_memarena.c
@@ -179,16 +179,6 @@ void *BLI_memarena_calloc(MemArena *ma, size_t size)
return ptr;
}
-/**
- * Transfer ownership of allocated blocks from `ma_src` into `ma_dst`,
- * cleaning the contents of `ma_src`.
- *
- * \note Useful for multi-threaded tasks that need a thread-local #MemArena
- * that is kept after the multi-threaded operation is completed.
- *
- * \note Avoid accumulating memory pools where possible
- * as any unused memory in `ma_src` is wasted every merge.
- */
void BLI_memarena_merge(MemArena *ma_dst, MemArena *ma_src)
{
/* Memory arenas must be compatible. */
@@ -231,10 +221,6 @@ void BLI_memarena_merge(MemArena *ma_dst, MemArena *ma_src)
VALGRIND_CREATE_MEMPOOL(ma_src, 0, false);
}
-/**
- * Clear for reuse, avoids re-allocation when an arena may
- * otherwise be free'd and recreated.
- */
void BLI_memarena_clear(MemArena *ma)
{
if (ma->bufs) {
diff --git a/source/blender/blenlib/intern/BLI_memblock.c b/source/blender/blenlib/intern/BLI_memblock.c
index 2fbdfbe8a95..4e9d68d92e4 100644
--- a/source/blender/blenlib/intern/BLI_memblock.c
+++ b/source/blender/blenlib/intern/BLI_memblock.c
@@ -99,8 +99,6 @@ void BLI_memblock_destroy(BLI_memblock *mblk, MemblockValFreeFP free_callback)
MEM_freeN(mblk);
}
-/* Reset elem count to 0 but keep as much memory allocated needed for at least the previous elem
- * count. */
void BLI_memblock_clear(BLI_memblock *mblk, MemblockValFreeFP free_callback)
{
int elem_per_chunk = mblk->chunk_size / mblk->elem_size;
@@ -191,9 +189,6 @@ void *BLI_memblock_iterstep(BLI_memblock_iter *iter)
return ptr;
}
-/* Direct access. elem is element index inside the chosen chunk.
- * Double usage: You can set chunk to 0 and set the absolute elem index.
- * The correct chunk will be retrieve. */
void *BLI_memblock_elem_get(BLI_memblock *mblk, int chunk, int elem)
{
BLI_assert(chunk < mblk->chunk_len);
diff --git a/source/blender/blenlib/intern/BLI_memiter.c b/source/blender/blenlib/intern/BLI_memiter.c
index effbe5da5c4..98348fe2938 100644
--- a/source/blender/blenlib/intern/BLI_memiter.c
+++ b/source/blender/blenlib/intern/BLI_memiter.c
@@ -125,15 +125,6 @@ static void memiter_init(BLI_memiter *mi)
/** \name Public API's
* \{ */
-/**
- * \param chunk_size_min: Should be a power of two and
- * significantly larger than the average element size used.
- *
- * While allocations of any size are supported, they won't be efficient
- * (effectively becoming a single-linked list).
- *
- * Its intended that many elements can be stored per chunk.
- */
BLI_memiter *BLI_memiter_create(uint chunk_size_min)
{
BLI_memiter *mi = MEM_mallocN(sizeof(BLI_memiter), "BLI_memiter");
@@ -261,7 +252,6 @@ uint BLI_memiter_count(const BLI_memiter *mi)
/** \name Helper API's
* \{ */
-/* Support direct lookup for first. */
void *BLI_memiter_elem_first(BLI_memiter *mi)
{
if (mi->head != NULL) {
diff --git a/source/blender/blenlib/intern/BLI_mempool.c b/source/blender/blenlib/intern/BLI_mempool.c
index bd6a124c7cb..df85d3e7553 100644
--- a/source/blender/blenlib/intern/BLI_mempool.c
+++ b/source/blender/blenlib/intern/BLI_mempool.c
@@ -367,11 +367,6 @@ void *BLI_mempool_calloc(BLI_mempool *pool)
return retval;
}
-/**
- * Free an element from the mempool.
- *
- * \note doesn't protect against double frees, take care!
- */
void BLI_mempool_free(BLI_mempool *pool, void *addr)
{
BLI_freenode *newhead = addr;
@@ -475,13 +470,6 @@ void *BLI_mempool_findelem(BLI_mempool *pool, uint index)
return NULL;
}
-/**
- * Fill in \a data with pointers to each element of the mempool,
- * to create lookup table.
- *
- * \param pool: Pool to create a table from.
- * \param data: array of pointers at least the size of 'pool->totused'
- */
void BLI_mempool_as_table(BLI_mempool *pool, void **data)
{
BLI_mempool_iter iter;
@@ -495,9 +483,6 @@ void BLI_mempool_as_table(BLI_mempool *pool, void **data)
BLI_assert((uint)(p - data) == pool->totused);
}
-/**
- * A version of #BLI_mempool_as_table that allocates and returns the data.
- */
void **BLI_mempool_as_tableN(BLI_mempool *pool, const char *allocstr)
{
void **data = MEM_mallocN((size_t)pool->totused * sizeof(void *), allocstr);
@@ -505,9 +490,6 @@ void **BLI_mempool_as_tableN(BLI_mempool *pool, const char *allocstr)
return data;
}
-/**
- * Fill in \a data with the contents of the mempool.
- */
void BLI_mempool_as_array(BLI_mempool *pool, void *data)
{
const uint esize = pool->esize;
@@ -522,9 +504,6 @@ void BLI_mempool_as_array(BLI_mempool *pool, void *data)
BLI_assert((uint)(p - (char *)data) == pool->totused * esize);
}
-/**
- * A version of #BLI_mempool_as_array that allocates and returns the data.
- */
void *BLI_mempool_as_arrayN(BLI_mempool *pool, const char *allocstr)
{
char *data = MEM_malloc_arrayN(pool->totused, pool->esize, allocstr);
@@ -532,9 +511,6 @@ void *BLI_mempool_as_arrayN(BLI_mempool *pool, const char *allocstr)
return data;
}
-/**
- * Initialize a new mempool iterator, #BLI_MEMPOOL_ALLOW_ITER flag must be set.
- */
void BLI_mempool_iternew(BLI_mempool *pool, BLI_mempool_iter *iter)
{
BLI_assert(pool->flag & BLI_MEMPOOL_ALLOW_ITER);
@@ -550,19 +526,6 @@ static void mempool_threadsafe_iternew(BLI_mempool *pool, BLI_mempool_threadsafe
ts_iter->curchunk_threaded_shared = NULL;
}
-/**
- * Initialize an array of mempool iterators, #BLI_MEMPOOL_ALLOW_ITER flag must be set.
- *
- * This is used in threaded code, to generate as much iterators as needed
- * (each task should have its own),
- * such that each iterator goes over its own single chunk,
- * and only getting the next chunk to iterate over has to be
- * protected against concurrency (which can be done in a lockless way).
- *
- * To be used when creating a task for each single item in the pool is totally overkill.
- *
- * See BLI_task_parallel_mempool implementation for detailed usage example.
- */
ParallelMempoolTaskData *mempool_iter_threadsafe_create(BLI_mempool *pool, const size_t num_iter)
{
BLI_assert(pool->flag & BLI_MEMPOOL_ALLOW_ITER);
@@ -625,13 +588,8 @@ void *BLI_mempool_iterstep(BLI_mempool_iter *iter)
return ret;
}
-#else
-
-/* optimized version of code above */
+#else /* Optimized version of code above. */
-/**
- * Step over the iterator, returning the mempool item or NULL.
- */
void *BLI_mempool_iterstep(BLI_mempool_iter *iter)
{
if (UNLIKELY(iter->curchunk == NULL)) {
@@ -660,11 +618,6 @@ void *BLI_mempool_iterstep(BLI_mempool_iter *iter)
return ret;
}
-/**
- * A version of #BLI_mempool_iterstep that uses
- * #BLI_mempool_threadsafe_iter.curchunk_threaded_shared for threaded iteration support.
- * (threaded section noted in comments).
- */
void *mempool_iter_threadsafe_step(BLI_mempool_threadsafe_iter *ts_iter)
{
BLI_mempool_iter *iter = &ts_iter->iter;
@@ -710,12 +663,6 @@ void *mempool_iter_threadsafe_step(BLI_mempool_threadsafe_iter *ts_iter)
#endif
-/**
- * Empty the pool, as if it were just created.
- *
- * \param pool: The pool to clear.
- * \param totelem_reserve: Optionally reserve how many items should be kept from clearing.
- */
void BLI_mempool_clear_ex(BLI_mempool *pool, const int totelem_reserve)
{
BLI_mempool_chunk *mpchunk;
@@ -768,17 +715,11 @@ void BLI_mempool_clear_ex(BLI_mempool *pool, const int totelem_reserve)
}
}
-/**
- * Wrap #BLI_mempool_clear_ex with no reserve set.
- */
void BLI_mempool_clear(BLI_mempool *pool)
{
BLI_mempool_clear_ex(pool, -1);
}
-/**
- * Free the mempool its self (and all elements).
- */
void BLI_mempool_destroy(BLI_mempool *pool)
{
mempool_chunk_free_all(pool->chunks);
diff --git a/source/blender/blenlib/intern/BLI_mempool_private.h b/source/blender/blenlib/intern/BLI_mempool_private.h
index e1c8205c80c..90569d87c41 100644
--- a/source/blender/blenlib/intern/BLI_mempool_private.h
+++ b/source/blender/blenlib/intern/BLI_mempool_private.h
@@ -41,10 +41,28 @@ typedef struct ParallelMempoolTaskData {
TaskParallelTLS tls;
} ParallelMempoolTaskData;
+/**
+ * Initialize an array of mempool iterators, #BLI_MEMPOOL_ALLOW_ITER flag must be set.
+ *
+ * This is used in threaded code, to generate as much iterators as needed
+ * (each task should have its own),
+ * such that each iterator goes over its own single chunk,
+ * and only getting the next chunk to iterate over has to be
+ * protected against concurrency (which can be done in a lock-less way).
+ *
+ * To be used when creating a task for each single item in the pool is totally overkill.
+ *
+ * See #BLI_task_parallel_mempool implementation for detailed usage example.
+ */
ParallelMempoolTaskData *mempool_iter_threadsafe_create(BLI_mempool *pool, const size_t num_iter)
ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
void mempool_iter_threadsafe_destroy(ParallelMempoolTaskData *iter_arr) ATTR_NONNULL();
+/**
+ * A version of #BLI_mempool_iterstep that uses
+ * #BLI_mempool_threadsafe_iter.curchunk_threaded_shared for threaded iteration support.
+ * (threaded section noted in comments).
+ */
void *mempool_iter_threadsafe_step(BLI_mempool_threadsafe_iter *iter);
#ifdef __cplusplus
diff --git a/source/blender/blenlib/intern/DLRB_tree.c b/source/blender/blenlib/intern/DLRB_tree.c
index 436b9b8d782..66c394f5eb2 100644
--- a/source/blender/blenlib/intern/DLRB_tree.c
+++ b/source/blender/blenlib/intern/DLRB_tree.c
@@ -29,14 +29,12 @@
/* *********************************************** */
/* Tree API */
-/* Create a new tree, and initialize as necessary */
DLRBT_Tree *BLI_dlrbTree_new(void)
{
/* just allocate for now */
return MEM_callocN(sizeof(DLRBT_Tree), "DLRBT_Tree");
}
-/* Just zero out the pointers used */
void BLI_dlrbTree_init(DLRBT_Tree *tree)
{
if (tree == NULL) {
@@ -62,7 +60,6 @@ static void recursive_tree_free_nodes(DLRBT_Node *node)
MEM_freeN(node);
}
-/* Free the given tree's data but not the tree itself */
void BLI_dlrbTree_free(DLRBT_Tree *tree)
{
if (tree == NULL) {
@@ -109,7 +106,6 @@ static void linkedlist_sync_add_node(DLRBT_Tree *tree, DLRBT_Node *node)
linkedlist_sync_add_node(tree, node->right);
}
-/* Make sure the tree's Double-Linked list representation is valid */
void BLI_dlrbTree_linkedlist_sync(DLRBT_Tree *tree)
{
/* sanity checks */
@@ -127,7 +123,6 @@ void BLI_dlrbTree_linkedlist_sync(DLRBT_Tree *tree)
/* *********************************************** */
/* Tree Search Utilities */
-/* Find the node which matches or is the closest to the requested node */
DLRBT_Node *BLI_dlrbTree_search(const DLRBT_Tree *tree,
DLRBT_Comparator_FP cmp_cb,
void *search_data)
@@ -175,7 +170,6 @@ DLRBT_Node *BLI_dlrbTree_search(const DLRBT_Tree *tree,
return node;
}
-/* Find the node which exactly matches the required data */
DLRBT_Node *BLI_dlrbTree_search_exact(const DLRBT_Tree *tree,
DLRBT_Comparator_FP cmp_cb,
void *search_data)
@@ -223,7 +217,6 @@ DLRBT_Node *BLI_dlrbTree_search_exact(const DLRBT_Tree *tree,
return (found == 1) ? (node) : (NULL);
}
-/* Find the node which occurs immediately before the best matching node */
DLRBT_Node *BLI_dlrbTree_search_prev(const DLRBT_Tree *tree,
DLRBT_Comparator_FP cmp_cb,
void *search_data)
@@ -254,7 +247,6 @@ DLRBT_Node *BLI_dlrbTree_search_prev(const DLRBT_Tree *tree,
return NULL;
}
-/* Find the node which occurs immediately after the best matching node */
DLRBT_Node *BLI_dlrbTree_search_next(const DLRBT_Tree *tree,
DLRBT_Comparator_FP cmp_cb,
void *search_data)
@@ -285,7 +277,6 @@ DLRBT_Node *BLI_dlrbTree_search_next(const DLRBT_Tree *tree,
return NULL;
}
-/* Check whether there is a node matching the requested node */
short BLI_dlrbTree_contains(DLRBT_Tree *tree, DLRBT_Comparator_FP cmp_cb, void *search_data)
{
/* check if an exact search throws up anything... */
@@ -522,9 +513,6 @@ static void insert_check_3(DLRBT_Tree *tree, DLRBT_Node *node)
/* ----- */
-/* Balance the tree after the given element has been added to it
- * (using custom code, in the Binary Tree way).
- */
void BLI_dlrbTree_insert(DLRBT_Tree *tree, DLRBT_Node *node)
{
/* sanity checks */
@@ -541,9 +529,6 @@ void BLI_dlrbTree_insert(DLRBT_Tree *tree, DLRBT_Node *node)
/* ----- */
-/* Add the given data to the tree, and return the node added */
-/* NOTE: for duplicates, the update_cb is called (if available),
- * and the existing node is returned */
DLRBT_Node *BLI_dlrbTree_add(DLRBT_Tree *tree,
DLRBT_Comparator_FP cmp_cb,
DLRBT_NAlloc_FP new_cb,
diff --git a/source/blender/blenlib/intern/array_store.c b/source/blender/blenlib/intern/array_store.c
index ee06d8b6347..08696c9168d 100644
--- a/source/blender/blenlib/intern/array_store.c
+++ b/source/blender/blenlib/intern/array_store.c
@@ -1399,26 +1399,6 @@ static BChunkList *bchunk_list_from_data_merge(const BArrayInfo *info,
/** \name Main Array Storage API
* \{ */
-/**
- * Create a new array store, which can store any number of arrays
- * as long as their stride matches.
- *
- * \param stride: `sizeof()` each element,
- *
- * \note while a stride of `1` will always work,
- * its less efficient since duplicate chunks of memory will be searched
- * at positions unaligned with the array data.
- *
- * \param chunk_count: Number of elements to split each chunk into.
- * - A small value increases the ability to de-duplicate chunks,
- * but adds overhead by increasing the number of chunks to look up when searching for duplicates,
- * as well as some overhead constructing the original array again, with more calls to `memcpy`.
- * - Larger values reduce the *book keeping* overhead,
- * but increase the chance a small,
- * isolated change will cause a larger amount of data to be duplicated.
- *
- * \return A new array store, to be freed with #BLI_array_store_destroy.
- */
BArrayStore *BLI_array_store_create(uint stride, uint chunk_count)
{
BArrayStore *bs = MEM_callocN(sizeof(BArrayStore), __func__);
@@ -1472,9 +1452,6 @@ static void array_store_free_data(BArrayStore *bs)
}
}
-/**
- * Free the #BArrayStore, including all states and chunks.
- */
void BLI_array_store_destroy(BArrayStore *bs)
{
array_store_free_data(bs);
@@ -1486,9 +1463,6 @@ void BLI_array_store_destroy(BArrayStore *bs)
MEM_freeN(bs);
}
-/**
- * Clear all contents, allowing reuse of \a bs.
- */
void BLI_array_store_clear(BArrayStore *bs)
{
array_store_free_data(bs);
@@ -1506,9 +1480,6 @@ void BLI_array_store_clear(BArrayStore *bs)
/** \name BArrayStore Statistics
* \{ */
-/**
- * \return the total amount of memory that would be used by getting the arrays for all states.
- */
size_t BLI_array_store_calc_size_expanded_get(const BArrayStore *bs)
{
size_t size_accum = 0;
@@ -1518,10 +1489,6 @@ size_t BLI_array_store_calc_size_expanded_get(const BArrayStore *bs)
return size_accum;
}
-/**
- * \return the amount of memory used by all #BChunk.data
- * (duplicate chunks are only counted once).
- */
size_t BLI_array_store_calc_size_compacted_get(const BArrayStore *bs)
{
size_t size_total = 0;
@@ -1541,18 +1508,6 @@ size_t BLI_array_store_calc_size_compacted_get(const BArrayStore *bs)
/** \name BArrayState Access
* \{ */
-/**
- *
- * \param data: Data used to create
- * \param state_reference: The state to use as a reference when adding the new state,
- * typically this is the previous state,
- * however it can be any previously created state from this \a bs.
- *
- * \return The new state,
- * which is used by the caller as a handle to get back the contents of \a data.
- * This may be removed using #BLI_array_store_state_remove,
- * otherwise it will be removed with #BLI_array_store_destroy.
- */
BArrayState *BLI_array_store_state_add(BArrayStore *bs,
const void *data,
const size_t data_len,
@@ -1601,11 +1556,6 @@ BArrayState *BLI_array_store_state_add(BArrayStore *bs,
return state;
}
-/**
- * Remove a state and free any unused #BChunk data.
- *
- * The states can be freed in any order.
- */
void BLI_array_store_state_remove(BArrayStore *bs, BArrayState *state)
{
#ifdef USE_PARANOID_CHECKS
@@ -1618,18 +1568,11 @@ void BLI_array_store_state_remove(BArrayStore *bs, BArrayState *state)
MEM_freeN(state);
}
-/**
- * \return the expanded size of the array,
- * use this to know how much memory to allocate #BLI_array_store_state_data_get's argument.
- */
size_t BLI_array_store_state_size_get(BArrayState *state)
{
return state->chunk_list->total_size;
}
-/**
- * Fill in existing allocated memory with the contents of \a state.
- */
void BLI_array_store_state_data_get(BArrayState *state, void *data)
{
#ifdef USE_PARANOID_CHECKS
@@ -1648,9 +1591,6 @@ void BLI_array_store_state_data_get(BArrayState *state, void *data)
}
}
-/**
- * Allocate an array for \a state and return it.
- */
void *BLI_array_store_state_data_get_alloc(BArrayState *state, size_t *r_data_len)
{
void *data = MEM_mallocN(state->chunk_list->total_size, __func__);
diff --git a/source/blender/blenlib/intern/array_utils.c b/source/blender/blenlib/intern/array_utils.c
index 9a12a7442b7..36bd193810e 100644
--- a/source/blender/blenlib/intern/array_utils.c
+++ b/source/blender/blenlib/intern/array_utils.c
@@ -35,11 +35,6 @@
#include "BLI_array_utils.h"
-/**
- *In-place array reverse.
- *
- * Access via #BLI_array_reverse
- */
void _bli_array_reverse(void *arr_v, uint arr_len, size_t arr_stride)
{
const uint arr_stride_uint = (uint)arr_stride;
@@ -56,12 +51,6 @@ void _bli_array_reverse(void *arr_v, uint arr_len, size_t arr_stride)
}
}
-/**
- * In-place array wrap.
- * (rotate the array one step forward or backwards).
- *
- * Access via #BLI_array_wrap
- */
void _bli_array_wrap(void *arr_v, uint arr_len, size_t arr_stride, int dir)
{
char *arr = arr_v;
@@ -82,12 +71,6 @@ void _bli_array_wrap(void *arr_v, uint arr_len, size_t arr_stride, int dir)
}
}
-/**
- *In-place array permute.
- * (re-arrange elements based on an array of indices).
- *
- * Access via #BLI_array_wrap
- */
void _bli_array_permute(
void *arr, const uint arr_len, const size_t arr_stride, const uint *order, void *arr_temp)
{
@@ -117,13 +100,6 @@ void _bli_array_permute(
}
}
-/**
- * In-place array de-duplication of an ordered array.
- *
- * \return The new length of the array.
- *
- * Access via #BLI_array_deduplicate_ordered
- */
uint _bli_array_deduplicate_ordered(void *arr, uint arr_len, size_t arr_stride)
{
if (UNLIKELY(arr_len <= 1)) {
@@ -146,13 +122,6 @@ uint _bli_array_deduplicate_ordered(void *arr, uint arr_len, size_t arr_stride)
return j + 1;
}
-/**
- * Find the first index of an item in an array.
- *
- * Access via #BLI_array_findindex
- *
- * \note Not efficient, use for error checks/asserts.
- */
int _bli_array_findindex(const void *arr, uint arr_len, size_t arr_stride, const void *p)
{
const char *arr_step = (const char *)arr;
@@ -164,9 +133,6 @@ int _bli_array_findindex(const void *arr, uint arr_len, size_t arr_stride, const
return -1;
}
-/**
- * A version of #BLI_array_findindex that searches from the end of the list.
- */
int _bli_array_rfindindex(const void *arr, uint arr_len, size_t arr_stride, const void *p)
{
const char *arr_step = (const char *)arr + (arr_stride * arr_len);
@@ -205,22 +171,6 @@ void _bli_array_binary_or(
}
}
-/**
- * Utility function to iterate over contiguous items in an array.
- *
- * \param use_wrap: Detect contiguous ranges across the first/last points.
- * In this case the second index of \a span_step may be lower than the first,
- * which indicates the values are wrapped.
- * \param use_delimit_bounds: When false,
- * ranges that defined by the start/end indices are excluded.
- * This option has no effect when \a use_wrap is enabled.
- * \param test_fn: Function to test if the item should be included in the range.
- * \param user_data: User data for \a test_fn.
- * \param span_step: Indices to iterate over,
- * initialize both values to the array length to initialize iteration.
- * \param r_span_len: The length of the span, useful when \a use_wrap is enabled,
- * where calculating the length isn't a simple subtraction.
- */
bool _bli_array_iter_span(const void *arr,
uint arr_len,
size_t arr_stride,
@@ -330,9 +280,6 @@ bool _bli_array_iter_span(const void *arr,
return false;
}
-/**
- * Simple utility to check memory is zeroed.
- */
bool _bli_array_is_zeroed(const void *arr_v, uint arr_len, size_t arr_stride)
{
const char *arr_step = (const char *)arr_v;
@@ -345,13 +292,6 @@ bool _bli_array_is_zeroed(const void *arr_v, uint arr_len, size_t arr_stride)
return true;
}
-/**
- * Smart function to sample a rect spiraling outside.
- * Nice for selection ID.
- *
- * \param arr_shape: dimensions [w, h].
- * \param center: coordinates [x, y] indicating where to start traversing.
- */
bool _bli_array_iter_spiral_square(const void *arr_v,
const int arr_shape[2],
size_t elem_size,
diff --git a/source/blender/blenlib/intern/astar.c b/source/blender/blenlib/intern/astar.c
index 1f71a62d191..8347e00adc8 100644
--- a/source/blender/blenlib/intern/astar.c
+++ b/source/blender/blenlib/intern/astar.c
@@ -53,25 +53,11 @@
#include "BLI_astar.h"
-/**
- * Init a node in A* graph.
- *
- * \param custom_data: an opaque pointer attached to this link,
- * available e.g. to cost callback function.
- */
void BLI_astar_node_init(BLI_AStarGraph *as_graph, const int node_index, void *custom_data)
{
as_graph->nodes[node_index].custom_data = custom_data;
}
-/**
- * Add a link between two nodes of our A* graph.
- *
- * \param cost: the 'length' of the link
- * (actual distance between two vertices or face centers e.g.).
- * \param custom_data: an opaque pointer attached to this link,
- * available e.g. to cost callback function.
- */
void BLI_astar_node_link_add(BLI_AStarGraph *as_graph,
const int node1_index,
const int node2_index,
@@ -93,22 +79,11 @@ void BLI_astar_node_link_add(BLI_AStarGraph *as_graph,
BLI_addtail(&(as_graph->nodes[node2_index].neighbor_links), &ld[1]);
}
-/**
- * \return The index of the other node of given link.
- */
int BLI_astar_node_link_other_node(BLI_AStarGNLink *lnk, const int idx)
{
return (lnk->nodes[0] == idx) ? lnk->nodes[1] : lnk->nodes[0];
}
-/**
- * Initialize a solution data for given A* graph. Does not compute anything!
- *
- * \param custom_data: an opaque pointer attached to this link, available e.g
- * . to cost callback function.
- *
- * \note BLI_AStarSolution stores nearly all data needed during solution compute.
- */
void BLI_astar_solution_init(BLI_AStarGraph *as_graph,
BLI_AStarSolution *as_solution,
void *custom_data)
@@ -133,12 +108,6 @@ void BLI_astar_solution_init(BLI_AStarGraph *as_graph,
as_solution->g_steps = BLI_memarena_alloc(mem, sizeof(*as_solution->g_steps) * node_num);
}
-/**
- * Clear given solution's data, but does not release its memory. Avoids having to recreate/allocate
- * a memarena in loops, e.g.
- *
- * \note This *has to be called* between each path solving.
- */
void BLI_astar_solution_clear(BLI_AStarSolution *as_solution)
{
if (as_solution->mem) {
@@ -156,9 +125,6 @@ void BLI_astar_solution_clear(BLI_AStarSolution *as_solution)
as_solution->g_steps = NULL;
}
-/**
- * Release the memory allocated for this solution.
- */
void BLI_astar_solution_free(BLI_AStarSolution *as_solution)
{
if (as_solution->mem) {
@@ -167,14 +133,6 @@ void BLI_astar_solution_free(BLI_AStarSolution *as_solution)
}
}
-/**
- * Init an A* graph. Total number of nodes must be known.
- *
- * Nodes might be e.g. vertices, faces, ...
- *
- * \param custom_data: an opaque pointer attached to this link,
- * available e.g. to cost callback function.
- */
void BLI_astar_graph_init(BLI_AStarGraph *as_graph, const int node_num, void *custom_data)
{
MemArena *mem = as_graph->mem;
@@ -199,14 +157,6 @@ void BLI_astar_graph_free(BLI_AStarGraph *as_graph)
}
}
-/**
- * Solve a path in given graph, using given 'cost' callback function.
- *
- * \param max_steps: maximum number of nodes the found path may have.
- * Useful in performance-critical usages.
- * If no path is found within given steps, returns false too.
- * \return true if a path was found, false otherwise.
- */
bool BLI_astar_graph_solve(BLI_AStarGraph *as_graph,
const int node_index_src,
const int node_index_dst,
diff --git a/source/blender/blenlib/intern/bitmap.c b/source/blender/blenlib/intern/bitmap.c
index 54edcaec2c8..681736b7927 100644
--- a/source/blender/blenlib/intern/bitmap.c
+++ b/source/blender/blenlib/intern/bitmap.c
@@ -29,13 +29,11 @@
#include "BLI_bitmap.h"
#include "BLI_utildefines.h"
-/** Set or clear all bits in the bitmap. */
void BLI_bitmap_set_all(BLI_bitmap *bitmap, bool set, size_t bits)
{
memset(bitmap, set ? UCHAR_MAX : 0, BLI_BITMAP_SIZE(bits));
}
-/** Invert all bits in the bitmap. */
void BLI_bitmap_flip_all(BLI_bitmap *bitmap, size_t bits)
{
size_t num_blocks = _BITMAP_NUM_BLOCKS(bits);
@@ -44,13 +42,11 @@ void BLI_bitmap_flip_all(BLI_bitmap *bitmap, size_t bits)
}
}
-/** Copy all bits from one bitmap to another. */
void BLI_bitmap_copy_all(BLI_bitmap *dst, const BLI_bitmap *src, size_t bits)
{
memcpy(dst, src, BLI_BITMAP_SIZE(bits));
}
-/** Combine two bitmaps with boolean AND. */
void BLI_bitmap_and_all(BLI_bitmap *dst, const BLI_bitmap *src, size_t bits)
{
size_t num_blocks = _BITMAP_NUM_BLOCKS(bits);
@@ -59,7 +55,6 @@ void BLI_bitmap_and_all(BLI_bitmap *dst, const BLI_bitmap *src, size_t bits)
}
}
-/** Combine two bitmaps with boolean OR. */
void BLI_bitmap_or_all(BLI_bitmap *dst, const BLI_bitmap *src, size_t bits)
{
size_t num_blocks = _BITMAP_NUM_BLOCKS(bits);
diff --git a/source/blender/blenlib/intern/bitmap_draw_2d.c b/source/blender/blenlib/intern/bitmap_draw_2d.c
index b0afe1349ad..670ea75e9ea 100644
--- a/source/blender/blenlib/intern/bitmap_draw_2d.c
+++ b/source/blender/blenlib/intern/bitmap_draw_2d.c
@@ -41,11 +41,6 @@
/** \name Draw Line
* \{ */
-/**
- * Plot a line from \a p1 to \a p2 (inclusive).
- *
- * \note For clipped line drawing, see: http://stackoverflow.com/a/40902741/432509
- */
void BLI_bitmap_draw_2d_line_v2v2i(const int p1[2],
const int p2[2],
bool (*callback)(int, int, void *),
@@ -223,9 +218,6 @@ static void draw_tri_flat_min(const int p[2],
}
}
-/**
- * \note Unclipped (clipped version can be added if needed).
- */
void BLI_bitmap_draw_2d_tri_v2i(
/* all 2d */
const int p1[2],
@@ -338,18 +330,6 @@ static int draw_poly_v2i_n__span_y_sort(const void *a_p, const void *b_p, void *
return 0;
}
-/**
- * Draws a filled polygon with support for self intersections.
- *
- * \param callback: Takes the x, y coords and x-span (\a x_end is not inclusive),
- * note that \a x_end will always be greater than \a x, so we can use:
- *
- * \code{.c}
- * do {
- * func(x, y);
- * } while (++x != x_end);
- * \endcode
- */
void BLI_bitmap_draw_2d_poly_v2i_n(const int xmin,
const int ymin,
const int xmax,
diff --git a/source/blender/blenlib/intern/boxpack_2d.c b/source/blender/blenlib/intern/boxpack_2d.c
index cf5831cada5..5d35feee699 100644
--- a/source/blender/blenlib/intern/boxpack_2d.c
+++ b/source/blender/blenlib/intern/boxpack_2d.c
@@ -120,6 +120,7 @@ static float box_ymax_get(const BoxPack *box)
{
return box->v[TR]->y;
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -165,6 +166,7 @@ static void box_ymax_set(BoxPack *box, const float f)
box->v[TR]->y = f;
box_v34y_update(box);
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -275,22 +277,9 @@ static int vertex_sort(const void *p1, const void *p2, void *vs_ctx_p)
}
return 0;
}
+
/** \} */
-/**
- * Main box-packing function accessed from other functions
- * This sets boxes x,y to positive values, sorting from 0,0 outwards.
- * There is no limit to the space boxes may take, only that they will be packed
- * tightly into the lower left hand corner (0,0)
- *
- * \param boxarray: a pre-allocated array of boxes.
- * only the 'box->x' and 'box->y' are set, 'box->w' and 'box->h' are used,
- * 'box->index' is not used at all, the only reason its there
- * is that the box array is sorted by area and programs need to be able
- * to have some way of writing the boxes back to the original data.
- * \param len: the number of boxes in the array.
- * \param r_tot_x, r_tot_y: set so you can normalize the data.
- */
void BLI_box_pack_2d(BoxPack *boxarray, const uint len, float *r_tot_x, float *r_tot_y)
{
uint box_index, verts_pack_len, i, j, k;
@@ -678,18 +667,6 @@ void BLI_box_pack_2d(BoxPack *boxarray, const uint len, float *r_tot_x, float *r
MEM_freeN(vs_ctx.vertarray);
}
-/* Packs boxes into a fixed area.
- * boxes and packed are linked lists containing structs that can be cast to
- * FixedSizeBoxPack (i.e. contains a FixedSizeBoxPack as its first element).
- * Boxes that were packed successfully are placed into *packed and removed from *boxes.
- *
- * The algorithm is a simplified version of https://github.com/TeamHypersomnia/rectpack2D.
- * Better ones could be used, but for the current use case (packing Image tiles into GPU
- * textures) this is fine.
- *
- * Note that packing efficiency depends on the order of the input boxes. Generally speaking,
- * larger boxes should come first, though how exactly size is best defined (e.g. area,
- * perimeter) depends on the particular application. */
void BLI_box_pack_2d_fixedarea(ListBase *boxes, int width, int height, ListBase *packed)
{
ListBase spaces = {NULL};
diff --git a/source/blender/blenlib/intern/buffer.c b/source/blender/blenlib/intern/buffer.c
index 74e97d89430..9df32051281 100644
--- a/source/blender/blenlib/intern/buffer.c
+++ b/source/blender/blenlib/intern/buffer.c
@@ -86,11 +86,6 @@ void BLI_buffer_resize(BLI_Buffer *buffer, const size_t new_count)
buffer->count = new_count;
}
-/**
- * Similar to #BLI_buffer_resize, but use when the existing data can be:
- * - Ignored (malloc'd)
- * - Cleared (when BLI_BUFFER_USE_CALLOC is set)
- */
void BLI_buffer_reinit(BLI_Buffer *buffer, const size_t new_count)
{
if (UNLIKELY(new_count > buffer->alloc_count)) {
@@ -114,7 +109,6 @@ void BLI_buffer_reinit(BLI_Buffer *buffer, const size_t new_count)
buffer->count = new_count;
}
-/* Callers use BLI_buffer_append_array. */
void _bli_buffer_append_array(BLI_Buffer *buffer, void *new_data, size_t count)
{
size_t size = buffer->count;
@@ -124,7 +118,6 @@ void _bli_buffer_append_array(BLI_Buffer *buffer, void *new_data, size_t count)
memcpy(bytes + size * buffer->elem_size, new_data, count * buffer->elem_size);
}
-/* callers use BLI_buffer_free */
void _bli_buffer_free(BLI_Buffer *buffer)
{
if ((buffer->flag & BLI_BUFFER_USE_STATIC) == 0) {
diff --git a/source/blender/blenlib/intern/convexhull_2d.c b/source/blender/blenlib/intern/convexhull_2d.c
index 233a1430fe7..df675b512d9 100644
--- a/source/blender/blenlib/intern/convexhull_2d.c
+++ b/source/blender/blenlib/intern/convexhull_2d.c
@@ -53,14 +53,6 @@ static float is_left(const float p0[2], const float p1[2], const float p2[2])
return (p1[0] - p0[0]) * (p2[1] - p0[1]) - (p2[0] - p0[0]) * (p1[1] - p0[1]);
}
-/**
- * A.M. Andrew's monotone chain 2D convex hull algorithm
- *
- * \param points: An array of 2D points presorted by increasing x and y-coords.
- * \param n: The number of points in points.
- * \param r_points: An array of the convex hull vertex indices (max is n).
- * \returns the number of points in r_points.
- */
int BLI_convexhull_2d_sorted(const float (*points)[2], const int n, int r_points[])
{
/* the output array r_points[] will be used as the stack */
@@ -182,16 +174,6 @@ static int pointref_cmp_yx(const void *a_, const void *b_)
return 0;
}
-/**
- * A.M. Andrew's monotone chain 2D convex hull algorithm
- *
- * \param points: An array of 2D points.
- * \param n: The number of points in points.
- * \param r_points: An array of the convex hull vertex indices (max is n).
- * _must_ be allocated as `n * 2` because of how its used internally,
- * even though the final result will be no more than \a n in size.
- * \returns the number of points in r_points.
- */
int BLI_convexhull_2d(const float (*points)[2], const int n, int r_points[])
{
struct PointRef *points_ref = MEM_mallocN(sizeof(*points_ref) * (size_t)n, __func__);
@@ -234,16 +216,6 @@ int BLI_convexhull_2d(const float (*points)[2], const int n, int r_points[])
/** \name Utility Convex-Hull Functions
* \{ */
-/**
- * \return The best angle for fitting the convex hull to an axis aligned bounding box.
- *
- * Intended to be used with #BLI_convexhull_2d
- *
- * \param points_hull: Ordered hull points
- * (result of #BLI_convexhull_2d mapped to a contiguous array).
- *
- * \note we could return the index of the best edge too if its needed.
- */
float BLI_convexhull_aabb_fit_hull_2d(const float (*points_hull)[2], unsigned int n)
{
unsigned int i, i_prev;
@@ -291,11 +263,6 @@ float BLI_convexhull_aabb_fit_hull_2d(const float (*points_hull)[2], unsigned in
return (area_best != FLT_MAX) ? atan2f(dvec_best[0], dvec_best[1]) : 0.0f;
}
-/**
- * Wrap #BLI_convexhull_aabb_fit_hull_2d and do the convex hull calculation.
- *
- * \param points: arbitrary 2d points.
- */
float BLI_convexhull_aabb_fit_points_2d(const float (*points)[2], unsigned int n)
{
int *index_map;
diff --git a/source/blender/blenlib/intern/edgehash.c b/source/blender/blenlib/intern/edgehash.c
index 6c397fae836..d8e59b6f6ee 100644
--- a/source/blender/blenlib/intern/edgehash.c
+++ b/source/blender/blenlib/intern/edgehash.c
@@ -272,10 +272,6 @@ void BLI_edgehash_print(EdgeHash *eh)
}
}
-/**
- * Insert edge (\a v0, \a v1) into hash with given value, does
- * not check for duplicates.
- */
void BLI_edgehash_insert(EdgeHash *eh, uint v0, uint v1, void *value)
{
edgehash_ensure_can_insert(eh);
@@ -283,9 +279,6 @@ void BLI_edgehash_insert(EdgeHash *eh, uint v0, uint v1, void *value)
edgehash_insert(eh, edge, value);
}
-/**
- * Assign a new value to a key that may already be in edgehash.
- */
bool BLI_edgehash_reinsert(EdgeHash *eh, uint v0, uint v1, void *value)
{
Edge edge = init_edge(v0, v1);
@@ -307,51 +300,24 @@ bool BLI_edgehash_reinsert(EdgeHash *eh, uint v0, uint v1, void *value)
}
}
-/**
- * A version of #BLI_edgehash_lookup which accepts a fallback argument.
- */
void *BLI_edgehash_lookup_default(const EdgeHash *eh, uint v0, uint v1, void *default_value)
{
EdgeHashEntry *entry = edgehash_lookup_entry(eh, v0, v1);
return entry ? entry->value : default_value;
}
-/**
- * Return value for given edge (\a v0, \a v1), or NULL if
- * if key does not exist in hash. (If need exists
- * to differentiate between key-value being NULL and
- * lack of key then see #BLI_edgehash_lookup_p().
- */
void *BLI_edgehash_lookup(const EdgeHash *eh, uint v0, uint v1)
{
EdgeHashEntry *entry = edgehash_lookup_entry(eh, v0, v1);
return entry ? entry->value : NULL;
}
-/**
- * Return pointer to value for given edge (\a v0, \a v1),
- * or NULL if key does not exist in hash.
- */
void **BLI_edgehash_lookup_p(EdgeHash *eh, uint v0, uint v1)
{
EdgeHashEntry *entry = edgehash_lookup_entry(eh, v0, v1);
return entry ? &entry->value : NULL;
}
-/**
- * Ensure \a (v0, v1) is exists in \a eh.
- *
- * This handles the common situation where the caller needs ensure a key is added to \a eh,
- * constructing a new value in the case the key isn't found.
- * Otherwise use the existing value.
- *
- * Such situations typically incur multiple lookups, however this function
- * avoids them by ensuring the key is added,
- * returning a pointer to the value so it can be used or initialized by the caller.
- *
- * \returns true when the value didn't need to be added.
- * (when false, the caller _must_ initialize the value).
- */
bool BLI_edgehash_ensure_p(EdgeHash *eh, uint v0, uint v1, void ***r_value)
{
Edge edge = init_edge(v0, v1);
@@ -373,13 +339,6 @@ bool BLI_edgehash_ensure_p(EdgeHash *eh, uint v0, uint v1, void ***r_value)
}
}
-/**
- * Remove \a key (v0, v1) from \a eh, or return false if the key wasn't found.
- *
- * \param v0, v1: The key to remove.
- * \param free_value: Optional callback to free the value.
- * \return true if \a key was removed from \a eh.
- */
bool BLI_edgehash_remove(EdgeHash *eh, uint v0, uint v1, EdgeHashFreeFP free_value)
{
uint old_length = eh->length;
@@ -390,16 +349,11 @@ bool BLI_edgehash_remove(EdgeHash *eh, uint v0, uint v1, EdgeHashFreeFP free_val
return old_length > eh->length;
}
-/* same as above but return the value,
- * no free value argument since it will be returned */
-/**
- * Remove \a key (v0, v1) from \a eh, returning the value or NULL if the key wasn't found.
- *
- * \param v0, v1: The key to remove.
- * \return the value of \a key int \a eh or NULL.
- */
void *BLI_edgehash_popkey(EdgeHash *eh, uint v0, uint v1)
{
+ /* Same as #BLI_edgehash_remove but return the value,
+ * no free value argument since it will be returned */
+
Edge edge = init_edge(v0, v1);
ITER_SLOTS (eh, edge, slot, index) {
@@ -420,25 +374,16 @@ void *BLI_edgehash_popkey(EdgeHash *eh, uint v0, uint v1)
}
}
-/**
- * Return boolean true/false if edge (v0,v1) in hash.
- */
bool BLI_edgehash_haskey(const EdgeHash *eh, uint v0, uint v1)
{
return edgehash_lookup_entry(eh, v0, v1) != NULL;
}
-/**
- * Return number of keys in hash.
- */
int BLI_edgehash_len(const EdgeHash *eh)
{
return (int)eh->length;
}
-/**
- * Remove all edges from hash.
- */
void BLI_edgehash_clear_ex(EdgeHash *eh, EdgeHashFreeFP free_value, const uint UNUSED(reserve))
{
/* TODO: handle reserve */
@@ -449,9 +394,6 @@ void BLI_edgehash_clear_ex(EdgeHash *eh, EdgeHashFreeFP free_value, const uint U
CLEAR_MAP(eh);
}
-/**
- * Wraps #BLI_edgehash_clear_ex with zero entries reserved.
- */
void BLI_edgehash_clear(EdgeHash *eh, EdgeHashFreeFP free_value)
{
BLI_edgehash_clear_ex(eh, free_value, 0);
@@ -463,11 +405,6 @@ void BLI_edgehash_clear(EdgeHash *eh, EdgeHashFreeFP free_value)
/** \name Edge Hash Iterator API
* \{ */
-/**
- * Create a new EdgeHashIterator. The hash table must not be mutated
- * while the iterator is in use, and the iterator will step exactly
- * BLI_edgehash_len(eh) times before becoming done.
- */
EdgeHashIterator *BLI_edgehashIterator_new(EdgeHash *eh)
{
EdgeHashIterator *ehi = MEM_mallocN(sizeof(EdgeHashIterator), __func__);
@@ -475,14 +412,6 @@ EdgeHashIterator *BLI_edgehashIterator_new(EdgeHash *eh)
return ehi;
}
-/**
- * Init an already allocated EdgeHashIterator. The hash table must not
- * be mutated while the iterator is in use, and the iterator will
- * step exactly BLI_edgehash_len(eh) times before becoming done.
- *
- * \param ehi: The EdgeHashIterator to initialize.
- * \param eh: The EdgeHash to iterate over.
- */
void BLI_edgehashIterator_init(EdgeHashIterator *ehi, EdgeHash *eh)
{
ehi->entries = eh->entries;
@@ -490,9 +419,6 @@ void BLI_edgehashIterator_init(EdgeHashIterator *ehi, EdgeHash *eh)
ehi->index = 0;
}
-/**
- * Free an EdgeHashIterator.
- */
void BLI_edgehashIterator_free(EdgeHashIterator *ehi)
{
MEM_freeN(ehi);
@@ -569,12 +495,6 @@ BLI_INLINE void edgeset_insert_at_slot(EdgeSet *es, uint slot, Edge edge)
es->length++;
}
-/**
- * A version of BLI_edgeset_insert which checks first if the key is in the set.
- * \returns true if a new key has been added.
- *
- * \note EdgeHash has no equivalent to this because typically the value would be different.
- */
bool BLI_edgeset_add(EdgeSet *es, uint v0, uint v1)
{
edgeset_ensure_can_insert(es);
@@ -591,10 +511,6 @@ bool BLI_edgeset_add(EdgeSet *es, uint v0, uint v1)
}
}
-/**
- * Adds the key to the set (no checks for unique keys!).
- * Matching #BLI_edgehash_insert
- */
void BLI_edgeset_insert(EdgeSet *es, uint v0, uint v1)
{
edgeset_ensure_can_insert(es);
diff --git a/source/blender/blenlib/intern/expr_pylike_eval.c b/source/blender/blenlib/intern/expr_pylike_eval.c
index 1acb8299aa2..c6be8836229 100644
--- a/source/blender/blenlib/intern/expr_pylike_eval.c
+++ b/source/blender/blenlib/intern/expr_pylike_eval.c
@@ -124,7 +124,6 @@ struct ExprPyLike_Parsed {
/** \name Public API
* \{ */
-/** Free the parsed data; NULL argument is ok. */
void BLI_expr_pylike_free(ExprPyLike_Parsed *expr)
{
if (expr != NULL) {
@@ -132,19 +131,16 @@ void BLI_expr_pylike_free(ExprPyLike_Parsed *expr)
}
}
-/** Check if the parsing result is valid for evaluation. */
bool BLI_expr_pylike_is_valid(ExprPyLike_Parsed *expr)
{
return expr != NULL && expr->ops_count > 0;
}
-/** Check if the parsed expression always evaluates to the same value. */
bool BLI_expr_pylike_is_constant(ExprPyLike_Parsed *expr)
{
return expr != NULL && expr->ops_count == 1 && expr->ops[0].opcode == OPCODE_CONST;
}
-/** Check if the parsed expression uses the parameter with the given index. */
bool BLI_expr_pylike_is_using_param(ExprPyLike_Parsed *expr, int index)
{
int i;
@@ -168,10 +164,6 @@ bool BLI_expr_pylike_is_using_param(ExprPyLike_Parsed *expr, int index)
/** \name Stack Machine Evaluation
* \{ */
-/**
- * Evaluate the expression with the given parameters.
- * The order and number of parameters must match the names given to parse.
- */
eExprPyLike_EvalStatus BLI_expr_pylike_eval(ExprPyLike_Parsed *expr,
const double *param_values,
int param_values_len,
@@ -1073,12 +1065,6 @@ static bool parse_expr(ExprParseState *state)
/** \name Main Parsing Function
* \{ */
-/**
- * Compile the expression and return the result.
- *
- * Parse the expression for evaluation later.
- * Returns non-NULL even on failure; use is_valid to check.
- */
ExprPyLike_Parsed *BLI_expr_pylike_parse(const char *expression,
const char **param_names,
int param_names_len)
diff --git a/source/blender/blenlib/intern/fileops.c b/source/blender/blenlib/intern/fileops.c
index c52feb097d2..838644054af 100644
--- a/source/blender/blenlib/intern/fileops.c
+++ b/source/blender/blenlib/intern/fileops.c
@@ -180,13 +180,6 @@ bool BLI_file_magic_is_zstd(const char header[4])
return false;
}
-/**
- * Returns true if the file with the specified name can be written.
- * This implementation uses access(2), which makes the check according
- * to the real UID and GID of the process, not its effective UID and GID.
- * This shouldn't matter for Blender, which is not going to run privileged
- * anyway.
- */
bool BLI_file_is_writable(const char *filename)
{
bool writable;
@@ -212,10 +205,6 @@ bool BLI_file_is_writable(const char *filename)
return writable;
}
-/**
- * Creates the file with nothing in it, or updates its last-modified date if it already exists.
- * Returns true if successful (like the unix touch command).
- */
bool BLI_file_touch(const char *file)
{
FILE *f = BLI_fopen(file, "r+b");
@@ -954,12 +943,6 @@ int BLI_access(const char *filename, int mode)
return access(filename, mode);
}
-/**
- * Deletes the specified file or directory (depending on dir), optionally
- * doing recursive delete of directory contents.
- *
- * \return zero on success (matching 'remove' behavior).
- */
int BLI_delete(const char *file, bool dir, bool recursive)
{
BLI_assert(!BLI_path_is_rel(file));
@@ -973,12 +956,6 @@ int BLI_delete(const char *file, bool dir, bool recursive)
return remove(file);
}
-/**
- * Soft deletes the specified file or directory (depending on dir) by moving the files to the
- * recycling bin, optionally doing recursive delete of directory contents.
- *
- * \return zero on success (matching 'remove' behavior).
- */
int BLI_delete_soft(const char *file, const char **error_message)
{
BLI_assert(!BLI_path_is_rel(file));
@@ -1251,7 +1228,6 @@ int BLI_create_symlink(const char *file, const char *to)
}
# endif
-/** \return true on success (i.e. given path now exists on FS), false otherwise. */
bool BLI_dir_create_recursive(const char *dirname)
{
char *lslash;
@@ -1301,9 +1277,6 @@ bool BLI_dir_create_recursive(const char *dirname)
return ret;
}
-/**
- * \return zero on success (matching 'rename' behavior).
- */
int BLI_rename(const char *from, const char *to)
{
if (!BLI_exists(from)) {
diff --git a/source/blender/blenlib/intern/filereader_zstd.c b/source/blender/blenlib/intern/filereader_zstd.c
index 55ce32713d9..5a04f5b11f3 100644
--- a/source/blender/blenlib/intern/filereader_zstd.c
+++ b/source/blender/blenlib/intern/filereader_zstd.c
@@ -331,5 +331,8 @@ FileReader *BLI_filereader_new_zstd(FileReader *base)
}
zstd->reader.close = zstd_close;
+ /* Rewind after the seek table check so that zstd_read starts at the file's start. */
+ zstd->base->seek(zstd->base, 0, SEEK_SET);
+
return (FileReader *)zstd;
}
diff --git a/source/blender/blenlib/intern/gsqueue.c b/source/blender/blenlib/intern/gsqueue.c
index ae34074e804..1bd99497432 100644
--- a/source/blender/blenlib/intern/gsqueue.c
+++ b/source/blender/blenlib/intern/gsqueue.c
@@ -101,9 +101,6 @@ static void queue_free_chunk(struct QueueChunk *data)
}
}
-/**
- * Free the queue's data and the queue itself
- */
void BLI_gsqueue_free(GSQueue *queue)
{
queue_free_chunk(queue->chunk_first);
@@ -111,14 +108,6 @@ void BLI_gsqueue_free(GSQueue *queue)
MEM_freeN(queue);
}
-/**
- * Copies the source value onto the end of the queue
- *
- * \note This copies #GSQueue.elem_size bytes from \a item,
- * (the pointer itself is not stored).
- *
- * \param item: source data to be copied to the queue.
- */
void BLI_gsqueue_push(GSQueue *queue, const void *item)
{
queue->chunk_last_index++;
@@ -153,12 +142,6 @@ void BLI_gsqueue_push(GSQueue *queue, const void *item)
memcpy(queue_get_last_elem(queue), item, queue->elem_size);
}
-/**
- * Retrieves and removes the first element from the queue.
- * The value is copies to \a r_item, which must be at least \a elem_size bytes.
- *
- * Does not reduce amount of allocated memory.
- */
void BLI_gsqueue_pop(GSQueue *queue, void *r_item)
{
BLI_assert(BLI_gsqueue_is_empty(queue) == false);
@@ -187,9 +170,6 @@ size_t BLI_gsqueue_len(const GSQueue *queue)
return queue->totelem;
}
-/**
- * Returns true if the queue is empty, false otherwise
- */
bool BLI_gsqueue_is_empty(const GSQueue *queue)
{
return (queue->chunk_first == NULL);
diff --git a/source/blender/blenlib/intern/hash_md5.c b/source/blender/blenlib/intern/hash_md5.c
index 3db1b7df0fa..6a0ca8bb33f 100644
--- a/source/blender/blenlib/intern/hash_md5.c
+++ b/source/blender/blenlib/intern/hash_md5.c
@@ -284,11 +284,6 @@ static void *md5_read_ctx(const struct md5_ctx *ctx, void *resbuf)
/* Top level public functions. */
-/**
- * Compute MD5 message digest for bytes read from 'stream'.
- * The resulting message digest number will be written into the 16 bytes beginning at 'resblock'.
- * \return Non-zero if an error occurred.
- */
int BLI_hash_md5_stream(FILE *stream, void *resblock)
{
#define BLOCKSIZE 4096 /* Important: must be a multiple of 64. */
@@ -362,11 +357,6 @@ int BLI_hash_md5_stream(FILE *stream, void *resblock)
return 0;
}
-/**
- * Compute MD5 message digest for 'len' bytes beginning at 'buffer'.
- * The result is always in little endian byte order,
- * so that a byte-wise output yields to the wanted ASCII representation of the message digest.
- */
void *BLI_hash_md5_buffer(const char *buffer, size_t len, void *resblock)
{
struct md5_ctx ctx;
diff --git a/source/blender/blenlib/intern/hash_mm2a.c b/source/blender/blenlib/intern/hash_mm2a.c
index 0899491cd0d..a98ae083fc8 100644
--- a/source/blender/blenlib/intern/hash_mm2a.c
+++ b/source/blender/blenlib/intern/hash_mm2a.c
@@ -110,7 +110,6 @@ uint32_t BLI_hash_mm2a_end(BLI_HashMurmur2A *mm2)
return mm2->hash;
}
-/* Non-incremental version, quicker for small keys. */
uint32_t BLI_hash_mm2(const unsigned char *data, size_t len, uint32_t seed)
{
/* Initialize the hash to a 'random' value */
diff --git a/source/blender/blenlib/intern/index_mask.cc b/source/blender/blenlib/intern/index_mask.cc
index cba985b8a44..a73e6caf313 100644
--- a/source/blender/blenlib/intern/index_mask.cc
+++ b/source/blender/blenlib/intern/index_mask.cc
@@ -18,21 +18,11 @@
namespace blender {
-/**
- * Create a sub-mask that is also shifted to the beginning. The shifting to the beginning allows
- * code to work with smaller indices, which is more memory efficient.
- *
- * \return New index mask with the size of #slice. It is either empty or starts with 0. It might
- * reference indices that have been appended to #r_new_indices.
- *
- * Example:
- * this: [2, 3, 5, 7, 8, 9, 10]
- * slice: ^--------^
- * output: [0, 2, 4, 5]
- *
- * All the indices in the sub-mask are shifted by 3 towards zero, so that the first index in the
- * output is zero.
- */
+IndexMask IndexMask::slice(IndexRange slice) const
+{
+ return IndexMask(indices_.slice(slice));
+}
+
IndexMask IndexMask::slice_and_offset(const IndexRange slice, Vector<int64_t> &r_new_indices) const
{
const int slice_size = slice.size();
diff --git a/source/blender/blenlib/intern/lasso_2d.c b/source/blender/blenlib/intern/lasso_2d.c
index a3b111cf0f2..ee10a233d39 100644
--- a/source/blender/blenlib/intern/lasso_2d.c
+++ b/source/blender/blenlib/intern/lasso_2d.c
@@ -65,7 +65,6 @@ bool BLI_lasso_is_point_inside(const int mcoords[][2],
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 mcoords[][2],
const unsigned int mcoords_len,
int x0,
diff --git a/source/blender/blenlib/intern/listbase.c b/source/blender/blenlib/intern/listbase.c
index 443bef42cc2..a166c846ea7 100644
--- a/source/blender/blenlib/intern/listbase.c
+++ b/source/blender/blenlib/intern/listbase.c
@@ -36,11 +36,6 @@
#include "BLI_strict_flags.h"
-/* implementation */
-
-/**
- * moves the entire contents of \a src onto the end of \a dst.
- */
void BLI_movelisttolist(ListBase *dst, ListBase *src)
{
if (src->first == NULL) {
@@ -59,9 +54,6 @@ void BLI_movelisttolist(ListBase *dst, ListBase *src)
src->first = src->last = NULL;
}
-/**
- * moves the entire contents of \a src at the beginning of \a dst.
- */
void BLI_movelisttolist_reverse(ListBase *dst, ListBase *src)
{
if (src->first == NULL) {
@@ -81,9 +73,6 @@ void BLI_movelisttolist_reverse(ListBase *dst, ListBase *src)
src->first = src->last = NULL;
}
-/**
- * Prepends \a vlink (assumed to begin with a Link) onto listbase.
- */
void BLI_addhead(ListBase *listbase, void *vlink)
{
Link *link = vlink;
@@ -104,9 +93,6 @@ void BLI_addhead(ListBase *listbase, void *vlink)
listbase->first = link;
}
-/**
- * Appends \a vlink (assumed to begin with a Link) onto listbase.
- */
void BLI_addtail(ListBase *listbase, void *vlink)
{
Link *link = vlink;
@@ -127,9 +113,6 @@ void BLI_addtail(ListBase *listbase, void *vlink)
listbase->last = link;
}
-/**
- * Removes \a vlink from \a listbase. Assumes it is linked into there!
- */
void BLI_remlink(ListBase *listbase, void *vlink)
{
Link *link = vlink;
@@ -153,9 +136,6 @@ void BLI_remlink(ListBase *listbase, void *vlink)
}
}
-/**
- * Checks that \a vlink is linked into listbase, removing it from there if so.
- */
bool BLI_remlink_safe(ListBase *listbase, void *vlink)
{
if (BLI_findindex(listbase, vlink) != -1) {
@@ -166,9 +146,6 @@ bool BLI_remlink_safe(ListBase *listbase, void *vlink)
return false;
}
-/**
- * Swaps \a vlinka and \a vlinkb in the list. Assumes they are both already in the list!
- */
void BLI_listbase_swaplinks(ListBase *listbase, void *vlinka, void *vlinkb)
{
Link *linka = vlinka;
@@ -222,10 +199,6 @@ void BLI_listbase_swaplinks(ListBase *listbase, void *vlinka, void *vlinkb)
}
}
-/**
- * Swaps \a vlinka and \a vlinkb from their respective lists.
- * Assumes they are both already in their \a listbasea!
- */
void BLI_listbases_swaplinks(ListBase *listbasea, ListBase *listbaseb, void *vlinka, void *vlinkb)
{
Link *linka = vlinka;
@@ -251,9 +224,6 @@ void BLI_listbases_swaplinks(ListBase *listbasea, ListBase *listbaseb, void *vli
BLI_remlink(listbasea, &linkc);
}
-/**
- * Removes the head from \a listbase and returns it.
- */
void *BLI_pophead(ListBase *listbase)
{
Link *link;
@@ -263,9 +233,6 @@ void *BLI_pophead(ListBase *listbase)
return link;
}
-/**
- * Removes the tail from \a listbase and returns it.
- */
void *BLI_poptail(ListBase *listbase)
{
Link *link;
@@ -275,9 +242,6 @@ void *BLI_poptail(ListBase *listbase)
return link;
}
-/**
- * Removes \a vlink from listbase and disposes of it. Assumes it is linked into there!
- */
void BLI_freelinkN(ListBase *listbase, void *vlink)
{
Link *link = vlink;
@@ -320,11 +284,6 @@ static void listbase_double_from_single(Link *iter, ListBase *listbase)
#undef SORT_IMPL_LINKTYPE
-/**
- * Sorts the elements of listbase into the order defined by cmp
- * (which should return 1 if its first arg should come after its second arg).
- * This uses insertion sort, so NOT ok for large list.
- */
void BLI_listbase_sort(ListBase *listbase, int (*cmp)(const void *, const void *))
{
if (listbase->first != listbase->last) {
@@ -345,10 +304,6 @@ void BLI_listbase_sort_r(ListBase *listbase,
}
}
-/**
- * Inserts \a vnewlink immediately following \a vprevlink in \a listbase.
- * Or, if \a vprevlink is NULL, puts \a vnewlink at the front of the list.
- */
void BLI_insertlinkafter(ListBase *listbase, void *vprevlink, void *vnewlink)
{
Link *prevlink = vprevlink;
@@ -388,10 +343,6 @@ void BLI_insertlinkafter(ListBase *listbase, void *vprevlink, void *vnewlink)
}
}
-/**
- * Inserts \a vnewlink immediately preceding \a vnextlink in listbase.
- * Or, if \a vnextlink is NULL, puts \a vnewlink at the end of the list.
- */
void BLI_insertlinkbefore(ListBase *listbase, void *vnextlink, void *vnewlink)
{
Link *nextlink = vnextlink;
@@ -431,13 +382,6 @@ void BLI_insertlinkbefore(ListBase *listbase, void *vnextlink, void *vnewlink)
}
}
-/**
- * Insert a link in place of another, without changing its position in the list.
- *
- * Puts `vnewlink` in the position of `vreplacelink`, removing `vreplacelink`.
- * - `vreplacelink` *must* be in the list.
- * - `vnewlink` *must not* be in the list.
- */
void BLI_insertlinkreplace(ListBase *listbase, void *vreplacelink, void *vnewlink)
{
Link *l_old = vreplacelink;
@@ -464,14 +408,6 @@ void BLI_insertlinkreplace(ListBase *listbase, void *vreplacelink, void *vnewlin
}
}
-/**
- * Reinsert \a vlink relative to its current position but offset by \a step. Doesn't move
- * item if new position would exceed list (could optionally move to head/tail).
- *
- * \param step: Absolute value defines step size, sign defines direction. E.g pass -1
- * to move \a vlink before previous, or 1 to move behind next.
- * \return If position of \a vlink has changed.
- */
bool BLI_listbase_link_move(ListBase *listbase, void *vlink, int step)
{
Link *link = vlink;
@@ -503,11 +439,6 @@ bool BLI_listbase_link_move(ListBase *listbase, void *vlink, int step)
return true;
}
-/**
- * Move the link at the index \a from to the position at index \a to.
- *
- * \return If the move was successful.
- */
bool BLI_listbase_move_index(ListBase *listbase, int from, int to)
{
if (from == to) {
@@ -524,9 +455,6 @@ bool BLI_listbase_move_index(ListBase *listbase, int from, int to)
return BLI_listbase_link_move(listbase, link, to - from);
}
-/**
- * Removes and disposes of the entire contents of listbase using direct free(3).
- */
void BLI_freelist(ListBase *listbase)
{
Link *link, *next;
@@ -541,9 +469,6 @@ void BLI_freelist(ListBase *listbase)
BLI_listbase_clear(listbase);
}
-/**
- * Removes and disposes of the entire contents of \a listbase using guardedalloc.
- */
void BLI_freelistN(ListBase *listbase)
{
Link *link, *next;
@@ -558,11 +483,6 @@ void BLI_freelistN(ListBase *listbase)
BLI_listbase_clear(listbase);
}
-/**
- * Returns the number of elements in \a listbase, up until (and including count_max)
- *
- * \note Use to avoid redundant looping.
- */
int BLI_listbase_count_at_most(const ListBase *listbase, const int count_max)
{
Link *link;
@@ -575,9 +495,6 @@ int BLI_listbase_count_at_most(const ListBase *listbase, const int count_max)
return count;
}
-/**
- * Returns the number of elements in \a listbase.
- */
int BLI_listbase_count(const ListBase *listbase)
{
Link *link;
@@ -590,9 +507,6 @@ int BLI_listbase_count(const ListBase *listbase)
return count;
}
-/**
- * Returns the nth element of \a listbase, numbering from 0.
- */
void *BLI_findlink(const ListBase *listbase, int number)
{
Link *link = NULL;
@@ -608,9 +522,6 @@ void *BLI_findlink(const ListBase *listbase, int number)
return link;
}
-/**
- * Returns the nth-last element of \a listbase, numbering from 0.
- */
void *BLI_rfindlink(const ListBase *listbase, int number)
{
Link *link = NULL;
@@ -626,9 +537,6 @@ void *BLI_rfindlink(const ListBase *listbase, int number)
return link;
}
-/**
- * Returns the position of \a vlink within \a listbase, numbering from 0, or -1 if not found.
- */
int BLI_findindex(const ListBase *listbase, const void *vlink)
{
Link *link = NULL;
@@ -651,10 +559,6 @@ int BLI_findindex(const ListBase *listbase, const void *vlink)
return -1;
}
-/**
- * Finds the first element of \a listbase which contains the null-terminated
- * string \a id at the specified offset, returning NULL if not found.
- */
void *BLI_findstring(const ListBase *listbase, const char *id, const int offset)
{
Link *link = NULL;
@@ -674,13 +578,10 @@ void *BLI_findstring(const ListBase *listbase, const char *id, const int offset)
return NULL;
}
-/* same as above but find reverse */
-/**
- * Finds the last element of \a listbase which contains the
- * null-terminated string \a id at the specified offset, returning NULL if not found.
- */
void *BLI_rfindstring(const ListBase *listbase, const char *id, const int offset)
{
+ /* Same as #BLI_findstring but find reverse. */
+
Link *link = NULL;
const char *id_iter;
@@ -695,10 +596,6 @@ void *BLI_rfindstring(const ListBase *listbase, const char *id, const int offset
return NULL;
}
-/**
- * Finds the first element of \a listbase which contains a pointer to the
- * null-terminated string \a id at the specified offset, returning NULL if not found.
- */
void *BLI_findstring_ptr(const ListBase *listbase, const char *id, const int offset)
{
Link *link = NULL;
@@ -715,13 +612,10 @@ void *BLI_findstring_ptr(const ListBase *listbase, const char *id, const int off
return NULL;
}
-/* same as above but find reverse */
-/**
- * Finds the last element of \a listbase which contains a pointer to the
- * null-terminated string \a id at the specified offset, returning NULL if not found.
- */
void *BLI_rfindstring_ptr(const ListBase *listbase, const char *id, const int offset)
{
+ /* Same as #BLI_findstring_ptr but find reverse. */
+
Link *link = NULL;
const char *id_iter;
@@ -737,10 +631,6 @@ void *BLI_rfindstring_ptr(const ListBase *listbase, const char *id, const int of
return NULL;
}
-/**
- * Finds the first element of listbase which contains the specified pointer value
- * at the specified offset, returning NULL if not found.
- */
void *BLI_findptr(const ListBase *listbase, const void *ptr, const int offset)
{
Link *link = NULL;
@@ -757,13 +647,10 @@ void *BLI_findptr(const ListBase *listbase, const void *ptr, const int offset)
return NULL;
}
-/* same as above but find reverse */
-/**
- * Finds the last element of listbase which contains the specified pointer value
- * at the specified offset, returning NULL if not found.
- */
void *BLI_rfindptr(const ListBase *listbase, const void *ptr, const int offset)
{
+ /* Same as #BLI_findptr but find reverse. */
+
Link *link = NULL;
const void *ptr_iter;
@@ -779,10 +666,6 @@ void *BLI_rfindptr(const ListBase *listbase, const void *ptr, const int offset)
return NULL;
}
-/**
- * Finds the first element of listbase which contains the specified bytes
- * at the specified offset, returning NULL if not found.
- */
void *BLI_listbase_bytes_find(const ListBase *listbase,
const void *bytes,
const size_t bytes_size,
@@ -801,16 +684,13 @@ void *BLI_listbase_bytes_find(const ListBase *listbase,
return NULL;
}
-/* same as above but find reverse */
-/**
- * Finds the last element of listbase which contains the specified bytes
- * at the specified offset, returning NULL if not found.
- */
void *BLI_listbase_bytes_rfind(const ListBase *listbase,
const void *bytes,
const size_t bytes_size,
const int offset)
{
+ /* Same as #BLI_listbase_bytes_find but find reverse. */
+
Link *link = NULL;
const void *ptr_iter;
@@ -825,13 +705,6 @@ void *BLI_listbase_bytes_rfind(const ListBase *listbase,
return NULL;
}
-/**
- * Find the first item in the list that matches the given string, or the given index as fallback.
- *
- * \note The string is only used is non-NULL and non-empty.
- *
- * \return The found item, or NULL.
- */
void *BLI_listbase_string_or_index_find(const ListBase *listbase,
const char *string,
const size_t string_offset,
@@ -856,10 +729,6 @@ void *BLI_listbase_string_or_index_find(const ListBase *listbase,
return link_at_index;
}
-/**
- * Returns the 0-based index of the first element of listbase which contains the specified
- * null-terminated string at the specified offset, or -1 if not found.
- */
int BLI_findstringindex(const ListBase *listbase, const char *id, const int offset)
{
Link *link = NULL;
@@ -880,9 +749,6 @@ int BLI_findstringindex(const ListBase *listbase, const char *id, const int offs
return -1;
}
-/**
- * Sets dst to a duplicate of the entire contents of src. dst may be the same as src.
- */
void BLI_duplicatelist(ListBase *dst, const ListBase *src)
{
struct Link *dst_link, *src_link;
@@ -918,9 +784,6 @@ void BLI_listbase_reverse(ListBase *lb)
lb->last = curr;
}
-/**
- * \param vlink: Link to make first.
- */
void BLI_listbase_rotate_first(ListBase *lb, void *vlink)
{
/* make circular */
@@ -934,9 +797,6 @@ void BLI_listbase_rotate_first(ListBase *lb, void *vlink)
((Link *)lb->last)->next = NULL;
}
-/**
- * \param vlink: Link to make last.
- */
void BLI_listbase_rotate_last(ListBase *lb, void *vlink)
{
/* make circular */
@@ -950,7 +810,6 @@ void BLI_listbase_rotate_last(ListBase *lb, void *vlink)
((Link *)lb->last)->next = NULL;
}
-/* create a generic list node containing link to provided data */
LinkData *BLI_genericNodeN(void *data)
{
LinkData *ld;
diff --git a/source/blender/blenlib/intern/math_base.c b/source/blender/blenlib/intern/math_base.c
index 1137c4114a5..be70acf622a 100644
--- a/source/blender/blenlib/intern/math_base.c
+++ b/source/blender/blenlib/intern/math_base.c
@@ -42,10 +42,10 @@ int pow_i(int base, int exp)
return result;
}
-/* from python 3.1 floatobject.c
- * ndigits must be between 0 and 21 */
double double_round(double x, int ndigits)
{
+ /* From Python 3.1 `floatobject.c`. */
+
double pow1, pow2, y, z;
if (ndigits >= 0) {
pow1 = pow(10.0, (double)ndigits);
@@ -79,15 +79,6 @@ double double_round(double x, int ndigits)
return z;
}
-/**
- * Floor to the nearest power of 10, e.g.:
- * - 15.0 -> 10.0
- * - 0.015 -> 0.01
- * - 1.0 -> 1.0
- *
- * \param f: Value to floor, must be over 0.0.
- * \note If we wanted to support signed values we could if this becomes necessary.
- */
float floor_power_of_10(float f)
{
BLI_assert(!(f < 0.0f));
@@ -97,15 +88,6 @@ float floor_power_of_10(float f)
return 0.0f;
}
-/**
- * Ceiling to the nearest power of 10, e.g.:
- * - 15.0 -> 100.0
- * - 0.015 -> 0.1
- * - 1.0 -> 1.0
- *
- * \param f: Value to ceiling, must be over 0.0.
- * \note If we wanted to support signed values we could if this becomes necessary.
- */
float ceil_power_of_10(float f)
{
BLI_assert(!(f < 0.0f));
diff --git a/source/blender/blenlib/intern/math_base_inline.c b/source/blender/blenlib/intern/math_base_inline.c
index f609d5f8e8b..53cf2d61963 100644
--- a/source/blender/blenlib/intern/math_base_inline.c
+++ b/source/blender/blenlib/intern/math_base_inline.c
@@ -45,7 +45,6 @@ extern "C" {
# define UNLIKELY(x) (x)
#endif
-/* powf is really slow for raising to integer powers. */
MINLINE float pow2f(float x)
{
return x * x;
@@ -192,21 +191,18 @@ MINLINE double ratiod(double min, double max, double pos)
return range == 0 ? 0 : ((pos - min) / range);
}
-/* Map a normalized value, i.e. from interval [0, 1] to interval [a, b]. */
MINLINE float scalenorm(float a, float b, float x)
{
BLI_assert(x <= 1 && x >= 0);
return (x * (b - a)) + a;
}
-/* Map a normalized value, i.e. from interval [0, 1] to interval [a, b]. */
MINLINE double scalenormd(double a, double b, double x)
{
BLI_assert(x <= 1 && x >= 0);
return (x * (b - a)) + a;
}
-/* Used for zoom values. */
MINLINE float power_of_2(float val)
{
return (float)pow(2.0, ceil(log((double)val) / M_LN2));
@@ -363,16 +359,11 @@ MINLINE signed char round_db_to_char_clamp(double a){
#undef _round_clamp_fl_impl
#undef _round_clamp_db_impl
-/**
- * Round to closest even number, halfway cases are rounded away from zero.
- */
MINLINE float round_to_even(float f)
{
return roundf(f * 0.5f) * 2.0f;
}
-/* integer division that rounds 0.5 up, particularly useful for color blending
- * with integers, to avoid gradual darkening when rounding down */
MINLINE int divide_round_i(int a, int b)
{
return (2 * a + b) / (2 * b);
@@ -397,9 +388,6 @@ MINLINE uint divide_ceil_u(uint a, uint b)
return (a + b - 1) / b;
}
-/**
- * modulo that handles negative numbers, works the same as Python's.
- */
MINLINE int mod_i(int i, int n)
{
return (i % n + n) % n;
@@ -629,27 +617,11 @@ MINLINE size_t clamp_z(size_t value, size_t min, size_t max)
return min_zz(max_zz(value, min), max);
}
-/**
- * Almost-equal for IEEE floats, using absolute difference method.
- *
- * \param max_diff: the maximum absolute difference.
- */
MINLINE int compare_ff(float a, float b, const float max_diff)
{
return fabsf(a - b) <= max_diff;
}
-/**
- * Almost-equal for IEEE floats, using their integer representation
- * (mixing ULP and absolute difference methods).
- *
- * \param max_diff: is the maximum absolute difference (allows to take care of the near-zero area,
- * where relative difference methods cannot really work).
- * \param max_ulps: is the 'maximum number of floats + 1'
- * allowed between \a a and \a b to consider them equal.
- *
- * \see https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
- */
MINLINE int compare_ff_relative(float a, float b, const float max_diff, const int max_ulps)
{
union {
@@ -728,19 +700,11 @@ MINLINE int signum_i(float a)
}
}
-/**
- * Returns number of (base ten) *significant* digits of integer part of given float
- * (negative in case of decimal-only floats, 0.01 returns -1 e.g.).
- */
MINLINE int integer_digits_f(const float f)
{
return (f == 0.0f) ? 0 : (int)floor(log10(fabs(f))) + 1;
}
-/**
- * Returns number of (base ten) *significant* digits of integer part of given double
- * (negative in case of decimal-only floats, 0.01 returns -1 e.g.).
- */
MINLINE int integer_digits_d(const double d)
{
return (d == 0.0) ? 0 : (int)floor(log10(fabs(d))) + 1;
diff --git a/source/blender/blenlib/intern/math_boolean.cc b/source/blender/blenlib/intern/math_boolean.cc
index 6d4806a3fbc..c16755868aa 100644
--- a/source/blender/blenlib/intern/math_boolean.cc
+++ b/source/blender/blenlib/intern/math_boolean.cc
@@ -33,10 +33,6 @@
namespace blender {
#ifdef WITH_GMP
-/**
- * Return +1 if a, b, c are in CCW order around a circle in the plane.
- * Return -1 if they are in CW order, and 0 if they are in line.
- */
int orient2d(const mpq2 &a, const mpq2 &b, const mpq2 &c)
{
mpq_class detleft = (a[0] - c[0]) * (b[1] - c[1]);
@@ -45,11 +41,6 @@ int orient2d(const mpq2 &a, const mpq2 &b, const mpq2 &c)
return sgn(det);
}
-/**
- Return +1 if d is in the oriented circle through a, b, and c.
- * The oriented circle goes CCW through a, b, and c.
- * Return -1 if d is outside, and 0 if it is on the circle.
- */
int incircle(const mpq2 &a, const mpq2 &b, const mpq2 &c, const mpq2 &d)
{
mpq_class adx = a[0] - d[0];
@@ -76,12 +67,6 @@ int incircle(const mpq2 &a, const mpq2 &b, const mpq2 &c, const mpq2 &d)
return sgn(det);
}
-/**
- * Return +1 if d is below the plane containing a, b, c (which appear
- * CCW when viewed from above the plane).
- * Return -1 if d is above the plane.
- * Return 0 if it is on the plane.
- */
int orient3d(const mpq3 &a, const mpq3 &b, const mpq3 &c, const mpq3 &d)
{
mpq_class adx = a[0] - d[0];
diff --git a/source/blender/blenlib/intern/math_color.c b/source/blender/blenlib/intern/math_color.c
index 14eb78648e0..5e52873649e 100644
--- a/source/blender/blenlib/intern/math_color.c
+++ b/source/blender/blenlib/intern/math_color.c
@@ -64,13 +64,11 @@ void hsl_to_rgb(float h, float s, float l, float *r_r, float *r_g, float *r_b)
*r_b = (nb - 0.5f) * chroma + l;
}
-/* convenience function for now */
void hsv_to_rgb_v(const float hsv[3], float r_rgb[3])
{
hsv_to_rgb(hsv[0], hsv[1], hsv[2], &r_rgb[0], &r_rgb[1], &r_rgb[2]);
}
-/* convenience function for now */
void hsl_to_rgb_v(const float hsl[3], float r_rgb[3])
{
hsl_to_rgb(hsl[0], hsl[1], hsl[2], &r_rgb[0], &r_rgb[1], &r_rgb[2]);
@@ -124,9 +122,6 @@ void yuv_to_rgb(float y, float u, float v, float *r_r, float *r_g, float *r_b, i
*r_b = b;
}
-/* The RGB inputs are supposed gamma corrected and in the range 0 - 1.0f
- *
- * Output YCC have a range of 16-235 and 16-240 except with JFIF_0_255 where the range is 0-255 */
void rgb_to_ycc(float r, float g, float b, float *r_y, float *r_cb, float *r_cr, int colorspace)
{
float sr, sg, sb;
@@ -162,12 +157,14 @@ void rgb_to_ycc(float r, float g, float b, float *r_y, float *r_cb, float *r_cr,
*r_cr = cr;
}
-/* YCC input have a range of 16-235 and 16-240 except with JFIF_0_255 where the range is 0-255 */
-/* RGB outputs are in the range 0 - 1.0f */
-
-/* FIXME comment above must be wrong because BLI_YCC_ITU_BT601 y 16.0 cr 16.0 -> r -0.7009 */
void ycc_to_rgb(float y, float cb, float cr, float *r_r, float *r_g, float *r_b, int colorspace)
{
+ /* FIXME the following comment must be wrong because:
+ * BLI_YCC_ITU_BT601 y 16.0 cr 16.0 -> r -0.7009. */
+
+ /* YCC input have a range of 16-235 and 16-240 except with JFIF_0_255 where the range is 0-255
+ * RGB outputs are in the range 0 - 1.0f. */
+
float r = 128.0f, g = 128.0f, b = 128.0f;
switch (colorspace) {
@@ -250,7 +247,6 @@ void rgb_to_hsv(float r, float g, float b, float *r_h, float *r_s, float *r_v)
*r_v = r;
}
-/* convenience function for now */
void rgb_to_hsv_v(const float rgb[3], float r_hsv[3])
{
rgb_to_hsv(rgb[0], rgb[1], rgb[2], &r_hsv[0], &r_hsv[1], &r_hsv[2]);
@@ -311,7 +307,6 @@ void rgb_to_hsl_compat_v(const float rgb[3], float r_hsl[3])
rgb_to_hsl_compat(rgb[0], rgb[1], rgb[2], &r_hsl[0], &r_hsl[1], &r_hsl[2]);
}
-/* convenience function for now */
void rgb_to_hsl_v(const float rgb[3], float r_hsl[3])
{
rgb_to_hsl(rgb[0], rgb[1], rgb[2], &r_hsl[0], &r_hsl[1], &r_hsl[2]);
@@ -338,13 +333,11 @@ void rgb_to_hsv_compat(float r, float g, float b, float *r_h, float *r_s, float
}
}
-/* convenience function for now */
void rgb_to_hsv_compat_v(const float rgb[3], float r_hsv[3])
{
rgb_to_hsv_compat(rgb[0], rgb[1], rgb[2], &r_hsv[0], &r_hsv[1], &r_hsv[2]);
}
-/* clamp hsv to usable values */
void hsv_clamp_v(float hsv[3], float v_max)
{
if (UNLIKELY(hsv[0] < 0.0f || hsv[0] > 1.0f)) {
@@ -354,12 +347,6 @@ void hsv_clamp_v(float hsv[3], float v_max)
CLAMP(hsv[2], 0.0f, v_max);
}
-/**
- * We define a 'cpack' here as a (3 byte color code)
- * number that can be expressed like 0xFFAA66 or so.
- * For that reason it is sensitive for endianness... with this function it works correctly.
- * \see #imm_cpack
- */
unsigned int hsv_to_cpack(float h, float s, float v)
{
unsigned int r, g, b;
@@ -473,12 +460,6 @@ void minmax_rgb(short c[3])
}
}
-/* If the requested RGB shade contains a negative weight for
- * one of the primaries, it lies outside the color gamut
- * accessible from the given triple of primaries. Desaturate
- * it by adding white, equal quantities of R, G, and B, enough
- * to make RGB all positive. The function returns 1 if the
- * components were modified, zero otherwise. */
int constrain_rgb(float *r, float *g, float *b)
{
/* Amount of white needed */
@@ -520,7 +501,6 @@ void lift_gamma_gain_to_asc_cdl(const float *lift,
/* ************************************* other ************************************************* */
-/* Applies an hue offset to a float rgb color */
void rgb_float_set_hue_float_offset(float rgb[3], float hue_offset)
{
float hsv[3];
@@ -538,7 +518,6 @@ void rgb_float_set_hue_float_offset(float rgb[3], float hue_offset)
hsv_to_rgb(hsv[0], hsv[1], hsv[2], rgb, rgb + 1, rgb + 2);
}
-/* Applies an hue offset to a byte rgb color */
void rgb_byte_set_hue_float_offset(unsigned char rgb[3], float hue_offset)
{
float rgb_float[3];
diff --git a/source/blender/blenlib/intern/math_color_inline.c b/source/blender/blenlib/intern/math_color_inline.c
index 24c4143e587..febe1568176 100644
--- a/source/blender/blenlib/intern/math_color_inline.c
+++ b/source/blender/blenlib/intern/math_color_inline.c
@@ -271,20 +271,6 @@ MINLINE void cpack_cpy_3ub(unsigned char r_col[3], const unsigned int pack)
*
* \{ */
-/**
- * ITU-R BT.709 primaries
- * https://en.wikipedia.org/wiki/Relative_luminance
- *
- * Real values are:
- * `Y = 0.2126390059(R) + 0.7151686788(G) + 0.0721923154(B)`
- * according to: "Derivation of Basic Television Color Equations", RP 177-1993
- *
- * As this sums slightly above 1.0, the document recommends to use:
- * `0.2126(R) + 0.7152(G) + 0.0722(B)`, as used here.
- *
- * The high precision values are used to calculate the rounded byte weights so they add up to 255:
- * `54(R) + 182(G) + 19(B)`
- */
MINLINE float rgb_to_grayscale(const float rgb[3])
{
return (0.2126f * rgb[0]) + (0.7152f * rgb[1]) + (0.0722f * rgb[2]);
@@ -317,11 +303,11 @@ MINLINE int compare_rgb_uchar(const unsigned char col_a[3],
return 0;
}
-/* Using a triangle distribution which gives a more final uniform noise.
- * See Banding in Games:A Noisy Rant(revision 5) Mikkel Gjøl, Playdead (slide 27) */
-/* Return triangle noise in [-0.5..1.5[ range */
MINLINE float dither_random_value(float s, float t)
{
+ /* Using a triangle distribution which gives a more final uniform noise.
+ * See Banding in Games:A Noisy Rant(revision 5) Mikkel Gjøl, Playdead (slide 27) */
+
/* Uniform noise in [0..1[ range, using common GLSL hash function.
* https://stackoverflow.com/questions/12964279/whats-the-origin-of-this-glsl-rand-one-liner. */
float hash0 = sinf(s * 12.9898f + t * 78.233f) * 43758.5453f;
diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c
index 8afb6b5a2be..a155877513a 100644
--- a/source/blender/blenlib/intern/math_geom.c
+++ b/source/blender/blenlib/intern/math_geom.c
@@ -86,11 +86,6 @@ float normal_quad_v3(
return normalize_v3(n);
}
-/**
- * Computes the normal of a planar
- * polygon See Graphics Gems for
- * computing newell normal.
- */
float normal_poly_v3(float n[3], const float verts[][3], unsigned int nr)
{
cross_poly_v3(n, verts, nr);
@@ -112,7 +107,6 @@ float area_squared_quad_v3(const float v1[3],
return area_squared_poly_v3(verts, 4);
}
-/* Triangles */
float area_tri_v3(const float v1[3], const float v2[3], const float v3[3])
{
float n[3];
@@ -162,12 +156,6 @@ float area_squared_poly_v3(const float verts[][3], unsigned int nr)
return len_squared_v3(n);
}
-/**
- * Scalar cross product of a 2d polygon.
- *
- * - equivalent to `area * 2`
- * - useful for checking polygon winding (a positive value is clockwise).
- */
float cross_poly_v2(const float verts[][2], unsigned int nr)
{
unsigned int a;
@@ -236,28 +224,18 @@ float cotangent_tri_weight_v3(const float v1[3], const float v2[3], const float
/********************************* Planes **********************************/
-/**
- * Calculate a plane from a point and a direction,
- * \note \a point_no isn't required to be normalized.
- */
void plane_from_point_normal_v3(float r_plane[4], const float plane_co[3], const float plane_no[3])
{
copy_v3_v3(r_plane, plane_no);
r_plane[3] = -dot_v3v3(r_plane, plane_co);
}
-/**
- * Get a point and a direction from a plane.
- */
void plane_to_point_vector_v3(const float plane[4], float r_plane_co[3], float r_plane_no[3])
{
mul_v3_v3fl(r_plane_co, plane, (-plane[3] / len_squared_v3(plane)));
copy_v3_v3(r_plane_no, plane);
}
-/**
- * version of #plane_to_point_vector_v3 that gets a unit length vector.
- */
void plane_to_point_vector_v3_normalized(const float plane[4],
float r_plane_co[3],
float r_plane_no[3])
@@ -268,9 +246,6 @@ void plane_to_point_vector_v3_normalized(const float plane[4],
/********************************* Volume **********************************/
-/**
- * The volume from a tetrahedron, points can be in any order
- */
float volume_tetrahedron_v3(const float v1[3],
const float v2[3],
const float v3[3],
@@ -283,9 +258,6 @@ float volume_tetrahedron_v3(const float v1[3],
return fabsf(determinant_m3_array(m)) / 6.0f;
}
-/**
- * The volume from a tetrahedron, normal pointing inside gives negative volume
- */
float volume_tetrahedron_signed_v3(const float v1[3],
const float v2[3],
const float v3[3],
@@ -298,12 +270,6 @@ float volume_tetrahedron_signed_v3(const float v1[3],
return determinant_m3_array(m) / 6.0f;
}
-/**
- * The volume from a triangle that is made into a tetrahedron.
- * This uses a simplified formula where the tip of the tetrahedron is in the world origin.
- * Using this method, the total volume of a closed triangle mesh can be calculated.
- * Note that you need to divide the result by 6 to get the actual volume.
- */
float volume_tri_tetrahedron_signed_v3_6x(const float v1[3], const float v2[3], const float v3[3])
{
float v_cross[3];
@@ -319,8 +285,6 @@ float volume_tri_tetrahedron_signed_v3(const float v1[3], const float v2[3], con
/********************************* Distance **********************************/
-/* distance p to line v1-v2
- * using Hesse formula, NO LINE PIECE! */
float dist_squared_to_line_v2(const float p[2], const float l1[2], const float l2[2])
{
float closest[2];
@@ -334,7 +298,6 @@ float dist_to_line_v2(const float p[2], const float l1[2], const float l2[2])
return sqrtf(dist_squared_to_line_v2(p, l1, l2));
}
-/* distance p to line-piece v1-v2 */
float dist_squared_to_line_segment_v2(const float p[2], const float l1[2], const float l2[2])
{
float closest[2];
@@ -349,7 +312,6 @@ float dist_to_line_segment_v2(const float p[2], const float l1[2], const float l
return sqrtf(dist_squared_to_line_segment_v2(p, l1, l2));
}
-/* point closest to v1 on line v2-v3 in 2D */
void closest_to_line_segment_v2(float r_close[2],
const float p[2],
const float l1[2],
@@ -371,7 +333,6 @@ void closest_to_line_segment_v2(float r_close[2],
}
}
-/* point closest to v1 on line v2-v3 in 3D */
void closest_to_line_segment_v3(float r_close[3],
const float p[3],
const float l1[3],
@@ -393,15 +354,6 @@ void closest_to_line_segment_v3(float r_close[3],
}
}
-/**
- * Find the closest point on a plane.
- *
- * \param r_close: Return coordinate
- * \param plane: The plane to test against.
- * \param pt: The point to find the nearest of
- *
- * \note non-unit-length planes are supported.
- */
void closest_to_plane_v3(float r_close[3], const float plane[4], const float pt[3])
{
const float len_sq = len_squared_v3(plane);
@@ -462,9 +414,6 @@ float dist_squared_to_plane3_v3(const float pt[3], const float plane[3])
return len_sq * (fac * fac);
}
-/**
- * Return the signed distance from the point to the plane.
- */
float dist_signed_to_plane_v3(const float pt[3], const float plane[4])
{
const float len_sq = len_squared_v3(plane);
@@ -489,7 +438,6 @@ float dist_to_plane3_v3(const float pt[3], const float plane[3])
return fabsf(dist_signed_to_plane3_v3(pt, plane));
}
-/* distance v1 to line-piece l1-l2 in 3D */
float dist_squared_to_line_segment_v3(const float p[3], const float l1[3], const float l2[3])
{
float closest[3];
@@ -517,29 +465,6 @@ float dist_to_line_v3(const float p[3], const float l1[3], const float l2[3])
return sqrtf(dist_squared_to_line_v3(p, l1, l2));
}
-/**
- * Check if \a p is inside the 2x planes defined by `(v1, v2, v3)`
- * where the 3x points define 2x planes.
- *
- * \param axis_ref: used when v1,v2,v3 form a line and to check if the corner is concave/convex.
- *
- * \note the distance from \a v1 & \a v3 to \a v2 doesn't matter
- * (it just defines the planes).
- *
- * \return the lowest squared distance to either of the planes.
- * where `(return < 0.0)` is outside.
- *
- * <pre>
- * v1
- * +
- * /
- * x - out / x - inside
- * /
- * +----+
- * v2 v3
- * x - also outside
- * </pre>
- */
float dist_signed_squared_to_corner_v3v3v3(const float p[3],
const float v1[3],
const float v2[3],
@@ -591,12 +516,6 @@ float dist_signed_squared_to_corner_v3v3v3(const float p[3],
return max_ff(dist_a, dist_b);
}
-/**
- * Compute the squared distance of a point to a line (defined as ray).
- * \param ray_origin: A point on the line.
- * \param ray_direction: Normalized direction of the line.
- * \param co: Point to which the distance is to be calculated.
- */
float dist_squared_to_ray_v3_normalized(const float ray_origin[3],
const float ray_direction[3],
const float co[3])
@@ -613,12 +532,6 @@ float dist_squared_to_ray_v3_normalized(const float ray_origin[3],
return len_squared_v3v3(co, co_projected_on_ray);
}
-/**
- * Find the closest point in a seg to a ray and return the distance squared.
- * \param r_point: Is the point on segment closest to ray
- * (or to ray_origin if the ray and the segment are parallel).
- * \param r_depth: the distance of r_point projection on ray to the ray_origin.
- */
float dist_squared_ray_to_seg_v3(const float ray_origin[3],
const float ray_direction[3],
const float v0[3],
@@ -655,8 +568,6 @@ float dist_squared_ray_to_seg_v3(const float ray_origin[3],
return len_squared_v3(dvec) - square_f(depth);
}
-/* Returns the coordinates of the nearest vertex and
- * the farthest vertex from a plane (or normal). */
void aabb_get_near_far_from_plane(const float plane_no[3],
const float bbmin[3],
const float bbmax[3],
@@ -707,9 +618,6 @@ void dist_squared_ray_to_aabb_v3_precalc(struct DistRayAABB_Precalc *neasrest_pr
}
}
-/**
- * Returns the distance from a ray to a bound-box (projected on ray)
- */
float dist_squared_ray_to_aabb_v3(const struct DistRayAABB_Precalc *data,
const float bb_min[3],
const float bb_max[3],
@@ -810,16 +718,13 @@ float dist_squared_ray_to_aabb_v3_simple(const float ray_origin[3],
dist_squared_ray_to_aabb_v3_precalc(&data, ray_origin, ray_direction);
return dist_squared_ray_to_aabb_v3(&data, bb_min, bb_max, r_point, r_depth);
}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name dist_squared_to_projected_aabb and helpers
* \{ */
-/**
- * \param projmat: Projection Matrix (usually perspective
- * matrix multiplied by object matrix).
- */
void dist_squared_to_projected_aabb_precalc(struct DistProjectedAABBPrecalc *precalc,
const float projmat[4][4],
const float winsize[2],
@@ -871,7 +776,6 @@ void dist_squared_to_projected_aabb_precalc(struct DistProjectedAABBPrecalc *pre
}
}
-/* Returns the distance from a 2d coordinate to a BoundBox (Projected) */
float dist_squared_to_projected_aabb(struct DistProjectedAABBPrecalc *data,
const float bbmin[3],
const float bbmax[3],
@@ -1014,15 +918,15 @@ float dist_squared_to_projected_aabb_simple(const float projmat[4][4],
bool dummy[3] = {true, true, true};
return dist_squared_to_projected_aabb(&data, bbmin, bbmax, dummy);
}
+
/** \} */
-/* Adapted from "Real-Time Collision Detection" by Christer Ericson,
- * published by Morgan Kaufmann Publishers, copyright 2005 Elsevier Inc.
- *
- * Set 'r' to the point in triangle (a, b, c) closest to point 'p' */
void closest_on_tri_to_point_v3(
float r[3], const float p[3], const float v1[3], const float v2[3], const float v3[3])
{
+ /* Adapted from "Real-Time Collision Detection" by Christer Ericson,
+ * published by Morgan Kaufmann Publishers, copyright 2005 Elsevier Inc. */
+
float ab[3], ac[3], ap[3], d1, d2;
float bp[3], d3, d4, vc, cp[3], d5, d6, vb, va;
float denom, v, w;
@@ -1100,7 +1004,6 @@ void closest_on_tri_to_point_v3(
/******************************* Intersection ********************************/
-/* intersect Line-Line, shorts */
int isect_seg_seg_v2_int(const int v1[2], const int v2[2], const int v3[2], const int v4[2])
{
float div, lambda, mu;
@@ -1123,7 +1026,6 @@ int isect_seg_seg_v2_int(const int v1[2], const int v2[2], const int v3[2], cons
return ISECT_LINE_LINE_NONE;
}
-/* intersect Line-Line, floats - gives intersection point */
int isect_line_line_v2_point(
const float v0[2], const float v1[2], const float v2[2], const float v3[2], float r_vi[2])
{
@@ -1147,7 +1049,6 @@ int isect_line_line_v2_point(
return ISECT_LINE_LINE_COLINEAR;
}
-/* intersect Line-Line, floats */
int isect_seg_seg_v2(const float v1[2], const float v2[2], const float v3[2], const float v4[2])
{
float div, lambda, mu;
@@ -1170,7 +1071,6 @@ int isect_seg_seg_v2(const float v1[2], const float v2[2], const float v3[2], co
return ISECT_LINE_LINE_NONE;
}
-/* Returns a point on each segment that is closest to the other. */
void isect_seg_seg_v3(const float a0[3],
const float a1[3],
const float b0[3],
@@ -1236,19 +1136,6 @@ void isect_seg_seg_v3(const float a0[3],
madd_v3_v3v3fl(r_b, b0, b_dir, fac_b);
}
-/**
- * Get intersection point of two 2D segments.
- *
- * \param endpoint_bias: Bias to use when testing for end-point overlap.
- * A positive value considers intersections that extend past the endpoints,
- * negative values contract the endpoints.
- * Note the bias is applied to a 0-1 factor, not scaled to the length of segments.
- *
- * \returns intersection type:
- * - -1: collinear.
- * - 1: intersection.
- * - 0: no intersection.
- */
int isect_seg_seg_v2_point_ex(const float v0[2],
const float v1[2],
const float v2[2],
@@ -1369,18 +1256,6 @@ bool isect_seg_seg_v2_simple(const float v1[2],
#undef CCW
}
-/**
- * If intersection == ISECT_LINE_LINE_CROSS or ISECT_LINE_LINE_NONE:
- * <pre>
- * pt = v1 + lambda * (v2 - v1) = v3 + mu * (v4 - v3)
- * </pre>
- * \returns intersection type:
- * - ISECT_LINE_LINE_COLINEAR: collinear.
- * - ISECT_LINE_LINE_EXACT: intersection at an endpoint of either.
- * - ISECT_LINE_LINE_CROSS: interaction, not at an endpoint.
- * - ISECT_LINE_LINE_NONE: no intersection.
- * Also returns lambda and mu in r_lambda and r_mu.
- */
int isect_seg_seg_v2_lambda_mu_db(const double v1[2],
const double v2[2],
const double v3[2],
@@ -1415,19 +1290,6 @@ int isect_seg_seg_v2_lambda_mu_db(const double v1[2],
return ISECT_LINE_LINE_NONE;
}
-/**
- * \param l1, l2: Coordinates (point of line).
- * \param sp, r: Coordinate and radius (sphere).
- * \return r_p1, r_p2: Intersection coordinates.
- *
- * \note The order of assignment for intersection points (\a r_p1, \a r_p2) is predictable,
- * based on the direction defined by `l2 - l1`,
- * this direction compared with the normal of each point on the sphere:
- * \a r_p1 always has a >= 0.0 dot product.
- * \a r_p2 always has a <= 0.0 dot product.
- * For example, when \a l1 is inside the sphere and \a l2 is outside,
- * \a r_p1 will always be between \a l1 and \a l2.
- */
int isect_line_sphere_v3(const float l1[3],
const float l2[3],
const float sp[3],
@@ -1490,7 +1352,6 @@ int isect_line_sphere_v3(const float l1[3],
return -1;
}
-/* keep in sync with isect_line_sphere_v3 */
int isect_line_sphere_v2(const float l1[2],
const float l2[2],
const float sp[2],
@@ -1498,6 +1359,8 @@ int isect_line_sphere_v2(const float l1[2],
float r_p1[2],
float r_p2[2])
{
+ /* Keep in sync with #isect_line_sphere_v3. */
+
const float ldir[2] = {l2[0] - l1[0], l2[1] - l1[1]};
const float a = dot_v2v2(ldir, ldir);
@@ -1537,12 +1400,13 @@ int isect_line_sphere_v2(const float l1[2],
return -1;
}
-/* point in polygon (keep float and int versions in sync) */
bool isect_point_poly_v2(const float pt[2],
const float verts[][2],
const unsigned int nr,
const bool UNUSED(use_holes))
{
+ /* Keep in sync with #isect_point_poly_v2_int. */
+
unsigned int i, j;
bool isect = false;
for (i = 0, j = nr - 1; i < nr; j = i++) {
@@ -1560,6 +1424,8 @@ bool isect_point_poly_v2_int(const int pt[2],
const unsigned int nr,
const bool UNUSED(use_holes))
{
+ /* Keep in sync with #isect_point_poly_v2. */
+
unsigned int i, j;
bool isect = false;
for (i = 0, j = nr - 1; i < nr; j = i++) {
@@ -1575,7 +1441,6 @@ bool isect_point_poly_v2_int(const int pt[2],
/* point in tri */
-/* only single direction */
bool isect_point_tri_v2_cw(const float pt[2],
const float v1[2],
const float v2[2],
@@ -1612,7 +1477,6 @@ int isect_point_tri_v2(const float pt[2], const float v1[2], const float v2[2],
return 0;
}
-/* point in quad - only convex quads */
int isect_point_quad_v2(
const float pt[2], const float v1[2], const float v2[2], const float v3[2], const float v4[2])
{
@@ -1638,10 +1502,6 @@ int isect_point_quad_v2(
return 0;
}
-/* moved from effect.c
- * test if the line starting at p1 ending at p2 intersects the triangle v0..v2
- * return non zero if it does
- */
bool isect_line_segment_tri_v3(const float p1[3],
const float p2[3],
const float v0[3],
@@ -1692,7 +1552,6 @@ bool isect_line_segment_tri_v3(const float p1[3],
return true;
}
-/* like isect_line_segment_tri_v3, but allows epsilon tolerance around triangle */
bool isect_line_segment_tri_epsilon_v3(const float p1[3],
const float p2[3],
const float v0[3],
@@ -1744,10 +1603,6 @@ bool isect_line_segment_tri_epsilon_v3(const float p1[3],
return true;
}
-/* moved from effect.c
- * test if the ray starting at p1 going in d direction intersects the triangle v0..v2
- * return non zero if it does
- */
bool isect_ray_tri_v3(const float ray_origin[3],
const float ray_direction[3],
const float v0[3],
@@ -1799,12 +1654,6 @@ bool isect_ray_tri_v3(const float ray_origin[3],
return true;
}
-/**
- * if clip is nonzero, will only return true if lambda is >= 0.0
- * (i.e. intersection point is along positive \a ray_direction)
- *
- * \note #line_plane_factor_v3() shares logic.
- */
bool isect_ray_plane_v3(const float ray_origin[3],
const float ray_direction[3],
const float plane[4],
@@ -2146,9 +1995,6 @@ bool isect_ray_line_v3(const float ray_origin[3],
return true;
}
-/**
- * Check if a point is behind all planes.
- */
bool isect_point_planes_v3(float (*planes)[4], int totplane, const float p[3])
{
int i;
@@ -2162,10 +2008,6 @@ bool isect_point_planes_v3(float (*planes)[4], int totplane, const float p[3])
return true;
}
-/**
- * Check if a point is in front all planes.
- * Same as isect_point_planes_v3 but with planes facing the opposite direction.
- */
bool isect_point_planes_v3_negated(const float (*planes)[4], const int totplane, const float p[3])
{
for (int i = 0; i < totplane; i++) {
@@ -2177,17 +2019,6 @@ bool isect_point_planes_v3_negated(const float (*planes)[4], const int totplane,
return true;
}
-/**
- * Intersect line/plane.
- *
- * \param r_isect_co: The intersection point.
- * \param l1: The first point of the line.
- * \param l2: The second point of the line.
- * \param plane_co: A point on the plane to intersect with.
- * \param plane_no: The direction of the plane (does not need to be normalized).
- *
- * \note #line_plane_factor_v3() shares logic.
- */
bool isect_line_plane_v3(float r_isect_co[3],
const float l1[3],
const float l2[3],
@@ -2211,13 +2042,6 @@ bool isect_line_plane_v3(float r_isect_co[3],
return false;
}
-/**
- * Intersect three planes, return the point where all 3 meet.
- * See Graphics Gems 1 pg 305
- *
- * \param plane_a, plane_b, plane_c: Planes.
- * \param r_isect_co: The resulting intersection point.
- */
bool isect_plane_plane_plane_v3(const float plane_a[4],
const float plane_b[4],
const float plane_c[4],
@@ -2251,17 +2075,6 @@ bool isect_plane_plane_plane_v3(const float plane_a[4],
return false;
}
-/**
- * Intersect two planes, return a point on the intersection and a vector
- * that runs on the direction of the intersection.
- * \note this is a slightly reduced version of #isect_plane_plane_plane_v3
- *
- * \param plane_a, plane_b: Planes.
- * \param r_isect_co: The resulting intersection point.
- * \param r_isect_no: The resulting vector of the intersection.
- *
- * \note \a r_isect_no isn't unit length.
- */
bool isect_plane_plane_v3(const float plane_a[4],
const float plane_b[4],
float r_isect_co[3],
@@ -2296,19 +2109,6 @@ bool isect_plane_plane_v3(const float plane_a[4],
return false;
}
-/**
- * Intersect all planes, calling `callback_fn` for each point that intersects
- * 3 of the planes that isn't outside any of the other planes.
- *
- * This can be thought of as calculating a convex-hull from an array of planes.
- *
- * \param eps_coplanar: Epsilon for testing if two planes are aligned (co-planar).
- * \param eps_isect: Epsilon for testing of a point is behind any of the planes.
- *
- * \warning As complexity is a little under `O(N^3)`, this is only suitable for small arrays.
- *
- * \note This function could be optimized by some spatial structure.
- */
bool isect_planes_v3_fn(
const float planes[][4],
const int planes_len,
@@ -2371,16 +2171,6 @@ bool isect_planes_v3_fn(
return found;
}
-/**
- * Intersect two triangles.
- *
- * \param r_i1, r_i2: Retrieve the overlapping edge between the 2 triangles.
- * \param r_tri_a_edge_isect_count: Indicates how many edges in the first triangle are intersected.
- * \return true when the triangles intersect.
- *
- * \note If it exists, \a r_i1 will be a point on the edge of the 1st triangle.
- * \note intersections between coplanar triangles are currently undetected.
- */
bool isect_tri_tri_v3_ex(const float tri_a[3][3],
const float tri_b[3][3],
float r_i1[3],
@@ -2755,14 +2545,6 @@ static bool getLowestRoot(
return false;
}
-/**
- * Checks status of an AABB in relation to a list of planes.
- *
- * \returns intersection type:
- * - ISECT_AABB_PLANE_BEHIND_ONE (0): AABB is completely behind at least 1 plane;
- * - ISECT_AABB_PLANE_CROSS_ANY (1): AABB intersects at least 1 plane;
- * - ISECT_AABB_PLANE_IN_FRONT_ALL (2): AABB is completely in front of all planes;
- */
int isect_aabb_planes_v3(const float (*planes)[4],
const int totplane,
const float bbmin[3],
@@ -3030,12 +2812,6 @@ bool isect_axial_line_segment_tri_v3(const int axis,
return true;
}
-/**
- * \return The number of point of interests
- * 0 - lines are collinear
- * 1 - lines are coplanar, i1 is set to intersection
- * 2 - i1 and i2 are the nearest points on line 1 (v1, v2) and line 2 (v3, v4) respectively
- */
int isect_line_line_epsilon_v3(const float v1[3],
const float v2[3],
const float v3[3],
@@ -3111,10 +2887,6 @@ int isect_line_line_v3(const float v1[3],
return isect_line_line_epsilon_v3(v1, v2, v3, v4, r_i1, r_i2, epsilon);
}
-/**
- * Intersection point strictly between the two lines
- * \return false when no intersection is found.
- */
bool isect_line_line_strict_v3(const float v1[3],
const float v2[3],
const float v3[3],
@@ -3165,12 +2937,6 @@ bool isect_line_line_strict_v3(const float v1[3],
return false;
}
-/**
- * Check if two rays are not parallel and returns a factor that indicates
- * the distance from \a ray_origin_b to the closest point on ray-a to ray-b.
- *
- * \note Neither directions need to be normalized.
- */
bool isect_ray_ray_epsilon_v3(const float ray_origin_a[3],
const float ray_direction_a[3],
const float ray_origin_b[3],
@@ -3247,12 +3013,13 @@ void isect_ray_aabb_v3_precalc(struct IsectRayAABB_Precalc *data,
data->sign[2] = data->ray_inv_dir[2] < 0.0f;
}
-/* Adapted from http://www.gamedev.net/community/forums/topic.asp?topic_id=459973 */
bool isect_ray_aabb_v3(const struct IsectRayAABB_Precalc *data,
const float bb_min[3],
const float bb_max[3],
float *tmin_out)
{
+ /* Adapted from http://www.gamedev.net/community/forums/topic.asp?topic_id=459973 */
+
float bbox[2][3];
copy_v3_v3(bbox[0], bb_min);
@@ -3298,13 +3065,6 @@ bool isect_ray_aabb_v3(const struct IsectRayAABB_Precalc *data,
return true;
}
-/**
- * Test a bounding box (AABB) for ray intersection.
- * Assumes the ray is already local to the boundbox space.
- *
- * \note \a direction should be normalized
- * if you intend to use the \a tmin or \a tmax distance results!
- */
bool isect_ray_aabb_v3_simple(const float orig[3],
const float dir[3],
const float bb_min[3],
@@ -3357,10 +3117,6 @@ float closest_to_ray_v3(float r_close[3],
return lambda;
}
-/**
- * Find closest point to p on line through (l1, l2) and return lambda,
- * where (0 <= lambda <= 1) when cp is in the line segment (l1, l2).
- */
float closest_to_line_v3(float r_close[3], const float p[3], const float l1[3], const float l2[3])
{
float u[3];
@@ -3424,13 +3180,6 @@ float ray_point_factor_v3(const float p[3],
return ray_point_factor_v3_ex(p, ray_origin, ray_direction, 0.0f, 0.0f);
}
-/**
- * A simplified version of #closest_to_line_v3
- * we only need to return the `lambda`
- *
- * \param epsilon: avoid approaching divide-by-zero.
- * Passing a zero will just check for nonzero division.
- */
float line_point_factor_v3_ex(const float p[3],
const float l1[3],
const float l2[3],
@@ -3471,9 +3220,6 @@ float line_point_factor_v2(const float p[2], const float l1[2], const float l2[2
return line_point_factor_v2_ex(p, l1, l2, 0.0f, 0.0f);
}
-/**
- * \note #isect_line_plane_v3() shares logic
- */
float line_plane_factor_v3(const float plane_co[3],
const float plane_no[3],
const float l1[3],
@@ -3487,10 +3233,6 @@ float line_plane_factor_v3(const float plane_co[3],
return (dot != 0.0f) ? -dot_v3v3(plane_no, h) / dot : 0.0f;
}
-/**
- * Ensure the distance between these points is no greater than 'dist'.
- * If it is, scale them both into the center.
- */
void limit_dist_v3(float v1[3], float v2[3], const float dist)
{
const float dist_old = len_v3v3(v1, v2);
@@ -3508,13 +3250,6 @@ void limit_dist_v3(float v1[3], float v2[3], const float dist)
}
}
-/*
- * x1,y2
- * | \
- * | \ .(a,b)
- * | \
- * x1,y1-- x2,y1
- */
int isect_point_tri_v2_int(
const int x1, const int y1, const int x2, const int y2, const int a, const int b)
{
@@ -3603,12 +3338,6 @@ bool isect_point_tri_prism_v3(const float p[3],
return true;
}
-/**
- * \param r_isect_co: The point \a p projected onto the triangle.
- * \return True when \a p is inside the triangle.
- * \note Its up to the caller to check the distance between \a p and \a r_vi
- * against an error margin.
- */
bool isect_point_tri_v3(
const float p[3], const float v1[3], const float v2[3], const float v3[3], float r_isect_co[3])
{
@@ -3739,16 +3468,6 @@ bool clip_segment_v3_plane_n(const float p1[3],
/****************************** Axis Utils ********************************/
-/**
- * \brief Normal to x,y matrix
- *
- * Creates a 3x3 matrix from a normal.
- * This matrix can be applied to vectors so their 'z' axis runs along \a normal.
- * In practice it means you can use x,y as 2d coords. \see
- *
- * \param r_mat: The matrix to return.
- * \param normal: A unit length vector.
- */
void axis_dominant_v3_to_m3(float r_mat[3][3], const float normal[3])
{
BLI_ASSERT_UNIT_V3(normal);
@@ -3766,9 +3485,6 @@ void axis_dominant_v3_to_m3(float r_mat[3][3], const float normal[3])
is_zero_v3(normal));
}
-/**
- * Same as axis_dominant_v3_to_m3, but flips the normal
- */
void axis_dominant_v3_to_m3_negate(float r_mat[3][3], const float normal[3])
{
BLI_ASSERT_UNIT_V3(normal);
@@ -3888,12 +3604,6 @@ void interp_weights_quad_v3(float w[4],
}
}
-/**
- * \return
- * - 0 if the point is outside of triangle.
- * - 1 if the point is inside triangle.
- * - 2 if it's on the edge.
- */
int barycentric_inside_triangle_v2(const float w[3])
{
if (IN_RANGE(w[0], 0.0f, 1.0f) && IN_RANGE(w[1], 0.0f, 1.0f) && IN_RANGE(w[2], 0.0f, 1.0f)) {
@@ -3907,9 +3617,6 @@ int barycentric_inside_triangle_v2(const float w[3])
return 0;
}
-/**
- * \return false for degenerated triangles.
- */
bool barycentric_coords_v2(
const float v1[2], const float v2[2], const float v3[2], const float co[2], float w[3])
{
@@ -3934,12 +3641,6 @@ bool barycentric_coords_v2(
return false;
}
-/**
- * \note Using #cross_tri_v2 means locations outside the triangle are correctly weighted.
- *
- * \note This is *exactly* the same calculation as #resolve_tri_uv_v2,
- * although it has double precision and is used for texture baking, so keep both.
- */
void barycentric_weights_v2(
const float v1[2], const float v2[2], const float v3[2], const float co[2], float w[3])
{
@@ -3963,11 +3664,6 @@ void barycentric_weights_v2(
copy_v3_fl(w, 1.0f / 3.0f);
}
-/**
- * A version of #barycentric_weights_v2 that doesn't allow negative weights.
- * Useful when negative values cause problems and points are only
- * ever slightly outside of the triangle.
- */
void barycentric_weights_v2_clamped(
const float v1[2], const float v2[2], const float v3[2], const float co[2], float w[3])
{
@@ -3991,10 +3687,6 @@ void barycentric_weights_v2_clamped(
copy_v3_fl(w, 1.0f / 3.0f);
}
-/**
- * still use 2D X,Y space but this works for verts transformed by a perspective matrix,
- * using their 4th component as a weight
- */
void barycentric_weights_v2_persp(
const float v1[4], const float v2[4], const float v3[4], const float co[2], float w[3])
{
@@ -4018,11 +3710,6 @@ void barycentric_weights_v2_persp(
copy_v3_fl(w, 1.0f / 3.0f);
}
-/**
- * same as #barycentric_weights_v2 but works with a quad,
- * NOTE: untested for values outside the quad's bounds
- * this is #interp_weights_poly_v2 expanded for quads only
- */
void barycentric_weights_v2_quad(const float v1[2],
const float v2[2],
const float v3[2],
@@ -4116,9 +3803,6 @@ void barycentric_weights_v2_quad(const float v1[2],
}
}
-/* given 2 triangles in 3D space, and a point in relation to the first triangle.
- * calculate the location of a point in relation to the second triangle.
- * Useful for finding relative positions with geometry */
void transform_point_by_tri_v3(float pt_tar[3],
float const pt_src[3],
const float tri_tar_p1[3],
@@ -4163,10 +3847,6 @@ void transform_point_by_tri_v3(float pt_tar[3],
madd_v3_v3v3fl(pt_tar, pt_tar, no_tar, (z_ofs_src / area_src) * area_tar);
}
-/**
- * Simply re-interpolates,
- * assumes p_src is between \a l_src_p1-l_src_p2
- */
void transform_point_by_seg_v3(float p_dst[3],
const float p_src[3],
const float l_dst_p1[3],
@@ -4178,8 +3858,6 @@ void transform_point_by_seg_v3(float p_dst[3],
interp_v3_v3v3(p_dst, l_dst_p1, l_dst_p2, t);
}
-/* given an array with some invalid values this function interpolates valid values
- * replacing the invalid ones */
int interp_sparse_array(float *array, const int list_size, const float skipval)
{
int found_invalid = 0;
@@ -4516,7 +4194,6 @@ void interp_weights_poly_v2(float *w, float v[][2], const int n, const float co[
/** \} */
-/* (x1, v1)(t1=0)------(x2, v2)(t2=1), 0<t<1 --> (x, v)(t) */
void interp_cubic_v3(float x[3],
float v[3],
const float x1[3],
@@ -4552,13 +4229,6 @@ void interp_cubic_v3(float x[3],
#define IS_ZERO(x) ((x > (-DBL_EPSILON) && x < DBL_EPSILON) ? 1 : 0)
-/**
- * Barycentric reverse
- *
- * Compute coordinates (u, v) for point \a st with respect to triangle (\a st0, \a st1, \a st2)
- *
- * \note same basic result as #barycentric_weights_v2, see its comment for details.
- */
void resolve_tri_uv_v2(
float r_uv[2], const float st[2], const float st0[2], const float st1[2], const float st2[2])
{
@@ -4581,11 +4251,6 @@ void resolve_tri_uv_v2(
}
}
-/**
- * Barycentric reverse 3d
- *
- * Compute coordinates (u, v) for point \a st with respect to triangle (\a st0, \a st1, \a st2)
- */
void resolve_tri_uv_v3(
float r_uv[2], const float st[3], const float st0[3], const float st1[3], const float st2[3])
{
@@ -4617,7 +4282,6 @@ void resolve_tri_uv_v3(
}
}
-/* bilinear reverse */
void resolve_quad_uv_v2(float r_uv[2],
const float st[2],
const float st0[2],
@@ -4628,7 +4292,6 @@ void resolve_quad_uv_v2(float r_uv[2],
resolve_quad_uv_v2_deriv(r_uv, NULL, st, st0, st1, st2, st3);
}
-/* bilinear reverse with derivatives */
void resolve_quad_uv_v2_deriv(float r_uv[2],
float r_deriv[2][2],
const float st[2],
@@ -4719,7 +4382,6 @@ void resolve_quad_uv_v2_deriv(float r_uv[2],
}
}
-/* a version of resolve_quad_uv_v2 that only calculates the 'u' */
float resolve_quad_u_v2(const float st[2],
const float st0[2],
const float st1[2],
@@ -4763,7 +4425,6 @@ float resolve_quad_u_v2(const float st[2],
#undef IS_ZERO
-/* reverse of the functions above */
void interp_bilinear_quad_v3(float data[4][3], float u, float v, float res[3])
{
float vec[3];
@@ -4797,9 +4458,6 @@ void interp_barycentric_tri_v3(float data[3][3], float u, float v, float res[3])
/***************************** View & Projection *****************************/
-/**
- * Matches `glOrtho` result.
- */
void orthographic_m4(float matrix[4][4],
const float left,
const float right,
@@ -4825,9 +4483,6 @@ void orthographic_m4(float matrix[4][4],
matrix[3][2] = -(farClip + nearClip) / Zdelta;
}
-/**
- * Matches `glFrustum` result.
- */
void perspective_m4(float mat[4][4],
const float left,
const float right,
@@ -4873,8 +4528,6 @@ void perspective_m4_fov(float mat[4][4],
mat[1][1] /= nearClip;
}
-/* translate a matrix created by orthographic_m4 or perspective_m4 in XY coords
- * (used to jitter the view) */
void window_translate_m4(float winmat[4][4], float perspmat[4][4], const float x, const float y)
{
if (winmat[2][3] == -1.0f) {
@@ -4903,12 +4556,6 @@ void window_translate_m4(float winmat[4][4], float perspmat[4][4], const float x
}
}
-/**
- * Frustum planes extraction from a projection matrix
- * (homogeneous 4d vector representations of planes).
- *
- * plane parameters can be NULL if you do not need them.
- */
void planes_from_projmat(const float mat[4][4],
float left[4],
float right[4],
@@ -5021,14 +4668,6 @@ void projmat_dimensions_db(const float winmat_fl[4][4],
}
}
-/**
- * Creates a projection matrix for a small region of the viewport.
- *
- * \param projmat: Projection Matrix.
- * \param win_size: Viewport Size.
- * \param x_min, x_max, y_min, y_max: Coordinates of the subregion.
- * \return r_projmat: Resulting Projection Matrix.
- */
void projmat_from_subregion(const float projmat[4][4],
const int win_size[2],
const int x_min,
@@ -5363,8 +5002,6 @@ void accumulate_vertex_normals_v3(float n1[3],
}
}
-/* Add weighted face normal component into normals of the face vertices.
- * Caller must pass pre-allocated vdiffs of nverts length. */
void accumulate_vertex_normals_poly_v3(float **vertnos,
const float polyno[3],
const float **vertcos,
@@ -5444,25 +5081,6 @@ void tangent_from_uv_v3(const float uv1[2],
/****************************** Vector Clouds ********************************/
/* vector clouds */
-/**
- * input
- *
- * \param list_size: 4 lists as pointer to array[list_size]
- * \param pos: current pos array of 'new' positions
- * \param weight: current weight array of 'new'weights (may be NULL pointer if you have no weights)
- * \param rpos: Reference rpos array of 'old' positions
- * \param rweight: Reference rweight array of 'old'weights
- * (may be NULL pointer if you have no weights).
- *
- * output
- *
- * \param lloc: Center of mass pos.
- * \param rloc: Center of mass rpos.
- * \param lrot: Rotation matrix.
- * \param lscale: Scale matrix.
- *
- * pointers may be NULL if not needed
- */
void vcloud_estimate_transform_v3(const int list_size,
const float (*pos)[3],
@@ -6057,11 +5675,6 @@ float form_factor_hemi_poly(
return contrib;
}
-/**
- * Check if the edge is convex or concave
- * (depends on face winding)
- * Copied from BM_edge_is_convex().
- */
bool is_edge_convex_v3(const float v1[3],
const float v2[3],
const float f1_no[3],
@@ -6078,9 +5691,6 @@ bool is_edge_convex_v3(const float v1[3],
return false;
}
-/**
- * Evaluate if entire quad is a proper convex quad
- */
bool is_quad_convex_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3])
{
/**
@@ -6176,12 +5786,6 @@ bool is_poly_convex_v2(const float verts[][2], unsigned int nr)
return true;
}
-/**
- * Check if either of the diagonals along this quad create flipped triangles
- * (normals pointing away from eachother).
- * - (1 << 0): (v1-v3) is flipped.
- * - (1 << 1): (v2-v4) is flipped.
- */
int is_quad_flip_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3])
{
float d_12[3], d_23[3], d_34[3], d_41[3];
@@ -6232,14 +5836,6 @@ bool is_quad_flip_v3_first_third_fast_with_normal(const float v1[3],
return (dot_v3v3(v4, tangent) >= dot) || (dot_v3v3(v2, tangent) <= dot);
}
-/**
- * Return the value which the distance between points will need to be scaled by,
- * to define a handle, given both points are on a perfect circle.
- *
- * Use when we want a bezier curve to match a circle as closely as possible.
- *
- * \note the return value will need to be divided by 0.75 for correct results.
- */
float cubic_tangent_factor_circle_v3(const float tan_l[3], const float tan_r[3])
{
BLI_ASSERT_UNIT_V3(tan_l);
@@ -6267,14 +5863,6 @@ float cubic_tangent_factor_circle_v3(const float tan_l[3], const float tan_r[3])
return ((1.0f - angle_cos) / (angle_sin * 2.0f)) / angle_sin;
}
-/**
- * Utility for computing approximate geodesic distances on triangle meshes.
- *
- * Given triangle with vertex coordinates v0, v1, v2, and known geodesic distances
- * dist1 and dist2 at v1 and v2, estimate a geodesic distance at vertex v0.
- *
- * From "Dart Throwing on Surfaces", EGSR 2009. Section 7, Geodesic Dart Throwing.
- */
float geodesic_distance_propagate_across_triangle(
const float v0[3], const float v1[3], const float v2[3], const float dist1, const float dist2)
{
diff --git a/source/blender/blenlib/intern/math_geom_inline.c b/source/blender/blenlib/intern/math_geom_inline.c
index 857cbfbde9c..09028a1eb9a 100644
--- a/source/blender/blenlib/intern/math_geom_inline.c
+++ b/source/blender/blenlib/intern/math_geom_inline.c
@@ -164,7 +164,6 @@ MINLINE void madd_sh_shfl(float r[9], const float sh[9], const float f)
add_sh_shsh(r, r, tmp);
}
-/* get the 2 dominant axis values, 0==X, 1==Y, 2==Z */
MINLINE void axis_dominant_v3(int *r_axis_a, int *r_axis_b, const float axis[3])
{
const float xn = fabsf(axis[0]);
@@ -185,7 +184,6 @@ MINLINE void axis_dominant_v3(int *r_axis_a, int *r_axis_b, const float axis[3])
}
}
-/* same as axis_dominant_v3 but return the max value */
MINLINE float axis_dominant_v3_max(int *r_axis_a, int *r_axis_b, const float axis[3])
{
const float xn = fabsf(axis[0]);
@@ -209,7 +207,6 @@ MINLINE float axis_dominant_v3_max(int *r_axis_a, int *r_axis_b, const float axi
}
}
-/* get the single dominant axis value, 0==X, 1==Y, 2==Z */
MINLINE int axis_dominant_v3_single(const float vec[3])
{
const float x = fabsf(vec[0]);
@@ -218,7 +215,6 @@ MINLINE int axis_dominant_v3_single(const float vec[3])
return ((x > y) ? ((x > z) ? 0 : 2) : ((y > z) ? 1 : 2));
}
-/* the dominant axis of an orthogonal vector */
MINLINE int axis_dominant_v3_ortho_single(const float vec[3])
{
const float x = fabsf(vec[0]);
@@ -243,15 +239,6 @@ MINLINE int min_axis_v3(const float vec[3])
return ((x < y) ? ((x < z) ? 0 : 2) : ((y < z) ? 1 : 2));
}
-/**
- * Simple function to either:
- * - Calculate how many triangles needed from the total number of polygons + loops.
- * - Calculate the first triangle index from the polygon index & that polygons loop-start.
- *
- * \param poly_count: The number of polygons or polygon-index
- * (3+ sided faces, 1-2 sided give incorrect results).
- * \param corner_count: The number of corners (also called loop-index).
- */
MINLINE int poly_to_tri_count(const int poly_count, const int corner_count)
{
BLI_assert(!poly_count || corner_count > poly_count * 2);
@@ -263,17 +250,10 @@ MINLINE float plane_point_side_v3(const float plane[4], const float co[3])
return dot_v3v3(co, plane) + plane[3];
}
-/* useful to calculate an even width shell, by taking the angle between 2 planes.
- * The return value is a scale on the offset.
- * no angle between planes is 1.0, as the angle between the 2 planes approaches 180d
- * the distance gets very high, 180d would be inf, but this case isn't valid */
MINLINE float shell_angle_to_dist(const float angle)
{
return (UNLIKELY(angle < SMALL_NUMBER)) ? 1.0f : fabsf(1.0f / cosf(angle));
}
-/**
- * Equivalent to `shell_angle_to_dist(angle_normalized_v3v3(a, b))`.
- */
MINLINE float shell_v3v3_normalized_to_dist(const float a[3], const float b[3])
{
const float angle_cos = fabsf(dot_v3v3(a, b));
@@ -281,9 +261,6 @@ MINLINE float shell_v3v3_normalized_to_dist(const float a[3], const float b[3])
BLI_ASSERT_UNIT_V3(b);
return (UNLIKELY(angle_cos < SMALL_NUMBER)) ? 1.0f : (1.0f / angle_cos);
}
-/**
- * Equivalent to `shell_angle_to_dist(angle_normalized_v2v2(a, b))`.
- */
MINLINE float shell_v2v2_normalized_to_dist(const float a[2], const float b[2])
{
const float angle_cos = fabsf(dot_v2v2(a, b));
@@ -292,9 +269,6 @@ MINLINE float shell_v2v2_normalized_to_dist(const float a[2], const float b[2])
return (UNLIKELY(angle_cos < SMALL_NUMBER)) ? 1.0f : (1.0f / angle_cos);
}
-/**
- * Equivalent to `shell_angle_to_dist(angle_normalized_v3v3(a, b) / 2)`.
- */
MINLINE float shell_v3v3_mid_normalized_to_dist(const float a[3], const float b[3])
{
float angle_cos;
@@ -306,9 +280,6 @@ MINLINE float shell_v3v3_mid_normalized_to_dist(const float a[3], const float b[
return (UNLIKELY(angle_cos < SMALL_NUMBER)) ? 1.0f : (1.0f / angle_cos);
}
-/**
- * Equivalent to `shell_angle_to_dist(angle_normalized_v2v2(a, b) / 2)`.
- */
MINLINE float shell_v2v2_mid_normalized_to_dist(const float a[2], const float b[2])
{
float angle_cos;
diff --git a/source/blender/blenlib/intern/math_interp.c b/source/blender/blenlib/intern/math_interp.c
index bd48edf70c0..54beb74abca 100644
--- a/source/blender/blenlib/intern/math_interp.c
+++ b/source/blender/blenlib/intern/math_interp.c
@@ -567,10 +567,11 @@ static void radangle2imp(float a2, float b2, float th, float *A, float *B, float
*F = a2 * b2;
}
-/* all tests here are done to make sure possible overflows are hopefully minimized */
void BLI_ewa_imp2radangle(
float A, float B, float C, float F, float *a, float *b, float *th, float *ecc)
{
+ /* NOTE: all tests here are done to make sure possible overflows are hopefully minimized. */
+
if (F <= 1e-5f) { /* use arbitrary major radius, zero minor, infinite eccentricity */
*a = sqrtf(A > C ? A : C);
*b = 0.0f;
diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c
index b6d80d76be1..eaf76696a0a 100644
--- a/source/blender/blenlib/intern/math_matrix.c
+++ b/source/blender/blenlib/intern/math_matrix.c
@@ -469,7 +469,6 @@ void mul_m4_m4m3(float R[4][4], const float A[4][4], const float B[3][3])
R[2][2] = B_[2][0] * A_[0][2] + B_[2][1] * A_[1][2] + B_[2][2] * A_[2][2];
}
-/* R = A * B, ignore the elements on the 4th row/column of A */
void mul_m3_m3m4(float R[3][3], const float A[3][3], const float B[4][4])
{
float B_[4][4], A_[3][3];
@@ -493,7 +492,6 @@ void mul_m3_m3m4(float R[3][3], const float A[3][3], const float B[4][4])
R[2][2] = B_[2][0] * A_[0][2] + B_[2][1] * A_[1][2] + B_[2][2] * A_[2][2];
}
-/* R = A * B, ignore the elements on the 4th row/column of B */
void mul_m3_m4m3(float R[3][3], const float A[4][4], const float B[3][3])
{
float B_[3][3], A_[4][4];
@@ -636,6 +634,7 @@ void _va_mul_m3_series_9(float r[3][3],
mul_m3_m3m3(r, r, m7);
mul_m3_m3m3(r, r, m8);
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -724,6 +723,7 @@ void _va_mul_m4_series_9(float r[4][4],
mul_m4_m4m4(r, r, m7);
mul_m4_m4m4(r, r, m8);
}
+
/** \} */
void mul_v2_m3v2(float r[2], const float m[3][3], const float v[2])
@@ -805,7 +805,6 @@ void mul_m2_v2(const float mat[2][2], float vec[2])
mul_v2_m2v2(vec, mat, vec);
}
-/** Same as #mul_m4_v3() but doesn't apply translation component. */
void mul_mat3_m4_v3(const float M[4][4], float r[3])
{
const float x = r[0];
@@ -1215,16 +1214,6 @@ bool invert_m4(float m[4][4])
return success;
}
-/**
- * Computes the inverse of mat and puts it in inverse.
- * Uses Gaussian Elimination with partial (maximal column) pivoting.
- * \return true on success (i.e. can always find a pivot) and false on failure.
- * Mark Segal - 1992.
- *
- * \note this has worse performance than #EIG_invert_m4_m4 (Eigen), but e.g.
- * for non-invertible scale matrices, finding a partial solution can
- * be useful to have a valid local transform center, see T57767.
- */
bool invert_m4_m4_fallback(float inverse[4][4], const float mat[4][4])
{
#ifndef MATH_STANDALONE
@@ -1308,14 +1297,6 @@ bool invert_m4_m4(float inverse[4][4], const float mat[4][4])
#endif
}
-/**
- * Combines transformations, handling scale separately in a manner equivalent
- * to the Aligned Inherit Scale mode, in order to avoid creating shear.
- * If A scale is uniform, the result is equivalent to ordinary multiplication.
- *
- * NOTE: this effectively takes output location from simple multiplication,
- * and uses mul_m4_m4m4_split_channels for rotation and scale.
- */
void mul_m4_m4m4_aligned_scale(float R[4][4], const float A[4][4], const float B[4][4])
{
float loc_a[3], rot_a[3][3], size_a[3];
@@ -1332,9 +1313,6 @@ void mul_m4_m4m4_aligned_scale(float R[4][4], const float A[4][4], const float B
loc_rot_size_to_mat4(R, loc_r, rot_r, size_r);
}
-/**
- * Separately combines location, rotation and scale of the input matrices.
- */
void mul_m4_m4m4_split_channels(float R[4][4], const float A[4][4], const float B[4][4])
{
float loc_a[3], rot_a[3][3], size_a[3];
@@ -1383,7 +1361,6 @@ void transpose_m3_m3(float R[3][3], const float M[3][3])
R[2][2] = M[2][2];
}
-/* seems obscure but in-fact a common operation */
void transpose_m3_m4(float R[3][3], const float M[4][4])
{
BLI_assert(&R[0][0] != &M[0][0]);
@@ -1461,11 +1438,6 @@ bool compare_m4m4(const float mat1[4][4], const float mat2[4][4], float limit)
return false;
}
-/**
- * Make an orthonormal matrix around the selected axis of the given matrix.
- *
- * \param axis: Axis to build the orthonormal basis around.
- */
void orthogonalize_m3(float R[3][3], int axis)
{
float size[3];
@@ -1550,11 +1522,6 @@ void orthogonalize_m3(float R[3][3], int axis)
mul_v3_fl(R[2], size[2]);
}
-/**
- * Make an orthonormal matrix around the selected axis of the given matrix.
- *
- * \param axis: Axis to build the orthonormal basis around.
- */
void orthogonalize_m4(float R[4][4], int axis)
{
float size[3];
@@ -1692,14 +1659,6 @@ static void orthogonalize_stable(float v1[3], float v2[3], float v3[3], bool nor
}
}
-/**
- * Make an orthonormal matrix around the selected axis of the given matrix,
- * in a way that is symmetric and stable to variations in the input, and
- * preserving the value of the determinant, i.e. the overall volume change.
- *
- * \param axis: Axis to build the orthonormal basis around.
- * \param normalize: Normalize the matrix instead of preserving volume.
- */
void orthogonalize_m3_stable(float R[3][3], int axis, bool normalize)
{
switch (axis) {
@@ -1718,14 +1677,6 @@ void orthogonalize_m3_stable(float R[3][3], int axis, bool normalize)
}
}
-/**
- * Make an orthonormal matrix around the selected axis of the given matrix,
- * in a way that is symmetric and stable to variations in the input, and
- * preserving the value of the determinant, i.e. the overall volume change.
- *
- * \param axis: Axis to build the orthonormal basis around.
- * \param normalize: Normalize the matrix instead of preserving volume.
- */
void orthogonalize_m4_stable(float R[4][4], int axis, bool normalize)
{
switch (axis) {
@@ -2193,10 +2144,6 @@ void mat4_to_size(float size[3], const float M[4][4])
size[2] = len_v3(M[2]);
}
-/**
- * Extract scale factors from the matrix, with correction to ensure
- * exact volume in case of a sheared matrix.
- */
void mat4_to_size_fix_shear(float size[3], const float M[4][4])
{
mat4_to_size(size, M);
@@ -2208,11 +2155,6 @@ void mat4_to_size_fix_shear(float size[3], const float M[4][4])
}
}
-/**
- * This computes the overall volume scale factor of a transformation matrix.
- * For an orthogonal matrix, it is the product of all three scale values.
- * Returns a negative value if the transform is flipped by negative scale.
- */
float mat3_to_volume_scale(const float mat[3][3])
{
return determinant_m3_array(mat);
@@ -2223,11 +2165,6 @@ float mat4_to_volume_scale(const float mat[4][4])
return determinant_m4_mat3_array(mat);
}
-/**
- * This gets the average scale of a matrix, only use when your scaling
- * data that has no idea of scale axis, examples are bone-envelope-radius
- * and curve radius.
- */
float mat3_to_scale(const float mat[3][3])
{
/* unit length vector */
@@ -2246,7 +2183,6 @@ float mat4_to_scale(const float mat[4][4])
return len_v3(unit_vec);
}
-/** Return 2D scale (in XY plane) of given mat4. */
float mat4_to_xy_scale(const float M[4][4])
{
/* unit length vector in xy plane */
@@ -2367,14 +2303,6 @@ void translate_m4(float mat[4][4], float Tx, float Ty, float Tz)
mat[3][2] += (Tx * mat[0][2] + Ty * mat[1][2] + Tz * mat[2][2]);
}
-/* TODO: enum for axis? */
-/**
- * Rotate a matrix in-place.
- *
- * \note To create a new rotation matrix see:
- * #axis_angle_to_mat4_single, #axis_angle_to_mat3_single, #angle_to_mat2
- * (axis & angle args are compatible).
- */
void rotate_m4(float mat[4][4], const char axis, const float angle)
{
const float angle_cos = cosf(angle);
@@ -2412,7 +2340,6 @@ void rotate_m4(float mat[4][4], const char axis, const float angle)
}
}
-/** Scale a matrix in-place. */
void rescale_m4(float mat[4][4], const float scale[3])
{
mul_v3_fl(mat[0], scale[0]);
@@ -2420,14 +2347,6 @@ void rescale_m4(float mat[4][4], const float scale[3])
mul_v3_fl(mat[2], scale[2]);
}
-/**
- * Scale or rotate around a pivot point,
- * a convenience function to avoid having to do inline.
- *
- * Since its common to make a scale/rotation matrix that pivots around an arbitrary point.
- *
- * Typical use case is to make 3x3 matrix, copy to 4x4, then pass to this function.
- */
void transform_pivot_set_m4(float mat[4][4], const float pivot[3])
{
float tmat[4][4];
@@ -2495,22 +2414,6 @@ void blend_m4_m4m4(float out[4][4],
/* for builds without Eigen */
#ifndef MATH_STANDALONE
-/**
- * A polar-decomposition-based interpolation between matrix A and matrix B.
- *
- * \note This code is about five times slower as the 'naive' interpolation done by #blend_m3_m3m3
- * (it typically remains below 2 usec on an average i74700,
- * while #blend_m3_m3m3 remains below 0.4 usec).
- * However, it gives expected results even with non-uniformly scaled matrices,
- * see T46418 for an example.
- *
- * Based on "Matrix Animation and Polar Decomposition", by Ken Shoemake & Tom Duff
- *
- * \param R: Resulting interpolated matrix.
- * \param A: Input matrix which is totally effective with `t = 0.0`.
- * \param B: Input matrix which is totally effective with `t = 1.0`.
- * \param t: Interpolation factor.
- */
void interp_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3], const float t)
{
/* 'Rotation' component ('U' part of polar decomposition,
@@ -2556,15 +2459,6 @@ void interp_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3], con
mul_m3_m3m3(R, U, P);
}
-/**
- * Complete transform matrix interpolation,
- * based on polar-decomposition-based interpolation from #interp_m3_m3m3.
- *
- * \param R: Resulting interpolated matrix.
- * \param A: Input matrix which is totally effective with `t = 0.0`.
- * \param B: Input matrix which is totally effective with `t = 1.0`.
- * \param t: Interpolation factor.
- */
void interp_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4], const float t)
{
float A3[3][3], B3[3][3], R3[3][3];
@@ -2621,10 +2515,6 @@ bool equals_m4m4(const float mat1[4][4], const float mat2[4][4])
equals_v4v4(mat1[2], mat2[2]) && equals_v4v4(mat1[3], mat2[3]));
}
-/**
- * Make a 4x4 matrix out of 3 transform components.
- * Matrices are made in the order: `scale * rot * loc`
- */
void loc_rot_size_to_mat4(float R[4][4],
const float loc[3],
const float rot[3][3],
@@ -2635,12 +2525,6 @@ void loc_rot_size_to_mat4(float R[4][4],
copy_v3_v3(R[3], loc);
}
-/**
- * Make a 4x4 matrix out of 3 transform components.
- * Matrices are made in the order: `scale * rot * loc`
- *
- * TODO: need to have a version that allows for rotation order...
- */
void loc_eul_size_to_mat4(float R[4][4],
const float loc[3],
const float eul[3],
@@ -2665,10 +2549,6 @@ void loc_eul_size_to_mat4(float R[4][4],
R[3][2] = loc[2];
}
-/**
- * Make a 4x4 matrix out of 3 transform components.
- * Matrices are made in the order: `scale * rot * loc`
- */
void loc_eulO_size_to_mat4(float R[4][4],
const float loc[3],
const float eul[3],
@@ -2694,10 +2574,6 @@ void loc_eulO_size_to_mat4(float R[4][4],
R[3][2] = loc[2];
}
-/**
- * Make a 4x4 matrix out of 3 transform components.
- * Matrices are made in the order: `scale * rot * loc`
- */
void loc_quat_size_to_mat4(float R[4][4],
const float loc[3],
const float quat[4],
@@ -2751,18 +2627,11 @@ void print_m4(const char *str, const float m[4][4])
printf("\n");
}
-/*********************************** SVD ************************************
- * from TNT matrix library
- *
- * Compute the Single Value Decomposition of an arbitrary matrix A
- * That is compute the 3 matrices U,W,V with U column orthogonal (m,n)
- * ,W a diagonal matrix and V an orthogonal square matrix `s.t.A = U.W.Vt`.
- * From this decomposition it is trivial to compute the (pseudo-inverse)
- * of `A` as `Ainv = V.Winv.transpose(U)`.
- */
-
void svd_m4(float U[4][4], float s[4], float V[4][4], float A_[4][4])
{
+ /* NOTE: originally from TNT (template numeric toolkit) matrix library.
+ * https://math.nist.gov/tnt */
+
float A[4][4];
float work1[4], work2[4];
int m = 4;
@@ -3269,12 +3138,6 @@ void invert_m4_m4_safe(float Ainv[4][4], const float A[4][4])
* where we want to specify the length of the degenerate axes.
* \{ */
-/**
- * A safe version of invert that uses valid axes, calculating the zero'd axis
- * based on the non-zero ones.
- *
- * This works well for transformation matrices, when a single axis is zerod.
- */
void invert_m4_m4_safe_ortho(float Ainv[4][4], const float A[4][4])
{
if (UNLIKELY(!invert_m4_m4(Ainv, A))) {
@@ -3299,37 +3162,6 @@ void invert_m3_m3_safe_ortho(float Ainv[3][3], const float A[3][3])
/** \} */
-/**
- * #SpaceTransform struct encapsulates all needed data to convert between two coordinate spaces
- * (where conversion can be represented by a matrix multiplication).
- *
- * A SpaceTransform is initialized using:
- * - #BLI_SPACE_TRANSFORM_SETUP(&data, ob1, ob2)
- *
- * After that the following calls can be used:
- * - Converts a coordinate in ob1 space to the corresponding ob2 space:
- * #BLI_space_transform_apply(&data, co);
- * - Converts a coordinate in ob2 space to the corresponding ob1 space:
- * #BLI_space_transform_invert(&data, co);
- *
- * Same concept as #BLI_space_transform_apply and #BLI_space_transform_invert,
- * but no is normalized after conversion (and not translated at all!):
- * - #BLI_space_transform_apply_normal(&data, no);
- * - #BLI_space_transform_invert_normal(&data, no);
- */
-
-/**
- * Global-invariant transform.
- *
- * This defines a matrix transforming a point in local space to a point in target space
- * such that its global coordinates remain unchanged.
- *
- * In other words, if we have a global point P with local coordinates (x, y, z)
- * and global coordinates (X, Y, Z),
- * this defines a transform matrix TM such that (x', y', z') = TM * (x, y, z)
- * where (x', y', z') are the coordinates of P' in target space
- * such that it keeps (X, Y, Z) coordinates in global space.
- */
void BLI_space_transform_from_matrices(SpaceTransform *data,
const float local[4][4],
const float target[4][4])
@@ -3340,18 +3172,6 @@ void BLI_space_transform_from_matrices(SpaceTransform *data,
invert_m4_m4(data->target2local, data->local2target);
}
-/**
- * Local-invariant transform.
- *
- * This defines a matrix transforming a point in global space
- * such that its local coordinates (from local space to target space) remain unchanged.
- *
- * In other words, if we have a local point p with local coordinates (x, y, z)
- * and global coordinates (X, Y, Z),
- * this defines a transform matrix TM such that (X', Y', Z') = TM * (X, Y, Z)
- * where (X', Y', Z') are the coordinates of p' in global space
- * such that it keeps (x, y, z) coordinates in target space.
- */
void BLI_space_transform_global_from_matrices(SpaceTransform *data,
const float local[4][4],
const float target[4][4])
diff --git a/source/blender/blenlib/intern/math_rotation.c b/source/blender/blenlib/intern/math_rotation.c
index 34baac6f2a4..dbcf3a6500c 100644
--- a/source/blender/blenlib/intern/math_rotation.c
+++ b/source/blender/blenlib/intern/math_rotation.c
@@ -34,7 +34,6 @@
# define QUAT_EPSILON 0.0001
#endif
-/* convenience, avoids setting Y axis everywhere */
void unit_axis_angle(float axis[3], float *angle)
{
axis[0] = 0.0f;
@@ -75,25 +74,6 @@ void mul_qt_qtqt(float q[4], const float a[4], const float b[4])
q[2] = t2;
}
-/**
- * \note
- * Assumes a unit quaternion?
- *
- * in fact not, but you may want to use a unit quat, read on...
- *
- * Shortcut for 'q v q*' when \a v is actually a quaternion.
- * This removes the need for converting a vector to a quaternion,
- * calculating q's conjugate and converting back to a vector.
- * It also happens to be faster (17+,24* vs * 24+,32*).
- * If \a q is not a unit quaternion, then \a v will be both rotated by
- * the same amount as if q was a unit quaternion, and scaled by the square of
- * the length of q.
- *
- * For people used to python mathutils, its like:
- * def mul_qt_v3(q, v): (q * Quaternion((0.0, v[0], v[1], v[2])) * q.conjugated())[1:]
- *
- * \note Multiplying by 3x3 matrix is ~25% faster.
- */
void mul_qt_v3(const float q[4], float r[3])
{
float t0, t1, t2;
@@ -150,11 +130,6 @@ void invert_qt_qt(float q1[4], const float q2[4])
invert_qt(q1);
}
-/**
- * This is just conjugate_qt for cases we know \a q is unit-length.
- * we could use #conjugate_qt directly, but use this function to show intent,
- * and assert if its ever becomes non-unit-length.
- */
void invert_qt_normalized(float q[4])
{
BLI_ASSERT_UNIT_QUAT(q);
@@ -167,7 +142,6 @@ void invert_qt_qt_normalized(float q1[4], const float q2[4])
invert_qt_normalized(q1);
}
-/* Simple multiply. */
void mul_qt_fl(float q[4], const float f)
{
q[0] *= f;
@@ -188,7 +162,6 @@ void sub_qt_qtqt(float q[4], const float a[4], const float b[4])
mul_qt_qtqt(q, a, n_b);
}
-/* raise a unit quaternion to the specified power */
void pow_qt_fl_normalized(float q[4], const float fac)
{
BLI_ASSERT_UNIT_QUAT(q);
@@ -200,10 +173,6 @@ void pow_qt_fl_normalized(float q[4], const float fac)
normalize_v3_length(q + 1, si);
}
-/**
- * Apply the rotation of \a a to \a q keeping the values compatible with \a old.
- * Avoid axis flipping for animated f-curves for eg.
- */
void quat_to_compatible_quat(float q[4], const float a[4], const float old[4])
{
const float eps = 1e-4f;
@@ -471,9 +440,6 @@ float normalize_qt_qt(float r[4], const float q[4])
return normalize_qt(r);
}
-/**
- * Calculate a rotation matrix from 2 normalized vectors.
- */
void rotation_between_vecs_to_mat3(float m[3][3], const float v1[3], const float v2[3])
{
float axis[3];
@@ -511,7 +477,6 @@ void rotation_between_vecs_to_mat3(float m[3][3], const float v1[3], const float
}
}
-/* NOTE: expects vectors to be normalized. */
void rotation_between_vecs_to_quat(float q[4], const float v1[3], const float v2[3])
{
float axis[3];
@@ -551,16 +516,6 @@ void rotation_between_quats_to_quat(float q[4], const float q1[4], const float q
mul_qt_qtqt(q, tquat, q2);
}
-/**
- * Decompose a quaternion into a swing rotation (quaternion with the selected
- * axis component locked at zero), followed by a twist rotation around the axis.
- *
- * \param q: input quaternion.
- * \param axis: twist axis in [0,1,2]
- * \param r_swing: if not NULL, receives the swing quaternion.
- * \param r_twist: if not NULL, receives the twist quaternion.
- * \returns twist angle.
- */
float quat_split_swing_and_twist(const float q_in[4], int axis, float r_swing[4], float r_twist[4])
{
BLI_assert(axis >= 0 && axis <= 2);
@@ -861,14 +816,6 @@ void QuatInterpolW(float *result, float quat1[4], float quat2[4], float t)
}
#endif
-/**
- * Generic function for implementing slerp
- * (quaternions and spherical vector coords).
- *
- * \param t: factor in [0..1]
- * \param cosom: dot product from normalized vectors/quats.
- * \param r_w: calculated weights.
- */
void interp_dot_slerp(const float t, const float cosom, float r_w[2])
{
const float eps = 1e-4f;
@@ -925,8 +872,6 @@ void add_qt_qtqt(float q[4], const float a[4], const float b[4], const float t)
q[3] = a[3] + t * b[3];
}
-/* same as tri_to_quat() but takes pre-computed normal from the triangle
- * used for ngons when we know their normal */
void tri_to_quat_ex(
float quat[4], const float v1[3], const float v2[3], const float v3[3], const float no_orig[3])
{
@@ -979,9 +924,6 @@ void tri_to_quat_ex(
mul_qt_qtqt(quat, q1, q2);
}
-/**
- * \return the length of the normal, use to test for degenerate triangles.
- */
float tri_to_quat(float q[4], const float a[3], const float b[3], const float c[3])
{
float vec[3];
@@ -1020,7 +962,6 @@ void axis_angle_to_quat(float r[4], const float axis[3], const float angle)
}
}
-/* Quaternions to Axis Angle */
void quat_to_axis_angle(float axis[3], float *angle, const float q[4])
{
float ha, si;
@@ -1054,7 +995,6 @@ void quat_to_axis_angle(float axis[3], float *angle, const float q[4])
}
}
-/* Axis Angle to Euler Rotation */
void axis_angle_to_eulO(float eul[3], const short order, const float axis[3], const float angle)
{
float q[4];
@@ -1064,7 +1004,6 @@ void axis_angle_to_eulO(float eul[3], const short order, const float axis[3], co
quat_to_eulO(eul, order, q);
}
-/* Euler Rotation to Axis Angle */
void eulO_to_axis_angle(float axis[3], float *angle, const float eul[3], const short order)
{
float q[4];
@@ -1074,15 +1013,6 @@ void eulO_to_axis_angle(float axis[3], float *angle, const float eul[3], const s
quat_to_axis_angle(axis, angle, q);
}
-/**
- * axis angle to 3x3 matrix
- *
- * This takes the angle with sin/cos applied so we can avoid calculating it in some cases.
- *
- * \param axis: rotation axis (must be normalized).
- * \param angle_sin: sin(angle)
- * \param angle_cos: cos(angle)
- */
void axis_angle_normalized_to_mat3_ex(float mat[3][3],
const float axis[3],
const float angle_sin,
@@ -1123,7 +1053,6 @@ void axis_angle_normalized_to_mat3(float R[3][3], const float axis[3], const flo
axis_angle_normalized_to_mat3_ex(R, axis, sinf(angle), cosf(angle));
}
-/* axis angle to 3x3 matrix - safer version (normalization of axis performed) */
void axis_angle_to_mat3(float R[3][3], const float axis[3], const float angle)
{
float nor[3];
@@ -1137,7 +1066,6 @@ void axis_angle_to_mat3(float R[3][3], const float axis[3], const float angle)
axis_angle_normalized_to_mat3(R, nor, angle);
}
-/* axis angle to 4x4 matrix - safer version (normalization of axis performed) */
void axis_angle_to_mat4(float R[4][4], const float axis[3], const float angle)
{
float tmat[3][3];
@@ -1147,7 +1075,6 @@ void axis_angle_to_mat4(float R[4][4], const float axis[3], const float angle)
copy_m4_m3(R, tmat);
}
-/* 3x3 matrix to axis angle */
void mat3_normalized_to_axis_angle(float axis[3], float *angle, const float mat[3][3])
{
float q[4];
@@ -1167,7 +1094,6 @@ void mat3_to_axis_angle(float axis[3], float *angle, const float mat[3][3])
quat_to_axis_angle(axis, angle, q);
}
-/* 4x4 matrix to axis angle */
void mat4_normalized_to_axis_angle(float axis[3], float *angle, const float mat[4][4])
{
float q[4];
@@ -1178,7 +1104,6 @@ void mat4_normalized_to_axis_angle(float axis[3], float *angle, const float mat[
quat_to_axis_angle(axis, angle, q);
}
-/* 4x4 matrix to axis angle */
void mat4_to_axis_angle(float axis[3], float *angle, const float mat[4][4])
{
float q[4];
@@ -1196,7 +1121,6 @@ void axis_angle_to_mat4_single(float R[4][4], const char axis, const float angle
copy_m4_m3(R, mat3);
}
-/* rotation matrix from a single axis */
void axis_angle_to_mat3_single(float R[3][3], const char axis, const float angle)
{
const float angle_cos = cosf(angle);
@@ -1305,7 +1229,6 @@ void expmap_to_quat(float r[4], const float expmap[3])
/******************************** XYZ Eulers *********************************/
-/* XYZ order */
void eul_to_mat3(float mat[3][3], const float eul[3])
{
double ci, cj, ch, si, sj, sh, cc, cs, sc, ss;
@@ -1332,7 +1255,6 @@ void eul_to_mat3(float mat[3][3], const float eul[3])
mat[2][2] = (float)(cj * ci);
}
-/* XYZ order */
void eul_to_mat4(float mat[4][4], const float eul[3])
{
double ci, cj, ch, si, sj, sh, cc, cs, sc, ss;
@@ -1390,7 +1312,6 @@ static void mat3_normalized_to_eul2(const float mat[3][3], float eul1[3], float
}
}
-/* XYZ order */
void mat3_normalized_to_eul(float eul[3], const float mat[3][3])
{
float eul1[3], eul2[3];
@@ -1413,7 +1334,6 @@ void mat3_to_eul(float eul[3], const float mat[3][3])
mat3_normalized_to_eul(eul, unit_mat);
}
-/* XYZ order */
void mat4_normalized_to_eul(float eul[3], const float m[4][4])
{
float mat3[3][3];
@@ -1427,7 +1347,6 @@ void mat4_to_eul(float eul[3], const float m[4][4])
mat3_to_eul(eul, mat3);
}
-/* XYZ order */
void quat_to_eul(float eul[3], const float quat[4])
{
float unit_mat[3][3];
@@ -1435,7 +1354,6 @@ void quat_to_eul(float eul[3], const float quat[4])
mat3_normalized_to_eul(eul, unit_mat);
}
-/* XYZ order */
void eul_to_quat(float quat[4], const float eul[3])
{
float ti, tj, th, ci, cj, ch, si, sj, sh, cc, cs, sc, ss;
@@ -1460,7 +1378,6 @@ void eul_to_quat(float quat[4], const float eul[3])
quat[3] = cj * cs - sj * sc;
}
-/* XYZ order */
void rotate_eul(float beul[3], const char axis, const float ang)
{
float eul[3], mat1[3][3], mat2[3][3], totmat[3][3];
@@ -1486,7 +1403,6 @@ void rotate_eul(float beul[3], const char axis, const float ang)
mat3_to_eul(beul, totmat);
}
-/* order independent! */
void compatible_eul(float eul[3], const float oldrot[3])
{
/* we could use M_PI as pi_thresh: which is correct but 5.1 gives better results.
@@ -1539,7 +1455,6 @@ void compatible_eul(float eul[3], const float oldrot[3])
/* uses 2 methods to retrieve eulers, and picks the closest */
-/* XYZ order */
void mat3_normalized_to_compatible_eul(float eul[3], const float oldrot[3], float mat[3][3])
{
float eul1[3], eul2[3];
@@ -1622,7 +1537,6 @@ static const RotOrderInfo *get_rotation_order_info(const short order)
return &rotOrders[5];
}
-/* Construct quaternion from Euler angles (in radians). */
void eulO_to_quat(float q[4], const float e[3], const short order)
{
const RotOrderInfo *R = get_rotation_order_info(order);
@@ -1660,7 +1574,6 @@ void eulO_to_quat(float q[4], const float e[3], const short order)
}
}
-/* Convert quaternion to Euler angles (in radians). */
void quat_to_eulO(float e[3], short const order, const float q[4])
{
float unit_mat[3][3];
@@ -1669,7 +1582,6 @@ void quat_to_eulO(float e[3], short const order, const float q[4])
mat3_normalized_to_eulO(e, order, unit_mat);
}
-/* Construct 3x3 matrix from Euler angles (in radians). */
void eulO_to_mat3(float M[3][3], const float e[3], const short order)
{
const RotOrderInfo *R = get_rotation_order_info(order);
@@ -1747,7 +1659,6 @@ static void mat3_normalized_to_eulo2(const float mat[3][3],
}
}
-/* Construct 4x4 matrix from Euler angles (in radians). */
void eulO_to_mat4(float mat[4][4], const float e[3], const short order)
{
float unit_mat[3][3];
@@ -1757,7 +1668,6 @@ void eulO_to_mat4(float mat[4][4], const float e[3], const short order)
copy_m4_m3(mat, unit_mat);
}
-/* Convert 3x3 matrix to Euler angles (in radians). */
void mat3_normalized_to_eulO(float eul[3], const short order, const float m[3][3])
{
float eul1[3], eul2[3];
@@ -1783,7 +1693,6 @@ void mat3_to_eulO(float eul[3], const short order, const float m[3][3])
mat3_normalized_to_eulO(eul, order, unit_mat);
}
-/* Convert 4x4 matrix to Euler angles (in radians). */
void mat4_normalized_to_eulO(float eul[3], const short order, const float m[4][4])
{
float mat3[3][3];
@@ -1801,7 +1710,6 @@ void mat4_to_eulO(float eul[3], const short order, const float m[4][4])
mat3_normalized_to_eulO(eul, order, mat3);
}
-/* uses 2 methods to retrieve eulers, and picks the closest */
void mat3_normalized_to_compatible_eulO(float eul[3],
const float oldrot[3],
const short order,
@@ -1901,7 +1809,6 @@ void rotate_eulO(float beul[3], const short order, char axis, float ang)
mat3_to_eulO(beul, order, totmat);
}
-/* the matrix is written to as 3 axis vectors */
void eulO_to_gimbal_axis(float gmat[3][3], const float eul[3], const short order)
{
const RotOrderInfo *R = get_rotation_order_info(order);
@@ -2190,7 +2097,6 @@ void copy_dq_dq(DualQuat *r, const DualQuat *dq)
memcpy(r, dq, sizeof(DualQuat));
}
-/* axis matches eTrackToAxis_Modes */
void quat_apply_track(float quat[4], short axis, short upflag)
{
/* rotations are hard coded to match vec_to_quat */
@@ -2271,7 +2177,6 @@ void vec_apply_track(float vec[3], short axis)
}
}
-/* lens/angle conversion (radians) */
float focallength_to_fov(float focal_length, float sensor)
{
return 2.0f * atanf((sensor / 2.0f) / focal_length);
@@ -2298,7 +2203,6 @@ float angle_wrap_deg(float angle)
return mod_inline(angle + 180.0f, 360.0f) - 180.0f;
}
-/* returns an angle compatible with angle_compat */
float angle_compat_rad(float angle, float angle_compat)
{
return angle_compat + angle_wrap_rad(angle - angle_compat);
@@ -2387,10 +2291,6 @@ BLI_INLINE int _axis_signed(const int axis)
return (axis < 3) ? axis : axis - 3;
}
-/**
- * Each argument us an axis in ['X', 'Y', 'Z', '-X', '-Y', '-Z']
- * where the first 2 are a source and the second 2 are the target.
- */
bool mat3_from_axis_conversion(
int src_forward, int src_up, int dst_forward, int dst_up, float r_mat[3][3])
{
@@ -2423,9 +2323,6 @@ bool mat3_from_axis_conversion(
return false;
}
-/**
- * Use when the second axis can be guessed.
- */
bool mat3_from_axis_conversion_single(int src_axis, int dst_axis, float r_mat[3][3])
{
if (src_axis == dst_axis) {
diff --git a/source/blender/blenlib/intern/math_solvers.c b/source/blender/blenlib/intern/math_solvers.c
index 131afc19f28..f7630efd203 100644
--- a/source/blender/blenlib/intern/math_solvers.c
+++ b/source/blender/blenlib/intern/math_solvers.c
@@ -32,13 +32,6 @@
/********************************** Eigen Solvers *********************************/
-/**
- * \brief Compute the eigen values and/or vectors of given 3D symmetric (aka adjoint) matrix.
- *
- * \param m3: the 3D symmetric matrix.
- * \return r_eigen_values the computed eigen values (NULL if not needed).
- * \return r_eigen_vectors the computed eigen vectors (NULL if not needed).
- */
bool BLI_eigen_solve_selfadjoint_m3(const float m3[3][3],
float r_eigen_values[3],
float r_eigen_vectors[3][3])
@@ -54,14 +47,6 @@ bool BLI_eigen_solve_selfadjoint_m3(const float m3[3][3],
3, (const float *)m3, r_eigen_values, (float *)r_eigen_vectors);
}
-/**
- * \brief Compute the SVD (Singular Values Decomposition) of given 3D matrix (m3 = USV*).
- *
- * \param m3: the matrix to decompose.
- * \return r_U the computed left singular vector of \a m3 (NULL if not needed).
- * \return r_S the computed singular values of \a m3 (NULL if not needed).
- * \return r_V the computed right singular vector of \a m3 (NULL if not needed).
- */
void BLI_svd_m3(const float m3[3][3], float r_U[3][3], float r_S[3], float r_V[3][3])
{
EIG_svd_square_matrix(3, (const float *)m3, (float *)r_U, (float *)r_S, (float *)r_V);
@@ -69,16 +54,6 @@ void BLI_svd_m3(const float m3[3][3], float r_U[3][3], float r_S[3], float r_V[3
/***************************** Simple Solvers ************************************/
-/**
- * \brief Solve a tridiagonal system of equations:
- *
- * a[i] * r_x[i-1] + b[i] * r_x[i] + c[i] * r_x[i+1] = d[i]
- *
- * Ignores a[0] and c[count-1]. Uses the Thomas algorithm, e.g. see wiki.
- *
- * \param r_x: output vector, may be shared with any of the input ones
- * \return true if success
- */
bool BLI_tridiagonal_solve(
const float *a, const float *b, const float *c, const float *d, float *r_x, const int count)
{
@@ -124,12 +99,6 @@ bool BLI_tridiagonal_solve(
return isfinite(x_prev);
}
-/**
- * \brief Solve a possibly cyclic tridiagonal system using the Sherman-Morrison formula.
- *
- * \param r_x: output vector, may be shared with any of the input ones
- * \return true if success
- */
bool BLI_tridiagonal_solve_cyclic(
const float *a, const float *b, const float *c, const float *d, float *r_x, const int count)
{
@@ -194,21 +163,6 @@ bool BLI_tridiagonal_solve_cyclic(
return success;
}
-/**
- * \brief Solve a generic f(x) = 0 equation using Newton's method.
- *
- * \param func_delta: Callback computing the value of f(x).
- * \param func_jacobian: Callback computing the Jacobian matrix of the function at x.
- * \param func_correction: Callback for forcing the search into an arbitrary custom domain.
- * May be NULL.
- * \param userdata: Data for the callbacks.
- * \param epsilon: Desired precision.
- * \param max_iterations: Limit on the iterations.
- * \param trace: Enables logging to console.
- * \param x_init: Initial solution vector.
- * \param result: Final result.
- * \return true if success
- */
bool BLI_newton3d_solve(Newton3D_DeltaFunc func_delta,
Newton3D_JacobianFunc func_jacobian,
Newton3D_CorrectionFunc func_correction,
diff --git a/source/blender/blenlib/intern/math_statistics.c b/source/blender/blenlib/intern/math_statistics.c
index b90ac99dbfe..8087e7a962a 100644
--- a/source/blender/blenlib/intern/math_statistics.c
+++ b/source/blender/blenlib/intern/math_statistics.c
@@ -87,18 +87,6 @@ static void covariance_m_vn_ex_task_cb(void *__restrict userdata,
}
}
-/**
- * \brief Compute the covariance matrix of given set of nD coordinates.
- *
- * \param n: the dimension of the vectors (and hence, of the covariance matrix to compute).
- * \param cos_vn: the nD points to compute covariance from.
- * \param nbr_cos_vn: the number of nD coordinates in cos_vn.
- * \param center: the center (or mean point) of cos_vn. If NULL,
- * it is assumed cos_vn is already centered.
- * \param use_sample_correction: whether to apply sample correction
- * (i.e. get 'sample variance' instead of 'population variance').
- * \return r_covmat the computed covariance matrix.
- */
void BLI_covariance_m_vn_ex(const int n,
const float *cos_vn,
const int nbr_cos_vn,
@@ -128,14 +116,6 @@ void BLI_covariance_m_vn_ex(const int n,
BLI_task_parallel_range(0, n * n, &data, covariance_m_vn_ex_task_cb, &settings);
}
-/**
- * \brief Compute the covariance matrix of given set of 3D coordinates.
- *
- * \param cos_v3: the 3D points to compute covariance from.
- * \param nbr_cos_v3: the number of 3D coordinates in cos_v3.
- * \return r_covmat the computed covariance matrix.
- * \return r_center the computed center (mean) of 3D points (may be NULL).
- */
void BLI_covariance_m3_v3n(const float (*cos_v3)[3],
const int nbr_cos_v3,
const bool use_sample_correction,
diff --git a/source/blender/blenlib/intern/math_time.c b/source/blender/blenlib/intern/math_time.c
index b85de7817dd..4484144a81e 100644
--- a/source/blender/blenlib/intern/math_time.c
+++ b/source/blender/blenlib/intern/math_time.c
@@ -23,13 +23,6 @@
#include "BLI_math.h"
-/** Explode given time value expressed in seconds, into a set of days, hours, minutes, seconds
- * and/or milliseconds (depending on which return parameters are not NULL).
- *
- * \note The smallest given return parameter will get the potential fractional remaining time
- * value. E.g. if you give `seconds=90.0` and do not pass `r_seconds` and `r_milliseconds`,
- * `r_minutes` will be set to `1.5`.
- */
void BLI_math_time_seconds_decompose(double seconds,
double *r_days,
double *r_hours,
diff --git a/source/blender/blenlib/intern/math_vector.c b/source/blender/blenlib/intern/math_vector.c
index 35dfe421cf0..a0afab8a179 100644
--- a/source/blender/blenlib/intern/math_vector.c
+++ b/source/blender/blenlib/intern/math_vector.c
@@ -37,8 +37,6 @@ void interp_v2_v2v2(float r[2], const float a[2], const float b[2], const float
r[1] = s * a[1] + t * b[1];
}
-/* weight 3 2D vectors,
- * 'w' must be unit length but is not a vector, just 3 weights */
void interp_v2_v2v2v2(
float r[2], const float a[2], const float b[2], const float c[2], const float t[3])
{
@@ -65,12 +63,6 @@ void interp_v4_v4v4(float r[4], const float a[4], const float b[4], const float
r[3] = s * a[3] + t * b[3];
}
-/**
- * slerp, treat vectors as spherical coordinates
- * \see #interp_qt_qtqt
- *
- * \return success
- */
bool interp_v3_v3v3_slerp(float target[3], const float a[3], const float b[3], const float t)
{
float cosom, w[2];
@@ -115,9 +107,6 @@ bool interp_v2_v2v2_slerp(float target[2], const float a[2], const float b[2], c
return true;
}
-/**
- * Same as #interp_v3_v3v3_slerp but uses fallback values for opposite vectors.
- */
void interp_v3_v3v3_slerp_safe(float target[3], const float a[3], const float b[3], const float t)
{
if (UNLIKELY(!interp_v3_v3v3_slerp(target, a, b, t))) {
@@ -186,8 +175,6 @@ void interp_v2_v2v2v2v2_cubic(float p[2],
/** \} */
-/* weight 3 vectors,
- * 'w' must be unit length but is not a vector, just 3 weights */
void interp_v3_v3v3v3(
float p[3], const float v1[3], const float v2[3], const float v3[3], const float w[3])
{
@@ -196,8 +183,6 @@ void interp_v3_v3v3v3(
p[2] = v1[2] * w[0] + v2[2] * w[1] + v3[2] * w[2];
}
-/* weight 3 vectors,
- * 'w' must be unit length but is not a vector, just 4 weights */
void interp_v3_v3v3v3v3(float p[3],
const float v1[3],
const float v2[3],
@@ -311,18 +296,6 @@ void mid_v3_v3_array(float r[3], const float (*vec_arr)[3], const uint nbr)
}
}
-/**
- * Specialized function for calculating normals.
- * Fast-path for:
- *
- * \code{.c}
- * add_v3_v3v3(r, a, b);
- * normalize_v3(r)
- * mul_v3_fl(r, angle_normalized_v3v3(a, b) / M_PI_2);
- * \endcode
- *
- * We can use the length of (a + b) to calculate the angle.
- */
void mid_v3_v3v3_angle_weighted(float r[3], const float a[3], const float b[3])
{
/* trick, we want the middle of 2 normals as well as the angle between them
@@ -341,10 +314,6 @@ void mid_v3_v3v3_angle_weighted(float r[3], const float a[3], const float b[3])
acosf(normalize_v3(r) / 2.0f);
mul_v3_fl(r, angle);
}
-/**
- * Same as mid_v3_v3v3_angle_weighted
- * but \a r is assumed to be accumulated normals, divided by their total.
- */
void mid_v3_angle_weighted(float r[3])
{
/* trick, we want the middle of 2 normals as well as the angle between them
@@ -407,13 +376,6 @@ bool is_finite_v4(const float v[4])
/********************************** Angles ***********************************/
-/* Return the angle in radians between vecs 1-2 and 2-3 in radians
- * If v1 is a shoulder, v2 is the elbow and v3 is the hand,
- * this would return the angle at the elbow.
- *
- * note that when v1/v2/v3 represent 3 points along a straight line
- * that the angle returned will be pi (180deg), rather than 0.0
- */
float angle_v3v3v3(const float a[3], const float b[3], const float c[3])
{
float vec1[3], vec2[3];
@@ -426,7 +388,6 @@ float angle_v3v3v3(const float a[3], const float b[3], const float c[3])
return angle_normalized_v3v3(vec1, vec2);
}
-/* Quicker than full angle computation */
float cos_v3v3v3(const float p1[3], const float p2[3], const float p3[3])
{
float vec1[3], vec2[3];
@@ -439,7 +400,6 @@ float cos_v3v3v3(const float p1[3], const float p2[3], const float p3[3])
return dot_v3v3(vec1, vec2);
}
-/* Return the shortest angle in radians between the 2 vectors */
float angle_v3v3(const float a[3], const float b[3])
{
float vec1[3], vec2[3];
@@ -466,7 +426,6 @@ float angle_v2v2v2(const float a[2], const float b[2], const float c[2])
return angle_normalized_v2v2(vec1, vec2);
}
-/* Quicker than full angle computation */
float cos_v2v2v2(const float p1[2], const float p2[2], const float p3[2])
{
float vec1[2], vec2[2];
@@ -479,7 +438,6 @@ float cos_v2v2v2(const float p1[2], const float p2[2], const float p3[2])
return dot_v2v2(vec1, vec2);
}
-/* Return the shortest angle in radians between the 2 vectors */
float angle_v2v2(const float a[2], const float b[2])
{
float vec1[2], vec2[2];
@@ -534,9 +492,6 @@ float angle_normalized_v2v2(const float a[2], const float b[2])
return (float)M_PI - 2.0f * saasin(len_v2v2(a, v2_n) / 2.0f);
}
-/**
- * Angle between 2 vectors, about an axis (axis can be considered a plane).
- */
float angle_on_axis_v3v3_v3(const float v1[3], const float v2[3], const float axis[3])
{
float v1_proj[3], v2_proj[3];
@@ -568,9 +523,6 @@ float angle_signed_on_axis_v3v3_v3(const float v1[3], const float v2[3], const f
return angle;
}
-/**
- * Angle between 2 vectors defined by 3 coords, about an axis (axis can be considered a plane).
- */
float angle_on_axis_v3v3v3_v3(const float v1[3],
const float v2[3],
const float v3[3],
@@ -652,9 +604,6 @@ void angle_poly_v3(float *angles, const float *verts[3], int len)
/********************************* Geometry **********************************/
-/**
- * Project \a p onto \a v_proj
- */
void project_v2_v2v2(float out[2], const float p[2], const float v_proj[2])
{
if (UNLIKELY(is_zero_v2(v_proj))) {
@@ -666,9 +615,6 @@ void project_v2_v2v2(float out[2], const float p[2], const float v_proj[2])
mul_v2_v2fl(out, v_proj, mul);
}
-/**
- * Project \a p onto \a v_proj
- */
void project_v3_v3v3(float out[3], const float p[3], const float v_proj[3])
{
if (UNLIKELY(is_zero_v3(v_proj))) {
@@ -691,9 +637,6 @@ void project_v3_v3v3_db(double out[3], const double p[3], const double v_proj[3]
mul_v3_v3db_db(out, v_proj, mul);
}
-/**
- * Project \a p onto a unit length \a v_proj
- */
void project_v2_v2v2_normalized(float out[2], const float p[2], const float v_proj[2])
{
BLI_ASSERT_UNIT_V2(v_proj);
@@ -702,9 +645,6 @@ void project_v2_v2v2_normalized(float out[2], const float p[2], const float v_pr
mul_v2_v2fl(out, v_proj, mul);
}
-/**
- * Project \a p onto a unit length \a v_proj
- */
void project_v3_v3v3_normalized(float out[3], const float p[3], const float v_proj[3])
{
BLI_ASSERT_UNIT_V3(v_proj);
@@ -713,19 +653,6 @@ void project_v3_v3v3_normalized(float out[3], const float p[3], const float v_pr
mul_v3_v3fl(out, v_proj, mul);
}
-/**
- * In this case plane is a 3D vector only (no 4th component).
- *
- * Projecting will make \a out a copy of \a p orthogonal to \a v_plane.
- *
- * \note If \a p is exactly perpendicular to \a v_plane, \a out will just be a copy of \a p.
- *
- * \note This function is a convenience to call:
- * \code{.c}
- * project_v3_v3v3(out, p, v_plane);
- * sub_v3_v3v3(out, p, out);
- * \endcode
- */
void project_plane_v3_v3v3(float out[3], const float p[3], const float v_plane[3])
{
const float mul = dot_v3v3(p, v_plane) / dot_v3v3(v_plane, v_plane);
@@ -756,7 +683,6 @@ void project_plane_normalized_v2_v2v2(float out[2], const float p[2], const floa
madd_v2_v2v2fl(out, p, v_plane, -mul);
}
-/* project a vector on a plane defined by normal and a plane point p */
void project_v3_plane(float out[3], const float plane_no[3], const float plane_co[3])
{
float vector[3];
@@ -769,7 +695,6 @@ void project_v3_plane(float out[3], const float plane_no[3], const float plane_c
madd_v3_v3fl(out, plane_no, -mul);
}
-/* Returns a vector bisecting the angle at b formed by a, b and c */
void bisect_v3_v3v3v3(float r[3], const float a[3], const float b[3], const float c[3])
{
float d_12[3], d_23[3];
@@ -781,22 +706,6 @@ void bisect_v3_v3v3v3(float r[3], const float a[3], const float b[3], const floa
normalize_v3(r);
}
-/**
- * Returns a reflection vector from a vector and a normal vector
- * reflect = vec - ((2 * dot(vec, mirror)) * mirror).
- *
- * <pre>
- * v
- * + ^
- * \ |
- * \|
- * + normal: axis of reflection
- * /
- * /
- * +
- * out: result (negate for a 'bounce').
- * </pre>
- */
void reflect_v3_v3v3(float out[3], const float v[3], const float normal[3])
{
BLI_ASSERT_UNIT_V3(normal);
@@ -813,11 +722,6 @@ void reflect_v3_v3v3_db(double out[3], const double v[3], const double normal[3]
madd_v3_v3v3db_db(out, v, normal, -dot2);
}
-/**
- * Takes a vector and computes 2 orthogonal directions.
- *
- * \note if \a n is n unit length, computed values will be too.
- */
void ortho_basis_v3v3_v3(float r_n1[3], float r_n2[3], const float n[3])
{
const float eps = FLT_EPSILON;
@@ -843,11 +747,6 @@ void ortho_basis_v3v3_v3(float r_n1[3], float r_n2[3], const float n[3])
}
}
-/**
- * Calculates \a p - a perpendicular vector to \a v
- *
- * \note return vector won't maintain same length.
- */
void ortho_v3_v3(float out[3], const float v[3])
{
const int axis = axis_dominant_v3_single(v);
@@ -873,9 +772,6 @@ void ortho_v3_v3(float out[3], const float v[3])
}
}
-/**
- * no brainer compared to v3, just have for consistency.
- */
void ortho_v2_v2(float out[2], const float v[2])
{
BLI_assert(out != v);
@@ -884,9 +780,6 @@ void ortho_v2_v2(float out[2], const float v[2])
out[1] = v[0];
}
-/**
- * Rotate a point \a p by \a angle around origin (0, 0)
- */
void rotate_v2_v2fl(float r[2], const float p[2], const float angle)
{
const float co = cosf(angle);
@@ -898,10 +791,6 @@ void rotate_v2_v2fl(float r[2], const float p[2], const float angle)
r[1] = si * p[0] + co * p[1];
}
-/**
- * Rotate a point \a p by \a angle around an arbitrary unit length \a axis.
- * http://local.wasp.uwa.edu.au/~pbourke/geometry/
- */
void rotate_normalized_v3_v3v3fl(float out[3],
const float p[3],
const float axis[3],
@@ -1040,7 +929,6 @@ void minmax_v3v3_v3_array(float r_min[3], float r_max[3], const float (*vec_arr)
}
}
-/** ensure \a v1 is \a dist from \a v2 */
void dist_ensure_v3_v3fl(float v1[3], const float v2[3], const float dist)
{
if (!equals_v3v3(v2, v1)) {
diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c
index bb32b511005..648f876acaa 100644
--- a/source/blender/blenlib/intern/math_vector_inline.c
+++ b/source/blender/blenlib/intern/math_vector_inline.c
@@ -101,6 +101,7 @@ MINLINE void copy_v4_fl(float r[4], float f)
}
/* unsigned char */
+
MINLINE void copy_v2_v2_uchar(unsigned char r[2], const unsigned char a[2])
{
r[0] = a[0];
@@ -144,6 +145,7 @@ 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])
{
r[0] = a[0];
@@ -224,6 +226,7 @@ MINLINE void copy_v4_v4_int(int r[4], const int a[4])
}
/* double */
+
MINLINE void zero_v3_db(double r[3])
{
r[0] = 0.0;
@@ -252,7 +255,6 @@ MINLINE void copy_v4_v4_db(double r[4], const double a[4])
r[3] = a[3];
}
-/* int <-> float */
MINLINE void round_v2i_v2fl(int r[2], const float a[2])
{
r[0] = (int)roundf(a[0]);
@@ -266,6 +268,7 @@ MINLINE void copy_v2fl_v2i(float r[2], const int a[2])
}
/* double -> float */
+
MINLINE void copy_v2fl_v2db(float r[2], const double a[2])
{
r[0] = (float)a[0];
@@ -288,6 +291,7 @@ MINLINE void copy_v4fl_v4db(float r[4], const double a[4])
}
/* float -> double */
+
MINLINE void copy_v2db_v2fl(double r[2], const float a[2])
{
r[0] = (double)a[0];
@@ -331,6 +335,7 @@ MINLINE void swap_v4_v4(float a[4], float b[4])
}
/* float args -> vec */
+
MINLINE void copy_v2_fl2(float v[2], float x, float y)
{
v[0] = x;
@@ -639,26 +644,11 @@ MINLINE void mul_v2_v2_ccw(float r[2], const float mat[2], const float vec[2])
r[1] = mat[1] * vec[0] + (+mat[0]) * vec[1];
}
-/**
- * Convenience function to get the projected depth of a position.
- * This avoids creating a temporary 4D vector and multiplying it - only for the 4th component.
- *
- * Matches logic for:
- *
- * \code{.c}
- * float co_4d[4] = {co[0], co[1], co[2], 1.0};
- * mul_m4_v4(mat, co_4d);
- * return co_4d[3];
- * \endcode
- */
MINLINE float mul_project_m4_v3_zfac(const float mat[4][4], const float co[3])
{
return (mat[0][3] * co[0]) + (mat[1][3] * co[1]) + (mat[2][3] * co[2]) + mat[3][3];
}
-/**
- * Has the effect of #mul_m3_v3(), on a single axis.
- */
MINLINE float dot_m3_v3_row_x(const float M[3][3], const float a[3])
{
return M[0][0] * a[0] + M[1][0] * a[1] + M[2][0] * a[2];
@@ -672,10 +662,6 @@ MINLINE float dot_m3_v3_row_z(const float M[3][3], const float a[3])
return M[0][2] * a[0] + M[1][2] * a[1] + M[2][2] * a[2];
}
-/**
- * Has the effect of #mul_mat3_m4_v3(), on a single axis.
- * (no adding translation)
- */
MINLINE float dot_m4_v3_row_x(const float M[4][4], const float a[3])
{
return M[0][0] * a[0] + M[1][0] * a[1] + M[2][0] * a[2];
@@ -817,7 +803,6 @@ MINLINE void negate_v4_v4(float r[4], const float a[4])
r[3] = -a[3];
}
-/* could add more... */
MINLINE void negate_v3_short(short r[3])
{
r[0] = (short)-r[0];
@@ -962,8 +947,6 @@ MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
r[2] = a[0] * b[1] - a[1] * b[0];
}
-/* cross product suffers from severe precision loss when vectors are
- * nearly parallel or opposite; doing the computation in double helps a lot */
MINLINE void cross_v3_v3v3_hi_prec(float r[3], const float a[3], const float b[3])
{
BLI_assert(r != a && r != b);
@@ -980,10 +963,6 @@ MINLINE void cross_v3_v3v3_db(double r[3], const double a[3], const double b[3])
r[2] = a[0] * b[1] - a[1] * b[0];
}
-/* Newell's Method */
-/* excuse this fairly specific function,
- * its used for polygon normals all over the place
- * could use a better name */
MINLINE void add_newell_cross_v3_v3v3(float n[3], const float v_prev[3], const float v_curr[3])
{
n[0] += (v_prev[1] - v_curr[1]) * (v_prev[2] + v_curr[2]);
@@ -1158,9 +1137,6 @@ MINLINE float len_v4v4(const float a[4], const float b[4])
return len_v4(d);
}
-/**
- * \note any vectors containing `nan` will be zeroed out.
- */
MINLINE float normalize_v2_v2_length(float r[2], const float a[2], const float unit_length)
{
float d = dot_v2v2(a, a);
@@ -1192,9 +1168,6 @@ MINLINE float normalize_v2_length(float n[2], const float unit_length)
return normalize_v2_v2_length(n, n, unit_length);
}
-/**
- * \note any vectors containing `nan` will be zeroed out.
- */
MINLINE float normalize_v3_v3_length(float r[3], const float a[3], const float unit_length)
{
float d = dot_v3v3(a, a);
@@ -1498,18 +1471,6 @@ MINLINE void clamp_v4_v4v4(float vec[4], const float min[4], const float max[4])
/** \} */
-/**
- * <pre>
- * + l1
- * |
- * neg <- | -> pos
- * |
- * + l2
- * </pre>
- *
- * \return Positive value when 'pt' is left-of-line
- * (looking from 'l1' -> 'l2').
- */
MINLINE float line_point_side_v2(const float l1[2], const float l2[2], const float pt[2])
{
return (((l1[0] - pt[0]) * (l2[1] - pt[1])) - ((l2[0] - pt[0]) * (l1[1] - pt[1])));
diff --git a/source/blender/blenlib/intern/memory_utils.c b/source/blender/blenlib/intern/memory_utils.c
index 4bb93877401..2befcb1bb19 100644
--- a/source/blender/blenlib/intern/memory_utils.c
+++ b/source/blender/blenlib/intern/memory_utils.c
@@ -30,9 +30,6 @@
#include "BLI_strict_flags.h"
-/**
- * Check if memory is zeroed, as with `memset(arr, 0, arr_size)`.
- */
bool BLI_memory_is_zero(const void *arr, const size_t arr_size)
{
const char *arr_byte = arr;
diff --git a/source/blender/blenlib/intern/mesh_boolean.cc b/source/blender/blenlib/intern/mesh_boolean.cc
index 8b029d11c3f..ce4db0c6b9d 100644
--- a/source/blender/blenlib/intern/mesh_boolean.cc
+++ b/source/blender/blenlib/intern/mesh_boolean.cc
@@ -1370,6 +1370,11 @@ static bool is_pwn(const IMesh &tm, const TriMeshTopology &tmtopo)
}
threading::parallel_for(tris.index_range(), 2048, [&](IndexRange range) {
+ if (!is_pwn.load()) {
+ /* Early out if mesh is already determined to be non-pwn. */
+ return;
+ }
+
for (int j : range) {
const Edge &edge = tris[j].first;
int tot_orient = 0;
@@ -1395,9 +1400,7 @@ static bool is_pwn(const IMesh &tm, const TriMeshTopology &tmtopo)
std::cout << "edge causing non-pwn: " << edge << "\n";
}
is_pwn = false;
-# ifdef WITH_TBB
- tbb::task::self().cancel_group_execution();
-# endif
+ break;
}
}
});
@@ -3673,10 +3676,6 @@ static void dump_test_spec(IMesh &imesh)
}
}
-/**
- * Do the boolean operation op on the polygon mesh imesh_in.
- * See the header file for a complete description.
- */
IMesh boolean_mesh(IMesh &imesh,
BoolOpType op,
int nshapes,
diff --git a/source/blender/blenlib/intern/mesh_intersect.cc b/source/blender/blenlib/intern/mesh_intersect.cc
index feb7b64f766..ab1db3f1fda 100644
--- a/source/blender/blenlib/intern/mesh_intersect.cc
+++ b/source/blender/blenlib/intern/mesh_intersect.cc
@@ -150,7 +150,6 @@ Plane::Plane(const double3 &norm, const double d) : norm(norm), d(d)
norm_exact = mpq3(0, 0, 0); /* Marks as "exact not yet populated". */
}
-/** This is wrong for degenerate planes, but we don't expect to call it on those. */
bool Plane::exact_populated() const
{
return norm_exact[0] != 0 || norm_exact[1] != 0 || norm_exact[2] != 0;
@@ -803,11 +802,6 @@ std::ostream &operator<<(std::ostream &os, const IMesh &mesh)
return os;
}
-/**
- * Assume bounding boxes have been expanded by a sufficient epsilon on all sides
- * so that the comparisons against the bb bounds are sufficient to guarantee that
- * if an overlap or even touching could happen, this will return true.
- */
bool bbs_might_intersect(const BoundingBox &bb_a, const BoundingBox &bb_b)
{
return isect_aabb_aabb_v3(bb_a.min, bb_a.max, bb_b.min, bb_b.max);
@@ -2276,12 +2270,6 @@ static Array<Face *> triangulate_poly(Face *f, IMeshArena *arena)
return ans;
}
-/**
- * Return an #IMesh that is a triangulation of a mesh with general
- * polygonal faces, #IMesh.
- * Added diagonals will be distinguishable by having edge original
- * indices of #NO_INDEX.
- */
IMesh triangulate_polymesh(IMesh &imesh, IMeshArena *arena)
{
Vector<Face *> face_tris;
@@ -2568,79 +2556,6 @@ static void calc_overlap_itts(Map<std::pair<int, int>, ITT_value> &itt_map,
}
/**
- * Data needed for parallelization of calc_subdivided_non_cluster_tris.
- */
-struct OverlapTriRange {
- int tri_index;
- int overlap_start;
- int len;
-};
-struct SubdivideTrisData {
- Array<IMesh> &r_tri_subdivided;
- const IMesh &tm;
- const Map<std::pair<int, int>, ITT_value> &itt_map;
- Span<BVHTreeOverlap> overlap;
- IMeshArena *arena;
-
- /* This vector gives, for each triangle in tm that has an intersection
- * we want to calculate: what the index of that triangle in tm is,
- * where it starts in the ov structure as indexA, and how many
- * overlap pairs have that same indexA (they will be continuous). */
- Vector<OverlapTriRange> overlap_tri_range;
-
- SubdivideTrisData(Array<IMesh> &r_tri_subdivided,
- const IMesh &tm,
- const Map<std::pair<int, int>, ITT_value> &itt_map,
- Span<BVHTreeOverlap> overlap,
- IMeshArena *arena)
- : r_tri_subdivided(r_tri_subdivided),
- tm(tm),
- itt_map(itt_map),
- overlap(overlap),
- arena(arena)
- {
- }
-};
-
-static void calc_subdivided_tri_range_func(void *__restrict userdata,
- const int iter,
- const TaskParallelTLS *__restrict UNUSED(tls))
-{
- constexpr int dbg_level = 0;
- SubdivideTrisData *data = static_cast<SubdivideTrisData *>(userdata);
- OverlapTriRange &otr = data->overlap_tri_range[iter];
- int t = otr.tri_index;
- if (dbg_level > 0) {
- std::cout << "calc_subdivided_tri_range_func\nt=" << t << " start=" << otr.overlap_start
- << " len=" << otr.len << "\n";
- }
- constexpr int inline_capacity = 100;
- Vector<ITT_value, inline_capacity> itts(otr.len);
- for (int j = otr.overlap_start; j < otr.overlap_start + otr.len; ++j) {
- int t_other = data->overlap[j].indexB;
- std::pair<int, int> key = canon_int_pair(t, t_other);
- ITT_value itt;
- if (data->itt_map.contains(key)) {
- itt = data->itt_map.lookup(key);
- }
- if (itt.kind != INONE) {
- itts.append(itt);
- }
- if (dbg_level > 0) {
- std::cout << " tri t" << t_other << "; result = " << itt << "\n";
- }
- }
- if (itts.size() > 0) {
- CDT_data cd_data = prepare_cdt_input(data->tm, t, itts);
- do_cdt(cd_data);
- data->r_tri_subdivided[t] = extract_subdivided_tri(cd_data, data->tm, t, data->arena);
- if (dbg_level > 0) {
- std::cout << "subdivide output\n" << data->r_tri_subdivided[t];
- }
- }
-}
-
-/**
* For each triangle in tm, fill in the corresponding slot in
* r_tri_subdivided with the result of intersecting it with
* all the other triangles in the mesh, if it intersects any others.
@@ -2658,10 +2573,14 @@ static void calc_subdivided_non_cluster_tris(Array<IMesh> &r_tri_subdivided,
std::cout << "\nCALC_SUBDIVIDED_TRIS\n\n";
}
Span<BVHTreeOverlap> overlap = ov.overlap();
- SubdivideTrisData data(r_tri_subdivided, tm, itt_map, overlap, arena);
+ struct OverlapTriRange {
+ int tri_index;
+ int overlap_start;
+ int len;
+ };
+ Vector<OverlapTriRange> overlap_tri_range;
int overlap_tot = overlap.size();
- data.overlap_tri_range = Vector<OverlapTriRange>();
- data.overlap_tri_range.reserve(overlap_tot);
+ overlap_tri_range.reserve(overlap_tot);
int overlap_index = 0;
while (overlap_index < overlap_tot) {
int t = overlap[overlap_index].indexA;
@@ -2676,7 +2595,7 @@ static void calc_subdivided_non_cluster_tris(Array<IMesh> &r_tri_subdivided,
int len = i - overlap_index + 1;
if (!(len == 1 && overlap[overlap_index].indexB == t)) {
OverlapTriRange range = {t, overlap_index, len};
- data.overlap_tri_range.append(range);
+ overlap_tri_range.append(range);
# ifdef PERFDEBUG
bumpperfcount(0, len); /* Non-cluster overlaps. */
# endif
@@ -2684,13 +2603,50 @@ static void calc_subdivided_non_cluster_tris(Array<IMesh> &r_tri_subdivided,
}
overlap_index = i + 1;
}
- int overlap_tri_range_tot = data.overlap_tri_range.size();
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.min_iter_per_thread = 50;
- settings.use_threading = intersect_use_threading;
- BLI_task_parallel_range(
- 0, overlap_tri_range_tot, &data, calc_subdivided_tri_range_func, &settings);
+ int overlap_tri_range_tot = overlap_tri_range.size();
+ Array<CDT_data> cd_data(overlap_tri_range_tot);
+ int grain_size = 64;
+ threading::parallel_for(overlap_tri_range.index_range(), grain_size, [&](IndexRange range) {
+ for (int otr_index : range) {
+ OverlapTriRange &otr = overlap_tri_range[otr_index];
+ int t = otr.tri_index;
+ if (dbg_level > 0) {
+ std::cout << "handling overlap range\nt=" << t << " start=" << otr.overlap_start
+ << " len=" << otr.len << "\n";
+ }
+ constexpr int inline_capacity = 100;
+ Vector<ITT_value, inline_capacity> itts(otr.len);
+ for (int j = otr.overlap_start; j < otr.overlap_start + otr.len; ++j) {
+ int t_other = overlap[j].indexB;
+ std::pair<int, int> key = canon_int_pair(t, t_other);
+ ITT_value itt;
+ if (itt_map.contains(key)) {
+ itt = itt_map.lookup(key);
+ }
+ if (itt.kind != INONE) {
+ itts.append(itt);
+ }
+ if (dbg_level > 0) {
+ std::cout << " tri t" << t_other << "; result = " << itt << "\n";
+ }
+ }
+ if (itts.size() > 0) {
+ cd_data[otr_index] = prepare_cdt_input(tm, t, itts);
+ do_cdt(cd_data[otr_index]);
+ }
+ }
+ });
+ /* Extract the new faces serially, so that Boolean is repeatable regardless of parallelism. */
+ for (int otr_index : overlap_tri_range.index_range()) {
+ CDT_data &cdd = cd_data[otr_index];
+ if (cdd.vert.size() > 0) {
+ int t = overlap_tri_range[otr_index].tri_index;
+ r_tri_subdivided[t] = extract_subdivided_tri(cdd, tm, t, arena);
+ if (dbg_level > 1) {
+ std::cout << "subdivide output for tri " << t << " = " << r_tri_subdivided[t];
+ }
+ }
+ }
/* Now have to put in the triangles that are the same as the input ones, and not in clusters.
*/
threading::parallel_for(tm.face_index_range(), 2048, [&](IndexRange range) {
@@ -2994,7 +2950,6 @@ static IMesh remove_degenerate_tris(const IMesh &tm_in)
return ans;
}
-/* This is the main routine for calculating the self_intersection of a triangle mesh. */
IMesh trimesh_self_intersect(const IMesh &tm_in, IMeshArena *arena)
{
return trimesh_nary_intersect(
@@ -3169,9 +3124,6 @@ static std::ostream &operator<<(std::ostream &os, const ITT_value &itt)
return os;
}
-/**
- * Writing the obj_mesh has the side effect of populating verts.
- */
void write_obj_mesh(IMesh &m, const std::string &objname)
{
/* Would like to use #BKE_tempdir_base() here, but that brings in dependence on kernel library.
@@ -3227,7 +3179,7 @@ struct PerfCounts {
static PerfCounts *perfdata = nullptr;
-static void perfdata_init(void)
+static void perfdata_init()
{
perfdata = new PerfCounts;
@@ -3279,7 +3231,7 @@ static void doperfmax(int maxnum, int val)
perfdata->max[maxnum] = max_ii(perfdata->max[maxnum], val);
}
-static void dump_perfdata(void)
+static void dump_perfdata()
{
std::cout << "\nPERFDATA\n";
for (int i : perfdata->count.index_range()) {
diff --git a/source/blender/blenlib/intern/noise.c b/source/blender/blenlib/intern/noise.c
index a0938f4f713..ce4dee16d32 100644
--- a/source/blender/blenlib/intern/noise.c
+++ b/source/blender/blenlib/intern/noise.c
@@ -429,15 +429,17 @@ static float orgBlenderNoise(float x, float y, float z)
return n;
}
-/* as orgBlenderNoise(), returning signed noise */
static float orgBlenderNoiseS(float x, float y, float z)
{
+ /* NOTE: As #orgBlenderNoise(), returning signed noise. */
+
return (2.0f * orgBlenderNoise(x, y, z) - 1.0f);
}
-/* separated from orgBlenderNoise above, with scaling */
float BLI_noise_hnoise(float noisesize, float x, float y, float z)
{
+ /* NOTE: Separated from orgBlenderNoise, with scaling. */
+
if (noisesize == 0.0f) {
return 0.0f;
}
@@ -447,7 +449,6 @@ float BLI_noise_hnoise(float noisesize, float x, float y, float z)
return orgBlenderNoise(x, y, z);
}
-/* original turbulence functions */
float BLI_noise_turbulence(float noisesize, float x, float y, float z, int nr)
{
float s, d = 0.5, div = 1.0;
@@ -926,8 +927,6 @@ static float dist_Minkovsky(float x, float y, float z, float e)
return powf(powf(fabsf(x), e) + powf(fabsf(y), e) + powf(fabsf(z), e), 1.0f / e);
}
-/* Not 'pure' Worley, but the results are virtually the same.
- * Returns distances in da and point coords in pa */
void BLI_noise_voronoi(float x, float y, float z, float *da, float *pa, float me, int dtype)
{
float (*distfunc)(float, float, float, float);
@@ -1137,13 +1136,11 @@ static float BLI_cellNoiseU(float x, float y, float z)
return ((float)(n * (n * n * 15731 + 789221) + 1376312589) / 4294967296.0f);
}
-/* idem, signed */
float BLI_noise_cell(float x, float y, float z)
{
return (2.0f * BLI_cellNoiseU(x, y, z) - 1.0f);
}
-/* returns a vector/point/color in ca, using point hasharray directly */
void BLI_noise_cell_v3(float x, float y, float z, float ca[3])
{
/* avoid precision issues on unit coordinates */
@@ -1166,9 +1163,6 @@ void BLI_noise_cell_v3(float x, float y, float z, float ca[3])
/** \name Public API's
* \{ */
-/**
- * newnoise: generic noise function for use with different `noisebasis`.
- */
float BLI_noise_generic_noise(
float noisesize, float x, float y, float z, bool hard, int noisebasis)
{
@@ -1226,7 +1220,6 @@ float BLI_noise_generic_noise(
return noisefunc(x, y, z);
}
-/* newnoise: generic turbulence function for use with different noisebasis */
float BLI_noise_generic_turbulence(
float noisesize, float x, float y, float z, int oct, bool hard, int noisebasis)
{
@@ -1289,21 +1282,12 @@ float BLI_noise_generic_turbulence(
return sum;
}
-/*
- * The following code is based on Ken Musgrave's explanations and sample
- * source code in the book "Texturing and Modeling: A procedural approach"
- */
-
-/**
- * Procedural `fBm` evaluated at "point"; returns value stored in "value".
- *
- * \param H: is the fractal increment parameter.
- * \param lacunarity: is the gap between successive frequencies.
- * \param octaves: is the number of frequencies in the `fBm`.
- */
float BLI_noise_mg_fbm(
float x, float y, float z, float H, float lacunarity, float octaves, int noisebasis)
{
+ /* The following code is based on Ken Musgrave's explanations and sample
+ * source code in the book "Texturing and Modeling: A procedural approach". */
+
float (*noisefunc)(float, float, float);
switch (noisebasis) {
case 1:
@@ -1358,24 +1342,13 @@ float BLI_noise_mg_fbm(
} /* fBm() */
-/**
- * Procedural multi-fractal evaluated at "point";
- * returns value stored in "value".
- *
- * \param H: determines the highest fractal dimension.
- * \param lacunarity: is gap between successive frequencies.
- * \param octaves: is the number of frequencies in the `fBm`.
- *
- * \note There used to be a parameter called `offset`, old docs read:
- * is the zero offset, which determines multi-fractality.
- */
-
-/* this one is in fact rather confusing,
- * there seem to be errors in the original source code (in all three versions of proc.text&mod),
- * I modified it to something that made sense to me, so it might be wrong... */
float BLI_noise_mg_multi_fractal(
float x, float y, float z, float H, float lacunarity, float octaves, int noisebasis)
{
+ /* This one is in fact rather confusing,
+ * there seem to be errors in the original source code (in all three versions of proc.text&mod),
+ * I modified it to something that made sense to me, so it might be wrong. */
+
float (*noisefunc)(float, float, float);
switch (noisebasis) {
case 1:
@@ -1428,15 +1401,6 @@ float BLI_noise_mg_multi_fractal(
return value;
}
-/**
- * Heterogeneous procedural terrain function: stats by altitude method.
- * Evaluated at "point"; returns value stored in "value".
- *
- * \param H: Determines the fractal dimension of the roughest areas.
- * \param lacunarity: Is the gap between successive frequencies.
- * \param octaves: Is the number of frequencies in the `fBm`.
- * \param offset: Raises the terrain from `sea level`.
- */
float BLI_noise_mg_hetero_terrain(float x,
float y,
float z,
@@ -1507,13 +1471,6 @@ float BLI_noise_mg_hetero_terrain(float x,
return value;
}
-/* Hybrid additive/multiplicative multifractal terrain model.
- *
- * Some good parameter values to start with:
- *
- * H: 0.25
- * offset: 0.7
- */
float BLI_noise_mg_hybrid_multi_fractal(float x,
float y,
float z,
@@ -1590,14 +1547,6 @@ float BLI_noise_mg_hybrid_multi_fractal(float x,
} /* HybridMultifractal() */
-/* Ridged multifractal terrain model.
- *
- * Some good parameter values to start with:
- *
- * H: 1.0
- * offset: 1.0
- * gain: 2.0
- */
float BLI_noise_mg_ridged_multi_fractal(float x,
float y,
float z,
@@ -1669,9 +1618,6 @@ float BLI_noise_mg_ridged_multi_fractal(float x,
return result;
} /* RidgedMultifractal() */
-/* "Variable Lacunarity Noise"
- * A distorted variety of Perlin noise.
- */
float BLI_noise_mg_variable_lacunarity(
float x, float y, float z, float distortion, int nbas1, int nbas2)
{
diff --git a/source/blender/blenlib/intern/noise.cc b/source/blender/blenlib/intern/noise.cc
index 959385bff31..a6ad18801fd 100644
--- a/source/blender/blenlib/intern/noise.cc
+++ b/source/blender/blenlib/intern/noise.cc
@@ -58,13 +58,12 @@
#include "BLI_utildefines.h"
namespace blender::noise {
-/* ------------------------------
- * Jenkins Lookup3 Hash Functions
- * ------------------------------
+
+/* -------------------------------------------------------------------- */
+/** \name Jenkins Lookup3 Hash Functions
*
* https://burtleburtle.net/bob/c/lookup3.c
- *
- */
+ * \{ */
BLI_INLINE uint32_t hash_bit_rotate(uint32_t x, uint32_t k)
{
@@ -283,16 +282,17 @@ float4 hash_float_to_float4(float4 k)
hash_float_to_float(float4(k.y, k.z, k.w, k.x)));
}
-/* ------------
- * Perlin Noise
- * ------------
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Perlin Noise
*
* Perlin, Ken. "Improving noise." Proceedings of the 29th annual conference on Computer graphics
* and interactive techniques. 2002.
*
* This implementation is functionally identical to the implementations in EEVEE, OSL, and SVM. So
* any changes should be applied in all relevant implementations.
- */
+ * \{ */
/* Linear Interpolation. */
BLI_INLINE float mix(float v0, float v1, float x)
@@ -757,25 +757,19 @@ float3 perlin_float3_fractal_distorted(float4 position,
perlin_fractal(position + random_float4_offset(5.0f), octaves, roughness));
}
-/* --------------
- * Musgrave Noise
- * --------------
- */
+/** \} */
-/* 1D Musgrave fBm
- *
- * H: fractal increment parameter
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- *
- * from "Texturing and Modelling: A procedural approach"
- */
+/* -------------------------------------------------------------------- */
+/** \name Musgrave Noise
+ * \{ */
float musgrave_fBm(const float co,
const float H,
const float lacunarity,
const float octaves_unclamped)
{
+ /* From "Texturing and Modelling: A procedural approach". */
+
float p = co;
float value = 0.0f;
float pwr = 1.0f;
@@ -796,13 +790,6 @@ float musgrave_fBm(const float co,
return value;
}
-/* 1D Musgrave Multifractal
- *
- * H: highest fractal dimension
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- */
-
float musgrave_multi_fractal(const float co,
const float H,
const float lacunarity,
@@ -828,14 +815,6 @@ float musgrave_multi_fractal(const float co,
return value;
}
-/* 1D Musgrave Heterogeneous Terrain
- *
- * H: fractal dimension of the roughest area
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- * offset: raises the terrain from `sea level'
- */
-
float musgrave_hetero_terrain(const float co,
const float H,
const float lacunarity,
@@ -867,14 +846,6 @@ float musgrave_hetero_terrain(const float co,
return value;
}
-/* 1D Hybrid Additive/Multiplicative Multifractal Terrain
- *
- * H: fractal dimension of the roughest area
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- * offset: raises the terrain from `sea level'
- */
-
float musgrave_hybrid_multi_fractal(const float co,
const float H,
const float lacunarity,
@@ -912,14 +883,6 @@ float musgrave_hybrid_multi_fractal(const float co,
return value;
}
-/* 1D Ridged Multifractal Terrain
- *
- * H: fractal dimension of the roughest area
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- * offset: raises the terrain from `sea level'
- */
-
float musgrave_ridged_multi_fractal(const float co,
const float H,
const float lacunarity,
@@ -951,20 +914,13 @@ float musgrave_ridged_multi_fractal(const float co,
return value;
}
-/* 2D Musgrave fBm
- *
- * H: fractal increment parameter
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- *
- * from "Texturing and Modelling: A procedural approach"
- */
-
float musgrave_fBm(const float2 co,
const float H,
const float lacunarity,
const float octaves_unclamped)
{
+ /* From "Texturing and Modelling: A procedural approach". */
+
float2 p = co;
float value = 0.0f;
float pwr = 1.0f;
@@ -985,13 +941,6 @@ float musgrave_fBm(const float2 co,
return value;
}
-/* 2D Musgrave Multifractal
- *
- * H: highest fractal dimension
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- */
-
float musgrave_multi_fractal(const float2 co,
const float H,
const float lacunarity,
@@ -1017,14 +966,6 @@ float musgrave_multi_fractal(const float2 co,
return value;
}
-/* 2D Musgrave Heterogeneous Terrain
- *
- * H: fractal dimension of the roughest area
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- * offset: raises the terrain from `sea level'
- */
-
float musgrave_hetero_terrain(const float2 co,
const float H,
const float lacunarity,
@@ -1057,14 +998,6 @@ float musgrave_hetero_terrain(const float2 co,
return value;
}
-/* 2D Hybrid Additive/Multiplicative Multifractal Terrain
- *
- * H: fractal dimension of the roughest area
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- * offset: raises the terrain from `sea level'
- */
-
float musgrave_hybrid_multi_fractal(const float2 co,
const float H,
const float lacunarity,
@@ -1102,14 +1035,6 @@ float musgrave_hybrid_multi_fractal(const float2 co,
return value;
}
-/* 2D Ridged Multifractal Terrain
- *
- * H: fractal dimension of the roughest area
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- * offset: raises the terrain from `sea level'
- */
-
float musgrave_ridged_multi_fractal(const float2 co,
const float H,
const float lacunarity,
@@ -1141,20 +1066,13 @@ float musgrave_ridged_multi_fractal(const float2 co,
return value;
}
-/* 3D Musgrave fBm
- *
- * H: fractal increment parameter
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- *
- * from "Texturing and Modelling: A procedural approach"
- */
-
float musgrave_fBm(const float3 co,
const float H,
const float lacunarity,
const float octaves_unclamped)
{
+ /* From "Texturing and Modelling: A procedural approach". */
+
float3 p = co;
float value = 0.0f;
float pwr = 1.0f;
@@ -1176,13 +1094,6 @@ float musgrave_fBm(const float3 co,
return value;
}
-/* 3D Musgrave Multifractal
- *
- * H: highest fractal dimension
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- */
-
float musgrave_multi_fractal(const float3 co,
const float H,
const float lacunarity,
@@ -1209,14 +1120,6 @@ float musgrave_multi_fractal(const float3 co,
return value;
}
-/* 3D Musgrave Heterogeneous Terrain
- *
- * H: fractal dimension of the roughest area
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- * offset: raises the terrain from `sea level'
- */
-
float musgrave_hetero_terrain(const float3 co,
const float H,
const float lacunarity,
@@ -1249,14 +1152,6 @@ float musgrave_hetero_terrain(const float3 co,
return value;
}
-/* 3D Hybrid Additive/Multiplicative Multifractal Terrain
- *
- * H: fractal dimension of the roughest area
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- * offset: raises the terrain from `sea level'
- */
-
float musgrave_hybrid_multi_fractal(const float3 co,
const float H,
const float lacunarity,
@@ -1294,14 +1189,6 @@ float musgrave_hybrid_multi_fractal(const float3 co,
return value;
}
-/* 3D Ridged Multifractal Terrain
- *
- * H: fractal dimension of the roughest area
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- * offset: raises the terrain from `sea level'
- */
-
float musgrave_ridged_multi_fractal(const float3 co,
const float H,
const float lacunarity,
@@ -1333,20 +1220,13 @@ float musgrave_ridged_multi_fractal(const float3 co,
return value;
}
-/* 4D Musgrave fBm
- *
- * H: fractal increment parameter
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- *
- * from "Texturing and Modelling: A procedural approach"
- */
-
float musgrave_fBm(const float4 co,
const float H,
const float lacunarity,
const float octaves_unclamped)
{
+ /* From "Texturing and Modelling: A procedural approach". */
+
float4 p = co;
float value = 0.0f;
float pwr = 1.0f;
@@ -1368,13 +1248,6 @@ float musgrave_fBm(const float4 co,
return value;
}
-/* 4D Musgrave Multifractal
- *
- * H: highest fractal dimension
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- */
-
float musgrave_multi_fractal(const float4 co,
const float H,
const float lacunarity,
@@ -1401,14 +1274,6 @@ float musgrave_multi_fractal(const float4 co,
return value;
}
-/* 4D Musgrave Heterogeneous Terrain
- *
- * H: fractal dimension of the roughest area
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- * offset: raises the terrain from `sea level'
- */
-
float musgrave_hetero_terrain(const float4 co,
const float H,
const float lacunarity,
@@ -1441,14 +1306,6 @@ float musgrave_hetero_terrain(const float4 co,
return value;
}
-/* 4D Hybrid Additive/Multiplicative Multifractal Terrain
- *
- * H: fractal dimension of the roughest area
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- * offset: raises the terrain from `sea level'
- */
-
float musgrave_hybrid_multi_fractal(const float4 co,
const float H,
const float lacunarity,
@@ -1486,14 +1343,6 @@ float musgrave_hybrid_multi_fractal(const float4 co,
return value;
}
-/* 4D Ridged Multifractal Terrain
- *
- * H: fractal dimension of the roughest area
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- * offset: raises the terrain from `sea level'
- */
-
float musgrave_ridged_multi_fractal(const float4 co,
const float H,
const float lacunarity,
@@ -1525,8 +1374,12 @@ float musgrave_ridged_multi_fractal(const float4 co,
return value;
}
-/*
- * Voronoi: Ported from Cycles code.
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Voronoi Noise
+ *
+ * \note Ported from Cycles code.
*
* Original code is under the MIT License, Copyright (c) 2013 Inigo Quilez.
*
@@ -1541,7 +1394,7 @@ float musgrave_ridged_multi_fractal(const float4 co,
*
* With optimization to change -2..2 scan window to -1..1 for better performance,
* as explained in https://www.shadertoy.com/view/llG3zy.
- */
+ * \{ */
/* **** 1D Voronoi **** */
@@ -2516,4 +2369,6 @@ void voronoi_n_sphere_radius(const float4 coord, const float randomness, float *
*r_radius = float4::distance(closestPointToClosestPoint, closestPoint) / 2.0f;
}
+/** \} */
+
} // namespace blender::noise
diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c
index 182fe211110..c824def9104 100644
--- a/source/blender/blenlib/intern/path_util.c
+++ b/source/blender/blenlib/intern/path_util.c
@@ -69,17 +69,6 @@ static bool BLI_path_is_abs(const char *name);
/* implementation */
-/**
- * Looks for a sequence of decimal digits in string, preceding any filename extension,
- * returning the integer value if found, or 0 if not.
- *
- * \param string: String to scan.
- * \param head: Optional area to return copy of part of string prior to digits,
- * or before dot if no digits.
- * \param tail: Optional area to return copy of part of string following digits,
- * or from dot if no digits.
- * \param r_num_len: Optional to return number of digits found.
- */
int BLI_path_sequence_decode(const char *string, char *head, char *tail, ushort *r_num_len)
{
uint nums = 0, nume = 0;
@@ -147,10 +136,6 @@ int BLI_path_sequence_decode(const char *string, char *head, char *tail, ushort
return 0;
}
-/**
- * Returns in area pointed to by string a string of the form "<head><pic><tail>", where pic
- * is formatted as numlen digits with leading zeroes.
- */
void BLI_path_sequence_encode(
char *string, const char *head, const char *tail, unsigned short numlen, int pic)
{
@@ -159,17 +144,6 @@ void BLI_path_sequence_encode(
static int BLI_path_unc_prefix_len(const char *path); /* defined below in same file */
-/* ******************** string encoding ***************** */
-
-/**
- * Remove redundant characters from \a path and optionally make absolute.
- *
- * \param relabase: The path this is relative to, or ignored when NULL.
- * \param path: Can be any input, and this function converts it to a regular full path.
- * Also removes garbage from directory paths, like `/../` or double slashes etc.
- *
- * \note \a path isn't protected for max string names...
- */
void BLI_path_normalize(const char *relabase, char *path)
{
ptrdiff_t a;
@@ -260,9 +234,6 @@ void BLI_path_normalize(const char *relabase, char *path)
#endif
}
-/**
- * Cleanup filepath ensuring a trailing slash.
- */
void BLI_path_normalize_dir(const char *relabase, char *dir)
{
/* Would just create an unexpected "/" path, just early exit entirely. */
@@ -274,28 +245,6 @@ void BLI_path_normalize_dir(const char *relabase, char *dir)
BLI_path_slash_ensure(dir);
}
-/**
- * Make given name safe to be used in paths.
- *
- * \return true if \a fname was changed, false otherwise.
- *
- * For now, simply replaces reserved chars (as listed in
- * https://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words )
- * by underscores ('_').
- *
- * \note Space case ' ' is a bit of an edge case here - in theory it is allowed,
- * but again can be an issue in some cases, so we simply replace it by an underscore too
- * (good practice anyway).
- * REMOVED based on popular demand (see T45900).
- * Percent '%' char is a bit same case - not recommended to use it,
- * but supported by all decent file-systems/operating-systems around.
- *
- * \note On Windows, it also ensures there is no '.' (dot char) at the end of the file,
- * this can lead to issues.
- *
- * \note On Windows, it also checks for forbidden names
- * (see https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx ).
- */
bool BLI_filename_make_safe(char *fname)
{
const char *invalid =
@@ -366,11 +315,6 @@ bool BLI_filename_make_safe(char *fname)
return changed;
}
-/**
- * Make given path OS-safe.
- *
- * \return true if \a path was changed, false otherwise.
- */
bool BLI_path_make_safe(char *path)
{
/* Simply apply BLI_filename_make_safe() over each component of the path.
@@ -404,16 +348,11 @@ bool BLI_path_make_safe(char *path)
return changed;
}
-/**
- * Does path begin with the special "//" prefix that Blender uses to indicate
- * a path relative to the .blend file.
- */
bool BLI_path_is_rel(const char *path)
{
return path[0] == '/' && path[1] == '/';
}
-/* return true if the path is a UNC share */
bool BLI_path_is_unc(const char *name)
{
return name[0] == '\\' && name[1] == '\\';
@@ -512,10 +451,6 @@ void BLI_path_normalize_unc_16(wchar_t *path_16)
}
#endif
-/**
- * Replaces `file` with a relative version (prefixed by "//") such that #BLI_path_abs, given
- * the same `relfile`, will convert it back to its original value.
- */
void BLI_path_rel(char *file, const char *relfile)
{
const char *lslash;
@@ -654,18 +589,6 @@ void BLI_path_rel(char *file, const char *relfile)
}
}
-/**
- * Appends a suffix to the string, fitting it before the extension
- *
- * string = Foo.png, suffix = 123, separator = _
- * Foo.png -> Foo_123.png
- *
- * \param string: original (and final) string
- * \param maxlen: Maximum length of string
- * \param suffix: String to append to the original string
- * \param sep: Optional separator character
- * \return true if succeeded
- */
bool BLI_path_suffix(char *string, size_t maxlen, const char *suffix, const char *sep)
{
#ifdef DEBUG_STRSIZE
@@ -701,10 +624,6 @@ bool BLI_path_suffix(char *string, size_t maxlen, const char *suffix, const char
return true;
}
-/**
- * Replaces path with the path of its parent directory, returning true if
- * it was able to find a parent directory within the path.
- */
bool BLI_path_parent_dir(char *path)
{
const char parent_dir[] = {'.', '.', SEP, '\0'}; /* "../" or "..\\" */
@@ -721,10 +640,6 @@ bool BLI_path_parent_dir(char *path)
return false;
}
-/**
- * Strips off nonexistent (or non-accessible) sub-directories from the end of `dir`,
- * leaving the path of the lowest-level directory that does exist and we can read.
- */
bool BLI_path_parent_dir_until_exists(char *dir)
{
bool valid_path = true;
@@ -795,10 +710,6 @@ static void ensure_digits(char *path, int digits)
}
}
-/**
- * Replaces "#" character sequence in last slash-separated component of `path`
- * with frame as decimal integer, with leading zeroes as necessary, to make digits digits.
- */
bool BLI_path_frame(char *path, int frame, int digits)
{
int ch_sta, ch_end;
@@ -817,11 +728,6 @@ bool BLI_path_frame(char *path, int frame, int digits)
return false;
}
-/**
- * Replaces "#" character sequence in last slash-separated component of `path`
- * with sta and end as decimal integers, with leading zeroes as necessary, to make digits
- * digits each, with a hyphen in-between.
- */
bool BLI_path_frame_range(char *path, int sta, int end, int digits)
{
int ch_sta, ch_end;
@@ -848,9 +754,6 @@ bool BLI_path_frame_range(char *path, int sta, int end, int digits)
return false;
}
-/**
- * Get the frame from a filename formatted by blender's frame scheme
- */
bool BLI_path_frame_get(char *path, int *r_frame, int *r_numdigits)
{
if (*path) {
@@ -952,19 +855,12 @@ void BLI_path_frame_strip(char *path, char *r_ext)
*c = '\0';
}
-/**
- * Check if we have '#' chars, usable for #BLI_path_frame, #BLI_path_frame_range
- */
bool BLI_path_frame_check_chars(const char *path)
{
int ch_sta, ch_end; /* dummy args */
return stringframe_chars(path, &ch_sta, &ch_end);
}
-/**
- * Creates a display string from path to be used menus and the user interface.
- * Like `bpy.path.display_name()`.
- */
void BLI_path_to_display_name(char *display_name, int maxlen, const char *name)
{
/* Strip leading underscores and spaces. */
@@ -1003,16 +899,6 @@ void BLI_path_to_display_name(char *display_name, int maxlen, const char *name)
}
}
-/**
- * If path begins with "//", strips that and replaces it with `basepath` directory.
- *
- * \note Also converts drive-letter prefix to something more sensible
- * if this is a non-drive-letter-based system.
- *
- * \param path: The path to convert.
- * \param basepath: The directory to base relative paths with.
- * \return true if the path was relative (started with "//").
- */
bool BLI_path_abs(char *path, const char *basepath)
{
const bool wasrelative = BLI_path_is_rel(path);
@@ -1114,33 +1000,30 @@ bool BLI_path_abs(char *path, const char *basepath)
return wasrelative;
}
-/**
- * Checks for relative path, expanding them relative to the current working directory.
- * Returns true if the expansion was performed.
- *
- * \note Should only be called with command line paths.
- * This is _not_ something Blender's internal paths support, instead they use the "//" prefix.
- * In most cases #BLI_path_abs should be used instead.
- */
-bool BLI_path_abs_from_cwd(char *path, const size_t maxlen)
+bool BLI_path_is_abs_from_cwd(const char *path)
{
-#ifdef DEBUG_STRSIZE
- memset(path, 0xff, sizeof(*path) * maxlen);
-#endif
- bool wasrelative = true;
- const int filelen = strlen(path);
+ bool is_abs = false;
+ const int path_len_clamp = BLI_strnlen(path, 3);
#ifdef WIN32
- if ((filelen >= 3 && BLI_path_is_abs(path)) || BLI_path_is_unc(path)) {
- wasrelative = false;
+ if ((path_len_clamp >= 3 && BLI_path_is_abs(path)) || BLI_path_is_unc(path)) {
+ is_abs = true;
}
#else
- if (filelen >= 2 && path[0] == '/') {
- wasrelative = false;
+ if (path_len_clamp >= 2 && path[0] == '/') {
+ is_abs = true;
}
#endif
+ return is_abs;
+}
- if (wasrelative) {
+bool BLI_path_abs_from_cwd(char *path, const size_t maxlen)
+{
+#ifdef DEBUG_STRSIZE
+ memset(path, 0xff, sizeof(*path) * maxlen);
+#endif
+
+ if (!BLI_path_is_abs_from_cwd(path)) {
char cwd[FILE_MAX];
/* in case the full path to the blend isn't used */
if (BLI_current_working_dir(cwd, sizeof(cwd))) {
@@ -1151,9 +1034,10 @@ bool BLI_path_abs_from_cwd(char *path, const size_t maxlen)
else {
printf("Could not get the current working directory - $PWD for an unknown reason.\n");
}
+ return true;
}
- return wasrelative;
+ return false;
}
#ifdef _WIN32
@@ -1209,9 +1093,6 @@ bool BLI_path_program_extensions_add_win32(char *name, const size_t maxlen)
}
#endif /* WIN32 */
-/**
- * Search for a binary (executable)
- */
bool BLI_path_program_search(char *fullname, const size_t maxlen, const char *name)
{
#ifdef DEBUG_STRSIZE
@@ -1264,10 +1145,6 @@ bool BLI_path_program_search(char *fullname, const size_t maxlen, const char *na
return retval;
}
-/**
- * Sets the specified environment variable to the specified value,
- * and clears it if `val == NULL`.
- */
void BLI_setenv(const char *env, const char *val)
{
/* free windows */
@@ -1286,12 +1163,6 @@ void BLI_setenv(const char *env, const char *val)
#endif
}
-/**
- * Only set an env var if already not there.
- * Like Unix setenv(env, val, 0);
- *
- * (not used anywhere).
- */
void BLI_setenv_if_new(const char *env, const char *val)
{
if (BLI_getenv(env) == NULL) {
@@ -1299,14 +1170,6 @@ void BLI_setenv_if_new(const char *env, const char *val)
}
}
-/**
- * Get an env var, result has to be used immediately.
- *
- * On windows #getenv gets its variables from a static copy of the environment variables taken at
- * process start-up, causing it to not pick up on environment variables created during runtime.
- * This function uses an alternative method to get environment variables that does pick up on
- * runtime environment variables. The result will be UTF-8 encoded.
- */
const char *BLI_getenv(const char *env)
{
#ifdef _MSC_VER
@@ -1336,11 +1199,6 @@ const char *BLI_getenv(const char *env)
#endif
}
-/**
- * Ensures that the parent directory of `name` exists.
- *
- * \return true on success (i.e. given path now exists on file-system), false otherwise.
- */
bool BLI_make_existing_file(const char *name)
{
char di[FILE_MAX];
@@ -1350,15 +1208,6 @@ bool BLI_make_existing_file(const char *name)
return BLI_dir_create_recursive(di);
}
-/**
- * Returns in `string` the concatenation of `dir` and `file` (also with `relabase` on the
- * front if specified and `dir` begins with "//"). Normalizes all occurrences of path
- * separators, including ensuring there is exactly one between the copies of `dir` and `file`,
- * and between the copies of `relabase` and `dir`.
- *
- * \param relabase: Optional prefix to substitute for "//" on front of `dir`.
- * \param string: Area to return result.
- */
void BLI_make_file_string(const char *relabase, char *string, const char *dir, const char *file)
{
int sl;
@@ -1452,7 +1301,6 @@ static bool path_extension_check_ex(const char *str,
(BLI_strcasecmp(ext, str + str_len - ext_len) == 0));
}
-/* does str end with ext. */
bool BLI_path_extension_check(const char *str, const char *ext)
{
return path_extension_check_ex(str, strlen(str), ext, strlen(ext));
@@ -1480,7 +1328,6 @@ bool BLI_path_extension_check_n(const char *str, ...)
return ret;
}
-/* does str end with any of the suffixes in *ext_array. */
bool BLI_path_extension_check_array(const char *str, const char **ext_array)
{
const size_t str_len = strlen(str);
@@ -1496,10 +1343,6 @@ bool BLI_path_extension_check_array(const char *str, const char **ext_array)
return false;
}
-/**
- * Semicolon separated wildcards, eg: `*.zip;*.py;*.exe`
- * does str match any of the semicolon-separated glob patterns in #fnmatch.
- */
bool BLI_path_extension_check_glob(const char *str, const char *ext_fnmatch)
{
const char *ext_step = ext_fnmatch;
@@ -1526,15 +1369,6 @@ bool BLI_path_extension_check_glob(const char *str, const char *ext_fnmatch)
return false;
}
-/**
- * Does basic validation of the given glob string, to prevent common issues from string
- * truncation.
- *
- * For now, only forbids last group to be a wildcard-only one, if there are more than one group
- * (i.e. things like `*.txt;*.cpp;*` are changed to `*.txt;*.cpp;`)
- *
- * \returns true if it had to modify given \a ext_fnmatch pattern.
- */
bool BLI_path_extension_glob_validate(char *ext_fnmatch)
{
bool only_wildcards = false;
@@ -1561,10 +1395,6 @@ bool BLI_path_extension_glob_validate(char *ext_fnmatch)
return false;
}
-/**
- * Removes any existing extension on the end of \a path and appends \a ext.
- * \return false if there was no room.
- */
bool BLI_path_extension_replace(char *path, size_t maxlen, const char *ext)
{
#ifdef DEBUG_STRSIZE
@@ -1592,9 +1422,6 @@ bool BLI_path_extension_replace(char *path, size_t maxlen, const char *ext)
return true;
}
-/**
- * Strip's trailing '.'s and adds the extension only when needed
- */
bool BLI_path_extension_ensure(char *path, size_t maxlen, const char *ext)
{
#ifdef DEBUG_STRSIZE
@@ -1640,14 +1467,6 @@ bool BLI_path_filename_ensure(char *filepath, size_t maxlen, const char *filenam
return false;
}
-/**
- * Converts `/foo/bar.txt` to `/foo/` and `bar.txt`
- *
- * - Won't change \a string.
- * - Won't create any directories.
- * - Doesn't use CWD, or deal with relative paths.
- * - Only fill's in \a dir and \a file when they are non NULL.
- */
void BLI_split_dirfile(
const char *string, char *dir, char *file, const size_t dirlen, const size_t filelen)
{
@@ -1673,26 +1492,16 @@ void BLI_split_dirfile(
}
}
-/**
- * Copies the parent directory part of string into `dir`, max length `dirlen`.
- */
void BLI_split_dir_part(const char *string, char *dir, const size_t dirlen)
{
BLI_split_dirfile(string, dir, NULL, dirlen, 0);
}
-/**
- * Copies the leaf filename part of string into `file`, max length `filelen`.
- */
void BLI_split_file_part(const char *string, char *file, const size_t filelen)
{
BLI_split_dirfile(string, NULL, file, 0, filelen);
}
-/**
- * Returns a pointer to the last extension (e.g. the position of the last period).
- * Returns NULL if there is no extension.
- */
const char *BLI_path_extension(const char *filepath)
{
const char *extension = strrchr(filepath, '.');
@@ -1707,9 +1516,6 @@ const char *BLI_path_extension(const char *filepath)
return extension;
}
-/**
- * Append a filename to a dir, ensuring slash separates.
- */
void BLI_path_append(char *__restrict dst, const size_t maxlen, const char *__restrict file)
{
size_t dirlen = BLI_strnlen(dst, maxlen);
@@ -1727,13 +1533,6 @@ void BLI_path_append(char *__restrict dst, const size_t maxlen, const char *__re
BLI_strncpy(dst + dirlen, file, maxlen - dirlen);
}
-/**
- * Simple appending of filename to dir, does not check for valid path!
- * Puts result into `dst`, which may be same area as `dir`.
- *
- * \note Consider using #BLI_path_join for more general path joining
- * that de-duplicates separators and can handle an arbitrary number of paths.
- */
void BLI_join_dirfile(char *__restrict dst,
const size_t maxlen,
const char *__restrict dir,
@@ -1776,13 +1575,6 @@ void BLI_join_dirfile(char *__restrict dst,
BLI_strncpy(dst + dirlen, file, maxlen - dirlen);
}
-/**
- * Join multiple strings into a path, ensuring only a single path separator between each,
- * and trailing slash is kept.
- *
- * \note If you want a trailing slash, add `SEP_STR` as the last path argument,
- * duplicate slashes will be cleaned up.
- */
size_t BLI_path_join(char *__restrict dst, const size_t dst_len, const char *path, ...)
{
#ifdef DEBUG_STRSIZE
@@ -1863,27 +1655,12 @@ size_t BLI_path_join(char *__restrict dst, const size_t dst_len, const char *pat
return ofs;
}
-/**
- * like Python's `os.path.basename()`
- *
- * \return The pointer into \a path string immediately after last slash,
- * or start of \a path if none found.
- */
const char *BLI_path_basename(const char *path)
{
const char *const filename = BLI_path_slash_rfind(path);
return filename ? filename + 1 : path;
}
-/**
- * Get an element of the path at an index, eg:
- * "/some/path/file.txt" where an index of...
- * - 0 or -3: "some"
- * - 1 or -2: "path"
- * - 2 or -1: "file.txt"
- *
- * Ignores multiple slashes at any point in the path (including start/end).
- */
bool BLI_path_name_at_index(const char *__restrict path,
const int index,
int *__restrict r_offset,
@@ -1975,9 +1752,6 @@ bool BLI_path_contains(const char *container_path, const char *containee_path)
return BLI_str_startswith(containee_native, container_native);
}
-/**
- * Returns pointer to the leftmost path separator in string. Not actually used anywhere.
- */
const char *BLI_path_slash_find(const char *string)
{
const char *const ffslash = strchr(string, '/');
@@ -1993,9 +1767,6 @@ const char *BLI_path_slash_find(const char *string)
return (ffslash < fbslash) ? ffslash : fbslash;
}
-/**
- * Returns pointer to the rightmost path separator in string.
- */
const char *BLI_path_slash_rfind(const char *string)
{
const char *const lfslash = strrchr(string, '/');
@@ -2011,10 +1782,6 @@ const char *BLI_path_slash_rfind(const char *string)
return (lfslash > lbslash) ? lfslash : lbslash;
}
-/**
- * Appends a slash to string if there isn't one there already.
- * Returns the new length of the string.
- */
int BLI_path_slash_ensure(char *string)
{
int len = strlen(string);
@@ -2026,9 +1793,6 @@ int BLI_path_slash_ensure(char *string)
return len;
}
-/**
- * Removes the last slash and everything after it to the end of string, if there is one.
- */
void BLI_path_slash_rstrip(char *string)
{
int len = strlen(string);
@@ -2043,9 +1807,6 @@ void BLI_path_slash_rstrip(char *string)
}
}
-/**
- * Changes to the path separators to the native ones for this OS.
- */
void BLI_path_slash_native(char *path)
{
#ifdef WIN32
diff --git a/source/blender/blenlib/intern/polyfill_2d.c b/source/blender/blenlib/intern/polyfill_2d.c
index 9af98359199..2a02abf147a 100644
--- a/source/blender/blenlib/intern/polyfill_2d.c
+++ b/source/blender/blenlib/intern/polyfill_2d.c
@@ -841,9 +841,6 @@ static void polyfill_calc(PolyFill *pf)
pf_triangulate(pf);
}
-/**
- * A version of #BLI_polyfill_calc that uses a memory arena to avoid re-allocations.
- */
void BLI_polyfill_calc_arena(const float (*coords)[2],
const uint coords_tot,
const int coords_sign,
@@ -889,19 +886,6 @@ void BLI_polyfill_calc_arena(const float (*coords)[2],
#endif
}
-/**
- * Triangulates the given (convex or concave) simple polygon to a list of triangle vertices.
- *
- * \param coords: 2D coordinates describing vertices of the polygon,
- * in either clockwise or counterclockwise order.
- * \param coords_tot: Total points in the array.
- * \param coords_sign: Pass this when we know the sign in advance to avoid extra calculations.
- *
- * \param r_tris: This array is filled in with triangle indices in clockwise order.
- * The length of the array must be `coords_tot - 2`.
- * Indices are guaranteed to be assigned to unique triangles, with valid indices,
- * even in the case of degenerate input (self intersecting polygons, zero area ears... etc).
- */
void BLI_polyfill_calc(const float (*coords)[2],
const uint coords_tot,
const int coords_sign,
diff --git a/source/blender/blenlib/intern/polyfill_2d_beautify.c b/source/blender/blenlib/intern/polyfill_2d_beautify.c
index ed07b002e32..684094234cf 100644
--- a/source/blender/blenlib/intern/polyfill_2d_beautify.c
+++ b/source/blender/blenlib/intern/polyfill_2d_beautify.c
@@ -92,21 +92,6 @@ BLI_INLINE bool is_boundary_edge(uint i_a, uint i_b, const uint coord_last)
BLI_assert(i_a < i_b);
return ((i_a + 1 == i_b) || UNLIKELY((i_a == 0) && (i_b == coord_last)));
}
-/**
- * Assuming we have 2 triangles sharing an edge (2 - 4),
- * check if the edge running from (1 - 3) gives better results.
- *
- * \param lock_degenerate: Use to avoid rotating out of a degenerate state:
- * - When true, an existing zero area face on either side of the (2 - 4
- * split will return a positive value.
- * - When false, the check must be non-biased towards either split direction.
- * \param r_area: Return the area of the quad,
- * This can be useful when comparing the return value with near zero epsilons.
- * In this case the epsilon can be scaled by the area to avoid the return value
- * of very large faces not having a reliable way to detect near-zero output.
- *
- * \return (negative number means the edge can be rotated, lager == better).
- */
float BLI_polyfill_beautify_quad_rotate_calc_ex(const float v1[2],
const float v2[2],
const float v3[2],
@@ -316,12 +301,6 @@ static void polyedge_rotate(struct HalfEdge *edges, struct HalfEdge *e)
ed[3]->v = ed[2]->v;
}
-/**
- * The intention is that this calculates the output of #BLI_polyfill_calc
- * \note assumes the \a coords form a boundary,
- * so any edges running along contiguous (wrapped) indices,
- * are ignored since the edges won't share 2 faces.
- */
void BLI_polyfill_beautify(const float (*coords)[2],
const uint coords_tot,
uint (*tris)[3],
diff --git a/source/blender/blenlib/intern/rand.cc b/source/blender/blenlib/intern/rand.cc
index db5e08d37ce..1d2274ede37 100644
--- a/source/blender/blenlib/intern/rand.cc
+++ b/source/blender/blenlib/intern/rand.cc
@@ -59,9 +59,6 @@ RNG *BLI_rng_new(unsigned int seed)
return rng;
}
-/**
- * A version of #BLI_rng_new that hashes the seed.
- */
RNG *BLI_rng_new_srandom(unsigned int seed)
{
RNG *rng = new RNG();
@@ -84,9 +81,6 @@ void BLI_rng_seed(RNG *rng, unsigned int seed)
rng->rng.seed(seed);
}
-/**
- * Use a hash table to create better seed.
- */
void BLI_rng_srandom(RNG *rng, unsigned int seed)
{
rng->rng.seed_random(seed);
@@ -107,17 +101,11 @@ unsigned int BLI_rng_get_uint(RNG *rng)
return rng->rng.get_uint32();
}
-/**
- * \return Random value (0..1), but never 1.0.
- */
double BLI_rng_get_double(RNG *rng)
{
return rng->rng.get_double();
}
-/**
- * \return Random value (0..1), but never 1.0.
- */
float BLI_rng_get_float(RNG *rng)
{
return rng->rng.get_float();
@@ -133,9 +121,6 @@ void BLI_rng_get_float_unit_v3(RNG *rng, float v[3])
copy_v3_v3(v, rng->rng.get_unit_float3());
}
-/**
- * Generate a random point inside given tri.
- */
void BLI_rng_get_tri_sample_float_v2(
RNG *rng, const float v1[2], const float v2[2], const float v3[2], float r_pt[2])
{
@@ -190,11 +175,6 @@ void BLI_rng_shuffle_bitmap(struct RNG *rng, BLI_bitmap *bitmap, unsigned int bi
}
}
-/**
- * Simulate getting \a n random values.
- *
- * \note Useful when threaded code needs consistent values, independent of task division.
- */
void BLI_rng_skip(RNG *rng, int n)
{
rng->rng.skip((uint)n);
@@ -202,7 +182,6 @@ void BLI_rng_skip(RNG *rng, int n)
/***/
-/* fill an array with random numbers */
void BLI_array_frand(float *ar, int count, unsigned int seed)
{
RNG rng;
@@ -272,7 +251,7 @@ struct RNG_THREAD_ARRAY {
RNG rng_tab[BLENDER_MAX_THREADS];
};
-RNG_THREAD_ARRAY *BLI_rng_threaded_new(void)
+RNG_THREAD_ARRAY *BLI_rng_threaded_new()
{
unsigned int i;
RNG_THREAD_ARRAY *rngarr = (RNG_THREAD_ARRAY *)MEM_mallocN(sizeof(RNG_THREAD_ARRAY),
@@ -402,9 +381,6 @@ void BLI_hammersley_2d_sequence(unsigned int n, double *r)
namespace blender {
-/**
- * Set a randomized hash of the value as seed.
- */
void RandomNumberGenerator::seed_random(uint32_t seed)
{
this->seed(seed + hash[seed & 255]);
@@ -434,9 +410,6 @@ float3 RandomNumberGenerator::get_unit_float3()
return {0.0f, 0.0f, 1.0f};
}
-/**
- * Generate a random point inside the given triangle.
- */
float2 RandomNumberGenerator::get_triangle_sample(float2 v1, float2 v2, float2 v3)
{
float u = this->get_float();
diff --git a/source/blender/blenlib/intern/rct.c b/source/blender/blenlib/intern/rct.c
index 35e24ecc785..091945c9b12 100644
--- a/source/blender/blenlib/intern/rct.c
+++ b/source/blender/blenlib/intern/rct.c
@@ -30,6 +30,7 @@
#include <float.h>
#include <limits.h>
+#include "BLI_math_base.h"
#include "BLI_rect.h"
#include "BLI_utildefines.h"
@@ -38,13 +39,6 @@
/* avoid including BLI_math */
static void unit_m4(float m[4][4]);
-/**
- * Determine if a rect is empty. An empty
- * rect is one with a zero (or negative)
- * width or height.
- *
- * \return True if \a rect is empty.
- */
bool BLI_rcti_is_empty(const rcti *rect)
{
return ((rect->xmax <= rect->xmin) || (rect->ymax <= rect->ymin));
@@ -167,10 +161,6 @@ bool BLI_rctf_isect_pt_v(const rctf *rect, const float xy[2])
return true;
}
-/**
- * \returns shortest distance from \a rect to x/y (0 if inside)
- */
-
int BLI_rcti_length_x(const rcti *rect, const int x)
{
if (x < rect->xmin) {
@@ -215,9 +205,6 @@ float BLI_rctf_length_y(const rctf *rect, const float y)
return 0.0f;
}
-/**
- * is \a rct_b inside \a rct_a
- */
bool BLI_rctf_inside_rctf(const rctf *rct_a, const rctf *rct_b)
{
return ((rct_a->xmin <= rct_b->xmin) && (rct_a->xmax >= rct_b->xmax) &&
@@ -401,35 +388,35 @@ bool BLI_rctf_isect_circle(const rctf *rect, const float xy[2], const float radi
return dx * dx + dy * dy <= radius * radius;
}
-void BLI_rctf_union(rctf *rct1, const rctf *rct2)
+void BLI_rctf_union(rctf *rct_a, const rctf *rct_b)
{
- if (rct1->xmin > rct2->xmin) {
- rct1->xmin = rct2->xmin;
+ if (rct_a->xmin > rct_b->xmin) {
+ rct_a->xmin = rct_b->xmin;
}
- if (rct1->xmax < rct2->xmax) {
- rct1->xmax = rct2->xmax;
+ if (rct_a->xmax < rct_b->xmax) {
+ rct_a->xmax = rct_b->xmax;
}
- if (rct1->ymin > rct2->ymin) {
- rct1->ymin = rct2->ymin;
+ if (rct_a->ymin > rct_b->ymin) {
+ rct_a->ymin = rct_b->ymin;
}
- if (rct1->ymax < rct2->ymax) {
- rct1->ymax = rct2->ymax;
+ if (rct_a->ymax < rct_b->ymax) {
+ rct_a->ymax = rct_b->ymax;
}
}
-void BLI_rcti_union(rcti *rct1, const rcti *rct2)
+void BLI_rcti_union(rcti *rct_a, const rcti *rct_b)
{
- if (rct1->xmin > rct2->xmin) {
- rct1->xmin = rct2->xmin;
+ if (rct_a->xmin > rct_b->xmin) {
+ rct_a->xmin = rct_b->xmin;
}
- if (rct1->xmax < rct2->xmax) {
- rct1->xmax = rct2->xmax;
+ if (rct_a->xmax < rct_b->xmax) {
+ rct_a->xmax = rct_b->xmax;
}
- if (rct1->ymin > rct2->ymin) {
- rct1->ymin = rct2->ymin;
+ if (rct_a->ymin > rct_b->ymin) {
+ rct_a->ymin = rct_b->ymin;
}
- if (rct1->ymax < rct2->ymax) {
- rct1->ymax = rct2->ymax;
+ if (rct_a->ymax < rct_b->ymax) {
+ rct_a->ymax = rct_b->ymax;
}
}
@@ -453,13 +440,6 @@ void BLI_rcti_init(rcti *rect, int xmin, int xmax, int ymin, int ymax)
BLI_rcti_sanitize(rect);
}
-/**
- * Check if X-min and Y-min are less than or equal to X-max and Y-max, respectively.
- * If this returns false, #BLI_rctf_sanitize() can be called to address this.
- *
- * This is not a hard constraint or invariant for rectangles, in some cases it may be useful to
- * have max < min. Usually this is what you'd want though.
- */
bool BLI_rctf_is_valid(const rctf *rect)
{
return (rect->xmin <= rect->xmax) && (rect->ymin <= rect->ymax);
@@ -470,9 +450,6 @@ bool BLI_rcti_is_valid(const rcti *rect)
return (rect->xmin <= rect->xmax) && (rect->ymin <= rect->ymax);
}
-/**
- * Ensure X-min and Y-min are less than or equal to X-max and Y-max, respectively.
- */
void BLI_rctf_sanitize(rctf *rect)
{
if (rect->xmin > rect->xmax) {
@@ -541,6 +518,14 @@ void BLI_rcti_do_minmax_v(rcti *rect, const int xy[2])
}
}
+void BLI_rcti_do_minmax_rcti(rcti *rect, const rcti *other)
+{
+ rect->xmin = min_ii(rect->xmin, other->xmin);
+ rect->xmax = max_ii(rect->xmax, other->xmax);
+ rect->ymin = min_ii(rect->ymin, other->ymin);
+ rect->ymax = max_ii(rect->ymax, other->ymax);
+}
+
void BLI_rctf_do_minmax_v(rctf *rect, const float xy[2])
{
if (xy[0] < rect->xmin) {
@@ -557,7 +542,6 @@ void BLI_rctf_do_minmax_v(rctf *rect, const float xy[2])
}
}
-/* given 2 rectangles - transform a point from one to another */
void BLI_rctf_transform_pt_v(const rctf *dst,
const rctf *src,
float xy_dst[2],
@@ -570,12 +554,6 @@ void BLI_rctf_transform_pt_v(const rctf *dst,
xy_dst[1] = dst->ymin + ((dst->ymax - dst->ymin) * xy_dst[1]);
}
-/**
- * Calculate a 4x4 matrix representing the transformation between two rectangles.
- *
- * \note Multiplying a vector by this matrix does *not*
- * give the same value as #BLI_rctf_transform_pt_v.
- */
void BLI_rctf_transform_calc_m4_pivot_min_ex(
const rctf *dst, const rctf *src, float matrix[4][4], uint x, uint y)
{
@@ -622,7 +600,6 @@ void BLI_rctf_recenter(rctf *rect, float x, float y)
BLI_rctf_translate(rect, dx, dy);
}
-/* change width & height around the central location */
void BLI_rcti_resize_x(rcti *rect, int x)
{
rect->xmin = BLI_rcti_cent_x(rect) - (x / 2);
@@ -777,14 +754,6 @@ bool BLI_rcti_clamp_pt_v(const rcti *rect, int xy[2])
return changed;
}
-/**
- * Clamp \a rect within \a rect_bounds, setting \a r_xy to the offset.
- *
- * Keeps the top left corner within the bounds, which for user interface
- * elements is typically where the most important information is.
- *
- * \return true if a change is made.
- */
bool BLI_rctf_clamp(rctf *rect, const rctf *rect_bounds, float r_xy[2])
{
bool changed = false;
@@ -1106,9 +1075,6 @@ void print_rcti(const char *str, const rcti *rect)
} \
((void)0)
-/**
- * Expand the rectangle to fit a rotated \a src.
- */
void BLI_rctf_rotate_expand(rctf *dst, const rctf *src, const float angle)
{
const float mat2[2] = {sinf(angle), cosf(angle)};
diff --git a/source/blender/blenlib/intern/scanfill_utils.c b/source/blender/blenlib/intern/scanfill_utils.c
index 33c0f4afd01..89c2a695829 100644
--- a/source/blender/blenlib/intern/scanfill_utils.c
+++ b/source/blender/blenlib/intern/scanfill_utils.c
@@ -369,11 +369,6 @@ static bool scanfill_preprocess_self_isect(ScanFillContext *sf_ctx,
return true;
}
-/**
- * Call before scanfill to remove self intersections.
- *
- * \return false if no changes were made.
- */
bool BLI_scanfill_calc_self_isect(ScanFillContext *sf_ctx,
ListBase *remvertbase,
ListBase *remedgebase)
diff --git a/source/blender/blenlib/intern/smallhash.c b/source/blender/blenlib/intern/smallhash.c
index 006a3798dcd..2278daf5516 100644
--- a/source/blender/blenlib/intern/smallhash.c
+++ b/source/blender/blenlib/intern/smallhash.c
@@ -214,7 +214,6 @@ void BLI_smallhash_init(SmallHash *sh)
BLI_smallhash_init_ex(sh, 0);
}
-/* NOTE: does *not* free *sh itself! only the direct data! */
void BLI_smallhash_release(SmallHash *sh)
{
if (sh->buckets != sh->buckets_stack) {
@@ -239,13 +238,6 @@ void BLI_smallhash_insert(SmallHash *sh, uintptr_t key, void *item)
e->val = item;
}
-/**
- * Inserts a new value to a key that may already be in ghash.
- *
- * Avoids #BLI_smallhash_remove, #BLI_smallhash_insert calls (double lookups)
- *
- * \returns true if a new key has been added.
- */
bool BLI_smallhash_reinsert(SmallHash *sh, uintptr_t key, void *item)
{
SmallHashEntry *e = smallhash_lookup(sh, key);
@@ -389,12 +381,6 @@ void BLI_smallhash_print(SmallHash *sh)
#endif
#ifdef DEBUG
-/**
- * Measure how well the hash function performs
- * (1.0 is perfect - no stepping needed).
- *
- * Smaller is better!
- */
double BLI_smallhash_calc_quality(SmallHash *sh)
{
uint64_t sum = 0;
diff --git a/source/blender/blenlib/intern/stack.c b/source/blender/blenlib/intern/stack.c
index 4a9bdd48a0a..629a6eaa78c 100644
--- a/source/blender/blenlib/intern/stack.c
+++ b/source/blender/blenlib/intern/stack.c
@@ -91,9 +91,6 @@ BLI_Stack *BLI_stack_new_ex(const size_t elem_size,
return stack;
}
-/**
- * Create a new homogeneous stack with elements of 'elem_size' bytes.
- */
BLI_Stack *BLI_stack_new(const size_t elem_size, const char *description)
{
return BLI_stack_new_ex(elem_size, description, CHUNK_SIZE_DEFAULT);
@@ -108,9 +105,6 @@ static void stack_free_chunks(struct StackChunk *data)
}
}
-/**
- * Free the stack's data and the stack itself
- */
void BLI_stack_free(BLI_Stack *stack)
{
stack_free_chunks(stack->chunk_curr);
@@ -118,12 +112,6 @@ void BLI_stack_free(BLI_Stack *stack)
MEM_freeN(stack);
}
-/**
- * Push a new item onto the stack.
- *
- * \return a pointer #BLI_Stack.elem_size
- * bytes of uninitialized memory (caller must fill in).
- */
void *BLI_stack_push_r(BLI_Stack *stack)
{
stack->chunk_index++;
@@ -152,26 +140,12 @@ void *BLI_stack_push_r(BLI_Stack *stack)
return stack_get_last_elem(stack);
}
-/**
- * Copies the source value onto the stack
- *
- * \note This copies #BLI_Stack.elem_size bytes from \a src,
- * (the pointer itself is not stored).
- *
- * \param src: source data to be copied to the stack.
- */
void BLI_stack_push(BLI_Stack *stack, const void *src)
{
void *dst = BLI_stack_push_r(stack);
memcpy(dst, src, stack->elem_size);
}
-/**
- * Retrieves and removes the top element from the stack.
- * The value is copies to \a dst, which must be at least \a elem_size bytes.
- *
- * Does not reduce amount of allocated memory.
- */
void BLI_stack_pop(BLI_Stack *stack, void *dst)
{
BLI_assert(BLI_stack_is_empty(stack) == false);
@@ -181,15 +155,6 @@ void BLI_stack_pop(BLI_Stack *stack, void *dst)
BLI_stack_discard(stack);
}
-/**
- * A version of #BLI_stack_pop which fills in an array.
- *
- * \param dst: The destination array,
- * must be at least (#BLI_Stack.elem_size * \a n) bytes long.
- * \param n: The number of items to pop.
- *
- * \note The first item in the array will be last item added to the stack.
- */
void BLI_stack_pop_n(BLI_Stack *stack, void *dst, unsigned int n)
{
BLI_assert(n <= BLI_stack_count(stack));
@@ -200,11 +165,6 @@ void BLI_stack_pop_n(BLI_Stack *stack, void *dst, unsigned int n)
}
}
-/**
- * A version of #BLI_stack_pop_n which fills in an array (in the reverse order).
- *
- * \note The first item in the array will be first item added to the stack.
- */
void BLI_stack_pop_n_reverse(BLI_Stack *stack, void *dst, unsigned int n)
{
BLI_assert(n <= BLI_stack_count(stack));
@@ -224,9 +184,6 @@ void *BLI_stack_peek(BLI_Stack *stack)
return stack_get_last_elem(stack);
}
-/**
- * Removes the top element from the stack.
- */
void BLI_stack_discard(BLI_Stack *stack)
{
BLI_assert(BLI_stack_is_empty(stack) == false);
@@ -247,9 +204,6 @@ void BLI_stack_discard(BLI_Stack *stack)
}
}
-/**
- * Discards all elements without freeing.
- */
void BLI_stack_clear(BLI_Stack *stack)
{
#ifdef USE_TOTELEM
@@ -304,9 +258,6 @@ size_t BLI_stack_count(const BLI_Stack *stack)
#endif
}
-/**
- * Returns true if the stack is empty, false otherwise
- */
bool BLI_stack_is_empty(const BLI_Stack *stack)
{
#ifdef USE_TOTELEM
diff --git a/source/blender/blenlib/intern/storage.c b/source/blender/blenlib/intern/storage.c
index 47bb2f0e8dd..c5e30ac6a6b 100644
--- a/source/blender/blenlib/intern/storage.c
+++ b/source/blender/blenlib/intern/storage.c
@@ -72,12 +72,6 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
-/**
- * Copies the current working directory into *dir (max size maxncpy), and
- * returns a pointer to same.
- *
- * \note can return NULL when the size is not big enough
- */
char *BLI_current_working_dir(char *dir, const size_t maxncpy)
{
#if defined(WIN32)
@@ -102,10 +96,6 @@ char *BLI_current_working_dir(char *dir, const size_t maxncpy)
#endif
}
-/**
- * Returns the number of free bytes on the volume containing the specified pathname. */
-/* Not actually used anywhere.
- */
double BLI_dir_free_space(const char *dir)
{
#ifdef WIN32
@@ -201,9 +191,6 @@ int64_t BLI_lseek(int fd, int64_t offset, int whence)
#endif
}
-/**
- * Returns the file size of an opened file descriptor.
- */
size_t BLI_file_descriptor_size(int file)
{
BLI_stat_t st;
@@ -213,9 +200,6 @@ size_t BLI_file_descriptor_size(int file)
return st.st_size;
}
-/**
- * Returns the size of a file.
- */
size_t BLI_file_size(const char *path)
{
BLI_stat_t stats;
@@ -343,10 +327,6 @@ bool BLI_file_alias_target(const char *filepath,
}
#endif
-/**
- * Returns the st_mode from stat-ing the specified path name, or 0 if stat fails
- * (most likely doesn't exist or no access).
- */
int BLI_exists(const char *path)
{
#if defined(WIN32)
@@ -430,18 +410,11 @@ int BLI_stat(const char *path, struct stat *buffer)
}
#endif
-/**
- * Does the specified path point to a directory?
- * \note Would be better in fileops.c except that it needs stat.h so add here
- */
bool BLI_is_dir(const char *file)
{
return S_ISDIR(BLI_exists(file));
}
-/**
- * Does the specified path point to a non-directory?
- */
bool BLI_is_file(const char *path)
{
const int mode = BLI_exists(path);
@@ -528,33 +501,6 @@ void *BLI_file_read_binary_as_mem(const char *filepath, size_t pad_bytes, size_t
return mem;
}
-/**
- * Return the text file data with:
-
- * - Newlines replaced with '\0'.
- * - Optionally trim white-space, replacing trailing <space> & <tab> with '\0'.
- *
- * This is an alternative to using #BLI_file_read_as_lines,
- * allowing us to loop over lines without converting it into a linked list
- * with individual allocations.
- *
- * \param trim_trailing_space: Replace trailing spaces & tabs with nil.
- * This arguments prevents the caller from counting blank lines (if that's important).
- * \param pad_bytes: When this is non-zero, the first byte is set to nil,
- * to simplify parsing the file.
- * It's recommended to pass in 1, so all text is nil terminated.
- *
- * Example looping over lines:
- *
- * \code{.c}
- * size_t data_len;
- * char *data = BLI_file_read_text_as_mem_with_newline_as_nil(filepath, true, 1, &data_len);
- * char *data_end = data + data_len;
- * for (char *line = data; line != data_end; line = strlen(line) + 1) {
- * printf("line='%s'\n", line);
- * }
- * \endcode
- */
void *BLI_file_read_text_as_mem_with_newline_as_nil(const char *filepath,
bool trim_trailing_space,
size_t pad_bytes,
@@ -585,9 +531,6 @@ void *BLI_file_read_text_as_mem_with_newline_as_nil(const char *filepath,
return mem;
}
-/**
- * Reads the contents of a text file and returns the lines in a linked list.
- */
LinkNode *BLI_file_read_as_lines(const char *filepath)
{
FILE *fp = BLI_fopen(filepath, "r");
@@ -634,15 +577,11 @@ LinkNode *BLI_file_read_as_lines(const char *filepath)
return lines.list;
}
-/*
- * Frees memory from a previous call to BLI_file_read_as_lines.
- */
void BLI_file_free_lines(LinkNode *lines)
{
BLI_linklist_freeN(lines);
}
-/** is file1 older than file2 */
bool BLI_file_older(const char *file1, const char *file2)
{
#ifdef WIN32
diff --git a/source/blender/blenlib/intern/storage_apple.mm b/source/blender/blenlib/intern/storage_apple.mm
index 8af98d61ecb..b0234b9a093 100644
--- a/source/blender/blenlib/intern/storage_apple.mm
+++ b/source/blender/blenlib/intern/storage_apple.mm
@@ -99,7 +99,7 @@ static bool find_attribute(const std::string &attributes, const char *search_att
*/
static bool test_onedrive_file_is_placeholder(const char *path)
{
- /* Note: Currently only checking for the "com.microsoft.OneDrive.RecallOnOpen" extended file
+ /* NOTE: Currently only checking for the "com.microsoft.OneDrive.RecallOnOpen" extended file
* attribute. In theory this attribute can also be set on files that aren't located inside a
* OneDrive folder. Maybe additional checks are required? */
@@ -184,3 +184,20 @@ eFileAttributes BLI_file_attributes(const char *path)
return (eFileAttributes)ret;
}
+
+const char *BLI_expand_tilde(const char *path_with_tilde)
+{
+ static char path_expanded[FILE_MAX];
+ @autoreleasepool {
+ const NSString *const str_with_tilde = [[NSString alloc] initWithCString:path_with_tilde
+ encoding:NSUTF8StringEncoding];
+ if (!str_with_tilde) {
+ return nullptr;
+ }
+ const NSString *const str_expanded = [str_with_tilde stringByExpandingTildeInPath];
+ [str_expanded getCString:path_expanded
+ maxLength:sizeof(path_expanded)
+ encoding:NSUTF8StringEncoding];
+ }
+ return path_expanded;
+}
diff --git a/source/blender/blenlib/intern/string.c b/source/blender/blenlib/intern/string.c
index 62c8625378d..2c626773871 100644
--- a/source/blender/blenlib/intern/string.c
+++ b/source/blender/blenlib/intern/string.c
@@ -42,15 +42,10 @@
// #define DEBUG_STRSIZE
-/**
- * Duplicates the first \a len bytes of cstring \a str
- * into a newly mallocN'd string and returns it. \a str
- * is assumed to be at least len bytes long.
- *
- * \param str: The string to be duplicated
- * \param len: The number of bytes to duplicate
- * \retval Returns the duplicated string
- */
+/* -------------------------------------------------------------------- */
+/** \name String Duplicate/Copy
+ * \{ */
+
char *BLI_strdupn(const char *str, const size_t len)
{
char *n = MEM_mallocN(len + 1, "strdup");
@@ -60,24 +55,11 @@ char *BLI_strdupn(const char *str, const size_t len)
return n;
}
-/**
- * Duplicates the cstring \a str into a newly mallocN'd
- * string and returns it.
- *
- * \param str: The string to be duplicated
- * \retval Returns the duplicated string
- */
char *BLI_strdup(const char *str)
{
return BLI_strdupn(str, strlen(str));
}
-/**
- * Appends the two strings, and returns new mallocN'ed string
- * \param str1: first string for copy
- * \param str2: second string for append
- * \retval Returns dst
- */
char *BLI_strdupcat(const char *__restrict str1, const char *__restrict str2)
{
/* include the NULL terminator of str2 only */
@@ -95,16 +77,6 @@ char *BLI_strdupcat(const char *__restrict str1, const char *__restrict str2)
return str;
}
-/**
- * Like strncpy but ensures dst is always
- * '\0' terminated.
- *
- * \param dst: Destination for copy
- * \param src: Source string to copy
- * \param maxncpy: Maximum number of characters to copy (generally
- * the size of dst)
- * \retval Returns dst
- */
char *BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t maxncpy)
{
size_t srclen = BLI_strnlen(src, maxncpy - 1);
@@ -119,16 +91,6 @@ char *BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t
return dst;
}
-/**
- * Like BLI_strncpy but ensures dst is always padded by given char,
- * on both sides (unless src is empty).
- *
- * \param dst: Destination for copy
- * \param src: Source string to copy
- * \param pad: the char to use for padding
- * \param maxncpy: Maximum number of characters to copy (generally the size of dst)
- * \retval Returns dst
- */
char *BLI_strncpy_ensure_pad(char *__restrict dst,
const char *__restrict src,
const char pad,
@@ -171,19 +133,6 @@ char *BLI_strncpy_ensure_pad(char *__restrict dst,
return dst;
}
-/**
- * Like strncpy but ensures dst is always
- * '\0' terminated.
- *
- * \note This is a duplicate of #BLI_strncpy that returns bytes copied.
- * And is a drop in replacement for 'snprintf(str, sizeof(str), "%s", arg);'
- *
- * \param dst: Destination for copy
- * \param src: Source string to copy
- * \param maxncpy: Maximum number of characters to copy (generally
- * the size of dst)
- * \retval The number of bytes copied (The only difference from BLI_strncpy).
- */
size_t BLI_strncpy_rlen(char *__restrict dst, const char *__restrict src, const size_t maxncpy)
{
size_t srclen = BLI_strnlen(src, maxncpy - 1);
@@ -205,9 +154,12 @@ size_t BLI_strcpy_rlen(char *__restrict dst, const char *__restrict src)
return srclen;
}
-/**
- * Portable replacement for `vsnprintf`.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name String Printing
+ * \{ */
+
size_t BLI_vsnprintf(char *__restrict buffer,
size_t maxncpy,
const char *__restrict format,
@@ -231,9 +183,6 @@ size_t BLI_vsnprintf(char *__restrict buffer,
return n;
}
-/**
- * A version of #BLI_vsnprintf that returns `strlen(buffer)`
- */
size_t BLI_vsnprintf_rlen(char *__restrict buffer,
size_t maxncpy,
const char *__restrict format,
@@ -258,9 +207,6 @@ size_t BLI_vsnprintf_rlen(char *__restrict buffer,
return n;
}
-/**
- * Portable replacement for #snprintf
- */
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format, ...)
{
size_t n;
@@ -277,9 +223,6 @@ size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict
return n;
}
-/**
- * A version of #BLI_snprintf that returns `strlen(dst)`
- */
size_t BLI_snprintf_rlen(char *__restrict dst, size_t maxncpy, const char *__restrict format, ...)
{
size_t n;
@@ -296,10 +239,6 @@ size_t BLI_snprintf_rlen(char *__restrict dst, size_t maxncpy, const char *__res
return n;
}
-/**
- * Print formatted string into a newly #MEM_mallocN'd string
- * and return it.
- */
char *BLI_sprintfN(const char *__restrict format, ...)
{
DynStr *ds;
@@ -318,18 +257,12 @@ char *BLI_sprintfN(const char *__restrict format, ...)
return n;
}
-/**
- * This roughly matches C and Python's string escaping with double quotes - `"`.
- *
- * Since every character may need escaping,
- * it's common to create a buffer twice as large as the input.
- *
- * \param dst: The destination string, at least \a dst_maxncpy, typically `(strlen(src) * 2) + 1`.
- * \param src: The un-escaped source string.
- * \param dst_maxncpy: The maximum number of bytes allowable to copy.
- *
- * \note This is used for creating animation paths in blend files.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name String Escape/Un-Escape
+ * \{ */
+
size_t BLI_str_escape(char *__restrict dst, const char *__restrict src, const size_t dst_maxncpy)
{
@@ -381,18 +314,6 @@ BLI_INLINE bool str_unescape_pair(char c_next, char *r_out)
return false;
}
-/**
- * This roughly matches C and Python's string escaping with double quotes - `"`.
- *
- * The destination will never be larger than the source, it will either be the same
- * or up to half when all characters are escaped.
- *
- * \param dst: The destination string, at least the size of `strlen(src) + 1`.
- * \param src: The escaped source string.
- * \param src_maxncpy: The maximum number of bytes allowable to copy from `src`.
- * \param dst_maxncpy: The maximum number of bytes allowable to copy into `dst`.
- * \param r_is_complete: Set to true when
- */
size_t BLI_str_unescape_ex(char *__restrict dst,
const char *__restrict src,
const size_t src_maxncpy,
@@ -418,16 +339,6 @@ size_t BLI_str_unescape_ex(char *__restrict dst,
return len;
}
-/**
- * See #BLI_str_unescape_ex doc-string.
- *
- * This function makes the assumption that `dst` always has
- * at least `src_maxncpy` bytes available.
- *
- * Use #BLI_str_unescape_ex if `dst` has a smaller fixed size.
- *
- * \note This is used for parsing animation paths in blend files (runs often).
- */
size_t BLI_str_unescape(char *__restrict dst, const char *__restrict src, const size_t src_maxncpy)
{
size_t len = 0;
@@ -442,14 +353,6 @@ size_t BLI_str_unescape(char *__restrict dst, const char *__restrict src, const
return len;
}
-/**
- * Find the first un-escaped quote in the string (to find the end of the string).
- *
- * \param str: Typically this is the first character in a quoted string.
- * Where the character before `*str` would be `"`.
-
- * \return The pointer to the first un-escaped quote.
- */
const char *BLI_str_escape_find_quote(const char *str)
{
bool escape = false;
@@ -462,18 +365,12 @@ const char *BLI_str_escape_find_quote(const char *str)
return (*str == '"') ? str : NULL;
}
-/**
- * Return the range of the quoted string (excluding quotes) `str` after `prefix`.
- *
- * A version of #BLI_str_quoted_substrN that calculates the range
- * instead of un-escaping and allocating the result.
- *
- * \param str: String potentially including `prefix`.
- * \param prefix: Quoted string prefix.
- * \param r_start: The start of the quoted string (after the first quote).
- * \param r_end: The end of the quoted string (before the last quote).
- * \return True when a quoted string range could be found after `prefix`.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name String Quote/Un-Quote
+ * \{ */
+
bool BLI_str_quoted_substr_range(const char *__restrict str,
const char *__restrict prefix,
int *__restrict r_start,
@@ -539,19 +436,6 @@ char *BLI_str_quoted_substrN(const char *__restrict str, const char *__restrict
}
#endif
-/**
- * Fills \a result with text within "" that appear after some the contents of \a prefix.
- * i.e. for string `pose["apples"]` with prefix `pose[`, it will return `apples`.
- *
- * \param str: is the entire string to chop.
- * \param prefix: is the part of the string to step over.
- * \param result: The buffer to fill.
- * \param result_maxlen: The maximum size of the buffer (including nil terminator).
- * \return True if the prefix was found and the entire quoted string was copied into result.
- *
- * Assume that the strings returned must be freed afterwards,
- * and that the inputs will contain data we want.
- */
bool BLI_str_quoted_substr(const char *__restrict str,
const char *__restrict prefix,
char *result,
@@ -570,19 +454,12 @@ bool BLI_str_quoted_substr(const char *__restrict str,
return is_complete;
}
-/**
- * string with all instances of substr_old replaced with substr_new,
- * Returns a copy of the c-string \a str into a newly #MEM_mallocN'd
- * and returns it.
- *
- * \note A rather wasteful string-replacement utility, though this shall do for now...
- * Feel free to replace this with an even safe + nicer alternative
- *
- * \param str: The string to replace occurrences of substr_old in
- * \param substr_old: The text in the string to find and replace
- * \param substr_new: The text in the string to find and replace
- * \retval Returns the duplicated string
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name String Replace
+ * \{ */
+
char *BLI_str_replaceN(const char *__restrict str,
const char *__restrict substr_old,
const char *__restrict substr_new)
@@ -638,13 +515,6 @@ char *BLI_str_replaceN(const char *__restrict str,
return BLI_strdup(str);
}
-/**
- * In-place replace every \a src to \a dst in \a str.
- *
- * \param str: The string to operate on.
- * \param src: The character to replace.
- * \param dst: The character to replace with.
- */
void BLI_str_replace_char(char *str, char src, char dst)
{
while (*str) {
@@ -655,13 +525,6 @@ void BLI_str_replace_char(char *str, char src, char dst)
}
}
-/**
- * Simple exact-match string replacement.
- *
- * \param replace_table: Array of source, destination pairs.
- *
- * \note Larger tables should use a hash table.
- */
bool BLI_str_replace_table_exact(char *string,
const size_t string_len,
const char *replace_table[][2],
@@ -678,19 +541,15 @@ bool BLI_str_replace_table_exact(char *string,
/** \} */
-/**
- * Compare two strings without regard to case.
- *
- * \retval True if the strings are equal, false otherwise.
- */
+/* -------------------------------------------------------------------- */
+/** \name String Comparison/Matching
+ * \{ */
+
int BLI_strcaseeq(const char *a, const char *b)
{
return (BLI_strcasecmp(a, b) == 0);
}
-/**
- * Portable replacement for `strcasestr` (not available in MSVC)
- */
char *BLI_strcasestr(const char *s, const char *find)
{
char c, sc;
@@ -745,9 +604,6 @@ bool BLI_string_all_words_matched(const char *name,
return all_words_matched;
}
-/**
- * Variation of #BLI_strcasestr with string length limited to \a len
- */
char *BLI_strncasestr(const char *s, const char *find, size_t len)
{
char c, sc;
@@ -875,10 +731,6 @@ static int left_number_strcmp(const char *s1, const char *s2, int *tiebreaker)
return 0;
}
-/**
- * Case insensitive, *natural* string comparison,
- * keeping numbers in order.
- */
int BLI_strcasecmp_natural(const char *s1, const char *s2)
{
int d1 = 0, d2 = 0;
@@ -946,10 +798,6 @@ int BLI_strcasecmp_natural(const char *s1, const char *s2)
return strcmp(s1, s2);
}
-/**
- * Like strcmp, but will ignore any heading/trailing pad char for comparison.
- * So e.g. if pad is '*', '*world' and 'world*' will compare equal.
- */
int BLI_strcmp_ignore_pad(const char *str1, const char *str2, const char pad)
{
size_t str1_len, str2_len;
@@ -990,7 +838,79 @@ int BLI_strcmp_ignore_pad(const char *str1, const char *str2, const char pad)
}
}
-/* determine the length of a fixed-size string */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name String Comparison at Start/End
+ * \{ */
+
+int BLI_str_index_in_array_n(const char *__restrict str,
+ const char **__restrict str_array,
+ const int str_array_len)
+{
+ int index;
+ const char **str_iter = str_array;
+
+ for (index = 0; index < str_array_len; str_iter++, index++) {
+ if (STREQ(str, *str_iter)) {
+ return index;
+ }
+ }
+ return -1;
+}
+
+int BLI_str_index_in_array(const char *__restrict str, const char **__restrict str_array)
+{
+ int index;
+ const char **str_iter = str_array;
+
+ for (index = 0; *str_iter; str_iter++, index++) {
+ if (STREQ(str, *str_iter)) {
+ return index;
+ }
+ }
+ return -1;
+}
+
+bool BLI_str_startswith(const char *__restrict str, const char *__restrict start)
+{
+ for (; *str && *start; str++, start++) {
+ if (*str != *start) {
+ return false;
+ }
+ }
+
+ return (*start == '\0');
+}
+
+bool BLI_strn_endswith(const char *__restrict str, const char *__restrict end, size_t slength)
+{
+ size_t elength = strlen(end);
+
+ if (elength < slength) {
+ const char *iter = &str[slength - elength];
+ while (*iter) {
+ if (*iter++ != *end++) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+bool BLI_str_endswith(const char *__restrict str, const char *__restrict end)
+{
+ const size_t slength = strlen(str);
+ return BLI_strn_endswith(str, end, slength);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name String Length
+ * \{ */
+
size_t BLI_strnlen(const char *s, const size_t maxlen)
{
size_t len;
@@ -1003,6 +923,12 @@ size_t BLI_strnlen(const char *s, const size_t maxlen)
return len;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name String Case Conversion
+ * \{ */
+
void BLI_str_tolower_ascii(char *str, const size_t len)
{
size_t i;
@@ -1025,9 +951,12 @@ void BLI_str_toupper_ascii(char *str, const size_t len)
}
}
-/**
- * Strip white-space from end of the string.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name String Stripping
+ * \{ */
+
void BLI_str_rstrip(char *str)
{
for (int i = (int)strlen(str) - 1; i >= 0; i--) {
@@ -1040,15 +969,6 @@ void BLI_str_rstrip(char *str)
}
}
-/**
- * Strip trailing zeros from a float, eg:
- * 0.0000 -> 0.0
- * 2.0010 -> 2.001
- *
- * \param str:
- * \param pad:
- * \return The number of zeros stripped.
- */
int BLI_str_rstrip_float_zero(char *str, const char pad)
{
char *p = strchr(str, '.');
@@ -1069,138 +989,22 @@ int BLI_str_rstrip_float_zero(char *str, const char pad)
return totstrip;
}
-/**
- * Return index of a string in a string array.
- *
- * \param str: The string to find.
- * \param str_array: Array of strings.
- * \param str_array_len: The length of the array, or -1 for a NULL-terminated array.
- * \return The index of str in str_array or -1.
- */
-int BLI_str_index_in_array_n(const char *__restrict str,
- const char **__restrict str_array,
- const int str_array_len)
-{
- int index;
- const char **str_iter = str_array;
-
- for (index = 0; index < str_array_len; str_iter++, index++) {
- if (STREQ(str, *str_iter)) {
- return index;
- }
- }
- return -1;
-}
-
-/**
- * Return index of a string in a string array.
- *
- * \param str: The string to find.
- * \param str_array: Array of strings, (must be NULL-terminated).
- * \return The index of str in str_array or -1.
- */
-int BLI_str_index_in_array(const char *__restrict str, const char **__restrict str_array)
-{
- int index;
- const char **str_iter = str_array;
-
- for (index = 0; *str_iter; str_iter++, index++) {
- if (STREQ(str, *str_iter)) {
- return index;
- }
- }
- return -1;
-}
-
-/**
- * Find if a string starts with another string.
- *
- * \param str: The string to search within.
- * \param start: The string we look for at the start.
- * \return If str starts with start.
- */
-bool BLI_str_startswith(const char *__restrict str, const char *__restrict start)
-{
- for (; *str && *start; str++, start++) {
- if (*str != *start) {
- return false;
- }
- }
-
- return (*start == '\0');
-}
-
-bool BLI_strn_endswith(const char *__restrict str, const char *__restrict end, size_t slength)
-{
- size_t elength = strlen(end);
+/** \} */
- if (elength < slength) {
- const char *iter = &str[slength - elength];
- while (*iter) {
- if (*iter++ != *end++) {
- return false;
- }
- }
- return true;
- }
- return false;
-}
+/* -------------------------------------------------------------------- */
+/** \name String Split (Partition)
+ * \{ */
-/**
- * Find if a string ends with another string.
- *
- * \param str: The string to search within.
- * \param end: The string we look for at the end.
- * \return If str ends with end.
- */
-bool BLI_str_endswith(const char *__restrict str, const char *__restrict end)
-{
- const size_t slength = strlen(str);
- return BLI_strn_endswith(str, end, slength);
-}
-
-/**
- * Find the first char matching one of the chars in \a delim, from left.
- *
- * \param str: The string to search within.
- * \param delim: The set of delimiters to search for, as unicode values.
- * \param sep: Return value, set to the first delimiter found (or NULL if none found).
- * \param suf: Return value, set to next char after the first delimiter found
- * (or NULL if none found).
- * \return The length of the prefix (i.e. *sep - str).
- */
size_t BLI_str_partition(const char *str, const char delim[], const char **sep, const char **suf)
{
return BLI_str_partition_ex(str, NULL, delim, sep, suf, false);
}
-/**
- * Find the first char matching one of the chars in \a delim, from right.
- *
- * \param str: The string to search within.
- * \param delim: The set of delimiters to search for, as unicode values.
- * \param sep: Return value, set to the first delimiter found (or NULL if none found).
- * \param suf: Return value, set to next char after the first delimiter found
- * (or NULL if none found).
- * \return The length of the prefix (i.e. *sep - str).
- */
size_t BLI_str_rpartition(const char *str, const char delim[], const char **sep, const char **suf)
{
return BLI_str_partition_ex(str, NULL, delim, sep, suf, true);
}
-/**
- * Find the first char matching one of the chars in \a delim, either from left or right.
- *
- * \param str: The string to search within.
- * \param end: If non-NULL, the right delimiter of the string.
- * \param delim: The set of delimiters to search for, as unicode values.
- * \param sep: Return value, set to the first delimiter found (or NULL if none found).
- * \param suf: Return value, set to next char after the first delimiter found
- * (or NULL if none found).
- * \param from_right: If %true, search from the right of \a str, else, search from its left.
- * \return The length of the prefix (i.e. *sep - str).
- */
size_t BLI_str_partition_ex(const char *str,
const char *end,
const char delim[],
@@ -1251,6 +1055,47 @@ size_t BLI_str_partition_ex(const char *str,
return end ? (size_t)(end - str) : strlen(str);
}
+int BLI_string_find_split_words(
+ const char *str, const size_t len, const char delim, int r_words[][2], int words_max)
+{
+ int n = 0, i;
+ bool charsearch = true;
+
+ /* Skip leading spaces */
+ for (i = 0; (i < len) && (str[i] != '\0'); i++) {
+ if (str[i] != delim) {
+ break;
+ }
+ }
+
+ for (; (i < len) && (str[i] != '\0') && (n < words_max); i++) {
+ if ((str[i] != delim) && (charsearch == true)) {
+ r_words[n][0] = i;
+ charsearch = false;
+ }
+ else {
+ if ((str[i] == delim) && (charsearch == false)) {
+ r_words[n][1] = i - r_words[n][0];
+ n++;
+ charsearch = true;
+ }
+ }
+ }
+
+ if (charsearch == false) {
+ r_words[n][1] = i - r_words[n][0];
+ n++;
+ }
+
+ return n;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name String Formatting (Numeric)
+ * \{ */
+
static size_t BLI_str_format_int_grouped_ex(char src[16], char dst[16], int num_len)
{
char *p_src = src;
@@ -1275,14 +1120,6 @@ static size_t BLI_str_format_int_grouped_ex(char src[16], char dst[16], int num_
return (size_t)(p_dst - dst);
}
-/**
- * Format ints with decimal grouping.
- * 1000 -> 1,000
- *
- * \param dst: The resulting string
- * \param num: Number to format
- * \return The length of \a dst
- */
size_t BLI_str_format_int_grouped(char dst[16], int num)
{
char src[16];
@@ -1291,14 +1128,6 @@ size_t BLI_str_format_int_grouped(char dst[16], int num)
return BLI_str_format_int_grouped_ex(src, dst, num_len);
}
-/**
- * Format uint64_t with decimal grouping.
- * 1000 -> 1,000
- *
- * \param dst: The resulting string
- * \param num: Number to format
- * \return The length of \a dst
- */
size_t BLI_str_format_uint64_grouped(char dst[16], uint64_t num)
{
/* NOTE: Buffer to hold maximum unsigned int64, which is 1.8e+19. but
@@ -1309,16 +1138,6 @@ size_t BLI_str_format_uint64_grouped(char dst[16], uint64_t num)
return BLI_str_format_int_grouped_ex(src, dst, num_len);
}
-/**
- * Format a size in bytes using binary units.
- * 1000 -> 1 KB
- * Number of decimal places grows with the used unit (e.g. 1.5 MB, 1.55 GB, 1.545 TB).
- *
- * \param dst: The resulting string.
- * Dimension of 14 to support largest possible value for \a bytes (#LLONG_MAX).
- * \param bytes: Number to format.
- * \param base_10: Calculate using base 10 (GB, MB, ...) or 2 (GiB, MiB, ...).
- */
void BLI_str_format_byte_unit(char dst[15], long long int bytes, const bool base_10)
{
double bytes_converted = bytes;
@@ -1345,24 +1164,6 @@ void BLI_str_format_byte_unit(char dst[15], long long int bytes, const bool base
BLI_strncpy(dst + len, base_10 ? units_base_10[order] : units_base_2[order], dst_len - len);
}
-/**
- * Format a count to up to 6 places (plus '\0' terminator) string using long number
- * names abbreviations. Used to produce a compact representation of large numbers.
- *
- * 1 -> 1
- * 15 -> 15
- * 155 -> 155
- * 1555 -> 1.6K
- * 15555 -> 15.6K
- * 155555 -> 156K
- * 1555555 -> 1.6M
- * 15555555 -> 15.6M
- * 155555555 -> 156M
- * 1000000000 -> 1B
- * ...
- *
- * Length of 7 is the maximum of the resulting string, for example, `-15.5K\0`.
- */
void BLI_str_format_attribute_domain_size(char dst[7], int number_to_format)
{
float number_to_format_converted = number_to_format;
@@ -1384,47 +1185,4 @@ void BLI_str_format_attribute_domain_size(char dst[7], int number_to_format)
BLI_snprintf(dst, dst_len, "%.*f%s", decimals, number_to_format_converted, units[order]);
}
-/**
- * Find the ranges needed to split \a str into its individual words.
- *
- * \param str: The string to search for words.
- * \param len: Size of the string to search.
- * \param delim: Character to use as a delimiter.
- * \param r_words: Info about the words found. Set to [index, len] pairs.
- * \param words_max: Max number of words to find
- * \return The number of words found in \a str
- */
-int BLI_string_find_split_words(
- const char *str, const size_t len, const char delim, int r_words[][2], int words_max)
-{
- int n = 0, i;
- bool charsearch = true;
-
- /* Skip leading spaces */
- for (i = 0; (i < len) && (str[i] != '\0'); i++) {
- if (str[i] != delim) {
- break;
- }
- }
-
- for (; (i < len) && (str[i] != '\0') && (n < words_max); i++) {
- if ((str[i] != delim) && (charsearch == true)) {
- r_words[n][0] = i;
- charsearch = false;
- }
- else {
- if ((str[i] == delim) && (charsearch == false)) {
- r_words[n][1] = i - r_words[n][0];
- n++;
- charsearch = true;
- }
- }
- }
-
- if (charsearch == false) {
- r_words[n][1] = i - r_words[n][0];
- n++;
- }
-
- return n;
-}
+/** \} */
diff --git a/source/blender/blenlib/intern/string_search.cc b/source/blender/blenlib/intern/string_search.cc
index 08ba473f96b..c5528dce2f2 100644
--- a/source/blender/blenlib/intern/string_search.cc
+++ b/source/blender/blenlib/intern/string_search.cc
@@ -35,14 +35,6 @@ static int64_t count_utf8_code_points(StringRef str)
return static_cast<int64_t>(BLI_strnlen_utf8(str.data(), static_cast<size_t>(str.size())));
}
-/**
- * Computes the cost of transforming string a into b. The cost/distance is the minimal number of
- * operations that need to be executed. Valid operations are deletion, insertion, substitution and
- * transposition.
- *
- * This function is utf8 aware in the sense that it works at the level of individual code points
- * (1-4 bytes long) instead of on individual bytes.
- */
int damerau_levenshtein_distance(StringRef a, StringRef b)
{
constexpr int deletion_cost = 1;
@@ -106,10 +98,6 @@ int damerau_levenshtein_distance(StringRef a, StringRef b)
return v1.last();
}
-/**
- * Returns -1 when this is no reasonably good match.
- * Otherwise returns the number of errors in the match.
- */
int get_fuzzy_match_errors(StringRef query, StringRef full)
{
/* If it is a perfect partial match, return immediately. */
@@ -346,10 +334,6 @@ static int score_query_against_words(Span<StringRef> query_words, Span<StringRef
return total_match_score;
}
-/**
- * Splits a string into words and normalizes them (currently that just means converting to lower
- * case). The returned strings are allocated in the given allocator.
- */
void extract_normalized_words(StringRef str,
LinearAllocator<> &allocator,
Vector<StringRef, 64> &r_words)
@@ -405,6 +389,7 @@ struct SearchItem {
blender::Span<blender::StringRef> normalized_words;
int length;
void *user_data;
+ int weight;
};
struct StringSearch {
@@ -417,25 +402,21 @@ StringSearch *BLI_string_search_new()
return new StringSearch();
}
-/**
- * Add a new possible result to the search.
- * The caller keeps ownership of all parameters.
- */
-void BLI_string_search_add(StringSearch *search, const char *str, void *user_data)
+void BLI_string_search_add(StringSearch *search,
+ const char *str,
+ void *user_data,
+ const int weight)
{
using namespace blender;
Vector<StringRef, 64> words;
StringRef str_ref{str};
string_search::extract_normalized_words(str_ref, search->allocator, words);
- search->items.append(
- {search->allocator.construct_array_copy(words.as_span()), (int)str_ref.size(), user_data});
+ search->items.append({search->allocator.construct_array_copy(words.as_span()),
+ (int)str_ref.size(),
+ user_data,
+ weight});
}
-/**
- * Filter and sort all previously added search items.
- * Returns an array containing the filtered user data.
- * The caller has to free the returned array.
- */
int BLI_string_search_query(StringSearch *search, const char *query, void ***r_data)
{
using namespace blender;
@@ -474,6 +455,11 @@ int BLI_string_search_query(StringSearch *search, const char *query, void ***r_d
std::sort(indices.begin(), indices.end(), [&](int a, int b) {
return search->items[a].length < search->items[b].length;
});
+ /* Prefer items with larger weights. Use `stable_sort` so that if the weights are the same,
+ * the order won't be changed. */
+ std::stable_sort(indices.begin(), indices.end(), [&](int a, int b) {
+ return search->items[a].weight > search->items[b].weight;
+ });
}
sorted_result_indices.extend(indices);
}
diff --git a/source/blender/blenlib/intern/string_utf8.c b/source/blender/blenlib/intern/string_utf8.c
index b9ea538ff24..807344a912c 100644
--- a/source/blender/blenlib/intern/string_utf8.c
+++ b/source/blender/blenlib/intern/string_utf8.c
@@ -42,9 +42,11 @@
// #define DEBUG_STRSIZE
-/* array copied from glib's gutf8.c, */
-/* NOTE: last two values (0xfe and 0xff) are forbidden in utf-8,
- * so they are considered 1 byte length too. */
+/**
+ * Array copied from GLIB's `gutf8.c`.
+ * \note last two values (0xfe and 0xff) are forbidden in UTF-8,
+ * so they are considered 1 byte length too.
+ */
static const size_t utf8_skip_data[256] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@@ -56,22 +58,18 @@ static const size_t utf8_skip_data[256] = {
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 1, 1,
};
-/* from libswish3, originally called u8_isvalid(),
- * modified to return the index of the bad character (byte index not utf).
- * http://svn.swish-e.org/libswish3/trunk/src/libswish3/utf8.c r3044 - campbell */
-
-/* based on the valid_utf8 routine from the PCRE library by Philip Hazel
- *
- * length is in bytes, since without knowing whether the string is valid
- * it's hard to know how many characters there are! */
-
-/**
- * Find first utf-8 invalid byte in given \a str, of \a length bytes.
- *
- * \return the offset of the first invalid byte.
- */
ptrdiff_t BLI_str_utf8_invalid_byte(const char *str, size_t length)
{
+ /* NOTE(@campbellbarton): from libswish3, originally called u8_isvalid(),
+ * modified to return the index of the bad character (byte index not UTF).
+ * http://svn.swish-e.org/libswish3/trunk/src/libswish3/utf8.c r3044.
+ *
+ * Comment from code in: `libswish3`.
+ * Based on the `valid_utf8` routine from the PCRE library by Philip Hazel
+ *
+ * length is in bytes, since without knowing whether the string is valid
+ * it's hard to know how many characters there are! */
+
const unsigned char *p, *perr, *pend = (const unsigned char *)str + length;
unsigned char c;
int ab;
@@ -195,11 +193,6 @@ utf8_error:
return ((const char *)perr - (const char *)str);
}
-/**
- * Remove any invalid utf-8 byte (taking into account multi-bytes sequence of course).
- *
- * \return number of stripped bytes.
- */
int BLI_str_utf8_invalid_strip(char *str, size_t length)
{
ptrdiff_t bad_char;
@@ -312,7 +305,6 @@ size_t BLI_strncpy_wchar_as_utf8(char *__restrict dst,
return len;
}
-/* wchar len in utf8 */
size_t BLI_wstrlen_utf8(const wchar_t *src)
{
size_t len = 0;
@@ -362,11 +354,6 @@ size_t BLI_strnlen_utf8_ex(const char *strc, const size_t maxlen, size_t *r_len_
return len;
}
-/**
- * \param strc: the string to measure the length.
- * \param maxlen: the string length (in bytes)
- * \return the unicode length (not in bytes!)
- */
size_t BLI_strnlen_utf8(const char *strc, const size_t maxlen)
{
size_t len_bytes;
@@ -389,8 +376,6 @@ size_t BLI_strncpy_wchar_from_utf8(wchar_t *__restrict dst_w,
/* end wchar_t / utf8 functions */
/* --------------------------------------------------------------------------*/
-/* count columns that character/string occupies, based on wcwidth.c */
-
int BLI_wcwidth(char32_t ucs)
{
return mk_wcwidth(ucs);
@@ -475,10 +460,10 @@ int BLI_str_utf8_char_width_safe(const char *p)
} \
(void)0
-/* uses glib functions but not from glib */
-/* gets the size of a single utf8 char */
int BLI_str_utf8_size(const char *p)
{
+ /* NOTE: uses glib functions but not from GLIB. */
+
int mask = 0, len;
const unsigned char c = (unsigned char)*p;
@@ -489,7 +474,6 @@ int BLI_str_utf8_size(const char *p)
return len;
}
-/* use when we want to skip errors */
int BLI_str_utf8_size_safe(const char *p)
{
int mask = 0, len;
@@ -502,21 +486,10 @@ int BLI_str_utf8_size_safe(const char *p)
return len;
}
-/* was g_utf8_get_char */
-/**
- * BLI_str_utf8_as_unicode:
- * \param p: a pointer to Unicode character encoded as UTF-8
- *
- * Converts a sequence of bytes encoded as UTF-8 to a Unicode character.
- * If \a p does not point to a valid UTF-8 encoded character, results are
- * undefined. If you are not sure that the bytes are complete
- * valid Unicode characters, you should use g_utf8_get_char_validated()
- * instead.
- *
- * Return value: the resulting character
- */
uint BLI_str_utf8_as_unicode(const char *p)
{
+ /* Originally `g_utf8_get_char` in GLIB. */
+
int i, len;
uint mask = 0;
uint result;
@@ -531,19 +504,6 @@ uint BLI_str_utf8_as_unicode(const char *p)
return result;
}
-/**
- * UTF8 decoding that steps over the index (unless an error is encountered).
- *
- * \param p: The text to step over.
- * \param p_len: The length of `p`.
- * \param index: Index of `p` to step over.
- * \return the code-point or #BLI_UTF8_ERR if there is a decoding error.
- *
- * \note The behavior for clipped text (where `p_len` limits decoding trailing bytes)
- * must have the same behavior is encountering a nil byte,
- * so functions that only use the first part of a string has matching behavior to functions
- * that null terminate the text.
- */
uint BLI_str_utf8_as_unicode_step_or_error(const char *__restrict p,
const size_t p_len,
size_t *__restrict index)
@@ -569,16 +529,6 @@ uint BLI_str_utf8_as_unicode_step_or_error(const char *__restrict p,
return result;
}
-/**
- * UTF8 decoding that steps over the index (unless an error is encountered).
- *
- * \param p: The text to step over.
- * \param p_len: The length of `p`.
- * \param index: Index of `p` to step over.
- * \return the code-point `(p + *index)` if there is a decoding error.
- *
- * \note Falls back to `LATIN1` for text drawing.
- */
uint BLI_str_utf8_as_unicode_step(const char *__restrict p,
const size_t p_len,
size_t *__restrict index)
@@ -633,18 +583,6 @@ size_t BLI_str_utf8_from_unicode_len(const uint c)
return len;
}
-/**
- * BLI_str_utf8_from_unicode:
- *
- * \param c: a Unicode character code
- * \param outbuf: output buffer, must have at least `outbuf_len` bytes of space.
- * If the length required by `c` exceeds `outbuf_len`,
- * the bytes available bytes will be zeroed and `outbuf_len` returned.
- *
- * Converts a single character to UTF-8.
- *
- * \return number of bytes written.
- */
size_t BLI_str_utf8_from_unicode(uint c, char *outbuf, const size_t outbuf_len)
{
@@ -724,7 +662,6 @@ size_t BLI_str_utf32_as_utf8(char *__restrict dst,
return len;
}
-/* utf32 len in utf8 */
size_t BLI_str_utf32_as_utf8_len(const char32_t *src)
{
size_t len = 0;
@@ -736,24 +673,10 @@ size_t BLI_str_utf32_as_utf8_len(const char32_t *src)
return len;
}
-/* was g_utf8_find_prev_char */
-/**
- * BLI_str_find_prev_char_utf8:
- * \param str: pointer to the beginning of a UTF-8 encoded string
- * \param p: pointer to some position within \a str
- *
- * Given a position \a p with a UTF-8 encoded string \a str, find the start
- * of the previous UTF-8 character starting before. \a p Returns \a str_start if no
- * UTF-8 characters are present in \a str_start before \a p.
- *
- * \a p does not have to be at the beginning of a UTF-8 character. No check
- * is made to see if the character found is actually valid other than
- * it starts with an appropriate byte.
- *
- * \return A pointer to the found character.
- */
const char *BLI_str_find_prev_char_utf8(const char *p, const char *str_start)
{
+ /* Originally `g_utf8_find_prev_char` in GLIB. */
+
BLI_assert(p >= str_start);
if (str_start < p) {
for (--p; p >= str_start; p--) {
@@ -765,22 +688,10 @@ const char *BLI_str_find_prev_char_utf8(const char *p, const char *str_start)
return p;
}
-/* was g_utf8_find_next_char */
-/**
- * BLI_str_find_next_char_utf8:
- * \param p: a pointer to a position within a UTF-8 encoded string
- * \param end: a pointer to the byte following the end of the string.
- *
- * Finds the start of the next UTF-8 character in the string after \a p
- *
- * \a p does not have to be at the beginning of a UTF-8 character. No check
- * is made to see if the character found is actually valid other than
- * it starts with an appropriate byte.
- *
- * \return a pointer to the found character or a pointer to the null terminating character '\0'.
- */
const char *BLI_str_find_next_char_utf8(const char *p, const char *str_end)
{
+ /* Originally `g_utf8_find_next_char` in GLIB. */
+
BLI_assert(p <= str_end);
if ((p < str_end) && (*p != '\0')) {
for (++p; p < str_end && (*p & 0xc0) == 0x80; p++) {
diff --git a/source/blender/blenlib/intern/string_utils.c b/source/blender/blenlib/intern/string_utils.c
index b62b9c3bc7a..21162904dbd 100644
--- a/source/blender/blenlib/intern/string_utils.c
+++ b/source/blender/blenlib/intern/string_utils.c
@@ -38,20 +38,6 @@
# pragma GCC diagnostic error "-Wsign-conversion"
#endif
-/**
- * Looks for a numeric suffix preceded by delim character on the end of
- * name, puts preceding part into *left and value of suffix into *nr.
- * Returns the length of *left.
- *
- * Foo.001 -> "Foo", 1
- * Returning the length of "Foo"
- *
- * \param left: Where to return copy of part preceding delim
- * \param nr: Where to return value of numeric suffix
- * \param name: String to split
- * \param delim: Delimiter character
- * \return Length of \a left
- */
size_t BLI_split_name_num(char *left, int *nr, const char *name, const char delim)
{
const size_t name_len = strlen(name);
@@ -102,10 +88,6 @@ static bool is_char_sep(const char c)
return ELEM(c, '.', ' ', '-', '_');
}
-/**
- * based on `BLI_split_dirfile()` / `os.path.splitext()`,
- * `"a.b.c"` -> (`"a.b"`, `".c"`).
- */
void BLI_string_split_suffix(const char *string, char *r_body, char *r_suf, const size_t str_len)
{
size_t len = BLI_strnlen(string, str_len);
@@ -124,9 +106,6 @@ void BLI_string_split_suffix(const char *string, char *r_body, char *r_suf, cons
memcpy(r_body, string, len + 1);
}
-/**
- * `"a.b.c"` -> (`"a."`, `"b.c"`)
- */
void BLI_string_split_prefix(const char *string, char *r_pre, char *r_body, const size_t str_len)
{
size_t len = BLI_strnlen(string, str_len);
@@ -146,17 +125,6 @@ void BLI_string_split_prefix(const char *string, char *r_pre, char *r_body, cons
BLI_strncpy(r_body, string, len);
}
-/**
- * Finds the best possible flipped (left/right) name.
- * For renaming; check for unique names afterwards.
- *
- * \param r_name: flipped name,
- * assumed to be a pointer to a string of at least \a name_len size.
- * \param from_name: original name,
- * assumed to be a pointer to a string of at least \a name_len size.
- * \param strip_number: If set, remove number extensions.
- * \return The number of bytes written into \a r_name.
- */
size_t BLI_string_flip_side_name(char *r_name,
const char *from_name,
const bool strip_number,
@@ -278,18 +246,6 @@ size_t BLI_string_flip_side_name(char *r_name,
/* Unique name utils. */
-/**
- * Ensures name is unique (according to criteria specified by caller in unique_check callback),
- * incrementing its numeric suffix as necessary. Returns true if name had to be adjusted.
- *
- * \param unique_check: Return true if name is not unique
- * \param arg: Additional arg to unique_check--meaning is up to caller
- * \param defname: To initialize name if latter is empty
- * \param delim: Delimits numeric suffix in name
- * \param name: Name to be ensured unique
- * \param name_len: Maximum length of name area
- * \return true if there if the name was changed
- */
bool BLI_uniquename_cb(UniquenameCheckCallback unique_check,
void *arg,
const char *defname,
@@ -366,17 +322,6 @@ static bool uniquename_unique_check(void *arg, const char *name)
return uniquename_find_dupe(data->lb, data->vlink, name, data->name_offset);
}
-/**
- * Ensures that the specified block has a unique name within the containing list,
- * incrementing its numeric suffix as necessary. Returns true if name had to be adjusted.
- *
- * \param list: List containing the block
- * \param vlink: The block to check the name for
- * \param defname: To initialize block name if latter is empty
- * \param delim: Delimits numeric suffix in name
- * \param name_offset: Offset of name within block structure
- * \param name_len: Maximum length of name area
- */
bool BLI_uniquename(
ListBase *list, void *vlink, const char *defname, char delim, int name_offset, size_t name_len)
{
@@ -432,9 +377,6 @@ char *BLI_string_join_array(char *result,
return c;
}
-/**
- * A version of #BLI_string_join that takes a separator which can be any character including '\0'.
- */
char *BLI_string_join_array_by_sep_char(
char *result, size_t result_len, char sep, const char *strings[], uint strings_len)
{
@@ -455,9 +397,6 @@ char *BLI_string_join_array_by_sep_char(
return c;
}
-/**
- * Join an array of strings into a newly allocated, null terminated string.
- */
char *BLI_string_join_arrayN(const char *strings[], uint strings_len)
{
uint total_len = 1;
@@ -474,9 +413,6 @@ char *BLI_string_join_arrayN(const char *strings[], uint strings_len)
return result;
}
-/**
- * A version of #BLI_string_joinN that takes a separator which can be any character including '\0'.
- */
char *BLI_string_join_array_by_sep_charN(char sep, const char *strings[], uint strings_len)
{
uint total_len = 0;
@@ -501,10 +437,6 @@ char *BLI_string_join_array_by_sep_charN(char sep, const char *strings[], uint s
return result;
}
-/**
- * A version of #BLI_string_join_array_by_sep_charN that takes a table array.
- * The new location of each string is written into this array.
- */
char *BLI_string_join_array_by_sep_char_with_tableN(char sep,
char *table[],
const char *strings[],
diff --git a/source/blender/blenlib/intern/system.c b/source/blender/blenlib/intern/system.c
index 66d0b44cfb3..e64d53467e4 100644
--- a/source/blender/blenlib/intern/system.c
+++ b/source/blender/blenlib/intern/system.c
@@ -73,9 +73,6 @@ int BLI_cpu_support_sse2(void)
/* Windows stack-walk lives in system_win32.c */
#if !defined(_MSC_VER)
-/**
- * Write a backtrace into a file for systems which support it.
- */
void BLI_system_backtrace(FILE *fp)
{
/* ------------- */
diff --git a/source/blender/blenlib/intern/system_win32.c b/source/blender/blenlib/intern/system_win32.c
index f65234b656b..b2360cf743f 100644
--- a/source/blender/blenlib/intern/system_win32.c
+++ b/source/blender/blenlib/intern/system_win32.c
@@ -373,6 +373,9 @@ static void bli_load_symbols()
}
}
+/**
+ * Write a backtrace into a file for systems which support it.
+ */
void BLI_system_backtrace(FILE *fp)
{
SymInitialize(GetCurrentProcess(), NULL, TRUE);
diff --git a/source/blender/blenlib/intern/task_iterator.c b/source/blender/blenlib/intern/task_iterator.c
index 6378d88e2b1..49666eb3082 100644
--- a/source/blender/blenlib/intern/task_iterator.c
+++ b/source/blender/blenlib/intern/task_iterator.c
@@ -274,21 +274,6 @@ static void task_parallel_iterator_do(const TaskParallelSettings *settings,
state->iter_shared.spin_lock = NULL;
}
-/**
- * This function allows to parallelize for loops using a generic iterator.
- *
- * \param userdata: Common userdata passed to all instances of \a func.
- * \param iter_func: Callback function used to generate chunks of items.
- * \param init_item: The initial item, if necessary (may be NULL if unused).
- * \param init_index: The initial index.
- * \param tot_items: The total amount of items to iterate over
- * (if unknown, set it to a negative number).
- * \param func: Callback function.
- * \param settings: See public API doc of TaskParallelSettings for description of all settings.
- *
- * \note Static scheduling is only available when \a tot_items is >= 0.
- */
-
void BLI_task_parallel_iterator(void *userdata,
TaskParallelIteratorIterFunc iter_func,
void *init_item,
@@ -332,17 +317,6 @@ static void task_parallel_listbase_get(void *__restrict UNUSED(userdata),
(*r_next_index)++;
}
-/**
- * This function allows to parallelize for loops over ListBase items.
- *
- * \param listbase: The double linked list to loop over.
- * \param userdata: Common userdata passed to all instances of \a func.
- * \param func: Callback function.
- * \param settings: See public API doc of ParallelRangeSettings for description of all settings.
- *
- * \note There is no static scheduling here,
- * since it would need another full loop over items to count them.
- */
void BLI_task_parallel_listbase(ListBase *listbase,
void *userdata,
TaskParallelIteratorFunc func,
@@ -388,16 +362,6 @@ static void parallel_mempool_func(TaskPool *__restrict pool, void *taskdata)
}
}
-/**
- * This function allows to parallelize for loops over Mempool items.
- *
- * \param mempool: The iterable BLI_mempool to loop over.
- * \param userdata: Common userdata passed to all instances of \a func.
- * \param func: Callback function.
- * \param settings: See public API doc of TaskParallelSettings for description of all settings.
- *
- * \note There is no static scheduling here.
- */
void BLI_task_parallel_mempool(BLI_mempool *mempool,
void *userdata,
TaskParallelMempoolFunc func,
diff --git a/source/blender/blenlib/intern/threads.cc b/source/blender/blenlib/intern/threads.cc
index 35097013439..3589c952409 100644
--- a/source/blender/blenlib/intern/threads.cc
+++ b/source/blender/blenlib/intern/threads.cc
@@ -140,7 +140,7 @@ struct ThreadSlot {
int avail;
};
-void BLI_threadapi_init(void)
+void BLI_threadapi_init()
{
mainid = pthread_self();
if (numaAPI_Initialize() == NUMAAPI_SUCCESS) {
@@ -148,14 +148,10 @@ void BLI_threadapi_init(void)
}
}
-void BLI_threadapi_exit(void)
+void BLI_threadapi_exit()
{
}
-/* tot = 0 only initializes malloc mutex in a safe way (see sequence.c)
- * problem otherwise: scene render will kill of the mutex!
- */
-
void BLI_threadpool_init(ListBase *threadbase, void *(*do_thread)(void *), int tot)
{
int a;
@@ -189,7 +185,6 @@ void BLI_threadpool_init(ListBase *threadbase, void *(*do_thread)(void *), int t
}
}
-/* amount of available threads */
int BLI_available_threads(ListBase *threadbase)
{
int counter = 0;
@@ -203,7 +198,6 @@ int BLI_available_threads(ListBase *threadbase)
return counter;
}
-/* returns thread number, for sample patterns or threadsafe tables */
int BLI_threadpool_available_thread_index(ListBase *threadbase)
{
int counter = 0;
@@ -231,7 +225,7 @@ static void *tslot_thread_start(void *tslot_p)
return tslot->do_thread(tslot->callerdata);
}
-int BLI_thread_is_main(void)
+int BLI_thread_is_main()
{
return pthread_equal(pthread_self(), mainid);
}
@@ -305,8 +299,7 @@ void BLI_threadpool_end(ListBase *threadbase)
/* System Information */
-/* how many threads are native on this system? */
-int BLI_system_thread_count(void)
+int BLI_system_thread_count()
{
static int t = -1;
@@ -347,7 +340,7 @@ void BLI_system_num_threads_override_set(int num)
num_threads_override = num;
}
-int BLI_system_num_threads_override_get(void)
+int BLI_system_num_threads_override_get()
{
return num_threads_override;
}
@@ -418,7 +411,7 @@ void BLI_mutex_end(ThreadMutex *mutex)
pthread_mutex_destroy(mutex);
}
-ThreadMutex *BLI_mutex_alloc(void)
+ThreadMutex *BLI_mutex_alloc()
{
ThreadMutex *mutex = static_cast<ThreadMutex *>(MEM_callocN(sizeof(ThreadMutex), "ThreadMutex"));
BLI_mutex_init(mutex);
@@ -533,7 +526,7 @@ void BLI_rw_mutex_end(ThreadRWMutex *mutex)
pthread_rwlock_destroy(mutex);
}
-ThreadRWMutex *BLI_rw_mutex_alloc(void)
+ThreadRWMutex *BLI_rw_mutex_alloc()
{
ThreadRWMutex *mutex = static_cast<ThreadRWMutex *>(
MEM_callocN(sizeof(ThreadRWMutex), "ThreadRWMutex"));
@@ -555,7 +548,7 @@ struct TicketMutex {
unsigned int queue_head, queue_tail;
};
-TicketMutex *BLI_ticket_mutex_alloc(void)
+TicketMutex *BLI_ticket_mutex_alloc()
{
TicketMutex *ticket = static_cast<TicketMutex *>(
MEM_callocN(sizeof(TicketMutex), "TicketMutex"));
@@ -640,7 +633,7 @@ struct ThreadQueue {
volatile int canceled;
};
-ThreadQueue *BLI_thread_queue_init(void)
+ThreadQueue *BLI_thread_queue_init()
{
ThreadQueue *queue;
@@ -818,8 +811,7 @@ void BLI_thread_queue_wait_finish(ThreadQueue *queue)
/* **** Special functions to help performance on crazy NUMA setups. **** */
#if 0 /* UNUSED */
-static bool check_is_threadripper2_alike_topology(void)
-{
+static bool check_is_threadripper2_alike_topology(){
/* NOTE: We hope operating system does not support CPU hot-swap to
* a different brand. And that SMP of different types is also not
* encouraged by the system. */
@@ -860,8 +852,7 @@ static bool check_is_threadripper2_alike_topology(void)
return is_threadripper2;
}
-static void threadripper_put_process_on_fast_node(void)
-{
+static void threadripper_put_process_on_fast_node(){
if (!is_numa_available) {
return;
}
@@ -880,8 +871,7 @@ static void threadripper_put_process_on_fast_node(void)
numaAPI_RunProcessOnNode(0);
}
-static void threadripper_put_thread_on_fast_node(void)
-{
+static void threadripper_put_thread_on_fast_node(){
if (!is_numa_available) {
return;
}
@@ -899,7 +889,7 @@ static void threadripper_put_thread_on_fast_node(void)
}
#endif /* UNUSED */
-void BLI_thread_put_process_on_fast_node(void)
+void BLI_thread_put_process_on_fast_node()
{
/* Disabled for now since this causes only 16 threads to be used on a
* thread-ripper for computations like sculpting and fluid sim. The problem
@@ -915,7 +905,7 @@ void BLI_thread_put_process_on_fast_node(void)
#endif
}
-void BLI_thread_put_thread_on_fast_node(void)
+void BLI_thread_put_thread_on_fast_node()
{
/* Disabled for now, see comment above. */
#if 0
diff --git a/source/blender/blenlib/intern/timecode.c b/source/blender/blenlib/intern/timecode.c
index 13f95ddf264..55131fa639d 100644
--- a/source/blender/blenlib/intern/timecode.c
+++ b/source/blender/blenlib/intern/timecode.c
@@ -35,19 +35,6 @@
#include "BLI_strict_flags.h"
-/**
- * Generate time-code/frame number string and store in \a str
- *
- * \param str: destination string
- * \param maxncpy: maximum number of characters to copy `sizeof(str)`
- * \param brevity_level: special setting for #View2D grid drawing,
- * used to specify how detailed we need to be
- * \param time_seconds: time total time in seconds
- * \param fps: frames per second, typically from the #FPS macro
- * \param timecode_style: enum from #eTimecodeStyles
- * \return length of \a str
- */
-
size_t BLI_timecode_string_from_time(char *str,
const size_t maxncpy,
const int brevity_level,
@@ -195,14 +182,6 @@ size_t BLI_timecode_string_from_time(char *str,
return rlen;
}
-/**
- * Generate time string and store in \a str
- *
- * \param str: destination string
- * \param maxncpy: maximum number of characters to copy `sizeof(str)`
- * \param time_seconds: time total time in seconds
- * \return length of \a str
- */
size_t BLI_timecode_string_from_time_simple(char *str,
const size_t maxncpy,
const double time_seconds)
@@ -225,18 +204,6 @@ size_t BLI_timecode_string_from_time_simple(char *str,
return rlen;
}
-/**
- * Generate time string and store in \a str
- *
- * \param str: destination string
- * \param maxncpy: maximum number of characters to copy `sizeof(str)`
- * \param brevity_level: special setting for #View2D grid drawing,
- * used to specify how detailed we need to be
- * \param time_seconds: time total time in seconds
- * \return length of \a str
- *
- * \note in some cases this is used to print non-seconds values.
- */
size_t BLI_timecode_string_from_time_seconds(char *str,
const size_t maxncpy,
const int brevity_level,
diff --git a/source/blender/blenlib/intern/uuid.cc b/source/blender/blenlib/intern/uuid.cc
index de4602bf3ed..e2578ffa7c7 100644
--- a/source/blender/blenlib/intern/uuid.cc
+++ b/source/blender/blenlib/intern/uuid.cc
@@ -81,7 +81,7 @@ bUUID BLI_uuid_generate_random()
return uuid;
}
-bUUID BLI_uuid_nil(void)
+bUUID BLI_uuid_nil()
{
const bUUID nil = {0, 0, 0, 0, 0, {0}};
return nil;
diff --git a/source/blender/blenlib/intern/uvproject.c b/source/blender/blenlib/intern/uvproject.c
index 093d08e643d..dbab0162eba 100644
--- a/source/blender/blenlib/intern/uvproject.c
+++ b/source/blender/blenlib/intern/uvproject.c
@@ -90,7 +90,6 @@ void BLI_uvproject_from_camera(float target[2], float source[3], ProjCameraInfo
target[1] += uci->shifty;
}
-/* could rv3d->persmat */
void BLI_uvproject_from_view(float target[2],
float source[3],
float persmat[4][4],
@@ -132,8 +131,6 @@ void BLI_uvproject_from_view(float target[2],
target[1] = (y + target[1]) / winy;
}
-/* 'rotmat' can be `obedit->obmat` when uv project is used.
- * 'winx' and 'winy' can be from `scene->r.xsch/ysch` */
ProjCameraInfo *BLI_uvproject_camera_info(Object *ob, float rotmat[4][4], float winx, float winy)
{
ProjCameraInfo uci;
diff --git a/source/blender/blenlib/intern/voxel.c b/source/blender/blenlib/intern/voxel.c
index c0c895654e3..a2b29ce1185 100644
--- a/source/blender/blenlib/intern/voxel.c
+++ b/source/blender/blenlib/intern/voxel.c
@@ -35,7 +35,7 @@ BLI_INLINE float D(const float *data, const int res[3], int x, int y, int z)
}
/* *** nearest neighbor *** */
-/* input coordinates must be in bounding box 0.0 - 1.0 */
+
float BLI_voxel_sample_nearest(const float *data, const int res[3], const float co[3])
{
int xi, yi, zi;
diff --git a/source/blender/blenlib/tests/BLI_color_test.cc b/source/blender/blenlib/tests/BLI_color_test.cc
index a91c743b133..5194d8048bf 100644
--- a/source/blender/blenlib/tests/BLI_color_test.cc
+++ b/source/blender/blenlib/tests/BLI_color_test.cc
@@ -6,8 +6,8 @@
namespace blender::tests {
-/**
- * \name Conversions
+/* -------------------------------------------------------------------- */
+/** \name Conversions
* \{ */
TEST(color, ThemeByteToFloat)
diff --git a/source/blender/blenlib/tests/BLI_virtual_array_test.cc b/source/blender/blenlib/tests/BLI_virtual_array_test.cc
index 7a548e7c434..62b7b383831 100644
--- a/source/blender/blenlib/tests/BLI_virtual_array_test.cc
+++ b/source/blender/blenlib/tests/BLI_virtual_array_test.cc
@@ -170,7 +170,7 @@ TEST(virtual_array, MutableToImmutable)
EXPECT_TRUE(varray.is_span());
EXPECT_EQ(varray.size(), 4);
EXPECT_EQ(varray[1], 2);
- EXPECT_EQ(mutable_varray.size(), 0);
+ EXPECT_EQ(mutable_varray.size(), 0); /* NOLINT: bugprone-use-after-move */
}
{
VArray<int> varray = VMutableArray<int>::ForSpan(array);
diff --git a/source/blender/blenloader/BLO_blend_validate.h b/source/blender/blenloader/BLO_blend_validate.h
index cdbf4bdd952..3a192284661 100644
--- a/source/blender/blenloader/BLO_blend_validate.h
+++ b/source/blender/blenloader/BLO_blend_validate.h
@@ -28,5 +28,12 @@
struct Main;
struct ReportList;
+/**
+ * Check (but do *not* fix) that all linked data-blocks are still valid
+ * (i.e. pointing to the right library).
+ */
bool BLO_main_validate_libraries(struct Main *bmain, struct ReportList *reports);
+/**
+ * * Check (and fix if needed) that shape key's 'from' pointer is valid.
+ */
bool BLO_main_validate_shapekeys(struct Main *bmain, struct ReportList *reports);
diff --git a/source/blender/blenloader/BLO_read_write.h b/source/blender/blenloader/BLO_read_write.h
index ca7ea6d8f09..fe8173e335a 100644
--- a/source/blender/blenloader/BLO_read_write.h
+++ b/source/blender/blenloader/BLO_read_write.h
@@ -58,8 +58,8 @@ struct BlendFileReadReport;
struct Main;
struct ReportList;
-/* Blend Write API
- * ===============
+/* -------------------------------------------------------------------- */
+/** \name Blend Write API
*
* Most functions fall into one of two categories. Either they write a DNA struct or a raw memory
* buffer to the .blend file.
@@ -91,19 +91,25 @@ struct ReportList;
* The code that reads this data might have to correct its byte-order. For the common cases
* there are convenience functions that write and read arrays of simple types such as `int32`.
* Those will correct endianness automatically.
- */
+ * \{ */
-/* Mapping between names and ids. */
+/**
+ * Mapping between names and ids.
+ */
int BLO_get_struct_id_by_name(BlendWriter *writer, const char *struct_name);
#define BLO_get_struct_id(writer, struct_name) SDNA_TYPE_FROM_STRUCT(struct_name)
-/* Write single struct. */
+/**
+ * Write single struct.
+ */
void BLO_write_struct_by_name(BlendWriter *writer, const char *struct_name, const void *data_ptr);
void BLO_write_struct_by_id(BlendWriter *writer, int struct_id, const void *data_ptr);
#define BLO_write_struct(writer, struct_name, data_ptr) \
BLO_write_struct_by_id(writer, BLO_get_struct_id(writer, struct_name), data_ptr)
-/* Write single struct at address. */
+/**
+ * Write single struct at address.
+ */
void BLO_write_struct_at_address_by_id(BlendWriter *writer,
int struct_id,
const void *address,
@@ -112,7 +118,9 @@ void BLO_write_struct_at_address_by_id(BlendWriter *writer,
BLO_write_struct_at_address_by_id( \
writer, BLO_get_struct_id(writer, struct_name), address, data_ptr)
-/* Write single struct at address and specify a filecode. */
+/**
+ * Write single struct at address and specify a file-code.
+ */
void BLO_write_struct_at_address_by_id_with_filecode(
BlendWriter *writer, int filecode, int struct_id, const void *address, const void *data_ptr);
#define BLO_write_struct_at_address_with_filecode( \
@@ -120,7 +128,9 @@ void BLO_write_struct_at_address_by_id_with_filecode(
BLO_write_struct_at_address_by_id_with_filecode( \
writer, filecode, BLO_get_struct_id(writer, struct_name), address, data_ptr)
-/* Write struct array. */
+/**
+ * Write struct array.
+ */
void BLO_write_struct_array_by_name(BlendWriter *writer,
const char *struct_name,
int array_size,
@@ -133,14 +143,18 @@ void BLO_write_struct_array_by_id(BlendWriter *writer,
BLO_write_struct_array_by_id( \
writer, BLO_get_struct_id(writer, struct_name), array_size, data_ptr)
-/* Write struct array at address. */
+/**
+ * Write struct array at address.
+ */
void BLO_write_struct_array_at_address_by_id(
BlendWriter *writer, int struct_id, int array_size, const void *address, const void *data_ptr);
#define BLO_write_struct_array_at_address(writer, struct_name, array_size, address, data_ptr) \
BLO_write_struct_array_at_address_by_id( \
writer, BLO_get_struct_id(writer, struct_name), array_size, address, data_ptr)
-/* Write struct list. */
+/**
+ * Write struct list.
+ */
void BLO_write_struct_list_by_name(BlendWriter *writer,
const char *struct_name,
struct ListBase *list);
@@ -148,7 +162,9 @@ void BLO_write_struct_list_by_id(BlendWriter *writer, int struct_id, struct List
#define BLO_write_struct_list(writer, struct_name, list_ptr) \
BLO_write_struct_list_by_id(writer, BLO_get_struct_id(writer, struct_name), list_ptr)
-/* Write id struct. */
+/**
+ * Write id struct.
+ */
void blo_write_id_struct(BlendWriter *writer,
int struct_id,
const void *id_address,
@@ -156,7 +172,9 @@ void blo_write_id_struct(BlendWriter *writer,
#define BLO_write_id_struct(writer, struct_name, id_address, id) \
blo_write_id_struct(writer, BLO_get_struct_id(writer, struct_name), id_address, id)
-/* Write raw data. */
+/**
+ * Write raw data.
+ */
void BLO_write_raw(BlendWriter *writer, size_t size_in_bytes, const void *data_ptr);
void BLO_write_int32_array(BlendWriter *writer, uint num, const int32_t *data_ptr);
void BLO_write_uint32_array(BlendWriter *writer, uint num, const uint32_t *data_ptr);
@@ -164,13 +182,23 @@ void BLO_write_float_array(BlendWriter *writer, uint num, const float *data_ptr)
void BLO_write_double_array(BlendWriter *writer, uint num, const double *data_ptr);
void BLO_write_float3_array(BlendWriter *writer, uint num, const float *data_ptr);
void BLO_write_pointer_array(BlendWriter *writer, uint num, const void *data_ptr);
+/**
+ * Write a null terminated string.
+ */
void BLO_write_string(BlendWriter *writer, const char *data_ptr);
/* Misc. */
+
+/**
+ * Sometimes different data is written depending on whether the file is saved to disk or used for
+ * undo. This function returns true when the current file-writing is done for undo.
+ */
bool BLO_write_is_undo(BlendWriter *writer);
-/* Blend Read Data API
- * ===================
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Blend Read Data API
*
* Generally, for every BLO_write_* call there should be a corresponding BLO_read_* call.
*
@@ -181,15 +209,18 @@ bool BLO_write_is_undo(BlendWriter *writer);
* updated to be NULL. When it was pointing to NULL before, it will stay that way.
*
* Examples of matching calls:
- * BLO_write_struct(writer, ClothSimSettings, clmd->sim_parms);
- * BLO_read_data_address(reader, &clmd->sim_parms);
*
- * BLO_write_struct_list(writer, TimeMarker, &action->markers);
- * BLO_read_list(reader, &action->markers);
+ * \code{.c}
+ * BLO_write_struct(writer, ClothSimSettings, clmd->sim_parms);
+ * BLO_read_data_address(reader, &clmd->sim_parms);
*
- * BLO_write_int32_array(writer, hmd->totindex, hmd->indexar);
- * BLO_read_int32_array(reader, hmd->totindex, &hmd->indexar);
- */
+ * BLO_write_struct_list(writer, TimeMarker, &action->markers);
+ * BLO_read_list(reader, &action->markers);
+ *
+ * BLO_write_int32_array(writer, hmd->totindex, hmd->indexar);
+ * BLO_read_int32_array(reader, hmd->totindex, &hmd->indexar);
+ * \endcode
+ * \{ */
void *BLO_read_get_new_data_address(BlendDataReader *reader, const void *old_address);
void *BLO_read_get_new_data_address_no_us(BlendDataReader *reader, const void *old_address);
@@ -201,10 +232,16 @@ void *BLO_read_get_new_packed_address(BlendDataReader *reader, const void *old_a
*((void **)ptr_p) = BLO_read_get_new_packed_address((reader), *(ptr_p))
typedef void (*BlendReadListFn)(BlendDataReader *reader, void *data);
+/**
+ * Updates all ->prev and ->next pointers of the list elements.
+ * Updates the list->first and list->last pointers.
+ * When not NULL, calls the callback on every element.
+ */
void BLO_read_list_cb(BlendDataReader *reader, struct ListBase *list, BlendReadListFn callback);
void BLO_read_list(BlendDataReader *reader, struct ListBase *list);
/* Update data pointers and correct byte-order if necessary. */
+
void BLO_read_int32_array(BlendDataReader *reader, int array_size, int32_t **ptr_p);
void BLO_read_uint32_array(BlendDataReader *reader, int array_size, uint32_t **ptr_p);
void BLO_read_float_array(BlendDataReader *reader, int array_size, float **ptr_p);
@@ -213,18 +250,21 @@ void BLO_read_double_array(BlendDataReader *reader, int array_size, double **ptr
void BLO_read_pointer_array(BlendDataReader *reader, void **ptr_p);
/* Misc. */
+
bool BLO_read_requires_endian_switch(BlendDataReader *reader);
bool BLO_read_data_is_undo(BlendDataReader *reader);
void BLO_read_data_globmap_add(BlendDataReader *reader, void *oldaddr, void *newaddr);
void BLO_read_glob_list(BlendDataReader *reader, struct ListBase *list);
struct BlendFileReadReport *BLO_read_data_reports(BlendDataReader *reader);
-/* Blend Read Lib API
- * ===================
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Blend Read Lib API
*
- * This API does almost the same as the Blend Read Data API. However, now only pointers to ID data
- * blocks are updated.
- */
+ * This API does almost the same as the Blend Read Data API.
+ * However, now only pointers to ID data blocks are updated.
+ * \{ */
ID *BLO_read_get_new_id_address(BlendLibReader *reader, struct Library *lib, struct ID *id);
@@ -232,30 +272,44 @@ ID *BLO_read_get_new_id_address(BlendLibReader *reader, struct Library *lib, str
*((void **)id_ptr_p) = (void *)BLO_read_get_new_id_address((reader), (lib), (ID *)*(id_ptr_p))
/* Misc. */
+
bool BLO_read_lib_is_undo(BlendLibReader *reader);
struct Main *BLO_read_lib_get_main(BlendLibReader *reader);
struct BlendFileReadReport *BLO_read_lib_reports(BlendLibReader *reader);
-/* Blend Expand API
- * ===================
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Blend Expand API
*
* BLO_expand has to be called for every data block that should be loaded. If the data block is in
- * a separate .blend file, it will be pulled from there.
- */
+ * a separate `.blend` file, it will be pulled from there.
+ * \{ */
void BLO_expand_id(BlendExpander *expander, struct ID *id);
#define BLO_expand(expander, id) BLO_expand_id(expander, (struct ID *)id)
-/* Report API
- * ===================
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Report API
+ * \{ */
+/**
+ * This function ensures that reports are printed,
+ * in the case of library linking errors this is important!
+ *
+ * bit kludge but better than doubling up on prints,
+ * we could alternatively have a versions of a report function which forces printing - campbell
+ */
void BLO_reportf_wrap(struct BlendFileReadReport *reports,
eReportType type,
const char *format,
...) ATTR_PRINTF_FORMAT(3, 4);
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h
index 22182edd070..567886e4d54 100644
--- a/source/blender/blenloader/BLO_readfile.h
+++ b/source/blender/blenloader/BLO_readfile.h
@@ -74,7 +74,7 @@ typedef struct BlendFileData {
int fileflags;
int globalf;
- char filename[1024]; /* 1024 = FILE_MAX */
+ char filepath[1024]; /* 1024 = FILE_MAX */
struct bScreen *curscreen; /* TODO: think this isn't needed anymore? */
struct Scene *curscene;
@@ -144,19 +144,50 @@ typedef enum eBLOReadSkip {
} eBLOReadSkip;
#define BLO_READ_SKIP_ALL (BLO_READ_SKIP_USERDEF | BLO_READ_SKIP_DATA)
+/**
+ * Open a blender file from a pathname. The function returns NULL
+ * and sets a report in the list if it cannot open the file.
+ *
+ * \param filepath: The path of the file to open.
+ * \param reports: If the return value is NULL, errors indicating the cause of the failure.
+ * \return The data of the file.
+ */
BlendFileData *BLO_read_from_file(const char *filepath,
eBLOReadSkip skip_flags,
struct BlendFileReadReport *reports);
+/**
+ * Open a blender file from memory. The function returns NULL
+ * and sets a report in the list if it cannot open the file.
+ *
+ * \param mem: The file data.
+ * \param memsize: The length of \a mem.
+ * \param reports: If the return value is NULL, errors indicating the cause of the failure.
+ * \return The data of the file.
+ */
BlendFileData *BLO_read_from_memory(const void *mem,
int memsize,
eBLOReadSkip skip_flags,
struct ReportList *reports);
+/**
+ * Used for undo/redo, skips part of libraries reading
+ * (assuming their data are already loaded & valid).
+ *
+ * \param oldmain: old main,
+ * from which we will keep libraries and other data-blocks that should not have changed.
+ * \param filename: current file, only for retrieving library data.
+ */
BlendFileData *BLO_read_from_memfile(struct Main *oldmain,
const char *filename,
struct MemFile *memfile,
const struct BlendFileReadParams *params,
struct ReportList *reports);
+/**
+ * Frees a BlendFileData structure and *all* the data associated with it
+ * (the userdef data, and the main libblock data).
+ *
+ * \param bfd: The structure to free.
+ */
void BLO_blendfiledata_free(BlendFileData *bfd);
/** \} */
@@ -170,24 +201,89 @@ typedef struct BLODataBlockInfo {
struct AssetMetaData *asset_data;
} BLODataBlockInfo;
+/**
+ * Open a blendhandle from a file path.
+ *
+ * \param filepath: The file path to open.
+ * \param reports: Report errors in opening the file (can be NULL).
+ * \return A handle on success, or NULL on failure.
+ */
BlendHandle *BLO_blendhandle_from_file(const char *filepath, struct BlendFileReadReport *reports);
+/**
+ * Open a blendhandle from memory.
+ *
+ * \param mem: The data to load from.
+ * \param memsize: The size of the data.
+ * \return A handle on success, or NULL on failure.
+ */
BlendHandle *BLO_blendhandle_from_memory(const void *mem,
int memsize,
struct BlendFileReadReport *reports);
+/**
+ * Gets the names of all the data-blocks in a file of a certain type
+ * (e.g. all the scene names in a file).
+ *
+ * \param bh: The blendhandle to access.
+ * \param ofblocktype: The type of names to get.
+ * \param use_assets_only: Only list IDs marked as assets.
+ * \param r_tot_names: The length of the returned list.
+ * \return A BLI_linklist of strings. The string links should be freed with #MEM_freeN().
+ */
struct LinkNode *BLO_blendhandle_get_datablock_names(BlendHandle *bh,
int ofblocktype,
const bool use_assets_only,
int *r_tot_names);
+/**
+ * Gets the names and asset-data (if ID is an asset) of data-blocks in a file of a certain type.
+ * The data-blocks can be limited to assets.
+ *
+ * \param bh: The blendhandle to access.
+ * \param ofblocktype: The type of names to get.
+ * \param use_assets_only: Limit the result to assets only.
+ * \param r_tot_info_items: The length of the returned list.
+ * \return A BLI_linklist of `BLODataBlockInfo *`.
+ * The links and #BLODataBlockInfo.asset_data should be freed with MEM_freeN.
+ */
struct LinkNode * /*BLODataBlockInfo */ BLO_blendhandle_get_datablock_info(
BlendHandle *bh, int ofblocktype, const bool use_assets_only, int *r_tot_info_items);
+/**
+ * Gets the previews of all the data-blocks in a file of a certain type
+ * (e.g. all the scene previews in a file).
+ *
+ * \param bh: The blendhandle to access.
+ * \param ofblocktype: The type of names to get.
+ * \param r_tot_prev: The length of the returned list.
+ * \return A BLI_linklist of #PreviewImage. The #PreviewImage links should be freed with malloc.
+ */
struct LinkNode *BLO_blendhandle_get_previews(BlendHandle *bh, int ofblocktype, int *r_tot_prev);
+/**
+ * Get the PreviewImage of a single data block in a file.
+ * (e.g. all the scene previews in a file).
+ *
+ * \param bh: The blendhandle to access.
+ * \param ofblocktype: The type of names to get.
+ * \param name: Name of the block without the ID_ prefix, to read the preview image from.
+ * \return PreviewImage or NULL when no preview Images have been found. Caller owns the returned
+ */
struct PreviewImage *BLO_blendhandle_get_preview_for_id(BlendHandle *bh,
int ofblocktype,
const char *name);
+/**
+ * Gets the names of all the linkable data-block types available in a file.
+ * (e.g. "Scene", "Mesh", "Light", etc.).
+ *
+ * \param bh: The blendhandle to access.
+ * \return A BLI_linklist of strings. The string links should be freed with #MEM_freeN().
+ */
struct LinkNode *BLO_blendhandle_get_linkable_groups(BlendHandle *bh);
+/**
+ * Close and free a blendhandle. The handle becomes invalid after this call.
+ *
+ * \param bh: The handle to close.
+ */
void BLO_blendhandle_close(BlendHandle *bh);
/** \} */
@@ -195,7 +291,25 @@ void BLO_blendhandle_close(BlendHandle *bh);
#define BLO_GROUP_MAX 32
#define BLO_EMBEDDED_STARTUP_BLEND "<startup.blend>"
+/**
+ * Check whether given path ends with a blend file compatible extension
+ * (`.blend`, `.ble` or `.blend.gz`).
+ *
+ * \param str: The path to check.
+ * \return true is this path ends with a blender file extension.
+ */
bool BLO_has_bfile_extension(const char *str);
+/**
+ * Try to explode given path into its 'library components'
+ * (i.e. a .blend file, id type/group, and data-block itself).
+ *
+ * \param path: the full path to explode.
+ * \param r_dir: the string that'll contain path up to blend file itself ('library' path).
+ * WARNING! Must be #FILE_MAX_LIBEXTRA long (it also stores group and name strings)!
+ * \param r_group: the string that'll contain 'group' part of the path, if any. May be NULL.
+ * \param r_name: the string that'll contain data's name part of the path, if any. May be NULL.
+ * \return true if path contains a blend file.
+ */
bool BLO_library_path_explode(const char *path, char *r_dir, char **r_group, char **r_name);
/* -------------------------------------------------------------------- */
@@ -212,14 +326,6 @@ typedef enum eBLOLibLinkFlags {
BLO_LIBLINK_USE_PLACEHOLDERS = 1 << 16,
/** Force loaded ID to be tagged as #LIB_TAG_INDIRECT (used in reload context only). */
BLO_LIBLINK_FORCE_INDIRECT = 1 << 17,
- /**
- * When set, tag ID types that pass the internal check #library_link_idcode_needs_tag_check
- *
- * Currently this is only used to instantiate objects in the scene.
- * Set this from #BLO_library_link_params_init_with_context so callers
- * don't need to remember to set this flag.
- */
- BLO_LIBLINK_NEEDS_ID_TAG_DOIT = 1 << 18,
/** Set fake user on appended IDs. */
BLO_LIBLINK_APPEND_SET_FAKEUSER = 1 << 19,
/** Append (make local) also indirect dependencies of appended IDs coming from other libraries.
@@ -241,7 +347,7 @@ typedef enum eBLOLibLinkFlags {
* #BLO_library_link_begin, #BLO_library_link_named_part & #BLO_library_link_end.
* Wrap these in parameters since it's important both functions receive matching values.
*/
-struct LibraryLink_Params {
+typedef struct LibraryLink_Params {
/** The current main database, e.g. #G_MAIN or `CTX_data_main(C)`. */
struct Main *bmain;
/** Options for linking, used for instantiating. */
@@ -257,7 +363,7 @@ struct LibraryLink_Params {
/** The active 3D viewport (only used to define local-view). */
const struct View3D *v3d;
} context;
-};
+} LibraryLink_Params;
void BLO_library_link_params_init(struct LibraryLink_Params *params,
struct Main *bmain,
@@ -271,20 +377,45 @@ void BLO_library_link_params_init_with_context(struct LibraryLink_Params *params
struct ViewLayer *view_layer,
const struct View3D *v3d);
+/**
+ * Initialize the #BlendHandle for linking library data.
+ *
+ * \param bh: A blender file handle as returned by
+ * #BLO_blendhandle_from_file or #BLO_blendhandle_from_memory.
+ * \param filepath: Used for relative linking, copied to the `lib->filepath`.
+ * \param params: Settings for linking that don't change from beginning to end of linking.
+ * \return the library #Main, to be passed to #BLO_library_link_named_part as \a mainl.
+ */
struct Main *BLO_library_link_begin(BlendHandle **bh,
const char *filepath,
const struct LibraryLink_Params *params);
+/**
+ * Link a named data-block from an external blend file.
+ *
+ * \param mainl: The main database to link from (not the active one).
+ * \param bh: The blender file handle.
+ * \param idcode: The kind of data-block to link.
+ * \param name: The name of the data-block (without the 2 char ID prefix).
+ * \return the linked ID when found.
+ */
struct ID *BLO_library_link_named_part(struct Main *mainl,
BlendHandle **bh,
const short idcode,
const char *name,
const struct LibraryLink_Params *params);
+/**
+ * Finalize linking from a given .blend file (library).
+ * Optionally instance the indirect object/collection in the scene when the flags are set.
+ * \note Do not use \a bh after calling this function, it may frees it.
+ *
+ * \param mainl: The main database to link from (not the active one).
+ * \param bh: The blender file handle (WARNING! may be freed by this function!).
+ * \param params: Settings for linking that don't change from beginning to end of linking.
+ */
void BLO_library_link_end(struct Main *mainl,
BlendHandle **bh,
const struct LibraryLink_Params *params);
-int BLO_library_link_copypaste(struct Main *mainl, BlendHandle *bh, const uint64_t id_types_mask);
-
/**
* Struct for temporarily loading datablocks from a blend file.
*/
@@ -314,6 +445,10 @@ void BLO_library_temp_free(TempLibraryContext *temp_lib_ctx);
void *BLO_library_read_struct(struct FileData *fd, struct BHead *bh, const char *blockname);
/* internal function but we need to expose it */
+/**
+ * Used to link a file (without UI) to the current UI.
+ * Note that it assumes the old pointers in UI are still valid, so old Main is not freed.
+ */
void blo_lib_link_restore(struct Main *oldmain,
struct Main *newmain,
struct wmWindowManager *curwm,
@@ -322,29 +457,50 @@ void blo_lib_link_restore(struct Main *oldmain,
typedef void (*BLOExpandDoitCallback)(void *fdhandle, struct Main *mainvar, void *idv);
+/**
+ * Set the callback func used over all ID data found by \a BLO_expand_main func.
+ *
+ * \param expand_doit_func: Called for each ID block it finds.
+ */
void BLO_main_expander(BLOExpandDoitCallback expand_doit_func);
+/**
+ * Loop over all ID data in Main to mark relations.
+ * Set (id->tag & LIB_TAG_NEED_EXPAND) to mark expanding. Flags get cleared after expanding.
+ *
+ * \param fdhandle: usually filedata, or own handle.
+ * \param mainvar: the Main database to expand.
+ */
void BLO_expand_main(void *fdhandle, struct Main *mainvar);
/**
* Update defaults in startup.blend, without having to save and embed it.
* \note defaults for preferences are stored in `userdef_default.c` and can be updated there.
*/
+/**
+ * Update defaults in startup.blend, without having to save and embed the file.
+ * This function can be emptied each time the startup.blend is updated.
+ *
+ * \note Screen data may be cleared at this point, this will happen in the case
+ * an app-template's data needs to be versioned when read-file is called with "Load UI" disabled.
+ * Versioning the screen data can be safely skipped without "Load UI" since the screen data
+ * will have been versioned when it was first loaded.
+ */
void BLO_update_defaults_startup_blend(struct Main *bmain, const char *app_template);
void BLO_update_defaults_workspace(struct WorkSpace *workspace, const char *app_template);
/* Disable unwanted experimental feature settings on startup. */
void BLO_sanitize_experimental_features_userpref_blend(struct UserDef *userdef);
+/**
+ * Does a very light reading of given .blend file to extract its stored thumbnail.
+ *
+ * \param filepath: The path of the file to extract thumbnail from.
+ * \return The raw thumbnail
+ * (MEM-allocated, as stored in file, use #BKE_main_thumbnail_to_imbuf()
+ * to convert it to ImBuf image).
+ */
struct BlendThumbnail *BLO_thumbnail_from_file(const char *filepath);
-void BLO_object_instantiate_object_base_instance_init(struct Main *bmain,
- struct Collection *collection,
- struct Object *ob,
- struct ViewLayer *view_layer,
- const struct View3D *v3d,
- const int flag,
- bool set_active);
-
/* datafiles (generated theme) */
extern const struct bTheme U_theme_default;
extern const struct UserDef U_default;
diff --git a/source/blender/blenloader/BLO_undofile.h b/source/blender/blenloader/BLO_undofile.h
index 4e240e2462b..0e2c22d7e4d 100644
--- a/source/blender/blenloader/BLO_undofile.h
+++ b/source/blender/blenloader/BLO_undofile.h
@@ -77,7 +77,7 @@ typedef struct {
bool memchunk_identical;
} UndoReader;
-/* actually only used writefile.c */
+/* Actually only used `writefile.c`. */
void BLO_memfile_write_init(MemFileWriteData *mem_data,
MemFile *written_memfile,
@@ -87,14 +87,31 @@ void BLO_memfile_write_finalize(MemFileWriteData *mem_data);
void BLO_memfile_chunk_add(MemFileWriteData *mem_data, const char *buf, size_t size);
/* exports */
+
+/**
+ * Not memfile itself.
+ */
extern void BLO_memfile_free(MemFile *memfile);
+/**
+ * Result is that 'first' is being freed.
+ * to keep list of memfiles consistent, 'first' is always first in list.
+ */
extern void BLO_memfile_merge(MemFile *first, MemFile *second);
+/**
+ * Clear is_identical_future before adding next memfile.
+ */
extern void BLO_memfile_clear_future(MemFile *memfile);
-/* utilities */
+/* Utilities. */
+
extern struct Main *BLO_memfile_main_get(struct MemFile *memfile,
struct Main *bmain,
struct Scene **r_scene);
+/**
+ * Saves .blend using undo buffer.
+ *
+ * \return success.
+ */
extern bool BLO_memfile_write_file(struct MemFile *memfile, const char *filename);
FileReader *BLO_memfile_new_filereader(MemFile *memfile, int undo_direction);
diff --git a/source/blender/blenloader/BLO_writefile.h b/source/blender/blenloader/BLO_writefile.h
index 746c663926d..9bc3714ff38 100644
--- a/source/blender/blenloader/BLO_writefile.h
+++ b/source/blender/blenloader/BLO_writefile.h
@@ -21,9 +21,13 @@
/** \file
* \ingroup blenloader
- * \brief external writefile function prototypes.
+ * \brief external `writefile.c` function prototypes.
*/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct BlendThumbnail;
struct Main;
struct MemFile;
@@ -60,15 +64,25 @@ struct BlendFileWriteParams {
const struct BlendThumbnail *thumb;
};
+/**
+ * \return Success.
+ */
extern bool BLO_write_file(struct Main *mainvar,
const char *filepath,
const int write_flags,
const struct BlendFileWriteParams *params,
struct ReportList *reports);
+/**
+ * \return Success.
+ */
extern bool BLO_write_file_mem(struct Main *mainvar,
struct MemFile *compare,
struct MemFile *current,
int write_flags);
/** \} */
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/blenloader/CMakeLists.txt b/source/blender/blenloader/CMakeLists.txt
index b3df5c8aa67..05f74bfa834 100644
--- a/source/blender/blenloader/CMakeLists.txt
+++ b/source/blender/blenloader/CMakeLists.txt
@@ -34,7 +34,6 @@ set(INC
../sequencer
../windowmanager
../../../intern/clog
- ../../../intern/ghost
../../../intern/guardedalloc
# for writefile.c: dna_type_offsets.h
@@ -114,6 +113,7 @@ if(WITH_GTESTS)
tests/blendfile_loading_base_test.h
)
set(TEST_INC
+ ../../../intern/ghost
)
set(TEST_LIB
bf_blenloader
diff --git a/source/blender/blenloader/intern/blend_validate.c b/source/blender/blenloader/intern/blend_validate.c
index 7d641d976e3..333f6e341c6 100644
--- a/source/blender/blenloader/intern/blend_validate.c
+++ b/source/blender/blenloader/intern/blend_validate.c
@@ -47,10 +47,6 @@
#include "readfile.h"
-/**
- * Check (but do *not* fix) that all linked data-blocks are still valid
- * (i.e. pointing to the right library).
- */
bool BLO_main_validate_libraries(Main *bmain, ReportList *reports)
{
ListBase mainlist;
@@ -165,7 +161,6 @@ bool BLO_main_validate_libraries(Main *bmain, ReportList *reports)
return is_valid;
}
-/** Check (and fix if needed) that shape key's 'from' pointer is valid. */
bool BLO_main_validate_shapekeys(Main *bmain, ReportList *reports)
{
ListBase *lb;
diff --git a/source/blender/blenloader/intern/readblenentry.c b/source/blender/blenloader/intern/readblenentry.c
index c0fdfa86907..f3c92aec338 100644
--- a/source/blender/blenloader/intern/readblenentry.c
+++ b/source/blender/blenloader/intern/readblenentry.c
@@ -61,13 +61,6 @@ void BLO_blendhandle_print_sizes(BlendHandle *bh, void *fp);
/* Access routines used by filesel. */
-/**
- * Open a blendhandle from a file path.
- *
- * \param filepath: The file path to open.
- * \param reports: Report errors in opening the file (can be NULL).
- * \return A handle on success, or NULL on failure.
- */
BlendHandle *BLO_blendhandle_from_file(const char *filepath, BlendFileReadReport *reports)
{
BlendHandle *bh;
@@ -77,13 +70,6 @@ BlendHandle *BLO_blendhandle_from_file(const char *filepath, BlendFileReadReport
return bh;
}
-/**
- * Open a blendhandle from memory.
- *
- * \param mem: The data to load from.
- * \param memsize: The size of the data.
- * \return A handle on success, or NULL on failure.
- */
BlendHandle *BLO_blendhandle_from_memory(const void *mem,
int memsize,
BlendFileReadReport *reports)
@@ -130,16 +116,6 @@ void BLO_blendhandle_print_sizes(BlendHandle *bh, void *fp)
fprintf(fp, "]\n");
}
-/**
- * Gets the names of all the data-blocks in a file of a certain type
- * (e.g. all the scene names in a file).
- *
- * \param bh: The blendhandle to access.
- * \param ofblocktype: The type of names to get.
- * \param tot_names: The length of the returned list.
- * \param use_assets_only: Only list IDs marked as assets.
- * \return A BLI_linklist of strings. The string links should be freed with #MEM_freeN().
- */
LinkNode *BLO_blendhandle_get_datablock_names(BlendHandle *bh,
int ofblocktype,
const bool use_assets_only,
@@ -169,17 +145,6 @@ LinkNode *BLO_blendhandle_get_datablock_names(BlendHandle *bh,
return names;
}
-/**
- * Gets the names and asset-data (if ID is an asset) of data-blocks in a file of a certain type.
- * The data-blocks can be limited to assets.
- *
- * \param bh: The blendhandle to access.
- * \param ofblocktype: The type of names to get.
- * \param use_assets_only: Limit the result to assets only.
- * \param tot_info_items: The length of the returned list.
- * \return A BLI_linklist of BLODataBlockInfo *. The links and #BLODataBlockInfo.asset_data should
- * be freed with MEM_freeN.
- */
LinkNode *BLO_blendhandle_get_datablock_info(BlendHandle *bh,
int ofblocktype,
const bool use_assets_only,
@@ -267,15 +232,6 @@ static BHead *blo_blendhandle_read_preview_rects(FileData *fd,
return bhead;
}
-/**
- * Get the PreviewImage of a single data block in a file.
- * (e.g. all the scene previews in a file).
- *
- * \param bh: The blendhandle to access.
- * \param ofblocktype: The type of names to get.
- * \param name: Name of the block without the ID_ prefix, to read the preview image from.
- * \return PreviewImage or NULL when no preview Images have been found. Caller owns the returned
- */
PreviewImage *BLO_blendhandle_get_preview_for_id(BlendHandle *bh,
int ofblocktype,
const char *name)
@@ -315,15 +271,6 @@ PreviewImage *BLO_blendhandle_get_preview_for_id(BlendHandle *bh,
return NULL;
}
-/**
- * Gets the previews of all the data-blocks in a file of a certain type
- * (e.g. all the scene previews in a file).
- *
- * \param bh: The blendhandle to access.
- * \param ofblocktype: The type of names to get.
- * \param r_tot_prev: The length of the returned list.
- * \return A BLI_linklist of PreviewImage. The PreviewImage links should be freed with malloc.
- */
LinkNode *BLO_blendhandle_get_previews(BlendHandle *bh, int ofblocktype, int *r_tot_prev)
{
FileData *fd = (FileData *)bh;
@@ -384,13 +331,6 @@ LinkNode *BLO_blendhandle_get_previews(BlendHandle *bh, int ofblocktype, int *r_
return previews;
}
-/**
- * Gets the names of all the linkable data-block types available in a file.
- * (e.g. "Scene", "Mesh", "Light", etc.).
- *
- * \param bh: The blendhandle to access.
- * \return A BLI_linklist of strings. The string links should be freed with #MEM_freeN().
- */
LinkNode *BLO_blendhandle_get_linkable_groups(BlendHandle *bh)
{
FileData *fd = (FileData *)bh;
@@ -418,11 +358,6 @@ LinkNode *BLO_blendhandle_get_linkable_groups(BlendHandle *bh)
return names;
}
-/**
- * Close and free a blendhandle. The handle becomes invalid after this call.
- *
- * \param bh: The handle to close.
- */
void BLO_blendhandle_close(BlendHandle *bh)
{
FileData *fd = (FileData *)bh;
@@ -432,14 +367,6 @@ void BLO_blendhandle_close(BlendHandle *bh)
/**********/
-/**
- * Open a blender file from a pathname. The function returns NULL
- * and sets a report in the list if it cannot open the file.
- *
- * \param filepath: The path of the file to open.
- * \param reports: If the return value is NULL, errors indicating the cause of the failure.
- * \return The data of the file.
- */
BlendFileData *BLO_read_from_file(const char *filepath,
eBLOReadSkip skip_flags,
BlendFileReadReport *reports)
@@ -457,15 +384,6 @@ BlendFileData *BLO_read_from_file(const char *filepath,
return bfd;
}
-/**
- * Open a blender file from memory. The function returns NULL
- * and sets a report in the list if it cannot open the file.
- *
- * \param mem: The file data.
- * \param memsize: The length of \a mem.
- * \param reports: If the return value is NULL, errors indicating the cause of the failure.
- * \return The data of the file.
- */
BlendFileData *BLO_read_from_memory(const void *mem,
int memsize,
eBLOReadSkip skip_flags,
@@ -485,14 +403,6 @@ BlendFileData *BLO_read_from_memory(const void *mem,
return bfd;
}
-/**
- * Used for undo/redo, skips part of libraries reading
- * (assuming their data are already loaded & valid).
- *
- * \param oldmain: old main,
- * from which we will keep libraries and other data-blocks that should not have changed.
- * \param filename: current file, only for retrieving library data.
- */
BlendFileData *BLO_read_from_memfile(Main *oldmain,
const char *filename,
MemFile *memfile,
@@ -548,12 +458,6 @@ BlendFileData *BLO_read_from_memfile(Main *oldmain,
return bfd;
}
-/**
- * Frees a BlendFileData structure and *all* the data associated with it
- * (the userdef data, and the main libblock data).
- *
- * \param bfd: The structure to free.
- */
void BLO_blendfiledata_free(BlendFileData *bfd)
{
if (bfd->main) {
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index e4fe3e8da00..56047bb7f4f 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -195,7 +195,6 @@ static void read_libraries(FileData *basefd, ListBase *mainlist);
static void *read_struct(FileData *fd, BHead *bh, const char *blockname);
static BHead *find_bhead_from_code_name(FileData *fd, const short idcode, const char *name);
static BHead *find_bhead_from_idname(FileData *fd, const char *idname);
-static bool library_link_idcode_needs_tag_check(const short idcode, const int flag);
typedef struct BHeadN {
struct BHeadN *next, *prev;
@@ -215,13 +214,6 @@ typedef struct BHeadN {
* because ID names are used in lookup tables. */
#define BHEAD_USE_READ_ON_DEMAND(bhead) ((bhead)->code == DATA)
-/**
- * This function ensures that reports are printed,
- * in the case of library linking errors this is important!
- *
- * bit kludge but better than doubling up on prints,
- * we could alternatively have a versions of a report function which forces printing - campbell
- */
void BLO_reportf_wrap(BlendFileReadReport *reports, eReportType type, const char *format, ...)
{
char fixed_buf[1024]; /* should be long enough */
@@ -639,7 +631,7 @@ static Main *blo_find_main(FileData *fd, const char *filepath, const char *relab
// printf("blo_find_main: converted to %s\n", name1);
for (m = mainlist->first; m; m = m->next) {
- const char *libname = (m->curlib) ? m->curlib->filepath_abs : m->name;
+ const char *libname = (m->curlib) ? m->curlib->filepath_abs : m->filepath;
if (BLI_path_cmp(name1, libname) == 0) {
if (G.debug & G_DEBUG) {
@@ -998,13 +990,11 @@ static BHead *blo_bhead_read_full(FileData *fd, BHead *thisblock)
}
#endif /* USE_BHEAD_READ_ON_DEMAND */
-/* Warning! Caller's responsibility to ensure given bhead **is** an ID one! */
const char *blo_bhead_id_name(const FileData *fd, const BHead *bhead)
{
return (const char *)POINTER_OFFSET(bhead, sizeof(*bhead) + fd->id_name_offset);
}
-/* Warning! Caller's responsibility to ensure given bhead **is** an ID one! */
AssetMetaData *blo_bhead_id_asset_data_address(const FileData *fd, const BHead *bhead)
{
BLI_assert(blo_bhead_is_id_valid_type(bhead));
@@ -1149,6 +1139,10 @@ static int *read_file_thumbnail(FileData *fd)
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name File Data API
+ * \{ */
+
static FileData *filedata_new(BlendFileReadReport *reports)
{
BLI_assert(reports != NULL);
@@ -1270,8 +1264,6 @@ static FileData *blo_filedata_from_file_open(const char *filepath, BlendFileRead
return blo_filedata_from_file_descriptor(filepath, reports, file);
}
-/* cannot be called with relative paths anymore! */
-/* on each new library added, it now checks for the current FileData and expands relativeness */
FileData *blo_filedata_from_file(const char *filepath, BlendFileReadReport *reports)
{
FileData *fd = blo_filedata_from_file_open(filepath, reports);
@@ -1412,30 +1404,12 @@ void blo_filedata_free(FileData *fd)
/** \name Public Utilities
* \{ */
-/**
- * Check whether given path ends with a blend file compatible extension
- * (`.blend`, `.ble` or `.blend.gz`).
- *
- * \param str: The path to check.
- * \return true is this path ends with a blender file extension.
- */
bool BLO_has_bfile_extension(const char *str)
{
const char *ext_test[4] = {".blend", ".ble", ".blend.gz", NULL};
return BLI_path_extension_check_array(str, ext_test);
}
-/**
- * Try to explode given path into its 'library components'
- * (i.e. a .blend file, id type/group, and data-block itself).
- *
- * \param path: the full path to explode.
- * \param r_dir: the string that'll contain path up to blend file itself ('library' path).
- * WARNING! Must be #FILE_MAX_LIBEXTRA long (it also stores group and name strings)!
- * \param r_group: the string that'll contain 'group' part of the path, if any. May be NULL.
- * \param r_name: the string that'll contain data's name part of the path, if any. May be NULL.
- * \return true if path contains a blend file.
- */
bool BLO_library_path_explode(const char *path, char *r_dir, char **r_group, char **r_name)
{
/* We might get some data names with slashes,
@@ -1496,14 +1470,6 @@ bool BLO_library_path_explode(const char *path, char *r_dir, char **r_group, cha
return true;
}
-/**
- * Does a very light reading of given .blend file to extract its stored thumbnail.
- *
- * \param filepath: The path of the file to extract thumbnail from.
- * \return The raw thumbnail
- * (MEM-allocated, as stored in file, use #BKE_main_thumbnail_to_imbuf()
- * to convert it to ImBuf image).
- */
BlendThumbnail *BLO_thumbnail_from_file(const char *filepath)
{
FileData *fd;
@@ -1552,7 +1518,6 @@ static void *newdataadr_no_us(FileData *fd, const void *adr)
return oldnewmap_lookup_and_inc(fd->datamap, adr, false);
}
-/* Direct datablocks with global linking. */
void *blo_read_get_new_globaldata_address(FileData *fd, const void *adr)
{
return oldnewmap_lookup_and_inc(fd->globmap, adr, true);
@@ -1574,7 +1539,6 @@ static void *newlibadr(FileData *fd, const void *lib, const void *adr)
return oldnewmap_liblookup(fd->libmap, adr, lib);
}
-/* only lib data */
void *blo_do_versions_newlibadr(FileData *fd, const void *lib, const void *adr)
{
return newlibadr(fd, lib, adr);
@@ -1616,12 +1580,6 @@ static void change_link_placeholder_to_real_ID_pointer(ListBase *mainlist,
}
}
-/* lib linked proxy objects point to our local data, we need
- * to clear that pointer before reading the undo memfile since
- * the object might be removed, it is set again in reading
- * if the local object still exists.
- * This is only valid for local proxy objects though, linked ones should not be affected here.
- */
void blo_clear_proxy_pointers_from_lib(Main *oldmain)
{
LISTBASE_FOREACH (Object *, ob, &oldmain->objects) {
@@ -1681,8 +1639,6 @@ void blo_make_packed_pointer_map(FileData *fd, Main *oldmain)
}
}
-/* set old main packed data to zero if it has been restored */
-/* this works because freeing old main only happens after this call */
void blo_end_packed_pointer_map(FileData *fd, Main *oldmain)
{
OldNew *entry = fd->packedmap->entries;
@@ -1719,7 +1675,6 @@ void blo_end_packed_pointer_map(FileData *fd, Main *oldmain)
}
}
-/* undo file support: add all library pointers in lookup */
void blo_add_library_pointer_map(ListBase *old_mainlist, FileData *fd)
{
ListBase *lbarray[INDEX_ID_MAX];
@@ -1736,8 +1691,6 @@ void blo_add_library_pointer_map(ListBase *old_mainlist, FileData *fd)
fd->old_mainlist = old_mainlist;
}
-/* Build a GSet of old main (we only care about local data here, so we can do that after
- * split_main() call. */
void blo_make_old_idmap_from_main(FileData *fd, Main *bmain)
{
if (fd->old_idmap != NULL) {
@@ -2771,10 +2724,6 @@ static void lib_link_workspace_layout_restore(struct IDNameLib_Map *id_map,
}
}
-/**
- * Used to link a file (without UI) to the current UI.
- * Note that it assumes the old pointers in UI are still valid, so old Main is not freed.
- */
void blo_lib_link_restore(Main *oldmain,
Main *newmain,
wmWindowManager *curwm,
@@ -2903,7 +2852,7 @@ static void lib_link_library(BlendLibReader *UNUSED(reader), Library *UNUSED(lib
* in relation to the blend file. */
static void fix_relpaths_library(const char *basepath, Main *main)
{
- /* BLO_read_from_memory uses a blank filename */
+ /* #BLO_read_from_memory uses a blank file-path. */
if (basepath == NULL || basepath[0] == '\0') {
LISTBASE_FOREACH (Library *, lib, &main->libraries) {
/* when loading a linked lib into a file which has not been saved,
@@ -3557,25 +3506,25 @@ static BHead *read_global(BlendFileData *bfd, FileData *fd, BHead *bhead)
bfd->fileflags = fg->fileflags;
bfd->globalf = fg->globalf;
- BLI_strncpy(bfd->filename, fg->filename, sizeof(bfd->filename));
+ STRNCPY(bfd->filepath, fg->filepath);
- /* Error in 2.65 and older: main->name was not set if you save from startup
+ /* Error in 2.65 and older: `main->filepath` was not set if you save from startup
* (not after loading file). */
- if (bfd->filename[0] == 0) {
+ if (bfd->filepath[0] == 0) {
if (fd->fileversion < 265 || (fd->fileversion == 265 && fg->subversion < 1)) {
if ((G.fileflags & G_FILE_RECOVER_READ) == 0) {
- BLI_strncpy(bfd->filename, BKE_main_blendfile_path(bfd->main), sizeof(bfd->filename));
+ STRNCPY(bfd->filepath, BKE_main_blendfile_path(bfd->main));
}
}
- /* early 2.50 version patch - filename not in FileGlobal struct at all */
+ /* early 2.50 version patch - filepath not in FileGlobal struct at all */
if (fd->fileversion <= 250) {
- BLI_strncpy(bfd->filename, BKE_main_blendfile_path(bfd->main), sizeof(bfd->filename));
+ STRNCPY(bfd->filepath, BKE_main_blendfile_path(bfd->main));
}
}
if (G.fileflags & G_FILE_RECOVER_READ) {
- BLI_strncpy(fd->relabase, fg->filename, sizeof(fd->relabase));
+ BLI_strncpy(fd->relabase, fg->filepath, sizeof(fd->relabase));
}
bfd->curscreen = fg->curscreen;
@@ -3671,7 +3620,7 @@ static void do_versions_after_linking(Main *main, ReportList *reports)
CLOG_INFO(&LOG,
2,
"Processing %s (%s), %d.%d",
- main->curlib ? main->curlib->filepath : main->name,
+ main->curlib ? main->curlib->filepath : main->filepath,
main->curlib ? "LIB" : "MAIN",
main->versionfile,
main->subversionfile);
@@ -3909,7 +3858,7 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
if ((fd->skip_flags & BLO_READ_SKIP_DATA) == 0) {
BLI_addtail(&mainlist, bfd->main);
fd->mainlist = &mainlist;
- BLI_strncpy(bfd->main->name, filepath, sizeof(bfd->main->name));
+ STRNCPY(bfd->main->filepath, filepath);
}
if (G.background) {
@@ -4384,23 +4333,11 @@ static void expand_id(BlendExpander *expander, ID *id)
expand_id_embedded_id(expander, id);
}
-/**
- * Set the callback func used over all ID data found by \a BLO_expand_main func.
- *
- * \param expand_doit_func: Called for each ID block it finds.
- */
void BLO_main_expander(BLOExpandDoitCallback expand_doit_func)
{
expand_doit = expand_doit_func;
}
-/**
- * Loop over all ID data in Main to mark relations.
- * Set (id->tag & LIB_TAG_NEED_EXPAND) to mark expanding. Flags get cleared after expanding.
- *
- * \param fdhandle: usually filedata, or own handle.
- * \param mainvar: the Main database to expand.
- */
void BLO_expand_main(void *fdhandle, Main *mainvar)
{
ListBase *lbarray[INDEX_ID_MAX];
@@ -4441,290 +4378,6 @@ void BLO_expand_main(void *fdhandle, Main *mainvar)
/** \name Library Linking (helper functions)
* \{ */
-static bool object_in_any_scene(Main *bmain, Object *ob)
-{
- LISTBASE_FOREACH (Scene *, sce, &bmain->scenes) {
- if (BKE_scene_object_find(sce, ob)) {
- return true;
- }
- }
-
- return false;
-}
-
-static bool object_in_any_collection(Main *bmain, Object *ob)
-{
- LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
- if (BKE_collection_has_object(collection, ob)) {
- return true;
- }
- }
-
- LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
- if (scene->master_collection != NULL &&
- BKE_collection_has_object(scene->master_collection, ob)) {
- return true;
- }
- }
-
- return false;
-}
-
-/**
- * Shared operations to perform on the object's base after adding it to the scene.
- */
-static void object_base_instance_init(
- Object *ob, ViewLayer *view_layer, const View3D *v3d, const int flag, bool set_active)
-{
- Base *base = BKE_view_layer_base_find(view_layer, ob);
-
- if (v3d != NULL) {
- base->local_view_bits |= v3d->local_view_uuid;
- }
-
- if (flag & FILE_AUTOSELECT) {
- /* All objects that use #FILE_AUTOSELECT must be selectable (unless linking data). */
- BLI_assert((base->flag & BASE_SELECTABLE) || (flag & FILE_LINK));
- if (base->flag & BASE_SELECTABLE) {
- base->flag |= BASE_SELECTED;
- }
- }
-
- if (set_active) {
- view_layer->basact = base;
- }
-
- BKE_scene_object_base_flag_sync_from_base(base);
-}
-
-/**
- * Exported for link/append to create objects as well.
- */
-void BLO_object_instantiate_object_base_instance_init(Main *bmain,
- Collection *collection,
- Object *ob,
- ViewLayer *view_layer,
- const View3D *v3d,
- const int flag,
- bool set_active)
-{
- /* Auto-select and appending. */
- if ((flag & FILE_AUTOSELECT) && ((flag & FILE_LINK) == 0)) {
- /* While in general the object should not be manipulated,
- * when the user requests the object to be selected, ensure it's visible and selectable. */
- ob->visibility_flag &= ~(OB_HIDE_VIEWPORT | OB_HIDE_SELECT);
- }
-
- BKE_collection_object_add(bmain, collection, ob);
-
- object_base_instance_init(ob, view_layer, v3d, flag, set_active);
-}
-
-static void add_loose_objects_to_scene(Main *mainvar,
- Main *bmain,
- Scene *scene,
- ViewLayer *view_layer,
- const View3D *v3d,
- Library *lib,
- const int flag)
-{
- Collection *active_collection = NULL;
- const bool do_append = (flag & FILE_LINK) == 0;
-
- BLI_assert(scene);
-
- /* Give all objects which are LIB_TAG_INDIRECT a base,
- * or for a collection when *lib has been set. */
- LISTBASE_FOREACH (Object *, ob, &mainvar->objects) {
- /* NOTE: Even if this is a directly linked object and is tagged for instantiation, it might
- * have already been instantiated through one of its owner collections, in which case we do not
- * want to re-instantiate it in the active collection here. */
- bool do_it = (ob->id.tag & LIB_TAG_DOIT) != 0 && !BKE_scene_object_find(scene, ob);
- if (do_it ||
- ((ob->id.tag & LIB_TAG_INDIRECT) != 0 && (ob->id.tag & LIB_TAG_PRE_EXISTING) == 0)) {
- if (do_append) {
- if (ob->id.us == 0) {
- do_it = true;
- }
- else if ((ob->id.lib == lib) && !object_in_any_collection(bmain, ob)) {
- /* When appending, make sure any indirectly loaded object gets a base,
- * when they are not part of any collection yet. */
- do_it = true;
- }
- }
-
- if (do_it) {
- /* Find or add collection as needed. */
- if (active_collection == NULL) {
- if (flag & FILE_ACTIVE_COLLECTION) {
- LayerCollection *lc = BKE_layer_collection_get_active(view_layer);
- active_collection = lc->collection;
- }
- else {
- active_collection = BKE_collection_add(bmain, scene->master_collection, NULL);
- }
- }
-
- CLAMP_MIN(ob->id.us, 0);
- ob->mode = OB_MODE_OBJECT;
-
- /* Do NOT make base active here! screws up GUI stuff,
- * if you want it do it at the editor level. */
- const bool set_active = false;
- BLO_object_instantiate_object_base_instance_init(
- bmain, active_collection, ob, view_layer, v3d, flag, set_active);
-
- ob->id.tag &= ~LIB_TAG_INDIRECT;
- ob->id.flag &= ~LIB_INDIRECT_WEAK_LINK;
- ob->id.tag |= LIB_TAG_EXTERN;
- }
- }
- }
-}
-
-static void add_loose_object_data_to_scene(Main *mainvar,
- Main *bmain,
- Scene *scene,
- ViewLayer *view_layer,
- const View3D *v3d,
- const int flag)
-{
- if ((flag & BLO_LIBLINK_OBDATA_INSTANCE) == 0) {
- return;
- }
-
- Collection *active_collection = scene->master_collection;
- if (flag & FILE_ACTIVE_COLLECTION) {
- LayerCollection *lc = BKE_layer_collection_get_active(view_layer);
- active_collection = lc->collection;
- }
-
- /* Do not re-instantiate obdata IDs that are already instantiated by an object. */
- LISTBASE_FOREACH (Object *, ob, &mainvar->objects) {
- if ((ob->id.tag & LIB_TAG_PRE_EXISTING) == 0 && ob->data != NULL) {
- ID *obdata = ob->data;
- BLI_assert(ID_REAL_USERS(obdata) > 0);
- if ((obdata->tag & LIB_TAG_PRE_EXISTING) == 0) {
- obdata->tag &= ~LIB_TAG_DOIT;
- }
- }
- }
-
- /* Loop over all ID types, instancing object-data for ID types that have support for it. */
- ListBase *lbarray[INDEX_ID_MAX];
- int i = set_listbasepointers(mainvar, lbarray);
- while (i--) {
- const short idcode = BKE_idtype_idcode_from_index(i);
- if (!OB_DATA_SUPPORT_ID(idcode)) {
- continue;
- }
-
- LISTBASE_FOREACH (ID *, id, lbarray[i]) {
- if (id->tag & LIB_TAG_DOIT) {
- const int type = BKE_object_obdata_to_type(id);
- BLI_assert(type != -1);
- Object *ob = BKE_object_add_only_object(bmain, type, id->name + 2);
- ob->data = id;
- id_us_plus(id);
- BKE_object_materials_test(bmain, ob, ob->data);
-
- /* Do NOT make base active here! screws up GUI stuff,
- * if you want it do it at the editor level. */
- bool set_active = false;
- BLO_object_instantiate_object_base_instance_init(
- bmain, active_collection, ob, view_layer, v3d, flag, set_active);
-
- copy_v3_v3(ob->loc, scene->cursor.location);
- }
- }
- }
-}
-
-static void add_collections_to_scene(Main *mainvar,
- Main *bmain,
- Scene *scene,
- ViewLayer *view_layer,
- const View3D *v3d,
- Library *lib,
- const int flag)
-{
- Collection *active_collection = scene->master_collection;
- if (flag & FILE_ACTIVE_COLLECTION) {
- LayerCollection *lc = BKE_layer_collection_get_active(view_layer);
- active_collection = lc->collection;
- }
-
- /* Give all objects which are tagged a base. */
- LISTBASE_FOREACH (Collection *, collection, &mainvar->collections) {
- if ((flag & BLO_LIBLINK_COLLECTION_INSTANCE) && (collection->id.tag & LIB_TAG_DOIT)) {
- /* Any indirect collection should not have been tagged. */
- BLI_assert((collection->id.tag & LIB_TAG_INDIRECT) == 0);
-
- /* BKE_object_add(...) messes with the selection. */
- Object *ob = BKE_object_add_only_object(bmain, OB_EMPTY, collection->id.name + 2);
- ob->type = OB_EMPTY;
- ob->empty_drawsize = U.collection_instance_empty_size;
-
- const bool set_selected = (flag & FILE_AUTOSELECT) != 0;
- /* TODO: why is it OK to make this active here but not in other situations?
- * See other callers of #object_base_instance_init */
- const bool set_active = set_selected;
- BLO_object_instantiate_object_base_instance_init(
- bmain, active_collection, ob, view_layer, v3d, flag, set_active);
-
- DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION);
-
- /* Assign the collection. */
- ob->instance_collection = collection;
- id_us_plus(&collection->id);
- ob->transflag |= OB_DUPLICOLLECTION;
- copy_v3_v3(ob->loc, scene->cursor.location);
- }
- /* We do not want to force instantiation of indirectly linked collections,
- * not even when appending. Users can now easily instantiate collections (and their objects)
- * as needed by themselves. See T67032. */
- else if ((collection->id.tag & LIB_TAG_INDIRECT) == 0) {
- bool do_add_collection = (collection->id.tag & LIB_TAG_DOIT) != 0;
- if (!do_add_collection) {
- /* We need to check that objects in that collections are already instantiated in a scene.
- * Otherwise, it's better to add the collection to the scene's active collection, than to
- * instantiate its objects in active scene's collection directly. See T61141.
- * Note that we only check object directly into that collection,
- * not recursively into its children.
- */
- LISTBASE_FOREACH (CollectionObject *, coll_ob, &collection->gobject) {
- Object *ob = coll_ob->ob;
- if ((ob->id.tag & (LIB_TAG_PRE_EXISTING | LIB_TAG_DOIT | LIB_TAG_INDIRECT)) == 0 &&
- (ob->id.lib == lib) && (object_in_any_scene(bmain, ob) == false)) {
- do_add_collection = true;
- break;
- }
- }
- }
- if (do_add_collection) {
- /* Add collection as child of active collection. */
- BKE_collection_child_add(bmain, active_collection, collection);
-
- if (flag & FILE_AUTOSELECT) {
- LISTBASE_FOREACH (CollectionObject *, coll_ob, &collection->gobject) {
- Object *ob = coll_ob->ob;
- Base *base = BKE_view_layer_base_find(view_layer, ob);
- if (base) {
- base->flag |= BASE_SELECTED;
- BKE_scene_object_base_flag_sync_from_base(base);
- }
- }
- }
-
- /* Those are kept for safety and consistency, but should not be needed anymore? */
- collection->id.tag &= ~LIB_TAG_INDIRECT;
- collection->id.flag &= ~LIB_INDIRECT_WEAK_LINK;
- collection->id.tag |= LIB_TAG_EXTERN;
- }
- }
- }
-}
-
/* returns true if the item was found
* but it may already have already been appended/linked */
static ID *link_named_part(
@@ -4774,75 +4427,9 @@ static ID *link_named_part(
/* if we found the id but the id is NULL, this is really bad */
BLI_assert(!((bhead != NULL) && (id == NULL)));
- /* Tag as loose object (or data associated with objects)
- * needing to be instantiated in #LibraryLink_Params.scene. */
- if ((id != NULL) && (flag & BLO_LIBLINK_NEEDS_ID_TAG_DOIT)) {
- if (library_link_idcode_needs_tag_check(idcode, flag)) {
- id->tag |= LIB_TAG_DOIT;
- }
- }
-
return id;
}
-/**
- * Simple reader for copy/paste buffers.
- */
-int BLO_library_link_copypaste(Main *mainl, BlendHandle *bh, const uint64_t id_types_mask)
-{
- FileData *fd = (FileData *)(bh);
- BHead *bhead;
- int num_directly_linked = 0;
-
- for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
- ID *id = NULL;
-
- if (bhead->code == ENDB) {
- break;
- }
-
- if (blo_bhead_is_id_valid_type(bhead) && BKE_idtype_idcode_is_linkable((short)bhead->code) &&
- (id_types_mask == 0 ||
- (BKE_idtype_idcode_to_idfilter((short)bhead->code) & id_types_mask) != 0)) {
- read_libblock(fd, mainl, bhead, LIB_TAG_NEED_EXPAND | LIB_TAG_EXTERN, false, &id);
- num_directly_linked++;
- }
-
- if (id) {
- /* sort by name in list */
- ListBase *lb = which_libbase(mainl, GS(id->name));
- id_sort_by_name(lb, id, NULL);
-
- /* Tag as loose object (or data associated with objects)
- * needing to be instantiated (see also #link_named_part and its usage of
- * #BLO_LIBLINK_NEEDS_ID_TAG_DOIT above). */
- if (library_link_idcode_needs_tag_check(GS(id->name), BLO_LIBLINK_NEEDS_ID_TAG_DOIT)) {
- id->tag |= LIB_TAG_DOIT;
- }
-
- if (bhead->code == ID_OB) {
- /* Instead of instancing Base's directly, postpone until after collections are loaded
- * otherwise the base's flag is set incorrectly when collections are used */
- Object *ob = (Object *)id;
- ob->mode = OB_MODE_OBJECT;
- /* ensure add_loose_objects_to_scene runs on this object */
- BLI_assert(id->us == 0);
- }
- }
- }
-
- return num_directly_linked;
-}
-
-/**
- * Link a named data-block from an external blend file.
- *
- * \param mainl: The main database to link from (not the active one).
- * \param bh: The blender file handle.
- * \param idcode: The kind of data-block to link.
- * \param name: The name of the data-block (without the 2 char ID prefix).
- * \return the linked ID when found.
- */
ID *BLO_library_link_named_part(Main *mainl,
BlendHandle **bh,
const short idcode,
@@ -4855,41 +4442,10 @@ ID *BLO_library_link_named_part(Main *mainl,
/* common routine to append/link something from a library */
-/**
- * Checks if the \a idcode needs to be tagged with #LIB_TAG_DOIT when linking/appending.
- */
-static bool library_link_idcode_needs_tag_check(const short idcode, const int flag)
-{
- if (flag & BLO_LIBLINK_NEEDS_ID_TAG_DOIT) {
- /* Always true because of #add_loose_objects_to_scene & #add_collections_to_scene. */
- if (ELEM(idcode, ID_OB, ID_GR)) {
- return true;
- }
- if (flag & BLO_LIBLINK_OBDATA_INSTANCE) {
- if (OB_DATA_SUPPORT_ID(idcode)) {
- return true;
- }
- }
- }
- return false;
-}
-
-/**
- * Clears #LIB_TAG_DOIT based on the result of #library_link_idcode_needs_tag_check.
- */
-static void library_link_clear_tag(Main *mainvar, const int flag)
-{
- for (int i = 0; i < INDEX_ID_MAX; i++) {
- const short idcode = BKE_idtype_idcode_from_index(i);
- BLI_assert(idcode != -1);
- if (library_link_idcode_needs_tag_check(idcode, flag)) {
- BKE_main_id_tag_idcode(mainvar, idcode, LIB_TAG_DOIT, false);
- }
- }
-}
-
-static Main *library_link_begin(
- Main *mainvar, FileData **fd, const char *filepath, const int flag, const int id_tag_extra)
+static Main *library_link_begin(Main *mainvar,
+ FileData **fd,
+ const char *filepath,
+ const int id_tag_extra)
{
Main *mainl;
@@ -4902,11 +4458,6 @@ static Main *library_link_begin(
(*fd)->mainlist = MEM_callocN(sizeof(ListBase), "FileData.mainlist");
- if (flag & BLO_LIBLINK_NEEDS_ID_TAG_DOIT) {
- /* Clear for objects and collections instantiating tag. */
- library_link_clear_tag(mainvar, flag);
- }
-
/* make mains */
blo_split_main((*fd)->mainlist, mainvar);
@@ -4945,30 +4496,18 @@ void BLO_library_link_params_init_with_context(struct LibraryLink_Params *params
{
BLO_library_link_params_init(params, bmain, flag, id_tag_extra);
if (scene != NULL) {
- /* Tagging is needed for instancing. */
- params->flag |= BLO_LIBLINK_NEEDS_ID_TAG_DOIT;
-
params->context.scene = scene;
params->context.view_layer = view_layer;
params->context.v3d = v3d;
}
}
-/**
- * Initialize the #BlendHandle for linking library data.
- *
- * \param bh: A blender file handle as returned by
- * #BLO_blendhandle_from_file or #BLO_blendhandle_from_memory.
- * \param filepath: Used for relative linking, copied to the `lib->filepath`.
- * \param params: Settings for linking that don't change from beginning to end of linking.
- * \return the library #Main, to be passed to #BLO_library_link_named_part as \a mainl.
- */
Main *BLO_library_link_begin(BlendHandle **bh,
const char *filepath,
const struct LibraryLink_Params *params)
{
FileData *fd = (FileData *)(*bh);
- return library_link_begin(params->bmain, &fd, filepath, params->flag, params->id_tag_extra);
+ return library_link_begin(params->bmain, &fd, filepath, params->id_tag_extra);
}
static void split_main_newid(Main *mainptr, Main *main_newid)
@@ -4976,7 +4515,7 @@ static void split_main_newid(Main *mainptr, Main *main_newid)
/* We only copy the necessary subset of data in this temp main. */
main_newid->versionfile = mainptr->versionfile;
main_newid->subversionfile = mainptr->subversionfile;
- BLI_strncpy(main_newid->name, mainptr->name, sizeof(main_newid->name));
+ STRNCPY(main_newid->filepath, mainptr->filepath);
main_newid->curlib = mainptr->curlib;
ListBase *lbarray[INDEX_ID_MAX];
@@ -4995,19 +4534,7 @@ static void split_main_newid(Main *mainptr, Main *main_newid)
}
}
-/**
- * \param scene: The scene in which to instantiate objects/collections
- * (if NULL, no instantiation is done).
- * \param v3d: The active 3D viewport.
- * (only to define active layers for instantiated objects & collections, can be NULL).
- */
-static void library_link_end(Main *mainl,
- FileData **fd,
- Main *bmain,
- const int flag,
- Scene *scene,
- ViewLayer *view_layer,
- const View3D *v3d)
+static void library_link_end(Main *mainl, FileData **fd, const int flag)
{
Main *mainvar;
Library *curlib;
@@ -5092,22 +4619,6 @@ static void library_link_end(Main *mainl,
/* Make all relative paths, relative to the open blend file. */
fix_relpaths_library(BKE_main_blendfile_path(mainvar), mainvar);
- /* Give a base to loose objects and collections.
- * Only directly linked objects & collections are instantiated by
- * #BLO_library_link_named_part & co,
- * here we handle indirect ones and other possible edge-cases. */
- if (flag & BLO_LIBLINK_NEEDS_ID_TAG_DOIT) {
- /* Should always be true. */
- if (scene != NULL) {
- add_collections_to_scene(mainvar, bmain, scene, view_layer, v3d, curlib, flag);
- add_loose_objects_to_scene(mainvar, bmain, scene, view_layer, v3d, curlib, flag);
- add_loose_object_data_to_scene(mainvar, bmain, scene, view_layer, v3d, flag);
- }
-
- /* Clear objects and collections instantiating tag. */
- library_link_clear_tag(mainvar, flag);
- }
-
/* patch to prevent switch_endian happens twice */
if ((*fd)->flags & FD_FLAGS_SWITCH_ENDIAN) {
blo_filedata_free(*fd);
@@ -5115,25 +4626,10 @@ static void library_link_end(Main *mainl,
}
}
-/**
- * Finalize linking from a given .blend file (library).
- * Optionally instance the indirect object/collection in the scene when the flags are set.
- * \note Do not use \a bh after calling this function, it may frees it.
- *
- * \param mainl: The main database to link from (not the active one).
- * \param bh: The blender file handle (WARNING! may be freed by this function!).
- * \param params: Settings for linking that don't change from beginning to end of linking.
- */
void BLO_library_link_end(Main *mainl, BlendHandle **bh, const struct LibraryLink_Params *params)
{
FileData *fd = (FileData *)(*bh);
- library_link_end(mainl,
- &fd,
- params->bmain,
- params->flag,
- params->context.scene,
- params->context.view_layer,
- params->context.v3d);
+ library_link_end(mainl, &fd, params->flag);
*bh = (BlendHandle *)fd;
}
@@ -5485,11 +4981,6 @@ bool BLO_read_requires_endian_switch(BlendDataReader *reader)
return (reader->fd->flags & FD_FLAGS_SWITCH_ENDIAN) != 0;
}
-/**
- * Updates all ->prev and ->next pointers of the list elements.
- * Updates the list->first and list->last pointers.
- * When not NULL, calls the callback on every element.
- */
void BLO_read_list_cb(BlendDataReader *reader, ListBase *list, BlendReadListFn callback)
{
if (BLI_listbase_is_empty(list)) {
diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h
index 75152a05063..3b5be3dd013 100644
--- a/source/blender/blenloader/intern/readfile.h
+++ b/source/blender/blenloader/intern/readfile.h
@@ -131,6 +131,11 @@ void blo_split_main(ListBase *mainlist, struct Main *main);
BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath);
+/**
+ * On each new library added, it now checks for the current #FileData and expands relativeness
+ *
+ * cannot be called with relative paths anymore!
+ */
FileData *blo_filedata_from_file(const char *filepath, struct BlendFileReadReport *reports);
FileData *blo_filedata_from_memory(const void *mem,
int memsize,
@@ -139,10 +144,28 @@ FileData *blo_filedata_from_memfile(struct MemFile *memfile,
const struct BlendFileReadParams *params,
struct BlendFileReadReport *reports);
+/**
+ * Lib linked proxy objects point to our local data, we need
+ * to clear that pointer before reading the undo memfile since
+ * the object might be removed, it is set again in reading
+ * if the local object still exists.
+ * This is only valid for local proxy objects though, linked ones should not be affected here.
+ */
void blo_clear_proxy_pointers_from_lib(struct Main *oldmain);
void blo_make_packed_pointer_map(FileData *fd, struct Main *oldmain);
+/**
+ * Set old main packed data to zero if it has been restored
+ * this works because freeing old main only happens after this call.
+ */
void blo_end_packed_pointer_map(FileData *fd, struct Main *oldmain);
+/**
+ * Undo file support: add all library pointers in lookup.
+ */
void blo_add_library_pointer_map(ListBase *old_mainlist, FileData *fd);
+/**
+ * Build a #GSet of old main (we only care about local data here,
+ * so we can do that after #blo_split_main() call.
+ */
void blo_make_old_idmap_from_main(FileData *fd, struct Main *bmain);
BHead *blo_read_asset_data_block(FileData *fd, BHead *bhead, struct AssetMetaData **r_asset_data);
@@ -157,23 +180,48 @@ BHead *blo_bhead_first(FileData *fd);
BHead *blo_bhead_next(FileData *fd, BHead *thisblock);
BHead *blo_bhead_prev(FileData *fd, BHead *thisblock);
+/**
+ * Warning! Caller's responsibility to ensure given bhead **is** an ID one!
+ */
const char *blo_bhead_id_name(const FileData *fd, const BHead *bhead);
+/**
+ * Warning! Caller's responsibility to ensure given bhead **is** an ID one!
+ */
struct AssetMetaData *blo_bhead_id_asset_data_address(const FileData *fd, const BHead *bhead);
/* do versions stuff */
+/**
+ * Manipulates SDNA before calling #DNA_struct_get_compareflags,
+ * allowing us to rename structs and struct members.
+ *
+ * - This means older versions of Blender won't have access to this data **USE WITH CARE**.
+ * - These changes are applied on file load (run-time), similar to versioning for compatibility.
+ *
+ * \attention ONLY USE THIS KIND OF VERSIONING WHEN `dna_rename_defs.h` ISN'T SUFFICIENT.
+ */
void blo_do_versions_dna(struct SDNA *sdna, const int versionfile, const int subversionfile);
void blo_do_versions_oldnewmap_insert(struct OldNewMap *onm,
const void *oldaddr,
void *newaddr,
int nr);
+/**
+ * Only library data.
+ */
void *blo_do_versions_newlibadr(struct FileData *fd, const void *lib, const void *adr);
void *blo_do_versions_newlibadr_us(struct FileData *fd, const void *lib, const void *adr);
+/**
+ * \note this version patch is intended for versions < 2.52.2,
+ * but was initially introduced in 2.27 already.
+ */
void blo_do_version_old_trackto_to_constraints(struct Object *ob);
void blo_do_versions_key_uidgen(struct Key *key);
+/**
+ * Patching #UserDef struct and Themes.
+ */
void blo_do_versions_userdef(struct UserDef *userdef);
void blo_do_versions_pre250(struct FileData *fd, struct Library *lib, struct Main *bmain);
@@ -193,6 +241,10 @@ void do_versions_after_linking_290(struct Main *bmain, struct ReportList *report
void do_versions_after_linking_300(struct Main *bmain, struct ReportList *reports);
void do_versions_after_linking_cycles(struct Main *bmain);
-/* This is rather unfortunate to have to expose this here, but better use that nasty hack in
- * do_version than readfile itself. */
+/**
+ * Direct data-blocks with global linking.
+ *
+ * \note This is rather unfortunate to have to expose this here,
+ * but better use that nasty hack in do_version than readfile itself.
+ */
void *blo_read_get_new_globaldata_address(struct FileData *fd, const void *adr);
diff --git a/source/blender/blenloader/intern/readfile_tempload.c b/source/blender/blenloader/intern/readfile_tempload.c
index 1b1cbb29ef5..311732adf99 100644
--- a/source/blender/blenloader/intern/readfile_tempload.c
+++ b/source/blender/blenloader/intern/readfile_tempload.c
@@ -39,7 +39,7 @@ TempLibraryContext *BLO_library_temp_load_id(struct Main *real_main,
temp_lib_ctx->bf_reports.reports = reports;
/* Copy the file path so any path remapping is performed properly. */
- STRNCPY(temp_lib_ctx->bmain_base->name, real_main->name);
+ STRNCPY(temp_lib_ctx->bmain_base->filepath, real_main->filepath);
temp_lib_ctx->blendhandle = BLO_blendhandle_from_file(blend_file_path,
&temp_lib_ctx->bf_reports);
diff --git a/source/blender/blenloader/intern/undofile.c b/source/blender/blenloader/intern/undofile.c
index 62072cf7df5..dfa6135dac9 100644
--- a/source/blender/blenloader/intern/undofile.c
+++ b/source/blender/blenloader/intern/undofile.c
@@ -55,7 +55,6 @@
/* **************** support for memory-write, for undo buffers *************** */
-/* not memfile itself */
void BLO_memfile_free(MemFile *memfile)
{
MemFileChunk *chunk;
@@ -69,8 +68,6 @@ void BLO_memfile_free(MemFile *memfile)
memfile->size = 0;
}
-/* to keep list of memfiles consistent, 'first' is always first in list */
-/* result is that 'first' is being freed */
void BLO_memfile_merge(MemFile *first, MemFile *second)
{
/* We use this mapping to store the memory buffers from second memfile chunks which are not owned
@@ -106,7 +103,6 @@ void BLO_memfile_merge(MemFile *first, MemFile *second)
BLO_memfile_free(first);
}
-/* Clear is_identical_future before adding next memfile. */
void BLO_memfile_clear_future(MemFile *memfile)
{
LISTBASE_FOREACH (MemFileChunk *, chunk, &memfile->chunks) {
@@ -216,11 +212,6 @@ struct Main *BLO_memfile_main_get(struct MemFile *memfile,
return bmain_undo;
}
-/**
- * Saves .blend using undo buffer.
- *
- * \return success.
- */
bool BLO_memfile_write_file(struct MemFile *memfile, const char *filename)
{
MemFileChunk *chunk;
diff --git a/source/blender/blenloader/intern/versioning_260.c b/source/blender/blenloader/intern/versioning_260.c
index c4d04392cba..8a22fd07c24 100644
--- a/source/blender/blenloader/intern/versioning_260.c
+++ b/source/blender/blenloader/intern/versioning_260.c
@@ -1892,7 +1892,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
for (cu = bmain->curves.first; cu; cu = cu->id.next) {
if (cu->flag & (CU_FRONT | CU_BACK)) {
- if (cu->ext1 != 0.0f || cu->ext2 != 0.0f) {
+ if (cu->extrude != 0.0f || cu->bevel_radius != 0.0f) {
Nurb *nu;
for (nu = cu->nurb.first; nu; nu = nu->next) {
diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c
index 125f3be0dd1..7a7f12a7e58 100644
--- a/source/blender/blenloader/intern/versioning_300.c
+++ b/source/blender/blenloader/intern/versioning_300.c
@@ -1321,13 +1321,16 @@ static void version_liboverride_rnacollections_insertion_object_constraints(
opop->subitem_local_name,
offsetof(bConstraint, name),
opop->subitem_local_index);
- if (constraint_anchor == NULL || constraint_anchor->next == NULL) {
+ bConstraint *constraint_src = constraint_anchor != NULL ? constraint_anchor->next :
+ constraints->first;
+
+ if (constraint_src == NULL) {
/* Invalid case, just remove that override property operation. */
- CLOG_ERROR(&LOG, "Could not find anchor or source constraints in stored override data");
+ CLOG_ERROR(&LOG, "Could not find source constraint in stored override data");
BKE_lib_override_library_property_operation_delete(op, opop);
continue;
}
- bConstraint *constraint_src = constraint_anchor->next;
+
opop->subitem_reference_name = opop->subitem_local_name;
opop->subitem_local_name = BLI_strdup(constraint_src->name);
opop->subitem_reference_index = opop->subitem_local_index;
@@ -1350,13 +1353,15 @@ static void version_liboverride_rnacollections_insertion_object(Object *object)
opop->subitem_local_name,
offsetof(ModifierData, name),
opop->subitem_local_index);
- if (mod_anchor == NULL || mod_anchor->next == NULL) {
+ ModifierData *mod_src = mod_anchor != NULL ? mod_anchor->next : object->modifiers.first;
+
+ if (mod_src == NULL) {
/* Invalid case, just remove that override property operation. */
- CLOG_ERROR(&LOG, "Could not find anchor or source modifiers in stored override data");
+ CLOG_ERROR(&LOG, "Could not find source modifier in stored override data");
BKE_lib_override_library_property_operation_delete(op, opop);
continue;
}
- ModifierData *mod_src = mod_anchor->next;
+
opop->subitem_reference_name = opop->subitem_local_name;
opop->subitem_local_name = BLI_strdup(mod_src->name);
opop->subitem_reference_index = opop->subitem_local_index;
@@ -1375,13 +1380,17 @@ static void version_liboverride_rnacollections_insertion_object(Object *object)
opop->subitem_local_name,
offsetof(GpencilModifierData, name),
opop->subitem_local_index);
- if (gp_mod_anchor == NULL || gp_mod_anchor->next == NULL) {
+ GpencilModifierData *gp_mod_src = gp_mod_anchor != NULL ?
+ gp_mod_anchor->next :
+ object->greasepencil_modifiers.first;
+
+ if (gp_mod_src == NULL) {
/* Invalid case, just remove that override property operation. */
- CLOG_ERROR(&LOG, "Could not find anchor GP modifier in stored override data");
+ CLOG_ERROR(&LOG, "Could not find source GP modifier in stored override data");
BKE_lib_override_library_property_operation_delete(op, opop);
continue;
}
- GpencilModifierData *gp_mod_src = gp_mod_anchor->next;
+
opop->subitem_reference_name = opop->subitem_local_name;
opop->subitem_local_name = BLI_strdup(gp_mod_src->name);
opop->subitem_reference_index = opop->subitem_local_index;
@@ -2182,7 +2191,7 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (ntree->type != NTREE_GEOMETRY) {
continue;
}
- version_node_id(ntree, FN_NODE_COMPARE_FLOATS, "FunctionNodeCompareFloats");
+ version_node_id(ntree, FN_NODE_COMPARE, "FunctionNodeCompareFloats");
version_node_id(ntree, GEO_NODE_CAPTURE_ATTRIBUTE, "GeometryNodeCaptureAttribute");
version_node_id(ntree, GEO_NODE_MESH_BOOLEAN, "GeometryNodeMeshBoolean");
version_node_id(ntree, GEO_NODE_FILL_CURVE, "GeometryNodeFillCurve");
@@ -2367,8 +2376,8 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
- /* Special case to handle older in-dev 3.1 files, before change from 3.0 branch gets merged in
- * master. */
+ /* Special case to handle older in-development 3.1 files, before change from 3.0 branch gets
+ * merged in master. */
if (!MAIN_VERSION_ATLEAST(bmain, 300, 42) ||
(bmain->versionfile == 301 && !MAIN_VERSION_ATLEAST(bmain, 301, 3))) {
/* Update LibOverride operations regarding insertions in RNA collections (i.e. modifiers,
@@ -2385,6 +2394,60 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
FOREACH_MAIN_ID_END;
}
+ if (!MAIN_VERSION_ATLEAST(bmain, 301, 4)) {
+ LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
+ if (ntree->type != NTREE_GEOMETRY) {
+ continue;
+ }
+ version_node_id(ntree, GEO_NODE_CURVE_SPLINE_PARAMETER, "GeometryNodeSplineParameter");
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type == GEO_NODE_CURVE_SPLINE_PARAMETER) {
+ version_node_add_socket_if_not_exist(
+ ntree, node, SOCK_OUT, SOCK_INT, PROP_NONE, "Index", "Index");
+ }
+
+ /* Convert float compare into a more general compare node. */
+ if (node->type == FN_NODE_COMPARE) {
+ if (node->storage == NULL) {
+ NodeFunctionCompare *data = (NodeFunctionCompare *)MEM_callocN(
+ sizeof(NodeFunctionCompare), __func__);
+ data->data_type = SOCK_FLOAT;
+ data->operation = node->custom1;
+ strcpy(node->idname, "FunctionNodeCompare");
+ node->update = NODE_UPDATE;
+ node->storage = data;
+ }
+ }
+ }
+ }
+
+ /* Add a toggle for the breadcrumbs overlay in the node editor. */
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, space, &area->spacedata) {
+ if (space->spacetype == SPACE_NODE) {
+ SpaceNode *snode = (SpaceNode *)space;
+ snode->overlay.flag |= SN_OVERLAY_SHOW_PATH;
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 301, 5)) {
+ LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
+ if (ntree->type != NTREE_GEOMETRY) {
+ continue;
+ }
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type != GEO_NODE_REALIZE_INSTANCES) {
+ continue;
+ }
+ node->custom1 |= GEO_NODE_REALIZE_INSTANCES_LEGACY_BEHAVIOR;
+ }
+ }
+ }
+
/**
* Versioning code until next subversion bump goes here.
*
@@ -2396,5 +2459,21 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
*/
{
/* Keep this block, even when empty. */
+
+ /* Add node storage for map range node. */
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type == SH_NODE_MAP_RANGE) {
+ if (node->storage == NULL) {
+ NodeMapRange *data = MEM_callocN(sizeof(NodeMapRange), __func__);
+ data->clamp = node->custom1;
+ data->data_type = CD_PROP_FLOAT;
+ data->interpolation_type = node->custom2;
+ node->storage = data;
+ }
+ }
+ }
+ }
+ FOREACH_NODETREE_END;
}
}
diff --git a/source/blender/blenloader/intern/versioning_common.cc b/source/blender/blenloader/intern/versioning_common.cc
index af765be619f..3deaaa040d6 100644
--- a/source/blender/blenloader/intern/versioning_common.cc
+++ b/source/blender/blenloader/intern/versioning_common.cc
@@ -61,11 +61,6 @@ ARegion *do_versions_add_region_if_not_found(ListBase *regionbase,
return new_region;
}
-/**
- * Rename if the ID doesn't exist.
- *
- * \return the ID (if found).
- */
ID *do_versions_rename_id(Main *bmain,
const short id_type,
const char *name_src,
@@ -104,9 +99,6 @@ static void change_node_socket_name(ListBase *sockets, const char *old_name, con
}
}
-/**
- * Convert `SocketName.001` unique name format to `SocketName_001`. Previously both were used.
- */
void version_node_socket_id_delim(bNodeSocket *socket)
{
StringRef name = socket->name;
@@ -165,9 +157,21 @@ void version_node_output_socket_name(bNodeTree *ntree,
}
}
-/**
- * Replace the ID name of all nodes in the tree with the given type with the new name.
- */
+bNodeSocket *version_node_add_socket_if_not_exist(bNodeTree *ntree,
+ bNode *node,
+ eNodeSocketInOut in_out,
+ int type,
+ int subtype,
+ const char *identifier,
+ const char *name)
+{
+ bNodeSocket *sock = nodeFindSocket(node, in_out, identifier);
+ if (sock != nullptr) {
+ return sock;
+ }
+ return nodeAddStaticSocket(ntree, node, in_out, type, subtype, identifier, name);
+}
+
void version_node_id(bNodeTree *ntree, const int node_type, const char *new_name)
{
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
@@ -179,23 +183,6 @@ void version_node_id(bNodeTree *ntree, const int node_type, const char *new_name
}
}
-/**
- * Adjust animation data for newly added node sockets.
- *
- * Node sockets are addressed by their index (in their RNA path, and thus FCurves/drivers), and
- * thus when a new node is added in the middle of the list, existing animation data needs to be
- * adjusted.
- *
- * Since this is about animation data, it only concerns input sockets.
- *
- * \param node_tree_type node tree type that has these nodes, for example NTREE_SHADER.
- * \param node_type node type to adjust, for example SH_NODE_BSDF_PRINCIPLED.
- * \param socket_index_orig the original index of the moved socket; when socket 4 moved to 6,
- * pass 4 here.
- * \param socket_index_offset the offset of the nodes, so when socket 4 moved to 6,
- * pass 2 here.
- * \param total_number_of_sockets the total number of sockets in the node.
- */
void version_node_socket_index_animdata(Main *bmain,
const int node_tree_type,
const int node_type,
diff --git a/source/blender/blenloader/intern/versioning_common.h b/source/blender/blenloader/intern/versioning_common.h
index 7f179800ddd..0613484b754 100644
--- a/source/blender/blenloader/intern/versioning_common.h
+++ b/source/blender/blenloader/intern/versioning_common.h
@@ -34,6 +34,11 @@ struct ARegion *do_versions_add_region_if_not_found(struct ListBase *regionbase,
const char *name,
int link_after_region_type);
+/**
+ * Rename if the ID doesn't exist.
+ *
+ * \return the ID (if found).
+ */
ID *do_versions_rename_id(Main *bmain,
const short id_type,
const char *name_src,
@@ -52,6 +57,23 @@ void version_node_output_socket_name(struct bNodeTree *ntree,
const char *old_name,
const char *new_name);
+/**
+ * Adjust animation data for newly added node sockets.
+ *
+ * Node sockets are addressed by their index (in their RNA path, and thus FCurves/drivers), and
+ * thus when a new node is added in the middle of the list, existing animation data needs to be
+ * adjusted.
+ *
+ * Since this is about animation data, it only concerns input sockets.
+ *
+ * \param node_tree_type: Node tree type that has these nodes, for example #NTREE_SHADER.
+ * \param node_type: Node type to adjust, for example #SH_NODE_BSDF_PRINCIPLED.
+ * \param socket_index_orig: The original index of the moved socket; when socket 4 moved to 6,
+ * pass 4 here.
+ * \param socket_index_offset: The offset of the nodes, so when socket 4 moved to 6,
+ * pass 2 here.
+ * \param total_number_of_sockets: The total number of sockets in the node.
+ */
void version_node_socket_index_animdata(
Main *bmain,
int node_tree_type, /* NTREE_....., e.g. NTREE_SHADER */
@@ -60,10 +82,24 @@ void version_node_socket_index_animdata(
int socket_index_offset,
int total_number_of_sockets);
+/**
+ * Replace the ID name of all nodes in the tree with the given type with the new name.
+ */
void version_node_id(struct bNodeTree *ntree, const int node_type, const char *new_name);
+/**
+ * Convert `SocketName.001` unique name format to `SocketName_001`. Previously both were used.
+ */
void version_node_socket_id_delim(bNodeSocket *socket);
+struct bNodeSocket *version_node_add_socket_if_not_exist(struct bNodeTree *ntree,
+ struct bNode *node,
+ eNodeSocketInOut in_out,
+ int type,
+ int subtype,
+ const char *identifier,
+ const char *name);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c
index fa61b1ca6cd..a5c44ea711b 100644
--- a/source/blender/blenloader/intern/versioning_defaults.c
+++ b/source/blender/blenloader/intern/versioning_defaults.c
@@ -367,15 +367,6 @@ static void blo_update_defaults_scene(Main *bmain, Scene *scene)
}
}
-/**
- * Update defaults in startup.blend, without having to save and embed the file.
- * This function can be emptied each time the startup.blend is updated.
- *
- * \note Screen data may be cleared at this point, this will happen in the case
- * an app-template's data needs to be versioned when read-file is called with "Load UI" disabled.
- * Versioning the screen data can be safely skipped without "Load UI" since the screen data
- * will have been versioned when it was first loaded.
- */
void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
{
/* For all app templates. */
diff --git a/source/blender/blenloader/intern/versioning_dna.c b/source/blender/blenloader/intern/versioning_dna.c
index aee54b94833..0a97eedb993 100644
--- a/source/blender/blenloader/intern/versioning_dna.c
+++ b/source/blender/blenloader/intern/versioning_dna.c
@@ -29,16 +29,6 @@
#include "BLO_readfile.h"
#include "readfile.h"
-/**
- * Manipulates SDNA before calling #DNA_struct_get_compareflags,
- * allowing us to rename structs and struct members.
- *
- * - This means older versions of Blender won't have access to this data **USE WITH CARE**.
- *
- * - These changes are applied on file load (run-time), similar to versioning for compatibility.
- *
- * \attention ONLY USE THIS KIND OF VERSIONING WHEN `dna_rename_defs.h` ISN'T SUFFICIENT.
- */
void blo_do_versions_dna(SDNA *sdna, const int versionfile, const int subversionfile)
{
#define DNA_VERSION_ATLEAST(ver, subver) \
diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c
index 37bf4898cb3..2fceb42262e 100644
--- a/source/blender/blenloader/intern/versioning_legacy.c
+++ b/source/blender/blenloader/intern/versioning_legacy.c
@@ -461,8 +461,6 @@ static void do_version_constraints_245(ListBase *lb)
}
}
-/* NOTE: this version patch is intended for versions < 2.52.2,
- * but was initially introduced in 2.27 already. */
void blo_do_version_old_trackto_to_constraints(Object *ob)
{
/* create new trackto constraint from the relationship */
diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c
index 0e5e0b76f43..3338d2f658c 100644
--- a/source/blender/blenloader/intern/versioning_userdef.c
+++ b/source/blender/blenloader/intern/versioning_userdef.c
@@ -399,7 +399,6 @@ static bool keymap_item_has_invalid_wm_context_data_path(wmKeyMapItem *kmi,
return false;
}
-/* patching UserDef struct and Themes */
void blo_do_versions_userdef(UserDef *userdef)
{
/* #UserDef & #Main happen to have the same struct member. */
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 56ff7151cb1..aa3eef4b475 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -50,7 +50,7 @@
* Almost all data in Blender are structures. Each struct saved
* gets a BHead header. With BHead the struct can be linked again
* and compared with #StructDNA.
-
+ *
* WRITE
* =====
*
@@ -1028,7 +1028,7 @@ static void write_global(WriteData *wd, int fileflags, Main *mainvar)
/* prevent mem checkers from complaining */
memset(fg._pad, 0, sizeof(fg._pad));
- memset(fg.filename, 0, sizeof(fg.filename));
+ memset(fg.filepath, 0, sizeof(fg.filepath));
memset(fg.build_hash, 0, sizeof(fg.build_hash));
fg._pad1 = NULL;
@@ -1045,7 +1045,7 @@ static void write_global(WriteData *wd, int fileflags, Main *mainvar)
fg.globalf = G.f;
/* Write information needed for recovery. */
if (fileflags & G_FILE_RECOVER_WRITE) {
- BLI_strncpy(fg.filename, mainvar->name, sizeof(fg.filename));
+ STRNCPY(fg.filepath, mainvar->filepath);
}
sprintf(subvstr, "%4d", BLENDER_FILE_SUBVERSION);
memcpy(fg.subvstr, subvstr, 4);
@@ -1312,15 +1312,15 @@ static bool do_history(const char *name, ReportList *reports)
/** \name File Writing (Public)
* \{ */
-/**
- * \return Success.
- */
bool BLO_write_file(Main *mainvar,
const char *filepath,
const int write_flags,
const struct BlendFileWriteParams *params,
ReportList *reports)
{
+ BLI_assert(!BLI_path_is_rel(filepath));
+ BLI_assert(BLI_path_is_abs_from_cwd(filepath));
+
char tempname[FILE_MAX + 1];
WriteWrap ww;
@@ -1329,10 +1329,12 @@ bool BLO_write_file(Main *mainvar,
const bool use_save_as_copy = params->use_save_as_copy;
const bool use_userdef = params->use_userdef;
const BlendThumbnail *thumb = params->thumb;
+ const bool relbase_valid = (mainvar->filepath[0] != '\0');
/* path backup/restore */
void *path_list_backup = NULL;
- const int path_list_flag = (BKE_BPATH_TRAVERSE_SKIP_LIBRARY | BKE_BPATH_TRAVERSE_SKIP_MULTIFILE);
+ const eBPathForeachFlag path_list_flag = (BKE_BPATH_FOREACH_PATH_SKIP_LINKED |
+ BKE_BPATH_FOREACH_PATH_SKIP_MULTIFILE);
if (G.debug & G_DEBUG_IO && mainvar->lock != NULL) {
BKE_report(reports, RPT_INFO, "Checking sanity of current .blend file *BEFORE* save to disk");
@@ -1351,35 +1353,47 @@ bool BLO_write_file(Main *mainvar,
return 0;
}
+ if (remap_mode == BLO_WRITE_PATH_REMAP_ABSOLUTE) {
+ /* Paths will already be absolute, no remapping to do. */
+ if (relbase_valid == false) {
+ remap_mode = BLO_WRITE_PATH_REMAP_NONE;
+ }
+ }
+
/* Remapping of relative paths to new file location. */
if (remap_mode != BLO_WRITE_PATH_REMAP_NONE) {
if (remap_mode == BLO_WRITE_PATH_REMAP_RELATIVE) {
- /* Make all relative as none of the existing paths can be relative in an unsaved document.
- */
- if (G.relbase_valid == false) {
+ /* Make all relative as none of the existing paths can be relative in an unsaved document. */
+ if (relbase_valid == false) {
remap_mode = BLO_WRITE_PATH_REMAP_RELATIVE_ALL;
}
}
+ /* The source path only makes sense to set if the file was saved (`relbase_valid`). */
char dir_src[FILE_MAX];
char dir_dst[FILE_MAX];
- BLI_split_dir_part(mainvar->name, dir_src, sizeof(dir_src));
- BLI_split_dir_part(filepath, dir_dst, sizeof(dir_dst));
- /* Just in case there is some subtle difference. */
- BLI_path_normalize(mainvar->name, dir_dst);
- BLI_path_normalize(mainvar->name, dir_src);
+ /* Normalize the paths in case there is some subtle difference (so they can be compared). */
+ if (relbase_valid) {
+ BLI_split_dir_part(mainvar->filepath, dir_src, sizeof(dir_src));
+ BLI_path_normalize(NULL, dir_src);
+ }
+ else {
+ dir_src[0] = '\0';
+ }
+ BLI_split_dir_part(filepath, dir_dst, sizeof(dir_dst));
+ BLI_path_normalize(NULL, dir_dst);
/* Only for relative, not relative-all, as this means making existing paths relative. */
if (remap_mode == BLO_WRITE_PATH_REMAP_RELATIVE) {
- if (G.relbase_valid && (BLI_path_cmp(dir_dst, dir_src) == 0)) {
+ if (relbase_valid && (BLI_path_cmp(dir_dst, dir_src) == 0)) {
/* Saved to same path. Nothing to do. */
remap_mode = BLO_WRITE_PATH_REMAP_NONE;
}
}
else if (remap_mode == BLO_WRITE_PATH_REMAP_ABSOLUTE) {
- if (G.relbase_valid == false) {
+ if (relbase_valid == false) {
/* Unsaved, all paths are absolute.Even if the user manages to set a relative path,
* there is no base-path that can be used to make it absolute. */
remap_mode = BLO_WRITE_PATH_REMAP_NONE;
@@ -1395,6 +1409,7 @@ bool BLO_write_file(Main *mainvar,
switch (remap_mode) {
case BLO_WRITE_PATH_REMAP_RELATIVE:
/* Saved, make relative paths relative to new location (if possible). */
+ BLI_assert(relbase_valid);
BKE_bpath_relative_rebase(mainvar, dir_src, dir_dst, NULL);
break;
case BLO_WRITE_PATH_REMAP_RELATIVE_ALL:
@@ -1403,6 +1418,7 @@ bool BLO_write_file(Main *mainvar,
break;
case BLO_WRITE_PATH_REMAP_ABSOLUTE:
/* Make all absolute (when requested or unsaved). */
+ BLI_assert(relbase_valid);
BKE_bpath_absolute_convert(mainvar, dir_src, NULL);
break;
case BLO_WRITE_PATH_REMAP_NONE:
@@ -1452,9 +1468,6 @@ bool BLO_write_file(Main *mainvar,
return 1;
}
-/**
- * \return Success.
- */
bool BLO_write_file_mem(Main *mainvar, MemFile *compare, MemFile *current, int write_flags)
{
bool use_userdef = false;
@@ -1577,9 +1590,6 @@ void BLO_write_float3_array(BlendWriter *writer, uint num, const float *data_ptr
BLO_write_raw(writer, sizeof(float[3]) * (size_t)num, data_ptr);
}
-/**
- * Write a null terminated string.
- */
void BLO_write_string(BlendWriter *writer, const char *data_ptr)
{
if (data_ptr != NULL) {
@@ -1587,10 +1597,6 @@ void BLO_write_string(BlendWriter *writer, const char *data_ptr)
}
}
-/**
- * Sometimes different data is written depending on whether the file is saved to disk or used for
- * undo. This function returns true when the current file-writing is done for undo.
- */
bool BLO_write_is_undo(BlendWriter *writer)
{
return writer->wd->use_memfile;
diff --git a/source/blender/blentranslation/BLT_lang.h b/source/blender/blentranslation/BLT_lang.h
index dcd4de10416..1a0981613a1 100644
--- a/source/blender/blentranslation/BLT_lang.h
+++ b/source/blender/blentranslation/BLT_lang.h
@@ -46,6 +46,15 @@ const char *BLT_lang_get(void);
* Non-null elements are always MEM_mallocN'ed, it's the caller's responsibility to free them.
* NOTE: Always available, even in non-WITH_INTERNATIONAL builds.
*/
+/**
+ * Get locale's elements (if relevant pointer is not NULL and element actually exists, e.g.
+ * if there is no variant,
+ * *variant and *language_variant will always be NULL).
+ * Non-null elements are always MEM_mallocN'ed, it's the caller's responsibility to free them.
+ *
+ * \note Keep that one always available, you never know,
+ * may become useful even in no #WITH_INTERNATIONAL context.
+ */
void BLT_lang_locale_explode(const char *locale,
char **language,
char **country,
diff --git a/source/blender/blentranslation/BLT_translation.h b/source/blender/blentranslation/BLT_translation.h
index 341e648443e..21296143226 100644
--- a/source/blender/blentranslation/BLT_translation.h
+++ b/source/blender/blentranslation/BLT_translation.h
@@ -44,6 +44,11 @@ const char *BLT_translate_do_iface(const char *msgctxt, const char *msgid);
const char *BLT_translate_do_tooltip(const char *msgctxt, const char *msgid);
const char *BLT_translate_do_new_dataname(const char *msgctxt, const char *msgid);
+/**
+ * Note that "lang" here is the _output_ display language. We used to restrict
+ * IME for keyboard _input_ language because our multilingual font was only used
+ * when some output languages were selected. That font is used all the time now.
+ */
bool BLT_lang_is_ime_supported(void);
/* The "translation-marker" macro. */
diff --git a/source/blender/blentranslation/intern/blt_lang.c b/source/blender/blentranslation/intern/blt_lang.c
index 91e8a81aec0..01f7574bd34 100644
--- a/source/blender/blentranslation/intern/blt_lang.c
+++ b/source/blender/blentranslation/intern/blt_lang.c
@@ -282,7 +282,6 @@ void BLT_lang_set(const char *str)
IMB_thumb_clear_translations();
}
-/* Get the current locale (short code, e.g. es_ES). */
const char *BLT_lang_get(void)
{
#ifdef WITH_INTERNATIONAL
@@ -303,15 +302,6 @@ const char *BLT_lang_get(void)
#undef LOCALE
#undef ULANGUAGE
-/**
- * Get locale's elements (if relevant pointer is not NULL and element actually exists, e.g.
- * if there is no variant,
- * *variant and *language_variant will always be NULL).
- * Non-null elements are always MEM_mallocN'ed, it's the caller's responsibility to free them.
- *
- * \note Keep that one always available, you never know,
- * may become useful even in no #WITH_INTERNATIONAL context.
- */
void BLT_lang_locale_explode(const char *locale,
char **language,
char **country,
@@ -372,9 +362,6 @@ void BLT_lang_locale_explode(const char *locale,
}
}
-/* Note that "lang" here is the _output_ display language. We used to restrict
- * IME for keyboard _input_ language because our multilingual font was only used
- * when some output languages were selected. That font is used all the time now. */
bool BLT_lang_is_ime_supported(void)
{
#ifdef WITH_INPUT_IME
diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c
index a10a911b06c..5a9d1ba7bc4 100644
--- a/source/blender/bmesh/intern/bmesh_construct.c
+++ b/source/blender/bmesh/intern/bmesh_construct.c
@@ -39,11 +39,6 @@
#define SELECT 1
-/**
- * Fill in a vertex array from an edge array.
- *
- * \returns false if any verts aren't found.
- */
bool BM_verts_from_edges(BMVert **vert_arr, BMEdge **edge_arr, const int len)
{
int i, i_prev = len - 1;
@@ -57,11 +52,6 @@ bool BM_verts_from_edges(BMVert **vert_arr, BMEdge **edge_arr, const int len)
return true;
}
-/**
- * Fill in an edge array from a vertex array (connected polygon loop).
- *
- * \returns false if any edges aren't found.
- */
bool BM_edges_from_verts(BMEdge **edge_arr, BMVert **vert_arr, const int len)
{
int i, i_prev = len - 1;
@@ -75,10 +65,6 @@ bool BM_edges_from_verts(BMEdge **edge_arr, BMVert **vert_arr, const int len)
return true;
}
-/**
- * Fill in an edge array from a vertex array (connected polygon loop).
- * Creating edges as-needed.
- */
void BM_edges_from_verts_ensure(BMesh *bm, BMEdge **edge_arr, BMVert **vert_arr, const int len)
{
int i, i_prev = len - 1;
@@ -93,20 +79,6 @@ void BM_edges_from_verts_ensure(BMesh *bm, BMEdge **edge_arr, BMVert **vert_arr,
static void bm_loop_attrs_copy(
BMesh *bm_src, BMesh *bm_dst, const BMLoop *l_src, BMLoop *l_dst, CustomDataMask mask_exclude);
-/**
- * \brief Make Quad/Triangle
- *
- * Creates a new quad or triangle from a list of 3 or 4 vertices.
- * If \a no_double is true, then a check is done to see if a face
- * with these vertices already exists and returns it instead.
- *
- * If a pointer to an example face is provided, its custom data
- * and properties will be copied to the new face.
- *
- * \note The winding of the face is determined by the order
- * of the vertices in the vertex array.
- */
-
BMFace *BM_face_create_quad_tri(BMesh *bm,
BMVert *v1,
BMVert *v2,
@@ -119,16 +91,6 @@ BMFace *BM_face_create_quad_tri(BMesh *bm,
return BM_face_create_verts(bm, vtar, v4 ? 4 : 3, f_example, create_flag, true);
}
-/**
- * \brief copies face loop data from shared adjacent faces.
- *
- * \param filter_fn: A function that filters the source loops before copying
- * (don't always want to copy all).
- *
- * \note when a matching edge is found, both loops of that edge are copied
- * this is done since the face may not be completely surrounded by faces,
- * this way: a quad with 2 connected quads on either side will still get all 4 loops updated
- */
void BM_face_copy_shared(BMesh *bm, BMFace *f, BMLoopFilterFunc filter_fn, void *user_data)
{
BMLoop *l_first;
@@ -260,20 +222,6 @@ error:
return false;
}
-/**
- * \brief Make NGon
- *
- * Makes an ngon from an unordered list of edges.
- * Verts \a v1 and \a v2 define the winding of the new face.
- *
- * \a edges are not required to be ordered, simply to form
- * a single closed loop as a whole.
- *
- * \note While this function will work fine when the edges
- * are already sorted, if the edges are always going to be sorted,
- * #BM_face_create should be considered over this function as it
- * avoids some unnecessary work.
- */
BMFace *BM_face_create_ngon(BMesh *bm,
BMVert *v1,
BMVert *v2,
@@ -294,14 +242,6 @@ BMFace *BM_face_create_ngon(BMesh *bm,
return NULL;
}
-/**
- * Create an ngon from an array of sorted verts
- *
- * Special features this has over other functions.
- * - Optionally calculate winding based on surrounding edges.
- * - Optionally create edges between vertices.
- * - Uses verts so no need to find edges (handy when you only have verts)
- */
BMFace *BM_face_create_ngon_verts(BMesh *bm,
BMVert **vert_arr,
const int len,
@@ -367,22 +307,6 @@ BMFace *BM_face_create_ngon_verts(BMesh *bm,
bm, v_winding[winding[0]], v_winding[winding[1]], edge_arr, len, f_example, create_flag);
}
-/**
- * Makes an NGon from an un-ordered set of verts
- *
- * assumes...
- * - that verts are only once in the list.
- * - that the verts have roughly planer bounds
- * - that the verts are roughly circular
- * there can be concave areas but overlapping folds from the center point will fail.
- *
- * a brief explanation of the method used
- * - find the center point
- * - find the normal of the vcloud
- * - order the verts around the face based on their angle to the normal vector at the center point.
- *
- * \note Since this is a vcloud there is no direction.
- */
void BM_verts_sort_radial_plane(BMVert **vert_arr, int len)
{
struct SortIntByFloat *vang = BLI_array_alloca(vang, len);
@@ -467,13 +391,6 @@ static void bm_face_attrs_copy(
f_dst->mat_nr = f_src->mat_nr;
}
-/* BMESH_TODO: Special handling for hide flags? */
-/* BMESH_TODO: swap src/dst args, everywhere else in bmesh does other way round */
-
-/**
- * Copies attributes, e.g. customdata, header flags, etc, from one element
- * to another of the same type.
- */
void BM_elem_attrs_copy_ex(BMesh *bm_src,
BMesh *bm_dst,
const void *ele_src_v,
@@ -481,6 +398,9 @@ void BM_elem_attrs_copy_ex(BMesh *bm_src,
const char hflag_mask,
const uint64_t cd_mask_exclude)
{
+ /* TODO: Special handling for hide flags? */
+ /* TODO: swap src/dst args, everywhere else in bmesh does other way round. */
+
const BMHeader *ele_src = ele_src_v;
BMHeader *ele_dst = ele_dst_v;
@@ -626,15 +546,6 @@ void BM_mesh_copy_init_customdata(BMesh *bm_dst, BMesh *bm_src, const BMAllocTem
CustomData_bmesh_init_pool(&bm_dst->pdata, allocsize->totface, BM_FACE);
}
-/**
- * Similar to #BM_mesh_copy_init_customdata but copies all layers ignoring
- * flags like #CD_FLAG_NOCOPY.
- *
- * \param bm_dst: BMesh whose custom-data layers will be added.
- * \param bm_src: BMesh whose custom-data layers will be copied.
- * \param htype: Specifies which custom-data layers will be initiated.
- * \param allocsize: Initialize the memory-pool before use (may be an estimate).
- */
void BM_mesh_copy_init_customdata_all_layers(BMesh *bm_dst,
BMesh *bm_src,
const char htype,
@@ -786,7 +697,6 @@ BMesh *BM_mesh_copy(BMesh *bm_old)
return bm_new;
}
-/* ME -> BM */
char BM_vert_flag_from_mflag(const char mflag)
{
return (((mflag & SELECT) ? BM_ELEM_SELECT : 0) | ((mflag & ME_HIDE) ? BM_ELEM_HIDDEN : 0));
@@ -804,7 +714,6 @@ char BM_face_flag_from_mflag(const char mflag)
((mflag & ME_SMOOTH) ? BM_ELEM_SMOOTH : 0) | ((mflag & ME_HIDE) ? BM_ELEM_HIDDEN : 0));
}
-/* BM -> ME */
char BM_vert_flag_to_mflag(BMVert *v)
{
const char hflag = v->head.hflag;
diff --git a/source/blender/bmesh/intern/bmesh_construct.h b/source/blender/bmesh/intern/bmesh_construct.h
index f2b5e2b4daa..692f3b403b5 100644
--- a/source/blender/bmesh/intern/bmesh_construct.h
+++ b/source/blender/bmesh/intern/bmesh_construct.h
@@ -25,14 +25,57 @@
struct BMAllocTemplate;
struct Mesh;
+/**
+ * Fill in a vertex array from an edge array.
+ *
+ * \returns false if any verts aren't found.
+ */
bool BM_verts_from_edges(BMVert **vert_arr, BMEdge **edge_arr, const int len);
+/**
+ * Fill in an edge array from a vertex array (connected polygon loop).
+ *
+ * \returns false if any edges aren't found.
+ */
bool BM_edges_from_verts(BMEdge **edge_arr, BMVert **vert_arr, const int len);
+/**
+ * Fill in an edge array from a vertex array (connected polygon loop).
+ * Creating edges as-needed.
+ */
void BM_edges_from_verts_ensure(BMesh *bm, BMEdge **edge_arr, BMVert **vert_arr, const int len);
-/* sort before creation */
+/**
+ * Makes an NGon from an un-ordered set of verts.
+ *
+ * Assumes:
+ * - that verts are only once in the list.
+ * - that the verts have roughly planer bounds
+ * - that the verts are roughly circular
+ *
+ * There can be concave areas but overlapping folds from the center point will fail.
+ *
+ * A brief explanation of the method used
+ * - find the center point
+ * - find the normal of the vertex-cloud
+ * - order the verts around the face based on their angle to the normal vector at the center point.
+ *
+ * \note Since this is a vertex-cloud there is no direction.
+ */
void BM_verts_sort_radial_plane(BMVert **vert_arr, int len);
+/**
+ * \brief Make Quad/Triangle
+ *
+ * Creates a new quad or triangle from a list of 3 or 4 vertices.
+ * If \a no_double is true, then a check is done to see if a face
+ * with these vertices already exists and returns it instead.
+ *
+ * If a pointer to an example face is provided, its custom data
+ * and properties will be copied to the new face.
+ *
+ * \note The winding of the face is determined by the order
+ * of the vertices in the vertex array.
+ */
BMFace *BM_face_create_quad_tri(BMesh *bm,
BMVert *v1,
BMVert *v2,
@@ -41,8 +84,32 @@ BMFace *BM_face_create_quad_tri(BMesh *bm,
const BMFace *f_example,
const eBMCreateFlag create_flag);
+/**
+ * \brief copies face loop data from shared adjacent faces.
+ *
+ * \param filter_fn: A function that filters the source loops before copying
+ * (don't always want to copy all).
+ *
+ * \note when a matching edge is found, both loops of that edge are copied
+ * this is done since the face may not be completely surrounded by faces,
+ * this way: a quad with 2 connected quads on either side will still get all 4 loops updated
+ */
void BM_face_copy_shared(BMesh *bm, BMFace *f, BMLoopFilterFunc filter_fn, void *user_data);
+/**
+ * \brief Make NGon
+ *
+ * Makes an ngon from an unordered list of edges.
+ * Verts \a v1 and \a v2 define the winding of the new face.
+ *
+ * \a edges are not required to be ordered, simply to form
+ * a single closed loop as a whole.
+ *
+ * \note While this function will work fine when the edges
+ * are already sorted, if the edges are always going to be sorted,
+ * #BM_face_create should be considered over this function as it
+ * avoids some unnecessary work.
+ */
BMFace *BM_face_create_ngon(BMesh *bm,
BMVert *v1,
BMVert *v2,
@@ -50,6 +117,14 @@ BMFace *BM_face_create_ngon(BMesh *bm,
const int len,
const BMFace *f_example,
const eBMCreateFlag create_flag);
+/**
+ * Create an ngon from an array of sorted verts
+ *
+ * Special features this has over other functions.
+ * - Optionally calculate winding based on surrounding edges.
+ * - Optionally create edges between vertices.
+ * - Uses verts so no need to find edges (handy when you only have verts)
+ */
BMFace *BM_face_create_ngon_verts(BMesh *bm,
BMVert **vert_arr,
const int len,
@@ -58,6 +133,10 @@ BMFace *BM_face_create_ngon_verts(BMesh *bm,
const bool calc_winding,
const bool create_edges);
+/**
+ * Copies attributes, e.g. customdata, header flags, etc, from one element
+ * to another of the same type.
+ */
void BM_elem_attrs_copy_ex(BMesh *bm_src,
BMesh *bm_dst,
const void *ele_src_v,
@@ -73,6 +152,15 @@ void BM_mesh_copy_init_customdata_from_mesh(BMesh *bm_dst,
void BM_mesh_copy_init_customdata(BMesh *bm_dst,
BMesh *bm_src,
const struct BMAllocTemplate *allocsize);
+/**
+ * Similar to #BM_mesh_copy_init_customdata but copies all layers ignoring
+ * flags like #CD_FLAG_NOCOPY.
+ *
+ * \param bm_dst: BMesh whose custom-data layers will be added.
+ * \param bm_src: BMesh whose custom-data layers will be copied.
+ * \param htype: Specifies which custom-data layers will be initiated.
+ * \param allocsize: Initialize the memory-pool before use (may be an estimate).
+ */
void BM_mesh_copy_init_customdata_all_layers(BMesh *bm_dst,
BMesh *bm_src,
const char htype,
@@ -81,7 +169,9 @@ BMesh *BM_mesh_copy(BMesh *bm_old);
char BM_face_flag_from_mflag(const char mflag);
char BM_edge_flag_from_mflag(const short mflag);
+/* ME -> BM */
char BM_vert_flag_from_mflag(const char mflag);
char BM_face_flag_to_mflag(BMFace *f);
short BM_edge_flag_to_mflag(BMEdge *e);
+/* BM -> ME */
char BM_vert_flag_to_mflag(BMVert *v);
diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c
index e72c689ddfb..1d7d10de96f 100644
--- a/source/blender/bmesh/intern/bmesh_core.c
+++ b/source/blender/bmesh/intern/bmesh_core.c
@@ -52,9 +52,6 @@
#endif
-/**
- * \brief Main function for creating a new vertex.
- */
BMVert *BM_vert_create(BMesh *bm,
const float co[3],
const BMVert *v_example,
@@ -137,13 +134,6 @@ BMVert *BM_vert_create(BMesh *bm,
return v;
}
-/**
- * \brief Main function for creating a new edge.
- *
- * \note Duplicate edges are supported by the API however users should _never_ see them.
- * so unless you need a unique edge or know the edge won't exist,
- * you should call with \a no_double = true.
- */
BMEdge *BM_edge_create(
BMesh *bm, BMVert *v1, BMVert *v2, const BMEdge *e_example, const eBMCreateFlag create_flag)
{
@@ -416,15 +406,6 @@ BLI_INLINE BMFace *bm_face_create__internal(BMesh *bm)
return f;
}
-/**
- * Main face creation function
- *
- * \param bm: The mesh
- * \param verts: A sorted array of verts size of len
- * \param edges: A sorted array of edges size of len
- * \param len: Length of the face
- * \param create_flag: Options for creating the face
- */
BMFace *BM_face_create(BMesh *bm,
BMVert **verts,
BMEdge **edges,
@@ -494,9 +475,6 @@ BMFace *BM_face_create(BMesh *bm,
return f;
}
-/**
- * Wrapper for #BM_face_create when you don't have an edge array
- */
BMFace *BM_face_create_verts(BMesh *bm,
BMVert **vert_arr,
const int len,
@@ -520,12 +498,6 @@ BMFace *BM_face_create_verts(BMesh *bm,
#ifndef NDEBUG
-/**
- * Check the element is valid.
- *
- * BMESH_TODO, when this raises an error the output is incredibly confusing.
- * need to have some nice way to print/debug what the heck's going on.
- */
int bmesh_elem_check(void *element, const char htype)
{
BMHeader *head = element;
@@ -833,10 +805,6 @@ static void bm_kill_only_loop(BMesh *bm, BMLoop *l)
BLI_mempool_free(bm->lpool, l);
}
-/**
- * kills all edges associated with \a f, along with any other faces containing
- * those edges
- */
void BM_face_edges_kill(BMesh *bm, BMFace *f)
{
BMEdge **edges = BLI_array_alloca(edges, f->len);
@@ -854,10 +822,6 @@ void BM_face_edges_kill(BMesh *bm, BMFace *f)
}
}
-/**
- * kills all verts associated with \a f, along with any other faces containing
- * those vertices
- */
void BM_face_verts_kill(BMesh *bm, BMFace *f)
{
BMVert **verts = BLI_array_alloca(verts, f->len);
@@ -875,9 +839,6 @@ void BM_face_verts_kill(BMesh *bm, BMFace *f)
}
}
-/**
- * Kills \a f and its loops.
- */
void BM_face_kill(BMesh *bm, BMFace *f)
{
#ifdef USE_BMESH_HOLES
@@ -922,10 +883,6 @@ void BM_face_kill(BMesh *bm, BMFace *f)
bm_kill_only_face(bm, f);
}
-/**
- * A version of #BM_face_kill which removes edges and verts
- * which have no remaining connected geometry.
- */
void BM_face_kill_loose(BMesh *bm, BMFace *f)
{
#ifdef USE_BMESH_HOLES
@@ -981,9 +938,6 @@ void BM_face_kill_loose(BMesh *bm, BMFace *f)
bm_kill_only_face(bm, f);
}
-/**
- * kills \a e and all faces that use it.
- */
void BM_edge_kill(BMesh *bm, BMEdge *e)
{
while (e->l) {
@@ -996,9 +950,6 @@ void BM_edge_kill(BMesh *bm, BMEdge *e)
bm_kill_only_edge(bm, e);
}
-/**
- * kills \a v and all edges that use it.
- */
void BM_vert_kill(BMesh *bm, BMVert *v)
{
while (v->e) {
@@ -1025,15 +976,6 @@ static int UNUSED_FUNCTION(bm_loop_length)(BMLoop *l)
return i;
}
-/**
- * \brief Loop Reverse
- *
- * Changes the winding order of a face from CW to CCW or vice versa.
- *
- * \param cd_loop_mdisp_offset: Cached result of `CustomData_get_offset(&bm->ldata, CD_MDISPS)`.
- * \param use_loop_mdisp_flip: When set, flip the Z-depth of the mdisp,
- * (use when flipping normals, disable when mirroring, eg: symmetrize).
- */
void bmesh_kernel_loop_reverse(BMesh *bm,
BMFace *f,
const int cd_loop_mdisp_offset,
@@ -1192,20 +1134,6 @@ static bool bm_vert_is_manifold_flagged(BMVert *v, const char api_flag)
/* Mid-level Topology Manipulation Functions */
-/**
- * \brief Join Connected Faces
- *
- * Joins a collected group of faces into one. Only restriction on
- * the input data is that the faces must be connected to each other.
- *
- * \return The newly created combine BMFace.
- *
- * \note If a pair of faces share multiple edges,
- * the pair of faces will be joined at every edge.
- *
- * \note this is a generic, flexible join faces function,
- * almost everything uses this, including #BM_faces_join_pair
- */
BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del)
{
BMFace *f, *f_new;
@@ -1422,44 +1350,6 @@ static BMFace *bm_face_create__sfme(BMesh *bm, BMFace *f_example)
return f;
}
-/**
- * \brief Split Face Make Edge (SFME)
- *
- * \warning this is a low level function, most likely you want to use #BM_face_split()
- *
- * Takes as input two vertices in a single face.
- * An edge is created which divides the original face into two distinct regions.
- * One of the regions is assigned to the original face and it is closed off.
- * The second region has a new face assigned to it.
- *
- * \par Examples:
- * <pre>
- * Before: After:
- * +--------+ +--------+
- * | | | |
- * | | | f1 |
- * v1 f1 v2 v1======v2
- * | | | f2 |
- * | | | |
- * +--------+ +--------+
- * </pre>
- *
- * \note the input vertices can be part of the same edge. This will
- * result in a two edged face. This is desirable for advanced construction
- * tools and particularly essential for edge bevel. Because of this it is
- * up to the caller to decide what to do with the extra edge.
- *
- * \note If \a holes is NULL, then both faces will lose
- * all holes from the original face. Also, you cannot split between
- * a hole vert and a boundary vert; that case is handled by higher-
- * level wrapping functions (when holes are fully implemented, anyway).
- *
- * \note that holes represents which holes goes to the new face, and of
- * course this requires removing them from the existing face first, since
- * you cannot have linked list links inside multiple lists.
- *
- * \return A BMFace pointer
- */
BMFace *bmesh_kernel_split_face_make_edge(BMesh *bm,
BMFace *f,
BMLoop *l_v1,
@@ -1599,24 +1489,6 @@ BMFace *bmesh_kernel_split_face_make_edge(BMesh *bm,
return f2;
}
-/**
- * \brief Split Edge Make Vert (SEMV)
- *
- * Takes \a e edge and splits it into two, creating a new vert.
- * \a tv should be one end of \a e : the newly created edge
- * will be attached to that end and is returned in \a r_e.
- *
- * \par Examples:
- *
- * <pre>
- * E
- * Before: OV-------------TV
- * E RE
- * After: OV------NV-----TV
- * </pre>
- *
- * \return The newly created BMVert pointer.
- */
BMVert *bmesh_kernel_split_edge_make_vert(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e)
{
BMLoop *l_next;
@@ -1770,36 +1642,6 @@ BMVert *bmesh_kernel_split_edge_make_vert(BMesh *bm, BMVert *tv, BMEdge *e, BMEd
return v_new;
}
-/**
- * \brief Join Edge Kill Vert (JEKV)
- *
- * Takes an edge \a e_kill and pointer to one of its vertices \a v_kill
- * and collapses the edge on that vertex.
- *
- * \par Examples:
- *
- * <pre>
- * Before: e_old e_kill
- * +-------+-------+
- * | | |
- * v_old v_kill v_target
- *
- * After: e_old
- * +---------------+
- * | |
- * v_old v_target
- * </pre>
- *
- * \par Restrictions:
- * KV is a vertex that must have a valance of exactly two. Furthermore
- * both edges in KV's disk cycle (OE and KE) must be unique (no double edges).
- *
- * \return The resulting edge, NULL for failure.
- *
- * \note This euler has the possibility of creating
- * faces with just 2 edges. It is up to the caller to decide what to do with
- * these faces.
- */
BMEdge *bmesh_kernel_join_edge_kill_vert(BMesh *bm,
BMEdge *e_kill,
BMVert *v_kill,
@@ -1967,24 +1809,6 @@ BMEdge *bmesh_kernel_join_edge_kill_vert(BMesh *bm,
return NULL;
}
-/**
- * \brief Join Vert Kill Edge (JVKE)
- *
- * Collapse an edge, merging surrounding data.
- *
- * Unlike #BM_vert_collapse_edge & #bmesh_kernel_join_edge_kill_vert
- * which only handle 2 valence verts,
- * this can handle any number of connected edges/faces.
- *
- * <pre>
- * Before: -> After:
- * +-+-+-+ +-+-+-+
- * | | | | | \ / |
- * +-+-+-+ +--+--+
- * | | | | | / \ |
- * +-+-+-+ +-+-+-+
- * </pre>
- */
BMVert *bmesh_kernel_join_vert_kill_edge(BMesh *bm,
BMEdge *e_kill,
BMVert *v_kill,
@@ -2068,37 +1892,6 @@ BMVert *bmesh_kernel_join_vert_kill_edge(BMesh *bm,
return v_target;
}
-/**
- * \brief Join Face Kill Edge (JFKE)
- *
- * Takes two faces joined by a single 2-manifold edge and fuses them together.
- * The edge shared by the faces must not be connected to any other edges which have
- * Both faces in its radial cycle
- *
- * \par Examples:
- * <pre>
- * A B
- * +--------+ +--------+
- * | | | |
- * | f1 | | f1 |
- * v1========v2 = Ok! v1==V2==v3 == Wrong!
- * | f2 | | f2 |
- * | | | |
- * +--------+ +--------+
- * </pre>
- *
- * In the example A, faces \a f1 and \a f2 are joined by a single edge,
- * and the euler can safely be used.
- * In example B however, \a f1 and \a f2 are joined by multiple edges and will produce an error.
- * The caller in this case should call #bmesh_kernel_join_edge_kill_vert on the extra edges
- * before attempting to fuse \a f1 and \a f2.
- *
- * \note The order of arguments decides whether or not certain per-face attributes are present
- * in the resultant face. For instance vertex winding, material index, smooth flags,
- * etc are inherited from \a f1, not \a f2.
- *
- * \return A BMFace pointer
- */
BMFace *bmesh_kernel_join_face_kill_edge(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e)
{
BMLoop *l_iter, *l_f1 = NULL, *l_f2 = NULL;
@@ -2221,11 +2014,6 @@ BMFace *bmesh_kernel_join_face_kill_edge(BMesh *bm, BMFace *f1, BMFace *f2, BMEd
return f1;
}
-/**
- * Check if splicing vertices would create any double edges.
- *
- * \note assume caller will handle case where verts share an edge.
- */
bool BM_vert_splice_check_double(BMVert *v_a, BMVert *v_b)
{
bool is_double = false;
@@ -2269,18 +2057,6 @@ bool BM_vert_splice_check_double(BMVert *v_a, BMVert *v_b)
return is_double;
}
-/**
- * \brief Splice Vert
- *
- * Merges two verts into one
- * (\a v_src into \a v_dst, removing \a v_src).
- *
- * \return Success
- *
- * \warning This doesn't work for collapsing edges,
- * where \a v and \a vtarget are connected by an edge
- * (assert checks for this case).
- */
bool BM_vert_splice(BMesh *bm, BMVert *v_dst, BMVert *v_src)
{
BMEdge *e;
@@ -2317,17 +2093,6 @@ BLI_INLINE bool bm_edge_supports_separate(const BMEdge *e)
return (e->l && e->l->radial_next != e->l);
}
-/**
- * \brief Separate Vert
- *
- * Separates all disjoint fans that meet at a vertex, making a unique
- * vertex for each region. returns an array of all resulting vertices.
- *
- * \note this is a low level function, bm_edge_separate needs to run on edges first
- * or, the faces sharing verts must not be sharing edges for them to split at least.
- *
- * \return Success
- */
void bmesh_kernel_vert_separate(
BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len, const bool copy_select)
{
@@ -2480,9 +2245,6 @@ static void bmesh_kernel_vert_separate__cleanup(BMesh *bm, LinkNode *edges_separ
} while ((edges_separate = edges_separate->next));
}
-/**
- * High level function which wraps both #bmesh_kernel_vert_separate and #bmesh_kernel_edge_separate
- */
void BM_vert_separate(BMesh *bm,
BMVert *v,
BMEdge **e_in,
@@ -2516,9 +2278,6 @@ void BM_vert_separate(BMesh *bm,
}
}
-/**
- * A version of #BM_vert_separate which takes a flag.
- */
void BM_vert_separate_hflag(BMesh *bm,
BMVert *v,
const char hflag,
@@ -2584,16 +2343,6 @@ void BM_vert_separate_tested_edges(BMesh *UNUSED(bm),
/** \} */
-/**
- * \brief Splice Edge
- *
- * Splice two unique edges which share the same two vertices into one edge.
- * (\a e_src into \a e_dst, removing e_src).
- *
- * \return Success
- *
- * \note Edges must already have the same vertices.
- */
bool BM_edge_splice(BMesh *bm, BMEdge *e_dst, BMEdge *e_src)
{
BMLoop *l;
@@ -2627,17 +2376,6 @@ bool BM_edge_splice(BMesh *bm, BMEdge *e_dst, BMEdge *e_src)
return true;
}
-/**
- * \brief Separate Edge
- *
- * Separates a single edge into two edge: the original edge and
- * a new edge that has only \a l_sep in its radial.
- *
- * \return Success
- *
- * \note Does nothing if \a l_sep is already the only loop in the
- * edge radial.
- */
void bmesh_kernel_edge_separate(BMesh *bm, BMEdge *e, BMLoop *l_sep, const bool copy_select)
{
BMEdge *e_new;
@@ -2673,15 +2411,6 @@ void bmesh_kernel_edge_separate(BMesh *bm, BMEdge *e, BMLoop *l_sep, const bool
BM_CHECK_ELEMENT(e);
}
-/**
- * \brief Un-glue Region Make Vert (URMV)
- *
- * Disconnects a face from its vertex fan at loop \a l_sep
- *
- * \return The newly created BMVert
- *
- * \note Will be a no-op and return original vertex if only two edges at that vertex.
- */
BMVert *bmesh_kernel_unglue_region_make_vert(BMesh *bm, BMLoop *l_sep)
{
BMVert *v_new = NULL;
@@ -2744,13 +2473,6 @@ BMVert *bmesh_kernel_unglue_region_make_vert(BMesh *bm, BMLoop *l_sep)
return v_new;
}
-/**
- * A version of #bmesh_kernel_unglue_region_make_vert that disconnects multiple loops at once.
- * The loops must all share the same vertex, can be in any order
- * and are all moved to use a single new vertex - which is returned.
- *
- * This function handles the details of finding fans boundaries.
- */
BMVert *bmesh_kernel_unglue_region_make_vert_multi(BMesh *bm, BMLoop **larr, int larr_len)
{
BMVert *v_sep = larr[0]->v;
@@ -2931,10 +2653,6 @@ static void bmesh_edge_vert_swap__recursive(BMEdge *e, BMVert *v_dst, BMVert *v_
} while ((l_iter = l_iter->radial_next) != l_first);
}
-/**
- * This function assumes l_sep is a part of a larger fan which has already been
- * isolated by calling #bmesh_kernel_edge_separate to segregate it radially.
- */
BMVert *bmesh_kernel_unglue_region_make_vert_multi_isolated(BMesh *bm, BMLoop *l_sep)
{
BMVert *v_new = BM_vert_create(bm, l_sep->v->co, l_sep->v, BM_CREATE_NOP);
@@ -2944,11 +2662,6 @@ BMVert *bmesh_kernel_unglue_region_make_vert_multi_isolated(BMesh *bm, BMLoop *l
return v_new;
}
-/**
- * Avoid calling this where possible,
- * low level function so both face pointers remain intact but point to swapped data.
- * \note must be from the same bmesh.
- */
void bmesh_face_swap_data(BMFace *f_a, BMFace *f_b)
{
BMLoop *l_iter, *l_first;
diff --git a/source/blender/bmesh/intern/bmesh_core.h b/source/blender/bmesh/intern/bmesh_core.h
index 8f7580714ae..cd0e1754cd1 100644
--- a/source/blender/bmesh/intern/bmesh_core.h
+++ b/source/blender/bmesh/intern/bmesh_core.h
@@ -25,26 +25,50 @@ BMFace *BM_face_copy(
typedef enum eBMCreateFlag {
BM_CREATE_NOP = 0,
- /* faces and edges only */
+ /** Faces and edges only. */
BM_CREATE_NO_DOUBLE = (1 << 1),
- /* Skip CustomData - for all element types data,
- * use if we immediately write customdata into the element so this skips copying from 'example'
- * args or setting defaults, speeds up conversion when data is converted all at once. */
+ /**
+ * Skip custom-data - for all element types data,
+ * use if we immediately write custom-data into the element so this skips copying from 'example'
+ * arguments or setting defaults, speeds up conversion when data is converted all at once.
+ */
BM_CREATE_SKIP_CD = (1 << 2),
} eBMCreateFlag;
+/**
+ * \brief Main function for creating a new vertex.
+ */
BMVert *BM_vert_create(BMesh *bm,
const float co[3],
const BMVert *v_example,
const eBMCreateFlag create_flag);
+/**
+ * \brief Main function for creating a new edge.
+ *
+ * \note Duplicate edges are supported by the API however users should _never_ see them.
+ * so unless you need a unique edge or know the edge won't exist,
+ * you should call with \a no_double = true.
+ */
BMEdge *BM_edge_create(
BMesh *bm, BMVert *v1, BMVert *v2, const BMEdge *e_example, const eBMCreateFlag create_flag);
+/**
+ * Main face creation function
+ *
+ * \param bm: The mesh
+ * \param verts: A sorted array of verts size of len
+ * \param edges: A sorted array of edges size of len
+ * \param len: Length of the face
+ * \param create_flag: Options for creating the face
+ */
BMFace *BM_face_create(BMesh *bm,
BMVert **verts,
BMEdge **edges,
const int len,
const BMFace *f_example,
const eBMCreateFlag create_flag);
+/**
+ * Wrapper for #BM_face_create when you don't have an edge array
+ */
BMFace *BM_face_create_verts(BMesh *bm,
BMVert **vert_arr,
const int len,
@@ -52,27 +76,105 @@ BMFace *BM_face_create_verts(BMesh *bm,
const eBMCreateFlag create_flag,
const bool create_edges);
+/**
+ * Kills all edges associated with \a f, along with any other faces containing those edges.
+ */
void BM_face_edges_kill(BMesh *bm, BMFace *f);
+/**
+ * kills all verts associated with \a f, along with any other faces containing
+ * those vertices
+ */
void BM_face_verts_kill(BMesh *bm, BMFace *f);
+/**
+ * A version of #BM_face_kill which removes edges and verts
+ * which have no remaining connected geometry.
+ */
void BM_face_kill_loose(BMesh *bm, BMFace *f);
+/**
+ * Kills \a f and its loops.
+ */
void BM_face_kill(BMesh *bm, BMFace *f);
+/**
+ * Kills \a e and all faces that use it.
+ */
void BM_edge_kill(BMesh *bm, BMEdge *e);
+/**
+ * Kills \a v and all edges that use it.
+ */
void BM_vert_kill(BMesh *bm, BMVert *v);
+/**
+ * \brief Splice Edge
+ *
+ * Splice two unique edges which share the same two vertices into one edge.
+ * (\a e_src into \a e_dst, removing e_src).
+ *
+ * \return Success
+ *
+ * \note Edges must already have the same vertices.
+ */
bool BM_edge_splice(BMesh *bm, BMEdge *e_dst, BMEdge *e_src);
+/**
+ * \brief Splice Vert
+ *
+ * Merges two verts into one
+ * (\a v_src into \a v_dst, removing \a v_src).
+ *
+ * \return Success
+ *
+ * \warning This doesn't work for collapsing edges,
+ * where \a v and \a vtarget are connected by an edge
+ * (assert checks for this case).
+ */
bool BM_vert_splice(BMesh *bm, BMVert *v_dst, BMVert *v_src);
+/**
+ * Check if splicing vertices would create any double edges.
+ *
+ * \note assume caller will handle case where verts share an edge.
+ */
bool BM_vert_splice_check_double(BMVert *v_a, BMVert *v_b);
+/**
+ * \brief Loop Reverse
+ *
+ * Changes the winding order of a face from CW to CCW or vice versa.
+ *
+ * \param cd_loop_mdisp_offset: Cached result of `CustomData_get_offset(&bm->ldata, CD_MDISPS)`.
+ * \param use_loop_mdisp_flip: When set, flip the Z-depth of the mdisp,
+ * (use when flipping normals, disable when mirroring, eg: symmetrize).
+ */
void bmesh_kernel_loop_reverse(BMesh *bm,
BMFace *f,
const int cd_loop_mdisp_offset,
const bool use_loop_mdisp_flip);
+/**
+ * Avoid calling this where possible,
+ * low level function so both face pointers remain intact but point to swapped data.
+ * \note must be from the same bmesh.
+ */
void bmesh_face_swap_data(BMFace *f_a, BMFace *f_b);
+/**
+ * \brief Join Connected Faces
+ *
+ * Joins a collected group of faces into one. Only restriction on
+ * the input data is that the faces must be connected to each other.
+ *
+ * \return The newly created combine BMFace.
+ *
+ * \note If a pair of faces share multiple edges,
+ * the pair of faces will be joined at every edge.
+ *
+ * \note this is a generic, flexible join faces function,
+ * almost everything uses this, including #BM_faces_join_pair
+ */
BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del);
+/**
+ * High level function which wraps both #bmesh_kernel_vert_separate and #bmesh_kernel_edge_separate
+ */
void BM_vert_separate(BMesh *bm,
BMVert *v,
BMEdge **e_in,
@@ -80,6 +182,9 @@ void BM_vert_separate(BMesh *bm,
const bool copy_select,
BMVert ***r_vout,
int *r_vout_len);
+/**
+ * A version of #BM_vert_separate which takes a flag.
+ */
void BM_vert_separate_hflag(BMesh *bm,
BMVert *v,
const char hflag,
@@ -94,10 +199,70 @@ void BM_vert_separate_tested_edges(
*
* Names are on the verbose side but these are only for low-level access.
*/
+/**
+ * \brief Separate Vert
+ *
+ * Separates all disjoint fans that meet at a vertex, making a unique
+ * vertex for each region. returns an array of all resulting vertices.
+ *
+ * \note this is a low level function, bm_edge_separate needs to run on edges first
+ * or, the faces sharing verts must not be sharing edges for them to split at least.
+ *
+ * \return Success
+ */
void bmesh_kernel_vert_separate(
BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len, const bool copy_select);
+/**
+ * \brief Separate Edge
+ *
+ * Separates a single edge into two edge: the original edge and
+ * a new edge that has only \a l_sep in its radial.
+ *
+ * \return Success
+ *
+ * \note Does nothing if \a l_sep is already the only loop in the
+ * edge radial.
+ */
void bmesh_kernel_edge_separate(BMesh *bm, BMEdge *e, BMLoop *l_sep, const bool copy_select);
+/**
+ * \brief Split Face Make Edge (SFME)
+ *
+ * \warning this is a low level function, most likely you want to use #BM_face_split()
+ *
+ * Takes as input two vertices in a single face.
+ * An edge is created which divides the original face into two distinct regions.
+ * One of the regions is assigned to the original face and it is closed off.
+ * The second region has a new face assigned to it.
+ *
+ * \par Examples:
+ * <pre>
+ * Before: After:
+ * +--------+ +--------+
+ * | | | |
+ * | | | f1 |
+ * v1 f1 v2 v1======v2
+ * | | | f2 |
+ * | | | |
+ * +--------+ +--------+
+ * </pre>
+ *
+ * \note the input vertices can be part of the same edge. This will
+ * result in a two edged face. This is desirable for advanced construction
+ * tools and particularly essential for edge bevel. Because of this it is
+ * up to the caller to decide what to do with the extra edge.
+ *
+ * \note If \a holes is NULL, then both faces will lose
+ * all holes from the original face. Also, you cannot split between
+ * a hole vert and a boundary vert; that case is handled by higher-
+ * level wrapping functions (when holes are fully implemented, anyway).
+ *
+ * \note that holes represents which holes goes to the new face, and of
+ * course this requires removing them from the existing face first, since
+ * you cannot have linked list links inside multiple lists.
+ *
+ * \return A BMFace pointer
+ */
BMFace *bmesh_kernel_split_face_make_edge(BMesh *bm,
BMFace *f,
BMLoop *l_v1,
@@ -109,7 +274,55 @@ BMFace *bmesh_kernel_split_face_make_edge(BMesh *bm,
BMEdge *example,
const bool no_double);
+/**
+ * \brief Split Edge Make Vert (SEMV)
+ *
+ * Takes \a e edge and splits it into two, creating a new vert.
+ * \a tv should be one end of \a e : the newly created edge
+ * will be attached to that end and is returned in \a r_e.
+ *
+ * \par Examples:
+ *
+ * <pre>
+ * E
+ * Before: OV-------------TV
+ * E RE
+ * After: OV------NV-----TV
+ * </pre>
+ *
+ * \return The newly created BMVert pointer.
+ */
BMVert *bmesh_kernel_split_edge_make_vert(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e);
+/**
+ * \brief Join Edge Kill Vert (JEKV)
+ *
+ * Takes an edge \a e_kill and pointer to one of its vertices \a v_kill
+ * and collapses the edge on that vertex.
+ *
+ * \par Examples:
+ *
+ * <pre>
+ * Before: e_old e_kill
+ * +-------+-------+
+ * | | |
+ * v_old v_kill v_target
+ *
+ * After: e_old
+ * +---------------+
+ * | |
+ * v_old v_target
+ * </pre>
+ *
+ * \par Restrictions:
+ * KV is a vertex that must have a valance of exactly two. Furthermore
+ * both edges in KV's disk cycle (OE and KE) must be unique (no double edges).
+ *
+ * \return The resulting edge, NULL for failure.
+ *
+ * \note This euler has the possibility of creating
+ * faces with just 2 edges. It is up to the caller to decide what to do with
+ * these faces.
+ */
BMEdge *bmesh_kernel_join_edge_kill_vert(BMesh *bm,
BMEdge *e_kill,
BMVert *v_kill,
@@ -117,14 +330,83 @@ BMEdge *bmesh_kernel_join_edge_kill_vert(BMesh *bm,
const bool check_edge_exists,
const bool kill_degenerate_faces,
const bool kill_duplicate_faces);
+/**
+ * \brief Join Vert Kill Edge (JVKE)
+ *
+ * Collapse an edge, merging surrounding data.
+ *
+ * Unlike #BM_vert_collapse_edge & #bmesh_kernel_join_edge_kill_vert
+ * which only handle 2 valence verts,
+ * this can handle any number of connected edges/faces.
+ *
+ * <pre>
+ * Before: -> After:
+ * +-+-+-+ +-+-+-+
+ * | | | | | \ / |
+ * +-+-+-+ +--+--+
+ * | | | | | / \ |
+ * +-+-+-+ +-+-+-+
+ * </pre>
+ */
BMVert *bmesh_kernel_join_vert_kill_edge(BMesh *bm,
BMEdge *e_kill,
BMVert *v_kill,
const bool do_del,
const bool check_edge_exists,
const bool kill_degenerate_faces);
+/**
+ * \brief Join Face Kill Edge (JFKE)
+ *
+ * Takes two faces joined by a single 2-manifold edge and fuses them together.
+ * The edge shared by the faces must not be connected to any other edges which have
+ * Both faces in its radial cycle
+ *
+ * \par Examples:
+ * <pre>
+ * A B
+ * +--------+ +--------+
+ * | | | |
+ * | f1 | | f1 |
+ * v1========v2 = Ok! v1==V2==v3 == Wrong!
+ * | f2 | | f2 |
+ * | | | |
+ * +--------+ +--------+
+ * </pre>
+ *
+ * In the example A, faces \a f1 and \a f2 are joined by a single edge,
+ * and the euler can safely be used.
+ * In example B however, \a f1 and \a f2 are joined by multiple edges and will produce an error.
+ * The caller in this case should call #bmesh_kernel_join_edge_kill_vert on the extra edges
+ * before attempting to fuse \a f1 and \a f2.
+ *
+ * \note The order of arguments decides whether or not certain per-face attributes are present
+ * in the resultant face. For instance vertex winding, material index, smooth flags,
+ * etc are inherited from \a f1, not \a f2.
+ *
+ * \return A BMFace pointer
+ */
BMFace *bmesh_kernel_join_face_kill_edge(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e);
+/**
+ * \brief Un-glue Region Make Vert (URMV)
+ *
+ * Disconnects a face from its vertex fan at loop \a l_sep
+ *
+ * \return The newly created BMVert
+ *
+ * \note Will be a no-op and return original vertex if only two edges at that vertex.
+ */
BMVert *bmesh_kernel_unglue_region_make_vert(BMesh *bm, BMLoop *l_sep);
+/**
+ * A version of #bmesh_kernel_unglue_region_make_vert that disconnects multiple loops at once.
+ * The loops must all share the same vertex, can be in any order
+ * and are all moved to use a single new vertex - which is returned.
+ *
+ * This function handles the details of finding fans boundaries.
+ */
BMVert *bmesh_kernel_unglue_region_make_vert_multi(BMesh *bm, BMLoop **larr, int larr_len);
+/**
+ * This function assumes l_sep is a part of a larger fan which has already been
+ * isolated by calling #bmesh_kernel_edge_separate to segregate it radially.
+ */
BMVert *bmesh_kernel_unglue_region_make_vert_multi_isolated(BMesh *bm, BMLoop *l_sep);
diff --git a/source/blender/bmesh/intern/bmesh_delete.c b/source/blender/bmesh/intern/bmesh_delete.c
index 9f2fb1370bb..ae93795d51c 100644
--- a/source/blender/bmesh/intern/bmesh_delete.c
+++ b/source/blender/bmesh/intern/bmesh_delete.c
@@ -99,10 +99,6 @@ void BMO_mesh_delete_oflag_tagged(BMesh *bm, const short oflag, const char htype
}
}
-/**
- * \warning oflag applies to different types in some contexts,
- * not just the type being removed.
- */
void BMO_mesh_delete_oflag_context(BMesh *bm, const short oflag, const int type)
{
BMEdge *e;
@@ -275,10 +271,6 @@ void BM_mesh_delete_hflag_tagged(BMesh *bm, const char hflag, const char htype)
}
}
-/**
- * \warning oflag applies to different types in some contexts,
- * not just the type being removed.
- */
void BM_mesh_delete_hflag_context(BMesh *bm, const char hflag, const int type)
{
BMEdge *e;
diff --git a/source/blender/bmesh/intern/bmesh_delete.h b/source/blender/bmesh/intern/bmesh_delete.h
index fcbcb8a90fc..18e278a99fd 100644
--- a/source/blender/bmesh/intern/bmesh_delete.h
+++ b/source/blender/bmesh/intern/bmesh_delete.h
@@ -23,5 +23,13 @@
void BMO_mesh_delete_oflag_tagged(BMesh *bm, const short oflag, const char htype);
void BM_mesh_delete_hflag_tagged(BMesh *bm, const char hflag, const char htype);
+/**
+ * \warning oflag applies to different types in some contexts,
+ * not just the type being removed.
+ */
void BMO_mesh_delete_oflag_context(BMesh *bm, const short oflag, const int type);
+/**
+ * \warning oflag applies to different types in some contexts,
+ * not just the type being removed.
+ */
void BM_mesh_delete_hflag_context(BMesh *bm, const char hflag, const int type);
diff --git a/source/blender/bmesh/intern/bmesh_edgeloop.c b/source/blender/bmesh/intern/bmesh_edgeloop.c
index ab14ec23fad..3c79d2bce04 100644
--- a/source/blender/bmesh/intern/bmesh_edgeloop.c
+++ b/source/blender/bmesh/intern/bmesh_edgeloop.c
@@ -121,9 +121,6 @@ static bool bm_loop_build(BMEdgeLoopStore *el_store, BMVert *v_prev, BMVert *v,
return true;
}
-/**
- * \return listbase of listbases, each linking to a vertex.
- */
int BM_mesh_edgeloops_find(BMesh *bm,
ListBase *r_eloops,
bool (*test_fn)(BMEdge *, void *user_data),
@@ -506,7 +503,6 @@ void BM_mesh_edgeloops_calc_order(BMesh *UNUSED(bm), ListBase *eloops, const boo
/* -------------------------------------------------------------------- */
/* BM_edgeloop_*** functions */
-/* return new edgeloops */
BMEdgeLoopStore *BM_edgeloop_copy(BMEdgeLoopStore *el_store)
{
BMEdgeLoopStore *el_store_copy = MEM_mallocN(sizeof(*el_store), __func__);
@@ -565,9 +561,6 @@ const float *BM_edgeloop_center_get(struct BMEdgeLoopStore *el_store)
#define NODE_AS_V(n) ((BMVert *)((LinkData *)n)->data)
#define NODE_AS_CO(n) ((BMVert *)((LinkData *)n)->data)->co
-/**
- * edges are assigned to one vert -> the next.
- */
void BM_edgeloop_edges_get(struct BMEdgeLoopStore *el_store, BMEdge **e_arr)
{
LinkData *node;
@@ -653,12 +646,6 @@ bool BM_edgeloop_calc_normal(BMesh *UNUSED(bm), BMEdgeLoopStore *el_store)
return true;
}
-/**
- * For open loops that are straight lines,
- * calculating the normal as if it were a polygon is meaningless.
- *
- * Instead use an alignment vector and calculate the normal based on that.
- */
bool BM_edgeloop_calc_normal_aligned(BMesh *UNUSED(bm),
BMEdgeLoopStore *el_store,
const float no_align[3])
diff --git a/source/blender/bmesh/intern/bmesh_edgeloop.h b/source/blender/bmesh/intern/bmesh_edgeloop.h
index 34fc4c0ccc1..58b0d92fb72 100644
--- a/source/blender/bmesh/intern/bmesh_edgeloop.h
+++ b/source/blender/bmesh/intern/bmesh_edgeloop.h
@@ -28,6 +28,9 @@ struct GSet;
struct ListBase;
/* multiple edgeloops (ListBase) */
+/**
+ * \return listbase of listbases, each linking to a vertex.
+ */
int BM_mesh_edgeloops_find(BMesh *bm,
struct ListBase *r_eloops,
bool (*test_fn)(BMEdge *, void *user_data),
@@ -47,7 +50,10 @@ void BM_mesh_edgeloops_calc_normal_aligned(BMesh *bm,
const float no_align[3]);
void BM_mesh_edgeloops_calc_order(BMesh *bm, ListBase *eloops, const bool use_normals);
-/* single edgeloop */
+/**
+ * Copy a single edge-loop.
+ * \return new edge-loops.
+ */
struct BMEdgeLoopStore *BM_edgeloop_copy(struct BMEdgeLoopStore *el_store);
struct BMEdgeLoopStore *BM_edgeloop_from_verts(BMVert **v_arr,
const int v_arr_tot,
@@ -59,9 +65,18 @@ int BM_edgeloop_length_get(struct BMEdgeLoopStore *el_store);
struct ListBase *BM_edgeloop_verts_get(struct BMEdgeLoopStore *el_store);
const float *BM_edgeloop_normal_get(struct BMEdgeLoopStore *el_store);
const float *BM_edgeloop_center_get(struct BMEdgeLoopStore *el_store);
+/**
+ * Edges are assigned to one vert -> the next.
+ */
void BM_edgeloop_edges_get(struct BMEdgeLoopStore *el_store, BMEdge **e_arr);
void BM_edgeloop_calc_center(BMesh *bm, struct BMEdgeLoopStore *el_store);
bool BM_edgeloop_calc_normal(BMesh *bm, struct BMEdgeLoopStore *el_store);
+/**
+ * For open loops that are straight lines,
+ * calculating the normal as if it were a polygon is meaningless.
+ *
+ * Instead use an alignment vector and calculate the normal based on that.
+ */
bool BM_edgeloop_calc_normal_aligned(BMesh *bm,
struct BMEdgeLoopStore *el_store,
const float no_align[3]);
diff --git a/source/blender/bmesh/intern/bmesh_error.h b/source/blender/bmesh/intern/bmesh_error.h
index 7694d4dbfb6..68ec3fe3ee8 100644
--- a/source/blender/bmesh/intern/bmesh_error.h
+++ b/source/blender/bmesh/intern/bmesh_error.h
@@ -48,13 +48,17 @@ typedef enum eBMOpErrorLevel {
BMO_ERROR_FATAL = 2,
} eBMOpErrorLevel;
-/* Pushes an error onto the bmesh error stack.
- * if msg is null, then the default message for the `errcode` is used. */
+/**
+ * Pushes an error onto the bmesh error stack.
+ * if msg is null, then the default message for the `errcode` is used.
+ */
void BMO_error_raise(BMesh *bm, BMOperator *owner, eBMOpErrorLevel level, const char *msg)
ATTR_NONNULL(1, 2, 4);
-/* Gets the topmost error from the stack.
- * returns error code or 0 if no error. */
+/**
+ * Gets the topmost error from the stack.
+ * returns error code or 0 if no error.
+ */
bool BMO_error_get(BMesh *bm, const char **r_msg, BMOperator **r_op, eBMOpErrorLevel *r_level);
bool BMO_error_get_at_level(BMesh *bm,
eBMOpErrorLevel level,
@@ -83,8 +87,10 @@ void BMO_error_clear(BMesh *bm);
# define _BMESH_DUMMY_ABORT() (void)0
#endif
-/* This is meant to be higher level than BLI_assert(),
- * its enabled even when in Release mode. */
+/**
+ * This is meant to be higher level than BLI_assert(),
+ * its enabled even when in Release mode.
+ */
#define BMESH_ASSERT(a) \
(void)((!(a)) ? ((fprintf(stderr, \
"BMESH_ASSERT failed: %s, %s(), %d at \'%s\'\n", \
diff --git a/source/blender/bmesh/intern/bmesh_interp.c b/source/blender/bmesh/intern/bmesh_interp.c
index 288c5fa8158..a1bcd8e6258 100644
--- a/source/blender/bmesh/intern/bmesh_interp.c
+++ b/source/blender/bmesh/intern/bmesh_interp.c
@@ -81,13 +81,6 @@ static void bm_data_interp_from_elem(CustomData *data_layer,
}
}
-/**
- * \brief Data, Interp From Verts
- *
- * Interpolates per-vertex data from two sources to \a v_dst
- *
- * \note This is an exact match to #BM_data_interp_from_edges
- */
void BM_data_interp_from_verts(
BMesh *bm, const BMVert *v_src_1, const BMVert *v_src_2, BMVert *v_dst, const float fac)
{
@@ -95,13 +88,6 @@ void BM_data_interp_from_verts(
&bm->vdata, (const BMElem *)v_src_1, (const BMElem *)v_src_2, (BMElem *)v_dst, fac);
}
-/**
- * \brief Data, Interp From Edges
- *
- * Interpolates per-edge data from two sources to \a e_dst.
- *
- * \note This is an exact match to #BM_data_interp_from_verts
- */
void BM_data_interp_from_edges(
BMesh *bm, const BMEdge *e_src_1, const BMEdge *e_src_2, BMEdge *e_dst, const float fac)
{
@@ -120,12 +106,6 @@ static void UNUSED_FUNCTION(BM_Data_Vert_Average)(BMesh *UNUSED(bm), BMFace *UNU
// BMIter iter;
}
-/**
- * \brief Data Face-Vert Edge Interp
- *
- * Walks around the faces of \a e and interpolates
- * the loop data between two sources.
- */
void BM_data_interp_face_vert_edge(BMesh *bm,
const BMVert *v_src_1,
const BMVert *UNUSED(v_src_2),
@@ -169,14 +149,6 @@ void BM_data_interp_face_vert_edge(BMesh *bm,
} while ((l_iter = l_iter->radial_next) != e->l);
}
-/**
- * \brief Data Interp From Face
- *
- * projects target onto source, and pulls interpolated customdata from
- * source.
- *
- * \note Only handles loop customdata. multires is handled.
- */
void BM_face_interp_from_face_ex(BMesh *bm,
BMFace *f_dst,
const BMFace *f_src,
@@ -570,9 +542,6 @@ void BM_loop_interp_multires_ex(BMesh *UNUSED(bm),
BLI_task_parallel_range(0, res, &data, loop_interp_multires_cb, &settings);
}
-/**
- * project the multires grid in target onto f_src's set of multires grids
- */
void BM_loop_interp_multires(BMesh *bm, BMLoop *l_dst, const BMFace *f_src)
{
const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
@@ -618,10 +587,6 @@ void BM_face_interp_multires(BMesh *bm, BMFace *f_dst, const BMFace *f_src)
}
}
-/**
- * smooths boundaries between multires grids,
- * including some borders in adjacent faces
- */
void BM_face_multires_bounds_smooth(BMesh *bm, BMFace *f)
{
const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
@@ -730,10 +695,6 @@ void BM_face_multires_bounds_smooth(BMesh *bm, BMFace *f)
}
}
-/**
- * projects a single loop, target, onto f_src for customdata interpolation. multires is handled.
- * if do_vertex is true, target's vert data will also get interpolated.
- */
void BM_loop_interp_from_face(
BMesh *bm, BMLoop *l_dst, const BMFace *f_src, const bool do_vertex, const bool do_multires)
{
@@ -1246,9 +1207,6 @@ static void bm_vert_loop_groups_data_layer_merge_weights__single(
}
}
-/**
- * Take existing custom data and merge each fan's data.
- */
void BM_vert_loop_groups_data_layer_merge(BMesh *bm, LinkNode *groups, const int layer_n)
{
const int type = bm->ldata.layers[layer_n].type;
@@ -1260,10 +1218,6 @@ void BM_vert_loop_groups_data_layer_merge(BMesh *bm, LinkNode *groups, const int
} while ((groups = groups->next));
}
-/**
- * A version of #BM_vert_loop_groups_data_layer_merge
- * that takes an array of loop-weights (aligned with #BM_LOOPS_OF_VERT iterator)
- */
void BM_vert_loop_groups_data_layer_merge_weights(BMesh *bm,
LinkNode *groups,
const int layer_n,
diff --git a/source/blender/bmesh/intern/bmesh_interp.h b/source/blender/bmesh/intern/bmesh_interp.h
index c77281bd798..d1a73509a4a 100644
--- a/source/blender/bmesh/intern/bmesh_interp.h
+++ b/source/blender/bmesh/intern/bmesh_interp.h
@@ -29,6 +29,9 @@ void BM_loop_interp_multires_ex(BMesh *bm,
const float f_dst_center[3],
const float f_src_center[3],
const int cd_loop_mdisp_offset);
+/**
+ * Project the multi-resolution grid in target onto f_src's set of multi-resolution grids.
+ */
void BM_loop_interp_multires(BMesh *bm, BMLoop *l_dst, const BMFace *f_src);
void BM_face_interp_multires_ex(BMesh *bm,
@@ -41,10 +44,30 @@ void BM_face_interp_multires(BMesh *bm, BMFace *f_dst, const BMFace *f_src);
void BM_vert_interp_from_face(BMesh *bm, BMVert *v_dst, const BMFace *f_src);
+/**
+ * \brief Data, Interpolate From Verts
+ *
+ * Interpolates per-vertex data from two sources to \a v_dst
+ *
+ * \note This is an exact match to #BM_data_interp_from_edges.
+ */
void BM_data_interp_from_verts(
BMesh *bm, const BMVert *v_src_1, const BMVert *v_src_2, BMVert *v_dst, const float fac);
+/**
+ * \brief Data, Interpolate From Edges
+ *
+ * Interpolates per-edge data from two sources to \a e_dst.
+ *
+ * \note This is an exact match to #BM_data_interp_from_verts.
+ */
void BM_data_interp_from_edges(
BMesh *bm, const BMEdge *e_src_1, const BMEdge *e_src_2, BMEdge *e_dst, const float fac);
+/**
+ * \brief Data Face-Vert Edge Interpolate
+ *
+ * Walks around the faces of \a e and interpolates
+ * the loop data between two sources.
+ */
void BM_data_interp_face_vert_edge(BMesh *bm,
const BMVert *v_src_1,
const BMVert *v_src_2,
@@ -60,6 +83,13 @@ void BM_data_layer_copy(BMesh *bm, CustomData *data, int type, int src_n, int ds
float BM_elem_float_data_get(CustomData *cd, void *element, int type);
void BM_elem_float_data_set(CustomData *cd, void *element, int type, const float val);
+/**
+ * \brief Data Interpolate From Face
+ *
+ * Projects target onto source, and pulls interpolated custom-data from source.
+ *
+ * \note Only handles loop custom-data. multi-res is handled.
+ */
void BM_face_interp_from_face_ex(BMesh *bm,
BMFace *f_dst,
const BMFace *f_src,
@@ -69,14 +99,30 @@ void BM_face_interp_from_face_ex(BMesh *bm,
float (*cos_2d)[2],
float axis_mat[3][3]);
void BM_face_interp_from_face(BMesh *bm, BMFace *f_dst, const BMFace *f_src, const bool do_vertex);
+/**
+ * Projects a single loop, target, onto f_src for custom-data interpolation.
+ * multi-resolution is handled.
+ * \param do_vertex: When true the target's vert data will also get interpolated.
+ */
void BM_loop_interp_from_face(
BMesh *bm, BMLoop *l_dst, const BMFace *f_src, const bool do_vertex, const bool do_multires);
+/**
+ * Smooths boundaries between multi-res grids,
+ * including some borders in adjacent faces.
+ */
void BM_face_multires_bounds_smooth(BMesh *bm, BMFace *f);
struct LinkNode *BM_vert_loop_groups_data_layer_create(
BMesh *bm, BMVert *v, const int layer_n, const float *loop_weights, struct MemArena *arena);
+/**
+ * Take existing custom data and merge each fan's data.
+ */
void BM_vert_loop_groups_data_layer_merge(BMesh *bm, struct LinkNode *groups, const int layer_n);
+/**
+ * A version of #BM_vert_loop_groups_data_layer_merge
+ * that takes an array of loop-weights (aligned with #BM_LOOPS_OF_VERT iterator).
+ */
void BM_vert_loop_groups_data_layer_merge_weights(BMesh *bm,
struct LinkNode *groups,
const int layer_n,
diff --git a/source/blender/bmesh/intern/bmesh_iterators.c b/source/blender/bmesh/intern/bmesh_iterators.c
index bd28022de4b..6a27e54c6a6 100644
--- a/source/blender/bmesh/intern/bmesh_iterators.c
+++ b/source/blender/bmesh/intern/bmesh_iterators.c
@@ -47,9 +47,6 @@ const char bm_iter_itype_htype_map[BM_ITYPE_MAX] = {
BM_LOOP, /* BM_LOOPS_OF_EDGE */
};
-/**
- * Utility function.
- */
int BM_iter_mesh_count(const char itype, BMesh *bm)
{
int count;
@@ -73,9 +70,6 @@ int BM_iter_mesh_count(const char itype, BMesh *bm)
return count;
}
-/**
- * \note Use #BM_vert_at_index / #BM_edge_at_index / #BM_face_at_index for mesh arrays.
- */
void *BM_iter_at_index(BMesh *bm, const char itype, void *data, int index)
{
BMIter iter;
@@ -98,12 +92,6 @@ void *BM_iter_at_index(BMesh *bm, const char itype, void *data, int index)
return val;
}
-/**
- * \brief Iterator as Array
- *
- * Sometimes its convenient to get the iterator as an array
- * to avoid multiple calls to #BM_iter_at_index.
- */
int BM_iter_as_array(BMesh *bm, const char itype, void *data, void **array, const int len)
{
int i = 0;
@@ -124,11 +112,6 @@ int BM_iter_as_array(BMesh *bm, const char itype, void *data, void **array, cons
return i;
}
-/**
- * \brief Operator Iterator as Array
- *
- * Sometimes its convenient to get the iterator as an array.
- */
int BMO_iter_as_array(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
const char restrictmask,
@@ -155,16 +138,6 @@ int BMO_iter_as_array(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
return i;
}
-/**
- * \brief Iterator as Array
- *
- * Allocates a new array, has the advantage that you don't need to know the size ahead of time.
- *
- * Takes advantage of less common iterator usage to avoid counting twice,
- * which you might end up doing when #BM_iter_as_array is used.
- *
- * Caller needs to free the array.
- */
void *BM_iter_as_arrayN(BMesh *bm,
const char itype,
void *data,
@@ -272,9 +245,6 @@ int BM_iter_mesh_bitmap_from_filter(const char itype,
return bitmap_enabled;
}
-/**
- * Needed when we want to check faces, but return a loop aligned array.
- */
int BM_iter_mesh_bitmap_from_filter_tessface(BMesh *bm,
BLI_bitmap *bitmap,
bool (*test_fn)(BMFace *, void *user_data),
@@ -305,11 +275,6 @@ int BM_iter_mesh_bitmap_from_filter_tessface(BMesh *bm,
return bitmap_enabled;
}
-/**
- * \brief Elem Iter Flag Count
- *
- * Counts how many flagged / unflagged items are found in this element.
- */
int BM_iter_elem_count_flag(const char itype, void *data, const char hflag, const bool value)
{
BMIter iter;
@@ -325,11 +290,6 @@ int BM_iter_elem_count_flag(const char itype, void *data, const char hflag, cons
return count;
}
-/**
- * \brief Elem Iter Tool Flag Count
- *
- * Counts how many flagged / unflagged items are found in this element.
- */
int BMO_iter_elem_count_flag(
BMesh *bm, const char itype, void *data, const short oflag, const bool value)
{
@@ -371,11 +331,6 @@ int BMO_iter_elem_count_flag(
return count;
}
-/**
- * \brief Mesh Iter Flag Count
- *
- * Counts how many flagged / unflagged items are found in this mesh.
- */
int BM_iter_mesh_count_flag(const char itype, BMesh *bm, const char hflag, const bool value)
{
BMIter iter;
diff --git a/source/blender/bmesh/intern/bmesh_iterators.h b/source/blender/bmesh/intern/bmesh_iterators.h
index ab4427e6968..12b3581b0a1 100644
--- a/source/blender/bmesh/intern/bmesh_iterators.h
+++ b/source/blender/bmesh/intern/bmesh_iterators.h
@@ -34,13 +34,6 @@
#include "BLI_compiler_attrs.h"
#include "BLI_mempool.h"
-/* Defines for passing to BM_iter_new.
- *
- * "OF" can be substituted for "around"
- * so BM_VERTS_OF_FACE means "vertices
- * around a face."
- */
-
/* these iterator over all elements of a specific
* type in the mesh.
*
@@ -75,6 +68,12 @@ typedef enum BMIterType {
/* the iterator htype for each iterator */
extern const char bm_iter_itype_htype_map[BM_ITYPE_MAX];
+/* -------------------------------------------------------------------- */
+/** \name Defines for passing to #BM_iter_new.
+ *
+ * "OF" can be substituted for "around" so #BM_VERTS_OF_FACE means "vertices* around a face."
+ * \{ */
+
#define BM_ITER_MESH(ele, iter, bm, itype) \
for (BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BM_iter_new(iter, bm, itype, NULL); ele; \
BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BM_iter_step(iter))
@@ -108,6 +107,8 @@ extern const char bm_iter_itype_htype_map[BM_ITYPE_MAX];
for (BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BM_iter_new(iter, NULL, itype, data), indexvar = 0; ele; \
BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BM_iter_step(iter), (indexvar)++)
+/** \} */
+
/* iterator type structs */
struct BMIter__elem_of_mesh {
BLI_mempool_iter pooliter;
@@ -184,14 +185,38 @@ typedef struct BMIter {
char itype;
} BMIter;
+/**
+ * \note Use #BM_vert_at_index / #BM_edge_at_index / #BM_face_at_index for mesh arrays.
+ */
void *BM_iter_at_index(BMesh *bm, const char itype, void *data, int index) ATTR_WARN_UNUSED_RESULT;
+/**
+ * \brief Iterator as Array
+ *
+ * Sometimes its convenient to get the iterator as an array
+ * to avoid multiple calls to #BM_iter_at_index.
+ */
int BM_iter_as_array(BMesh *bm, const char itype, void *data, void **array, const int len);
+/**
+ * \brief Iterator as Array
+ *
+ * Allocates a new array, has the advantage that you don't need to know the size ahead of time.
+ *
+ * Takes advantage of less common iterator usage to avoid counting twice,
+ * which you might end up doing when #BM_iter_as_array is used.
+ *
+ * Caller needs to free the array.
+ */
void *BM_iter_as_arrayN(BMesh *bm,
const char itype,
void *data,
int *r_len,
void **stack_array,
int stack_array_size) ATTR_WARN_UNUSED_RESULT;
+/**
+ * \brief Operator Iterator as Array
+ *
+ * Sometimes its convenient to get the iterator as an array.
+ */
int BMO_iter_as_array(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
const char restrictmask,
@@ -210,15 +235,36 @@ int BM_iter_mesh_bitmap_from_filter(const char itype,
uint *bitmap,
bool (*test_fn)(BMElem *, void *user_data),
void *user_data);
+/**
+ * Needed when we want to check faces, but return a loop aligned array.
+ */
int BM_iter_mesh_bitmap_from_filter_tessface(BMesh *bm,
uint *bitmap,
bool (*test_fn)(BMFace *, void *user_data),
void *user_data);
+/**
+ * \brief Elem Iter Flag Count
+ *
+ * Counts how many flagged / unflagged items are found in this element.
+ */
int BM_iter_elem_count_flag(const char itype, void *data, const char hflag, const bool value);
+/**
+ * \brief Elem Iter Tool Flag Count
+ *
+ * Counts how many flagged / unflagged items are found in this element.
+ */
int BMO_iter_elem_count_flag(
BMesh *bm, const char itype, void *data, const short oflag, const bool value);
+/**
+ * Utility function.
+ */
int BM_iter_mesh_count(const char itype, BMesh *bm);
+/**
+ * \brief Mesh Iter Flag Count
+ *
+ * Counts how many flagged / unflagged items are found in this mesh.
+ */
int BM_iter_mesh_count_flag(const char itype, BMesh *bm, const char hflag, const bool value);
/* private for bmesh_iterators_inline.c */
diff --git a/source/blender/bmesh/intern/bmesh_log.c b/source/blender/bmesh/intern/bmesh_log.c
index 9033e43374b..e667505caca 100644
--- a/source/blender/bmesh/intern/bmesh_log.c
+++ b/source/blender/bmesh/intern/bmesh_log.c
@@ -468,7 +468,6 @@ static void bm_log_id_ghash_release(BMLog *log, GHash *id_ghash)
/***************************** Public API *****************************/
-/* Allocate, initialize, and assign a new BMLog */
BMLog *BM_log_create(BMesh *bm)
{
BMLog *log = MEM_callocN(sizeof(*log), __func__);
@@ -506,14 +505,6 @@ void BM_log_cleanup_entry(BMLogEntry *entry)
}
}
-/* Allocate and initialize a new BMLog using existing BMLogEntries
- *
- * The 'entry' should be the last entry in the BMLog. Its prev pointer
- * will be followed back to find the first entry.
- *
- * The unused IDs field of the log will be initialized by taking all
- * keys from all GHashes in the log entry.
- */
BMLog *BM_log_from_existing_entries_create(BMesh *bm, BMLogEntry *entry)
{
BMLog *log = BM_log_create(bm);
@@ -555,7 +546,6 @@ BMLog *BM_log_from_existing_entries_create(BMesh *bm, BMLogEntry *entry)
return log;
}
-/* Free all the data in a BMLog including the log itself */
void BM_log_free(BMLog *log)
{
BMLogEntry *entry;
@@ -581,13 +571,11 @@ void BM_log_free(BMLog *log)
MEM_freeN(log);
}
-/* Get the number of log entries */
int BM_log_length(const BMLog *log)
{
return BLI_listbase_count(&log->entries);
}
-/* Apply a consistent ordering to BMesh vertices */
void BM_log_mesh_elems_reorder(BMesh *bm, BMLog *log)
{
uint *varr;
@@ -639,16 +627,6 @@ void BM_log_mesh_elems_reorder(BMesh *bm, BMLog *log)
MEM_freeN(farr);
}
-/* Start a new log entry and update the log entry list
- *
- * If the log entry list is empty, or if the current log entry is the
- * last entry, the new entry is simply appended to the end.
- *
- * Otherwise, the new entry is added after the current entry and all
- * following entries are deleted.
- *
- * In either case, the new entry is set as the current log entry.
- */
BMLogEntry *BM_log_entry_add(BMLog *log)
{
/* WARNING: this is now handled by the UndoSystem: BKE_UNDOSYS_TYPE_SCULPT
@@ -676,15 +654,6 @@ BMLogEntry *BM_log_entry_add(BMLog *log)
return entry;
}
-/* Remove an entry from the log
- *
- * Uses entry->log as the log. If the log is NULL, the entry will be
- * free'd but not removed from any list, nor shall its IDs be
- * released.
- *
- * This operation is only valid on the first and last entries in the
- * log. Deleting from the middle will assert.
- */
void BM_log_entry_drop(BMLogEntry *entry)
{
BMLog *log = entry->log;
@@ -751,9 +720,6 @@ void BM_log_entry_drop(BMLogEntry *entry)
BLI_freelinkN(&log->entries, entry);
}
-/* Undo one BMLogEntry
- *
- * Has no effect if there's nothing left to undo */
void BM_log_undo(BMesh *bm, BMLog *log)
{
BMLogEntry *entry = log->current_entry;
@@ -775,9 +741,6 @@ void BM_log_undo(BMesh *bm, BMLog *log)
}
}
-/* Redo one BMLogEntry
- *
- * Has no effect if there's nothing left to redo */
void BM_log_redo(BMesh *bm, BMLog *log)
{
BMLogEntry *entry = log->current_entry;
@@ -812,29 +775,6 @@ void BM_log_redo(BMesh *bm, BMLog *log)
}
}
-/* Log a vertex before it is modified
- *
- * Before modifying vertex coordinates, masks, or hflags, call this
- * function to log its current values. This is better than logging
- * after the coordinates have been modified, because only those
- * vertices that are modified need to have their original values
- * stored.
- *
- * Handles two separate cases:
- *
- * If the vertex was added in the current log entry, update the
- * vertex in the map of added vertices.
- *
- * If the vertex already existed prior to the current log entry, a
- * separate key/value map of modified vertices is used (using the
- * vertex's ID as the key). The values stored in that case are
- * the vertex's original state so that an undo can restore the
- * previous state.
- *
- * On undo, the current vertex state will be swapped with the stored
- * state so that a subsequent redo operation will restore the newer
- * vertex state.
- */
void BM_log_vert_before_modified(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
{
BMLogEntry *entry = log->current_entry;
@@ -853,12 +793,6 @@ void BM_log_vert_before_modified(BMLog *log, BMVert *v, const int cd_vert_mask_o
}
}
-/* Log a new vertex as added to the BMesh
- *
- * The new vertex gets a unique ID assigned. It is then added to a map
- * of added vertices, with the key being its ID and the value
- * containing everything needed to reconstruct that vertex.
- */
void BM_log_vert_added(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
{
BMLogVert *lv;
@@ -870,11 +804,6 @@ void BM_log_vert_added(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
BLI_ghash_insert(log->current_entry->added_verts, key, lv);
}
-/* Log a face before it is modified
- *
- * This is intended to handle only header flags and we always
- * assume face has been added before
- */
void BM_log_face_modified(BMLog *log, BMFace *f)
{
BMLogFace *lf;
@@ -885,12 +814,6 @@ void BM_log_face_modified(BMLog *log, BMFace *f)
BLI_ghash_insert(log->current_entry->modified_faces, key, lf);
}
-/* Log a new face as added to the BMesh
- *
- * The new face gets a unique ID assigned. It is then added to a map
- * of added faces, with the key being its ID and the value containing
- * everything needed to reconstruct that face.
- */
void BM_log_face_added(BMLog *log, BMFace *f)
{
BMLogFace *lf;
@@ -905,22 +828,6 @@ void BM_log_face_added(BMLog *log, BMFace *f)
BLI_ghash_insert(log->current_entry->added_faces, key, lf);
}
-/* Log a vertex as removed from the BMesh
- *
- * A couple things can happen here:
- *
- * If the vertex was added as part of the current log entry, then it's
- * deleted and forgotten about entirely. Its unique ID is returned to
- * the unused pool.
- *
- * If the vertex was already part of the BMesh before the current log
- * entry, it is added to a map of deleted vertices, with the key being
- * its ID and the value containing everything needed to reconstruct
- * that vertex.
- *
- * If there's a move record for the vertex, that's used as the
- * vertices original location, then the move record is deleted.
- */
void BM_log_vert_removed(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
{
BMLogEntry *entry = log->current_entry;
@@ -949,19 +856,6 @@ void BM_log_vert_removed(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
}
}
-/* Log a face as removed from the BMesh
- *
- * A couple things can happen here:
- *
- * If the face was added as part of the current log entry, then it's
- * deleted and forgotten about entirely. Its unique ID is returned to
- * the unused pool.
- *
- * If the face was already part of the BMesh before the current log
- * entry, it is added to a map of deleted faces, with the key being
- * its ID and the value containing everything needed to reconstruct
- * that face.
- */
void BM_log_face_removed(BMLog *log, BMFace *f)
{
BMLogEntry *entry = log->current_entry;
@@ -983,7 +877,6 @@ void BM_log_face_removed(BMLog *log, BMFace *f)
}
}
-/* Log all vertices/faces in the BMesh as added */
void BM_log_all_added(BMesh *bm, BMLog *log)
{
const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
@@ -1011,7 +904,6 @@ void BM_log_all_added(BMesh *bm, BMLog *log)
}
}
-/* Log all vertices/faces in the BMesh as removed */
void BM_log_before_all_removed(BMesh *bm, BMLog *log)
{
const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
@@ -1030,9 +922,6 @@ void BM_log_before_all_removed(BMesh *bm, BMLog *log)
}
}
-/* Get the logged coordinates of a vertex
- *
- * Does not modify the log or the vertex */
const float *BM_log_original_vert_co(BMLog *log, BMVert *v)
{
BMLogEntry *entry = log->current_entry;
@@ -1048,9 +937,6 @@ const float *BM_log_original_vert_co(BMLog *log, BMVert *v)
return lv->co;
}
-/* Get the logged normal of a vertex
- *
- * Does not modify the log or the vertex */
const short *BM_log_original_vert_no(BMLog *log, BMVert *v)
{
BMLogEntry *entry = log->current_entry;
@@ -1066,9 +952,6 @@ const short *BM_log_original_vert_no(BMLog *log, BMVert *v)
return lv->no;
}
-/* Get the logged mask of a vertex
- *
- * Does not modify the log or the vertex */
float BM_log_original_mask(BMLog *log, BMVert *v)
{
BMLogEntry *entry = log->current_entry;
@@ -1102,13 +985,11 @@ void BM_log_original_vert_data(BMLog *log, BMVert *v, const float **r_co, const
/************************ Debugging and Testing ***********************/
-/* For internal use only (unit testing) */
BMLogEntry *BM_log_current_entry(BMLog *log)
{
return log->current_entry;
}
-/* For internal use only (unit testing) */
RangeTreeUInt *BM_log_unused_ids(BMLog *log)
{
return log->unused_ids;
diff --git a/source/blender/bmesh/intern/bmesh_log.h b/source/blender/bmesh/intern/bmesh_log.h
index 5c0ca78bddf..c6df87168ee 100644
--- a/source/blender/bmesh/intern/bmesh_log.h
+++ b/source/blender/bmesh/intern/bmesh_log.h
@@ -29,71 +29,190 @@ typedef struct BMLog BMLog;
typedef struct BMLogEntry BMLogEntry;
/* Allocate and initialize a new BMLog */
+/* Allocate, initialize, and assign a new BMLog */
BMLog *BM_log_create(BMesh *bm);
/* Allocate and initialize a new BMLog using existing BMLogEntries */
+/* Allocate and initialize a new BMLog using existing BMLogEntries
+ *
+ * The 'entry' should be the last entry in the BMLog. Its prev pointer
+ * will be followed back to find the first entry.
+ *
+ * The unused IDs field of the log will be initialized by taking all
+ * keys from all GHashes in the log entry.
+ */
BMLog *BM_log_from_existing_entries_create(BMesh *bm, BMLogEntry *entry);
/* Free all the data in a BMLog including the log itself */
+/* Free all the data in a BMLog including the log itself */
void BM_log_free(BMLog *log);
/* Get the number of log entries */
+/* Get the number of log entries */
int BM_log_length(const BMLog *log);
/* Apply a consistent ordering to BMesh vertices and faces */
+/* Apply a consistent ordering to BMesh vertices */
void BM_log_mesh_elems_reorder(BMesh *bm, BMLog *log);
/* Start a new log entry and update the log entry list */
+/* Start a new log entry and update the log entry list
+ *
+ * If the log entry list is empty, or if the current log entry is the
+ * last entry, the new entry is simply appended to the end.
+ *
+ * Otherwise, the new entry is added after the current entry and all
+ * following entries are deleted.
+ *
+ * In either case, the new entry is set as the current log entry.
+ */
BMLogEntry *BM_log_entry_add(BMLog *log);
/* Mark all used ids as unused for this node */
void BM_log_cleanup_entry(BMLogEntry *entry);
/* Remove an entry from the log */
+/* Remove an entry from the log
+ *
+ * Uses entry->log as the log. If the log is NULL, the entry will be
+ * free'd but not removed from any list, nor shall its IDs be
+ * released.
+ *
+ * This operation is only valid on the first and last entries in the
+ * log. Deleting from the middle will assert.
+ */
void BM_log_entry_drop(BMLogEntry *entry);
/* Undo one BMLogEntry */
+/* Undo one BMLogEntry
+ *
+ * Has no effect if there's nothing left to undo */
void BM_log_undo(BMesh *bm, BMLog *log);
/* Redo one BMLogEntry */
+/* Redo one BMLogEntry
+ *
+ * Has no effect if there's nothing left to redo */
void BM_log_redo(BMesh *bm, BMLog *log);
/* Log a vertex before it is modified */
+/* Log a vertex before it is modified
+ *
+ * Before modifying vertex coordinates, masks, or hflags, call this
+ * function to log its current values. This is better than logging
+ * after the coordinates have been modified, because only those
+ * vertices that are modified need to have their original values
+ * stored.
+ *
+ * Handles two separate cases:
+ *
+ * If the vertex was added in the current log entry, update the
+ * vertex in the map of added vertices.
+ *
+ * If the vertex already existed prior to the current log entry, a
+ * separate key/value map of modified vertices is used (using the
+ * vertex's ID as the key). The values stored in that case are
+ * the vertex's original state so that an undo can restore the
+ * previous state.
+ *
+ * On undo, the current vertex state will be swapped with the stored
+ * state so that a subsequent redo operation will restore the newer
+ * vertex state.
+ */
void BM_log_vert_before_modified(BMLog *log, struct BMVert *v, const int cd_vert_mask_offset);
/* Log a new vertex as added to the BMesh */
+/* Log a new vertex as added to the BMesh
+ *
+ * The new vertex gets a unique ID assigned. It is then added to a map
+ * of added vertices, with the key being its ID and the value
+ * containing everything needed to reconstruct that vertex.
+ */
void BM_log_vert_added(BMLog *log, struct BMVert *v, const int cd_vert_mask_offset);
/* Log a face before it is modified */
+/* Log a face before it is modified
+ *
+ * This is intended to handle only header flags and we always
+ * assume face has been added before
+ */
void BM_log_face_modified(BMLog *log, struct BMFace *f);
/* Log a new face as added to the BMesh */
+/* Log a new face as added to the BMesh
+ *
+ * The new face gets a unique ID assigned. It is then added to a map
+ * of added faces, with the key being its ID and the value containing
+ * everything needed to reconstruct that face.
+ */
void BM_log_face_added(BMLog *log, struct BMFace *f);
/* Log a vertex as removed from the BMesh */
+/* Log a vertex as removed from the BMesh
+ *
+ * A couple things can happen here:
+ *
+ * If the vertex was added as part of the current log entry, then it's
+ * deleted and forgotten about entirely. Its unique ID is returned to
+ * the unused pool.
+ *
+ * If the vertex was already part of the BMesh before the current log
+ * entry, it is added to a map of deleted vertices, with the key being
+ * its ID and the value containing everything needed to reconstruct
+ * that vertex.
+ *
+ * If there's a move record for the vertex, that's used as the
+ * vertices original location, then the move record is deleted.
+ */
void BM_log_vert_removed(BMLog *log, struct BMVert *v, const int cd_vert_mask_offset);
/* Log a face as removed from the BMesh */
+/* Log a face as removed from the BMesh
+ *
+ * A couple things can happen here:
+ *
+ * If the face was added as part of the current log entry, then it's
+ * deleted and forgotten about entirely. Its unique ID is returned to
+ * the unused pool.
+ *
+ * If the face was already part of the BMesh before the current log
+ * entry, it is added to a map of deleted faces, with the key being
+ * its ID and the value containing everything needed to reconstruct
+ * that face.
+ */
void BM_log_face_removed(BMLog *log, struct BMFace *f);
/* Log all vertices/faces in the BMesh as added */
+/* Log all vertices/faces in the BMesh as added */
void BM_log_all_added(BMesh *bm, BMLog *log);
/* Log all vertices/faces in the BMesh as removed */
+/* Log all vertices/faces in the BMesh as removed */
void BM_log_before_all_removed(BMesh *bm, BMLog *log);
/* Get the logged coordinates of a vertex */
+/* Get the logged coordinates of a vertex
+ *
+ * Does not modify the log or the vertex */
const float *BM_log_original_vert_co(BMLog *log, BMVert *v);
/* Get the logged normal of a vertex */
+/* Get the logged normal of a vertex
+ *
+ * Does not modify the log or the vertex */
const short *BM_log_original_vert_no(BMLog *log, BMVert *v);
/* Get the logged mask of a vertex */
+/* Get the logged mask of a vertex
+ *
+ * Does not modify the log or the vertex */
float BM_log_original_mask(BMLog *log, BMVert *v);
/* Get the logged data of a vertex (avoid multiple lookups) */
void BM_log_original_vert_data(BMLog *log, BMVert *v, const float **r_co, const short **r_no);
/* For internal use only (unit testing) */
+/* For internal use only (unit testing) */
BMLogEntry *BM_log_current_entry(BMLog *log);
+/* For internal use only (unit testing) */
struct RangeTreeUInt *BM_log_unused_ids(BMLog *log);
diff --git a/source/blender/bmesh/intern/bmesh_marking.c b/source/blender/bmesh/intern/bmesh_marking.c
index b70e26f51ea..b756aa25edd 100644
--- a/source/blender/bmesh/intern/bmesh_marking.c
+++ b/source/blender/bmesh/intern/bmesh_marking.c
@@ -251,14 +251,6 @@ static bool bm_edge_is_face_visible_any(const BMEdge *e)
/** \} */
-/**
- * \brief Select Mode Clean
- *
- * Remove isolated selected elements when in a mode doesn't support them.
- * eg: in edge-mode a selected vertex must be connected to a selected edge.
- *
- * \note this could be made a part of #BM_mesh_select_mode_flush_ex
- */
void BM_mesh_select_mode_clean_ex(BMesh *bm, const short selectmode)
{
if (selectmode & SCE_SELECT_VERTEX) {
@@ -424,13 +416,6 @@ static void bm_mesh_select_mode_flush_edge_to_face(BMesh *bm)
bm->totfacesel += chunk_data.delta_selection_len;
}
-/**
- * \brief Select Mode Flush
- *
- * Makes sure to flush selections 'upwards'
- * (ie: all verts of an edge selects the edge and so on).
- * This should only be called by system and not tool authors.
- */
void BM_mesh_select_mode_flush_ex(BMesh *bm, const short selectmode, eBMSelectionFlushFLags flags)
{
if (selectmode & SCE_SELECT_VERTEX) {
@@ -463,9 +448,6 @@ void BM_mesh_select_mode_flush(BMesh *bm)
/** \} */
-/**
- * mode independent flushing up/down
- */
void BM_mesh_deselect_flush(BMesh *bm)
{
BMIter eiter;
@@ -498,9 +480,6 @@ void BM_mesh_deselect_flush(BMesh *bm)
recount_totsels(bm);
}
-/**
- * mode independent flushing up/down
- */
void BM_mesh_select_flush(BMesh *bm)
{
BMEdge *e;
@@ -542,12 +521,6 @@ void BM_mesh_select_flush(BMesh *bm)
recount_totsels(bm);
}
-/**
- * \brief Select Vert
- *
- * Changes selection state of a single vertex
- * in a mesh
- */
void BM_vert_select_set(BMesh *bm, BMVert *v, const bool select)
{
BLI_assert(v->head.htype == BM_VERT);
@@ -570,11 +543,6 @@ void BM_vert_select_set(BMesh *bm, BMVert *v, const bool select)
}
}
-/**
- * \brief Select Edge
- *
- * Changes selection state of a single edge in a mesh.
- */
void BM_edge_select_set(BMesh *bm, BMEdge *e, const bool select)
{
BLI_assert(e->head.htype == BM_EDGE);
@@ -615,12 +583,6 @@ void BM_edge_select_set(BMesh *bm, BMEdge *e, const bool select)
}
}
-/**
- * \brief Select Face
- *
- * Changes selection state of a single
- * face in a mesh.
- */
void BM_face_select_set(BMesh *bm, BMFace *f, const bool select)
{
BMLoop *l_iter;
@@ -746,12 +708,6 @@ void BM_face_select_set_noflush(BMesh *bm, BMFace *f, const bool select)
/** \} */
-/**
- * Select Mode Set
- *
- * Sets the selection mode for the bmesh,
- * updating the selection state.
- */
void BM_mesh_select_mode_set(BMesh *bm, int selectmode)
{
BMIter iter;
@@ -867,10 +823,6 @@ int BM_mesh_elem_hflag_count_disabled(BMesh *bm,
return bm_mesh_flag_count(bm, htype, hflag, respecthide, false);
}
-/**
- * \note use BM_elem_flag_test(ele, BM_ELEM_SELECT) to test selection
- * \note by design, this will not touch the editselection history stuff
- */
void BM_elem_select_set(BMesh *bm, BMElem *ele, const bool select)
{
switch (ele->head.htype) {
@@ -889,7 +841,6 @@ void BM_elem_select_set(BMesh *bm, BMElem *ele, const bool select)
}
}
-/* this replaces the active flag used in uv/face mode */
void BM_mesh_active_face_set(BMesh *bm, BMFace *f)
{
bm->act_face = f;
@@ -974,15 +925,6 @@ BMElem *BM_mesh_active_elem_get(BMesh *bm)
return NULL;
}
-/**
- * Generic way to get data from an EditSelection type
- * These functions were written to be used by the Modifier widget
- * when in Rotate about active mode, but can be used anywhere.
- *
- * - #BM_editselection_center
- * - #BM_editselection_normal
- * - #BM_editselection_plane
- */
void BM_editselection_center(BMEditSelection *ese, float r_center[3])
{
if (ese->htype == BM_VERT) {
@@ -1027,11 +969,6 @@ void BM_editselection_normal(BMEditSelection *ese, float r_normal[3])
}
}
-/**
- * Calculate a plane that is right angles to the edge/vert/faces normal
- * also make the plane run along an axis that is related to the geometry,
- * because this is used for the gizmos Y axis.
- */
void BM_editselection_plane(BMEditSelection *ese, float r_plane[3])
{
if (ese->htype == BM_VERT) {
@@ -1098,6 +1035,7 @@ static BMEditSelection *bm_select_history_create(BMHeader *ele)
}
/* --- macro wrapped funcs --- */
+
bool _bm_select_history_check(BMesh *bm, const BMHeader *ele)
{
return (BLI_findptr(&bm->selected, ele, offsetof(BMEditSelection, ele)) != NULL);
@@ -1170,9 +1108,6 @@ void BM_select_history_validate(BMesh *bm)
}
}
-/**
- * Get the active mesh element (with active-face fallback).
- */
bool BM_select_history_active_get(BMesh *bm, BMEditSelection *ese)
{
BMEditSelection *ese_last = bm->selected.last;
@@ -1209,9 +1144,6 @@ bool BM_select_history_active_get(BMesh *bm, BMEditSelection *ese)
return true;
}
-/**
- * Return a map from BMVert/Edge/Face -> BMEditSelection
- */
GHash *BM_select_history_map_create(BMesh *bm)
{
BMEditSelection *ese;
@@ -1230,9 +1162,6 @@ GHash *BM_select_history_map_create(BMesh *bm)
return map;
}
-/**
- * Map arguments may all be the same pointer.
- */
void BM_select_history_merge_from_targetmap(
BMesh *bm, GHash *vert_map, GHash *edge_map, GHash *face_map, const bool use_chain)
{
diff --git a/source/blender/bmesh/intern/bmesh_marking.h b/source/blender/bmesh/intern/bmesh_marking.h
index 99feae1d66c..72b520cc72c 100644
--- a/source/blender/bmesh/intern/bmesh_marking.h
+++ b/source/blender/bmesh/intern/bmesh_marking.h
@@ -36,14 +36,20 @@ typedef enum eBMSelectionFlushFLags {
BM_SELECT_LEN_FLUSH_RECALC_FACE),
} eBMSelectionFlushFLags;
-/* geometry hiding code */
+/* Geometry hiding code. */
+
#define BM_elem_hide_set(bm, ele, hide) _bm_elem_hide_set(bm, &(ele)->head, hide)
void _bm_elem_hide_set(BMesh *bm, BMHeader *head, const bool hide);
void BM_vert_hide_set(BMVert *v, const bool hide);
void BM_edge_hide_set(BMEdge *e, const bool hide);
void BM_face_hide_set(BMFace *f, const bool hide);
-/* Selection code */
+/* Selection code. */
+
+/**
+ * \note use BM_elem_flag_test(ele, BM_ELEM_SELECT) to test selection
+ * \note by design, this will not touch the editselection history stuff
+ */
void BM_elem_select_set(BMesh *bm, BMElem *ele, const bool select);
void BM_mesh_elem_hflag_enable_test(BMesh *bm,
@@ -68,24 +74,70 @@ void BM_mesh_elem_hflag_disable_all(BMesh *bm,
const char hflag,
const bool respecthide);
-/* Individual element select functions, BM_elem_select_set is a shortcut for these
+/* Individual element select functions, #BM_elem_select_set is a shortcut for these
* that automatically detects which one to use. */
+
+/**
+ * \brief Select Vert
+ *
+ * Changes selection state of a single vertex
+ * in a mesh
+ */
void BM_vert_select_set(BMesh *bm, BMVert *v, const bool select);
+/**
+ * \brief Select Edge
+ *
+ * Changes selection state of a single edge in a mesh.
+ */
void BM_edge_select_set(BMesh *bm, BMEdge *e, const bool select);
+/**
+ * \brief Select Face
+ *
+ * Changes selection state of a single
+ * face in a mesh.
+ */
void BM_face_select_set(BMesh *bm, BMFace *f, const bool select);
-/* lower level functions which don't do flushing */
+/* Lower level functions which don't do flushing. */
+
void BM_edge_select_set_noflush(BMesh *bm, BMEdge *e, const bool select);
void BM_face_select_set_noflush(BMesh *bm, BMFace *f, const bool select);
+/**
+ * \brief Select Mode Clean
+ *
+ * Remove isolated selected elements when in a mode doesn't support them.
+ * eg: in edge-mode a selected vertex must be connected to a selected edge.
+ *
+ * \note this could be made a part of #BM_mesh_select_mode_flush_ex
+ */
void BM_mesh_select_mode_clean_ex(BMesh *bm, const short selectmode);
void BM_mesh_select_mode_clean(BMesh *bm);
+/**
+ * Select Mode Set
+ *
+ * Sets the selection mode for the bmesh,
+ * updating the selection state.
+ */
void BM_mesh_select_mode_set(BMesh *bm, int selectmode);
+/**
+ * \brief Select Mode Flush
+ *
+ * Makes sure to flush selections 'upwards'
+ * (ie: all verts of an edge selects the edge and so on).
+ * This should only be called by system and not tool authors.
+ */
void BM_mesh_select_mode_flush_ex(BMesh *bm, const short selectmode, eBMSelectionFlushFLags flags);
void BM_mesh_select_mode_flush(BMesh *bm);
+/**
+ * Mode independent de-selection flush (up/down).
+ */
void BM_mesh_deselect_flush(BMesh *bm);
+/**
+ * Mode independent selection flush (up/down).
+ */
void BM_mesh_select_flush(BMesh *bm);
int BM_mesh_elem_hflag_count_enabled(BMesh *bm,
@@ -97,15 +149,30 @@ int BM_mesh_elem_hflag_count_disabled(BMesh *bm,
const char hflag,
const bool respecthide);
-/* edit selection stuff */
+/* Edit selection stuff. */
+
void BM_mesh_active_face_set(BMesh *bm, BMFace *f);
BMFace *BM_mesh_active_face_get(BMesh *bm, const bool is_sloppy, const bool is_selected);
BMEdge *BM_mesh_active_edge_get(BMesh *bm);
BMVert *BM_mesh_active_vert_get(BMesh *bm);
BMElem *BM_mesh_active_elem_get(BMesh *bm);
+/**
+ * Generic way to get data from an #BMEditSelection type
+ * These functions were written to be used by the Modifier widget
+ * when in Rotate about active mode, but can be used anywhere.
+ *
+ * - #BM_editselection_center
+ * - #BM_editselection_normal
+ * - #BM_editselection_plane
+ */
void BM_editselection_center(BMEditSelection *ese, float r_center[3]);
void BM_editselection_normal(BMEditSelection *ese, float r_normal[3]);
+/**
+ * Calculate a plane that is right angles to the edge/vert/faces normal
+ * also make the plane run along an axis that is related to the geometry,
+ * because this is used for the gizmos Y axis.
+ */
void BM_editselection_plane(BMEditSelection *ese, float r_plane[3]);
#define BM_select_history_check(bm, ele) _bm_select_history_check(bm, &(ele)->head)
@@ -131,9 +198,18 @@ void _bm_select_history_store_after_notest(BMesh *bm, BMEditSelection *ese_ref,
void BM_select_history_validate(BMesh *bm);
void BM_select_history_clear(BMesh *bm);
+/**
+ * Get the active mesh element (with active-face fallback).
+ */
bool BM_select_history_active_get(BMesh *bm, struct BMEditSelection *ese);
+/**
+ * Return a map from #BMVert/#BMEdge/#BMFace -> #BMEditSelection.
+ */
struct GHash *BM_select_history_map_create(BMesh *bm);
+/**
+ * Map arguments may all be the same pointer.
+ */
void BM_select_history_merge_from_targetmap(
BMesh *bm, GHash *vert_map, GHash *edge_map, GHash *face_map, const bool use_chain);
diff --git a/source/blender/bmesh/intern/bmesh_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c
index b2958a9e744..ad52daa4731 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.c
+++ b/source/blender/bmesh/intern/bmesh_mesh.c
@@ -34,7 +34,6 @@
#include "bmesh.h"
-/* used as an extern, defined in bmesh.h */
const BMAllocTemplate bm_mesh_allocsize_default = {512, 1024, 2048, 512};
const BMAllocTemplate bm_mesh_chunksize_default = {512, 1024, 2048, 512};
@@ -137,15 +136,6 @@ void BM_mesh_elem_toolflags_clear(BMesh *bm)
}
}
-/**
- * \brief BMesh Make Mesh
- *
- * Allocates a new BMesh structure.
- *
- * \return The New bmesh
- *
- * \note ob is needed by multires
- */
BMesh *BM_mesh_create(const BMAllocTemplate *allocsize, const struct BMeshCreateParams *params)
{
/* allocate the structure */
@@ -167,13 +157,6 @@ BMesh *BM_mesh_create(const BMAllocTemplate *allocsize, const struct BMeshCreate
return bm;
}
-/**
- * \brief BMesh Free Mesh Data
- *
- * Frees a BMesh structure.
- *
- * \note frees mesh, but not actual BMesh struct
- */
void BM_mesh_data_free(BMesh *bm)
{
BMVert *v;
@@ -265,11 +248,6 @@ void BM_mesh_data_free(BMesh *bm)
BMO_error_clear(bm);
}
-/**
- * \brief BMesh Clear Mesh
- *
- * Clear all data in bm
- */
void BM_mesh_clear(BMesh *bm)
{
const bool use_toolflags = bm->use_toolflags;
@@ -291,11 +269,6 @@ void BM_mesh_clear(BMesh *bm)
CustomData_reset(&bm->pdata);
}
-/**
- * \brief BMesh Free Mesh
- *
- * Frees a BMesh data and its structure.
- */
void BM_mesh_free(BMesh *bm)
{
BM_mesh_data_free(bm);
@@ -310,13 +283,6 @@ void BM_mesh_free(BMesh *bm)
MEM_freeN(bm);
}
-/**
- * \brief BMesh Begin Edit
- *
- * Functions for setting up a mesh for editing and cleaning up after
- * the editing operations are done. These are called by the tools/operator
- * API for each time a tool is executed.
- */
void bmesh_edit_begin(BMesh *UNUSED(bm), BMOpTypeFlag UNUSED(type_flag))
{
/* Most operators seem to be using BMO_OPTYPE_FLAG_UNTAN_MULTIRES to change the MDisps to
@@ -337,9 +303,6 @@ void bmesh_edit_begin(BMesh *UNUSED(bm), BMOpTypeFlag UNUSED(type_flag))
#endif
}
-/**
- * \brief BMesh End Edit
- */
void bmesh_edit_end(BMesh *bm, BMOpTypeFlag type_flag)
{
ListBase select_history;
@@ -499,18 +462,6 @@ void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
BM_mesh_elem_index_ensure_ex(bm, htype, NULL);
}
-/**
- * Array checking/setting macros
- *
- * Currently vert/edge/loop/face index data is being abused, in a few areas of the code.
- *
- * To avoid correcting them afterwards, set 'bm->elem_index_dirty' however its possible
- * this flag is set incorrectly which could crash blender.
- *
- * Code that calls this functions may depend on dirty indices on being set.
- * Keep this function read-only.
- */
-
void BM_mesh_elem_index_validate(
BMesh *bm, const char *location, const char *func, const char *msg_a, const char *msg_b)
{
@@ -693,7 +644,6 @@ finally:
bm->elem_table_dirty &= ~htype_needed;
}
-/* use BM_mesh_elem_table_ensure where possible to avoid full rebuild */
void BM_mesh_elem_table_init(BMesh *bm, const char htype)
{
BLI_assert((htype & ~BM_ALL_NOLOOP) == 0);
@@ -754,11 +704,6 @@ BMLoop *BM_loop_at_index_find(BMesh *bm, const int index)
return NULL;
}
-/**
- * Use lookup table when available, else use slower find functions.
- *
- * \note Try to use #BM_mesh_elem_table_ensure instead.
- */
BMVert *BM_vert_at_index_find_or_table(BMesh *bm, const int index)
{
if ((bm->elem_table_dirty & BM_VERT) == 0) {
@@ -783,9 +728,6 @@ BMFace *BM_face_at_index_find_or_table(BMesh *bm, const int index)
return BM_face_at_index_find(bm, index);
}
-/**
- * Return the amount of element of type 'type' in a given bmesh.
- */
int BM_mesh_elem_count(BMesh *bm, const char htype)
{
BLI_assert((htype & ~BM_ALL_NOLOOP) == 0);
@@ -804,20 +746,6 @@ int BM_mesh_elem_count(BMesh *bm, const char htype)
}
}
-/**
- * Remaps the vertices, edges and/or faces of the bmesh as indicated by vert/edge/face_idx arrays
- * (xxx_idx[org_index] = new_index).
- *
- * A NULL array means no changes.
- *
- * \note
- * - Does not mess with indices, just sets elem_index_dirty flag.
- * - For verts/edges/faces only (as loops must remain "ordered" and "aligned"
- * on a per-face basis...).
- *
- * \warning Be careful if you keep pointers to affected BM elements,
- * or arrays, when using this func!
- */
void BM_mesh_remap(BMesh *bm, const uint *vert_idx, const uint *edge_idx, const uint *face_idx)
{
/* Mapping old to new pointers. */
@@ -1106,12 +1034,6 @@ void BM_mesh_remap(BMesh *bm, const uint *vert_idx, const uint *edge_idx, const
}
}
-/**
- * Use new memory pools for this mesh.
- *
- * \note needed for re-sizing elements (adding/removing tool flags)
- * but could also be used for packing fragmented bmeshes.
- */
void BM_mesh_rebuild(BMesh *bm,
const struct BMeshCreateParams *params,
BLI_mempool *vpool_dst,
@@ -1363,9 +1285,6 @@ void BM_mesh_rebuild(BMesh *bm,
}
}
-/**
- * Re-allocates mesh data with/without toolflags.
- */
void BM_mesh_toolflags_set(BMesh *bm, bool use_toolflags)
{
if (bm->use_toolflags == use_toolflags) {
diff --git a/source/blender/bmesh/intern/bmesh_mesh.h b/source/blender/bmesh/intern/bmesh_mesh.h
index bd0504b038a..e00461ba571 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.h
+++ b/source/blender/bmesh/intern/bmesh_mesh.h
@@ -34,28 +34,83 @@ struct BMeshCreateParams {
uint use_toolflags : 1;
};
+/**
+ * \brief BMesh Make Mesh
+ *
+ * Allocates a new BMesh structure.
+ *
+ * \return The New bmesh
+ *
+ * \note ob is needed by multires
+ */
BMesh *BM_mesh_create(const struct BMAllocTemplate *allocsize,
const struct BMeshCreateParams *params);
+/**
+ * \brief BMesh Free Mesh
+ *
+ * Frees a BMesh data and its structure.
+ */
void BM_mesh_free(BMesh *bm);
+/**
+ * \brief BMesh Free Mesh Data
+ *
+ * Frees a BMesh structure.
+ *
+ * \note frees mesh, but not actual BMesh struct
+ */
void BM_mesh_data_free(BMesh *bm);
+/**
+ * \brief BMesh Clear Mesh
+ *
+ * Clear all data in bm
+ */
void BM_mesh_clear(BMesh *bm);
+/**
+ * \brief BMesh Begin Edit
+ *
+ * Functions for setting up a mesh for editing and cleaning up after
+ * the editing operations are done. These are called by the tools/operator
+ * API for each time a tool is executed.
+ */
void bmesh_edit_begin(BMesh *bm, const BMOpTypeFlag type_flag);
+/**
+ * \brief BMesh End Edit
+ */
void bmesh_edit_end(BMesh *bm, const BMOpTypeFlag type_flag);
void BM_mesh_elem_index_ensure_ex(BMesh *bm, const char htype, int elem_offset[4]);
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype);
+/**
+ * Array checking/setting macros.
+ *
+ * Currently vert/edge/loop/face index data is being abused, in a few areas of the code.
+ *
+ * To avoid correcting them afterwards, set 'bm->elem_index_dirty' however its possible
+ * this flag is set incorrectly which could crash blender.
+ *
+ * Functions that calls this function may depend on dirty indices on being set.
+ *
+ * This is read-only, so it can be used for assertions that don't impact behavior.
+ */
void BM_mesh_elem_index_validate(
BMesh *bm, const char *location, const char *func, const char *msg_a, const char *msg_b);
-void BM_mesh_toolflags_set(BMesh *bm, bool use_toolflags);
-
#ifndef NDEBUG
+/**
+ * \see #BM_mesh_elem_index_validate the same rationale applies to this function.
+ */
bool BM_mesh_elem_table_check(BMesh *bm);
#endif
+/**
+ * Re-allocates mesh data with/without toolflags.
+ */
+void BM_mesh_toolflags_set(BMesh *bm, bool use_toolflags);
+
void BM_mesh_elem_table_ensure(BMesh *bm, const char htype);
+/* use BM_mesh_elem_table_ensure where possible to avoid full rebuild */
void BM_mesh_elem_table_init(BMesh *bm, const char htype);
void BM_mesh_elem_table_free(BMesh *bm, const char htype);
@@ -83,16 +138,44 @@ BMEdge *BM_edge_at_index_find(BMesh *bm, const int index);
BMFace *BM_face_at_index_find(BMesh *bm, const int index);
BMLoop *BM_loop_at_index_find(BMesh *bm, const int index);
+/**
+ * Use lookup table when available, else use slower find functions.
+ *
+ * \note Try to use #BM_mesh_elem_table_ensure instead.
+ */
BMVert *BM_vert_at_index_find_or_table(BMesh *bm, const int index);
BMEdge *BM_edge_at_index_find_or_table(BMesh *bm, const int index);
BMFace *BM_face_at_index_find_or_table(BMesh *bm, const int index);
// XXX
+/**
+ * Return the amount of element of type 'type' in a given bmesh.
+ */
int BM_mesh_elem_count(BMesh *bm, const char htype);
+/**
+ * Remaps the vertices, edges and/or faces of the bmesh as indicated by vert/edge/face_idx arrays
+ * (xxx_idx[org_index] = new_index).
+ *
+ * A NULL array means no changes.
+ *
+ * \note
+ * - Does not mess with indices, just sets elem_index_dirty flag.
+ * - For verts/edges/faces only (as loops must remain "ordered" and "aligned"
+ * on a per-face basis...).
+ *
+ * \warning Be careful if you keep pointers to affected BM elements,
+ * or arrays, when using this func!
+ */
void BM_mesh_remap(BMesh *bm, const uint *vert_idx, const uint *edge_idx, const uint *face_idx);
+/**
+ * Use new memory pools for this mesh.
+ *
+ * \note needed for re-sizing elements (adding/removing tool flags)
+ * but could also be used for packing fragmented bmeshes.
+ */
void BM_mesh_rebuild(BMesh *bm,
const struct BMeshCreateParams *params,
struct BLI_mempool *vpool,
@@ -104,6 +187,7 @@ typedef struct BMAllocTemplate {
int totvert, totedge, totloop, totface;
} BMAllocTemplate;
+/* used as an extern, defined in bmesh.h */
extern const BMAllocTemplate bm_mesh_allocsize_default;
extern const BMAllocTemplate bm_mesh_chunksize_default;
diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.c b/source/blender/bmesh/intern/bmesh_mesh_convert.c
index 9d29a90a7a4..544a81f7020 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_convert.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_convert.c
@@ -176,16 +176,6 @@ static BMFace *bm_face_create_from_mpoly(
return BM_face_create(bm, verts, edges, mp->totloop, NULL, BM_CREATE_SKIP_CD);
}
-/**
- * \brief Mesh -> BMesh
- * \param bm: The mesh to write into, while this is typically a newly created BMesh,
- * merging into existing data is supported.
- * Note the custom-data layout isn't used.
- * If more comprehensive merging is needed we should move this into a separate function
- * since this should be kept fast for edit-mode switching and storing undo steps.
- *
- * \warning This function doesn't calculate face normals.
- */
void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshParams *params)
{
const bool is_new = !(bm->totvert || (bm->vdata.totlayer || bm->edata.totlayer ||
@@ -582,10 +572,6 @@ BLI_INLINE void bmesh_quick_edgedraw_flag(MEdge *med, BMEdge *e)
}
}
-/**
- *
- * \param bmain: May be NULL in case \a calc_object_remap parameter option is not set.
- */
void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMeshParams *params)
{
MEdge *med;
@@ -1005,23 +991,6 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
BKE_mesh_runtime_clear_geometry(me);
}
-/**
- * A version of #BM_mesh_bm_to_me intended for getting the mesh
- * to pass to the modifier stack for evaluation,
- * instead of mode switching (where we make sure all data is kept
- * and do expensive lookups to maintain shape keys).
- *
- * Key differences:
- *
- * - Don't support merging with existing mesh.
- * - Ignore shape-keys.
- * - Ignore vertex-parents.
- * - Ignore selection history.
- * - Uses simpler method to calculate #ME_EDGEDRAW
- * - Uses #CD_MASK_DERIVEDMESH instead of #CD_MASK_MESH.
- *
- * \note Was `cddm_from_bmesh_ex` in 2.7x, removed `MFace` support.
- */
void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *cd_mask_extra)
{
/* Must be an empty mesh. */
diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.h b/source/blender/bmesh/intern/bmesh_mesh_convert.h
index 1b5d001d35d..ea114487285 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_convert.h
+++ b/source/blender/bmesh/intern/bmesh_mesh_convert.h
@@ -43,6 +43,16 @@ struct BMeshFromMeshParams {
int active_shapekey;
struct CustomData_MeshMasks cd_mask_extra;
};
+/**
+ * \brief Mesh -> BMesh
+ * \param bm: The mesh to write into, while this is typically a newly created BMesh,
+ * merging into existing data is supported.
+ * Note the custom-data layout isn't used.
+ * If more comprehensive merging is needed we should move this into a separate function
+ * since this should be kept fast for edit-mode switching and storing undo steps.
+ *
+ * \warning This function doesn't calculate face normals.
+ */
void BM_mesh_bm_from_me(BMesh *bm, const struct Mesh *me, const struct BMeshFromMeshParams *params)
ATTR_NONNULL(1, 3);
@@ -61,11 +71,32 @@ struct BMeshToMeshParams {
uint update_shapekey_indices : 1;
struct CustomData_MeshMasks cd_mask_extra;
};
+/**
+ *
+ * \param bmain: May be NULL in case \a calc_object_remap parameter option is not set.
+ */
void BM_mesh_bm_to_me(struct Main *bmain,
BMesh *bm,
struct Mesh *me,
const struct BMeshToMeshParams *params) ATTR_NONNULL(2, 3, 4);
+/**
+ * A version of #BM_mesh_bm_to_me intended for getting the mesh
+ * to pass to the modifier stack for evaluation,
+ * instead of mode switching (where we make sure all data is kept
+ * and do expensive lookups to maintain shape keys).
+ *
+ * Key differences:
+ *
+ * - Don't support merging with existing mesh.
+ * - Ignore shape-keys.
+ * - Ignore vertex-parents.
+ * - Ignore selection history.
+ * - Uses simpler method to calculate #ME_EDGEDRAW
+ * - Uses #CD_MASK_DERIVEDMESH instead of #CD_MASK_MESH.
+ *
+ * \note Was `cddm_from_bmesh_ex` in 2.7x, removed `MFace` support.
+ */
void BM_mesh_bm_to_me_for_eval(BMesh *bm,
struct Mesh *me,
const struct CustomData_MeshMasks *cd_mask_extra)
diff --git a/source/blender/bmesh/intern/bmesh_mesh_duplicate.c b/source/blender/bmesh/intern/bmesh_mesh_duplicate.c
index 1d393abcd56..db21e50bb71 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_duplicate.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_duplicate.c
@@ -85,9 +85,6 @@ static BMFace *bm_face_copy_with_arrays(
return f_dst;
}
-/**
- * Geometry must be completely isolated.
- */
void BM_mesh_copy_arrays(BMesh *bm_src,
BMesh *bm_dst,
BMVert **verts_src,
diff --git a/source/blender/bmesh/intern/bmesh_mesh_duplicate.h b/source/blender/bmesh/intern/bmesh_mesh_duplicate.h
index 8ace555d61f..d15ef8f4ab2 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_duplicate.h
+++ b/source/blender/bmesh/intern/bmesh_mesh_duplicate.h
@@ -20,6 +20,9 @@
* \ingroup bmesh
*/
+/**
+ * Geometry must be completely isolated.
+ */
void BM_mesh_copy_arrays(BMesh *bm_src,
BMesh *bm_dst,
BMVert **verts_src,
diff --git a/source/blender/bmesh/intern/bmesh_mesh_normals.c b/source/blender/bmesh/intern/bmesh_mesh_normals.c
index 8119d9eb57d..34c07b4f310 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_normals.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_normals.c
@@ -247,11 +247,6 @@ static void bm_face_calc_normals_cb(void *UNUSED(userdata),
BM_face_calc_normal(f, f->no);
}
-/**
- * \brief BMesh Compute Normals
- *
- * Updates the normals of a mesh.
- */
void BM_mesh_normals_update_ex(BMesh *bm, const struct BMeshNormalsUpdate_Params *params)
{
if (params->face_normals) {
@@ -295,10 +290,6 @@ static void bm_partial_verts_parallel_range_calc_normal_cb(
bm_vert_calc_normals_impl(v);
}
-/**
- * A version of #BM_mesh_normals_update that updates a subset of geometry,
- * used to avoid the overhead of updating everything.
- */
void BM_mesh_normals_update_with_partial_ex(BMesh *UNUSED(bm),
const BMPartialUpdate *bmpinfo,
const struct BMeshNormalsUpdate_Params *params)
@@ -343,12 +334,6 @@ void BM_mesh_normals_update_with_partial(BMesh *bm, const BMPartialUpdate *bmpin
/** \name Update Vertex & Face Normals (Custom Coords)
* \{ */
-/**
- * \brief BMesh Compute Normals from/to external data.
- *
- * Computes the vertex normals of a mesh into vnos,
- * using given vertex coordinates (vcos) and polygon normals (fnos).
- */
void BM_verts_calc_normal_vcos(BMesh *bm,
const float (*fnos)[3],
const float (*vcos)[3],
@@ -435,12 +420,6 @@ static void bm_mesh_edges_sharp_tag(BMesh *bm,
bm->elem_index_dirty &= ~BM_EDGE;
}
-/**
- * Define sharp edges as needed to mimic 'autosmooth' from angle threshold.
- *
- * Used when defining an empty custom loop normals data layer,
- * to keep same shading as with auto-smooth!
- */
void BM_edges_sharp_from_angle_set(BMesh *bm, const float split_angle)
{
if (split_angle >= (float)M_PI) {
@@ -457,11 +436,6 @@ void BM_edges_sharp_from_angle_set(BMesh *bm, const float split_angle)
/** \name Loop Normals Calculation API
* \{ */
-/**
- * Check whether given loop is part of an unknown-so-far cyclic smooth fan, or not.
- * Needed because cyclic smooth fans have no obvious 'entry point',
- * and yet we need to walk them once, and only once.
- */
bool BM_loop_check_cyclic_smooth_fan(BMLoop *l_curr)
{
BMLoop *lfan_pivot_next = l_curr;
@@ -520,7 +494,8 @@ static int bm_mesh_loops_calc_normals_for_loop(BMesh *bm,
float (*r_lnos)[3],
MLoopNorSpaceArray *r_lnors_spacearr)
{
- BLI_assert((bm->elem_index_dirty & (BM_FACE | BM_LOOP)) == 0);
+ BLI_assert((bm->elem_index_dirty & BM_LOOP) == 0);
+ BLI_assert((fnos == NULL) || ((bm->elem_index_dirty & BM_FACE) == 0));
BLI_assert((vcos == NULL) || ((bm->elem_index_dirty & BM_VERT) == 0));
UNUSED_VARS_NDEBUG(bm);
@@ -1719,13 +1694,6 @@ static void bm_mesh_loops_calc_normals_no_autosmooth(BMesh *bm,
}
}
-/**
- * \brief BMesh Compute Loop Normals from/to external data.
- *
- * Compute split normals, i.e. vertex normals associated with each poly (hence 'loop normals').
- * Useful to materialize sharp edges (or non-smooth faces) without actually modifying the geometry
- * (splitting edges).
- */
void BM_loops_calc_normal_vcos(BMesh *bm,
const float (*vcos)[3],
const float (*vnos)[3],
@@ -1932,10 +1900,6 @@ void BM_lnorspace_rebuild(BMesh *bm, bool preserve_clnor)
#endif
}
-/**
- * \warning This function sets #BM_ELEM_TAG on loops & edges via #bm_mesh_loops_calc_normals,
- * take care to run this before setting up tags.
- */
void BM_lnorspace_update(BMesh *bm)
{
if (bm->lnor_spacearr == NULL) {
@@ -2249,10 +2213,6 @@ void BM_loop_normal_editdata_array_free(BMLoopNorEditDataArray *lnors_ed_arr)
/** \name Custom Normals / Vector Layer Conversion
* \{ */
-/**
- * \warning This function sets #BM_ELEM_TAG on loops & edges via #bm_mesh_loops_calc_normals,
- * take care to run this before setting up tags.
- */
bool BM_custom_loop_normals_to_vector_layer(BMesh *bm)
{
BMFace *f;
diff --git a/source/blender/bmesh/intern/bmesh_mesh_normals.h b/source/blender/bmesh/intern/bmesh_mesh_normals.h
index ecd627d4bfe..a2e64b1dc9b 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_normals.h
+++ b/source/blender/bmesh/intern/bmesh_mesh_normals.h
@@ -30,17 +30,39 @@ struct BMeshNormalsUpdate_Params {
bool face_normals;
};
+/**
+ * \brief BMesh Compute Normals
+ *
+ * Updates the normals of a mesh.
+ */
void BM_mesh_normals_update_ex(BMesh *bm, const struct BMeshNormalsUpdate_Params *param);
void BM_mesh_normals_update(BMesh *bm);
+/**
+ * A version of #BM_mesh_normals_update that updates a subset of geometry,
+ * used to avoid the overhead of updating everything.
+ */
void BM_mesh_normals_update_with_partial_ex(BMesh *bm,
const struct BMPartialUpdate *bmpinfo,
const struct BMeshNormalsUpdate_Params *param);
void BM_mesh_normals_update_with_partial(BMesh *bm, const struct BMPartialUpdate *bmpinfo);
+/**
+ * \brief BMesh Compute Normals from/to external data.
+ *
+ * Computes the vertex normals of a mesh into vnos,
+ * using given vertex coordinates (vcos) and polygon normals (fnos).
+ */
void BM_verts_calc_normal_vcos(BMesh *bm,
const float (*fnos)[3],
const float (*vcos)[3],
float (*vnos)[3]);
+/**
+ * \brief BMesh Compute Loop Normals from/to external data.
+ *
+ * Compute split normals, i.e. vertex normals associated with each poly (hence 'loop normals').
+ * Useful to materialize sharp edges (or non-smooth faces) without actually modifying the geometry
+ * (splitting edges).
+ */
void BM_loops_calc_normal_vcos(BMesh *bm,
const float (*vcos)[3],
const float (*vnos)[3],
@@ -53,10 +75,19 @@ void BM_loops_calc_normal_vcos(BMesh *bm,
const int cd_loop_clnors_offset,
const bool do_rebuild);
+/**
+ * Check whether given loop is part of an unknown-so-far cyclic smooth fan, or not.
+ * Needed because cyclic smooth fans have no obvious 'entry point',
+ * and yet we need to walk them once, and only once.
+ */
bool BM_loop_check_cyclic_smooth_fan(BMLoop *l_curr);
void BM_lnorspacearr_store(BMesh *bm, float (*r_lnors)[3]);
void BM_lnorspace_invalidate(BMesh *bm, const bool do_invalidate_all);
void BM_lnorspace_rebuild(BMesh *bm, bool preserve_clnor);
+/**
+ * \warning This function sets #BM_ELEM_TAG on loops & edges via #bm_mesh_loops_calc_normals,
+ * take care to run this before setting up tags.
+ */
void BM_lnorspace_update(BMesh *bm);
void BM_normals_loops_edges_tag(BMesh *bm, const bool do_edges);
#ifndef NDEBUG
@@ -68,7 +99,17 @@ struct BMLoopNorEditDataArray *BM_loop_normal_editdata_array_init(BMesh *bm,
const bool do_all_loops_of_vert);
void BM_loop_normal_editdata_array_free(struct BMLoopNorEditDataArray *lnors_ed_arr);
+/**
+ * \warning This function sets #BM_ELEM_TAG on loops & edges via #bm_mesh_loops_calc_normals,
+ * take care to run this before setting up tags.
+ */
bool BM_custom_loop_normals_to_vector_layer(struct BMesh *bm);
void BM_custom_loop_normals_from_vector_layer(struct BMesh *bm, bool add_sharp_edges);
+/**
+ * Define sharp edges as needed to mimic 'autosmooth' from angle threshold.
+ *
+ * Used when defining an empty custom loop normals data layer,
+ * to keep same shading as with auto-smooth!
+ */
void BM_edges_sharp_from_angle_set(BMesh *bm, const float split_angle);
diff --git a/source/blender/bmesh/intern/bmesh_mesh_partial_update.c b/source/blender/bmesh/intern/bmesh_mesh_partial_update.c
index 46fd2ad9a31..ad9b8414525 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_partial_update.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_partial_update.c
@@ -103,10 +103,6 @@ BLI_INLINE bool partial_elem_face_ensure(BMPartialUpdate *bmpinfo,
return false;
}
-/**
- * All Tagged & Connected, see: #BM_mesh_partial_create_from_verts
- * Operate on everything that's tagged as well as connected geometry.
- */
BMPartialUpdate *BM_mesh_partial_create_from_verts(BMesh *bm,
const BMPartialUpdate_Params *params,
const BLI_bitmap *verts_mask,
@@ -216,11 +212,6 @@ BMPartialUpdate *BM_mesh_partial_create_from_verts(BMesh *bm,
return bmpinfo;
}
-/**
- * All Connected, operate on all faces that have both tagged and un-tagged vertices.
- *
- * Reduces computations when transforming isolated regions.
- */
BMPartialUpdate *BM_mesh_partial_create_from_verts_group_single(
BMesh *bm,
const BMPartialUpdate_Params *params,
@@ -314,25 +305,6 @@ BMPartialUpdate *BM_mesh_partial_create_from_verts_group_single(
return bmpinfo;
}
-/**
- * All Connected, operate on all faces that have vertices in the same group.
- *
- * Reduces computations when transforming isolated regions.
- *
- * This is a version of #BM_mesh_partial_create_from_verts_group_single
- * that handles multiple groups instead of a bitmap mask.
- *
- * This is needed for example when transform has mirror enabled,
- * since one side needs to have a different group to the other since a face that has vertices
- * attached to both won't have an affine transformation.
- *
- * \param verts_groups: Vertex aligned array of groups.
- * Values are used as follows:
- * - >0: Each face is grouped with other faces of the same group.
- * - 0: Not in a group (don't handle these).
- * - -1: Don't use grouping logic (include any face that contains a vertex with this group).
- * \param verts_groups_count: The number of non-zero values in `verts_groups`.
- */
BMPartialUpdate *BM_mesh_partial_create_from_verts_group_multi(
BMesh *bm,
const BMPartialUpdate_Params *params,
diff --git a/source/blender/bmesh/intern/bmesh_mesh_partial_update.h b/source/blender/bmesh/intern/bmesh_mesh_partial_update.h
index cf4eab22836..57f57053606 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_partial_update.h
+++ b/source/blender/bmesh/intern/bmesh_mesh_partial_update.h
@@ -52,18 +52,46 @@ typedef struct BMPartialUpdate {
BMPartialUpdate_Params params;
} BMPartialUpdate;
+/**
+ * All Tagged & Connected, see: #BM_mesh_partial_create_from_verts
+ * Operate on everything that's tagged as well as connected geometry.
+ */
BMPartialUpdate *BM_mesh_partial_create_from_verts(BMesh *bm,
const BMPartialUpdate_Params *params,
const unsigned int *verts_mask,
const int verts_mask_count)
ATTR_NONNULL(1, 2, 3) ATTR_WARN_UNUSED_RESULT;
+/**
+ * All Connected, operate on all faces that have both tagged and un-tagged vertices.
+ *
+ * Reduces computations when transforming isolated regions.
+ */
BMPartialUpdate *BM_mesh_partial_create_from_verts_group_single(
BMesh *bm,
const BMPartialUpdate_Params *params,
const unsigned int *verts_mask,
const int verts_mask_count) ATTR_NONNULL(1, 2, 3) ATTR_WARN_UNUSED_RESULT;
+/**
+ * All Connected, operate on all faces that have vertices in the same group.
+ *
+ * Reduces computations when transforming isolated regions.
+ *
+ * This is a version of #BM_mesh_partial_create_from_verts_group_single
+ * that handles multiple groups instead of a bitmap mask.
+ *
+ * This is needed for example when transform has mirror enabled,
+ * since one side needs to have a different group to the other since a face that has vertices
+ * attached to both won't have an affine transformation.
+ *
+ * \param verts_group: Vertex aligned array of groups.
+ * Values are used as follows:
+ * - >0: Each face is grouped with other faces of the same group.
+ * - 0: Not in a group (don't handle these).
+ * - -1: Don't use grouping logic (include any face that contains a vertex with this group).
+ * \param verts_group_count: The number of non-zero values in `verts_groups`.
+ */
BMPartialUpdate *BM_mesh_partial_create_from_verts_group_multi(
BMesh *bm,
const BMPartialUpdate_Params *params,
diff --git a/source/blender/bmesh/intern/bmesh_mesh_tessellate.c b/source/blender/bmesh/intern/bmesh_mesh_tessellate.c
index 9f477bc8a9c..94d8901edf8 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_tessellate.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_tessellate.c
@@ -549,9 +549,6 @@ static int bmesh_calc_tessellation_for_face_beauty(BMLoop *(*looptris)[3],
}
}
-/**
- * A version of #BM_mesh_calc_tessellation that avoids degenerate triangles.
- */
void BM_mesh_calc_tessellation_beauty(BMesh *bm, BMLoop *(*looptris)[3])
{
#ifndef NDEBUG
diff --git a/source/blender/bmesh/intern/bmesh_mesh_tessellate.h b/source/blender/bmesh/intern/bmesh_mesh_tessellate.h
index 9a6a20d7568..91eac6bc6fc 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_tessellate.h
+++ b/source/blender/bmesh/intern/bmesh_mesh_tessellate.h
@@ -35,6 +35,9 @@ void BM_mesh_calc_tessellation_ex(BMesh *bm,
const struct BMeshCalcTessellation_Params *params);
void BM_mesh_calc_tessellation(BMesh *bm, BMLoop *(*looptris)[3]);
+/**
+ * A version of #BM_mesh_calc_tessellation that avoids degenerate triangles.
+ */
void BM_mesh_calc_tessellation_beauty(BMesh *bm, BMLoop *(*looptris)[3]);
void BM_mesh_calc_tessellation_with_partial_ex(BMesh *bm,
diff --git a/source/blender/bmesh/intern/bmesh_mesh_validate.c b/source/blender/bmesh/intern/bmesh_mesh_validate.c
index f8830e1557b..3145ceceafd 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_validate.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_validate.c
@@ -50,12 +50,6 @@
(void)0
# endif
-/**
- * Check of this BMesh is valid,
- * this function can be slow since its intended to help with debugging.
- *
- * \return true when the mesh is valid.
- */
bool BM_mesh_validate(BMesh *bm)
{
EdgeHash *edge_hash = BLI_edgehash_new_ex(__func__, bm->totedge);
diff --git a/source/blender/bmesh/intern/bmesh_mesh_validate.h b/source/blender/bmesh/intern/bmesh_mesh_validate.h
index 2112e1f3200..203c8a89c55 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_validate.h
+++ b/source/blender/bmesh/intern/bmesh_mesh_validate.h
@@ -23,4 +23,10 @@
* \ingroup bmesh
*/
+/**
+ * Check of this #BMesh is valid,
+ * this function can be slow since its intended to help with debugging.
+ *
+ * \return true when the mesh is valid.
+ */
bool BM_mesh_validate(BMesh *bm);
diff --git a/source/blender/bmesh/intern/bmesh_mods.c b/source/blender/bmesh/intern/bmesh_mods.c
index 5fa12397a07..0a3857a6e0a 100644
--- a/source/blender/bmesh/intern/bmesh_mods.c
+++ b/source/blender/bmesh/intern/bmesh_mods.c
@@ -31,31 +31,6 @@
#include "bmesh.h"
#include "intern/bmesh_private.h"
-/**
- * \brief Dissolve Vert
- *
- * Turns the face region surrounding a manifold vertex into a single polygon.
- *
- * \par Example:
- * <pre>
- * +---------+ +---------+
- * | \ / | | |
- * Before: | v | After: | |
- * | / \ | | |
- * +---------+ +---------+
- * </pre>
- *
- * This function can also collapse edges too
- * in cases when it can't merge into faces.
- *
- * \par Example:
- * <pre>
- * Before: +----v----+ After: +---------+
- * </pre>
- *
- * \note dissolves vert, in more situations than BM_disk_dissolve
- * (e.g. if the vert is part of a wire edge, etc).
- */
bool BM_vert_dissolve(BMesh *bm, BMVert *v)
{
/* logic for 3 or more is identical */
@@ -87,9 +62,6 @@ bool BM_vert_dissolve(BMesh *bm, BMVert *v)
return BM_disk_dissolve(bm, v);
}
-/**
- * dissolves all faces around a vert, and removes it.
- */
bool BM_disk_dissolve(BMesh *bm, BMVert *v)
{
BMEdge *e, *keepedge = NULL, *baseedge = NULL;
@@ -205,19 +177,6 @@ bool BM_disk_dissolve(BMesh *bm, BMVert *v)
return true;
}
-/**
- * \brief Faces Join Pair
- *
- * Joins two adjacent faces together.
- *
- * \note This method calls to #BM_faces_join to do its work.
- * This means connected edges which also share the two faces will be joined.
- *
- * If the windings do not match the winding of the new face will follow
- * \a l_a's winding (i.e. \a l_b will be reversed before the join).
- *
- * \return The combined face or NULL on failure.
- */
BMFace *BM_faces_join_pair(BMesh *bm, BMLoop *l_a, BMLoop *l_b, const bool do_del)
{
BLI_assert((l_a != l_b) && (l_a->e == l_b->e));
@@ -231,24 +190,6 @@ BMFace *BM_faces_join_pair(BMesh *bm, BMLoop *l_a, BMLoop *l_b, const bool do_de
return BM_faces_join(bm, faces, 2, do_del);
}
-/**
- * \brief Face Split
- *
- * Split a face along two vertices. returns the newly made face, and sets
- * the \a r_l member to a loop in the newly created edge.
- *
- * \param bm: The bmesh
- * \param f: the original face
- * \param l_a, l_b: Loops of this face, their vertices define
- * the split edge to be created (must be differ and not can't be adjacent in the face).
- * \param r_l: pointer which will receive the BMLoop for the split edge in the new face
- * \param example: Edge used for attributes of splitting edge, if non-NULL
- * \param no_double: Use an existing edge if found
- *
- * \return Pointer to the newly created face representing one side of the split
- * if the split is successful (and the original face will be the other side).
- * NULL if the split fails.
- */
BMFace *BM_face_split(BMesh *bm,
BMFace *f,
BMLoop *l_a,
@@ -313,24 +254,6 @@ BMFace *BM_face_split(BMesh *bm,
return f_new;
}
-/**
- * \brief Face Split with intermediate points
- *
- * Like BM_face_split, but with an edge split by \a n intermediate points with given coordinates.
- *
- * \param bm: The bmesh.
- * \param f: the original face.
- * \param l_a, l_b: Vertices which define the split edge, must be different.
- * \param cos: Array of coordinates for intermediate points.
- * \param n: Length of \a cos (must be > 0).
- * \param r_l: pointer which will receive the BMLoop.
- * for the first split edge (from \a l_a) in the new face.
- * \param example: Edge used for attributes of splitting edge, if non-NULL.
- *
- * \return Pointer to the newly created face representing one side of the split
- * if the split is successful (and the original face will be the other side).
- * NULL if the split fails.
- */
BMFace *BM_face_split_n(BMesh *bm,
BMFace *f,
BMLoop *l_a,
@@ -404,29 +327,6 @@ BMFace *BM_face_split_n(BMesh *bm,
return f_new;
}
-/**
- * \brief Vert Collapse Faces
- *
- * Collapses vertex \a v_kill that has only two manifold edges
- * onto a vertex it shares an edge with.
- * \a fac defines the amount of interpolation for Custom Data.
- *
- * \note that this is not a general edge collapse function.
- *
- * \note this function is very close to #BM_vert_collapse_edge,
- * both collapse a vertex and return a new edge.
- * Except this takes a factor and merges custom data.
- *
- * \param bm: The bmesh
- * \param e_kill: The edge to collapse
- * \param v_kill: The vertex to collapse into the edge
- * \param fac: The factor along the edge
- * \param join_faces: When true the faces around the vertex will be joined
- * otherwise collapse the vertex by merging the 2 edges this vert touches into one.
- * \param kill_degenerate_faces: Removes faces with less than 3 verts after collapsing.
- *
- * \returns The New Edge
- */
BMEdge *BM_vert_collapse_faces(BMesh *bm,
BMEdge *e_kill,
BMVert *v_kill,
@@ -513,13 +413,6 @@ BMEdge *BM_vert_collapse_faces(BMesh *bm,
return e_new;
}
-/**
- * \brief Vert Collapse Faces
- *
- * Collapses a vertex onto another vertex it shares an edge with.
- *
- * \return The New Edge
- */
BMEdge *BM_vert_collapse_edge(BMesh *bm,
BMEdge *e_kill,
BMVert *v_kill,
@@ -560,34 +453,12 @@ BMEdge *BM_vert_collapse_edge(BMesh *bm,
#undef DO_V_INTERP
-/**
- * Collapse and edge into a single vertex.
- */
BMVert *BM_edge_collapse(
BMesh *bm, BMEdge *e_kill, BMVert *v_kill, const bool do_del, const bool kill_degenerate_faces)
{
return bmesh_kernel_join_vert_kill_edge(bm, e_kill, v_kill, do_del, true, kill_degenerate_faces);
}
-/**
- * \brief Edge Split
- *
- * <pre>
- * Before: v
- * +-----------------------------------+
- * e
- *
- * After: v v_new (returned)
- * +-----------------+-----------------+
- * r_e e
- * </pre>
- *
- * \param e: The edge to split.
- * \param v: One of the vertices in \a e and defines the "from" end of the splitting operation,
- * the new vertex will be \a fac of the way from \a v to the other end.
- * \param r_e: The newly created edge.
- * \return The new vertex.
- */
BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac)
{
BMVert *v_new, *v_other;
@@ -703,11 +574,6 @@ BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac)
return v_new;
}
-/**
- * \brief Split an edge multiple times evenly
- *
- * \param r_varr: Optional array, verts in between (v1 -> v2)
- */
BMVert *BM_edge_split_n(BMesh *bm, BMEdge *e, int numcuts, BMVert **r_varr)
{
int i;
@@ -725,11 +591,6 @@ BMVert *BM_edge_split_n(BMesh *bm, BMEdge *e, int numcuts, BMVert **r_varr)
return v_new;
}
-/**
- * Swap v1 & v2
- *
- * \note Typically we shouldn't care about this, however it's used when extruding wire edges.
- */
void BM_edge_verts_swap(BMEdge *e)
{
SWAP(BMVert *, e->v1, e->v2);
@@ -785,20 +646,6 @@ bool BM_face_validate(BMFace *face, FILE *err)
}
#endif
-/**
- * Calculate the 2 loops which _would_ make up the newly rotated Edge
- * but don't actually change anything.
- *
- * Use this to further inspect if the loops to be connected have issues:
- *
- * Examples:
- * - the newly formed edge already exists
- * - the new face would be degenerate (zero area / concave / bow-tie)
- * - may want to measure if the new edge gives improved results topology.
- * over the old one, as with beauty fill.
- *
- * \note #BM_edge_rotate_check must have already run.
- */
void BM_edge_calc_rotate(BMEdge *e, const bool ccw, BMLoop **r_l1, BMLoop **r_l2)
{
BMVert *v1, *v2;
@@ -825,12 +672,6 @@ void BM_edge_calc_rotate(BMEdge *e, const bool ccw, BMLoop **r_l1, BMLoop **r_l2
*r_l2 = BM_face_other_vert_loop(fa, v1, v2);
}
-/**
- * \brief Check if Rotate Edge is OK
- *
- * Quick check to see if we could rotate the edge,
- * use this to avoid calling exceptions on common cases.
- */
bool BM_edge_rotate_check(BMEdge *e)
{
BMFace *fa, *fb;
@@ -860,17 +701,6 @@ bool BM_edge_rotate_check(BMEdge *e)
return false;
}
-/**
- * \brief Check if Edge Rotate Gives Degenerate Faces
- *
- * Check 2 cases
- * 1) does the newly forms edge form a flipped face (compare with previous cross product)
- * 2) does the newly formed edge cause a zero area corner (or close enough to be almost zero)
- *
- * \param e: The edge to test rotation.
- * \param l1, l2: are the loops of the proposed verts to rotate too and should
- * be the result of calling #BM_edge_calc_rotate
- */
bool BM_edge_rotate_check_degenerate(BMEdge *e, BMLoop *l1, BMLoop *l2)
{
/* NOTE: for these vars 'old' just means initial edge state. */
@@ -966,20 +796,6 @@ bool BM_edge_rotate_check_beauty(BMEdge *e, BMLoop *l1, BMLoop *l2)
return (len_squared_v3v3(e->v1->co, e->v2->co) > len_squared_v3v3(l1->v->co, l2->v->co));
}
-/**
- * \brief Rotate Edge
- *
- * Spins an edge topologically,
- * either counter-clockwise or clockwise depending on \a ccw.
- *
- * \return The spun edge, NULL on error
- * (e.g., if the edge isn't surrounded by exactly two faces).
- *
- * \note This works by dissolving the edge then re-creating it,
- * so the returned edge won't have the same pointer address as the original one.
- *
- * \see header definition for \a check_flag enum.
- */
BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_flag)
{
BMVert *v1, *v2;
@@ -1091,9 +907,6 @@ BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_f
return e_new;
}
-/**
- * \brief Rip a single face from a vertex fan
- */
BMVert *BM_face_loop_separate(BMesh *bm, BMLoop *l_sep)
{
return bmesh_kernel_unglue_region_make_vert(bm, l_sep);
diff --git a/source/blender/bmesh/intern/bmesh_mods.h b/source/blender/bmesh/intern/bmesh_mods.h
index 4328187b95e..f4a5a0bce33 100644
--- a/source/blender/bmesh/intern/bmesh_mods.h
+++ b/source/blender/bmesh/intern/bmesh_mods.h
@@ -20,14 +20,73 @@
* \ingroup bmesh
*/
+/**
+ * \brief Dissolve Vert
+ *
+ * Turns the face region surrounding a manifold vertex into a single polygon.
+ *
+ * \par Example:
+ * <pre>
+ * +---------+ +---------+
+ * | \ / | | |
+ * Before: | v | After: | |
+ * | / \ | | |
+ * +---------+ +---------+
+ * </pre>
+ *
+ * This function can also collapse edges too
+ * in cases when it can't merge into faces.
+ *
+ * \par Example:
+ * <pre>
+ * Before: +----v----+ After: +---------+
+ * </pre>
+ *
+ * \note dissolves vert, in more situations than BM_disk_dissolve
+ * (e.g. if the vert is part of a wire edge, etc).
+ */
bool BM_vert_dissolve(BMesh *bm, BMVert *v);
+/**
+ * dissolves all faces around a vert, and removes it.
+ */
bool BM_disk_dissolve(BMesh *bm, BMVert *v);
+/**
+ * \brief Faces Join Pair
+ *
+ * Joins two adjacent faces together.
+ *
+ * \note This method calls to #BM_faces_join to do its work.
+ * This means connected edges which also share the two faces will be joined.
+ *
+ * If the windings do not match the winding of the new face will follow
+ * \a l_a's winding (i.e. \a l_b will be reversed before the join).
+ *
+ * \return The combined face or NULL on failure.
+ */
BMFace *BM_faces_join_pair(BMesh *bm, BMLoop *l_a, BMLoop *l_b, const bool do_del);
/** see: bmesh_polygon_edgenet.h for #BM_face_split_edgenet */
+/**
+ * \brief Face Split
+ *
+ * Split a face along two vertices. returns the newly made face, and sets
+ * the \a r_l member to a loop in the newly created edge.
+ *
+ * \param bm: The bmesh
+ * \param f: the original face
+ * \param l_a, l_b: Loops of this face, their vertices define
+ * the split edge to be created (must be differ and not can't be adjacent in the face).
+ * \param r_l: pointer which will receive the BMLoop for the split edge in the new face
+ * \param example: Edge used for attributes of splitting edge, if non-NULL
+ * \param no_double: Use an existing edge if found
+ *
+ * \return Pointer to the newly created face representing one side of the split
+ * if the split is successful (and the original face will be the other side).
+ * NULL if the split fails.
+ */
BMFace *BM_face_split(BMesh *bm,
BMFace *f,
BMLoop *l_a,
@@ -36,6 +95,24 @@ BMFace *BM_face_split(BMesh *bm,
BMEdge *example,
const bool no_double);
+/**
+ * \brief Face Split with intermediate points
+ *
+ * Like BM_face_split, but with an edge split by \a n intermediate points with given coordinates.
+ *
+ * \param bm: The bmesh.
+ * \param f: the original face.
+ * \param l_a, l_b: Vertices which define the split edge, must be different.
+ * \param cos: Array of coordinates for intermediate points.
+ * \param n: Length of \a cos (must be > 0).
+ * \param r_l: pointer which will receive the BMLoop.
+ * for the first split edge (from \a l_a) in the new face.
+ * \param example: Edge used for attributes of splitting edge, if non-NULL.
+ *
+ * \return Pointer to the newly created face representing one side of the split
+ * if the split is successful (and the original face will be the other side).
+ * NULL if the split fails.
+ */
BMFace *BM_face_split_n(BMesh *bm,
BMFace *f,
BMLoop *l_a,
@@ -45,6 +122,29 @@ BMFace *BM_face_split_n(BMesh *bm,
BMLoop **r_l,
BMEdge *example);
+/**
+ * \brief Vert Collapse Faces
+ *
+ * Collapses vertex \a v_kill that has only two manifold edges
+ * onto a vertex it shares an edge with.
+ * \a fac defines the amount of interpolation for Custom Data.
+ *
+ * \note that this is not a general edge collapse function.
+ *
+ * \note this function is very close to #BM_vert_collapse_edge,
+ * both collapse a vertex and return a new edge.
+ * Except this takes a factor and merges custom data.
+ *
+ * \param bm: The bmesh
+ * \param e_kill: The edge to collapse
+ * \param v_kill: The vertex to collapse into the edge
+ * \param fac: The factor along the edge
+ * \param join_faces: When true the faces around the vertex will be joined
+ * otherwise collapse the vertex by merging the 2 edges this vert touches into one.
+ * \param kill_degenerate_faces: Removes faces with less than 3 verts after collapsing.
+ *
+ * \returns The New Edge
+ */
BMEdge *BM_vert_collapse_faces(BMesh *bm,
BMEdge *e_kill,
BMVert *v_kill,
@@ -53,6 +153,13 @@ BMEdge *BM_vert_collapse_faces(BMesh *bm,
const bool join_faces,
const bool kill_degenerate_faces,
const bool kill_duplicate_faces);
+/**
+ * \brief Vert Collapse Faces
+ *
+ * Collapses a vertex onto another vertex it shares an edge with.
+ *
+ * \return The New Edge
+ */
BMEdge *BM_vert_collapse_edge(BMesh *bm,
BMEdge *e_kill,
BMVert *v_kill,
@@ -60,24 +167,101 @@ BMEdge *BM_vert_collapse_edge(BMesh *bm,
const bool kill_degenerate_faces,
const bool kill_duplicate_faces);
+/**
+ * Collapse and edge into a single vertex.
+ */
BMVert *BM_edge_collapse(BMesh *bm,
BMEdge *e_kill,
BMVert *v_kill,
const bool do_del,
const bool kill_degenerate_faces);
+/**
+ * \brief Edge Split
+ *
+ * <pre>
+ * Before: v
+ * +-----------------------------------+
+ * e
+ *
+ * After: v v_new (returned)
+ * +-----------------+-----------------+
+ * r_e e
+ * </pre>
+ *
+ * \param e: The edge to split.
+ * \param v: One of the vertices in \a e and defines the "from" end of the splitting operation,
+ * the new vertex will be \a fac of the way from \a v to the other end.
+ * \param r_e: The newly created edge.
+ * \return The new vertex.
+ */
BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac);
+/**
+ * \brief Split an edge multiple times evenly
+ *
+ * \param r_varr: Optional array, verts in between (v1 -> v2)
+ */
BMVert *BM_edge_split_n(BMesh *bm, BMEdge *e, int numcuts, BMVert **r_varr);
+/**
+ * Swap v1 & v2
+ *
+ * \note Typically we shouldn't care about this, however it's used when extruding wire edges.
+ */
void BM_edge_verts_swap(BMEdge *e);
bool BM_face_validate(BMFace *face, FILE *err);
+/**
+ * Calculate the 2 loops which _would_ make up the newly rotated Edge
+ * but don't actually change anything.
+ *
+ * Use this to further inspect if the loops to be connected have issues:
+ *
+ * Examples:
+ * - the newly formed edge already exists
+ * - the new face would be degenerate (zero area / concave / bow-tie)
+ * - may want to measure if the new edge gives improved results topology.
+ * over the old one, as with beauty fill.
+ *
+ * \note #BM_edge_rotate_check must have already run.
+ */
void BM_edge_calc_rotate(BMEdge *e, const bool ccw, BMLoop **r_l1, BMLoop **r_l2);
+/**
+ * \brief Check if Rotate Edge is OK
+ *
+ * Quick check to see if we could rotate the edge,
+ * use this to avoid calling exceptions on common cases.
+ */
bool BM_edge_rotate_check(BMEdge *e);
+/**
+ * \brief Check if Edge Rotate Gives Degenerate Faces
+ *
+ * Check 2 cases
+ * 1) does the newly forms edge form a flipped face (compare with previous cross product)
+ * 2) does the newly formed edge cause a zero area corner (or close enough to be almost zero)
+ *
+ * \param e: The edge to test rotation.
+ * \param l1, l2: are the loops of the proposed verts to rotate too and should
+ * be the result of calling #BM_edge_calc_rotate
+ */
bool BM_edge_rotate_check_degenerate(BMEdge *e, BMLoop *l1, BMLoop *l2);
bool BM_edge_rotate_check_beauty(BMEdge *e, BMLoop *l1, BMLoop *l2);
+/**
+ * \brief Rotate Edge
+ *
+ * Spins an edge topologically,
+ * either counter-clockwise or clockwise depending on \a ccw.
+ *
+ * \return The spun edge, NULL on error
+ * (e.g., if the edge isn't surrounded by exactly two faces).
+ *
+ * \note This works by dissolving the edge then re-creating it,
+ * so the returned edge won't have the same pointer address as the original one.
+ *
+ * \see header definition for \a check_flag enum.
+ */
BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_flag);
/** Flags for #BM_edge_rotate */
@@ -92,6 +276,9 @@ enum {
BM_EDGEROT_CHECK_BEAUTY = (1 << 3),
};
+/**
+ * \brief Rip a single face from a vertex fan
+ */
BMVert *BM_face_loop_separate(BMesh *bm, BMLoop *l_sep);
BMVert *BM_face_loop_separate_multi_isolated(BMesh *bm, BMLoop *l_sep);
BMVert *BM_face_loop_separate_multi(BMesh *bm, BMLoop **larr, int larr_len);
diff --git a/source/blender/bmesh/intern/bmesh_operator_api.h b/source/blender/bmesh/intern/bmesh_operator_api.h
index 0f9488bd091..c60e8af68e5 100644
--- a/source/blender/bmesh/intern/bmesh_operator_api.h
+++ b/source/blender/bmesh/intern/bmesh_operator_api.h
@@ -341,50 +341,161 @@ typedef struct BMOpDefine {
BMOpTypeFlag type_flag;
} BMOpDefine;
-/*------------- Operator API --------------*/
-
-/* data types that use pointers (arrays, etc) should never
- * have it set directly. and never use BMO_slot_ptr_set to
- * pass in a list of edges or any arrays, really. */
+/* -------------------------------------------------------------------- */
+/** \name BMesh Operator API
+ *
+ * \note data types that use pointers (arrays, etc) must _never_ have it set directly.
+ * Don't #BMO_slot_ptr_set to pass in a list of edges or any arrays.
+ * \{ */
+/**
+ * \brief BMESH OPSTACK INIT OP
+ *
+ * Initializes an operator structure to a certain type
+ */
void BMO_op_init(BMesh *bm, BMOperator *op, const int flag, const char *opname);
-/* executes an operator, pushing and popping a new tool flag
- * layer as appropriate. */
+/**
+ * \brief BMESH OPSTACK EXEC OP
+ *
+ * Executes a passed in operator.
+ *
+ * This handles the allocation and freeing of temporary tool flag
+ * layers and starting/stopping the modeling loop.
+ * Can be called from other operators exec callbacks as well.
+ */
void BMO_op_exec(BMesh *bm, BMOperator *op);
-/* finishes an operator (though note the operator's tool flag is removed
- * after it finishes executing in BMO_op_exec). */
+/**
+ * \brief BMESH OPSTACK FINISH OP
+ *
+ * Does housekeeping chores related to finishing up an operator.
+ *
+ * \note the operator's tool flag is removed after it finishes executing in #BMO_op_exec.
+ */
void BMO_op_finish(BMesh *bm, BMOperator *op);
-/* count the number of elements with the specified flag enabled.
- * type can be a bitmask of BM_FACE, BM_EDGE, or BM_FACE. */
+/**
+ * Count the number of elements with the specified flag enabled.
+ * type can be a bit-mask of #BM_FACE, #BM_EDGE, or #BM_FACE.
+ */
int BMO_mesh_enabled_flag_count(BMesh *bm, const char htype, const short oflag);
-/* count the number of elements with the specified flag disabled.
- * type can be a bitmask of BM_FACE, BM_EDGE, or BM_FACE. */
+/**
+ * Count the number of elements with the specified flag disabled.
+ * type can be a bit-mask of #BM_FACE, #BM_EDGE, or #BM_FACE.
+ */
int BMO_mesh_disabled_flag_count(BMesh *bm, const char htype, const short oflag);
-/*---------formatted operator initialization/execution-----------*/
+/**
+ * \brief BMESH OPSTACK PUSH
+ *
+ * Pushes the operator-stack down one level and allocates a new flag layer if appropriate.
+ */
void BMO_push(BMesh *bm, BMOperator *op);
+/**
+ * \brief BMESH OPSTACK POP
+ *
+ * Pops the operator-stack one level and frees a flag layer if appropriate
+ *
+ * BMESH_TODO: investigate NOT freeing flag layers.
+ */
void BMO_pop(BMesh *bm);
-/* Executes an operator. */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Formatted Operator Initialization/Execution
+ *
+ * Format Strings for #BMOperator Initialization.
+ *
+ * This system is used to execute or initialize an operator,
+ * using a formatted-string system.
+ *
+ * The basic format for the format string is:
+ * `[operatorname] [slot_name]=%[code] [slot_name]=%[code]`
+ *
+ * Example:
+ *
+ * \code{.c}
+ * BMO_op_callf(bm, BMO_FLAG_DEFAULTS,
+ * "delete context=%i geom=%hv",
+ * DEL_ONLYFACES, BM_ELEM_SELECT);
+ * \endcode
+ * **Primitive Types**
+ * - `b` - boolean (same as int but 1/0 only). #BMO_OP_SLOT_BOOL
+ * - `i` - int. #BMO_OP_SLOT_INT
+ * - `f` - float. #BMO_OP_SLOT_FLT
+ * - `p` - pointer (normally to a Scene/Mesh/Object/BMesh). #BMO_OP_SLOT_PTR
+ * - `m3` - 3x3 matrix of floats. #BMO_OP_SLOT_MAT
+ * - `m4` - 4x4 matrix of floats. #BMO_OP_SLOT_MAT
+ * - `v` - 3D vector of floats. #BMO_OP_SLOT_VEC
+ * **Utility**
+ *
+ * Pass an existing slot which is copied to either an input or output slot.
+ * Taking the operator and slot-name pair of args (BMOperator *, const char *).
+ * - `s` - slot_in (lower case)
+ * - `S` - slot_out (upper case)
+ * **Element Buffer** (#BMO_OP_SLOT_ELEMENT_BUF)
+ * - `e` - single element vert/edge/face (use with #BMO_OP_SLOT_SUBTYPE_ELEM_IS_SINGLE).
+ * - `eb` - elem buffer, take an array and a length.
+ * - `av` - all verts
+ * - `ae` - all edges
+ * - `af` - all faces
+ * - `hv` - header flagged verts (hflag)
+ * - `he` - header flagged edges (hflag)
+ * - `hf` - header flagged faces (hflag)
+ * - `Hv` - header flagged verts (hflag off)
+ * - `He` - header flagged edges (hflag off)
+ * - `Hf` - header flagged faces (hflag off)
+ * - `fv` - flagged verts (oflag)
+ * - `fe` - flagged edges (oflag)
+ * - `ff` - flagged faces (oflag)
+ * - `Fv` - flagged verts (oflag off)
+ * - `Fe` - flagged edges (oflag off)
+ * - `Ff` - flagged faces (oflag off)
+ *
+ * \note The common v/e/f suffix can be mixed,
+ * so `avef` is can be used for all verts, edges and faces.
+ * Order is not important so `Hfev` is also valid (all un-flagged verts, edges and faces).
+ *
+ * \{ */
+
+/** Executes an operator. */
bool BMO_op_callf(BMesh *bm, const int flag, const char *fmt, ...);
-/* initializes, but doesn't execute an operator. this is so you can
+/**
+ * Initializes, but doesn't execute an operator. this is so you can
* gain access to the outputs of the operator. note that you have
- * to execute/finish (BMO_op_exec and BMO_op_finish) yourself. */
+ * to execute/finish (BMO_op_exec and BMO_op_finish) yourself.
+ */
bool BMO_op_initf(BMesh *bm, BMOperator *op, const int flag, const char *fmt, ...);
-/* va_list version, used to implement the above two functions,
- * plus EDBM_op_callf in editmesh_utils.c. */
+/**
+ * A `va_list` version, used to implement the above two functions,
+ * plus #EDBM_op_callf in editmesh_utils.c.
+ */
bool BMO_op_vinitf(BMesh *bm, BMOperator *op, const int flag, const char *fmt, va_list vlist);
-/* test whether a named slot exists */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name BMesh Operator Slot Access
+ * \{ */
+
+/**
+ * \brief BMESH OPSTACK HAS SLOT
+ *
+ * \return Success if the slot if found.
+ */
bool BMO_slot_exists(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier);
/* get a pointer to a slot. this may be removed layer on from the public API. */
+/**
+ * \brief BMESH OPSTACK GET SLOT
+ *
+ * Returns a pointer to the slot of type 'slot_code'
+ */
BMOpSlot *BMO_slot_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier);
/* copies the data of a slot from one operator to another. src and dst are the
@@ -393,12 +504,20 @@ BMOpSlot *BMO_slot_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identif
_bmo_slot_copy( \
(op_src)->slots_src, slot_name_src, (op_dst)->slots_dst, slot_name_dst, (op_dst)->arena)
+/**
+ * \brief BMESH OPSTACK COPY SLOT
+ *
+ * define used.
+ * Copies data from one slot to another.
+ */
void _bmo_slot_copy(BMOpSlot slot_args_src[BMO_OP_MAX_SLOTS],
const char *slot_name_src,
BMOpSlot slot_args_dst[BMO_OP_MAX_SLOTS],
const char *slot_name_dst,
struct MemArena *arena_dst);
+/** \} */
+
/* del "context" slot values, used for operator too */
enum {
DEL_VERTS = 1,
@@ -433,6 +552,10 @@ typedef enum {
void BMO_op_flag_enable(BMesh *bm, BMOperator *op, const int op_flag);
void BMO_op_flag_disable(BMesh *bm, BMOperator *op, const int op_flag);
+/* -------------------------------------------------------------------- */
+/** \name BMesh Operator Slot Get/Set
+ * \{ */
+
void BMO_slot_float_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
const float f);
@@ -441,13 +564,17 @@ void BMO_slot_int_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_nam
int BMO_slot_int_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name);
void BMO_slot_bool_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const bool i);
bool BMO_slot_bool_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name);
+/**
+ * Return a copy of the element buffer.
+ */
void *BMO_slot_as_arrayN(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, int *len);
-/* don't pass in arrays that are supposed to map to elements this way.
+/**
+ * Don't pass in arrays that are supposed to map to elements this way.
*
* so, e.g. passing in list of floats per element in another slot is bad.
- * passing in, e.g. pointer to an editmesh for the conversion operator is fine
- * though. */
+ * passing in, e.g. pointer to an edit-mesh for the conversion operator is fine though.
+ */
void BMO_slot_ptr_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, void *p);
void *BMO_slot_ptr_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name);
void BMO_slot_vec_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
@@ -455,10 +582,12 @@ void BMO_slot_vec_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const float vec[3]);
void BMO_slot_vec_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, float r_vec[3]);
-/* only supports square mats */
-/* size must be 3 or 4; this api is meant only for transformation matrices.
- * note that internally the matrix is stored in 4x4 form, and it's safe to
- * call whichever BMO_Get_MatXXX function you want. */
+/**
+ * Only supports square matrices.
+ * size must be 3 or 4; this api is meant only for transformation matrices.
+ *
+ * \note the matrix is stored in 4x4 form, and it's safe to call whichever function you want.
+ */
void BMO_slot_mat_set(BMOperator *op,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
@@ -471,6 +600,8 @@ void BMO_slot_mat3_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
float r_mat[3][3]);
+/** \} */
+
void BMO_mesh_flag_disable_all(BMesh *bm, BMOperator *op, const char htype, const short oflag);
void BMO_mesh_selected_remap(BMesh *bm,
@@ -479,19 +610,25 @@ void BMO_mesh_selected_remap(BMesh *bm,
BMOpSlot *slot_face_map,
const bool check_select);
-/* copies the values from another slot to the end of the output slot */
+/**
+ * Copies the values from another slot to the end of the output slot.
+ */
#define BMO_slot_buffer_append( \
op_src, slots_src, slot_name_src, op_dst, slots_dst, slot_name_dst) \
_bmo_slot_buffer_append( \
(op_src)->slots_src, slot_name_src, (op_dst)->slots_dst, slot_name_dst, (op_dst)->arena)
+/**
+ * Copies the values from another slot to the end of the output slot.
+ */
void _bmo_slot_buffer_append(BMOpSlot slot_args_dst[BMO_OP_MAX_SLOTS],
const char *slot_name_dst,
BMOpSlot slot_args_src[BMO_OP_MAX_SLOTS],
const char *slot_name_src,
struct MemArena *arena_dst);
-/* puts every element of type 'type' (which is a bitmask) with tool
- * flag 'flag', into a slot. */
+/**
+ * Puts every element of type 'type' (which is a bit-mask) with tool flag 'flag', into a slot.
+ */
void BMO_slot_buffer_from_enabled_flag(BMesh *bm,
BMOperator *op,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
@@ -499,8 +636,9 @@ void BMO_slot_buffer_from_enabled_flag(BMesh *bm,
const char htype,
const short oflag);
-/* puts every element of type 'type' (which is a bitmask) without tool
- * flag 'flag', into a slot. */
+/**
+ * Puts every element of type 'type' (which is a bit-mask) without tool flag 'flag', into a slot.
+ */
void BMO_slot_buffer_from_disabled_flag(BMesh *bm,
BMOperator *op,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
@@ -508,27 +646,45 @@ void BMO_slot_buffer_from_disabled_flag(BMesh *bm,
const char htype,
const short oflag);
-/* tool-flags all elements inside an element slot array with flag flag. */
+/**
+ * \brief BMO_FLAG_BUFFER
+ *
+ * Flags elements in a slots buffer
+ */
void BMO_slot_buffer_flag_enable(BMesh *bm,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
const char htype,
const short oflag);
-/* clears tool-flag flag from all elements inside a slot array. */
+/**
+ * \brief BMO_FLAG_BUFFER
+ *
+ * Removes flags from elements in a slots buffer
+ */
void BMO_slot_buffer_flag_disable(BMesh *bm,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
const char htype,
const short oflag);
-/* tool-flags all elements inside an element slot array with flag flag. */
+/**
+ * \brief BMO_FLAG_BUFFER
+ *
+ * Header Flags elements in a slots buffer, automatically
+ * using the selection API where appropriate.
+ */
void BMO_slot_buffer_hflag_enable(BMesh *bm,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
const char htype,
const char hflag,
const bool do_flush);
-/* clears tool-flag flag from all elements inside a slot array. */
+/**
+ * \brief BMO_FLAG_BUFFER
+ *
+ * Removes flags from elements in a slots buffer, automatically
+ * using the selection API where appropriate.
+ */
void BMO_slot_buffer_hflag_disable(BMesh *bm,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
@@ -536,19 +692,20 @@ void BMO_slot_buffer_hflag_disable(BMesh *bm,
const char hflag,
const bool do_flush);
-/* puts every element of type 'type' (which is a bitmask) with header
- * flag 'flag', into a slot. NOTE: ignores hidden elements
- * (e.g. elements with header flag BM_ELEM_HIDDEN set). */
+/**
+ * Puts every element of type 'type' (which is a bit-mask) with header flag 'flag', into a slot.
+ * \note ignores hidden elements (e.g. elements with header flag BM_ELEM_HIDDEN set).
+ */
void BMO_slot_buffer_from_enabled_hflag(BMesh *bm,
BMOperator *op,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
const char htype,
const char hflag);
-
-/* puts every element of type 'type' (which is a bitmask) without
- * header flag 'flag', into a slot. NOTE: ignores hidden elements
- * (e.g. elements with header flag BM_ELEM_HIDDEN set). */
+/**
+ * Puts every element of type 'type' (which is a bit-mask) without header flag 'flag', into a slot.
+ * \note ignores hidden elements (e.g. elements with header flag BM_ELEM_HIDDEN set).
+ */
void BMO_slot_buffer_from_disabled_hflag(BMesh *bm,
BMOperator *op,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
@@ -564,14 +721,21 @@ void BMO_slot_buffer_from_array(BMOperator *op,
void BMO_slot_buffer_from_single(BMOperator *op, BMOpSlot *slot, BMHeader *ele);
void *BMO_slot_buffer_get_single(BMOpSlot *slot);
-/* counts number of elements inside a slot array. */
+/** Return the number of elements inside a slot array. */
int BMO_slot_buffer_len(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name);
+/** Return the number of elements inside a slot map. */
int BMO_slot_map_len(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name);
+/**
+ * Inserts a key/value mapping into a mapping slot. note that it copies the
+ * value, it doesn't store a reference to it.
+ */
void BMO_slot_map_insert(BMOperator *op, BMOpSlot *slot, const void *element, const void *data);
-/* flags all elements in a mapping. note that the mapping must only have
- * bmesh elements in it. */
+/**
+ * Flags all elements in a mapping.
+ * \note that the mapping must only have #BMesh elements in it.
+ */
void BMO_slot_map_to_flag(BMesh *bm,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
@@ -583,6 +747,11 @@ void *BMO_slot_buffer_alloc(BMOperator *op,
const char *slot_name,
const int len);
+/**
+ * \brief BMO_ALL_TO_SLOT
+ *
+ * Copies all elements of a certain type into an operator slot.
+ */
void BMO_slot_buffer_from_all(BMesh *bm,
BMOperator *op,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
@@ -636,12 +805,22 @@ typedef struct BMOIter {
void *BMO_slot_buffer_get_first(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name);
+/**
+ * \brief New Iterator
+ *
+ * \param restrictmask: restricts the iteration to certain element types
+ * (e.g. combination of BM_VERT, BM_EDGE, BM_FACE), if iterating
+ * over an element buffer (not a mapping). */
void *BMO_iter_new(BMOIter *iter,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
const char restrictmask);
void *BMO_iter_step(BMOIter *iter);
+/**
+ * Returns a pointer to the key-value when iterating over mappings.
+ * remember for pointer maps this will be a pointer to a pointer.
+ */
void **BMO_iter_map_value_p(BMOIter *iter);
void *BMO_iter_map_value_ptr(BMOIter *iter);
@@ -660,6 +839,7 @@ bool BMO_iter_map_value_bool(BMOIter *iter);
ele; \
BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BMO_iter_step(iter), i_++)
+/* operator slot type information - size of one element of the type given. */
extern const int BMO_OPSLOT_TYPEINFO[BMO_OP_SLOT_TOTAL_TYPES];
int BMO_opcode_from_opname(const char *opname);
diff --git a/source/blender/bmesh/intern/bmesh_operators.c b/source/blender/bmesh/intern/bmesh_operators.c
index 221994aa313..dd35f0feee7 100644
--- a/source/blender/bmesh/intern/bmesh_operators.c
+++ b/source/blender/bmesh/intern/bmesh_operators.c
@@ -42,7 +42,6 @@ static int bmo_name_to_slotcode(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char
static int bmo_name_to_slotcode_check(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *identifier);
-/* operator slot type information - size of one element of the type given. */
const int BMO_OPSLOT_TYPEINFO[BMO_OP_SLOT_TOTAL_TYPES] = {
0, /* 0: BMO_OP_SLOT_SENTINEL */
sizeof(int), /* 1: BMO_OP_SLOT_BOOL */
@@ -70,11 +69,6 @@ void BMO_op_flag_disable(BMesh *UNUSED(bm), BMOperator *op, const int op_flag)
op->flag &= ~op_flag;
}
-/**
- * \brief BMESH OPSTACK PUSH
- *
- * Pushes the opstack down one level and allocates a new flag layer if appropriate.
- */
void BMO_push(BMesh *bm, BMOperator *UNUSED(op))
{
bm->toolflag_index++;
@@ -90,13 +84,6 @@ void BMO_push(BMesh *bm, BMOperator *UNUSED(op))
}
}
-/**
- * \brief BMESH OPSTACK POP
- *
- * Pops the opstack one level and frees a flag layer if appropriate
- *
- * BMESH_TODO: investigate NOT freeing flag layers.
- */
void BMO_pop(BMesh *bm)
{
if (bm->toolflag_index > 0) {
@@ -152,11 +139,6 @@ static void bmo_op_slots_free(const BMOSlotType *slot_types, BMOpSlot *slot_args
}
}
-/**
- * \brief BMESH OPSTACK INIT OP
- *
- * Initializes an operator structure to a certain type
- */
void BMO_op_init(BMesh *bm, BMOperator *op, const int flag, const char *opname)
{
int opcode = BMO_opcode_from_opname(opname);
@@ -188,15 +170,6 @@ void BMO_op_init(BMesh *bm, BMOperator *op, const int flag, const char *opname)
BLI_memarena_use_calloc(op->arena);
}
-/**
- * \brief BMESH OPSTACK EXEC OP
- *
- * Executes a passed in operator.
- *
- * This handles the allocation and freeing of temporary flag
- * layers and starting/stopping the modeling loop.
- * Can be called from other operators exec callbacks as well.
- */
void BMO_op_exec(BMesh *bm, BMOperator *op)
{
/* allocate tool flags on demand */
@@ -216,11 +189,6 @@ void BMO_op_exec(BMesh *bm, BMOperator *op)
BMO_pop(bm);
}
-/**
- * \brief BMESH OPSTACK FINISH OP
- *
- * Does housekeeping chores related to finishing up an operator.
- */
void BMO_op_finish(BMesh *bm, BMOperator *op)
{
bmo_op_slots_free(bmo_opdefines[op->type]->slot_types_in, op->slots_in);
@@ -238,22 +206,12 @@ void BMO_op_finish(BMesh *bm, BMOperator *op)
#endif
}
-/**
- * \brief BMESH OPSTACK HAS SLOT
- *
- * \return Success if the slot if found.
- */
bool BMO_slot_exists(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier)
{
int slot_code = bmo_name_to_slotcode(slot_args, identifier);
return (slot_code >= 0);
}
-/**
- * \brief BMESH OPSTACK GET SLOT
- *
- * Returns a pointer to the slot of type 'slot_code'
- */
BMOpSlot *BMO_slot_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier)
{
int slot_code = bmo_name_to_slotcode_check(slot_args, identifier);
@@ -267,12 +225,6 @@ BMOpSlot *BMO_slot_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identif
return &slot_args[slot_code];
}
-/**
- * \brief BMESH OPSTACK COPY SLOT
- *
- * define used.
- * Copies data from one slot to another.
- */
void _bmo_slot_copy(BMOpSlot slot_args_src[BMO_OP_MAX_SLOTS],
const char *slot_name_src,
BMOpSlot slot_args_dst[BMO_OP_MAX_SLOTS],
@@ -393,7 +345,6 @@ void BMO_slot_bool_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_na
slot->data.i = i;
}
-/* only supports square mats */
void BMO_slot_mat_set(BMOperator *op,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
@@ -515,7 +466,6 @@ bool BMO_slot_bool_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_na
return slot->data.i;
}
-/* if you want a copy of the elem buffer */
void *BMO_slot_as_arrayN(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, int *len)
{
BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
@@ -698,9 +648,6 @@ int BMO_slot_map_len(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name
return BLI_ghash_len(slot->data.ghash);
}
-/* inserts a key/value mapping into a mapping slot. note that it copies the
- * value, it doesn't store a reference to it. */
-
void BMO_slot_map_insert(BMOperator *op, BMOpSlot *slot, const void *element, const void *data)
{
(void)op; /* Ignored in release builds. */
@@ -796,11 +743,6 @@ void *BMO_slot_buffer_alloc(BMOperator *op,
return slot->data.buf;
}
-/**
- * \brief BMO_ALL_TO_SLOT
- *
- * Copies all elements of a certain type into an operator slot.
- */
void BMO_slot_buffer_from_all(BMesh *bm,
BMOperator *op,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
@@ -987,9 +929,6 @@ void *BMO_slot_buffer_get_single(BMOpSlot *slot)
return slot->len ? (BMHeader *)slot->data.buf[0] : NULL;
}
-/**
- * Copies the values from another slot to the end of the output slot.
- */
void _bmo_slot_buffer_append(BMOpSlot slot_args_dst[BMO_OP_MAX_SLOTS],
const char *slot_name_dst,
BMOpSlot slot_args_src[BMO_OP_MAX_SLOTS],
@@ -1115,12 +1054,6 @@ void BMO_slot_buffer_from_disabled_flag(BMesh *bm,
bmo_slot_buffer_from_flag(bm, op, slot_args, slot_name, htype, oflag, false);
}
-/**
- * \brief BMO_FLAG_BUFFER
- *
- * Header Flags elements in a slots buffer, automatically
- * using the selection API where appropriate.
- */
void BMO_slot_buffer_hflag_enable(BMesh *bm,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
@@ -1155,12 +1088,6 @@ void BMO_slot_buffer_hflag_enable(BMesh *bm,
}
}
-/**
- * \brief BMO_FLAG_BUFFER
- *
- * Removes flags from elements in a slots buffer, automatically
- * using the selection API where appropriate.
- */
void BMO_slot_buffer_hflag_disable(BMesh *bm,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
@@ -1194,11 +1121,6 @@ void BMO_slot_buffer_hflag_disable(BMesh *bm,
}
}
-/**
- * \brief BMO_FLAG_BUFFER
- *
- * Flags elements in a slots buffer
- */
void BMO_slot_buffer_flag_enable(BMesh *bm,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
@@ -1221,11 +1143,6 @@ void BMO_slot_buffer_flag_enable(BMesh *bm,
}
}
-/**
- * \brief BMO_FLAG_BUFFER
- *
- * Removes flags from elements in a slots buffer
- */
void BMO_slot_buffer_flag_disable(BMesh *bm,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
@@ -1434,12 +1351,6 @@ void *BMO_slot_buffer_get_first(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char
return slot->data.buf ? *slot->data.buf : NULL;
}
-/**
- * \brief New Iterator
- *
- * \param restrictmask: restricts the iteration to certain element types
- * (e.g. combination of BM_VERT, BM_EDGE, BM_FACE), if iterating
- * over an element buffer (not a mapping). */
void *BMO_iter_new(BMOIter *iter,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
@@ -1513,10 +1424,6 @@ void *BMO_iter_step(BMOIter *iter)
/* used for iterating over mappings */
-/**
- * Returns a pointer to the key-value when iterating over mappings.
- * remember for pointer maps this will be a pointer to a pointer.
- */
void **BMO_iter_map_value_p(BMOIter *iter)
{
return iter->val;
@@ -1584,7 +1491,6 @@ bool BMO_error_occurred_at_level(BMesh *bm, eBMOpErrorLevel level)
return false;
}
-/* returns error code or 0 if no error */
bool BMO_error_get(BMesh *bm, const char **r_msg, BMOperator **r_op, eBMOpErrorLevel *r_level)
{
BMOpError *err = bm->errorstack.first;
@@ -1694,60 +1600,6 @@ static int BMO_opcode_from_opname_check(const char *opname)
return i;
}
-/**
- * \brief Format Strings for #BMOperator Initialization.
- *
- * This system is used to execute or initialize an operator,
- * using a formatted-string system.
- *
- * The basic format for the format string is:
- * `[operatorname] [slot_name]=%[code] [slot_name]=%[code]`
- *
- * Example:
- *
- * \code{.c}
- * BMO_op_callf(bm, BMO_FLAG_DEFAULTS,
- * "delete context=%i geom=%hv",
- * DEL_ONLYFACES, BM_ELEM_SELECT);
- * \endcode
- * **Primitive Types**
- * - `b` - boolean (same as int but 1/0 only). #BMO_OP_SLOT_BOOL
- * - `i` - int. #BMO_OP_SLOT_INT
- * - `f` - float. #BMO_OP_SLOT_FLT
- * - `p` - pointer (normally to a Scene/Mesh/Object/BMesh). #BMO_OP_SLOT_PTR
- * - `m3` - 3x3 matrix of floats. #BMO_OP_SLOT_MAT
- * - `m4` - 4x4 matrix of floats. #BMO_OP_SLOT_MAT
- * - `v` - 3D vector of floats. #BMO_OP_SLOT_VEC
- * **Utility**
- *
- * Pass an existing slot which is copied to either an input or output slot.
- * Taking the operator and slot-name pair of args (BMOperator *, const char *).
- * - `s` - slot_in (lower case)
- * - `S` - slot_out (upper case)
- * **Element Buffer** (#BMO_OP_SLOT_ELEMENT_BUF)
- * - `e` - single element vert/edge/face (use with #BMO_OP_SLOT_SUBTYPE_ELEM_IS_SINGLE).
- * - `eb` - elem buffer, take an array and a length.
- * - `av` - all verts
- * - `ae` - all edges
- * - `af` - all faces
- * - `hv` - header flagged verts (hflag)
- * - `he` - header flagged edges (hflag)
- * - `hf` - header flagged faces (hflag)
- * - `Hv` - header flagged verts (hflag off)
- * - `He` - header flagged edges (hflag off)
- * - `Hf` - header flagged faces (hflag off)
- * - `fv` - flagged verts (oflag)
- * - `fe` - flagged edges (oflag)
- * - `ff` - flagged faces (oflag)
- * - `Fv` - flagged verts (oflag off)
- * - `Fe` - flagged edges (oflag off)
- * - `Ff` - flagged faces (oflag off)
- *
- * \note The common v/e/f suffix can be mixed,
- * so `avef` is can be used for all verts, edges and faces.
- * Order is not important so `Hfev` is also valid (all un-flagged verts, edges and faces).
- */
-
bool BMO_op_vinitf(BMesh *bm, BMOperator *op, const int flag, const char *_fmt, va_list vlist)
{
// BMOpDefine *def;
diff --git a/source/blender/bmesh/intern/bmesh_operators.h b/source/blender/bmesh/intern/bmesh_operators.h
index a701fe3eb85..83f2c402c35 100644
--- a/source/blender/bmesh/intern/bmesh_operators.h
+++ b/source/blender/bmesh/intern/bmesh_operators.h
@@ -170,17 +170,50 @@ void BM_mesh_esubdivide(BMesh *bm,
const short use_only_quads,
const int seed);
+/**
+ * Fills first available UV-map with grid-like UV's for all faces with `oflag` set.
+ *
+ * \param bm: The BMesh to operate on
+ * \param x_segments: The x-resolution of the grid
+ * \param y_segments: The y-resolution of the grid
+ * \param oflag: The flag to check faces with.
+ */
void BM_mesh_calc_uvs_grid(BMesh *bm,
const uint x_segments,
const uint y_segments,
const short oflag,
const int cd_loop_uv_offset);
+/**
+ * Fills first available UV-map with spherical projected UVs for all faces with `oflag` set.
+ *
+ * \param bm: The BMesh to operate on
+ * \param oflag: The flag to check faces with.
+ */
void BM_mesh_calc_uvs_sphere(BMesh *bm, const short oflag, const int cd_loop_uv_offset);
+/**
+ * Fills first available UV-map with 2D projected UVs for all faces with `oflag` set.
+ *
+ * \param bm: The BMesh to operate on.
+ * \param mat: The transform matrix applied to the created circle.
+ * \param radius: The size of the circle.
+ * \param oflag: The flag to check faces with.
+ */
void BM_mesh_calc_uvs_circle(BMesh *bm,
float mat[4][4],
const float radius,
const short oflag,
const int cd_loop_uv_offset);
+/**
+ * Fills first available UV-map with cylinder/cone-like UVs for all faces with `oflag` set.
+ *
+ * \param bm: The BMesh to operate on.
+ * \param mat: The transform matrix applied to the created cone/cylinder.
+ * \param radius_top: The size of the top end of the cone/cylinder.
+ * \param radius_bottom: The size of the bottom end of the cone/cylinder.
+ * \param segments: The number of subdivisions in the sides of the cone/cylinder.
+ * \param cap_ends: Whether the ends of the cone/cylinder are filled or not.
+ * \param oflag: The flag to check faces with.
+ */
void BM_mesh_calc_uvs_cone(BMesh *bm,
float mat[4][4],
const float radius_top,
@@ -189,6 +222,15 @@ void BM_mesh_calc_uvs_cone(BMesh *bm,
const bool cap_ends,
const short oflag,
const int cd_loop_uv_offset);
+/**
+ * Fills first available UV-map with cube-like UVs for all faces with `oflag` set.
+ *
+ * \note Expects tagged faces to be six quads.
+ * \note Caller must order faces for correct alignment.
+ *
+ * \param bm: The BMesh to operate on.
+ * \param oflag: The flag to check faces with.
+ */
void BM_mesh_calc_uvs_cube(BMesh *bm, const short oflag);
#include "intern/bmesh_operator_api_inline.h"
diff --git a/source/blender/bmesh/intern/bmesh_polygon.c b/source/blender/bmesh/intern/bmesh_polygon.c
index 51ae47adacc..e9eaf865e3c 100644
--- a/source/blender/bmesh/intern/bmesh_polygon.c
+++ b/source/blender/bmesh/intern/bmesh_polygon.c
@@ -117,15 +117,6 @@ static void bm_face_calc_poly_center_median_vertex_cos(const BMFace *f,
mul_v3_fl(r_cent, 1.0f / f->len);
}
-/**
- * For tools that insist on using triangles, ideally we would cache this data.
- *
- * \param use_fixed_quad: When true,
- * always split quad along (0 -> 2) regardless of concave corners,
- * (as done in #BM_mesh_calc_tessellation).
- * \param r_loops: Store face loop pointers, (f->len)
- * \param r_index: Store triangle triples, indices into \a r_loops, `((f->len - 2) * 3)`
- */
void BM_face_calc_tessellation(const BMFace *f,
const bool use_fixed_quad,
BMLoop **r_loops,
@@ -177,9 +168,6 @@ void BM_face_calc_tessellation(const BMFace *f,
}
}
-/**
- * Return a point inside the face.
- */
void BM_face_calc_point_in_face(const BMFace *f, float r_co[3])
{
const BMLoop *l_tri[3];
@@ -218,9 +206,6 @@ void BM_face_calc_point_in_face(const BMFace *f, float r_co[3])
mid_v3_v3v3v3(r_co, l_tri[0]->v->co, l_tri[1]->v->co, l_tri[2]->v->co);
}
-/**
- * get the area of the face
- */
float BM_face_calc_area(const BMFace *f)
{
/* inline 'area_poly_v3' logic, avoid creating a temp array */
@@ -235,9 +220,6 @@ float BM_face_calc_area(const BMFace *f)
return len_v3(n) * 0.5f;
}
-/**
- * Get the area of the face in world space.
- */
float BM_face_calc_area_with_mat3(const BMFace *f, const float mat3[3][3])
{
/* inline 'area_poly_v3' logic, avoid creating a temp array */
@@ -257,9 +239,6 @@ float BM_face_calc_area_with_mat3(const BMFace *f, const float mat3[3][3])
return len_v3(n) * 0.5f;
}
-/**
- * get the area of UV face
- */
float BM_face_calc_area_uv(const BMFace *f, int cd_loop_uv_offset)
{
/* inline 'area_poly_v2' logic, avoid creating a temp array */
@@ -276,9 +255,6 @@ float BM_face_calc_area_uv(const BMFace *f, int cd_loop_uv_offset)
return fabsf(cross * 0.5f);
}
-/**
- * compute the perimeter of an ngon
- */
float BM_face_calc_perimeter(const BMFace *f)
{
const BMLoop *l_iter, *l_first;
@@ -292,9 +268,6 @@ float BM_face_calc_perimeter(const BMFace *f)
return perimeter;
}
-/**
- * Calculate the perimeter of a ngon in world space.
- */
float BM_face_calc_perimeter_with_mat3(const BMFace *f, const float mat3[3][3])
{
const BMLoop *l_iter, *l_first;
@@ -355,14 +328,6 @@ static int bm_vert_tri_find_unique_edge(BMVert *verts[3])
return order[0];
}
-/**
- * Calculate a tangent from any 3 vertices.
- *
- * The tangent aligns to the most *unique* edge
- * (the edge most unlike the other two).
- *
- * \param r_tangent: Calculated unit length tangent (return value).
- */
void BM_vert_tri_calc_tangent_edge(BMVert *verts[3], float r_tangent[3])
{
const int index = bm_vert_tri_find_unique_edge(verts);
@@ -372,14 +337,6 @@ void BM_vert_tri_calc_tangent_edge(BMVert *verts[3], float r_tangent[3])
normalize_v3(r_tangent);
}
-/**
- * Calculate a tangent from any 3 vertices,
- *
- * The tangent follows the center-line formed by the most unique edges center
- * and the opposite vertex.
- *
- * \param r_tangent: Calculated unit length tangent (return value).
- */
void BM_vert_tri_calc_tangent_edge_pair(BMVert *verts[3], float r_tangent[3])
{
const int index = bm_vert_tri_find_unique_edge(verts);
@@ -394,9 +351,6 @@ void BM_vert_tri_calc_tangent_edge_pair(BMVert *verts[3], float r_tangent[3])
normalize_v3(r_tangent);
}
-/**
- * Compute the tangent of the face, using the longest edge.
- */
void BM_face_calc_tangent_edge(const BMFace *f, float r_tangent[3])
{
const BMLoop *l_long = BM_face_find_longest_loop((BMFace *)f);
@@ -406,11 +360,6 @@ void BM_face_calc_tangent_edge(const BMFace *f, float r_tangent[3])
normalize_v3(r_tangent);
}
-/**
- * Compute the tangent of the face, using the two longest disconnected edges.
- *
- * \param r_tangent: Calculated unit length tangent (return value).
- */
void BM_face_calc_tangent_edge_pair(const BMFace *f, float r_tangent[3])
{
if (f->len == 3) {
@@ -471,11 +420,6 @@ void BM_face_calc_tangent_edge_pair(const BMFace *f, float r_tangent[3])
}
}
-/**
- * Compute the tangent of the face, using the edge farthest away from any vertex in the face.
- *
- * \param r_tangent: Calculated unit length tangent (return value).
- */
void BM_face_calc_tangent_edge_diagonal(const BMFace *f, float r_tangent[3])
{
BMLoop *l_iter, *l_first;
@@ -508,11 +452,6 @@ void BM_face_calc_tangent_edge_diagonal(const BMFace *f, float r_tangent[3])
normalize_v3(r_tangent);
}
-/**
- * Compute the tangent of the face, using longest distance between vertices on the face.
- *
- * \note The logic is almost identical to #BM_face_calc_tangent_edge_diagonal
- */
void BM_face_calc_tangent_vert_diagonal(const BMFace *f, float r_tangent[3])
{
BMLoop *l_iter, *l_first;
@@ -541,11 +480,6 @@ void BM_face_calc_tangent_vert_diagonal(const BMFace *f, float r_tangent[3])
normalize_v3(r_tangent);
}
-/**
- * Compute a meaningful direction along the face (use for gizmo axis).
- *
- * \note Callers shouldn't depend on the *exact* method used here.
- */
void BM_face_calc_tangent_auto(const BMFace *f, float r_tangent[3])
{
if (f->len == 3) {
@@ -564,9 +498,6 @@ void BM_face_calc_tangent_auto(const BMFace *f, float r_tangent[3])
}
}
-/**
- * expands bounds (min/max must be initialized).
- */
void BM_face_calc_bounds_expand(const BMFace *f, float min[3], float max[3])
{
const BMLoop *l_iter, *l_first;
@@ -576,9 +507,6 @@ void BM_face_calc_bounds_expand(const BMFace *f, float min[3], float max[3])
} while ((l_iter = l_iter->next) != l_first);
}
-/**
- * computes center of face in 3d. uses center of bounding box.
- */
void BM_face_calc_center_bounds(const BMFace *f, float r_cent[3])
{
const BMLoop *l_iter, *l_first;
@@ -594,9 +522,6 @@ void BM_face_calc_center_bounds(const BMFace *f, float r_cent[3])
mid_v3_v3v3(r_cent, min, max);
}
-/**
- * computes center of face in 3d. uses center of bounding box.
- */
void BM_face_calc_center_bounds_vcos(const BMesh *bm,
const BMFace *f,
float r_cent[3],
@@ -619,9 +544,6 @@ void BM_face_calc_center_bounds_vcos(const BMesh *bm,
mid_v3_v3v3(r_cent, min, max);
}
-/**
- * computes the center of a face, using the mean average
- */
void BM_face_calc_center_median(const BMFace *f, float r_cent[3])
{
const BMLoop *l_iter, *l_first;
@@ -635,10 +557,6 @@ void BM_face_calc_center_median(const BMFace *f, float r_cent[3])
mul_v3_fl(r_cent, 1.0f / (float)f->len);
}
-/**
- * computes the center of a face, using the mean average
- * weighted by edge length
- */
void BM_face_calc_center_median_weighted(const BMFace *f, float r_cent[3])
{
const BMLoop *l_iter;
@@ -663,12 +581,6 @@ void BM_face_calc_center_median_weighted(const BMFace *f, float r_cent[3])
}
}
-/**
- * \brief POLY ROTATE PLANE
- *
- * Rotates a polygon so that its
- * normal is pointing towards the mesh Z axis
- */
void poly_rotate_plane(const float normal[3], float (*verts)[3], const uint nverts)
{
float mat[3][3];
@@ -684,9 +596,6 @@ void poly_rotate_plane(const float normal[3], float (*verts)[3], const uint nver
}
}
-/**
- * updates face and vertex normals incident on an edge
- */
void BM_edge_normals_update(BMEdge *e)
{
BMIter iter;
@@ -800,24 +709,11 @@ void BM_vert_normal_update_all(BMVert *v)
}
}
-/**
- * update a vert normal (but not the faces incident on it)
- */
void BM_vert_normal_update(BMVert *v)
{
BM_vert_calc_normal(v, v->no);
}
-/**
- * \brief BMESH UPDATE FACE NORMAL
- *
- * Updates the stored normal for the
- * given face. Requires that a buffer
- * of sufficient length to store projected
- * coordinates for all of the face's vertices
- * is passed in as well.
- */
-
float BM_face_calc_normal(const BMFace *f, float r_no[3])
{
BMLoop *l;
@@ -849,7 +745,6 @@ void BM_face_normal_update(BMFace *f)
BM_face_calc_normal(f, f->no);
}
-/* exact same as 'BM_face_calc_normal' but accepts vertex coords */
float BM_face_calc_normal_vcos(const BMesh *bm,
const BMFace *f,
float r_no[3],
@@ -884,12 +779,6 @@ float BM_face_calc_normal_vcos(const BMesh *bm,
}
}
-/**
- * Calculate a normal from a vertex cloud.
- *
- * \note We could make a higher quality version that takes all vertices into account.
- * Currently it finds 4 outer most points returning its normal.
- */
void BM_verts_calc_normal_from_cloud_ex(
BMVert **varr, int varr_len, float r_normal[3], float r_center[3], int *r_index_tangent)
{
@@ -991,9 +880,6 @@ void BM_verts_calc_normal_from_cloud(BMVert **varr, int varr_len, float r_normal
BM_verts_calc_normal_from_cloud_ex(varr, varr_len, r_normal, NULL, NULL);
}
-/**
- * Calculates the face subset normal.
- */
float BM_face_calc_normal_subset(const BMLoop *l_first, const BMLoop *l_last, float r_no[3])
{
const float *v_prev, *v_curr;
@@ -1014,7 +900,6 @@ float BM_face_calc_normal_subset(const BMLoop *l_first, const BMLoop *l_last, fl
return normalize_v3(r_no);
}
-/* exact same as 'BM_face_calc_normal' but accepts vertex coords */
void BM_face_calc_center_median_vcos(const BMesh *bm,
const BMFace *f,
float r_cent[3],
@@ -1027,12 +912,6 @@ void BM_face_calc_center_median_vcos(const BMesh *bm,
bm_face_calc_poly_center_median_vertex_cos(f, r_cent, vertexCos);
}
-/**
- * \brief Face Flip Normal
- *
- * Reverses the winding of a face.
- * \note This updates the calculated normal.
- */
void BM_face_normal_flip_ex(BMesh *bm,
BMFace *f,
const int cd_loop_mdisp_offset,
@@ -1048,16 +927,6 @@ void BM_face_normal_flip(BMesh *bm, BMFace *f)
BM_face_normal_flip_ex(bm, f, cd_loop_mdisp_offset, true);
}
-/**
- * BM POINT IN FACE
- *
- * Projects co onto face f, and returns true if it is inside
- * the face bounds.
- *
- * \note this uses a best-axis projection test,
- * instead of projecting co directly into f's orientation space,
- * so there might be accuracy issues.
- */
bool BM_face_point_inside_test(const BMFace *f, const float co[3])
{
float axis_mat[3][3];
@@ -1080,29 +949,6 @@ bool BM_face_point_inside_test(const BMFace *f, const float co[3])
return isect_point_poly_v2(co_2d, projverts, f->len, false);
}
-/**
- * \brief BMESH TRIANGULATE FACE
- *
- * Breaks all quads and ngons down to triangles.
- * It uses polyfill for the ngons splitting, and
- * the beautify operator when use_beauty is true.
- *
- * \param r_faces_new: if non-null, must be an array of BMFace pointers,
- * with a length equal to (f->len - 3). It will be filled with the new
- * triangles (not including the original triangle).
- *
- * \param r_faces_double: When newly created faces are duplicates of existing faces,
- * they're added to this list. Caller must handle de-duplication.
- * This is done because its possible _all_ faces exist already,
- * and in that case we would have to remove all faces including the one passed,
- * which causes complications adding/removing faces while looking over them.
- *
- * \note The number of faces is _almost_ always (f->len - 3),
- * However there may be faces that already occupying the
- * triangles we would make, so the caller must check \a r_faces_new_tot.
- *
- * \note use_tag tags new flags and edges.
- */
void BM_face_triangulate(BMesh *bm,
BMFace *f,
BMFace **r_faces_new,
@@ -1325,14 +1171,6 @@ void BM_face_triangulate(BMesh *bm,
}
}
-/**
- * each pair of loops defines a new edge, a split. this function goes
- * through and sets pairs that are geometrically invalid to null. a
- * split is invalid, if it forms a concave angle or it intersects other
- * edges in the face, or it intersects another split. in the case of
- * intersecting splits, only the first of the set of intersecting
- * splits survives
- */
void BM_face_splits_check_legal(BMesh *bm, BMFace *f, BMLoop *(*loops)[2], int len)
{
float out[2] = {-FLT_MAX, -FLT_MAX};
@@ -1430,10 +1268,6 @@ void BM_face_splits_check_legal(BMesh *bm, BMFace *f, BMLoop *(*loops)[2], int l
#undef EDGE_SHARE_VERT
}
-/**
- * This simply checks that the verts don't connect faces which would have more optimal splits.
- * but _not_ check for correctness.
- */
void BM_face_splits_check_optimal(BMFace *f, BMLoop *(*loops)[2], int len)
{
int i;
@@ -1447,12 +1281,6 @@ void BM_face_splits_check_optimal(BMFace *f, BMLoop *(*loops)[2], int len)
}
}
-/**
- * Small utility functions for fast access
- *
- * faster alternative to:
- * BM_iter_as_array(bm, BM_VERTS_OF_FACE, f, (void **)v, 3);
- */
void BM_face_as_array_vert_tri(BMFace *f, BMVert *r_verts[3])
{
BMLoop *l = BM_FACE_FIRST_LOOP(f);
@@ -1466,10 +1294,6 @@ void BM_face_as_array_vert_tri(BMFace *f, BMVert *r_verts[3])
r_verts[2] = l->v;
}
-/**
- * faster alternative to:
- * BM_iter_as_array(bm, BM_VERTS_OF_FACE, f, (void **)v, 4);
- */
void BM_face_as_array_vert_quad(BMFace *f, BMVert *r_verts[4])
{
BMLoop *l = BM_FACE_FIRST_LOOP(f);
@@ -1485,12 +1309,6 @@ void BM_face_as_array_vert_quad(BMFace *f, BMVert *r_verts[4])
r_verts[3] = l->v;
}
-/**
- * Small utility functions for fast access
- *
- * faster alternative to:
- * BM_iter_as_array(bm, BM_LOOPS_OF_FACE, f, (void **)l, 3);
- */
void BM_face_as_array_loop_tri(BMFace *f, BMLoop *r_loops[3])
{
BMLoop *l = BM_FACE_FIRST_LOOP(f);
@@ -1504,10 +1322,6 @@ void BM_face_as_array_loop_tri(BMFace *f, BMLoop *r_loops[3])
r_loops[2] = l;
}
-/**
- * faster alternative to:
- * BM_iter_as_array(bm, BM_LOOPS_OF_FACE, f, (void **)l, 4);
- */
void BM_face_as_array_loop_quad(BMFace *f, BMLoop *r_loops[4])
{
BMLoop *l = BM_FACE_FIRST_LOOP(f);
diff --git a/source/blender/bmesh/intern/bmesh_polygon.h b/source/blender/bmesh/intern/bmesh_polygon.h
index 5be7f4a5f3b..e4545e610a0 100644
--- a/source/blender/bmesh/intern/bmesh_polygon.h
+++ b/source/blender/bmesh/intern/bmesh_polygon.h
@@ -25,68 +25,200 @@ struct Heap;
#include "BLI_compiler_attrs.h"
+/**
+ * For tools that insist on using triangles, ideally we would cache this data.
+ *
+ * \param use_fixed_quad: When true,
+ * always split quad along (0 -> 2) regardless of concave corners,
+ * (as done in #BM_mesh_calc_tessellation).
+ * \param r_loops: Store face loop pointers, (f->len)
+ * \param r_index: Store triangle triples, indices into \a r_loops, `((f->len - 2) * 3)`
+ */
void BM_face_calc_tessellation(const BMFace *f,
const bool use_fixed_quad,
BMLoop **r_loops,
uint (*r_index)[3]);
+/**
+ * Return a point inside the face.
+ */
void BM_face_calc_point_in_face(const BMFace *f, float r_co[3]);
+
+/**
+ * \brief BMESH UPDATE FACE NORMAL
+ *
+ * Updates the stored normal for the
+ * given face. Requires that a buffer
+ * of sufficient length to store projected
+ * coordinates for all of the face's vertices
+ * is passed in as well.
+ */
float BM_face_calc_normal(const BMFace *f, float r_no[3]) ATTR_NONNULL();
+/* exact same as 'BM_face_calc_normal' but accepts vertex coords */
float BM_face_calc_normal_vcos(const BMesh *bm,
const BMFace *f,
float r_no[3],
float const (*vertexCos)[3]) ATTR_NONNULL();
+/**
+ * Calculate a normal from a vertex cloud.
+ *
+ * \note We could make a higher quality version that takes all vertices into account.
+ * Currently it finds 4 outer most points returning its normal.
+ */
void BM_verts_calc_normal_from_cloud_ex(
BMVert **varr, int varr_len, float r_normal[3], float r_center[3], int *r_index_tangent);
void BM_verts_calc_normal_from_cloud(BMVert **varr, int varr_len, float r_normal[3]);
+/**
+ * Calculates the face subset normal.
+ */
float BM_face_calc_normal_subset(const BMLoop *l_first, const BMLoop *l_last, float r_no[3])
ATTR_NONNULL();
+/**
+ * get the area of the face
+ */
float BM_face_calc_area(const BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Get the area of the face in world space.
+ */
float BM_face_calc_area_with_mat3(const BMFace *f, const float mat3[3][3]) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * get the area of UV face
+ */
float BM_face_calc_area_uv(const BMFace *f, int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * compute the perimeter of an ngon
+ */
float BM_face_calc_perimeter(const BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Calculate the perimeter of a ngon in world space.
+ */
float BM_face_calc_perimeter_with_mat3(const BMFace *f,
const float mat3[3][3]) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Compute the tangent of the face, using the longest edge.
+ */
void BM_face_calc_tangent_edge(const BMFace *f, float r_tangent[3]) ATTR_NONNULL();
+/**
+ * Compute the tangent of the face, using the two longest disconnected edges.
+ *
+ * \param r_tangent: Calculated unit length tangent (return value).
+ */
void BM_face_calc_tangent_edge_pair(const BMFace *f, float r_tangent[3]) ATTR_NONNULL();
+/**
+ * Compute the tangent of the face, using the edge farthest away from any vertex in the face.
+ *
+ * \param r_tangent: Calculated unit length tangent (return value).
+ */
void BM_face_calc_tangent_edge_diagonal(const BMFace *f, float r_tangent[3]) ATTR_NONNULL();
+/**
+ * Compute the tangent of the face, using longest distance between vertices on the face.
+ *
+ * \note The logic is almost identical to #BM_face_calc_tangent_edge_diagonal
+ */
void BM_face_calc_tangent_vert_diagonal(const BMFace *f, float r_tangent[3]) ATTR_NONNULL();
+/**
+ * Compute a meaningful direction along the face (use for gizmo axis).
+ *
+ * \note Callers shouldn't depend on the *exact* method used here.
+ */
void BM_face_calc_tangent_auto(const BMFace *f, float r_tangent[3]) ATTR_NONNULL();
+/**
+ * computes center of face in 3d. uses center of bounding box.
+ */
void BM_face_calc_center_bounds(const BMFace *f, float r_cent[3]) ATTR_NONNULL();
+/**
+ * computes center of face in 3d. uses center of bounding box.
+ */
void BM_face_calc_center_bounds_vcos(const BMesh *bm,
const BMFace *f,
float r_center[3],
float const (*vertexCos)[3]) ATTR_NONNULL();
+/**
+ * computes the center of a face, using the mean average
+ */
void BM_face_calc_center_median(const BMFace *f, float r_center[3]) ATTR_NONNULL();
+/* exact same as 'BM_face_calc_normal' but accepts vertex coords */
void BM_face_calc_center_median_vcos(const BMesh *bm,
const BMFace *f,
float r_center[3],
float const (*vertexCos)[3]) ATTR_NONNULL();
+/**
+ * computes the center of a face, using the mean average
+ * weighted by edge length
+ */
void BM_face_calc_center_median_weighted(const BMFace *f, float r_cent[3]) ATTR_NONNULL();
+/**
+ * expands bounds (min/max must be initialized).
+ */
void BM_face_calc_bounds_expand(const BMFace *f, float min[3], float max[3]);
void BM_face_normal_update(BMFace *f) ATTR_NONNULL();
+/**
+ * updates face and vertex normals incident on an edge
+ */
void BM_edge_normals_update(BMEdge *e) ATTR_NONNULL();
bool BM_vert_calc_normal_ex(const BMVert *v, const char hflag, float r_no[3]);
bool BM_vert_calc_normal(const BMVert *v, float r_no[3]);
+/**
+ * update a vert normal (but not the faces incident on it)
+ */
void BM_vert_normal_update(BMVert *v) ATTR_NONNULL();
void BM_vert_normal_update_all(BMVert *v) ATTR_NONNULL();
+/**
+ * \brief Face Flip Normal
+ *
+ * Reverses the winding of a face.
+ * \note This updates the calculated normal.
+ */
void BM_face_normal_flip_ex(BMesh *bm,
BMFace *f,
const int cd_loop_mdisp_offset,
const bool use_loop_mdisp_flip) ATTR_NONNULL();
void BM_face_normal_flip(BMesh *bm, BMFace *f) ATTR_NONNULL();
+/**
+ * BM POINT IN FACE
+ *
+ * Projects co onto face f, and returns true if it is inside
+ * the face bounds.
+ *
+ * \note this uses a best-axis projection test,
+ * instead of projecting co directly into f's orientation space,
+ * so there might be accuracy issues.
+ */
bool BM_face_point_inside_test(const BMFace *f, const float co[3]) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * \brief BMESH TRIANGULATE FACE
+ *
+ * Breaks all quads and ngons down to triangles.
+ * It uses poly-fill for the ngons splitting, and
+ * the beautify operator when use_beauty is true.
+ *
+ * \param r_faces_new: if non-null, must be an array of BMFace pointers,
+ * with a length equal to (f->len - 3). It will be filled with the new
+ * triangles (not including the original triangle).
+ *
+ * \param r_faces_double: When newly created faces are duplicates of existing faces,
+ * they're added to this list. Caller must handle de-duplication.
+ * This is done because its possible _all_ faces exist already,
+ * and in that case we would have to remove all faces including the one passed,
+ * which causes complications adding/removing faces while looking over them.
+ *
+ * \note The number of faces is _almost_ always (f->len - 3),
+ * However there may be faces that already occupying the
+ * triangles we would make, so the caller must check \a r_faces_new_tot.
+ *
+ * \note use_tag tags new flags and edges.
+ */
void BM_face_triangulate(BMesh *bm,
BMFace *f,
BMFace **r_faces_new,
@@ -100,14 +232,62 @@ void BM_face_triangulate(BMesh *bm,
struct MemArena *pf_arena,
struct Heap *pf_heap) ATTR_NONNULL(1, 2);
+/**
+ * each pair of loops defines a new edge, a split. this function goes
+ * through and sets pairs that are geometrically invalid to null. a
+ * split is invalid, if it forms a concave angle or it intersects other
+ * edges in the face, or it intersects another split. in the case of
+ * intersecting splits, only the first of the set of intersecting
+ * splits survives
+ */
void BM_face_splits_check_legal(BMesh *bm, BMFace *f, BMLoop *(*loops)[2], int len) ATTR_NONNULL();
+/**
+ * This simply checks that the verts don't connect faces which would have more optimal splits.
+ * but _not_ check for correctness.
+ */
void BM_face_splits_check_optimal(BMFace *f, BMLoop *(*loops)[2], int len) ATTR_NONNULL();
+/**
+ * Small utility functions for fast access
+ *
+ * faster alternative to:
+ * BM_iter_as_array(bm, BM_VERTS_OF_FACE, f, (void **)v, 3);
+ */
void BM_face_as_array_vert_tri(BMFace *f, BMVert *r_verts[3]) ATTR_NONNULL();
+/**
+ * faster alternative to:
+ * BM_iter_as_array(bm, BM_VERTS_OF_FACE, f, (void **)v, 4);
+ */
void BM_face_as_array_vert_quad(BMFace *f, BMVert *r_verts[4]) ATTR_NONNULL();
+/**
+ * Small utility functions for fast access
+ *
+ * faster alternative to:
+ * BM_iter_as_array(bm, BM_LOOPS_OF_FACE, f, (void **)l, 3);
+ */
void BM_face_as_array_loop_tri(BMFace *f, BMLoop *r_loops[3]) ATTR_NONNULL();
+/**
+ * faster alternative to:
+ * BM_iter_as_array(bm, BM_LOOPS_OF_FACE, f, (void **)l, 4);
+ */
void BM_face_as_array_loop_quad(BMFace *f, BMLoop *r_loops[4]) ATTR_NONNULL();
+/**
+ * Calculate a tangent from any 3 vertices.
+ *
+ * The tangent aligns to the most *unique* edge
+ * (the edge most unlike the other two).
+ *
+ * \param r_tangent: Calculated unit length tangent (return value).
+ */
void BM_vert_tri_calc_tangent_edge(BMVert *verts[3], float r_tangent[3]);
+/**
+ * Calculate a tangent from any 3 vertices,
+ *
+ * The tangent follows the center-line formed by the most unique edges center
+ * and the opposite vertex.
+ *
+ * \param r_tangent: Calculated unit length tangent (return value).
+ */
void BM_vert_tri_calc_tangent_edge_pair(BMVert *verts[3], float r_tangent[3]);
diff --git a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c
index 103d7621f87..24d9c194054 100644
--- a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c
+++ b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c
@@ -452,14 +452,6 @@ static bool bm_face_split_edgenet_find_loop(BMVert *v_init,
return false;
}
-/**
- * Splits a face into many smaller faces defined by an edge-net.
- * handle customdata and degenerate cases.
- *
- * - Isolated holes or unsupported face configurations, will be ignored.
- * - Customdata calculations aren't efficient
- * (need to calculate weights for each vert).
- */
bool BM_face_split_edgenet(BMesh *bm,
BMFace *f,
BMEdge **edge_net,
@@ -1223,14 +1215,6 @@ static bool bm_vert_partial_connect_check_overlap(const int *remap,
#endif /* USE_PARTIAL_CONNECT */
-/**
- * For when the edge-net has holes in it-this connects them.
- *
- * \param use_partial_connect: Support for handling islands connected by only a single edge,
- * \note that this is quite slow so avoid using where possible.
- * \param mem_arena: Avoids many small allocs & should be cleared after each use.
- * take care since \a edge_net_new is stored in \a r_edge_net_new.
- */
bool BM_face_split_edgenet_connect_islands(BMesh *bm,
BMFace *f,
BMEdge **edge_net_init,
diff --git a/source/blender/bmesh/intern/bmesh_polygon_edgenet.h b/source/blender/bmesh/intern/bmesh_polygon_edgenet.h
index 6833f067421..a25f38a84b3 100644
--- a/source/blender/bmesh/intern/bmesh_polygon_edgenet.h
+++ b/source/blender/bmesh/intern/bmesh_polygon_edgenet.h
@@ -20,6 +20,14 @@
* \ingroup bmesh
*/
+/**
+ * Splits a face into many smaller faces defined by an edge-net.
+ * handle customdata and degenerate cases.
+ *
+ * - Isolated holes or unsupported face configurations, will be ignored.
+ * - Customdata calculations aren't efficient
+ * (need to calculate weights for each vert).
+ */
bool BM_face_split_edgenet(BMesh *bm,
BMFace *f,
BMEdge **edge_net,
@@ -27,12 +35,20 @@ bool BM_face_split_edgenet(BMesh *bm,
BMFace ***r_face_arr,
int *r_face_arr_len);
+/**
+ * For when the edge-net has holes in it-this connects them.
+ *
+ * \param use_partial_connect: Support for handling islands connected by only a single edge,
+ * \note that this is quite slow so avoid using where possible.
+ * \param mem_arena: Avoids many small allocs & should be cleared after each use.
+ * take care since \a edge_net_new is stored in \a r_edge_net_new.
+ */
bool BM_face_split_edgenet_connect_islands(BMesh *bm,
BMFace *f,
BMEdge **edge_net_init,
const uint edge_net_init_len,
bool use_partial_connect,
- struct MemArena *arena,
+ struct MemArena *mem_arena,
BMEdge ***r_edge_net_new,
uint *r_edge_net_new_len) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1, 2, 3, 6, 7, 8);
diff --git a/source/blender/bmesh/intern/bmesh_private.h b/source/blender/bmesh/intern/bmesh_private.h
index e1df7744e41..e7e8b7107e5 100644
--- a/source/blender/bmesh/intern/bmesh_private.h
+++ b/source/blender/bmesh/intern/bmesh_private.h
@@ -34,6 +34,12 @@
* it can take most of the CPU time when running some tools. */
# define BM_CHECK_ELEMENT(el) (void)(el)
#else
+/**
+ * Check the element is valid.
+ *
+ * BMESH_TODO, when this raises an error the output is incredibly confusing.
+ * need to have some nice way to print/debug what the heck's going on.
+ */
int bmesh_elem_check(void *element, const char htype);
# define BM_CHECK_ELEMENT(el) \
{ \
@@ -86,6 +92,12 @@ enum {
} \
(void)0
+/**
+ * \brief POLY ROTATE PLANE
+ *
+ * Rotates a polygon so that its
+ * normal is pointing towards the mesh Z axis
+ */
void poly_rotate_plane(const float normal[3], float (*verts)[3], const uint nverts);
/* include the rest of our private declarations */
diff --git a/source/blender/bmesh/intern/bmesh_query.c b/source/blender/bmesh/intern/bmesh_query.c
index 795d8829ee7..fe2142670a2 100644
--- a/source/blender/bmesh/intern/bmesh_query.c
+++ b/source/blender/bmesh/intern/bmesh_query.c
@@ -37,24 +37,6 @@
#include "bmesh.h"
#include "intern/bmesh_private.h"
-/**
- * \brief Other Loop in Face Sharing an Edge
- *
- * Finds the other loop that shares \a v with \a e loop in \a f.
- * <pre>
- * +----------+
- * | |
- * | f |
- * | |
- * +----------+ <-- return the face loop of this vertex.
- * v --> e
- * ^ ^ <------- These vert args define direction
- * in the face to check.
- * The faces loop direction is ignored.
- * </pre>
- *
- * \note caller must ensure \a e is used in \a f
- */
BMLoop *BM_face_other_edge_loop(BMFace *f, BMEdge *e, BMVert *v)
{
BMLoop *l = BM_face_edge_share_loop(f, e);
@@ -62,38 +44,12 @@ BMLoop *BM_face_other_edge_loop(BMFace *f, BMEdge *e, BMVert *v)
return BM_loop_other_edge_loop(l, v);
}
-/**
- * See #BM_face_other_edge_loop This is the same functionality
- * to be used when the edges loop is already known.
- */
BMLoop *BM_loop_other_edge_loop(BMLoop *l, BMVert *v)
{
BLI_assert(BM_vert_in_edge(l->e, v));
return l->v == v ? l->prev : l->next;
}
-/**
- * \brief Other Loop in Face Sharing a Vertex
- *
- * Finds the other loop in a face.
- *
- * This function returns a loop in \a f that shares an edge with \a v
- * The direction is defined by \a v_prev, where the return value is
- * the loop of what would be 'v_next'
- * <pre>
- * +----------+ <-- return the face loop of this vertex.
- * | |
- * | f |
- * | |
- * +----------+
- * v_prev --> v
- * ^^^^^^ ^ <-- These vert args define direction
- * in the face to check.
- * The faces loop direction is ignored.
- * </pre>
- *
- * \note \a v_prev and \a v _implicitly_ define an edge.
- */
BMLoop *BM_face_other_vert_loop(BMFace *f, BMVert *v_prev, BMVert *v)
{
BMLoop *l_iter = BM_face_vert_share_loop(f, v);
@@ -116,22 +72,6 @@ BMLoop *BM_face_other_vert_loop(BMFace *f, BMVert *v_prev, BMVert *v)
return NULL;
}
-/**
- * \brief Other Loop in Face Sharing a Vert
- *
- * Finds the other loop that shares \a v with \a e loop in \a f.
- * <pre>
- * +----------+ <-- return the face loop of this vertex.
- * | |
- * | |
- * | |
- * +----------+ <-- This vertex defines the direction.
- * l v
- * ^ <------- This loop defines both the face to search
- * and the edge, in combination with 'v'
- * The faces loop direction is ignored.
- * </pre>
- */
BMLoop *BM_loop_other_vert_loop(BMLoop *l, BMVert *v)
{
#if 0 /* works but slow */
@@ -157,22 +97,6 @@ BMLoop *BM_loop_other_vert_loop(BMLoop *l, BMVert *v)
#endif
}
-/**
- * Return the other loop that uses this edge.
- *
- * In this case the loop defines the vertex,
- * the edge passed in defines the direction to step.
- *
- * <pre>
- * +----------+ <-- Return the face-loop of this vertex.
- * | |
- * | e | <-- This edge defines the direction.
- * | |
- * +----------+ <-- This loop defines the face and vertex..
- * l
- * </pre>
- *
- */
BMLoop *BM_loop_other_vert_loop_by_edge(BMLoop *l, BMEdge *e)
{
BLI_assert(BM_vert_in_edge(e, l->v));
@@ -187,9 +111,6 @@ BMLoop *BM_loop_other_vert_loop_by_edge(BMLoop *l, BMEdge *e)
return NULL;
}
-/**
- * Check if verts share a face.
- */
bool BM_vert_pair_share_face_check(BMVert *v_a, BMVert *v_b)
{
if (v_a->e && v_b->e) {
@@ -255,9 +176,6 @@ BMFace *BM_vert_pair_shared_face_cb(BMVert *v_a,
return NULL;
}
-/**
- * Given 2 verts, find the smallest face they share and give back both loops.
- */
BMFace *BM_vert_pair_share_face_by_len(
BMVert *v_a, BMVert *v_b, BMLoop **r_l_a, BMLoop **r_l_b, const bool allow_adjacent)
{
@@ -325,24 +243,12 @@ static float bm_face_calc_split_dot(BMLoop *l_a, BMLoop *l_b)
return -1.0f;
}
-/**
- * Check if a point is inside the corner defined by a loop
- * (within the 2 planes defined by the loops corner & face normal).
- *
- * \return signed, squared distance to the loops planes, less than 0.0 when outside.
- */
float BM_loop_point_side_of_loop_test(const BMLoop *l, const float co[3])
{
const float *axis = l->f->no;
return dist_signed_squared_to_corner_v3v3v3(co, l->prev->v->co, l->v->co, l->next->v->co, axis);
}
-/**
- * Check if a point is inside the edge defined by a loop
- * (within the plane defined by the loops edge & face normal).
- *
- * \return signed, squared distance to the edge plane, less than 0.0 when outside.
- */
float BM_loop_point_side_of_edge_test(const BMLoop *l, const float co[3])
{
const float *axis = l->f->no;
@@ -356,13 +262,6 @@ float BM_loop_point_side_of_edge_test(const BMLoop *l, const float co[3])
return dist_signed_squared_to_plane_v3(co, plane);
}
-/**
- * Given 2 verts,
- * find a face they share that has the lowest angle across these verts and give back both loops.
- *
- * This can be better than #BM_vert_pair_share_face_by_len
- * because concave splits are ranked lowest.
- */
BMFace *BM_vert_pair_share_face_by_angle(
BMVert *v_a, BMVert *v_b, BMLoop **r_l_a, BMLoop **r_l_b, const bool allow_adjacent)
{
@@ -409,25 +308,15 @@ BMFace *BM_vert_pair_share_face_by_angle(
return f_cur;
}
-/**
- * Get the first loop of a vert. Uses the same initialization code for the first loop of the
- * iterator API
- */
BMLoop *BM_vert_find_first_loop(BMVert *v)
{
return v->e ? bmesh_disk_faceloop_find_first(v->e, v) : NULL;
}
-/**
- * A version of #BM_vert_find_first_loop that ignores hidden loops.
- */
BMLoop *BM_vert_find_first_loop_visible(BMVert *v)
{
return v->e ? bmesh_disk_faceloop_find_first_visible(v->e, v) : NULL;
}
-/**
- * Returns true if the vertex is used in a given face.
- */
bool BM_vert_in_face(BMVert *v, BMFace *f)
{
BMLoop *l_iter, *l_first;
@@ -452,10 +341,6 @@ bool BM_vert_in_face(BMVert *v, BMFace *f)
return false;
}
-/**
- * Compares the number of vertices in an array
- * that appear in a given face
- */
int BM_verts_in_face_count(BMVert **varr, int len, BMFace *f)
{
BMLoop *l_iter, *l_first;
@@ -496,9 +381,6 @@ int BM_verts_in_face_count(BMVert **varr, int len, BMFace *f)
return count;
}
-/**
- * Return true if all verts are in the face.
- */
bool BM_verts_in_face(BMVert **varr, int len, BMFace *f)
{
BMLoop *l_iter, *l_first;
@@ -549,9 +431,6 @@ bool BM_verts_in_face(BMVert **varr, int len, BMFace *f)
return ok;
}
-/**
- * Returns whether or not a given edge is part of a given face.
- */
bool BM_edge_in_face(const BMEdge *e, const BMFace *f)
{
if (e->l) {
@@ -568,22 +447,6 @@ bool BM_edge_in_face(const BMEdge *e, const BMFace *f)
return false;
}
-/**
- * Given a edge and a loop (assumes the edge is manifold). returns
- * the other faces loop, sharing the same vertex.
- *
- * <pre>
- * +-------------------+
- * | |
- * | |
- * |l_other <-- return |
- * +-------------------+ <-- A manifold edge between 2 faces
- * |l e <-- edge |
- * |^ <-------- loop |
- * | |
- * +-------------------+
- * </pre>
- */
BMLoop *BM_edge_other_loop(BMEdge *e, BMLoop *l)
{
BMLoop *l_other;
@@ -609,31 +472,6 @@ BMLoop *BM_edge_other_loop(BMEdge *e, BMLoop *l)
return l_other;
}
-/**
- * Utility function to step around a fan of loops,
- * using an edge to mark the previous side.
- *
- * \note all edges must be manifold,
- * once a non manifold edge is hit, return NULL.
- *
- * <pre>
- * ,.,-->|
- * _,-' |
- * ,' | (notice how 'e_step'
- * / | and 'l' define the
- * / | direction the arrow
- * | return | points).
- * | loop --> |
- * ---------------------+---------------------
- * ^ l --> |
- * | |
- * assign e_step |
- * |
- * begin e_step ----> |
- * |
- * </pre>
- */
-
BMLoop *BM_vert_step_fan_loop(BMLoop *l, BMEdge **e_step)
{
BMEdge *e_prev = *e_step;
@@ -655,12 +493,6 @@ BMLoop *BM_vert_step_fan_loop(BMLoop *l, BMEdge **e_step)
return NULL;
}
-/**
- * The function takes a vertex at the center of a fan and returns the opposite edge in the fan.
- * All edges in the fan must be manifold, otherwise return NULL.
- *
- * \note This could (probably) be done more efficiently.
- */
BMEdge *BM_vert_other_disk_edge(BMVert *v, BMEdge *e_first)
{
BMLoop *l_a;
@@ -707,28 +539,16 @@ BMEdge *BM_vert_other_disk_edge(BMVert *v, BMEdge *e_first)
return NULL;
}
-/**
- * Returns edge length
- */
float BM_edge_calc_length(const BMEdge *e)
{
return len_v3v3(e->v1->co, e->v2->co);
}
-/**
- * Returns edge length squared (for comparisons)
- */
float BM_edge_calc_length_squared(const BMEdge *e)
{
return len_squared_v3v3(e->v1->co, e->v2->co);
}
-/**
- * Utility function, since enough times we have an edge
- * and want to access 2 connected faces.
- *
- * \return true when only 2 faces are found.
- */
bool BM_edge_face_pair(BMEdge *e, BMFace **r_fa, BMFace **r_fb)
{
BMLoop *la, *lb;
@@ -744,12 +564,6 @@ bool BM_edge_face_pair(BMEdge *e, BMFace **r_fa, BMFace **r_fb)
return false;
}
-/**
- * Utility function, since enough times we have an edge
- * and want to access 2 connected loops.
- *
- * \return true when only 2 faces are found.
- */
bool BM_edge_loop_pair(BMEdge *e, BMLoop **r_la, BMLoop **r_lb)
{
BMLoop *la, *lb;
@@ -765,9 +579,6 @@ bool BM_edge_loop_pair(BMEdge *e, BMLoop **r_la, BMLoop **r_lb)
return false;
}
-/**
- * Fast alternative to `(BM_vert_edge_count(v) == 2)`.
- */
bool BM_vert_is_edge_pair(const BMVert *v)
{
const BMEdge *e = v->e;
@@ -778,10 +589,6 @@ bool BM_vert_is_edge_pair(const BMVert *v)
return false;
}
-/**
- * Fast alternative to `(BM_vert_edge_count(v) == 2)`
- * that checks both edges connect to the same faces.
- */
bool BM_vert_is_edge_pair_manifold(const BMVert *v)
{
const BMEdge *e = v->e;
@@ -794,11 +601,6 @@ bool BM_vert_is_edge_pair_manifold(const BMVert *v)
return false;
}
-/**
- * Access a verts 2 connected edges.
- *
- * \return true when only 2 verts are found.
- */
bool BM_vert_edge_pair(BMVert *v, BMEdge **r_e_a, BMEdge **r_e_b)
{
BMEdge *e_a = v->e;
@@ -816,9 +618,6 @@ bool BM_vert_edge_pair(BMVert *v, BMEdge **r_e_a, BMEdge **r_e_b)
return false;
}
-/**
- * Returns the number of edges around this vertex.
- */
int BM_vert_edge_count(const BMVert *v)
{
return bmesh_disk_count(v);
@@ -841,9 +640,6 @@ int BM_vert_edge_count_nonwire(const BMVert *v)
}
return count;
}
-/**
- * Returns the number of faces around this edge
- */
int BM_edge_face_count(const BMEdge *e)
{
int count = 0;
@@ -879,10 +675,6 @@ int BM_edge_face_count_at_most(const BMEdge *e, const int count_max)
return count;
}
-/**
- * Returns the number of faces around this vert
- * length matches #BM_LOOPS_OF_VERT iterator
- */
int BM_vert_face_count(const BMVert *v)
{
return bmesh_disk_facevert_count(v);
@@ -893,11 +685,6 @@ int BM_vert_face_count_at_most(const BMVert *v, int count_max)
return bmesh_disk_facevert_count_at_most(v, count_max);
}
-/**
- * Return true if the vertex is connected to _any_ faces.
- *
- * same as `BM_vert_face_count(v) != 0` or `BM_vert_find_first_loop(v) == NULL`.
- */
bool BM_vert_face_check(const BMVert *v)
{
if (v->e != NULL) {
@@ -912,10 +699,6 @@ bool BM_vert_face_check(const BMVert *v)
return false;
}
-/**
- * Tests whether or not the vertex is part of a wire edge.
- * (ie: has no faces attached to it)
- */
bool BM_vert_is_wire(const BMVert *v)
{
if (v->e) {
@@ -933,13 +716,6 @@ bool BM_vert_is_wire(const BMVert *v)
return false;
}
-/**
- * A vertex is non-manifold if it meets the following conditions:
- * 1: Loose - (has no edges/faces incident upon it).
- * 2: Joins two distinct regions - (two pyramids joined at the tip).
- * 3: Is part of an edge with more than 2 faces.
- * 4: Is part of a wire edge.
- */
bool BM_vert_is_manifold(const BMVert *v)
{
BMEdge *e_iter, *e_first, *e_prev;
@@ -1064,9 +840,6 @@ static int bm_loop_region_count__clear(BMLoop *l)
return count;
}
-/**
- * The number of loops connected to this loop (not including disconnected regions).
- */
int BM_loop_region_loops_count_at_most(BMLoop *l, int *r_loop_total)
{
const int count = bm_loop_region_count__recursive(l->e, l->v);
@@ -1085,10 +858,6 @@ int BM_loop_region_loops_count(BMLoop *l)
return BM_loop_region_loops_count_at_most(l, NULL);
}
-/**
- * A version of #BM_vert_is_manifold
- * which only checks if we're connected to multiple isolated regions.
- */
bool BM_vert_is_manifold_region(const BMVert *v)
{
BMLoop *l_first = BM_vert_find_first_loop((BMVert *)v);
@@ -1100,10 +869,6 @@ bool BM_vert_is_manifold_region(const BMVert *v)
return true;
}
-/**
- * Check if the edge is convex or concave
- * (depends on face winding)
- */
bool BM_edge_is_convex(const BMEdge *e)
{
if (BM_edge_is_manifold(e)) {
@@ -1121,9 +886,6 @@ bool BM_edge_is_convex(const BMEdge *e)
return true;
}
-/**
- * \return true when loop customdata is contiguous.
- */
bool BM_edge_is_contiguous_loop_cd(const BMEdge *e,
const int cd_loop_type,
const int cd_loop_offset)
@@ -1182,11 +944,6 @@ bool BM_vert_is_boundary(const BMVert *v)
return false;
}
-/**
- * Returns the number of faces that are adjacent to both f1 and f2,
- * \note Could be sped up a bit by not using iterators and by tagging
- * faces on either side, then count the tags rather then searching.
- */
int BM_face_share_face_count(BMFace *f_a, BMFace *f_b)
{
BMIter iter1, iter2;
@@ -1205,9 +962,6 @@ int BM_face_share_face_count(BMFace *f_a, BMFace *f_b)
return count;
}
-/**
- * same as #BM_face_share_face_count but returns a bool
- */
bool BM_face_share_face_check(BMFace *f_a, BMFace *f_b)
{
BMIter iter1, iter2;
@@ -1225,9 +979,6 @@ bool BM_face_share_face_check(BMFace *f_a, BMFace *f_b)
return false;
}
-/**
- * Counts the number of edges two faces share (if any)
- */
int BM_face_share_edge_count(BMFace *f_a, BMFace *f_b)
{
BMLoop *l_iter;
@@ -1244,9 +995,6 @@ int BM_face_share_edge_count(BMFace *f_a, BMFace *f_b)
return count;
}
-/**
- * Returns true if the faces share an edge
- */
bool BM_face_share_edge_check(BMFace *f1, BMFace *f2)
{
BMLoop *l_iter;
@@ -1262,9 +1010,6 @@ bool BM_face_share_edge_check(BMFace *f1, BMFace *f2)
return false;
}
-/**
- * Counts the number of verts two faces share (if any).
- */
int BM_face_share_vert_count(BMFace *f_a, BMFace *f_b)
{
BMLoop *l_iter;
@@ -1281,9 +1026,6 @@ int BM_face_share_vert_count(BMFace *f_a, BMFace *f_b)
return count;
}
-/**
- * Returns true if the faces share a vert.
- */
bool BM_face_share_vert_check(BMFace *f_a, BMFace *f_b)
{
BMLoop *l_iter;
@@ -1299,18 +1041,12 @@ bool BM_face_share_vert_check(BMFace *f_a, BMFace *f_b)
return false;
}
-/**
- * Returns true when 2 loops share an edge (are adjacent in the face-fan)
- */
bool BM_loop_share_edge_check(BMLoop *l_a, BMLoop *l_b)
{
BLI_assert(l_a->v == l_b->v);
return (ELEM(l_a->e, l_b->e, l_b->prev->e) || ELEM(l_b->e, l_a->e, l_a->prev->e));
}
-/**
- * Test if e1 shares any faces with e2
- */
bool BM_edge_share_face_check(BMEdge *e1, BMEdge *e2)
{
BMLoop *l;
@@ -1329,9 +1065,6 @@ bool BM_edge_share_face_check(BMEdge *e1, BMEdge *e2)
return false;
}
-/**
- * Test if e1 shares any quad faces with e2
- */
bool BM_edge_share_quad_check(BMEdge *e1, BMEdge *e2)
{
BMLoop *l;
@@ -1352,17 +1085,11 @@ bool BM_edge_share_quad_check(BMEdge *e1, BMEdge *e2)
return false;
}
-/**
- * Tests to see if e1 shares a vertex with e2
- */
bool BM_edge_share_vert_check(BMEdge *e1, BMEdge *e2)
{
return (e1->v1 == e2->v1 || e1->v1 == e2->v2 || e1->v2 == e2->v1 || e1->v2 == e2->v2);
}
-/**
- * Return the shared vertex between the two edges or NULL
- */
BMVert *BM_edge_share_vert(BMEdge *e1, BMEdge *e2)
{
BLI_assert(e1 != e2);
@@ -1375,14 +1102,6 @@ BMVert *BM_edge_share_vert(BMEdge *e1, BMEdge *e2)
return NULL;
}
-/**
- * \brief Return the Loop Shared by Edge and Vert
- *
- * Finds the loop used which uses \a in face loop \a l
- *
- * \note this function takes a loop rather than an edge
- * so we can select the face that the loop should be from.
- */
BMLoop *BM_edge_vert_share_loop(BMLoop *l, BMVert *v)
{
BLI_assert(BM_vert_in_edge(l->e, v));
@@ -1392,14 +1111,6 @@ BMLoop *BM_edge_vert_share_loop(BMLoop *l, BMVert *v)
return l->next;
}
-/**
- * \brief Return the Loop Shared by Face and Vertex
- *
- * Finds the loop used which uses \a v in face loop \a l
- *
- * \note currently this just uses simple loop in future may be sped up
- * using radial vars
- */
BMLoop *BM_face_vert_share_loop(BMFace *f, BMVert *v)
{
BMLoop *l_first;
@@ -1415,14 +1126,6 @@ BMLoop *BM_face_vert_share_loop(BMFace *f, BMVert *v)
return NULL;
}
-/**
- * \brief Return the Loop Shared by Face and Edge
- *
- * Finds the loop used which uses \a e in face loop \a l
- *
- * \note currently this just uses simple loop in future may be sped up
- * using radial vars
- */
BMLoop *BM_face_edge_share_loop(BMFace *f, BMEdge *e)
{
BMLoop *l_first;
@@ -1438,18 +1141,6 @@ BMLoop *BM_face_edge_share_loop(BMFace *f, BMEdge *e)
return NULL;
}
-/**
- * Returns the verts of an edge as used in a face
- * if used in a face at all, otherwise just assign as used in the edge.
- *
- * Useful to get a deterministic winding order when calling
- * BM_face_create_ngon() on an arbitrary array of verts,
- * though be sure to pick an edge which has a face.
- *
- * \note This is in fact quite a simple check,
- * mainly include this function so the intent is more obvious.
- * We know these 2 verts will _always_ make up the loops edge
- */
void BM_edge_ordered_verts_ex(const BMEdge *edge,
BMVert **r_v1,
BMVert **r_v2,
@@ -1466,9 +1157,6 @@ void BM_edge_ordered_verts(const BMEdge *edge, BMVert **r_v1, BMVert **r_v2)
BM_edge_ordered_verts_ex(edge, r_v1, r_v2, edge->l);
}
-/**
- * \return The previous loop, over \a eps_sq distance from \a l (or \a NULL if l_stop is reached).
- */
BMLoop *BM_loop_find_prev_nodouble(BMLoop *l, BMLoop *l_stop, const float eps_sq)
{
BMLoop *l_step = l->prev;
@@ -1486,9 +1174,6 @@ BMLoop *BM_loop_find_prev_nodouble(BMLoop *l, BMLoop *l_stop, const float eps_sq
return l_step;
}
-/**
- * \return The next loop, over \a eps_sq distance from \a l (or \a NULL if l_stop is reached).
- */
BMLoop *BM_loop_find_next_nodouble(BMLoop *l, BMLoop *l_stop, const float eps_sq)
{
BMLoop *l_step = l->next;
@@ -1506,10 +1191,6 @@ BMLoop *BM_loop_find_next_nodouble(BMLoop *l, BMLoop *l_stop, const float eps_sq
return l_step;
}
-/**
- * Check if the loop is convex or concave
- * (depends on face normal)
- */
bool BM_loop_is_convex(const BMLoop *l)
{
float e_dir_prev[3];
@@ -1522,26 +1203,11 @@ bool BM_loop_is_convex(const BMLoop *l)
return dot_v3v3(l_no, l->f->no) > 0.0f;
}
-/**
- * Calculates the angle between the previous and next loops
- * (angle at this loops face corner).
- *
- * \return angle in radians
- */
float BM_loop_calc_face_angle(const BMLoop *l)
{
return angle_v3v3v3(l->prev->v->co, l->v->co, l->next->v->co);
}
-/**
- * \brief BM_loop_calc_face_normal
- *
- * Calculate the normal at this loop corner or fallback to the face normal on straight lines.
- *
- * \param l: The loop to calculate the normal at.
- * \param epsilon_sq: Value to avoid numeric errors (1e-5f works well).
- * \param r_normal: Resulting normal.
- */
float BM_loop_calc_face_normal_safe_ex(const BMLoop *l, const float epsilon_sq, float r_normal[3])
{
/* NOTE: we cannot use result of normal_tri_v3 here to detect colinear vectors
@@ -1571,9 +1237,6 @@ float BM_loop_calc_face_normal_safe_ex(const BMLoop *l, const float epsilon_sq,
return 0.0f;
}
-/**
- * A version of BM_loop_calc_face_normal_safe_ex which takes vertex coordinates.
- */
float BM_loop_calc_face_normal_safe_vcos_ex(const BMLoop *l,
const float normal_fallback[3],
float const (*vertexCos)[3],
@@ -1604,11 +1267,6 @@ float BM_loop_calc_face_normal_safe_vcos_ex(const BMLoop *l,
return 0.0f;
}
-/**
- * #BM_loop_calc_face_normal_safe_ex with predefined sane epsilon.
- *
- * Since this doesn't scale based on triangle size, fixed value works well.
- */
float BM_loop_calc_face_normal_safe(const BMLoop *l, float r_normal[3])
{
return BM_loop_calc_face_normal_safe_ex(l, 1e-5f, r_normal);
@@ -1623,15 +1281,6 @@ float BM_loop_calc_face_normal_safe_vcos(const BMLoop *l,
return BM_loop_calc_face_normal_safe_vcos_ex(l, normal_fallback, vertexCos, 1e-5f, r_normal);
}
-/**
- * \brief BM_loop_calc_face_normal
- *
- * Calculate the normal at this loop corner or fallback to the face normal on straight lines.
- *
- * \param l: The loop to calculate the normal at
- * \param r_normal: Resulting normal
- * \return The length of the cross product (double the area).
- */
float BM_loop_calc_face_normal(const BMLoop *l, float r_normal[3])
{
float v1[3], v2[3];
@@ -1646,14 +1295,6 @@ float BM_loop_calc_face_normal(const BMLoop *l, float r_normal[3])
return len;
}
-/**
- * \brief BM_loop_calc_face_direction
- *
- * Calculate the direction a loop is pointing.
- *
- * \param l: The loop to calculate the direction at
- * \param r_dir: Resulting direction
- */
void BM_loop_calc_face_direction(const BMLoop *l, float r_dir[3])
{
float v_prev[3];
@@ -1669,15 +1310,6 @@ void BM_loop_calc_face_direction(const BMLoop *l, float r_dir[3])
normalize_v3(r_dir);
}
-/**
- * \brief BM_loop_calc_face_tangent
- *
- * Calculate the tangent at this loop corner or fallback to the face normal on straight lines.
- * This vector always points inward into the face.
- *
- * \param l: The loop to calculate the tangent at
- * \param r_tangent: Resulting tangent
- */
void BM_loop_calc_face_tangent(const BMLoop *l, float r_tangent[3])
{
float v_prev[3];
@@ -1708,14 +1340,6 @@ void BM_loop_calc_face_tangent(const BMLoop *l, float r_tangent[3])
normalize_v3(r_tangent);
}
-/**
- * \brief BMESH EDGE/FACE ANGLE
- *
- * Calculates the angle between two faces.
- * Assumes the face normals are correct.
- *
- * \return angle in radians
- */
float BM_edge_calc_face_angle_ex(const BMEdge *e, const float fallback)
{
if (BM_edge_is_manifold(e)) {
@@ -1730,14 +1354,6 @@ float BM_edge_calc_face_angle(const BMEdge *e)
return BM_edge_calc_face_angle_ex(e, DEG2RADF(90.0f));
}
-/**
- * \brief BMESH EDGE/FACE ANGLE
- *
- * Calculates the angle between two faces in world space.
- * Assumes the face normals are correct.
- *
- * \return angle in radians
- */
float BM_edge_calc_face_angle_with_imat3_ex(const BMEdge *e,
const float imat3[3][3],
const float fallback)
@@ -1764,14 +1380,6 @@ float BM_edge_calc_face_angle_with_imat3(const BMEdge *e, const float imat3[3][3
return BM_edge_calc_face_angle_with_imat3_ex(e, imat3, DEG2RADF(90.0f));
}
-/**
- * \brief BMESH EDGE/FACE ANGLE
- *
- * Calculates the angle between two faces.
- * Assumes the face normals are correct.
- *
- * \return angle in radians
- */
float BM_edge_calc_face_angle_signed_ex(const BMEdge *e, const float fallback)
{
if (BM_edge_is_manifold(e)) {
@@ -1787,19 +1395,6 @@ float BM_edge_calc_face_angle_signed(const BMEdge *e)
return BM_edge_calc_face_angle_signed_ex(e, DEG2RADF(90.0f));
}
-/**
- * \brief BMESH EDGE/FACE TANGENT
- *
- * Calculate the tangent at this loop corner or fallback to the face normal on straight lines.
- * This vector always points inward into the face.
- *
- * \brief BM_edge_calc_face_tangent
- * \param e:
- * \param e_loop: The loop to calculate the tangent at,
- * used to get the face and winding direction.
- * \param r_tangent: The loop corner tangent to set
- */
-
void BM_edge_calc_face_tangent(const BMEdge *e, const BMLoop *e_loop, float r_tangent[3])
{
float tvec[3];
@@ -1813,13 +1408,6 @@ void BM_edge_calc_face_tangent(const BMEdge *e, const BMLoop *e_loop, float r_ta
normalize_v3(r_tangent);
}
-/**
- * \brief BMESH VERT/EDGE ANGLE
- *
- * Calculates the angle a verts 2 edges.
- *
- * \returns the angle in radians
- */
float BM_vert_calc_edge_angle_ex(const BMVert *v, const float fallback)
{
BMEdge *e1, *e2;
@@ -1843,10 +1431,6 @@ float BM_vert_calc_edge_angle(const BMVert *v)
return BM_vert_calc_edge_angle_ex(v, DEG2RADF(90.0f));
}
-/**
- * \note this isn't optimal to run on an array of verts,
- * see 'solidify_add_thickness' for a function which runs on an array.
- */
float BM_vert_calc_shell_factor(const BMVert *v)
{
BMIter iter;
@@ -1865,8 +1449,6 @@ float BM_vert_calc_shell_factor(const BMVert *v)
}
return 1.0f;
}
-/* alternate version of #BM_vert_calc_shell_factor which only
- * uses 'hflag' faces, but falls back to all if none found. */
float BM_vert_calc_shell_factor_ex(const BMVert *v, const float no[3], const char hflag)
{
BMIter iter;
@@ -1896,10 +1478,6 @@ float BM_vert_calc_shell_factor_ex(const BMVert *v, const float no[3], const cha
return 1.0f;
}
-/**
- * \note quite an obscure function.
- * used in bmesh operators that have a relative scale options,
- */
float BM_vert_calc_median_tagged_edge_length(const BMVert *v)
{
BMIter iter;
@@ -1920,9 +1498,6 @@ float BM_vert_calc_median_tagged_edge_length(const BMVert *v)
return 0.0f;
}
-/**
- * Returns the loop of the shortest edge in f.
- */
BMLoop *BM_face_find_shortest_loop(BMFace *f)
{
BMLoop *shortest_loop = NULL;
@@ -1944,9 +1519,6 @@ BMLoop *BM_face_find_shortest_loop(BMFace *f)
return shortest_loop;
}
-/**
- * Returns the loop of the longest edge in f.
- */
BMLoop *BM_face_find_longest_loop(BMFace *f)
{
BMLoop *longest_loop = NULL;
@@ -2020,11 +1592,6 @@ BMEdge *BM_edge_exists(BMVert *v_a, BMVert *v_b)
}
#endif
-/**
- * Returns an edge sharing the same vertices as this one.
- * This isn't an invalid state but tools should clean up these cases before
- * returning the mesh to the user.
- */
BMEdge *BM_edge_find_double(BMEdge *e)
{
BMVert *v = e->v1;
@@ -2042,10 +1609,6 @@ BMEdge *BM_edge_find_double(BMEdge *e)
return NULL;
}
-/**
- * Only #BMEdge.l access us needed, however when we want the first visible loop,
- * a utility function is needed.
- */
BMLoop *BM_edge_find_first_loop_visible(BMEdge *e)
{
if (e->l != NULL) {
@@ -2060,13 +1623,6 @@ BMLoop *BM_edge_find_first_loop_visible(BMEdge *e)
return NULL;
}
-/**
- * Given a set of vertices (varr), find out if
- * there is a face with exactly those vertices
- * (and only those vertices).
- *
- * \note there used to be a BM_face_exists_overlap function that checks for partial overlap.
- */
BMFace *BM_face_exists(BMVert **varr, int len)
{
if (varr[0]->e) {
@@ -2115,9 +1671,6 @@ BMFace *BM_face_exists(BMVert **varr, int len)
return NULL;
}
-/**
- * Check if the face has an exact duplicate (both winding directions).
- */
BMFace *BM_face_find_double(BMFace *f)
{
BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
@@ -2150,18 +1703,6 @@ BMFace *BM_face_find_double(BMFace *f)
return NULL;
}
-/**
- * Given a set of vertices and edges (\a varr, \a earr), find out if
- * all those vertices are filled in by existing faces that _only_ use those vertices.
- *
- * This is for use in cases where creating a face is possible but would result in
- * many overlapping faces.
- *
- * An example of how this is used: when 2 tri's are selected that share an edge,
- * pressing Fkey would make a new overlapping quad (without a check like this)
- *
- * \a earr and \a varr can be in any order, however they _must_ form a closed loop.
- */
bool BM_face_exists_multi(BMVert **varr, BMEdge **earr, int len)
{
BMFace *f;
@@ -2270,7 +1811,6 @@ finally:
return ok;
}
-/* same as 'BM_face_exists_multi' but built vert array from edges */
bool BM_face_exists_multi_edge(BMEdge **earr, int len)
{
BMVert **varr = BLI_array_alloca(varr, len);
@@ -2284,20 +1824,6 @@ bool BM_face_exists_multi_edge(BMEdge **earr, int len)
return BM_face_exists_multi(varr, earr, len);
}
-/**
- * Given a set of vertices (varr), find out if
- * all those vertices overlap an existing face.
- *
- * \note The face may contain other verts \b not in \a varr.
- *
- * \note Its possible there are more than one overlapping faces,
- * in this case the first one found will be returned.
- *
- * \param varr: Array of unordered verts.
- * \param len: \a varr array length.
- * \return The face or NULL.
- */
-
BMFace *BM_face_exists_overlap(BMVert **varr, const int len)
{
BMIter viter;
@@ -2336,14 +1862,6 @@ BMFace *BM_face_exists_overlap(BMVert **varr, const int len)
return f_overlap;
}
-/**
- * Given a set of vertices (varr), find out if
- * there is a face that uses vertices only from this list
- * (that the face is a subset or made from the vertices given).
- *
- * \param varr: Array of unordered verts.
- * \param len: varr array length.
- */
bool BM_face_exists_overlap_subset(BMVert **varr, const int len)
{
BMIter viter;
@@ -2477,7 +1995,6 @@ bool BM_edge_is_any_face_flag_test(const BMEdge *e, const char hflag)
return false;
}
-/* convenience functions for checking flags */
bool BM_edge_is_any_vert_flag_test(const BMEdge *e, const char hflag)
{
return (BM_elem_flag_test(e->v1, hflag) || BM_elem_flag_test(e->v2, hflag));
@@ -2527,9 +2044,6 @@ bool BM_edge_is_any_face_len_test(const BMEdge *e, const int len)
return false;
}
-/**
- * Use within assert's to check normals are valid.
- */
bool BM_face_is_normal_valid(const BMFace *f)
{
const float eps = 0.0001f;
@@ -2591,23 +2105,6 @@ double BM_mesh_calc_volume(BMesh *bm, bool is_signed)
return vol;
}
-/* NOTE: almost duplicate of #BM_mesh_calc_edge_groups, keep in sync. */
-/**
- * Calculate isolated groups of faces with optional filtering.
- *
- * \param bm: the BMesh.
- * \param r_groups_array: Array of ints to fill in, length of bm->totface
- * (or when hflag_test is set, the number of flagged faces).
- * \param r_group_index: index, length pairs into \a r_groups_array, size of return value
- * int pairs: (array_start, array_length).
- * \param filter_fn: Filter the edge-loops or vert-loops we step over (depends on \a htype_step).
- * \param user_data: Optional user data for \a filter_fn, can be NULL.
- * \param hflag_test: Optional flag to test faces,
- * use to exclude faces from the calculation, 0 for all faces.
- * \param htype_step: BM_VERT to walk over face-verts, BM_EDGE to walk over faces edges
- * (having both set is supported too).
- * \return The number of groups found.
- */
int BM_mesh_calc_face_groups(BMesh *bm,
int *r_groups_array,
int (**r_group_index)[2],
@@ -2617,6 +2114,8 @@ int BM_mesh_calc_face_groups(BMesh *bm,
const char hflag_test,
const char htype_step)
{
+ /* NOTE: almost duplicate of #BM_mesh_calc_edge_groups, keep in sync. */
+
#ifdef DEBUG
int group_index_len = 1;
#else
@@ -2755,25 +2254,6 @@ int BM_mesh_calc_face_groups(BMesh *bm,
return group_curr;
}
-/* NOTE: almost duplicate of #BM_mesh_calc_face_groups, keep in sync. */
-/**
- * Calculate isolated groups of edges with optional filtering.
- *
- * \param bm: the BMesh.
- * \param r_groups_array: Array of ints to fill in, length of bm->totedge
- * (or when hflag_test is set, the number of flagged edges).
- * \param r_group_index: index, length pairs into \a r_groups_array, size of return value
- * int pairs: (array_start, array_length).
- * \param filter_fn: Filter the edges or verts we step over (depends on \a htype_step)
- * as to which types we deal with.
- * \param user_data: Optional user data for \a filter_fn, can be NULL.
- * \param hflag_test: Optional flag to test edges,
- * use to exclude edges from the calculation, 0 for all edges.
- * \return The number of groups found.
- *
- * \note Unlike #BM_mesh_calc_face_groups there is no 'htype_step' argument,
- * since we always walk over verts.
- */
int BM_mesh_calc_edge_groups(BMesh *bm,
int *r_groups_array,
int (**r_group_index)[2],
@@ -2781,6 +2261,8 @@ int BM_mesh_calc_edge_groups(BMesh *bm,
void *user_data,
const char hflag_test)
{
+ /* NOTE: almost duplicate of #BM_mesh_calc_face_groups, keep in sync. */
+
#ifdef DEBUG
int group_index_len = 1;
#else
@@ -2892,13 +2374,6 @@ int BM_mesh_calc_edge_groups(BMesh *bm,
return group_curr;
}
-/**
- * This is an alternative to #BM_mesh_calc_edge_groups.
- *
- * While we could call this, then create vertex & face arrays,
- * it requires looping over geometry connectivity twice,
- * this slows down edit-mesh separate by loose parts, see: T70864.
- */
int BM_mesh_calc_edge_groups_as_arrays(
BMesh *bm, BMVert **verts, BMEdge **edges, BMFace **faces, int (**r_groups)[3])
{
diff --git a/source/blender/bmesh/intern/bmesh_query.h b/source/blender/bmesh/intern/bmesh_query.h
index 021358f81ad..48a1d100c72 100644
--- a/source/blender/bmesh/intern/bmesh_query.h
+++ b/source/blender/bmesh/intern/bmesh_query.h
@@ -20,11 +20,24 @@
* \ingroup bmesh
*/
+/**
+ * Returns true if the vertex is used in a given face.
+ */
bool BM_vert_in_face(BMVert *v, BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Compares the number of vertices in an array
+ * that appear in a given face
+ */
int BM_verts_in_face_count(BMVert **varr, int len, BMFace *f) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Return true if all verts are in the face.
+ */
bool BM_verts_in_face(BMVert **varr, int len, BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Returns whether or not a given edge is part of a given face.
+ */
bool BM_edge_in_face(const BMEdge *e, const BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BLI_INLINE bool BM_edge_in_loop(const BMEdge *e, const BMLoop *l) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
@@ -35,27 +48,175 @@ BLI_INLINE bool BM_verts_in_edge(const BMVert *v1,
const BMVert *v2,
const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Returns edge length
+ */
float BM_edge_calc_length(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Returns edge length squared (for comparisons)
+ */
float BM_edge_calc_length_squared(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Utility function, since enough times we have an edge
+ * and want to access 2 connected faces.
+ *
+ * \return true when only 2 faces are found.
+ */
bool BM_edge_face_pair(BMEdge *e, BMFace **r_fa, BMFace **r_fb) ATTR_NONNULL();
+/**
+ * Utility function, since enough times we have an edge
+ * and want to access 2 connected loops.
+ *
+ * \return true when only 2 faces are found.
+ */
bool BM_edge_loop_pair(BMEdge *e, BMLoop **r_la, BMLoop **r_lb) ATTR_NONNULL();
BLI_INLINE BMVert *BM_edge_other_vert(BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Given a edge and a loop (assumes the edge is manifold). returns
+ * the other faces loop, sharing the same vertex.
+ *
+ * <pre>
+ * +-------------------+
+ * | |
+ * | |
+ * |l_other <-- return |
+ * +-------------------+ <-- A manifold edge between 2 faces
+ * |l e <-- edge |
+ * |^ <-------- loop |
+ * | |
+ * +-------------------+
+ * </pre>
+ */
BMLoop *BM_edge_other_loop(BMEdge *e, BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * \brief Other Loop in Face Sharing an Edge
+ *
+ * Finds the other loop that shares \a v with \a e loop in \a f.
+ * <pre>
+ * +----------+
+ * | |
+ * | f |
+ * | |
+ * +----------+ <-- return the face loop of this vertex.
+ * v --> e
+ * ^ ^ <------- These vert args define direction
+ * in the face to check.
+ * The faces loop direction is ignored.
+ * </pre>
+ *
+ * \note caller must ensure \a e is used in \a f
+ */
BMLoop *BM_face_other_edge_loop(BMFace *f, BMEdge *e, BMVert *v) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * See #BM_face_other_edge_loop This is the same functionality
+ * to be used when the edges loop is already known.
+ */
BMLoop *BM_loop_other_edge_loop(BMLoop *l, BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * \brief Other Loop in Face Sharing a Vertex
+ *
+ * Finds the other loop in a face.
+ *
+ * This function returns a loop in \a f that shares an edge with \a v
+ * The direction is defined by \a v_prev, where the return value is
+ * the loop of what would be 'v_next'
+ * <pre>
+ * +----------+ <-- return the face loop of this vertex.
+ * | |
+ * | f |
+ * | |
+ * +----------+
+ * v_prev --> v
+ * ^^^^^^ ^ <-- These vert args define direction
+ * in the face to check.
+ * The faces loop direction is ignored.
+ * </pre>
+ *
+ * \note \a v_prev and \a v _implicitly_ define an edge.
+ */
BMLoop *BM_face_other_vert_loop(BMFace *f, BMVert *v_prev, BMVert *v) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Return the other loop that uses this edge.
+ *
+ * In this case the loop defines the vertex,
+ * the edge passed in defines the direction to step.
+ *
+ * <pre>
+ * +----------+ <-- Return the face-loop of this vertex.
+ * | |
+ * | e | <-- This edge defines the direction.
+ * | |
+ * +----------+ <-- This loop defines the face and vertex..
+ * l
+ * </pre>
+ *
+ */
BMLoop *BM_loop_other_vert_loop_by_edge(BMLoop *l, BMEdge *e) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * \brief Other Loop in Face Sharing a Vert
+ *
+ * Finds the other loop that shares \a v with \a e loop in \a f.
+ * <pre>
+ * +----------+ <-- return the face loop of this vertex.
+ * | |
+ * | |
+ * | |
+ * +----------+ <-- This vertex defines the direction.
+ * l v
+ * ^ <------- This loop defines both the face to search
+ * and the edge, in combination with 'v'
+ * The faces loop direction is ignored.
+ * </pre>
+ */
BMLoop *BM_loop_other_vert_loop(BMLoop *l, BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Utility function to step around a fan of loops,
+ * using an edge to mark the previous side.
+ *
+ * \note all edges must be manifold,
+ * once a non manifold edge is hit, return NULL.
+ *
+ * \code{.unparsed}
+ * ,.,-->|
+ * _,-' |
+ * ,' | (notice how 'e_step'
+ * / | and 'l' define the
+ * / | direction the arrow
+ * | return | points).
+ * | loop --> |
+ * ---------------------+---------------------
+ * ^ l --> |
+ * | |
+ * assign e_step |
+ * |
+ * begin e_step ----> |
+ * |
+ * \endcode
+ */
BMLoop *BM_vert_step_fan_loop(BMLoop *l, BMEdge **e_step) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Get the first loop of a vert. Uses the same initialization code for the first loop of the
+ * iterator API
+ */
BMLoop *BM_vert_find_first_loop(BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * A version of #BM_vert_find_first_loop that ignores hidden loops.
+ */
BMLoop *BM_vert_find_first_loop_visible(BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Only #BMEdge.l access us needed, however when we want the first visible loop,
+ * a utility function is needed.
+ */
BMLoop *BM_edge_find_first_loop_visible(BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Check if verts share a face.
+ */
bool BM_vert_pair_share_face_check(BMVert *v_a, BMVert *v_b) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
bool BM_vert_pair_share_face_check_cb(BMVert *v_a,
@@ -70,11 +231,21 @@ BMFace *BM_vert_pair_shared_face_cb(BMVert *v_a,
void *user_data,
BMLoop **r_l_a,
BMLoop **r_l_b) ATTR_NONNULL(1, 2, 4, 6, 7);
+/**
+ * Given 2 verts, find the smallest face they share and give back both loops.
+ */
BMFace *BM_vert_pair_share_face_by_len(BMVert *v_a,
BMVert *v_b,
BMLoop **r_l_a,
BMLoop **r_l_b,
const bool allow_adjacent) ATTR_NONNULL();
+/**
+ * Given 2 verts,
+ * find a face they share that has the lowest angle across these verts and give back both loops.
+ *
+ * This can be better than #BM_vert_pair_share_face_by_len
+ * because concave splits are ranked lowest.
+ */
BMFace *BM_vert_pair_share_face_by_angle(BMVert *v_a,
BMVert *v_b,
BMLoop **r_l_a,
@@ -92,57 +263,169 @@ int BM_vert_edge_count_nonwire(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NON
#define BM_vert_edge_count_is_over(v, n) (BM_vert_edge_count_at_most(v, (n) + 1) == (n) + 1)
int BM_vert_edge_count_at_most(const BMVert *v, const int count_max) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Returns the number of edges around this vertex.
+ */
int BM_vert_edge_count(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
#define BM_edge_face_count_is_equal(e, n) (BM_edge_face_count_at_most(e, (n) + 1) == n)
#define BM_edge_face_count_is_over(e, n) (BM_edge_face_count_at_most(e, (n) + 1) == (n) + 1)
int BM_edge_face_count_at_most(const BMEdge *e, const int count_max) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Returns the number of faces around this edge
+ */
int BM_edge_face_count(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
#define BM_vert_face_count_is_equal(v, n) (BM_vert_face_count_at_most(v, (n) + 1) == n)
#define BM_vert_face_count_is_over(v, n) (BM_vert_face_count_at_most(v, (n) + 1) == (n) + 1)
int BM_vert_face_count_at_most(const BMVert *v, int count_max) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Returns the number of faces around this vert
+ * length matches #BM_LOOPS_OF_VERT iterator
+ */
int BM_vert_face_count(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * The function takes a vertex at the center of a fan and returns the opposite edge in the fan.
+ * All edges in the fan must be manifold, otherwise return NULL.
+ *
+ * \note This could (probably) be done more efficiently.
+ */
BMEdge *BM_vert_other_disk_edge(BMVert *v, BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Fast alternative to `(BM_vert_edge_count(v) == 2)`.
+ */
bool BM_vert_is_edge_pair(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Fast alternative to `(BM_vert_edge_count(v) == 2)`
+ * that checks both edges connect to the same faces.
+ */
bool BM_vert_is_edge_pair_manifold(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Access a verts 2 connected edges.
+ *
+ * \return true when only 2 verts are found.
+ */
bool BM_vert_edge_pair(BMVert *v, BMEdge **r_e_a, BMEdge **r_e_b);
+/**
+ * Return true if the vertex is connected to _any_ faces.
+ *
+ * same as `BM_vert_face_count(v) != 0` or `BM_vert_find_first_loop(v) == NULL`.
+ */
bool BM_vert_face_check(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Tests whether or not the vertex is part of a wire edge.
+ * (ie: has no faces attached to it)
+ */
bool BM_vert_is_wire(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BLI_INLINE bool BM_edge_is_wire(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * A vertex is non-manifold if it meets the following conditions:
+ * 1: Loose - (has no edges/faces incident upon it).
+ * 2: Joins two distinct regions - (two pyramids joined at the tip).
+ * 3: Is part of an edge with more than 2 faces.
+ * 4: Is part of a wire edge.
+ */
bool BM_vert_is_manifold(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * A version of #BM_vert_is_manifold
+ * which only checks if we're connected to multiple isolated regions.
+ */
bool BM_vert_is_manifold_region(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BLI_INLINE bool BM_edge_is_manifold(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BM_vert_is_boundary(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BLI_INLINE bool BM_edge_is_boundary(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BLI_INLINE bool BM_edge_is_contiguous(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Check if the edge is convex or concave
+ * (depends on face winding)
+ */
bool BM_edge_is_convex(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * \return true when loop customdata is contiguous.
+ */
bool BM_edge_is_contiguous_loop_cd(const BMEdge *e,
const int cd_loop_type,
const int cd_loop_offset) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * The number of loops connected to this loop (not including disconnected regions).
+ */
int BM_loop_region_loops_count_at_most(BMLoop *l, int *r_loop_total) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1);
int BM_loop_region_loops_count(BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Check if the loop is convex or concave
+ * (depends on face normal)
+ */
bool BM_loop_is_convex(const BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BLI_INLINE bool BM_loop_is_adjacent(const BMLoop *l_a, const BMLoop *l_b) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Check if a point is inside the corner defined by a loop
+ * (within the 2 planes defined by the loops corner & face normal).
+ *
+ * \return signed, squared distance to the loops planes, less than 0.0 when outside.
+ */
float BM_loop_point_side_of_loop_test(const BMLoop *l, const float co[3]) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Check if a point is inside the edge defined by a loop
+ * (within the plane defined by the loops edge & face normal).
+ *
+ * \return signed, squared distance to the edge plane, less than 0.0 when outside.
+ */
float BM_loop_point_side_of_edge_test(const BMLoop *l, const float co[3]) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * \return The previous loop, over \a eps_sq distance from \a l (or \a NULL if l_stop is reached).
+ */
BMLoop *BM_loop_find_prev_nodouble(BMLoop *l, BMLoop *l_stop, const float eps_sq);
+/**
+ * \return The next loop, over \a eps_sq distance from \a l (or \a NULL if l_stop is reached).
+ */
BMLoop *BM_loop_find_next_nodouble(BMLoop *l, BMLoop *l_stop, const float eps_sq);
+/**
+ * Calculates the angle between the previous and next loops
+ * (angle at this loops face corner).
+ *
+ * \return angle in radians
+ */
float BM_loop_calc_face_angle(const BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * \brief BM_loop_calc_face_normal
+ *
+ * Calculate the normal at this loop corner or fallback to the face normal on straight lines.
+ *
+ * \param l: The loop to calculate the normal at
+ * \param r_normal: Resulting normal
+ * \return The length of the cross product (double the area).
+ */
float BM_loop_calc_face_normal(const BMLoop *l, float r_normal[3]) ATTR_NONNULL();
+/**
+ * #BM_loop_calc_face_normal_safe_ex with predefined sane epsilon.
+ *
+ * Since this doesn't scale based on triangle size, fixed value works well.
+ */
float BM_loop_calc_face_normal_safe(const BMLoop *l, float r_normal[3]) ATTR_NONNULL();
-float BM_loop_calc_face_normal_safe_ex(const BMLoop *l, const float epsilon, float r_normal[3])
+/**
+ * \brief BM_loop_calc_face_normal
+ *
+ * Calculate the normal at this loop corner or fallback to the face normal on straight lines.
+ *
+ * \param l: The loop to calculate the normal at.
+ * \param epsilon_sq: Value to avoid numeric errors (1e-5f works well).
+ * \param r_normal: Resulting normal.
+ */
+float BM_loop_calc_face_normal_safe_ex(const BMLoop *l, const float epsilon_sq, float r_normal[3])
ATTR_NONNULL();
+/**
+ * A version of BM_loop_calc_face_normal_safe_ex which takes vertex coordinates.
+ */
float BM_loop_calc_face_normal_safe_vcos_ex(const BMLoop *l,
const float normal_fallback[3],
float const (*vertexCos)[3],
@@ -153,15 +436,56 @@ float BM_loop_calc_face_normal_safe_vcos(const BMLoop *l,
float const (*vertexCos)[3],
float r_normal[3]) ATTR_NONNULL();
+/**
+ * \brief BM_loop_calc_face_direction
+ *
+ * Calculate the direction a loop is pointing.
+ *
+ * \param l: The loop to calculate the direction at
+ * \param r_dir: Resulting direction
+ */
void BM_loop_calc_face_direction(const BMLoop *l, float r_dir[3]);
+/**
+ * \brief BM_loop_calc_face_tangent
+ *
+ * Calculate the tangent at this loop corner or fallback to the face normal on straight lines.
+ * This vector always points inward into the face.
+ *
+ * \param l: The loop to calculate the tangent at
+ * \param r_tangent: Resulting tangent
+ */
void BM_loop_calc_face_tangent(const BMLoop *l, float r_tangent[3]);
+/**
+ * \brief BMESH EDGE/FACE ANGLE
+ *
+ * Calculates the angle between two faces.
+ * Assumes the face normals are correct.
+ *
+ * \return angle in radians
+ */
float BM_edge_calc_face_angle_ex(const BMEdge *e, const float fallback) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
float BM_edge_calc_face_angle(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * \brief BMESH EDGE/FACE ANGLE
+ *
+ * Calculates the angle between two faces.
+ * Assumes the face normals are correct.
+ *
+ * \return angle in radians
+ */
float BM_edge_calc_face_angle_signed_ex(const BMEdge *e,
const float fallback) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * \brief BMESH EDGE/FACE ANGLE
+ *
+ * Calculates the angle between two faces in world space.
+ * Assumes the face normals are correct.
+ *
+ * \return angle in radians
+ */
float BM_edge_calc_face_angle_with_imat3_ex(const BMEdge *e,
const float imat3[3][3],
const float fallback) ATTR_WARN_UNUSED_RESULT
@@ -170,55 +494,210 @@ float BM_edge_calc_face_angle_with_imat3(const BMEdge *e,
const float imat3[3][3]) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
float BM_edge_calc_face_angle_signed(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * \brief BMESH EDGE/FACE TANGENT
+ *
+ * Calculate the tangent at this loop corner or fallback to the face normal on straight lines.
+ * This vector always points inward into the face.
+ *
+ * \brief BM_edge_calc_face_tangent
+ * \param e:
+ * \param e_loop: The loop to calculate the tangent at,
+ * used to get the face and winding direction.
+ * \param r_tangent: The loop corner tangent to set
+ */
void BM_edge_calc_face_tangent(const BMEdge *e, const BMLoop *e_loop, float r_tangent[3])
ATTR_NONNULL();
float BM_vert_calc_edge_angle(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * \brief BMESH VERT/EDGE ANGLE
+ *
+ * Calculates the angle a verts 2 edges.
+ *
+ * \returns the angle in radians
+ */
float BM_vert_calc_edge_angle_ex(const BMVert *v, const float fallback) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * \note this isn't optimal to run on an array of verts,
+ * see 'solidify_add_thickness' for a function which runs on an array.
+ */
float BM_vert_calc_shell_factor(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/* alternate version of #BM_vert_calc_shell_factor which only
+ * uses 'hflag' faces, but falls back to all if none found. */
float BM_vert_calc_shell_factor_ex(const BMVert *v,
const float no[3],
const char hflag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * \note quite an obscure function.
+ * used in bmesh operators that have a relative scale options,
+ */
float BM_vert_calc_median_tagged_edge_length(const BMVert *v) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Returns the loop of the shortest edge in f.
+ */
BMLoop *BM_face_find_shortest_loop(BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Returns the loop of the longest edge in f.
+ */
BMLoop *BM_face_find_longest_loop(BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BMEdge *BM_edge_exists(BMVert *v_a, BMVert *v_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Returns an edge sharing the same vertices as this one.
+ * This isn't an invalid state but tools should clean up these cases before
+ * returning the mesh to the user.
+ */
BMEdge *BM_edge_find_double(BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Given a set of vertices (varr), find out if
+ * there is a face with exactly those vertices
+ * (and only those vertices).
+ *
+ * \note there used to be a BM_face_exists_overlap function that checks for partial overlap.
+ */
BMFace *BM_face_exists(BMVert **varr, int len) ATTR_NONNULL(1);
+/**
+ * Check if the face has an exact duplicate (both winding directions).
+ */
BMFace *BM_face_find_double(BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Given a set of vertices and edges (\a varr, \a earr), find out if
+ * all those vertices are filled in by existing faces that _only_ use those vertices.
+ *
+ * This is for use in cases where creating a face is possible but would result in
+ * many overlapping faces.
+ *
+ * An example of how this is used: when 2 tri's are selected that share an edge,
+ * pressing Fkey would make a new overlapping quad (without a check like this)
+ *
+ * \a earr and \a varr can be in any order, however they _must_ form a closed loop.
+ */
bool BM_face_exists_multi(BMVert **varr, BMEdge **earr, int len) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/* same as 'BM_face_exists_multi' but built vert array from edges */
bool BM_face_exists_multi_edge(BMEdge **earr, int len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Given a set of vertices (varr), find out if
+ * all those vertices overlap an existing face.
+ *
+ * \note The face may contain other verts \b not in \a varr.
+ *
+ * \note Its possible there are more than one overlapping faces,
+ * in this case the first one found will be returned.
+ *
+ * \param varr: Array of unordered verts.
+ * \param len: \a varr array length.
+ * \return The face or NULL.
+ */
BMFace *BM_face_exists_overlap(BMVert **varr, const int len) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Given a set of vertices (varr), find out if
+ * there is a face that uses vertices only from this list
+ * (that the face is a subset or made from the vertices given).
+ *
+ * \param varr: Array of unordered verts.
+ * \param len: varr array length.
+ */
bool BM_face_exists_overlap_subset(BMVert **varr, const int len) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Returns the number of faces that are adjacent to both f1 and f2,
+ * \note Could be sped up a bit by not using iterators and by tagging
+ * faces on either side, then count the tags rather then searching.
+ */
int BM_face_share_face_count(BMFace *f_a, BMFace *f_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Counts the number of edges two faces share (if any)
+ */
int BM_face_share_edge_count(BMFace *f_a, BMFace *f_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Counts the number of verts two faces share (if any).
+ */
int BM_face_share_vert_count(BMFace *f_a, BMFace *f_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * same as #BM_face_share_face_count but returns a bool
+ */
bool BM_face_share_face_check(BMFace *f_a, BMFace *f_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Returns true if the faces share an edge
+ */
bool BM_face_share_edge_check(BMFace *f_a, BMFace *f_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Returns true if the faces share a vert.
+ */
bool BM_face_share_vert_check(BMFace *f_a, BMFace *f_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Returns true when 2 loops share an edge (are adjacent in the face-fan)
+ */
bool BM_loop_share_edge_check(BMLoop *l_a, BMLoop *l_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Test if e1 shares any faces with e2
+ */
bool BM_edge_share_face_check(BMEdge *e1, BMEdge *e2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Test if e1 shares any quad faces with e2
+ */
bool BM_edge_share_quad_check(BMEdge *e1, BMEdge *e2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Tests to see if e1 shares a vertex with e2
+ */
bool BM_edge_share_vert_check(BMEdge *e1, BMEdge *e2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Return the shared vertex between the two edges or NULL
+ */
BMVert *BM_edge_share_vert(BMEdge *e1, BMEdge *e2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * \brief Return the Loop Shared by Edge and Vert
+ *
+ * Finds the loop used which uses \a in face loop \a l
+ *
+ * \note this function takes a loop rather than an edge
+ * so we can select the face that the loop should be from.
+ */
BMLoop *BM_edge_vert_share_loop(BMLoop *l, BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * \brief Return the Loop Shared by Face and Vertex
+ *
+ * Finds the loop used which uses \a v in face loop \a l
+ *
+ * \note currently this just uses simple loop in future may be sped up
+ * using radial vars
+ */
BMLoop *BM_face_vert_share_loop(BMFace *f, BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * \brief Return the Loop Shared by Face and Edge
+ *
+ * Finds the loop used which uses \a e in face loop \a l
+ *
+ * \note currently this just uses simple loop in future may be sped up
+ * using radial vars
+ */
BMLoop *BM_face_edge_share_loop(BMFace *f, BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
void BM_edge_ordered_verts(const BMEdge *edge, BMVert **r_v1, BMVert **r_v2) ATTR_NONNULL();
+/**
+ * Returns the verts of an edge as used in a face
+ * if used in a face at all, otherwise just assign as used in the edge.
+ *
+ * Useful to get a deterministic winding order when calling
+ * BM_face_create_ngon() on an arbitrary array of verts,
+ * though be sure to pick an edge which has a face.
+ *
+ * \note This is in fact quite a simple check,
+ * mainly include this function so the intent is more obvious.
+ * We know these 2 verts will _always_ make up the loops edge
+ */
void BM_edge_ordered_verts_ex(const BMEdge *edge,
BMVert **r_v1,
BMVert **r_v2,
@@ -234,6 +713,7 @@ bool BM_edge_is_all_face_flag_test(const BMEdge *e,
const char hflag,
const bool respect_hide) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/* convenience functions for checking flags */
bool BM_edge_is_any_vert_flag_test(const BMEdge *e, const char hflag) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
bool BM_edge_is_any_face_flag_test(const BMEdge *e, const char hflag) ATTR_WARN_UNUSED_RESULT
@@ -246,10 +726,29 @@ bool BM_face_is_any_edge_flag_test(const BMFace *f, const char hflag) ATTR_WARN_
bool BM_edge_is_any_face_len_test(const BMEdge *e, const int len) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Use within assert's to check normals are valid.
+ */
bool BM_face_is_normal_valid(const BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
double BM_mesh_calc_volume(BMesh *bm, bool is_signed) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Calculate isolated groups of faces with optional filtering.
+ *
+ * \param bm: the BMesh.
+ * \param r_groups_array: Array of ints to fill in, length of bm->totface
+ * (or when hflag_test is set, the number of flagged faces).
+ * \param r_group_index: index, length pairs into \a r_groups_array, size of return value
+ * int pairs: (array_start, array_length).
+ * \param filter_fn: Filter the edge-loops or vert-loops we step over (depends on \a htype_step).
+ * \param user_data: Optional user data for \a filter_fn, can be NULL.
+ * \param hflag_test: Optional flag to test faces,
+ * use to exclude faces from the calculation, 0 for all faces.
+ * \param htype_step: BM_VERT to walk over face-verts, BM_EDGE to walk over faces edges
+ * (having both set is supported too).
+ * \return The number of groups found.
+ */
int BM_mesh_calc_face_groups(BMesh *bm,
int *r_groups_array,
int (**r_group_index)[2],
@@ -258,6 +757,24 @@ int BM_mesh_calc_face_groups(BMesh *bm,
void *user_data,
const char hflag_test,
const char htype_step) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3);
+/**
+ * Calculate isolated groups of edges with optional filtering.
+ *
+ * \param bm: the BMesh.
+ * \param r_groups_array: Array of ints to fill in, length of `bm->totedge`
+ * (or when hflag_test is set, the number of flagged edges).
+ * \param r_group_index: index, length pairs into \a r_groups_array, size of return value
+ * int pairs: (array_start, array_length).
+ * \param filter_fn: Filter the edges or verts we step over (depends on \a htype_step)
+ * as to which types we deal with.
+ * \param user_data: Optional user data for \a filter_fn, can be NULL.
+ * \param hflag_test: Optional flag to test edges,
+ * use to exclude edges from the calculation, 0 for all edges.
+ * \return The number of groups found.
+ *
+ * \note Unlike #BM_mesh_calc_face_groups there is no 'htype_step' argument,
+ * since we always walk over verts.
+ */
int BM_mesh_calc_edge_groups(BMesh *bm,
int *r_groups_array,
int (**r_group_index)[2],
@@ -265,6 +782,13 @@ int BM_mesh_calc_edge_groups(BMesh *bm,
void *user_data,
const char hflag_test) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3);
+/**
+ * This is an alternative to #BM_mesh_calc_edge_groups.
+ *
+ * While we could call this, then create vertex & face arrays,
+ * it requires looping over geometry connectivity twice,
+ * this slows down edit-mesh separate by loose parts, see: T70864.
+ */
int BM_mesh_calc_edge_groups_as_arrays(BMesh *bm,
BMVert **verts,
BMEdge **edges,
diff --git a/source/blender/bmesh/intern/bmesh_query_uv.c b/source/blender/bmesh/intern/bmesh_query_uv.c
index f9b87e4e71c..f069613f5b3 100644
--- a/source/blender/bmesh/intern/bmesh_query_uv.c
+++ b/source/blender/bmesh/intern/bmesh_query_uv.c
@@ -48,14 +48,6 @@ static void uv_aspect(const BMLoop *l,
*/
#define UV_ASPECT(l, r_uv) uv_aspect(l, aspect, cd_loop_uv_offset, r_uv)
-/**
- * Computes the UV center of a face, using the mean average weighted by edge length.
- *
- * See #BM_face_calc_center_median_weighted for matching spatial functionality.
- *
- * \param aspect: Calculate the center scaling by these values, and finally dividing.
- * Since correct weighting depends on having the correct aspect.
- */
void BM_face_uv_calc_center_median_weighted(const BMFace *f,
const float aspect[2],
const int cd_loop_uv_offset,
@@ -109,9 +101,6 @@ void BM_face_uv_calc_center_median(const BMFace *f, const int cd_loop_uv_offset,
mul_v2_fl(r_cent, 1.0f / (float)f->len);
}
-/**
- * Calculate the UV cross product (use the sign to check the winding).
- */
float BM_face_uv_calc_cross(const BMFace *f, const int cd_loop_uv_offset)
{
float(*uvs)[2] = BLI_array_alloca(uvs, f->len);
@@ -148,9 +137,6 @@ void BM_face_uv_transform(BMFace *f, const float matrix[2][2], const int cd_loop
} while ((l_iter = l_iter->next) != l_first);
}
-/**
- * Check if two loops that share an edge also have the same UV coordinates.
- */
bool BM_loop_uv_share_edge_check(BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_offset)
{
BLI_assert(l_a->e == l_b->e);
@@ -165,9 +151,6 @@ bool BM_loop_uv_share_edge_check(BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_
equals_v2v2(luv_a_next->uv, luv_b_next->uv));
}
-/**
- * Check if two loops that share a vertex also have the same UV coordinates.
- */
bool BM_loop_uv_share_vert_check(BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_offset)
{
BLI_assert(l_a->v == l_b->v);
@@ -179,9 +162,6 @@ bool BM_loop_uv_share_vert_check(BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_
return true;
}
-/**
- * Check if two loops that share a vertex also have the same UV coordinates.
- */
bool BM_edge_uv_share_vert_check(BMEdge *e, BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_offset)
{
BLI_assert(l_a->v == l_b->v);
@@ -204,9 +184,6 @@ bool BM_edge_uv_share_vert_check(BMEdge *e, BMLoop *l_a, BMLoop *l_b, const int
return true;
}
-/**
- * Check if the point is inside the UV face.
- */
bool BM_face_uv_point_inside_test(const BMFace *f, const float co[2], const int cd_loop_uv_offset)
{
float(*projverts)[2] = BLI_array_alloca(projverts, f->len);
diff --git a/source/blender/bmesh/intern/bmesh_query_uv.h b/source/blender/bmesh/intern/bmesh_query_uv.h
index 850b27d3894..d63b8e5e701 100644
--- a/source/blender/bmesh/intern/bmesh_query_uv.h
+++ b/source/blender/bmesh/intern/bmesh_query_uv.h
@@ -27,6 +27,14 @@ float BM_loop_uv_calc_edge_length(const BMLoop *l,
const int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Computes the UV center of a face, using the mean average weighted by edge length.
+ *
+ * See #BM_face_calc_center_median_weighted for matching spatial functionality.
+ *
+ * \param aspect: Calculate the center scaling by these values, and finally dividing.
+ * Since correct weighting depends on having the correct aspect.
+ */
void BM_face_uv_calc_center_median_weighted(const BMFace *f,
const float aspect[2],
const int cd_loop_uv_offset,
@@ -34,6 +42,9 @@ void BM_face_uv_calc_center_median_weighted(const BMFace *f,
void BM_face_uv_calc_center_median(const BMFace *f, const int cd_loop_uv_offset, float r_cent[2])
ATTR_NONNULL();
+/**
+ * Calculate the UV cross product (use the sign to check the winding).
+ */
float BM_face_uv_calc_cross(const BMFace *f, const int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
@@ -46,19 +57,31 @@ bool BM_loop_uv_share_edge_check_with_limit(BMLoop *l_a,
const int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Check if two loops that share an edge also have the same UV coordinates.
+ */
bool BM_loop_uv_share_edge_check(BMLoop *l_a,
BMLoop *l_b,
const int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Check if two loops that share a vertex also have the same UV coordinates.
+ */
bool BM_edge_uv_share_vert_check(BMEdge *e, BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_offset)
ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Check if two loops that share a vertex also have the same UV coordinates.
+ */
bool BM_loop_uv_share_vert_check(BMLoop *l_a,
BMLoop *l_b,
const int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Check if the point is inside the UV face.
+ */
bool BM_face_uv_point_inside_test(const BMFace *f,
const float co[2],
const int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
diff --git a/source/blender/bmesh/intern/bmesh_structure.c b/source/blender/bmesh/intern/bmesh_structure.c
index 1f1ad0bae5b..08b0920c115 100644
--- a/source/blender/bmesh/intern/bmesh_structure.c
+++ b/source/blender/bmesh/intern/bmesh_structure.c
@@ -47,11 +47,6 @@ void bmesh_disk_vert_swap(BMEdge *e, BMVert *v_dst, BMVert *v_src)
}
}
-/**
- * Handles all connected data, use with care.
- *
- * Assumes caller has setup correct state before the swap is done.
- */
void bmesh_edge_vert_swap(BMEdge *e, BMVert *v_dst, BMVert *v_src)
{
/* swap out loops */
@@ -268,14 +263,6 @@ bool bmesh_disk_validate(int len, BMEdge *e, BMVert *v)
return true;
}
-/**
- * \brief DISK COUNT FACE VERT
- *
- * Counts the number of loop users
- * for this vertex. Note that this is
- * equivalent to counting the number of
- * faces incident upon this vertex
- */
int bmesh_disk_facevert_count(const BMVert *v)
{
/* is there an edge on this vert at all */
@@ -315,14 +302,6 @@ int bmesh_disk_facevert_count_at_most(const BMVert *v, const int count_max)
return count;
}
-/**
- * \brief FIND FIRST FACE EDGE
- *
- * Finds the first edge in a vertices
- * Disk cycle that has one of this
- * vert's loops attached
- * to it.
- */
BMEdge *bmesh_disk_faceedge_find_first(const BMEdge *e, const BMVert *v)
{
const BMEdge *e_iter = e;
@@ -334,11 +313,6 @@ BMEdge *bmesh_disk_faceedge_find_first(const BMEdge *e, const BMVert *v)
return NULL;
}
-/**
- * Special case for BM_LOOPS_OF_VERT & BM_FACES_OF_VERT, avoids 2x calls.
- *
- * The returned BMLoop.e matches the result of #bmesh_disk_faceedge_find_first
- */
BMLoop *bmesh_disk_faceloop_find_first(const BMEdge *e, const BMVert *v)
{
const BMEdge *e_iter = e;
@@ -350,9 +324,6 @@ BMLoop *bmesh_disk_faceloop_find_first(const BMEdge *e, const BMVert *v)
return NULL;
}
-/**
- * A version of #bmesh_disk_faceloop_find_first that ignores hidden faces.
- */
BMLoop *bmesh_disk_faceloop_find_first_visible(const BMEdge *e, const BMVert *v)
{
const BMEdge *e_iter = e;
@@ -384,7 +355,6 @@ BMEdge *bmesh_disk_faceedge_find_next(const BMEdge *e, const BMVert *v)
return (BMEdge *)e;
}
-/*****radial cycle functions, e.g. loops surrounding edges**** */
bool bmesh_radial_validate(int radlen, BMLoop *l)
{
BMLoop *l_iter = l;
@@ -442,14 +412,6 @@ void bmesh_radial_loop_append(BMEdge *e, BMLoop *l)
l->e = e;
}
-/**
- * \brief BMESH RADIAL REMOVE LOOP
- *
- * Removes a loop from an radial cycle. If edge e is non-NULL
- * it should contain the radial cycle, and it will also get
- * updated (in the case that the edge's link into the radial
- * cycle was the loop which is being removed from the cycle).
- */
void bmesh_radial_loop_remove(BMEdge *e, BMLoop *l)
{
/* if e is non-NULL, l must be in the radial cycle of e */
@@ -480,10 +442,6 @@ void bmesh_radial_loop_remove(BMEdge *e, BMLoop *l)
l->e = NULL;
}
-/**
- * A version of #bmesh_radial_loop_remove which only performs the radial unlink,
- * leaving the edge untouched.
- */
void bmesh_radial_loop_unlink(BMLoop *l)
{
if (l->radial_next != l) {
@@ -497,12 +455,6 @@ void bmesh_radial_loop_unlink(BMLoop *l)
l->e = NULL;
}
-/**
- * \brief BME RADIAL FIND FIRST FACE VERT
- *
- * Finds the first loop of v around radial
- * cycle
- */
BMLoop *bmesh_radial_faceloop_find_first(const BMLoop *l, const BMVert *v)
{
const BMLoop *l_iter;
@@ -553,12 +505,6 @@ int bmesh_radial_length(const BMLoop *l)
return i;
}
-/**
- * \brief RADIAL COUNT FACE VERT
- *
- * Returns the number of times a vertex appears
- * in a radial cycle
- */
int bmesh_radial_facevert_count(const BMLoop *l, const BMVert *v)
{
const BMLoop *l_iter;
@@ -590,11 +536,6 @@ int bmesh_radial_facevert_count_at_most(const BMLoop *l, const BMVert *v, const
return count;
}
-/**
- * \brief RADIAL CHECK FACE VERT
- *
- * Quicker check for `bmesh_radial_facevert_count(...) != 0`.
- */
bool bmesh_radial_facevert_check(const BMLoop *l, const BMVert *v)
{
const BMLoop *l_iter;
@@ -608,7 +549,6 @@ bool bmesh_radial_facevert_check(const BMLoop *l, const BMVert *v)
return false;
}
-/*****loop cycle functions, e.g. loops surrounding a face**** */
bool bmesh_loop_validate(BMFace *f)
{
int i;
diff --git a/source/blender/bmesh/intern/bmesh_structure.h b/source/blender/bmesh/intern/bmesh_structure.h
index ca51a9c39de..e2e26a69d44 100644
--- a/source/blender/bmesh/intern/bmesh_structure.h
+++ b/source/blender/bmesh/intern/bmesh_structure.h
@@ -31,6 +31,7 @@
*/
/* LOOP CYCLE MANAGEMENT */
+/*****loop cycle functions, e.g. loops surrounding a face**** */
bool bmesh_loop_validate(BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/* DISK CYCLE MANAGEMENT */
@@ -48,11 +49,35 @@ BLI_INLINE BMEdge *bmesh_disk_edge_prev(const BMEdge *e, const BMVert *v) ATTR_W
ATTR_NONNULL();
int bmesh_disk_facevert_count_at_most(const BMVert *v, const int count_max) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * \brief DISK COUNT FACE VERT
+ *
+ * Counts the number of loop users
+ * for this vertex. Note that this is
+ * equivalent to counting the number of
+ * faces incident upon this vertex
+ */
int bmesh_disk_facevert_count(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * \brief FIND FIRST FACE EDGE
+ *
+ * Finds the first edge in a vertices
+ * Disk cycle that has one of this
+ * vert's loops attached
+ * to it.
+ */
BMEdge *bmesh_disk_faceedge_find_first(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Special case for BM_LOOPS_OF_VERT & BM_FACES_OF_VERT, avoids 2x calls.
+ *
+ * The returned BMLoop.e matches the result of #bmesh_disk_faceedge_find_first
+ */
BMLoop *bmesh_disk_faceloop_find_first(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * A version of #bmesh_disk_faceloop_find_first that ignores hidden faces.
+ */
BMLoop *bmesh_disk_faceloop_find_first_visible(const BMEdge *e,
const BMVert *v) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
@@ -61,7 +86,19 @@ BMEdge *bmesh_disk_faceedge_find_next(const BMEdge *e, const BMVert *v) ATTR_WAR
/* RADIAL CYCLE MANAGEMENT */
void bmesh_radial_loop_append(BMEdge *e, BMLoop *l) ATTR_NONNULL();
+/**
+ * \brief BMESH RADIAL REMOVE LOOP
+ *
+ * Removes a loop from an radial cycle. If edge e is non-NULL
+ * it should contain the radial cycle, and it will also get
+ * updated (in the case that the edge's link into the radial
+ * cycle was the loop which is being removed from the cycle).
+ */
void bmesh_radial_loop_remove(BMEdge *e, BMLoop *l) ATTR_NONNULL();
+/**
+ * A version of #bmesh_radial_loop_remove which only performs the radial unlink,
+ * leaving the edge untouched.
+ */
void bmesh_radial_loop_unlink(BMLoop *l) ATTR_NONNULL();
/* NOTE:
* bmesh_radial_loop_next(BMLoop *l) / prev.
@@ -71,20 +108,43 @@ int bmesh_radial_facevert_count_at_most(const BMLoop *l,
const BMVert *v,
const int count_max) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * \brief RADIAL COUNT FACE VERT
+ *
+ * Returns the number of times a vertex appears
+ * in a radial cycle
+ */
int bmesh_radial_facevert_count(const BMLoop *l, const BMVert *v) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * \brief RADIAL CHECK FACE VERT
+ *
+ * Quicker check for `bmesh_radial_facevert_count(...) != 0`.
+ */
bool bmesh_radial_facevert_check(const BMLoop *l, const BMVert *v) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * \brief BME RADIAL FIND FIRST FACE VERT
+ *
+ * Finds the first loop of v around radial
+ * cycle
+ */
BMLoop *bmesh_radial_faceloop_find_first(const BMLoop *l, const BMVert *v) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
BMLoop *bmesh_radial_faceloop_find_next(const BMLoop *l, const BMVert *v) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
BMLoop *bmesh_radial_faceloop_find_vert(const BMFace *f, const BMVert *v) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/*****radial cycle functions, e.g. loops surrounding edges**** */
bool bmesh_radial_validate(int radlen, BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/* EDGE UTILITIES */
void bmesh_disk_vert_swap(BMEdge *e, BMVert *v_dst, BMVert *v_src) ATTR_NONNULL();
+/**
+ * Handles all connected data, use with care.
+ *
+ * Assumes caller has setup correct state before the swap is done.
+ */
void bmesh_edge_vert_swap(BMEdge *e, BMVert *v_dst, BMVert *v_src) ATTR_NONNULL();
void bmesh_disk_vert_replace(BMEdge *e, BMVert *v_dst, BMVert *v_src) ATTR_NONNULL();
BMEdge *bmesh_disk_edge_exists(const BMVert *v1, const BMVert *v2) ATTR_WARN_UNUSED_RESULT
diff --git a/source/blender/bmesh/intern/bmesh_walkers.c b/source/blender/bmesh/intern/bmesh_walkers.c
index b8fdd534842..e1f7430bc53 100644
--- a/source/blender/bmesh/intern/bmesh_walkers.c
+++ b/source/blender/bmesh/intern/bmesh_walkers.c
@@ -60,12 +60,6 @@ void *BMW_begin(BMWalker *walker, void *start)
return BMW_current_state(walker) ? walker->step(walker) : NULL;
}
-/**
- * \brief Init Walker
- *
- * Allocates and returns a new mesh walker of a given type.
- * The elements visited are filtered by the bitmask 'searchmask'.
- */
void BMW_init(BMWalker *walker,
BMesh *bm,
int type,
@@ -124,11 +118,6 @@ void BMW_init(BMWalker *walker,
BLI_listbase_clear(&walker->states);
}
-/**
- * \brief End Walker
- *
- * Frees a walker's worklist.
- */
void BMW_end(BMWalker *walker)
{
BLI_mempool_destroy(walker->worklist);
@@ -136,9 +125,6 @@ void BMW_end(BMWalker *walker)
BLI_gset_free(walker->visit_set_alt, NULL);
}
-/**
- * \brief Step Walker
- */
void *BMW_step(BMWalker *walker)
{
BMHeader *head;
@@ -148,22 +134,11 @@ void *BMW_step(BMWalker *walker)
return head;
}
-/**
- * \brief Walker Current Depth
- *
- * Returns the current depth of the walker.
- */
-
int BMW_current_depth(BMWalker *walker)
{
return walker->depth;
}
-/**
- * \brief Main Walking Function
- *
- * Steps a mesh walker forward by one element
- */
void *BMW_walk(BMWalker *walker)
{
void *current = NULL;
@@ -177,13 +152,6 @@ void *BMW_walk(BMWalker *walker)
return NULL;
}
-/**
- * \brief Current Walker State
- *
- * Returns the first state from the walker state
- * worklist. This state is the next in the
- * worklist for processing.
- */
void *BMW_current_state(BMWalker *walker)
{
BMwGenericWalker *currentstate = walker->states.first;
@@ -203,12 +171,6 @@ void *BMW_current_state(BMWalker *walker)
return currentstate;
}
-/**
- * \brief Remove Current Walker State
- *
- * Remove and free an item from the end of the walker state
- * worklist.
- */
void BMW_state_remove(BMWalker *walker)
{
void *oldstate;
@@ -217,15 +179,6 @@ void BMW_state_remove(BMWalker *walker)
BLI_mempool_free(walker->worklist, oldstate);
}
-/**
- * \brief Add a new Walker State
- *
- * Allocate a new empty state and put it on the worklist.
- * A pointer to the new state is returned so that the caller
- * can fill in the state data. The new state will be inserted
- * at the front for depth-first walks, and at the end for
- * breadth-first walks.
- */
void *BMW_state_add(BMWalker *walker)
{
BMwGenericWalker *newstate;
@@ -245,12 +198,6 @@ void *BMW_state_add(BMWalker *walker)
return newstate;
}
-/**
- * \brief Reset Walker
- *
- * Frees all states from the worklist, resetting the walker
- * for reuse in a new walk.
- */
void BMW_reset(BMWalker *walker)
{
while (BMW_current_state(walker)) {
diff --git a/source/blender/bmesh/intern/bmesh_walkers.h b/source/blender/bmesh/intern/bmesh_walkers.h
index d0348aa11dc..f36f77ce009 100644
--- a/source/blender/bmesh/intern/bmesh_walkers.h
+++ b/source/blender/bmesh/intern/bmesh_walkers.h
@@ -67,6 +67,12 @@ typedef struct BMWalker {
/* define to make BMW_init more clear */
#define BMW_MASK_NOP 0
+/**
+ * \brief Init Walker
+ *
+ * Allocates and returns a new mesh walker of a given type.
+ * The elements visited are filtered by the bitmask 'searchmask'.
+ */
void BMW_init(struct BMWalker *walker,
BMesh *bm,
int type,
@@ -76,15 +82,61 @@ void BMW_init(struct BMWalker *walker,
BMWFlag flag,
int layer);
void *BMW_begin(BMWalker *walker, void *start);
+/**
+ * \brief Step Walker
+ */
void *BMW_step(struct BMWalker *walker);
+/**
+ * \brief End Walker
+ *
+ * Frees a walker's worklist.
+ */
void BMW_end(struct BMWalker *walker);
+/**
+ * \brief Walker Current Depth
+ *
+ * Returns the current depth of the walker.
+ */
int BMW_current_depth(BMWalker *walker);
/* These are used by custom walkers. */
+/**
+ * \brief Current Walker State
+ *
+ * Returns the first state from the walker state
+ * worklist. This state is the next in the
+ * worklist for processing.
+ */
void *BMW_current_state(BMWalker *walker);
+/**
+ * \brief Add a new Walker State
+ *
+ * Allocate a new empty state and put it on the worklist.
+ * A pointer to the new state is returned so that the caller
+ * can fill in the state data. The new state will be inserted
+ * at the front for depth-first walks, and at the end for
+ * breadth-first walks.
+ */
void *BMW_state_add(BMWalker *walker);
+/**
+ * \brief Remove Current Walker State
+ *
+ * Remove and free an item from the end of the walker state
+ * worklist.
+ */
void BMW_state_remove(BMWalker *walker);
+/**
+ * \brief Main Walking Function
+ *
+ * Steps a mesh walker forward by one element
+ */
void *BMW_walk(BMWalker *walker);
+/**
+ * \brief Reset Walker
+ *
+ * Frees all states from the worklist, resetting the walker
+ * for reuse in a new walk.
+ */
void BMW_reset(BMWalker *walker);
#define BMW_ITER(ele, walker, data) \
diff --git a/source/blender/bmesh/intern/bmesh_walkers_impl.c b/source/blender/bmesh/intern/bmesh_walkers_impl.c
index 7931e953295..15d3a6a6a53 100644
--- a/source/blender/bmesh/intern/bmesh_walkers_impl.c
+++ b/source/blender/bmesh/intern/bmesh_walkers_impl.c
@@ -94,6 +94,7 @@ static bool bmw_edge_is_wire(const BMWalker *walker, const BMEdge *e)
}
return BM_edge_is_wire(e);
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -107,6 +108,7 @@ static bool bmw_edge_is_wire(const BMWalker *walker, const BMEdge *e)
*
* \todo Add restriction flag/callback for wire edges.
* \{ */
+
static void bmw_VertShellWalker_visitEdge(BMWalker *walker, BMEdge *e)
{
BMwShellWalker *shellWalk = NULL;
@@ -236,6 +238,7 @@ static void *bmw_VertShellWalker_step(BMWalker *walker)
*
* \note this is mainly useful to loop over a shell delimited by edges.
* \{ */
+
static void bmw_LoopShellWalker_visitLoop(BMWalker *walker, BMLoop *l)
{
BMwLoopShellWalker *shellWalk = NULL;
@@ -509,6 +512,7 @@ static void *bmw_LoopShellWireWalker_step(BMWalker *walker)
* Starts at an edge on the mesh and walks over the 'shell' it belongs
* to via visiting connected faces.
* \{ */
+
static void bmw_FaceShellWalker_visitEdge(BMWalker *walker, BMEdge *e)
{
BMwShellWalker *shellWalk = NULL;
@@ -564,6 +568,7 @@ static void *bmw_FaceShellWalker_step(BMWalker *walker)
return e;
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -573,6 +578,7 @@ static void *bmw_FaceShellWalker_step(BMWalker *walker)
*
* Walk from a vertex to all connected vertices.
* \{ */
+
static void bmw_ConnectedVertexWalker_visitVertex(BMWalker *walker, BMVert *v)
{
BMwConnectedVertexWalker *vwalk;
@@ -640,6 +646,7 @@ static void *bmw_ConnectedVertexWalker_step(BMWalker *walker)
*
* \todo Add restriction flag/callback for wire edges.
* \{ */
+
static void bmw_IslandboundWalker_begin(BMWalker *walker, void *data)
{
BMLoop *l = data;
@@ -735,6 +742,7 @@ static void *bmw_IslandboundWalker_step(BMWalker *walker)
*
* \todo Add restriction flag/callback for wire edges.
* \{ */
+
static void bmw_IslandWalker_begin(BMWalker *walker, void *data)
{
BMwIslandWalker *iwalk = NULL;
@@ -1299,6 +1307,7 @@ static void *bmw_FaceLoopWalker_step(BMWalker *walker)
* Conditions for starting and stepping the edge ring have been
* tuned to match behavior users expect (dating back to v2.4x).
* \{ */
+
static void bmw_EdgeringWalker_begin(BMWalker *walker, void *data)
{
BMwEdgeringWalker *lwalk, owalk, *owalk_pt;
@@ -1850,6 +1859,12 @@ static BMWalker bmw_ConnectedVertexWalker_Type = {
BM_VERT, /* Valid restrict masks. */
};
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name All Walker Types
+ * \{ */
+
BMWalker *bm_walker_types[] = {
&bmw_VertShellWalker_Type, /* #BMW_VERT_SHELL */
&bmw_LoopShellWalker_Type, /* #BMW_LOOP_SHELL */
@@ -1868,3 +1883,5 @@ BMWalker *bm_walker_types[] = {
};
const int bm_totwalkers = ARRAY_SIZE(bm_walker_types);
+
+/** \} */
diff --git a/source/blender/bmesh/operators/bmo_connect_pair.c b/source/blender/bmesh/operators/bmo_connect_pair.c
index 660633e8a0f..29fd8d9094b 100644
--- a/source/blender/bmesh/operators/bmo_connect_pair.c
+++ b/source/blender/bmesh/operators/bmo_connect_pair.c
@@ -120,19 +120,18 @@ typedef struct PathLinkState {
float co_prev[3];
} PathLinkState;
-/**
- * \name Min Dist Dir Util
+/* -------------------------------------------------------------------- */
+/** \name Min Dist Dir Util
*
* Simply getting the closest intersecting vert/edge is _not_ good enough. see T43792
* we need to get the closest in both directions since the absolute closest may be a dead-end.
*
* Logic is simple:
*
- * - first intersection, store the direction.
- * - successive intersections will update the first distance if its aligned with the first hit.
+ * - First intersection, store the direction.
+ * - Successive intersections will update the first distance if its aligned with the first hit.
* otherwise update the opposite distance.
- * - caller stores best outcome in both directions.
- *
+ * - Caller stores best outcome in both directions.
* \{ */
typedef struct MinDistDir {
diff --git a/source/blender/bmesh/operators/bmo_create.c b/source/blender/bmesh/operators/bmo_create.c
index a740e4d66e8..c337724d096 100644
--- a/source/blender/bmesh/operators/bmo_create.c
+++ b/source/blender/bmesh/operators/bmo_create.c
@@ -31,12 +31,11 @@
#define ELE_NEW 1
#define ELE_OUT 2
-/* This is what runs when pressing the F key
- * doing the best thing here isn't always easy create vs dissolve, its nice to support
- * but it _really_ gives issues we might have to not call dissolve. - campbell
- */
void bmo_contextual_create_exec(BMesh *bm, BMOperator *op)
{
+ /* NOTE(@campbellbarton): doing the best thing here isn't always easy create vs dissolve,
+ * its nice to support but it _really_ gives issues we might have to not call dissolve. */
+
BMOIter oiter;
BMHeader *h;
int totv = 0, tote = 0, totf = 0;
diff --git a/source/blender/bmesh/operators/bmo_dissolve.c b/source/blender/bmesh/operators/bmo_dissolve.c
index 360dcc2c79e..82d277ec3af 100644
--- a/source/blender/bmesh/operators/bmo_dissolve.c
+++ b/source/blender/bmesh/operators/bmo_dissolve.c
@@ -488,7 +488,6 @@ void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op)
/* done with cleanup */
}
-/* Limited Dissolve */
void bmo_dissolve_limit_exec(BMesh *bm, BMOperator *op)
{
BMOpSlot *einput = BMO_slot_get(op->slots_in, "edges");
diff --git a/source/blender/bmesh/operators/bmo_primitive.c b/source/blender/bmesh/operators/bmo_primitive.c
index d8047499780..69404c8ba0e 100644
--- a/source/blender/bmesh/operators/bmo_primitive.c
+++ b/source/blender/bmesh/operators/bmo_primitive.c
@@ -787,14 +787,6 @@ void bmo_create_grid_exec(BMesh *bm, BMOperator *op)
}
}
-/**
- * Fills first available UV-map with grid-like UV's for all faces with `oflag` set.
- *
- * \param bm: The BMesh to operate on
- * \param x_segments: The x-resolution of the grid
- * \param y_segments: The y-resolution of the grid
- * \param oflag: The flag to check faces with.
- */
void BM_mesh_calc_uvs_grid(BMesh *bm,
const uint x_segments,
const uint y_segments,
@@ -1130,12 +1122,6 @@ static void bm_mesh_calc_uvs_sphere_face(BMFace *f, const int cd_loop_uv_offset)
}
}
-/**
- * Fills first available UV-map with spherical projected UVs for all faces with `oflag` set.
- *
- * \param bm: The BMesh to operate on
- * \param oflag: The flag to check faces with.
- */
void BM_mesh_calc_uvs_sphere(BMesh *bm, const short oflag, const int cd_loop_uv_offset)
{
BMFace *f;
@@ -1343,14 +1329,6 @@ void bmo_create_circle_exec(BMesh *bm, BMOperator *op)
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK);
}
-/**
- * Fills first available UV-map with 2D projected UVs for all faces with `oflag` set.
- *
- * \param bm: The BMesh to operate on.
- * \param mat: The transform matrix applied to the created circle.
- * \param radius: The size of the circle.
- * \param oflag: The flag to check faces with.
- */
void BM_mesh_calc_uvs_circle(
BMesh *bm, float mat[4][4], const float radius, const short oflag, const int cd_loop_uv_offset)
{
@@ -1534,17 +1512,6 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op)
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK);
}
-/**
- * Fills first available UV-map with cylinder/cone-like UVs for all faces with `oflag` set.
- *
- * \param bm: The BMesh to operate on.
- * \param mat: The transform matrix applied to the created cone/cylinder.
- * \param radius_top: The size of the top end of the cone/cylinder.
- * \param radius_bottom: The size of the bottom end of the cone/cylinder.
- * \param segments: The number of subdivisions in the sides of the cone/cylinder.
- * \param cap_ends: Whether the ends of the cone/cylinder are filled or not.
- * \param oflag: The flag to check faces with.
- */
void BM_mesh_calc_uvs_cone(BMesh *bm,
float mat[4][4],
const float radius_top,
@@ -1710,15 +1677,6 @@ void bmo_create_cube_exec(BMesh *bm, BMOperator *op)
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK);
}
-/**
- * Fills first available UV-map with cube-like UVs for all faces with `oflag` set.
- *
- * \note Expects tagged faces to be six quads.
- * \note Caller must order faces for correct alignment.
- *
- * \param bm: The BMesh to operate on.
- * \param oflag: The flag to check faces with.
- */
void BM_mesh_calc_uvs_cube(BMesh *bm, const short oflag)
{
BMFace *f;
diff --git a/source/blender/bmesh/operators/bmo_split_edges.c b/source/blender/bmesh/operators/bmo_split_edges.c
index d030a6e11b0..5a00094ef45 100644
--- a/source/blender/bmesh/operators/bmo_split_edges.c
+++ b/source/blender/bmesh/operators/bmo_split_edges.c
@@ -27,7 +27,6 @@
#include "intern/bmesh_operators_private.h" /* own include */
-/* keep this operator fast, its used in a modifier */
void bmo_split_edges_exec(BMesh *bm, BMOperator *op)
{
const bool use_verts = BMO_slot_bool_get(op->slots_in, "use_verts");
diff --git a/source/blender/bmesh/operators/bmo_subdivide.c b/source/blender/bmesh/operators/bmo_subdivide.c
index 7311c94a0d8..05837ae2a0e 100644
--- a/source/blender/bmesh/operators/bmo_subdivide.c
+++ b/source/blender/bmesh/operators/bmo_subdivide.c
@@ -1187,12 +1187,14 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op)
vlen = BLI_array_len(loops);
/* find the boundary of one of the split edges */
- for (a = 1; a < vlen; a++) {
- if (!BMO_vert_flag_test(bm, loops[a - 1]->v, ELE_INNER) &&
+ for (a = 0; a < vlen; a++) {
+ if (!BMO_vert_flag_test(bm, loops[a ? (a - 1) : (vlen - 1)]->v, ELE_INNER) &&
BMO_vert_flag_test(bm, loops[a]->v, ELE_INNER)) {
break;
}
}
+ /* Failure to break means there is an internal error. */
+ BLI_assert(a < vlen);
if (BMO_vert_flag_test(bm, loops[(a + numcuts + 1) % vlen]->v, ELE_INNER)) {
b = (a + numcuts + 1) % vlen;
diff --git a/source/blender/bmesh/operators/bmo_subdivide_edgering.c b/source/blender/bmesh/operators/bmo_subdivide_edgering.c
index 6a80f360f59..7f0bfc5e2c9 100644
--- a/source/blender/bmesh/operators/bmo_subdivide_edgering.c
+++ b/source/blender/bmesh/operators/bmo_subdivide_edgering.c
@@ -1061,9 +1061,10 @@ static bool bm_edge_rim_test_cb(BMEdge *e, void *bm_v)
return BMO_edge_flag_test_bool(bm, e, EDGE_RIM);
}
-/* keep this operator fast, its used in a modifier */
void bmo_subdivide_edgering_exec(BMesh *bm, BMOperator *op)
{
+ /* NOTE: keep this operator fast, its used in a modifier. */
+
ListBase eloops_rim = {NULL};
BMOIter siter;
BMEdge *e;
diff --git a/source/blender/bmesh/operators/bmo_unsubdivide.c b/source/blender/bmesh/operators/bmo_unsubdivide.c
index c5de6df34a7..f11e359e962 100644
--- a/source/blender/bmesh/operators/bmo_unsubdivide.c
+++ b/source/blender/bmesh/operators/bmo_unsubdivide.c
@@ -29,11 +29,10 @@
#include "intern/bmesh_operators_private.h" /* own include */
-/* - BMVert.flag & BM_ELEM_TAG: shows we touched this vert
- * - BMVert.index == -1: shows we will remove this vert
- */
void bmo_unsubdivide_exec(BMesh *bm, BMOperator *op)
{
+ /* - `BMVert.flag & BM_ELEM_TAG`: Shows we touched this vert.
+ * - `BMVert.index == -1`: Shows we will remove this vert. */
BMVert *v;
BMIter iter;
diff --git a/source/blender/bmesh/tools/bmesh_beautify.c b/source/blender/bmesh/tools/bmesh_beautify.c
index d5c5063f2cb..b7cf9c88282 100644
--- a/source/blender/bmesh/tools/bmesh_beautify.c
+++ b/source/blender/bmesh/tools/bmesh_beautify.c
@@ -235,12 +235,6 @@ static float bm_edge_calc_rotate_beauty__angle(const float v1[3],
return FLT_MAX;
}
-/**
- * Assuming we have 2 triangles sharing an edge (2 - 4),
- * check if the edge running from (1 - 3) gives better results.
- *
- * \return (negative number means the edge can be rotated, lager == better).
- */
float BM_verts_calc_rotate_beauty(const BMVert *v1,
const BMVert *v2,
const BMVert *v3,
@@ -374,9 +368,6 @@ static void bm_edge_update_beauty_cost(BMEdge *e,
/* -------------------------------------------------------------------- */
/* Beautify Fill */
-/**
- * \note This function sets the edge indices to invalid values.
- */
void BM_mesh_beautify_fill(BMesh *bm,
BMEdge **edge_array,
const int edge_array_len,
diff --git a/source/blender/bmesh/tools/bmesh_beautify.h b/source/blender/bmesh/tools/bmesh_beautify.h
index d0fef828e7c..2e7950118c1 100644
--- a/source/blender/bmesh/tools/bmesh_beautify.h
+++ b/source/blender/bmesh/tools/bmesh_beautify.h
@@ -27,6 +27,9 @@ enum {
EDGE_RESTRICT_DEGENERATE = (1 << 1),
};
+/**
+ * \note This function sets the edge indices to invalid values.
+ */
void BM_mesh_beautify_fill(BMesh *bm,
BMEdge **edge_array,
const int edge_array_len,
@@ -35,6 +38,12 @@ void BM_mesh_beautify_fill(BMesh *bm,
const short oflag_edge,
const short oflag_face);
+/**
+ * Assuming we have 2 triangles sharing an edge (2 - 4),
+ * check if the edge running from (1 - 3) gives better results.
+ *
+ * \return (negative number means the edge can be rotated, lager == better).
+ */
float BM_verts_calc_rotate_beauty(const BMVert *v1,
const BMVert *v2,
const BMVert *v3,
diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c
index 6cf3641fed2..2f471bf0b81 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.c
+++ b/source/blender/bmesh/tools/bmesh_bevel.c
@@ -7443,18 +7443,6 @@ static void bevel_limit_offset(BevelParams *bp, BMesh *bm)
}
}
-/**
- * - Currently only bevels BM_ELEM_TAG'd verts and edges.
- *
- * - Newly created faces, edges, and verts are BM_ELEM_TAG'd too,
- * the caller needs to ensure these are cleared before calling
- * if its going to use this tag.
- *
- * - If limit_offset is set, adjusts offset down if necessary
- * to avoid geometry collisions.
- *
- * \warning all tagged edges _must_ be manifold.
- */
void BM_mesh_bevel(BMesh *bm,
const float offset,
const int offset_type,
diff --git a/source/blender/bmesh/tools/bmesh_bevel.h b/source/blender/bmesh/tools/bmesh_bevel.h
index de57e1c62a9..03c10ee9f80 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.h
+++ b/source/blender/bmesh/tools/bmesh_bevel.h
@@ -23,6 +23,18 @@
struct CurveProfile;
struct MDeformVert;
+/**
+ * - Currently only bevels BM_ELEM_TAG'd verts and edges.
+ *
+ * - Newly created faces, edges, and verts are BM_ELEM_TAG'd too,
+ * the caller needs to ensure these are cleared before calling
+ * if its going to use this tag.
+ *
+ * - If limit_offset is set, adjusts offset down if necessary
+ * to avoid geometry collisions.
+ *
+ * \warning all tagged edges _must_ be manifold.
+ */
void BM_mesh_bevel(BMesh *bm,
const float offset,
const int offset_type,
diff --git a/source/blender/bmesh/tools/bmesh_bisect_plane.c b/source/blender/bmesh/tools/bmesh_bisect_plane.c
index 8f03b86b859..d220b183b8d 100644
--- a/source/blender/bmesh/tools/bmesh_bisect_plane.c
+++ b/source/blender/bmesh/tools/bmesh_bisect_plane.c
@@ -88,7 +88,7 @@ static short plane_point_test_v3(const float plane[4],
*
* Hide flag access
* (for more readable code since same flag is used differently for vert/edge-face).
- */
+ * \{ */
/** Enable when vertex is in the center and its faces have been added to the stack. */
BLI_INLINE void vert_is_center_enable(BMVert *v)
@@ -411,11 +411,6 @@ finally:
/** \name Public BMesh Bisect Function
* \{ */
-/**
- * \param use_snap_center: Snap verts onto the plane.
- * \param use_tag: Only bisect tagged edges and faces.
- * \param oflag_center: Operator flag, enabled for geometry on the axis (existing and created)
- */
void BM_mesh_bisect_plane(BMesh *bm,
const float plane[4],
const bool use_snap_center,
diff --git a/source/blender/bmesh/tools/bmesh_bisect_plane.h b/source/blender/bmesh/tools/bmesh_bisect_plane.h
index f64b5d8097c..120935296b7 100644
--- a/source/blender/bmesh/tools/bmesh_bisect_plane.h
+++ b/source/blender/bmesh/tools/bmesh_bisect_plane.h
@@ -20,6 +20,11 @@
* \ingroup bmesh
*/
+/**
+ * \param use_snap_center: Snap verts onto the plane.
+ * \param use_tag: Only bisect tagged edges and faces.
+ * \param oflag_center: Operator flag, enabled for geometry on the axis (existing and created)
+ */
void BM_mesh_bisect_plane(BMesh *bm,
const float plane[4],
const bool use_snap_center,
diff --git a/source/blender/bmesh/tools/bmesh_boolean.cc b/source/blender/bmesh/tools/bmesh_boolean.cc
index 487ef6427af..e244bc377db 100644
--- a/source/blender/bmesh/tools/bmesh_boolean.cc
+++ b/source/blender/bmesh/tools/bmesh_boolean.cc
@@ -456,14 +456,6 @@ bool BM_mesh_boolean(BMesh *bm,
static_cast<blender::meshintersect::BoolOpType>(boolean_mode));
}
-/**
- * Perform a Knife Intersection operation on the mesh bm.
- * There are either one or two operands, the same as described above for BM_mesh_boolean().
- * If use_separate_all is true, each edge that is created from the intersection should
- * be used to separate all its incident faces. TODO: implement that.
- * TODO: need to ensure that "selected/non-selected" flag of original faces gets propagated
- * to the intersection result faces.
- */
bool BM_mesh_boolean_knife(BMesh *bm,
struct BMLoop *(*looptris)[3],
const int looptris_tot,
diff --git a/source/blender/bmesh/tools/bmesh_boolean.h b/source/blender/bmesh/tools/bmesh_boolean.h
index ed77242e14c..4dacc7b1095 100644
--- a/source/blender/bmesh/tools/bmesh_boolean.h
+++ b/source/blender/bmesh/tools/bmesh_boolean.h
@@ -35,6 +35,16 @@ bool BM_mesh_boolean(BMesh *bm,
const bool hole_tolerant,
const int boolean_mode);
+/**
+ * Perform a Knife Intersection operation on the mesh `bm`.
+ * There are either one or two operands, the same as described above for #BM_mesh_boolean().
+ *
+ * \param use_separate_all: When true, each edge that is created from the intersection should
+ * be used to separate all its incident faces. TODO: implement that.
+ *
+ * TODO: need to ensure that "selected/non-selected" flag of original faces gets propagated
+ * to the intersection result faces.
+ */
bool BM_mesh_boolean_knife(BMesh *bm,
struct BMLoop *(*looptris)[3],
const int looptris_tot,
diff --git a/source/blender/bmesh/tools/bmesh_decimate.h b/source/blender/bmesh/tools/bmesh_decimate.h
index c62288c269a..1de241a1326 100644
--- a/source/blender/bmesh/tools/bmesh_decimate.h
+++ b/source/blender/bmesh/tools/bmesh_decimate.h
@@ -20,6 +20,20 @@
* \ingroup bmesh
*/
+/**
+ * \brief BM_mesh_decimate
+ * \param bm: The mesh
+ * \param factor: face count multiplier [0 - 1]
+ * \param vweights: Optional array of vertex aligned weights [0 - 1],
+ * a vertex group is the usual source for this.
+ * \param symmetry_axis: Axis of symmetry, -1 to disable mirror decimate.
+ * \param symmetry_eps: Threshold when matching mirror verts.
+ *
+ * \note The caller is responsible for recalculating face and vertex normals.
+ * - Vertex normals are maintained while decimating,
+ * although they won't necessarily match the final recalculated normals.
+ * - Face normals are not maintained at all.
+ */
void BM_mesh_decimate_collapse(BMesh *bm,
const float factor,
float *vweights,
@@ -28,6 +42,8 @@ void BM_mesh_decimate_collapse(BMesh *bm,
const int symmetry_axis,
const float symmetry_eps);
+/**
+ * \param tag_only: so we can call this from an operator */
void BM_mesh_decimate_unsubdivide_ex(BMesh *bm, const int iterations, const bool tag_only);
void BM_mesh_decimate_unsubdivide(BMesh *bm, const int iterations);
diff --git a/source/blender/bmesh/tools/bmesh_decimate_collapse.c b/source/blender/bmesh/tools/bmesh_decimate_collapse.c
index 97fccbe01fd..e90e50ef8ff 100644
--- a/source/blender/bmesh/tools/bmesh_decimate_collapse.c
+++ b/source/blender/bmesh/tools/bmesh_decimate_collapse.c
@@ -1277,20 +1277,6 @@ static bool bm_decim_edge_collapse(BMesh *bm,
/* Main Decimate Function
* ********************** */
-/**
- * \brief BM_mesh_decimate
- * \param bm: The mesh
- * \param factor: face count multiplier [0 - 1]
- * \param vweights: Optional array of vertex aligned weights [0 - 1],
- * a vertex group is the usual source for this.
- * \param symmetry_axis: Axis of symmetry, -1 to disable mirror decimate.
- * \param symmetry_eps: Threshold when matching mirror verts.
- *
- * \note The caller is responsible for recalculating face and vertex normals.
- * - Vertex normals are maintained while decimating,
- * although they won't necessarily match the final recalculated normals.
- * - Face normals are not maintained at all.
- */
void BM_mesh_decimate_collapse(BMesh *bm,
const float factor,
float *vweights,
diff --git a/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c b/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c
index c96a7be1adf..ca0f31fdf75 100644
--- a/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c
+++ b/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c
@@ -168,8 +168,6 @@ enum {
* - BMVert.index == -1: shows we will remove this vert
*/
-/**
- * \param tag_only: so we can call this from an operator */
void BM_mesh_decimate_unsubdivide_ex(BMesh *bm, const int iterations, const bool tag_only)
{
#ifdef USE_WALKER
diff --git a/source/blender/bmesh/tools/bmesh_edgenet.c b/source/blender/bmesh/tools/bmesh_edgenet.c
index 242b269ed47..4cad1d3cb3c 100644
--- a/source/blender/bmesh/tools/bmesh_edgenet.c
+++ b/source/blender/bmesh/tools/bmesh_edgenet.c
@@ -422,15 +422,6 @@ static LinkNode *bm_edgenet_path_calc_best(BMEdge *e,
return path;
}
-/**
- * Fill in faces from an edgenet made up of boundary and wire edges.
- *
- * \note New faces currently don't have their normals calculated and are flipped randomly.
- * The caller needs to flip faces correctly.
- *
- * \param bm: The mesh to operate on.
- * \param use_edge_tag: Only fill tagged edges.
- */
void BM_mesh_edgenet(BMesh *bm, const bool use_edge_tag, const bool use_new_face_tag)
{
VertNetInfo *vnet_info = MEM_callocN(sizeof(*vnet_info) * (size_t)bm->totvert, __func__);
diff --git a/source/blender/bmesh/tools/bmesh_edgenet.h b/source/blender/bmesh/tools/bmesh_edgenet.h
index 7855b2e2886..20edb30442c 100644
--- a/source/blender/bmesh/tools/bmesh_edgenet.h
+++ b/source/blender/bmesh/tools/bmesh_edgenet.h
@@ -20,4 +20,13 @@
* \ingroup bmesh
*/
+/**
+ * Fill in faces from an edgenet made up of boundary and wire edges.
+ *
+ * \note New faces currently don't have their normals calculated and are flipped randomly.
+ * The caller needs to flip faces correctly.
+ *
+ * \param bm: The mesh to operate on.
+ * \param use_edge_tag: Only fill tagged edges.
+ */
void BM_mesh_edgenet(BMesh *bm, const bool use_edge_tag, const bool use_new_face_tag);
diff --git a/source/blender/bmesh/tools/bmesh_edgesplit.c b/source/blender/bmesh/tools/bmesh_edgesplit.c
index 388e7f41aba..cd5200a660d 100644
--- a/source/blender/bmesh/tools/bmesh_edgesplit.c
+++ b/source/blender/bmesh/tools/bmesh_edgesplit.c
@@ -28,11 +28,6 @@
#include "bmesh_edgesplit.h" /* own include */
-/**
- * \param use_verts: Use flagged verts instead of edges.
- * \param tag_only: Only split tagged edges.
- * \param copy_select: Copy selection history.
- */
void BM_mesh_edgesplit(BMesh *bm,
const bool use_verts,
const bool tag_only,
diff --git a/source/blender/bmesh/tools/bmesh_edgesplit.h b/source/blender/bmesh/tools/bmesh_edgesplit.h
index 4d3db67ef5f..bcbb3ab7857 100644
--- a/source/blender/bmesh/tools/bmesh_edgesplit.h
+++ b/source/blender/bmesh/tools/bmesh_edgesplit.h
@@ -24,6 +24,11 @@
extern "C" {
#endif
+/**
+ * \param use_verts: Use flagged verts instead of edges.
+ * \param tag_only: Only split tagged edges.
+ * \param copy_select: Copy selection history.
+ */
void BM_mesh_edgesplit(BMesh *bm,
const bool use_verts,
const bool tag_only,
diff --git a/source/blender/bmesh/tools/bmesh_intersect.c b/source/blender/bmesh/tools/bmesh_intersect.c
index 947442c7bd8..6824dd5008a 100644
--- a/source/blender/bmesh/tools/bmesh_intersect.c
+++ b/source/blender/bmesh/tools/bmesh_intersect.c
@@ -947,14 +947,6 @@ static int isect_bvhtree_point_v3(BVHTree *tree, const float **looptris, const f
#endif /* USE_BVH */
-/**
- * Intersect tessellated faces
- * leaving the resulting edges tagged.
- *
- * \param test_fn: Return value: -1: skip, 0: tree_a, 1: tree_b (use_self == false)
- * \param boolean_mode: -1: no-boolean, 0: intersection... see #BMESH_ISECT_BOOLEAN_ISECT.
- * \return true if the mesh is changed (intersections cut or faces removed from boolean).
- */
bool BM_mesh_intersect(BMesh *bm,
struct BMLoop *(*looptris)[3],
const int looptris_tot,
diff --git a/source/blender/bmesh/tools/bmesh_intersect.h b/source/blender/bmesh/tools/bmesh_intersect.h
index d09ea67a3bb..a6c91715f31 100644
--- a/source/blender/bmesh/tools/bmesh_intersect.h
+++ b/source/blender/bmesh/tools/bmesh_intersect.h
@@ -24,6 +24,14 @@
extern "C" {
#endif
+/**
+ * Intersect tessellated faces
+ * leaving the resulting edges tagged.
+ *
+ * \param test_fn: Return value: -1: skip, 0: tree_a, 1: tree_b (use_self == false)
+ * \param boolean_mode: -1: no-boolean, 0: intersection... see #BMESH_ISECT_BOOLEAN_ISECT.
+ * \return true if the mesh is changed (intersections cut or faces removed from boolean).
+ */
bool BM_mesh_intersect(BMesh *bm,
struct BMLoop *(*looptris)[3],
const int looptris_tot,
diff --git a/source/blender/bmesh/tools/bmesh_path.c b/source/blender/bmesh/tools/bmesh_path.c
index ea1e7eb1e43..52bb92a6221 100644
--- a/source/blender/bmesh/tools/bmesh_path.c
+++ b/source/blender/bmesh/tools/bmesh_path.c
@@ -580,4 +580,5 @@ LinkNode *BM_mesh_calc_path_face(BMesh *bm,
return path;
}
+
/** \} */
diff --git a/source/blender/bmesh/tools/bmesh_path_uv.c b/source/blender/bmesh/tools/bmesh_path_uv.c
index 30b109d4731..131a8aa0085 100644
--- a/source/blender/bmesh/tools/bmesh_path_uv.c
+++ b/source/blender/bmesh/tools/bmesh_path_uv.c
@@ -198,6 +198,7 @@ struct LinkNode *BM_mesh_calc_path_uv_vert(BMesh *bm,
/* -------------------------------------------------------------------- */
/** \name BM_mesh_calc_path_uv_edge
* \{ */
+
/* TODO(campbell): not very urgent, since the operator fakes this using vertex path. */
/** \} */
diff --git a/source/blender/bmesh/tools/bmesh_region_match.c b/source/blender/bmesh/tools/bmesh_region_match.c
index 924538490ad..2ada18f51e7 100644
--- a/source/blender/bmesh/tools/bmesh_region_match.c
+++ b/source/blender/bmesh/tools/bmesh_region_match.c
@@ -1223,6 +1223,7 @@ static BMEdge *bm_face_region_pivot_edge_find(BMFace **faces_region,
return e_pivot;
}
+
/** \} */
#endif /* USE_PIVOT_SEARCH */
@@ -1332,12 +1333,6 @@ static void bm_vert_fasthash_destroy(UUIDFashMatch *fm)
#endif /* USE_PIVOT_FASTMATCH */
-/**
- * Take a face-region and return a list of matching face-regions.
- *
- * \param faces_region: A single, contiguous face-region.
- * \return A list of matching null-terminated face-region arrays.
- */
int BM_mesh_region_match(BMesh *bm,
BMFace **faces_region,
uint faces_region_len,
diff --git a/source/blender/bmesh/tools/bmesh_region_match.h b/source/blender/bmesh/tools/bmesh_region_match.h
index 799af938c31..7b7233783ce 100644
--- a/source/blender/bmesh/tools/bmesh_region_match.h
+++ b/source/blender/bmesh/tools/bmesh_region_match.h
@@ -20,6 +20,12 @@
* \ingroup bmesh
*/
+/**
+ * Take a face-region and return a list of matching face-regions.
+ *
+ * \param faces_region: A single, contiguous face-region.
+ * \return A list of matching null-terminated face-region arrays.
+ */
int BM_mesh_region_match(BMesh *bm,
BMFace **faces_region,
uint faces_region_len,
diff --git a/source/blender/bmesh/tools/bmesh_separate.c b/source/blender/bmesh/tools/bmesh_separate.c
index 3c69ea111bf..e00829604d5 100644
--- a/source/blender/bmesh/tools/bmesh_separate.c
+++ b/source/blender/bmesh/tools/bmesh_separate.c
@@ -32,10 +32,6 @@
#include "bmesh_separate.h" /* own include */
#include "intern/bmesh_private.h"
-/**
- * Split all faces that match `filter_fn`.
- * \note
- */
void BM_mesh_separate_faces(BMesh *bm, BMFaceFilterFunc filter_fn, void *user_data)
{
BMFace **faces_array_all = MEM_mallocN(bm->totface * sizeof(BMFace *), __func__);
diff --git a/source/blender/bmesh/tools/bmesh_separate.h b/source/blender/bmesh/tools/bmesh_separate.h
index 9260903a8fa..8c599eef2b0 100644
--- a/source/blender/bmesh/tools/bmesh_separate.h
+++ b/source/blender/bmesh/tools/bmesh_separate.h
@@ -20,4 +20,8 @@
* \ingroup bmesh
*/
+/**
+ * Split all faces that match `filter_fn`.
+ * \note
+ */
void BM_mesh_separate_faces(BMesh *bm, BMFaceFilterFunc filter_fn, void *user_data);
diff --git a/source/blender/bmesh/tools/bmesh_wireframe.c b/source/blender/bmesh/tools/bmesh_wireframe.c
index af4a4424103..67010fc89c7 100644
--- a/source/blender/bmesh/tools/bmesh_wireframe.c
+++ b/source/blender/bmesh/tools/bmesh_wireframe.c
@@ -152,12 +152,6 @@ static bool bm_loop_is_radial_boundary(BMLoop *l_first)
return true;
}
-/**
- * \param defgrp_index: Vertex group index, -1 for no vertex groups.
- *
- * \note All edge tags must be cleared.
- * \note Behavior matches MOD_solidify.c
- */
void BM_mesh_wireframe(BMesh *bm,
const float offset,
const float offset_fac,
diff --git a/source/blender/bmesh/tools/bmesh_wireframe.h b/source/blender/bmesh/tools/bmesh_wireframe.h
index b2c2f5f5523..5b64a16435f 100644
--- a/source/blender/bmesh/tools/bmesh_wireframe.h
+++ b/source/blender/bmesh/tools/bmesh_wireframe.h
@@ -22,6 +22,12 @@
#pragma once
+/**
+ * \param defgrp_index: Vertex group index, -1 for no vertex groups.
+ *
+ * \note All edge tags must be cleared.
+ * \note Behavior matches MOD_solidify.c
+ */
void BM_mesh_wireframe(BMesh *bm,
const float offset,
const float offset_fac,
diff --git a/source/blender/compositor/COM_compositor.h b/source/blender/compositor/COM_compositor.h
index 73e66ffeb03..67d189fe5f8 100644
--- a/source/blender/compositor/COM_compositor.h
+++ b/source/blender/compositor/COM_compositor.h
@@ -28,12 +28,19 @@ extern "C" {
/* Keep ascii art. */
/* clang-format off */
/**
+ *
* \defgroup Model The data model of the compositor
+ * \ingroup compositor
* \defgroup Memory The memory management stuff
+ * \ingroup compositor
* \defgroup Execution The execution logic
+ * \ingroup compositor
* \defgroup Conversion Conversion logic
+ * \ingroup compositor
* \defgroup Node All nodes of the compositor
+ * \ingroup compositor
* \defgroup Operation All operations of the compositor
+ * \ingroup compositor
*
* \page Introduction of the Blender Compositor
*
@@ -301,10 +308,10 @@ extern "C" {
* It can be executed during editing (blenkernel/node.cc) or rendering
* (renderer/pipeline.c)
*
- * \param rd: [struct RenderData]
+ * \param render_data: [struct RenderData]
* Render data for this composite, this won't always belong to a scene.
*
- * \param editingtree: [struct bNodeTree]
+ * \param node_tree: [struct bNodeTree]
* reference to the compositor editing tree
*
* \param rendering: [true false]
diff --git a/source/blender/compositor/intern/COM_ConstantFolder.cc b/source/blender/compositor/intern/COM_ConstantFolder.cc
index 2cf3ac001d1..ca5fd9e8274 100644
--- a/source/blender/compositor/intern/COM_ConstantFolder.cc
+++ b/source/blender/compositor/intern/COM_ConstantFolder.cc
@@ -30,10 +30,6 @@ namespace blender::compositor {
using Link = NodeOperationBuilder::Link;
-/**
- * \param operations_builder: Contains all operations to fold.
- * \param exec_system: Execution system.
- */
ConstantFolder::ConstantFolder(NodeOperationBuilder &operations_builder)
: operations_builder_(operations_builder)
{
@@ -135,7 +131,6 @@ Vector<MemoryBuffer *> ConstantFolder::get_constant_input_buffers(NodeOperation
return inputs_bufs;
}
-/** Returns constant operations resulted from folded operations. */
Vector<ConstantOperation *> ConstantFolder::try_fold_operations(Span<NodeOperation *> operations)
{
Set<NodeOperation *> foldable_ops = find_constant_foldable_operations(operations);
@@ -151,9 +146,6 @@ Vector<ConstantOperation *> ConstantFolder::try_fold_operations(Span<NodeOperati
return new_folds;
}
-/**
- * Evaluate operations with constant elements into primitive constant operations.
- */
int ConstantFolder::fold_operations()
{
WorkScheduler::start(operations_builder_.context());
diff --git a/source/blender/compositor/intern/COM_ConstantFolder.h b/source/blender/compositor/intern/COM_ConstantFolder.h
index f31cb4f4e78..972dbf0e125 100644
--- a/source/blender/compositor/intern/COM_ConstantFolder.h
+++ b/source/blender/compositor/intern/COM_ConstantFolder.h
@@ -42,10 +42,18 @@ class ConstantFolder {
rcti first_elem_area_;
public:
+ /**
+ * \param operations_builder: Contains all operations to fold.
+ * \param exec_system: Execution system.
+ */
ConstantFolder(NodeOperationBuilder &operations_builder);
+ /**
+ * Evaluate operations with constant elements into primitive constant operations.
+ */
int fold_operations();
private:
+ /** Returns constant operations resulted from folded operations. */
Vector<ConstantOperation *> try_fold_operations(Span<NodeOperation *> operations);
ConstantOperation *fold_operation(NodeOperation *operation);
diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.cc b/source/blender/compositor/intern/COM_ExecutionGroup.cc
index d2198fc14e8..63ca642d52d 100644
--- a/source/blender/compositor/intern/COM_ExecutionGroup.cc
+++ b/source/blender/compositor/intern/COM_ExecutionGroup.cc
@@ -302,10 +302,6 @@ blender::Array<unsigned int> ExecutionGroup::get_execution_order() const
return chunk_order;
}
-/**
- * this method is called for the top execution groups. containing the compositor node or the
- * preview node or the viewer node)
- */
void ExecutionGroup::execute(ExecutionSystem *graph)
{
const CompositorContext &context = graph->get_context();
diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.h b/source/blender/compositor/intern/COM_ExecutionGroup.h
index ce5e9dd4699..430cde89a3b 100644
--- a/source/blender/compositor/intern/COM_ExecutionGroup.h
+++ b/source/blender/compositor/intern/COM_ExecutionGroup.h
@@ -365,6 +365,10 @@ class ExecutionGroup {
* \see ViewerOperation
* \param graph:
*/
+ /**
+ * This method is called for the top execution groups. containing the compositor node or the
+ * preview node or the viewer node).
+ */
void execute(ExecutionSystem *graph);
/**
diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.cc b/source/blender/compositor/intern/COM_ExecutionSystem.cc
index 82821a1ddb1..038df6ed9df 100644
--- a/source/blender/compositor/intern/COM_ExecutionSystem.cc
+++ b/source/blender/compositor/intern/COM_ExecutionSystem.cc
@@ -118,9 +118,6 @@ void ExecutionSystem::execute()
execution_model_->execute(*this);
}
-/**
- * Multi-threadedly execute given work function passing work_rect splits as argument.
- */
void ExecutionSystem::execute_work(const rcti &work_rect,
std::function<void(const rcti &split_rect)> work_func)
{
diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.h b/source/blender/compositor/intern/COM_ExecutionSystem.h
index 4a3fecaca47..4456ec107fa 100644
--- a/source/blender/compositor/intern/COM_ExecutionSystem.h
+++ b/source/blender/compositor/intern/COM_ExecutionSystem.h
@@ -208,6 +208,9 @@ class ExecutionSystem {
return active_buffers_;
}
+ /**
+ * Multi-threadedly execute given work function passing work_rect splits as argument.
+ */
void execute_work(const rcti &work_rect, std::function<void(const rcti &split_rect)> work_func);
/**
diff --git a/source/blender/compositor/intern/COM_FullFrameExecutionModel.cc b/source/blender/compositor/intern/COM_FullFrameExecutionModel.cc
index 1295437785f..15dbbfde7ed 100644
--- a/source/blender/compositor/intern/COM_FullFrameExecutionModel.cc
+++ b/source/blender/compositor/intern/COM_FullFrameExecutionModel.cc
@@ -73,10 +73,6 @@ void FullFrameExecutionModel::determine_areas_to_render_and_reads()
}
}
-/**
- * Returns input buffers with an offset relative to given output coordinates. Returned memory
- * buffers must be deleted.
- */
Vector<MemoryBuffer *> FullFrameExecutionModel::get_input_buffers(NodeOperation *op,
const int output_x,
const int output_y)
@@ -137,9 +133,6 @@ void FullFrameExecutionModel::render_operation(NodeOperation *op)
operation_finished(op);
}
-/**
- * Render output operations in order of priority.
- */
void FullFrameExecutionModel::render_operations()
{
const bool is_rendering = context_.is_rendering();
@@ -200,9 +193,6 @@ void FullFrameExecutionModel::render_output_dependencies(NodeOperation *output_o
}
}
-/**
- * Determines all operations areas needed to render given output area.
- */
void FullFrameExecutionModel::determine_areas_to_render(NodeOperation *output_op,
const rcti &output_area)
{
@@ -235,10 +225,6 @@ void FullFrameExecutionModel::determine_areas_to_render(NodeOperation *output_op
}
}
-/**
- * Determines reads to receive by operations in output operation tree (i.e: Number of dependent
- * operations each operation has).
- */
void FullFrameExecutionModel::determine_reads(NodeOperation *output_op)
{
BLI_assert(output_op->is_output_operation(context_.is_rendering()));
@@ -258,10 +244,6 @@ void FullFrameExecutionModel::determine_reads(NodeOperation *output_op)
}
}
-/**
- * Calculates given output operation area to be rendered taking into account viewer and render
- * borders.
- */
void FullFrameExecutionModel::get_output_render_area(NodeOperation *output_op, rcti &r_area)
{
BLI_assert(output_op->is_output_operation(context_.is_rendering()));
diff --git a/source/blender/compositor/intern/COM_FullFrameExecutionModel.h b/source/blender/compositor/intern/COM_FullFrameExecutionModel.h
index 36d42886c27..ce724a6b934 100644
--- a/source/blender/compositor/intern/COM_FullFrameExecutionModel.h
+++ b/source/blender/compositor/intern/COM_FullFrameExecutionModel.h
@@ -42,8 +42,8 @@ class SharedOperationBuffers;
class FullFrameExecutionModel : public ExecutionModel {
private:
/**
- * Contains operations active buffers data. Buffers will be disposed once reader operations are
- * finished.
+ * Contains operations active buffers data.
+ * Buffers will be disposed once reader operations are finished.
*/
SharedOperationBuffers &active_buffers_;
@@ -66,8 +66,15 @@ class FullFrameExecutionModel : public ExecutionModel {
private:
void determine_areas_to_render_and_reads();
+ /**
+ * Render output operations in order of priority.
+ */
void render_operations();
void render_output_dependencies(NodeOperation *output_op);
+ /**
+ * Returns input buffers with an offset relative to given output coordinates.
+ * Returned memory buffers must be deleted.
+ */
Vector<MemoryBuffer *> get_input_buffers(NodeOperation *op,
const int output_x,
const int output_y);
@@ -76,8 +83,19 @@ class FullFrameExecutionModel : public ExecutionModel {
void operation_finished(NodeOperation *operation);
+ /**
+ * Calculates given output operation area to be rendered taking into account viewer and render
+ * borders.
+ */
void get_output_render_area(NodeOperation *output_op, rcti &r_area);
+ /**
+ * Determines all operations areas needed to render given output area.
+ */
void determine_areas_to_render(NodeOperation *output_op, const rcti &output_area);
+ /**
+ * Determines reads to receive by operations in output operation tree (i.e: Number of dependent
+ * operations each operation has).
+ */
void determine_reads(NodeOperation *output_op);
void update_progress_bar();
diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.cc b/source/blender/compositor/intern/COM_MemoryBuffer.cc
index 96888ea1c96..ae925f796ee 100644
--- a/source/blender/compositor/intern/COM_MemoryBuffer.cc
+++ b/source/blender/compositor/intern/COM_MemoryBuffer.cc
@@ -74,20 +74,12 @@ MemoryBuffer::MemoryBuffer(DataType data_type, const rcti &rect, bool is_a_singl
set_strides();
}
-/**
- * Construct MemoryBuffer from a float buffer. MemoryBuffer is not responsible for
- * freeing it.
- */
MemoryBuffer::MemoryBuffer(
float *buffer, int num_channels, int width, int height, bool is_a_single_elem)
: MemoryBuffer(buffer, num_channels, create_rect(width, height), is_a_single_elem)
{
}
-/**
- * Construct MemoryBuffer from a float buffer area. MemoryBuffer is not responsible for
- * freeing given buffer.
- */
MemoryBuffer::MemoryBuffer(float *buffer,
const int num_channels,
const rcti &rect,
@@ -145,10 +137,6 @@ BuffersIterator<float> MemoryBuffer::iterate_with(Span<MemoryBuffer *> inputs, c
return builder.build();
}
-/**
- * Converts a single elem buffer to a full size buffer (allocates memory for all
- * elements in resolution).
- */
MemoryBuffer *MemoryBuffer::inflate() const
{
BLI_assert(is_a_single_elem());
diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.h b/source/blender/compositor/intern/COM_MemoryBuffer.h
index 33d78c99ca6..1af047e9ce1 100644
--- a/source/blender/compositor/intern/COM_MemoryBuffer.h
+++ b/source/blender/compositor/intern/COM_MemoryBuffer.h
@@ -132,9 +132,17 @@ class MemoryBuffer {
*/
MemoryBuffer(DataType data_type, const rcti &rect, bool is_a_single_elem = false);
+ /**
+ * Construct MemoryBuffer from a float buffer. MemoryBuffer is not responsible for
+ * freeing it.
+ */
MemoryBuffer(
float *buffer, int num_channels, int width, int height, bool is_a_single_elem = false);
+ /**
+ * Construct MemoryBuffer from a float buffer area. MemoryBuffer is not responsible for
+ * freeing given buffer.
+ */
MemoryBuffer(float *buffer, int num_channels, const rcti &rect, bool is_a_single_elem = false);
/**
@@ -377,6 +385,10 @@ class MemoryBuffer {
return buffer_;
}
+ /**
+ * Converts a single elem buffer to a full size buffer (allocates memory for all
+ * elements in resolution).
+ */
MemoryBuffer *inflate() const;
inline void wrap_pixel(int &x, int &y, MemoryBufferExtend extend_x, MemoryBufferExtend extend_y)
diff --git a/source/blender/compositor/intern/COM_MemoryProxy.cc b/source/blender/compositor/intern/COM_MemoryProxy.cc
index 895990bc87f..6263c47fc9e 100644
--- a/source/blender/compositor/intern/COM_MemoryProxy.cc
+++ b/source/blender/compositor/intern/COM_MemoryProxy.cc
@@ -25,6 +25,7 @@ MemoryProxy::MemoryProxy(DataType datatype)
{
write_buffer_operation_ = nullptr;
executor_ = nullptr;
+ buffer_ = nullptr;
datatype_ = datatype;
}
diff --git a/source/blender/compositor/intern/COM_MetaData.cc b/source/blender/compositor/intern/COM_MetaData.cc
index 530634a6e41..50561975ae4 100644
--- a/source/blender/compositor/intern/COM_MetaData.cc
+++ b/source/blender/compositor/intern/COM_MetaData.cc
@@ -36,10 +36,6 @@ void MetaData::add_cryptomatte_entry(const blender::StringRef layer_name,
add(blender::bke::cryptomatte::BKE_cryptomatte_meta_data_key(layer_name, key), value);
}
-/* Replace the hash neutral cryptomatte keys with hashed versions.
- *
- * When a conversion happens it will also add the cryptomatte name key with the given
- * `layer_name`. */
void MetaData::replace_hash_neutral_cryptomatte_keys(const blender::StringRef layer_name)
{
std::string cryptomatte_hash = entries_.pop_default(META_DATA_KEY_CRYPTOMATTE_HASH, "");
diff --git a/source/blender/compositor/intern/COM_MetaData.h b/source/blender/compositor/intern/COM_MetaData.h
index 0bb014525c3..be47d7c281e 100644
--- a/source/blender/compositor/intern/COM_MetaData.h
+++ b/source/blender/compositor/intern/COM_MetaData.h
@@ -50,6 +50,12 @@ class MetaData {
public:
void add(const blender::StringRef key, const blender::StringRef value);
+ /**
+ * Replace the hash neutral cryptomatte keys with hashed versions.
+ *
+ * When a conversion happens it will also add the cryptomatte name key with the given
+ * `layer_name`.
+ */
void replace_hash_neutral_cryptomatte_keys(const blender::StringRef layer_name);
void add_to_render_result(RenderResult *render_result) const;
#ifdef WITH_CXX_GUARDEDALLOC
diff --git a/source/blender/compositor/intern/COM_NodeOperation.cc b/source/blender/compositor/intern/COM_NodeOperation.cc
index 8a7ae1f4fcb..1f8bc542843 100644
--- a/source/blender/compositor/intern/COM_NodeOperation.cc
+++ b/source/blender/compositor/intern/COM_NodeOperation.cc
@@ -37,14 +37,12 @@ NodeOperation::NodeOperation()
btree_ = nullptr;
}
-/** Get constant value when operation is constant, otherwise return default_value. */
float NodeOperation::get_constant_value_default(float default_value)
{
BLI_assert(outputs_.size() > 0 && get_output_socket()->get_data_type() == DataType::Value);
return *get_constant_elem_default(&default_value);
}
-/** Get constant elem when operation is constant, otherwise return default_elem. */
const float *NodeOperation::get_constant_elem_default(const float *default_elem)
{
BLI_assert(outputs_.size() > 0);
@@ -55,11 +53,6 @@ const float *NodeOperation::get_constant_elem_default(const float *default_elem)
return default_elem;
}
-/**
- * Generate a hash that identifies the operation result in the current execution.
- * Requires `hash_output_params` to be implemented, otherwise `std::nullopt` is returned.
- * If the operation parameters or its linked inputs change, the hash must be re-generated.
- */
std::optional<NodeOperationHash> NodeOperation::generate_hash()
{
params_hash_ = get_default_hash_2(canvas_.xmin, canvas_.xmax);
@@ -150,7 +143,7 @@ void NodeOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
modify_determined_canvas_fn_(r_area);
}
- rcti unused_area;
+ rcti unused_area = COM_AREA_NONE;
const rcti &local_preferred_area = r_area;
for (unsigned int index = 0; index < inputs_.size(); index++) {
if (index == used_canvas_index) {
@@ -213,10 +206,6 @@ const rcti &NodeOperation::get_canvas() const
return canvas_;
}
-/**
- * Mainly used for re-determining canvas of constant operations in cases where preferred canvas
- * depends on the constant element.
- */
void NodeOperation::unset_canvas()
{
BLI_assert(inputs_.size() == 0);
@@ -275,18 +264,6 @@ bool NodeOperation::determine_depending_area_of_interest(rcti *input,
/** \name Full Frame Methods
* \{ */
-/**
- * \brief Get input operation area being read by this operation on rendering given output area.
- *
- * Implementation don't need to ensure r_input_area is within input operation bounds. The
- * caller must clamp it.
- * TODO: See if it's possible to use parameter overloading (input_id for example).
- *
- * \param input_idx: Input operation index for which we want to calculate the area being read.
- * \param output_area: Area being rendered by this operation.
- * \param r_input_area: Returned input operation area that needs to be read in order to render
- * given output area.
- */
void NodeOperation::get_area_of_interest(const int input_idx,
const rcti &output_area,
rcti &r_input_area)
@@ -315,12 +292,6 @@ void NodeOperation::get_area_of_interest(NodeOperation *input_op,
BLI_assert_msg(0, "input_op is not an input operation.");
}
-/**
- * Executes operation image manipulation algorithm rendering given areas.
- * \param output_buf: Buffer to write result to.
- * \param areas: Areas within this operation bounds to render.
- * \param inputs_bufs: Inputs operations buffers.
- */
void NodeOperation::render(MemoryBuffer *output_buf,
Span<rcti> areas,
Span<MemoryBuffer *> inputs_bufs)
@@ -333,9 +304,6 @@ void NodeOperation::render(MemoryBuffer *output_buf,
}
}
-/**
- * Renders given areas using operations full frame implementation.
- */
void NodeOperation::render_full_frame(MemoryBuffer *output_buf,
Span<rcti> areas,
Span<MemoryBuffer *> inputs_bufs)
@@ -347,9 +315,6 @@ void NodeOperation::render_full_frame(MemoryBuffer *output_buf,
deinit_execution();
}
-/**
- * Renders given areas using operations tiled implementation.
- */
void NodeOperation::render_full_frame_fallback(MemoryBuffer *output_buf,
Span<rcti> areas,
Span<MemoryBuffer *> inputs_bufs)
@@ -405,9 +370,6 @@ void NodeOperation::render_tile(MemoryBuffer *output_buf, rcti *tile_rect)
}
}
-/**
- * \return Replaced inputs links.
- */
Vector<NodeOperationOutput *> NodeOperation::replace_inputs_with_buffers(
Span<MemoryBuffer *> inputs_bufs)
{
@@ -461,9 +423,6 @@ SocketReader *NodeOperationInput::get_reader()
return nullptr;
}
-/**
- * \return Whether canvas area could be determined.
- */
bool NodeOperationInput::determine_canvas(const rcti &preferred_area, rcti &r_area)
{
if (link_) {
diff --git a/source/blender/compositor/intern/COM_NodeOperation.h b/source/blender/compositor/intern/COM_NodeOperation.h
index 627fffb1ec7..4412c021517 100644
--- a/source/blender/compositor/intern/COM_NodeOperation.h
+++ b/source/blender/compositor/intern/COM_NodeOperation.h
@@ -134,6 +134,9 @@ class NodeOperationInput {
SocketReader *get_reader();
+ /**
+ * \return Whether canvas area could be determined.
+ */
bool determine_canvas(const rcti &preferred_area, rcti &r_area);
#ifdef WITH_CXX_GUARDEDALLOC
@@ -351,7 +354,7 @@ class NodeOperation {
*/
eExecutionModel execution_model_;
- rcti canvas_;
+ rcti canvas_ = COM_AREA_NONE;
/**
* Flags how to evaluate this operation.
@@ -385,7 +388,9 @@ class NodeOperation {
return id_;
}
+ /** Get constant value when operation is constant, otherwise return default_value. */
float get_constant_value_default(float default_value);
+ /** Get constant elem when operation is constant, otherwise return default_elem. */
const float *get_constant_elem_default(const float *default_elem);
const NodeOperationFlags get_flags() const
@@ -393,6 +398,11 @@ class NodeOperation {
return flags_;
}
+ /**
+ * Generate a hash that identifies the operation result in the current execution.
+ * Requires `hash_output_params` to be implemented, otherwise `std::nullopt` is returned.
+ * If the operation parameters or its linked inputs change, the hash must be re-generated.
+ */
std::optional<NodeOperationHash> generate_hash();
unsigned int get_number_of_input_sockets() const
@@ -511,6 +521,10 @@ class NodeOperation {
void set_canvas(const rcti &canvas_area);
const rcti &get_canvas() const;
+ /**
+ * Mainly used for re-determining canvas of constant operations in cases where preferred canvas
+ * depends on the constant element.
+ */
void unset_canvas();
/**
@@ -618,6 +632,12 @@ class NodeOperation {
/** \name Full Frame Methods
* \{ */
+ /**
+ * Executes operation image manipulation algorithm rendering given areas.
+ * \param output_buf: Buffer to write result to.
+ * \param areas: Areas within this operation bounds to render.
+ * \param inputs_bufs: Inputs operations buffers.
+ */
void render(MemoryBuffer *output_buf, Span<rcti> areas, Span<MemoryBuffer *> inputs_bufs);
/**
@@ -630,7 +650,16 @@ class NodeOperation {
}
/**
- * Get input operation area being read by this operation on rendering given output area.
+ * \brief Get input operation area being read by this operation on rendering given output area.
+ *
+ * Implementation don't need to ensure r_input_area is within input operation bounds.
+ * The caller must clamp it.
+ * TODO: See if it's possible to use parameter overloading (input_id for example).
+ *
+ * \param input_idx: Input operation index for which we want to calculate the area being read.
+ * \param output_area: Area being rendered by this operation.
+ * \param r_input_area: Returned input operation area that needs to be read in order to render
+ * given output area.
*/
virtual void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area);
void get_area_of_interest(NodeOperation *input_op, const rcti &output_area, rcti &r_input_area);
@@ -749,14 +778,23 @@ class NodeOperation {
/** \name Full Frame Methods
* \{ */
+ /**
+ * Renders given areas using operations full frame implementation.
+ */
void render_full_frame(MemoryBuffer *output_buf,
Span<rcti> areas,
Span<MemoryBuffer *> inputs_bufs);
+ /**
+ * Renders given areas using operations tiled implementation.
+ */
void render_full_frame_fallback(MemoryBuffer *output_buf,
Span<rcti> areas,
Span<MemoryBuffer *> inputs);
void render_tile(MemoryBuffer *output_buf, rcti *tile_rect);
+ /**
+ * \return Replaced inputs links.
+ */
Vector<NodeOperationOutput *> replace_inputs_with_buffers(Span<MemoryBuffer *> inputs_bufs);
void remove_buffers_and_restore_original_inputs(
Span<NodeOperationOutput *> original_inputs_links);
diff --git a/source/blender/compositor/intern/COM_NodeOperationBuilder.cc b/source/blender/compositor/intern/COM_NodeOperationBuilder.cc
index 5dc66fea670..2109dd9c582 100644
--- a/source/blender/compositor/intern/COM_NodeOperationBuilder.cc
+++ b/source/blender/compositor/intern/COM_NodeOperationBuilder.cc
@@ -481,7 +481,6 @@ static Vector<NodeOperationHash> generate_hashes(Span<NodeOperation *> operation
return hashes;
}
-/** Merge operations with same type, inputs and parameters that produce the same result. */
void NodeOperationBuilder::merge_equal_operations()
{
bool check_for_next_merge = true;
@@ -793,7 +792,6 @@ void NodeOperationBuilder::save_graphviz(StringRefNull name)
}
}
-/** Create a graphviz representation of the NodeOperationBuilder. */
std::ostream &operator<<(std::ostream &os, const NodeOperationBuilder &builder)
{
os << "# Builder start\n";
diff --git a/source/blender/compositor/intern/COM_NodeOperationBuilder.h b/source/blender/compositor/intern/COM_NodeOperationBuilder.h
index fcb2dd3800e..efc927e7c9e 100644
--- a/source/blender/compositor/intern/COM_NodeOperationBuilder.h
+++ b/source/blender/compositor/intern/COM_NodeOperationBuilder.h
@@ -169,6 +169,7 @@ class NodeOperationBuilder {
private:
PreviewOperation *make_preview_operation() const;
void unlink_inputs_and_relink_outputs(NodeOperation *unlinked_op, NodeOperation *linked_op);
+ /** Merge operations with same type, inputs and parameters that produce the same result. */
void merge_equal_operations();
void merge_equal_operations(NodeOperation *from, NodeOperation *into);
void save_graphviz(StringRefNull name = "");
@@ -177,6 +178,7 @@ class NodeOperationBuilder {
#endif
};
+/** Create a graphviz representation of the NodeOperationBuilder. */
std::ostream &operator<<(std::ostream &os, const NodeOperationBuilder &builder);
std::ostream &operator<<(std::ostream &os, const NodeOperationBuilder::Link &link);
diff --git a/source/blender/compositor/intern/COM_SharedOperationBuffers.cc b/source/blender/compositor/intern/COM_SharedOperationBuffers.cc
index c67251b2d20..567b5e0ee53 100644
--- a/source/blender/compositor/intern/COM_SharedOperationBuffers.cc
+++ b/source/blender/compositor/intern/COM_SharedOperationBuffers.cc
@@ -31,13 +31,11 @@ SharedOperationBuffers::BufferData &SharedOperationBuffers::get_buffer_data(Node
return buffers_.lookup_or_add_cb(op, []() { return BufferData(); });
}
-/**
- * Whether given operation area to render is already registered.
- * TODO: Possibly refactor to "request_area". Current implementation is incomplete: partial
- * overlapping, etc. Leading to more rendering than necessary.
- */
bool SharedOperationBuffers::is_area_registered(NodeOperation *op, const rcti &area_to_render)
{
+ /* TODO: Possibly refactor to "request_area". Current implementation is incomplete:
+ * partial overlapping, etc. Leading to more rendering than necessary. */
+
BufferData &buf_data = get_buffer_data(op);
for (rcti &reg_rect : buf_data.render_areas) {
if (BLI_rcti_inside_rcti(&reg_rect, &area_to_render)) {
@@ -47,34 +45,21 @@ bool SharedOperationBuffers::is_area_registered(NodeOperation *op, const rcti &a
return false;
}
-/**
- * Registers an operation area to render.
- */
void SharedOperationBuffers::register_area(NodeOperation *op, const rcti &area_to_render)
{
get_buffer_data(op).render_areas.append(area_to_render);
}
-/**
- * Whether given operation has any registered reads (other operation registered it depends on given
- * operation).
- */
bool SharedOperationBuffers::has_registered_reads(NodeOperation *op)
{
return get_buffer_data(op).registered_reads > 0;
}
-/**
- * Registers an operation read (other operation depends on given operation).
- */
void SharedOperationBuffers::register_read(NodeOperation *read_op)
{
get_buffer_data(read_op).registered_reads++;
}
-/**
- * Get registered areas given operation needs to render.
- */
Vector<rcti> SharedOperationBuffers::get_areas_to_render(NodeOperation *op,
const int offset_x,
const int offset_y)
@@ -88,17 +73,11 @@ Vector<rcti> SharedOperationBuffers::get_areas_to_render(NodeOperation *op,
return dst_areas;
}
-/**
- * Whether this operation buffer has already been rendered.
- */
bool SharedOperationBuffers::is_operation_rendered(NodeOperation *op)
{
return get_buffer_data(op).is_rendered;
}
-/**
- * Stores given operation rendered buffer.
- */
void SharedOperationBuffers::set_rendered_buffer(NodeOperation *op,
std::unique_ptr<MemoryBuffer> buffer)
{
@@ -109,19 +88,12 @@ void SharedOperationBuffers::set_rendered_buffer(NodeOperation *op,
buf_data.is_rendered = true;
}
-/**
- * Get given operation rendered buffer.
- */
MemoryBuffer *SharedOperationBuffers::get_rendered_buffer(NodeOperation *op)
{
BLI_assert(is_operation_rendered(op));
return get_buffer_data(op).buffer.get();
}
-/**
- * Reports an operation has finished reading given operation. If all given operation dependencies
- * have finished its buffer will be disposed.
- */
void SharedOperationBuffers::read_finished(NodeOperation *read_op)
{
BufferData &buf_data = get_buffer_data(read_op);
diff --git a/source/blender/compositor/intern/COM_SharedOperationBuffers.h b/source/blender/compositor/intern/COM_SharedOperationBuffers.h
index d7d0dffabb5..fd053fce02f 100644
--- a/source/blender/compositor/intern/COM_SharedOperationBuffers.h
+++ b/source/blender/compositor/intern/COM_SharedOperationBuffers.h
@@ -50,17 +50,46 @@ class SharedOperationBuffers {
blender::Map<NodeOperation *, BufferData> buffers_;
public:
+ /**
+ * Whether given operation area to render is already registered.
+ */
bool is_area_registered(NodeOperation *op, const rcti &area_to_render);
+ /**
+ * Registers an operation area to render.
+ */
void register_area(NodeOperation *op, const rcti &area_to_render);
+ /**
+ * Whether given operation has any registered reads (other operation registered it depends on
+ * given operation).
+ */
bool has_registered_reads(NodeOperation *op);
+ /**
+ * Registers an operation read (other operation depends on given operation).
+ */
void register_read(NodeOperation *read_op);
+ /**
+ * Get registered areas given operation needs to render.
+ */
Vector<rcti> get_areas_to_render(NodeOperation *op, int offset_x, int offset_y);
+ /**
+ * Whether this operation buffer has already been rendered.
+ */
bool is_operation_rendered(NodeOperation *op);
+ /**
+ * Stores given operation rendered buffer.
+ */
void set_rendered_buffer(NodeOperation *op, std::unique_ptr<MemoryBuffer> buffer);
+ /**
+ * Get given operation rendered buffer.
+ */
MemoryBuffer *get_rendered_buffer(NodeOperation *op);
+ /**
+ * Reports an operation has finished reading given operation. If all given operation dependencies
+ * have finished its buffer will be disposed.
+ */
void read_finished(NodeOperation *read_op);
private:
diff --git a/source/blender/compositor/operations/COM_BlurBaseOperation.cc b/source/blender/compositor/operations/COM_BlurBaseOperation.cc
index aefe74a7e26..702733498c8 100644
--- a/source/blender/compositor/operations/COM_BlurBaseOperation.cc
+++ b/source/blender/compositor/operations/COM_BlurBaseOperation.cc
@@ -111,8 +111,6 @@ __m128 *BlurBaseOperation::convert_gausstab_sse(const float *gausstab, int size)
}
#endif
-/* normalized distance from the current (inverted so 1.0 is close and 0.0 is far)
- * 'ease' is applied after, looks nicer */
float *BlurBaseOperation::make_dist_fac_inverse(float rad, int size, int falloff)
{
float *dist_fac_invert, val;
diff --git a/source/blender/compositor/operations/COM_BlurBaseOperation.h b/source/blender/compositor/operations/COM_BlurBaseOperation.h
index ab378983100..e12c5427082 100644
--- a/source/blender/compositor/operations/COM_BlurBaseOperation.h
+++ b/source/blender/compositor/operations/COM_BlurBaseOperation.h
@@ -41,6 +41,10 @@ class BlurBaseOperation : public MultiThreadedOperation, public QualityStepHelpe
#ifdef BLI_HAVE_SSE2
__m128 *convert_gausstab_sse(const float *gausstab, int size);
#endif
+ /**
+ * Normalized distance from the current (inverted so 1.0 is close and 0.0 is far)
+ * 'ease' is applied after, looks nicer.
+ */
float *make_dist_fac_inverse(float rad, int size, int falloff);
void update_size();
diff --git a/source/blender/compositor/operations/COM_ColorCurveOperation.cc b/source/blender/compositor/operations/COM_ColorCurveOperation.cc
index 7cfa1c09298..bf82ae73d55 100644
--- a/source/blender/compositor/operations/COM_ColorCurveOperation.cc
+++ b/source/blender/compositor/operations/COM_ColorCurveOperation.cc
@@ -45,7 +45,7 @@ void ColorCurveOperation::init_execution()
input_black_program_ = this->get_input_socket_reader(2);
input_white_program_ = this->get_input_socket_reader(3);
- BKE_curvemapping_premultiply(curve_mapping_, 0);
+ BKE_curvemapping_premultiply(curve_mapping_, false);
}
void ColorCurveOperation::execute_pixel_sampled(float output[4],
@@ -145,7 +145,7 @@ void ConstantLevelColorCurveOperation::init_execution()
input_fac_program_ = this->get_input_socket_reader(0);
input_image_program_ = this->get_input_socket_reader(1);
- BKE_curvemapping_premultiply(curve_mapping_, 0);
+ BKE_curvemapping_premultiply(curve_mapping_, false);
BKE_curvemapping_set_black_white(curve_mapping_, black_, white_);
}
diff --git a/source/blender/compositor/operations/COM_DilateErodeOperation.cc b/source/blender/compositor/operations/COM_DilateErodeOperation.cc
index 2abc4f71b5e..3aaf402ae24 100644
--- a/source/blender/compositor/operations/COM_DilateErodeOperation.cc
+++ b/source/blender/compositor/operations/COM_DilateErodeOperation.cc
@@ -21,7 +21,6 @@
namespace blender::compositor {
-/* DilateErode Distance Threshold */
DilateErodeThresholdOperation::DilateErodeThresholdOperation()
{
this->add_input_socket(DataType::Value);
@@ -268,7 +267,6 @@ void DilateErodeThresholdOperation::update_memory_buffer_partial(MemoryBuffer *o
}
}
-/* Dilate Distance. */
DilateDistanceOperation::DilateDistanceOperation()
{
this->add_input_socket(DataType::Value);
@@ -458,7 +456,6 @@ void DilateDistanceOperation::update_memory_buffer_partial(MemoryBuffer *output,
}
}
-/* Erode Distance */
ErodeDistanceOperation::ErodeDistanceOperation() : DilateDistanceOperation()
{
/* pass */
@@ -531,7 +528,6 @@ void ErodeDistanceOperation::update_memory_buffer_partial(MemoryBuffer *output,
}
}
-/* Dilate step */
DilateStepOperation::DilateStepOperation()
{
this->add_input_socket(DataType::Value);
@@ -809,7 +805,6 @@ void DilateStepOperation::update_memory_buffer_partial(MemoryBuffer *output,
step_update_memory_buffer<Max2Selector>(output, inputs[0], area, iterations_, -FLT_MAX);
}
-/* Erode step */
ErodeStepOperation::ErodeStepOperation() : DilateStepOperation()
{
/* pass */
diff --git a/source/blender/compositor/operations/COM_DilateErodeOperation.h b/source/blender/compositor/operations/COM_DilateErodeOperation.h
index 04d25a1fca6..2ca6431862d 100644
--- a/source/blender/compositor/operations/COM_DilateErodeOperation.h
+++ b/source/blender/compositor/operations/COM_DilateErodeOperation.h
@@ -43,6 +43,7 @@ class DilateErodeThresholdOperation : public MultiThreadedOperation {
int scope_;
public:
+ /* DilateErode Distance Threshold */
DilateErodeThresholdOperation();
/**
@@ -98,6 +99,7 @@ class DilateDistanceOperation : public MultiThreadedOperation {
int scope_;
public:
+ /* Dilate Distance. */
DilateDistanceOperation();
/**
@@ -140,6 +142,7 @@ class DilateDistanceOperation : public MultiThreadedOperation {
class ErodeDistanceOperation : public DilateDistanceOperation {
public:
+ /* Erode Distance */
ErodeDistanceOperation();
/**
@@ -169,6 +172,7 @@ class DilateStepOperation : public MultiThreadedOperation {
int iterations_;
public:
+ /* Dilate step */
DilateStepOperation();
/**
@@ -205,6 +209,7 @@ class DilateStepOperation : public MultiThreadedOperation {
class ErodeStepOperation : public DilateStepOperation {
public:
+ /** Erode step. */
ErodeStepOperation();
void *initialize_tile_data(rcti *rect) override;
diff --git a/source/blender/compositor/operations/COM_InpaintOperation.cc b/source/blender/compositor/operations/COM_InpaintOperation.cc
index 2d632bb3681..83bc81d35fc 100644
--- a/source/blender/compositor/operations/COM_InpaintOperation.cc
+++ b/source/blender/compositor/operations/COM_InpaintOperation.cc
@@ -25,7 +25,6 @@ namespace blender::compositor {
#define ASSERT_XY_RANGE(x, y) \
BLI_assert(x >= 0 && x < this->get_width() && y >= 0 && y < this->get_height())
-/* In-paint (simple convolve using average of known pixels). */
InpaintSimpleOperation::InpaintSimpleOperation()
{
this->add_input_socket(DataType::Color);
diff --git a/source/blender/compositor/operations/COM_InpaintOperation.h b/source/blender/compositor/operations/COM_InpaintOperation.h
index b0d44e22b85..989d154dab5 100644
--- a/source/blender/compositor/operations/COM_InpaintOperation.h
+++ b/source/blender/compositor/operations/COM_InpaintOperation.h
@@ -39,6 +39,7 @@ class InpaintSimpleOperation : public NodeOperation {
short *manhattan_distance_;
public:
+ /** In-paint (simple convolve using average of known pixels). */
InpaintSimpleOperation();
/**
diff --git a/source/blender/compositor/operations/COM_MathBaseOperation.cc b/source/blender/compositor/operations/COM_MathBaseOperation.cc
index 86993ffe887..1a4684ae3f0 100644
--- a/source/blender/compositor/operations/COM_MathBaseOperation.cc
+++ b/source/blender/compositor/operations/COM_MathBaseOperation.cc
@@ -52,7 +52,7 @@ void MathBaseOperation::deinit_execution()
void MathBaseOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
{
NodeOperationInput *socket;
- rcti temp_area;
+ rcti temp_area = COM_AREA_NONE;
socket = this->get_input_socket(0);
const bool determined = socket->determine_canvas(COM_AREA_NONE, temp_area);
if (determined) {
diff --git a/source/blender/compositor/operations/COM_MixOperation.cc b/source/blender/compositor/operations/COM_MixOperation.cc
index 09bbb633459..edae4454b13 100644
--- a/source/blender/compositor/operations/COM_MixOperation.cc
+++ b/source/blender/compositor/operations/COM_MixOperation.cc
@@ -70,7 +70,7 @@ void MixBaseOperation::execute_pixel_sampled(float output[4],
void MixBaseOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
{
NodeOperationInput *socket;
- rcti temp_area;
+ rcti temp_area = COM_AREA_NONE;
socket = this->get_input_socket(1);
bool determined = socket->determine_canvas(COM_AREA_NONE, temp_area);
diff --git a/source/blender/compositor/operations/COM_PlaneTrackOperation.h b/source/blender/compositor/operations/COM_PlaneTrackOperation.h
index 4c584ca43f4..22ece04b900 100644
--- a/source/blender/compositor/operations/COM_PlaneTrackOperation.h
+++ b/source/blender/compositor/operations/COM_PlaneTrackOperation.h
@@ -81,7 +81,7 @@ class PlaneTrackMaskOperation : public PlaneDistortMaskOperation, public PlaneTr
{
PlaneTrackCommon::determine_canvas(preferred_area, r_area);
- rcti unused;
+ rcti unused = COM_AREA_NONE;
rcti &preferred = r_area;
NodeOperation::determine_canvas(preferred, unused);
}
@@ -102,7 +102,7 @@ class PlaneTrackWarpImageOperation : public PlaneDistortWarpImageOperation,
{
PlaneTrackCommon::determine_canvas(preferred_area, r_area);
- rcti unused;
+ rcti unused = COM_AREA_NONE;
rcti &preferred = r_area;
NodeOperation::determine_canvas(preferred, unused);
}
diff --git a/source/blender/compositor/operations/COM_RenderLayersProg.cc b/source/blender/compositor/operations/COM_RenderLayersProg.cc
index 7650def2c87..d8e73b7c979 100644
--- a/source/blender/compositor/operations/COM_RenderLayersProg.cc
+++ b/source/blender/compositor/operations/COM_RenderLayersProg.cc
@@ -263,6 +263,7 @@ void RenderLayersProg::update_memory_buffer_partial(MemoryBuffer *output,
}
/* ******** Render Layers AO Operation ******** */
+
void RenderLayersAOOperation::execute_pixel_sampled(float output[4],
float x,
float y,
@@ -294,6 +295,7 @@ void RenderLayersAOOperation::update_memory_buffer_partial(MemoryBuffer *output,
}
/* ******** Render Layers Alpha Operation ******** */
+
void RenderLayersAlphaProg::execute_pixel_sampled(float output[4],
float x,
float y,
@@ -326,6 +328,7 @@ void RenderLayersAlphaProg::update_memory_buffer_partial(MemoryBuffer *output,
}
/* ******** Render Layers Depth Operation ******** */
+
void RenderLayersDepthProg::execute_pixel_sampled(float output[4],
float x,
float y,
diff --git a/source/blender/compositor/operations/COM_RotateOperation.cc b/source/blender/compositor/operations/COM_RotateOperation.cc
index 8129516f81c..145a2f9c9d0 100644
--- a/source/blender/compositor/operations/COM_RotateOperation.cc
+++ b/source/blender/compositor/operations/COM_RotateOperation.cc
@@ -227,7 +227,7 @@ void RotateOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
get_input_socket(IMAGE_INPUT_INDEX)->determine_canvas(preferred_area, r_area);
if (image_determined) {
rcti input_canvas = r_area;
- rcti unused;
+ rcti unused = COM_AREA_NONE;
get_input_socket(DEGREE_INPUT_INDEX)->determine_canvas(input_canvas, unused);
ensure_degree();
diff --git a/source/blender/compositor/operations/COM_SMAAOperation.cc b/source/blender/compositor/operations/COM_SMAAOperation.cc
index ef67b6ca5f9..20e85c69ac8 100644
--- a/source/blender/compositor/operations/COM_SMAAOperation.cc
+++ b/source/blender/compositor/operations/COM_SMAAOperation.cc
@@ -664,9 +664,6 @@ void SMAABlendingWeightCalculationOperation::get_area_of_interest(const int UNUS
/*-----------------------------------------------------------------------------*/
/* Diagonal Search Functions */
-/**
- * These functions allows to perform diagonal pattern searches.
- */
int SMAABlendingWeightCalculationOperation::search_diag1(int x, int y, int dir, bool *found)
{
float e[4];
@@ -714,9 +711,6 @@ int SMAABlendingWeightCalculationOperation::search_diag2(int x, int y, int dir,
return x - dir;
}
-/**
- * This searches for diagonal patterns and returns the corresponding weights.
- */
void SMAABlendingWeightCalculationOperation::calculate_diag_weights(int x,
int y,
const float edges[2],
diff --git a/source/blender/compositor/operations/COM_SMAAOperation.h b/source/blender/compositor/operations/COM_SMAAOperation.h
index 65a88d43fdf..ec04594e0aa 100644
--- a/source/blender/compositor/operations/COM_SMAAOperation.h
+++ b/source/blender/compositor/operations/COM_SMAAOperation.h
@@ -111,8 +111,14 @@ class SMAABlendingWeightCalculationOperation : public MultiThreadedOperation {
private:
/* Diagonal Search Functions */
+ /**
+ * These functions allows to perform diagonal pattern searches.
+ */
int search_diag1(int x, int y, int dir, bool *found);
int search_diag2(int x, int y, int dir, bool *found);
+ /**
+ * This searches for diagonal patterns and returns the corresponding weights.
+ */
void calculate_diag_weights(int x, int y, const float edges[2], float weights[2]);
bool is_vertical_search_unneeded(int x, int y);
diff --git a/source/blender/compositor/operations/COM_ScaleOperation.cc b/source/blender/compositor/operations/COM_ScaleOperation.cc
index 350934b0d3b..281087bb4c7 100644
--- a/source/blender/compositor/operations/COM_ScaleOperation.cc
+++ b/source/blender/compositor/operations/COM_ScaleOperation.cc
@@ -223,7 +223,7 @@ void ScaleOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
get_input_socket(IMAGE_INPUT_INDEX)->determine_canvas(preferred_area, r_area);
if (image_determined) {
rcti image_canvas = r_area;
- rcti unused;
+ rcti unused = COM_AREA_NONE;
NodeOperationInput *x_socket = get_input_socket(X_INPUT_INDEX);
NodeOperationInput *y_socket = get_input_socket(Y_INPUT_INDEX);
x_socket->determine_canvas(image_canvas, unused);
@@ -374,7 +374,6 @@ bool ScaleAbsoluteOperation::determine_depending_area_of_interest(
return ScaleOperation::determine_depending_area_of_interest(&new_input, read_operation, output);
}
-/* Absolute fixed size. */
ScaleFixedSizeOperation::ScaleFixedSizeOperation() : BaseScaleOperation()
{
this->add_input_socket(DataType::Color, ResizeMode::None);
@@ -503,7 +502,7 @@ void ScaleFixedSizeOperation::determine_canvas(const rcti &preferred_area, rcti
rcti local_preferred = preferred_area;
local_preferred.xmax = local_preferred.xmin + new_width_;
local_preferred.ymax = local_preferred.ymin + new_height_;
- rcti input_canvas;
+ rcti input_canvas = COM_AREA_NONE;
const bool input_determined = get_input_socket(0)->determine_canvas(local_preferred,
input_canvas);
if (input_determined) {
diff --git a/source/blender/compositor/operations/COM_ScaleOperation.h b/source/blender/compositor/operations/COM_ScaleOperation.h
index 7710aa34c54..cac865b41aa 100644
--- a/source/blender/compositor/operations/COM_ScaleOperation.h
+++ b/source/blender/compositor/operations/COM_ScaleOperation.h
@@ -173,6 +173,7 @@ class ScaleFixedSizeOperation : public BaseScaleOperation {
bool is_offset_;
public:
+ /** Absolute fixed size. */
ScaleFixedSizeOperation();
bool determine_depending_area_of_interest(rcti *input,
ReadBufferOperation *read_operation,
diff --git a/source/blender/compositor/operations/COM_SplitOperation.cc b/source/blender/compositor/operations/COM_SplitOperation.cc
index e98c5c986f5..39d097b02e1 100644
--- a/source/blender/compositor/operations/COM_SplitOperation.cc
+++ b/source/blender/compositor/operations/COM_SplitOperation.cc
@@ -60,7 +60,7 @@ void SplitOperation::execute_pixel_sampled(float output[4],
void SplitOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
{
- rcti unused_area;
+ rcti unused_area = COM_AREA_NONE;
const bool determined = this->get_input_socket(0)->determine_canvas(COM_AREA_NONE, unused_area);
this->set_canvas_input_index(determined ? 0 : 1);
diff --git a/source/blender/compositor/operations/COM_TextureOperation.cc b/source/blender/compositor/operations/COM_TextureOperation.cc
index 2ed83e87569..f5d47478a8d 100644
--- a/source/blender/compositor/operations/COM_TextureOperation.cc
+++ b/source/blender/compositor/operations/COM_TextureOperation.cc
@@ -80,7 +80,7 @@ void TextureBaseOperation::determine_canvas(const rcti &preferred_area, rcti &r_
if (execution_model_ == eExecutionModel::FullFrame) {
/* Determine inputs. */
- rcti temp;
+ rcti temp = COM_AREA_NONE;
NodeOperation::determine_canvas(r_area, temp);
}
}
diff --git a/source/blender/compositor/operations/COM_TransformOperation.cc b/source/blender/compositor/operations/COM_TransformOperation.cc
index be9bb32e7f0..f18e7e44094 100644
--- a/source/blender/compositor/operations/COM_TransformOperation.cc
+++ b/source/blender/compositor/operations/COM_TransformOperation.cc
@@ -126,7 +126,7 @@ void TransformOperation::determine_canvas(const rcti &preferred_area, rcti &r_ar
get_input_socket(IMAGE_INPUT_INDEX)->determine_canvas(preferred_area, r_area);
if (image_determined) {
rcti image_canvas = r_area;
- rcti unused;
+ rcti unused = COM_AREA_NONE;
get_input_socket(X_INPUT_INDEX)->determine_canvas(image_canvas, unused);
get_input_socket(Y_INPUT_INDEX)->determine_canvas(image_canvas, unused);
get_input_socket(DEGREE_INPUT_INDEX)->determine_canvas(image_canvas, unused);
@@ -171,7 +171,6 @@ void TransformOperation::determine_canvas(const rcti &preferred_area, rcti &r_ar
}
}
-/** Translate -> Rotate -> Scale. */
void TransformOperation::transform(BuffersIterator<float> &it, const MemoryBuffer *input_img)
{
float rotate_center_x, rotate_center_y;
@@ -198,7 +197,6 @@ void TransformOperation::transform(BuffersIterator<float> &it, const MemoryBuffe
}
}
-/** Scale -> Rotate -> Translate. */
void TransformOperation::transform_inverted(BuffersIterator<float> &it,
const MemoryBuffer *input_img)
{
diff --git a/source/blender/compositor/operations/COM_TransformOperation.h b/source/blender/compositor/operations/COM_TransformOperation.h
index 3c5584a1bea..4db2145cc2d 100644
--- a/source/blender/compositor/operations/COM_TransformOperation.h
+++ b/source/blender/compositor/operations/COM_TransformOperation.h
@@ -35,9 +35,9 @@ class TransformOperation : public MultiThreadedOperation {
int translate_x_;
int translate_y_;
float scale_;
- rcti scale_canvas_;
- rcti rotate_canvas_;
- rcti translate_canvas_;
+ rcti scale_canvas_ = COM_AREA_NONE;
+ rcti rotate_canvas_ = COM_AREA_NONE;
+ rcti translate_canvas_ = COM_AREA_NONE;
/* Set variables. */
PixelSampler sampler_;
@@ -82,7 +82,9 @@ class TransformOperation : public MultiThreadedOperation {
void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
private:
+ /** Translate -> Rotate -> Scale. */
void transform(BuffersIterator<float> &it, const MemoryBuffer *input_img);
+ /** Scale -> Rotate -> Translate. */
void transform_inverted(BuffersIterator<float> &it, const MemoryBuffer *input_img);
};
diff --git a/source/blender/compositor/operations/COM_TranslateOperation.cc b/source/blender/compositor/operations/COM_TranslateOperation.cc
index 89c7468a67c..d3c87b09fb7 100644
--- a/source/blender/compositor/operations/COM_TranslateOperation.cc
+++ b/source/blender/compositor/operations/COM_TranslateOperation.cc
@@ -158,7 +158,7 @@ void TranslateCanvasOperation::determine_canvas(const rcti &preferred_area, rcti
if (determined) {
NodeOperationInput *x_socket = get_input_socket(X_INPUT_INDEX);
NodeOperationInput *y_socket = get_input_socket(Y_INPUT_INDEX);
- rcti unused;
+ rcti unused = COM_AREA_NONE;
x_socket->determine_canvas(r_area, unused);
y_socket->determine_canvas(r_area, unused);
diff --git a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cc b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cc
index 891518d53bf..86bc6d0041a 100644
--- a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cc
+++ b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cc
@@ -69,7 +69,7 @@ void *VariableSizeBokehBlurOperation::initialize_tile_data(rcti *rect)
data->bokeh = (MemoryBuffer *)input_bokeh_program_->initialize_tile_data(rect);
data->size = (MemoryBuffer *)input_size_program_->initialize_tile_data(rect);
- rcti rect2;
+ rcti rect2 = COM_AREA_NONE;
this->determine_depending_area_of_interest(
rect, (ReadBufferOperation *)input_size_program_, &rect2);
@@ -398,7 +398,7 @@ void VariableSizeBokehBlurOperation::update_memory_buffer_partial(MemoryBuffer *
p.image_width = this->get_width();
p.image_height = this->get_height();
- rcti scalar_area;
+ rcti scalar_area = COM_AREA_NONE;
this->get_area_of_interest(SIZE_INPUT_INDEX, area, scalar_area);
BLI_rcti_isect(&scalar_area, &p.size_input->get_rect(), &scalar_area);
const float max_size = p.size_input->get_max_value(scalar_area);
diff --git a/source/blender/compositor/operations/COM_VectorBlurOperation.cc b/source/blender/compositor/operations/COM_VectorBlurOperation.cc
index b220990db76..e34b629f457 100644
--- a/source/blender/compositor/operations/COM_VectorBlurOperation.cc
+++ b/source/blender/compositor/operations/COM_VectorBlurOperation.cc
@@ -40,6 +40,7 @@ void zbuf_free_span(ZSpan *zspan);
void antialias_tagbuf(int xsize, int ysize, char *rectmove);
/* VectorBlurOperation */
+
VectorBlurOperation::VectorBlurOperation()
{
this->add_input_socket(DataType::Color);
diff --git a/source/blender/depsgraph/DEG_depsgraph.h b/source/blender/depsgraph/DEG_depsgraph.h
index aa184cce433..0b3e028cd06 100644
--- a/source/blender/depsgraph/DEG_depsgraph.h
+++ b/source/blender/depsgraph/DEG_depsgraph.h
@@ -80,45 +80,67 @@ extern "C" {
/* ************************************************ */
/* Depsgraph API */
-/* CRUD ------------------------------------------- */
+/* -------------------------------------------------------------------- */
+/** \name CRUD
+ * \{ */
/* Get main depsgraph instance from context! */
-/* Create new Depsgraph instance */
-/* TODO: what args are needed here? What's the building-graph entry point? */
+/**
+ * Create new Depsgraph instance.
+ *
+ * TODO: what arguments are needed here? What's the building-graph entry point?
+ */
Depsgraph *DEG_graph_new(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,
eEvaluationMode mode);
+/**
+ * Replace the "owner" pointers (currently Main/Scene/ViewLayer) of this depsgraph.
+ * Used for:
+ * - Undo steps when we do want to re-use the old depsgraph data as much as possible.
+ * - Rendering where we want to re-use objects between different view layers.
+ */
void DEG_graph_replace_owners(struct Depsgraph *depsgraph,
struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer);
-/* Free Depsgraph itself and all its data */
+/** Free graph's contents and graph itself. */
void DEG_graph_free(Depsgraph *graph);
-/* Node Types Registry ---------------------------- */
+/** \} */
-/* Register all node types */
+/* -------------------------------------------------------------------- */
+/** \name Node Types Registry
+ * \{ */
+
+/** Register all node types. */
void DEG_register_node_types(void);
-/* Free node type registry on exit */
+/** Free node type registry on exit. */
void DEG_free_node_types(void);
-/* Update Tagging -------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Update Tagging
+ * \{ */
-/* Tag dependency graph for updates when visible scenes/layers changes. */
+/** Tag dependency graph for updates when visible scenes/layers changes. */
void DEG_graph_tag_on_visible_update(Depsgraph *depsgraph, const bool do_time);
-/* Tag all dependency graphs for update when visible scenes/layers changes. */
+/** Tag all dependency graphs for update when visible scenes/layers changes. */
void DEG_tag_on_visible_update(struct Main *bmain, const bool do_time);
-/* NOTE: Will return NULL if the flag is not known, allowing to gracefully handle situations
- * when recalc flag has been removed. */
+/**
+ * \note Will return NULL if the flag is not known, allowing to gracefully handle situations
+ * when recalc flag has been removed.
+ */
const char *DEG_update_tag_as_string(IDRecalcFlag flag);
+/** Tag given ID for an update in all the dependency graphs. */
void DEG_id_tag_update(struct ID *id, int flag);
void DEG_id_tag_update_ex(struct Main *bmain, struct ID *id, int flag);
@@ -127,48 +149,68 @@ void DEG_graph_id_tag_update(struct Main *bmain,
struct ID *id,
int flag);
-/* Tag all dependency graphs when time has changed. */
+/** Tag all dependency graphs when time has changed. */
void DEG_time_tag_update(struct Main *bmain);
-/* Tag a dependency graph when time has changed. */
+/** Tag a dependency graph when time has changed. */
void DEG_graph_time_tag_update(struct Depsgraph *depsgraph);
-/* Mark a particular datablock type as having changing. This does
- * not cause any updates but is used by external render engines to detect if for
- * example a datablock was removed. */
+/**
+ * Mark a particular data-block type as having changing.
+ * This does not cause any updates but is used by external
+ * render engines to detect if for example a data-block was removed.
+ */
void DEG_graph_id_type_tag(struct Depsgraph *depsgraph, short id_type);
void DEG_id_type_tag(struct Main *bmain, short id_type);
-/* Set a depsgraph to flush updates to editors. This would be done
- * for viewport depsgraphs, but not render or export depsgraph for example. */
+/**
+ * Set a depsgraph to flush updates to editors. This would be done
+ * for viewport depsgraphs, but not render or export depsgraph for example.
+ */
void DEG_enable_editors_update(struct Depsgraph *depsgraph);
-/* Check if something was changed in the database and inform editors about this. */
+/** Check if something was changed in the database and inform editors about this. */
void DEG_editors_update(struct Depsgraph *depsgraph, bool time);
-/* Clear recalc flags after editors or renderers have handled updates. */
+/** Clear recalc flags after editors or renderers have handled updates. */
void DEG_ids_clear_recalc(Depsgraph *depsgraph, const bool backup);
-/* Restore recalc flags, backed up by a previous call to DEG_ids_clear_recalc.
- * This also clears the backup. */
+/**
+ * Restore recalc flags, backed up by a previous call to #DEG_ids_clear_recalc.
+ * This also clears the backup.
+ */
void DEG_ids_restore_recalc(Depsgraph *depsgraph);
+/** \} */
+
/* ************************************************ */
/* Evaluation Engine API */
-/* Graph Evaluation ----------------------------- */
+/* -------------------------------------------------------------------- */
+/** \name Graph Evaluation
+ * \{ */
-/* Frame changed recalculation entry point. */
+/**
+ * Frame changed recalculation entry point.
+ *
+ * \note The frame-change happened for root scene that graph belongs to.
+ */
void DEG_evaluate_on_framechange(Depsgraph *graph, float frame);
-/* Data changed recalculation entry point. */
+/**
+ * Data changed recalculation entry point.
+ * Evaluate all nodes tagged for updating.
+ */
void DEG_evaluate_on_refresh(Depsgraph *graph);
-/* Editors Integration -------------------------- */
+/** \} */
-/* Mechanism to allow editors to be informed of depsgraph updates,
+/* -------------------------------------------------------------------- */
+/** \name Editors Integration
+ *
+ * Mechanism to allow editors to be informed of depsgraph updates,
* to do their own updates based on changes.
- */
+ * \{ */
typedef struct DEGEditorUpdateContext {
struct Main *bmain;
@@ -181,10 +223,14 @@ typedef void (*DEG_EditorUpdateIDCb)(const DEGEditorUpdateContext *update_ctx, s
typedef void (*DEG_EditorUpdateSceneCb)(const DEGEditorUpdateContext *update_ctx,
const bool updated);
-/* Set callbacks which are being called when depsgraph changes. */
+/** Set callbacks which are being called when depsgraph changes. */
void DEG_editors_set_update_cb(DEG_EditorUpdateIDCb id_func, DEG_EditorUpdateSceneCb scene_func);
-/* Evaluation ----------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Evaluation
+ * \{ */
bool DEG_is_evaluating(const struct Depsgraph *depsgraph);
@@ -192,7 +238,11 @@ bool DEG_is_active(const struct Depsgraph *depsgraph);
void DEG_make_active(struct Depsgraph *depsgraph);
void DEG_make_inactive(struct Depsgraph *depsgraph);
-/* Evaluation Debug ------------------------------ */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Evaluation Debug
+ * \{ */
void DEG_debug_print_begin(struct Depsgraph *depsgraph);
@@ -232,6 +282,8 @@ void DEG_debug_print_eval_time(struct Depsgraph *depsgraph,
const void *object_address,
float time);
+/** \} */
+
#ifdef __cplusplus
} /* extern "C" */
#endif
diff --git a/source/blender/depsgraph/DEG_depsgraph_build.h b/source/blender/depsgraph/DEG_depsgraph_build.h
index c029d203574..94cba833096 100644
--- a/source/blender/depsgraph/DEG_depsgraph_build.h
+++ b/source/blender/depsgraph/DEG_depsgraph_build.h
@@ -50,17 +50,22 @@ extern "C" {
/* Graph Building -------------------------------- */
-/* Build depsgraph for the given scene, and dump results in given graph container. */
+/** Build depsgraph for the given scene layer, and dump results in given graph container. */
void DEG_graph_build_from_view_layer(struct Depsgraph *graph);
-/* Build depsgraph for all objects (so also invisible ones) in the given view layer. */
+/**
+ * Build depsgraph for all objects (so also invisible ones) in the given view layer.
+ */
void DEG_graph_build_for_all_objects(struct Depsgraph *graph);
-/* Special version of builder which produces dependency graph suitable for the render pipeline.
- * It will contain sequencer and compositor (if needed) and all their dependencies. */
+/**
+ * Special version of builder which produces dependency graph suitable for the render pipeline.
+ * It will contain sequencer and compositor (if needed) and all their dependencies.
+ */
void DEG_graph_build_for_render_pipeline(struct Depsgraph *graph);
-/* Builds minimal dependency graph for compositor preview.
+/**
+ * Builds minimal dependency graph for compositor preview.
*
* Note that compositor editor might have pinned node tree, which is different from scene's node
* tree.
@@ -69,18 +74,19 @@ void DEG_graph_build_for_compositor_preview(struct Depsgraph *graph, struct bNod
void DEG_graph_build_from_ids(struct Depsgraph *graph, struct ID **ids, const int num_ids);
-/* Tag relations from the given graph for update. */
+/** Tag relations from the given graph for update. */
void DEG_graph_tag_relations_update(struct Depsgraph *graph);
-/* Create or update relations in the specified graph. */
+/** Create or update relations in the specified graph. */
void DEG_graph_relations_update(struct Depsgraph *graph);
-/* Tag all relations in the database for update. */
+/** Tag all relations in the database for update. */
void DEG_relations_tag_update(struct Main *bmain);
/* Add Dependencies ----------------------------- */
-/* Handle for components to define their dependencies from callbacks.
+/**
+ * Handle for components to define their dependencies from callbacks.
* This is generated by the depsgraph and passed to dependency callbacks
* as a symbolic reference to the current DepsNode.
* All relations will be defined in reference to that node.
@@ -159,23 +165,28 @@ void DEG_add_object_cache_relation(struct DepsNodeHandle *handle,
struct CacheFile *cache_file,
eDepsObjectComponentType component,
const char *description);
-/* Adds relation from DEG_OPCODE_GENERIC_DATABLOCK_UPDATE of a given ID.
- * Is used for such entities as textures and images. */
+/**
+ * Adds relation from #DEG_OPCODE_GENERIC_DATABLOCK_UPDATE of a given ID.
+ * Is used for such entities as textures and images.
+ */
void DEG_add_generic_id_relation(struct DepsNodeHandle *node_handle,
struct ID *id,
const char *description);
-/* Special function which is used from modifiers' updateDepsgraph() callback
+/**
+ * Special function which is used from modifiers' #updateDepsgraph() callback
* to indicate that the modifier needs to know transformation of the object
* which that modifier belongs to.
* This function will take care of checking which operation is required to
- * have transformation for the modifier, taking into account possible simulation
- * solvers. */
+ * have transformation for the modifier, taking into account possible simulation solvers.
+ */
void DEG_add_modifier_to_transform_relation(struct DepsNodeHandle *node_handle,
const char *description);
-/* Adds relations from the given component of a given object to the given node
- * handle AND the component to the point cache component of the node's ID. */
+/**
+ * Adds relations from the given component of a given object to the given node
+ * handle AND the component to the point cache component of the node's ID.
+ */
void DEG_add_object_pointcache_relation(struct DepsNodeHandle *node_handle,
struct Object *object,
eDepsObjectComponentType component,
diff --git a/source/blender/depsgraph/DEG_depsgraph_debug.h b/source/blender/depsgraph/DEG_depsgraph_debug.h
index 2aea10fd5b4..5c400a1392f 100644
--- a/source/blender/depsgraph/DEG_depsgraph_debug.h
+++ b/source/blender/depsgraph/DEG_depsgraph_debug.h
@@ -37,7 +37,7 @@ struct ViewLayer;
/* ------------------------------------------------ */
-/* NOTE: Those flags are same bitmask as G.debug_flags */
+/* NOTE: Those flags are same bit-mask as #G.debug_flags */
void DEG_debug_flags_set(struct Depsgraph *depsgraph, int flags);
int DEG_debug_flags_get(const struct Depsgraph *depsgraph);
@@ -47,6 +47,12 @@ const char *DEG_debug_name_get(struct Depsgraph *depsgraph);
/* ------------------------------------------------ */
+/**
+ * Obtain simple statistics about the complexity of the depsgraph.
+ * \param[out] r_outer: The number of outer nodes in the graph.
+ * \param[out] r_operations: The number of operation nodes in the graph.
+ * \param[out] r_relations: The number of relations between (executable) nodes in the graph.
+ */
void DEG_stats_simple(const struct Depsgraph *graph,
size_t *r_outer,
size_t *r_operations,
@@ -64,16 +70,16 @@ void DEG_debug_stats_gnuplot(const struct Depsgraph *graph,
/* ************************************************ */
-/* Compare two dependency graphs. */
+/** Compare two dependency graphs. */
bool DEG_debug_compare(const struct Depsgraph *graph1, const struct Depsgraph *graph2);
-/* Check that dependencies in the graph are really up to date. */
+/** Check that dependencies in the graph are really up to date. */
bool DEG_debug_graph_relations_validate(struct Depsgraph *graph,
struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer);
-/* Perform consistency check on the graph. */
+/** Perform consistency check on the graph. */
bool DEG_debug_consistency_check(struct Depsgraph *graph);
#ifdef __cplusplus
diff --git a/source/blender/depsgraph/DEG_depsgraph_query.h b/source/blender/depsgraph/DEG_depsgraph_query.h
index e9195a1eb26..ebb5f4d669c 100644
--- a/source/blender/depsgraph/DEG_depsgraph_query.h
+++ b/source/blender/depsgraph/DEG_depsgraph_query.h
@@ -47,87 +47,106 @@ struct ViewLayer;
extern "C" {
#endif
-/* *********************** DEG input data ********************* */
+/* -------------------------------------------------------------------- */
+/** \name DEG input data
+ * \{ */
-/* Get scene that depsgraph was built for. */
+/** Get scene that depsgraph was built for. */
struct Scene *DEG_get_input_scene(const Depsgraph *graph);
-/* Get view layer that depsgraph was built for. */
+/** Get view layer that depsgraph was built for. */
struct ViewLayer *DEG_get_input_view_layer(const Depsgraph *graph);
-/* Get bmain that depsgraph was built for. */
+/** Get bmain that depsgraph was built for. */
struct Main *DEG_get_bmain(const Depsgraph *graph);
-/* Get evaluation mode that depsgraph was built for. */
+/** Get evaluation mode that depsgraph was built for. */
eEvaluationMode DEG_get_mode(const Depsgraph *graph);
-/* Get time that depsgraph is being evaluated or was last evaluated at. */
+/** Get time that depsgraph is being evaluated or was last evaluated at. */
float DEG_get_ctime(const Depsgraph *graph);
-/* ********************* DEG evaluated data ******************* */
+/** \} */
-/* Check if given ID type was tagged for update. */
+/* -------------------------------------------------------------------- */
+/** \name DEG evaluated data
+ * \{ */
+
+/** Check if given ID type was tagged for update. */
bool DEG_id_type_updated(const struct Depsgraph *depsgraph, short id_type);
bool DEG_id_type_any_updated(const struct Depsgraph *depsgraph);
-/* Check if given ID type is present in the depsgraph */
+/** Check if given ID type is present in the depsgraph */
bool DEG_id_type_any_exists(const struct Depsgraph *depsgraph, short id_type);
-/* Get additional evaluation flags for the given ID. */
+/** Get additional evaluation flags for the given ID. */
uint32_t DEG_get_eval_flags_for_id(const struct Depsgraph *graph, struct ID *id);
-/* Get additional mesh CustomData_MeshMasks flags for the given object. */
+/** Get additional mesh CustomData_MeshMasks flags for the given object. */
void DEG_get_customdata_mask_for_object(const struct Depsgraph *graph,
struct Object *object,
struct CustomData_MeshMasks *r_mask);
-/* Get scene at its evaluated state.
+/**
+ * Get scene at its evaluated state.
*
* Technically, this is a copied-on-written and fully evaluated version of the input scene.
* This function will check that the data-block has been expanded (and copied) from the original
- * one. Assert will happen if it's not. */
+ * one. Assert will happen if it's not.
+ */
struct Scene *DEG_get_evaluated_scene(const struct Depsgraph *graph);
-/* Get view layer at its evaluated state.
- * This is a shortcut for accessing active view layer from evaluated scene. */
+/**
+ * Get view layer at its evaluated state.
+ * This is a shortcut for accessing active view layer from evaluated scene.
+ */
struct ViewLayer *DEG_get_evaluated_view_layer(const struct Depsgraph *graph);
-/* Get evaluated version of object for given original one. */
+/** Get evaluated version of object for given original one. */
struct Object *DEG_get_evaluated_object(const struct Depsgraph *depsgraph, struct Object *object);
-/* Get evaluated version of given ID data-block. */
+/** Get evaluated version of given ID data-block. */
struct ID *DEG_get_evaluated_id(const struct Depsgraph *depsgraph, struct ID *id);
-/* Get evaluated version of data pointed to by RNA pointer */
+/** Get evaluated version of data pointed to by RNA pointer */
void DEG_get_evaluated_rna_pointer(const struct Depsgraph *depsgraph,
struct PointerRNA *ptr,
struct PointerRNA *r_ptr_eval);
-/* Get original version of object for given evaluated one. */
+/** Get original version of object for given evaluated one. */
struct Object *DEG_get_original_object(struct Object *object);
-/* Get original version of given evaluated ID data-block. */
+/** Get original version of given evaluated ID data-block. */
struct ID *DEG_get_original_id(struct ID *id);
-/* Check whether given ID is an original,
+/**
+ * Check whether given ID is an original,
*
* 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. */
+ * not out-of-main localized data-blocks.
+ */
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(const struct ID *id);
bool DEG_is_evaluated_object(const struct Object *object);
-/* Check whether depsgraph is fully evaluated. This includes the following checks:
+/**
+ * Check whether depsgraph is fully evaluated. This includes the following checks:
* - Relations are up-to-date.
- * - Nothing is tagged for update. */
+ * - Nothing is tagged for update.
+ */
bool DEG_is_fully_evaluated(const struct Depsgraph *depsgraph);
-/* ************************ DEG object iterators ********************* */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name DEG object iterators
+ * \{ */
enum {
DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY = (1 << 0),
@@ -207,7 +226,11 @@ void DEG_iterator_objects_end(struct BLI_Iterator *iter);
#define DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END DEG_OBJECT_ITER_END
-/* ************************ DEG ID iterators ********************* */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name DEG ID iterators
+ * \{ */
typedef struct DEGIDIterData {
struct Depsgraph *graph;
@@ -221,15 +244,20 @@ void DEG_iterator_ids_begin(struct BLI_Iterator *iter, DEGIDIterData *data);
void DEG_iterator_ids_next(struct BLI_Iterator *iter);
void DEG_iterator_ids_end(struct BLI_Iterator *iter);
-/* ************************ DEG traversal ********************* */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name DEG traversal
+ * \{ */
typedef void (*DEGForeachIDCallback)(ID *id, void *user_data);
typedef void (*DEGForeachIDComponentCallback)(ID *id,
eDepsObjectComponentType component,
void *user_data);
-/* NOTE: Modifies runtime flags in depsgraph nodes, so can not be used in
- * parallel. Keep an eye on that!
+/**
+ * \note Modifies runtime flags in depsgraph nodes,
+ * so can not be used in parallel. Keep an eye on that!
*/
void DEG_foreach_ancestor_ID(const Depsgraph *depsgraph,
const ID *id,
@@ -240,8 +268,10 @@ void DEG_foreach_dependent_ID(const Depsgraph *depsgraph,
DEGForeachIDCallback callback,
void *user_data);
-/* Starts traversal from given component of the given ID, invokes callback for every other
- * component which is directly on indirectly dependent on the source one. */
+/**
+ * Starts traversal from given component of the given ID, invokes callback for every other
+ * component which is directly on indirectly dependent on the source one.
+ */
enum {
/* Ignore transform solvers which depends on multiple inputs and affects final transform.
* Is used for cases like snapping objects which are part of a rigid body simulation:
@@ -262,6 +292,8 @@ void DEG_foreach_dependent_ID_component(const Depsgraph *depsgraph,
void DEG_foreach_ID(const Depsgraph *depsgraph, DEGForeachIDCallback callback, void *user_data);
+/** \} */
+
#ifdef __cplusplus
} /* extern "C" */
#endif
diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc
index 41512168f57..b2e136c3d3b 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder.cc
@@ -176,7 +176,22 @@ void deg_graph_build_flush_visibility(Depsgraph *graph)
for (Relation *rel : op_node->inlinks) {
if (rel->from->type == NodeType::OPERATION) {
OperationNode *op_from = (OperationNode *)rel->from;
- op_from->owner->affects_directly_visible |= op_node->owner->affects_directly_visible;
+ ComponentNode *comp_from = op_from->owner;
+ const bool target_directly_visible = op_node->owner->affects_directly_visible;
+
+ /* Visibility component forces all components of the current ID to be considered as
+ * affecting directly visible. */
+ if (comp_from->type == NodeType::VISIBILITY) {
+ if (target_directly_visible) {
+ IDNode *id_node_from = comp_from->owner;
+ for (ComponentNode *comp_node : id_node_from->components.values()) {
+ comp_node->affects_directly_visible |= target_directly_visible;
+ }
+ }
+ }
+ else {
+ comp_from->affects_directly_visible |= target_directly_visible;
+ }
}
}
/* Schedule parent nodes. */
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
index a09f79ffa39..51582508b6f 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -179,15 +179,30 @@ IDNode *DepsgraphNodeBuilder::add_id_node(ID *id)
id_node->previously_visible_components_mask = previously_visible_components_mask;
id_node->previous_eval_flags = previous_eval_flags;
id_node->previous_customdata_masks = previous_customdata_masks;
+
/* NOTE: Zero number of components indicates that ID node was just created. */
- if (id_node->components.is_empty() && deg_copy_on_write_is_needed(id_type)) {
- ComponentNode *comp_cow = id_node->add_component(NodeType::COPY_ON_WRITE);
- OperationNode *op_cow = comp_cow->add_operation(
- [id_node](::Depsgraph *depsgraph) { deg_evaluate_copy_on_write(depsgraph, id_node); },
- OperationCode::COPY_ON_WRITE,
- "",
- -1);
- graph_->operations.append(op_cow);
+ const bool is_newly_created = id_node->components.is_empty();
+
+ if (is_newly_created) {
+ if (deg_copy_on_write_is_needed(id_type)) {
+ ComponentNode *comp_cow = id_node->add_component(NodeType::COPY_ON_WRITE);
+ OperationNode *op_cow = comp_cow->add_operation(
+ [id_node](::Depsgraph *depsgraph) { deg_evaluate_copy_on_write(depsgraph, id_node); },
+ OperationCode::COPY_ON_WRITE,
+ "",
+ -1);
+ graph_->operations.append(op_cow);
+ }
+
+ ComponentNode *visibility_component = id_node->add_component(NodeType::VISIBILITY);
+ OperationNode *visibility_operation = visibility_component->add_operation(
+ nullptr, OperationCode::OPERATION, "", -1);
+ /* Pin the node so that it and its relations are preserved by the unused nodes/relations
+ * deletion. This is mainly to make it easier to debug visibility. */
+ /* NOTE: Keep un-pinned for the 3.0 release. This way we are more sure that side effects of the
+ * change is minimal outside of the dependency graph area. */
+ // visibility_operation->flag |= OperationFlag::DEPSOP_FLAG_PINNED;
+ graph_->operations.append(visibility_operation);
}
return id_node;
}
@@ -375,8 +390,6 @@ void DepsgraphNodeBuilder::begin_build()
* NOTE: This is split in two, a static function and a public method of the node builder, to allow
* the code to access the builder's data more easily. */
-/* `id_cow_self` is the user of `id_pointer`, see also `LibraryIDLinkCallbackData` struct
- * definition. */
int DepsgraphNodeBuilder::foreach_id_cow_detect_need_for_update_callback(ID *id_cow_self,
ID *id_pointer)
{
@@ -425,21 +438,18 @@ static int foreach_id_cow_detect_need_for_update_callback(LibraryIDLinkCallbackD
return builder->foreach_id_cow_detect_need_for_update_callback(id_cow_self, id);
}
-/* Check for IDs that need to be flushed (COW-updated) because the depsgraph itself created or
- * removed some of their evaluated dependencies.
- *
- * NOTE: Currently the only ID types that depsgraph may decide to not evaluate/generate COW
- * copies for, even though they are referenced by other data-blocks, are Collections and Objects
- * (through their various visibility flags, and the ones from LayerCollections too). However, this
- * code is kept generic as it makes it more future-proof, and optimization here would give
- * negligible performance improvements in typical cases.
- *
- * NOTE: This mechanism may also 'fix' some missing update tagging from non-depsgraph code in
- * some cases. This is slightly unfortunate (as it may hide issues in other parts of Blender
- * code), but cannot really be avoided currently.
- */
void DepsgraphNodeBuilder::update_invalid_cow_pointers()
{
+ /* NOTE: Currently the only ID types that depsgraph may decide to not evaluate/generate COW
+ * copies for, even though they are referenced by other data-blocks, are Collections and Objects
+ * (through their various visibility flags, and the ones from #LayerCollections too). However,
+ * this code is kept generic as it makes it more future-proof, and optimization here would give
+ * negligible performance improvements in typical cases.
+ *
+ * NOTE: This mechanism may also 'fix' some missing update tagging from non-depsgraph code in
+ * some cases. This is slightly unfortunate (as it may hide issues in other parts of Blender
+ * code), but cannot really be avoided currently. */
+
for (const IDNode *id_node : graph_->id_nodes) {
if (id_node->previously_visible_components_mask == 0) {
/* Newly added node/ID, no need to check it. */
@@ -1056,10 +1066,6 @@ void DepsgraphNodeBuilder::build_object_pointcache(Object *object)
});
}
-/**
- * Build graph nodes for AnimData block and any animated images used.
- * \param id: ID-Block which hosts the AnimData
- */
void DepsgraphNodeBuilder::build_animdata(ID *id)
{
/* Special handling for animated images/sequences. */
@@ -1113,9 +1119,6 @@ void DepsgraphNodeBuilder::build_animdata_nlastrip_targets(ListBase *strips)
}
}
-/**
- * Build graph nodes to update the current frame in image users.
- */
void DepsgraphNodeBuilder::build_animation_images(ID *id)
{
if (BKE_image_user_id_has_animation(id)) {
@@ -1137,12 +1140,6 @@ void DepsgraphNodeBuilder::build_action(bAction *action)
add_operation_node(&action->id, NodeType::ANIMATION, OperationCode::ANIMATION_EVAL);
}
-/**
- * Build graph node(s) for Driver
- * \param id: ID-Block that driver is attached to
- * \param fcu: Driver-FCurve
- * \param driver_index: Index in animation data drivers list
- */
void DepsgraphNodeBuilder::build_driver(ID *id, FCurve *fcurve, int driver_index)
{
/* Create data node for this driver */
@@ -1715,7 +1712,6 @@ void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree)
build_animdata(&ntree->id);
/* Shading update. */
add_operation_node(&ntree->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE);
- add_operation_node(&ntree->id, NodeType::SHADING_PARAMETERS, OperationCode::MATERIAL_UPDATE);
/* nodetree's nodes... */
LISTBASE_FOREACH (bNode *, bnode, &ntree->nodes) {
build_idproperties(bnode->prop);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
index d31290ecbff..2d24dc49802 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
@@ -102,6 +102,10 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
virtual void begin_build();
virtual void end_build();
+ /**
+ * `id_cow_self` is the user of `id_pointer`,
+ * see also `LibraryIDLinkCallbackData` struct definition.
+ */
int foreach_id_cow_detect_need_for_update_callback(ID *id_cow_self, ID *id_pointer);
IDNode *add_id_node(ID *id);
@@ -199,10 +203,23 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
virtual void build_rigidbody(Scene *scene);
virtual void build_particle_systems(Object *object, bool is_object_visible);
virtual void build_particle_settings(ParticleSettings *part);
+ /**
+ * Build graph nodes for #AnimData block and any animated images used.
+ * \param id: ID-Block which hosts the #AnimData
+ */
virtual void build_animdata(ID *id);
virtual void build_animdata_nlastrip_targets(ListBase *strips);
+ /**
+ * Build graph nodes to update the current frame in image users.
+ */
virtual void build_animation_images(ID *id);
virtual void build_action(bAction *action);
+ /**
+ * Build graph node(s) for Driver
+ * \param id: ID-Block that driver is attached to
+ * \param fcurve: Driver-FCurve
+ * \param driver_index: Index in animation data drivers list
+ */
virtual void build_driver(ID *id, FCurve *fcurve, int driver_index);
virtual void build_driver_variables(ID *id, FCurve *fcurve);
virtual void build_driver_id_property(ID *id, const char *rna_path);
@@ -280,6 +297,10 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
void *user_data);
void tag_previously_tagged_nodes();
+ /**
+ * Check for IDs that need to be flushed (COW-updated)
+ * because the depsgraph itself created or removed some of their evaluated dependencies.
+ */
void update_invalid_cow_pointers();
/* State which demotes currently built entities. */
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc
index 17c2925b7f4..79f358213d3 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc
@@ -30,7 +30,6 @@
namespace blender::deg {
-/* Debug contents of map */
void RootPChanMap::print_debug()
{
map_.foreach_item([](StringRefNull key, const Set<StringRefNull> &values) {
@@ -42,13 +41,11 @@ void RootPChanMap::print_debug()
});
}
-/* Add a mapping. */
void RootPChanMap::add_bone(const char *bone, const char *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
{
const Set<StringRefNull> *bone1_roots = map_.lookup_ptr(bone1);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h
index 0dd4062c353..42f9ec9cc6a 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h
@@ -29,13 +29,13 @@ namespace blender {
namespace deg {
struct RootPChanMap {
- /* Debug contents of map. */
+ /** Debug contents of map. */
void print_debug();
- /* Add a mapping. */
+ /** Add a mapping. */
void add_bone(const char *bone, const char *root);
- /* Check if there's a common root bone between two bones. */
+ /** Check if there's a common root bone between two bones. */
bool has_common_root(const char *bone1, const char *bone2) const;
protected:
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index 55e8c5ed033..b195b2d9e11 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -368,6 +368,13 @@ Relation *DepsgraphRelationBuilder::add_time_relation(TimeSourceNode *timesrc,
return nullptr;
}
+void DepsgraphRelationBuilder::add_visibility_relation(ID *id_from, ID *id_to)
+{
+ ComponentKey from_key(id_from, NodeType::VISIBILITY);
+ ComponentKey to_key(id_to, NodeType::VISIBILITY);
+ add_relation(from_key, to_key, "visibility");
+}
+
Relation *DepsgraphRelationBuilder::add_operation_relation(OperationNode *node_from,
OperationNode *node_to,
const char *description,
@@ -2066,7 +2073,8 @@ void DepsgraphRelationBuilder::build_shapekeys(Key *key)
* and also for the links coming from the shapekey data-blocks
* - Animation/Drivers affecting the parameters of the geometry are made to
* trigger updates on the obdata geometry component, which then trigger
- * downstream re-evaluation of the individual instances of this geometry. */
+ * downstream re-evaluation of the individual instances of this geometry.
+ */
void DepsgraphRelationBuilder::build_object_data_geometry(Object *object)
{
ID *obdata = (ID *)object->data;
@@ -2521,16 +2529,13 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
}
OperationKey shading_update_key(&ntree->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE);
- OperationKey shading_parameters_key(
- &ntree->id, NodeType::SHADING_PARAMETERS, OperationCode::MATERIAL_UPDATE);
- add_relation(shading_parameters_key, shading_update_key, "NTree Shading Parameters");
if (check_id_has_anim_component(&ntree->id)) {
ComponentKey animation_key(&ntree->id, NodeType::ANIMATION);
- add_relation(animation_key, shading_parameters_key, "NTree Shading Parameters");
+ add_relation(animation_key, shading_update_key, "NTree Shading Parameters");
}
ComponentKey parameters_key(&ntree->id, NodeType::PARAMETERS);
- add_relation(parameters_key, shading_parameters_key, "NTree Shading Parameters");
+ add_relation(parameters_key, shading_update_key, "NTree Shading Parameters");
}
/* Recursively build graph for material */
@@ -2864,7 +2869,8 @@ void DepsgraphRelationBuilder::build_copy_on_write_relations()
}
}
-/* Nested datablocks (node trees, shape keys) requires special relation to
+/**
+ * Nested datablocks (node trees, shape keys) requires special relation to
* ensure owner's datablock remapping happens after node tree itself is ready.
*
* This is similar to what happens in ntree_hack_remap_pointers().
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
index f0393544511..09003de3ce4 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
@@ -336,6 +336,11 @@ class DepsgraphRelationBuilder : public DepsgraphBuilder {
Node *node_to,
const char *description,
int flags = 0);
+
+ /* Add relation which ensures visibility of `id_from` when `id_to` is visible.
+ * For the more detailed explanation see comment for `NodeType::VISIBILITY`. */
+ void add_visibility_relation(ID *id_from, ID *id_to);
+
Relation *add_operation_relation(OperationNode *node_from,
OperationNode *node_to,
const char *description,
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_drivers.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_drivers.cc
index bf3af571f0b..6e5c1f05cf3 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_drivers.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_drivers.cc
@@ -83,7 +83,6 @@ bool DriverDescriptor::is_array() const
return is_array_;
}
-/* Assumes that 'other' comes from the same RNA group, that is, has the same RNA path prefix. */
bool DriverDescriptor::is_same_array_as(const DriverDescriptor &other) const
{
if (!is_array_ || !other.is_array_) {
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_drivers.h b/source/blender/depsgraph/intern/builder/deg_builder_relations_drivers.h
index c80c69be9e2..4ad5bdda1ef 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_drivers.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_drivers.h
@@ -37,14 +37,17 @@ namespace deg {
/* Helper class for determining which relations are needed between driver evaluation nodes. */
class DriverDescriptor {
public:
- /* Drivers are grouped by their RNA prefix. The prefix is the part of the RNA
+ /**
+ * Drivers are grouped by their RNA prefix. The prefix is the part of the RNA
* path up to the last dot, the suffix is the remainder of the RNA path:
*
+ * \code{.unparsed}
* fcu->rna_path rna_prefix rna_suffix
* ------------------------------- ---------------------- ----------
* 'color' '' 'color'
* 'rigidbody_world.time_scale' 'rigidbody_world' 'time_scale'
* 'pose.bones["master"].location' 'pose.bones["master"]' 'location'
+ * \endcode
*/
StringRef rna_prefix;
StringRef rna_suffix;
@@ -54,7 +57,7 @@ class DriverDescriptor {
bool driver_relations_needed() const;
bool is_array() const;
- /* Assumes that 'other' comes from the same RNA group, that is, has the same RNA path prefix. */
+ /** Assumes that 'other' comes from the same RNA group, that is, has the same RNA path prefix. */
bool is_same_array_as(const DriverDescriptor &other) const;
OperationKey depsgraph_key() const;
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 4754749e2e5..3039eebe857 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
@@ -450,6 +450,7 @@ void DepsgraphRelationBuilder::build_rig(Object *object)
/* Custom shape. */
if (pchan->custom != nullptr) {
build_object(pchan->custom);
+ add_visibility_relation(&pchan->custom->id, &armature->id);
}
}
}
@@ -506,6 +507,12 @@ void DepsgraphRelationBuilder::build_proxy_rig(Object *object)
&proxy_from->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL, pchan->name);
add_relation(from_bone_parameters, bone_parameters, "Proxy Bone Parameters");
}
+
+ /* Custom shape. */
+ if (pchan->custom != nullptr) {
+ build_object(pchan->custom);
+ add_visibility_relation(&pchan->custom->id, &armature->id);
+ }
}
}
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 57c6f062611..7be661d9668 100644
--- a/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc
+++ b/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc
@@ -105,11 +105,10 @@ static const int deg_debug_node_type_color_map[][2] = {
{NodeType::GEOMETRY, 6},
{NodeType::SEQUENCER, 7},
{NodeType::SHADING, 8},
- {NodeType::SHADING_PARAMETERS, 9},
- {NodeType::CACHE, 10},
- {NodeType::POINT_CACHE, 11},
- {NodeType::LAYER_COLLECTIONS, 12},
- {NodeType::COPY_ON_WRITE, 13},
+ {NodeType::CACHE, 9},
+ {NodeType::POINT_CACHE, 10},
+ {NodeType::LAYER_COLLECTIONS, 11},
+ {NodeType::COPY_ON_WRITE, 12},
{-1, 0},
};
#endif
@@ -411,7 +410,6 @@ static void deg_debug_graphviz_node(DotExportContext &ctx,
case NodeType::EVAL_POSE:
case NodeType::BONE:
case NodeType::SHADING:
- case NodeType::SHADING_PARAMETERS:
case NodeType::CACHE:
case NodeType::POINT_CACHE:
case NodeType::IMAGE_ANIMATION:
@@ -426,6 +424,7 @@ static void deg_debug_graphviz_node(DotExportContext &ctx,
case NodeType::AUDIO:
case NodeType::ARMATURE:
case NodeType::GENERIC_DATABLOCK:
+ case NodeType::VISIBILITY:
case NodeType::SIMULATION: {
ComponentNode *comp_node = (ComponentNode *)node;
if (comp_node->operations.is_empty()) {
diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc
index 4c036417ba0..b348ab0f432 100644
--- a/source/blender/depsgraph/intern/depsgraph.cc
+++ b/source/blender/depsgraph/intern/depsgraph.cc
@@ -182,7 +182,6 @@ void Depsgraph::clear_id_nodes()
clear_physics_relations(this);
}
-/* Add new relation between two nodes */
Relation *Depsgraph::add_new_relation(Node *from, Node *to, const char *description, int flags)
{
Relation *rel = nullptr;
@@ -228,7 +227,6 @@ Relation *Depsgraph::check_nodes_connected(const Node *from,
/* Low level tagging -------------------------------------- */
-/* Tag a specific node as needing updates. */
void Depsgraph::add_entry_tag(OperationNode *node)
{
/* Sanity check. */
@@ -280,7 +278,6 @@ ID *Depsgraph::get_cow_id(const ID *id_orig) const
/* **************** */
/* Public Graph API */
-/* Initialize a new Depsgraph */
Depsgraph *DEG_graph_new(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluationMode mode)
{
deg::Depsgraph *deg_depsgraph = new deg::Depsgraph(bmain, scene, view_layer, mode);
@@ -288,10 +285,6 @@ Depsgraph *DEG_graph_new(Main *bmain, Scene *scene, ViewLayer *view_layer, eEval
return reinterpret_cast<Depsgraph *>(deg_depsgraph);
}
-/* Replace the "owner" pointers (currently Main/Scene/ViewLayer) of this depsgraph.
- * Used for:
- * - Undo steps when we do want to re-use the old depsgraph data as much as possible.
- * - Rendering where we want to re-use objects between different view layers. */
void DEG_graph_replace_owners(struct Depsgraph *depsgraph,
Main *bmain,
Scene *scene,
@@ -313,7 +306,6 @@ void DEG_graph_replace_owners(struct Depsgraph *depsgraph,
}
}
-/* Free graph's contents and graph itself */
void DEG_graph_free(Depsgraph *graph)
{
if (graph == nullptr) {
diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h
index 913b61ca563..bfe6ed649f6 100644
--- a/source/blender/depsgraph/intern/depsgraph.h
+++ b/source/blender/depsgraph/intern/depsgraph.h
@@ -72,7 +72,7 @@ struct Depsgraph {
IDNode *add_id_node(ID *id, ID *id_cow_hint = nullptr);
void clear_id_nodes();
- /* Add new relationship between two nodes. */
+ /** Add new relationship between two nodes. */
Relation *add_new_relation(Node *from, Node *to, const char *description, int flags = 0);
/* Check whether two nodes are connected by relation with given
diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc
index 9e9191c5ab9..db00c595383 100644
--- a/source/blender/depsgraph/intern/depsgraph_build.cc
+++ b/source/blender/depsgraph/intern/depsgraph_build.cc
@@ -252,7 +252,6 @@ struct Depsgraph *DEG_get_graph_from_handle(struct DepsNodeHandle *node_handle)
/* ******************** */
/* Graph Building API's */
-/* Build depsgraph for the given scene layer, and dump results in given graph container. */
void DEG_graph_build_from_view_layer(Depsgraph *graph)
{
deg::ViewLayerBuilderPipeline builder(graph);
@@ -283,7 +282,6 @@ void DEG_graph_build_from_ids(Depsgraph *graph, ID **ids, const int num_ids)
builder.build();
}
-/* Tag graph relations for update. */
void DEG_graph_tag_relations_update(Depsgraph *graph)
{
DEG_DEBUG_PRINTF(graph, TAG, "%s: Tagging relations for update.\n", __func__);
@@ -301,7 +299,6 @@ void DEG_graph_tag_relations_update(Depsgraph *graph)
}
}
-/* Create or update relations in the specified graph. */
void DEG_graph_relations_update(Depsgraph *graph)
{
deg::Depsgraph *deg_graph = (deg::Depsgraph *)graph;
@@ -312,7 +309,6 @@ void DEG_graph_relations_update(Depsgraph *graph)
DEG_graph_build_from_view_layer(graph);
}
-/* Tag all relations for update. */
void DEG_relations_tag_update(Main *bmain)
{
DEG_GLOBAL_DEBUG_PRINTF(TAG, "%s: Tagging relations for update.\n", __func__);
diff --git a/source/blender/depsgraph/intern/depsgraph_debug.cc b/source/blender/depsgraph/intern/depsgraph_debug.cc
index 3677f80469c..9e3cbdbec09 100644
--- a/source/blender/depsgraph/intern/depsgraph_debug.cc
+++ b/source/blender/depsgraph/intern/depsgraph_debug.cc
@@ -196,12 +196,6 @@ bool DEG_debug_consistency_check(Depsgraph *graph)
/* ------------------------------------------------ */
-/**
- * Obtain simple statistics about the complexity of the depsgraph.
- * \param[out] r_outer: The number of outer nodes in the graph
- * \param[out] r_operations: The number of operation nodes in the graph
- * \param[out] r_relations: The number of relations between (executable) nodes in the graph
- */
void DEG_stats_simple(const Depsgraph *graph,
size_t *r_outer,
size_t *r_operations,
diff --git a/source/blender/depsgraph/intern/depsgraph_eval.cc b/source/blender/depsgraph/intern/depsgraph_eval.cc
index 0314219b725..7952f27507f 100644
--- a/source/blender/depsgraph/intern/depsgraph_eval.cc
+++ b/source/blender/depsgraph/intern/depsgraph_eval.cc
@@ -60,7 +60,6 @@ static void deg_flush_updates_and_refresh(deg::Depsgraph *deg_graph)
deg::deg_evaluate_on_refresh(deg_graph);
}
-/* Evaluate all nodes tagged for updating. */
void DEG_evaluate_on_refresh(Depsgraph *graph)
{
deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(graph);
@@ -77,7 +76,6 @@ void DEG_evaluate_on_refresh(Depsgraph *graph)
deg_flush_updates_and_refresh(deg_graph);
}
-/* Frame-change happened for root scene that graph belongs to. */
void DEG_evaluate_on_framechange(Depsgraph *graph, float frame)
{
deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(graph);
diff --git a/source/blender/depsgraph/intern/depsgraph_query.cc b/source/blender/depsgraph/intern/depsgraph_query.cc
index aab4c3ca0f6..6c1947728b5 100644
--- a/source/blender/depsgraph/intern/depsgraph_query.cc
+++ b/source/blender/depsgraph/intern/depsgraph_query.cc
@@ -200,7 +200,6 @@ ID *DEG_get_evaluated_id(const Depsgraph *depsgraph, ID *id)
return id_node->id_cow;
}
-/* Get evaluated version of data pointed to by RNA pointer */
void DEG_get_evaluated_rna_pointer(const Depsgraph *depsgraph,
PointerRNA *ptr,
PointerRNA *r_ptr_eval)
diff --git a/source/blender/depsgraph/intern/depsgraph_query_foreach.cc b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc
index 6ce7cc0837b..65a21323258 100644
--- a/source/blender/depsgraph/intern/depsgraph_query_foreach.cc
+++ b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc
@@ -77,6 +77,12 @@ void deg_foreach_dependent_operation(const Depsgraph *UNUSED(graph),
TraversalQueue queue;
Set<OperationNode *> scheduled;
for (ComponentNode *comp_node : target_id_node->components.values()) {
+ if (comp_node->type == NodeType::VISIBILITY) {
+ /* Visibility component is only used internally. It is not to be reporting dependencies to
+ * the outer world. */
+ continue;
+ }
+
if (source_component_type != DEG_OB_COMP_ANY &&
nodeTypeToObjectComponent(comp_node->type) != source_component_type) {
continue;
diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc
index dd96c5a3b2b..2b0d0e6e780 100644
--- a/source/blender/depsgraph/intern/depsgraph_tag.cc
+++ b/source/blender/depsgraph/intern/depsgraph_tag.cc
@@ -193,12 +193,7 @@ void depsgraph_tag_to_component_opcode(const ID *id,
*component_type = NodeType::COPY_ON_WRITE;
break;
case ID_RECALC_SHADING:
- if (id_type == ID_NT) {
- *component_type = NodeType::SHADING_PARAMETERS;
- }
- else {
- *component_type = NodeType::SHADING;
- }
+ *component_type = NodeType::SHADING;
break;
case ID_RECALC_SELECT:
depsgraph_select_tag_to_component_opcode(id, component_type, operation_code);
@@ -760,7 +755,6 @@ const char *DEG_update_tag_as_string(IDRecalcFlag flag)
/* Data-Based Tagging. */
-/* Tag given ID for an update in all the dependency graphs. */
void DEG_id_tag_update(ID *id, int flag)
{
DEG_id_tag_update_ex(G.main, id, flag);
@@ -797,7 +791,6 @@ void DEG_graph_time_tag_update(struct Depsgraph *depsgraph)
deg_graph->tag_time_source();
}
-/* Mark a particular data-block type as having changing. */
void DEG_graph_id_type_tag(Depsgraph *depsgraph, short id_type)
{
if (id_type == ID_NT) {
@@ -822,7 +815,6 @@ void DEG_id_type_tag(Main *bmain, short id_type)
}
}
-/* Update dependency graph when visible scenes/layers changes. */
void DEG_graph_tag_on_visible_update(Depsgraph *depsgraph, const bool do_time)
{
deg::Depsgraph *graph = (deg::Depsgraph *)depsgraph;
@@ -842,8 +834,6 @@ void DEG_enable_editors_update(Depsgraph *depsgraph)
graph->use_editors_update = true;
}
-/* Check if something was changed in the database and inform
- * editors about this. */
void DEG_editors_update(Depsgraph *depsgraph, bool time)
{
deg::Depsgraph *graph = (deg::Depsgraph *)depsgraph;
diff --git a/source/blender/depsgraph/intern/depsgraph_type.cc b/source/blender/depsgraph/intern/depsgraph_type.cc
index 07664cb4f0b..0405a7d90b4 100644
--- a/source/blender/depsgraph/intern/depsgraph_type.cc
+++ b/source/blender/depsgraph/intern/depsgraph_type.cc
@@ -39,8 +39,7 @@
namespace deg = blender::deg;
-/* Register all node types */
-void DEG_register_node_types(void)
+void DEG_register_node_types()
{
/* register node types */
deg::deg_register_base_depsnodes();
@@ -48,8 +47,7 @@ void DEG_register_node_types(void)
deg::deg_register_operation_depsnodes();
}
-/* Free registry on exit */
-void DEG_free_node_types(void)
+void DEG_free_node_types()
{
}
diff --git a/source/blender/depsgraph/intern/depsgraph_update.cc b/source/blender/depsgraph/intern/depsgraph_update.cc
index bb72320ca67..ec287edbd12 100644
--- a/source/blender/depsgraph/intern/depsgraph_update.cc
+++ b/source/blender/depsgraph/intern/depsgraph_update.cc
@@ -50,7 +50,6 @@ void deg_editors_scene_update(const DEGEditorUpdateContext *update_ctx, bool upd
} // namespace blender::deg
-/* Set callbacks which are being called when depsgraph changes. */
void DEG_editors_set_update_cb(DEG_EditorUpdateIDCb id_func, DEG_EditorUpdateSceneCb scene_func)
{
deg::deg_editor_update_id_cb = id_func;
diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc
index d6877adb66b..30aeeee5b2c 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval.cc
@@ -361,13 +361,6 @@ static TaskPool *deg_evaluate_task_pool_create(DepsgraphEvalState *state)
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
- * called from frame-change update.
- *
- * \note Time sources should be all valid!
- */
void deg_evaluate_on_refresh(Depsgraph *graph)
{
/* Nothing to update, early out. */
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc
index 68a72638c7d..116dba054fa 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc
@@ -906,7 +906,9 @@ ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph, const IDNode
return id_cow;
}
-/* NOTE: Depsgraph is supposed to have ID node already. */
+/**
+ * \note Depsgraph is supposed to have ID node already.
+ */
ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph, ID *id_orig)
{
IDNode *id_node = depsgraph->find_id_node(id_orig);
@@ -987,10 +989,12 @@ void discard_edit_mode_pointers(ID *id_cow)
} // namespace
-/* Free content of the CoW data-block
+/**
+ Free content of the CoW data-block.
* Notes:
* - Does not recurse into nested ID data-blocks.
- * - Does not free data-block itself. */
+ * - Does not free data-block itself.
+ */
void deg_free_copy_on_write_datablock(ID *id_cow)
{
if (!check_datablock_expanded(id_cow)) {
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h
index 70e510b5ef9..bc023766a46 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h
+++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h
@@ -50,34 +50,40 @@ struct Depsgraph;
class DepsgraphNodeBuilder;
struct IDNode;
-/* Makes sure given CoW data-block is brought back to state of the original
+/**
+ * Makes sure given CoW data-block is brought back to state of the original
* data-block.
*/
ID *deg_update_copy_on_write_datablock(const struct Depsgraph *depsgraph, const IDNode *id_node);
ID *deg_update_copy_on_write_datablock(const struct Depsgraph *depsgraph, struct ID *id_orig);
-/* Helper function which frees memory used by copy-on-written data-block. */
+/** Helper function which frees memory used by copy-on-written data-block. */
void deg_free_copy_on_write_datablock(struct ID *id_cow);
-/* Callback function for depsgraph operation node which ensures copy-on-write
+/**
+ * Callback function for depsgraph operation node which ensures copy-on-write
* data-block is ready for use by further evaluation routines.
*/
void deg_evaluate_copy_on_write(struct ::Depsgraph *depsgraph, const struct IDNode *id_node);
-/* Check that given ID is properly expanded and does not have any shallow
- * copies inside. */
+/**
+ * Check that given ID is properly expanded and does not have any shallow
+ * copies inside.
+ */
bool deg_validate_copy_on_write_datablock(ID *id_cow);
-/* Tag given ID block as being copy-on-written. */
+/** Tag given ID block as being copy-on-written. */
void deg_tag_copy_on_write_id(struct ID *id_cow, const struct ID *id_orig);
-/* Check whether ID data-block is expanded.
+/**
+ * Check whether ID data-block is expanded.
*
* TODO(sergey): Make it an inline function or a macro.
*/
bool deg_copy_on_write_is_expanded(const struct ID *id_cow);
-/* Check whether copy-on-write data-block is needed for given ID.
+/**
+ * Check whether copy-on-write data-block is needed for given ID.
*
* There are some exceptions on data-blocks which are covered by dependency graph
* but which we don't want to start duplicating.
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
index a015491e2d7..7ec77689ba5 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
@@ -346,9 +346,6 @@ void invalidate_tagged_evaluated_data(Depsgraph *graph)
} // namespace
-/* Flush updates from tagged nodes outwards until all affected nodes
- * are tagged.
- */
void deg_graph_flush_updates(Depsgraph *graph)
{
/* Sanity checks. */
@@ -395,7 +392,6 @@ void deg_graph_flush_updates(Depsgraph *graph)
invalidate_tagged_evaluated_data(graph);
}
-/* Clear tags from all operation nodes. */
void deg_graph_clear_tags(Depsgraph *graph)
{
/* Go over all operation nodes, clearing tags. */
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.h b/source/blender/depsgraph/intern/eval/deg_eval_flush.h
index ec661360fdf..d70df62cb38 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_flush.h
+++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.h
@@ -30,12 +30,14 @@ namespace deg {
struct Depsgraph;
-/* Flush updates from tagged nodes outwards until all affected nodes
- * are tagged.
+/**
+ * Flush updates from tagged nodes outwards until all affected nodes are tagged.
*/
void deg_graph_flush_updates(struct Depsgraph *graph);
-/* Clear tags from all operation nodes. */
+/**
+ * Clear tags from all operation nodes.
+ */
void deg_graph_clear_tags(struct Depsgraph *graph);
} // namespace deg
diff --git a/source/blender/depsgraph/intern/node/deg_node.cc b/source/blender/depsgraph/intern/node/deg_node.cc
index 16089ba27dd..8bc03d8b736 100644
--- a/source/blender/depsgraph/intern/node/deg_node.cc
+++ b/source/blender/depsgraph/intern/node/deg_node.cc
@@ -94,8 +94,6 @@ const char *nodeTypeAsString(NodeType type)
return "PARTICLE_SETTINGS";
case NodeType::SHADING:
return "SHADING";
- case NodeType::SHADING_PARAMETERS:
- return "SHADING_PARAMETERS";
case NodeType::CACHE:
return "CACHE";
case NodeType::POINT_CACHE:
@@ -114,6 +112,8 @@ const char *nodeTypeAsString(NodeType type)
return "ARMATURE";
case NodeType::GENERIC_DATABLOCK:
return "GENERIC_DATABLOCK";
+ case NodeType::VISIBILITY:
+ return "VISIBILITY";
case NodeType::SIMULATION:
return "SIMULATION";
@@ -159,7 +159,6 @@ eDepsSceneComponentType nodeTypeToSceneComponent(NodeType type)
case NodeType::GENERIC_DATABLOCK:
case NodeType::PARTICLE_SYSTEM:
case NodeType::PARTICLE_SETTINGS:
- case NodeType::SHADING_PARAMETERS:
case NodeType::POINT_CACHE:
case NodeType::IMAGE_ANIMATION:
case NodeType::BATCH_CACHE:
@@ -176,6 +175,10 @@ eDepsSceneComponentType nodeTypeToSceneComponent(NodeType type)
case NodeType::PROXY:
case NodeType::SIMULATION:
return DEG_SCENE_COMP_PARAMETERS;
+
+ case NodeType::VISIBILITY:
+ BLI_assert_msg(0, "Visibility component is supposed to be only used internally.");
+ return DEG_SCENE_COMP_PARAMETERS;
}
BLI_assert_msg(0, "Unhandled node type, not supposed to happen.");
return DEG_SCENE_COMP_PARAMETERS;
@@ -242,7 +245,6 @@ eDepsObjectComponentType nodeTypeToObjectComponent(NodeType type)
case NodeType::GENERIC_DATABLOCK:
case NodeType::PARTICLE_SYSTEM:
case NodeType::PARTICLE_SETTINGS:
- case NodeType::SHADING_PARAMETERS:
case NodeType::POINT_CACHE:
case NodeType::IMAGE_ANIMATION:
case NodeType::BATCH_CACHE:
@@ -252,6 +254,10 @@ eDepsObjectComponentType nodeTypeToObjectComponent(NodeType type)
case NodeType::UNDEFINED:
case NodeType::NUM_TYPES:
return DEG_OB_COMP_PARAMETERS;
+
+ case NodeType::VISIBILITY:
+ BLI_assert_msg(0, "Visibility component is supposed to be only used internally.");
+ return DEG_OB_COMP_PARAMETERS;
}
BLI_assert_msg(0, "Unhandled node type, not suppsed to happen.");
return DEG_OB_COMP_PARAMETERS;
@@ -305,7 +311,6 @@ Node::~Node()
}
}
-/* Generic identifier for Depsgraph Nodes. */
string Node::identifier() const
{
return string(nodeTypeAsString(type)) + " : " + name;
diff --git a/source/blender/depsgraph/intern/node/deg_node.h b/source/blender/depsgraph/intern/node/deg_node.h
index e1469b68b0e..7e093ab8765 100644
--- a/source/blender/depsgraph/intern/node/deg_node.h
+++ b/source/blender/depsgraph/intern/node/deg_node.h
@@ -103,6 +103,22 @@ enum class NodeType {
* not have very distinctive update procedure. */
GENERIC_DATABLOCK,
+ /* Component which is used to define visibility relation between IDs, on the ID level.
+ *
+ * Consider two ID nodes NodeA and NodeB, with the relation between visibility components going
+ * as NodeA -> NodeB. If NodeB is considered visible on screen, then the relation will ensure
+ * that NodeA is also visible. The way how relation is oriented could be seen as a inverted from
+ * visibility dependency point of view, but it follows the same direction as data dependency
+ * which simplifies common algorithms which are dealing with relations and visibility.
+ *
+ * The fact that the visibility operates on the ID level basically means that all components in
+ * NodeA will be considered as affecting directly visible when NodeB's visibility is
+ * affecting directly visible ID.
+ *
+ * This is the way to ensure objects needed for visualization without any actual data dependency
+ * are properly evaluated. Example of this is custom shapes for bones. */
+ VISIBILITY,
+
/* **** Evaluation-Related Outer Types (with Subdata) **** */
/* Pose Component - Owner/Container of Bones Eval */
@@ -114,7 +130,6 @@ enum class NodeType {
PARTICLE_SETTINGS,
/* Material Shading Component */
SHADING,
- SHADING_PARAMETERS,
/* Point cache Component */
POINT_CACHE,
/* Image Animation Component */
@@ -186,6 +201,7 @@ struct Node {
Node();
virtual ~Node();
+ /** Generic identifier for Depsgraph Nodes. */
virtual string identifier() const;
virtual void init(const ID * /*id*/, const char * /*subdata*/)
diff --git a/source/blender/depsgraph/intern/node/deg_node_component.cc b/source/blender/depsgraph/intern/node/deg_node_component.cc
index 0947fad7670..b716877902c 100644
--- a/source/blender/depsgraph/intern/node/deg_node_component.cc
+++ b/source/blender/depsgraph/intern/node/deg_node_component.cc
@@ -43,7 +43,9 @@ namespace blender::deg {
/* *********** */
/* Outer Nodes */
-/* Standard Component Methods ============================= */
+/* -------------------------------------------------------------------- */
+/** \name Standard Component Methods
+ * \{ */
ComponentNode::OperationIDKey::OperationIDKey()
: opcode(OperationCode::OPERATION), name(""), name_tag(-1)
@@ -86,7 +88,6 @@ ComponentNode::ComponentNode()
operations_map = new Map<ComponentNode::OperationIDKey, OperationNode *>();
}
-/* Initialize 'component' node - from pointer data given */
void ComponentNode::init(const ID * /*id*/, const char * /*subdata*/)
{
/* hook up eval context? */
@@ -297,9 +298,12 @@ void ComponentNode::finalize_build(Depsgraph * /*graph*/)
operations_map = nullptr;
}
-/* Bone Component ========================================= */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Bone Component
+ * \{ */
-/* Initialize 'bone component' node - from pointer data given */
void BoneComponentNode::init(const ID *id, const char *subdata)
{
/* generic component-node... */
@@ -315,7 +319,11 @@ void BoneComponentNode::init(const ID *id, const char *subdata)
this->pchan = BKE_pose_channel_find_name(object->pose, subdata);
}
-/* Register all components. =============================== */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Register All Components
+ * \{ */
DEG_COMPONENT_NODE_DEFINE(Animation, ANIMATION, ID_RECALC_ANIMATION);
/* TODO(sergey): Is this a correct tag? */
@@ -334,7 +342,6 @@ DEG_COMPONENT_NODE_DEFINE(Pose, EVAL_POSE, ID_RECALC_GEOMETRY);
DEG_COMPONENT_NODE_DEFINE(Proxy, PROXY, ID_RECALC_GEOMETRY);
DEG_COMPONENT_NODE_DEFINE(Sequencer, SEQUENCER, 0);
DEG_COMPONENT_NODE_DEFINE(Shading, SHADING, ID_RECALC_SHADING);
-DEG_COMPONENT_NODE_DEFINE(ShadingParameters, SHADING_PARAMETERS, ID_RECALC_SHADING);
DEG_COMPONENT_NODE_DEFINE(Transform, TRANSFORM, ID_RECALC_TRANSFORM);
DEG_COMPONENT_NODE_DEFINE(ObjectFromLayer, OBJECT_FROM_LAYER, 0);
DEG_COMPONENT_NODE_DEFINE(Dupli, DUPLI, 0);
@@ -342,9 +349,14 @@ DEG_COMPONENT_NODE_DEFINE(Synchronization, SYNCHRONIZATION, 0);
DEG_COMPONENT_NODE_DEFINE(Audio, AUDIO, 0);
DEG_COMPONENT_NODE_DEFINE(Armature, ARMATURE, 0);
DEG_COMPONENT_NODE_DEFINE(GenericDatablock, GENERIC_DATABLOCK, 0);
+DEG_COMPONENT_NODE_DEFINE(Visibility, VISIBILITY, 0);
DEG_COMPONENT_NODE_DEFINE(Simulation, SIMULATION, 0);
-/* Node Types Register =================================== */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Node Types Register
+ * \{ */
void deg_register_component_depsnodes()
{
@@ -364,7 +376,6 @@ void deg_register_component_depsnodes()
register_node_typeinfo(&DNTI_EVAL_POSE);
register_node_typeinfo(&DNTI_SEQUENCER);
register_node_typeinfo(&DNTI_SHADING);
- register_node_typeinfo(&DNTI_SHADING_PARAMETERS);
register_node_typeinfo(&DNTI_TRANSFORM);
register_node_typeinfo(&DNTI_OBJECT_FROM_LAYER);
register_node_typeinfo(&DNTI_DUPLI);
@@ -372,7 +383,10 @@ void deg_register_component_depsnodes()
register_node_typeinfo(&DNTI_AUDIO);
register_node_typeinfo(&DNTI_ARMATURE);
register_node_typeinfo(&DNTI_GENERIC_DATABLOCK);
+ register_node_typeinfo(&DNTI_VISIBILITY);
register_node_typeinfo(&DNTI_SIMULATION);
}
+/** \} */
+
} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/node/deg_node_component.h b/source/blender/depsgraph/intern/node/deg_node_component.h
index 6e31ef268ed..9f108af8012 100644
--- a/source/blender/depsgraph/intern/node/deg_node_component.h
+++ b/source/blender/depsgraph/intern/node/deg_node_component.h
@@ -67,6 +67,7 @@ struct ComponentNode : public Node {
ComponentNode();
~ComponentNode();
+ /** Initialize 'component' node - from pointer data given. */
void init(const ID *id, const char *subdata) override;
virtual string identifier() const override;
@@ -188,6 +189,15 @@ struct ComponentNode : public Node {
} \
}
+#define DEG_COMPONENT_NODE_DECLARE_NO_COW(name) \
+ struct name##ComponentNode : public ComponentNode { \
+ DEG_COMPONENT_NODE_DECLARE; \
+ virtual bool depends_on_cow() \
+ { \
+ return false; \
+ } \
+ }
+
DEG_COMPONENT_NODE_DECLARE_GENERIC(Animation);
DEG_COMPONENT_NODE_DECLARE_NO_COW_TAG_ON_UPDATE(BatchCache);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Cache);
@@ -210,10 +220,12 @@ DEG_COMPONENT_NODE_DECLARE_GENERIC(Synchronization);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Audio);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Armature);
DEG_COMPONENT_NODE_DECLARE_GENERIC(GenericDatablock);
+DEG_COMPONENT_NODE_DECLARE_NO_COW(Visibility);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Simulation);
/* Bone Component */
struct BoneComponentNode : public ComponentNode {
+ /** Initialize 'bone component' node - from pointer data given. */
void init(const ID *id, const char *subdata);
struct bPoseChannel *pchan; /* the bone that this component represents */
diff --git a/source/blender/depsgraph/intern/node/deg_node_id.cc b/source/blender/depsgraph/intern/node/deg_node_id.cc
index 2b1ebc663fe..baad8318de2 100644
--- a/source/blender/depsgraph/intern/node/deg_node_id.cc
+++ b/source/blender/depsgraph/intern/node/deg_node_id.cc
@@ -73,7 +73,6 @@ uint64_t IDNode::ComponentIDKey::hash() const
BLI_ghashutil_strhash_p(name));
}
-/* Initialize 'id' node - from pointer data given. */
void IDNode::init(const ID *id, const char *UNUSED(subdata))
{
BLI_assert(id != nullptr);
diff --git a/source/blender/depsgraph/intern/node/deg_node_id.h b/source/blender/depsgraph/intern/node/deg_node_id.h
index 073469598dc..257e42b8e67 100644
--- a/source/blender/depsgraph/intern/node/deg_node_id.h
+++ b/source/blender/depsgraph/intern/node/deg_node_id.h
@@ -58,6 +58,7 @@ struct IDNode : public Node {
const char *name;
};
+ /** Initialize 'id' node - from pointer data given. */
virtual void init(const ID *id, const char *subdata) override;
void init_copy_on_write(ID *id_cow_hint = nullptr);
~IDNode();
diff --git a/source/blender/depsgraph/intern/node/deg_node_operation.cc b/source/blender/depsgraph/intern/node/deg_node_operation.cc
index c25dc6fc8d5..eaae5d2d5dc 100644
--- a/source/blender/depsgraph/intern/node/deg_node_operation.cc
+++ b/source/blender/depsgraph/intern/node/deg_node_operation.cc
@@ -218,8 +218,6 @@ string OperationNode::identifier() const
return string(operationCodeAsString(opcode)) + "(" + name + ")";
}
-/* Full node identifier, including owner name.
- * used for logging and debug prints. */
string OperationNode::full_identifier() const
{
string owner_str = owner->owner->name;
diff --git a/source/blender/depsgraph/intern/node/deg_node_operation.h b/source/blender/depsgraph/intern/node/deg_node_operation.h
index a17186da941..31cbb9702ba 100644
--- a/source/blender/depsgraph/intern/node/deg_node_operation.h
+++ b/source/blender/depsgraph/intern/node/deg_node_operation.h
@@ -233,6 +233,10 @@ struct OperationNode : public Node {
OperationNode();
virtual string identifier() const override;
+ /**
+ * Full node identifier, including owner name.
+ * used for logging and debug prints.
+ */
string full_identifier() const;
virtual void tag_update(Depsgraph *graph, eUpdateSource source) override;
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index b8ca22d33d3..30a3b8087c0 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -223,6 +223,9 @@ set(SRC
engines/external/external_engine.h
engines/image/image_engine.h
engines/image/image_private.hh
+ engines/image/image_drawing_mode_image_space.hh
+ engines/image/image_space_image.hh
+ engines/image/image_space_node.hh
engines/workbench/workbench_engine.h
engines/workbench/workbench_private.h
engines/select/select_engine.h
diff --git a/source/blender/draw/DRW_engine.h b/source/blender/draw/DRW_engine.h
index af6c8ea62b2..98e166ac3a7 100644
--- a/source/blender/draw/DRW_engine.h
+++ b/source/blender/draw/DRW_engine.h
@@ -75,9 +75,21 @@ typedef enum eDRWSelectStage {
typedef bool (*DRW_SelectPassFn)(eDRWSelectStage stage, void *user_data);
typedef bool (*DRW_ObjectFilterFn)(struct Object *ob, void *user_data);
+/**
+ * Everything starts here.
+ * This function takes care of calling all cache and rendering functions
+ * for each relevant engine / mode engine.
+ */
void DRW_draw_view(const struct bContext *C);
+/**
+ * Draw render engine info.
+ */
void DRW_draw_region_engine_info(int xoffset, int *yoffset, int line_height);
+/**
+ * Used for both regular and off-screen drawing.
+ * Need to reset DST before calling this function
+ */
void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph,
struct RenderEngineType *engine_type,
struct ARegion *region,
@@ -88,6 +100,9 @@ void DRW_draw_render_loop(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
struct GPUViewport *viewport);
+/**
+ * \param viewport: can be NULL, in this case we create one.
+ */
void DRW_draw_render_loop_offscreen(struct Depsgraph *depsgraph,
struct RenderEngineType *engine_type,
struct ARegion *region,
@@ -101,6 +116,9 @@ void DRW_draw_render_loop_2d_ex(struct Depsgraph *depsgraph,
struct ARegion *region,
struct GPUViewport *viewport,
const struct bContext *evil_C);
+/**
+ * object mode select-loop, see: #ED_view3d_draw_select_loop (legacy drawing).
+ */
void DRW_draw_select_loop(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
@@ -113,14 +131,23 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
void *select_pass_user_data,
DRW_ObjectFilterFn object_filter_fn,
void *object_filter_user_data);
+/**
+ * object mode select-loop, see: #ED_view3d_draw_depth_loop (legacy drawing).
+ */
void DRW_draw_depth_loop(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
struct GPUViewport *viewport);
+/**
+ * Converted from #ED_view3d_draw_depth_gpencil (legacy drawing).
+ */
void DRW_draw_depth_loop_gpencil(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
struct GPUViewport *viewport);
+/**
+ * Clears the Depth Buffer and draws only the specified object.
+ */
void DRW_draw_depth_object(struct Scene *scene,
struct ARegion *region,
struct View3D *v3d,
@@ -131,11 +158,17 @@ void DRW_draw_select_id(struct Depsgraph *depsgraph,
struct View3D *v3d,
const struct rcti *rect);
-/* grease pencil render */
+/* Grease pencil render. */
+
+/**
+ * Helper to check if exit object type to render.
+ */
bool DRW_render_check_grease_pencil(struct Depsgraph *depsgraph);
void DRW_render_gpencil(struct RenderEngine *engine, struct Depsgraph *depsgraph);
-/* This is here because GPUViewport needs it */
+/**
+ * This is here because #GPUViewport needs it.
+ */
struct DRWInstanceDataList *DRW_instance_data_list_create(void);
void DRW_instance_data_list_free(struct DRWInstanceDataList *idatalist);
void DRW_uniform_attrs_pool_free(struct GHash *table);
@@ -165,11 +198,21 @@ void DRW_opengl_context_disable_ex(bool restore);
void DRW_opengl_render_context_enable(void *re_gl_context);
void DRW_opengl_render_context_disable(void *re_gl_context);
+/**
+ * Needs to be called AFTER #DRW_opengl_render_context_enable().
+ */
void DRW_gpu_render_context_enable(void *re_gpu_context);
+/**
+ * Needs to be called BEFORE #DRW_opengl_render_context_disable().
+ */
void DRW_gpu_render_context_disable(void *re_gpu_context);
void DRW_deferred_shader_remove(struct GPUMaterial *mat);
+/**
+ * Get DrawData from the given ID-block. In order for this to work, we assume that
+ * the DrawData pointer is stored in the struct in the same fashion as in #IdDdtTemplate.
+ */
struct DrawDataList *DRW_drawdatalist_from_id(struct ID *id);
void DRW_drawdata_free(struct ID *id);
@@ -179,7 +222,10 @@ void DRW_viewport_data_free(struct DRWData *drw_data);
bool DRW_opengl_context_release(void);
void DRW_opengl_context_activate(bool drw_state);
-/* We may want to move this into a more general location. */
+/**
+ * We may want to move this into a more general location.
+ * \note This doesn't require the draw context to be in use.
+ */
void DRW_draw_cursor_2d_ex(const struct ARegion *region, const float cursor[2]);
#ifdef __cplusplus
diff --git a/source/blender/draw/DRW_select_buffer.h b/source/blender/draw/DRW_select_buffer.h
index 43d4005c3a9..18134558af8 100644
--- a/source/blender/draw/DRW_select_buffer.h
+++ b/source/blender/draw/DRW_select_buffer.h
@@ -81,6 +81,7 @@ typedef struct SELECTID_Context {
} SELECTID_Context;
/* draw_select_buffer.c */
+
bool DRW_select_buffer_elem_get(const uint sel_id,
uint *r_elem,
uint *r_base_index,
@@ -88,22 +89,41 @@ bool DRW_select_buffer_elem_get(const uint sel_id,
uint DRW_select_buffer_context_offset_for_object_elem(struct Depsgraph *depsgraph,
struct Object *object,
char elem_type);
+/**
+ * Main function to read a block of pixels from the select frame buffer.
+ */
uint *DRW_select_buffer_read(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
const rcti *rect,
uint *r_buf_len);
+/**
+ * \param rect: The rectangle to sample indices from (min/max inclusive).
+ * \returns a #BLI_bitmap the length of \a bitmap_len or NULL on failure.
+ */
uint *DRW_select_buffer_bitmap_from_rect(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
const struct rcti *rect,
uint *r_bitmap_len);
+/**
+ * \param center: Circle center.
+ * \param radius: Circle radius.
+ * \param r_bitmap_len: Number of indices in the selection id buffer.
+ * \returns a #BLI_bitmap the length of \a r_bitmap_len or NULL on failure.
+ */
uint *DRW_select_buffer_bitmap_from_circle(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
const int center[2],
const int radius,
uint *r_bitmap_len);
+/**
+ * \param poly: The polygon coordinates.
+ * \param poly_len: Length of the polygon.
+ * \param rect: Polygon boundaries.
+ * \returns a #BLI_bitmap.
+ */
uint *DRW_select_buffer_bitmap_from_poly(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
@@ -111,10 +131,18 @@ uint *DRW_select_buffer_bitmap_from_poly(struct Depsgraph *depsgraph,
const int poly_len,
const struct rcti *rect,
uint *r_bitmap_len);
+/**
+ * Samples a single pixel.
+ */
uint DRW_select_buffer_sample_point(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
const int center[2]);
+/**
+ * Find the selection id closest to \a center.
+ * \param dist: Use to initialize the distance,
+ * when found, this value is set to the distance of the selection that's returned.
+ */
uint DRW_select_buffer_find_nearest_to_point(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
diff --git a/source/blender/draw/engines/basic/basic_engine.c b/source/blender/draw/engines/basic/basic_engine.c
index 8a825a7c81f..228281af2b0 100644
--- a/source/blender/draw/engines/basic/basic_engine.c
+++ b/source/blender/draw/engines/basic/basic_engine.c
@@ -265,6 +265,7 @@ DrawEngineType draw_engine_basic_type = {
&basic_data_size,
NULL,
&basic_engine_free,
+ NULL, /* instance_free */
&basic_cache_init,
&basic_cache_populate,
&basic_cache_finish,
diff --git a/source/blender/draw/engines/eevee/eevee_cryptomatte.c b/source/blender/draw/engines/eevee/eevee_cryptomatte.c
index 1b8e967e38f..80207523a65 100644
--- a/source/blender/draw/engines/eevee/eevee_cryptomatte.c
+++ b/source/blender/draw/engines/eevee/eevee_cryptomatte.c
@@ -435,9 +435,6 @@ void EEVEE_cryptomatte_output_accumulate(EEVEE_ViewLayerData *UNUSED(sldata), EE
/** \name Update Render Passes
* \{ */
-/* Register the render passes needed for cryptomatte
- * normally this is done in `EEVEE_render_update_passes`, but it has been placed here to keep
- * related code side-by-side for clarity. */
void EEVEE_cryptomatte_update_passes(RenderEngine *engine, Scene *scene, ViewLayer *view_layer)
{
char cryptomatte_pass_name[MAX_NAME];
diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c
index c2f3e3a6d95..3d32b4acd82 100644
--- a/source/blender/draw/engines/eevee/eevee_effects.c
+++ b/source/blender/draw/engines/eevee/eevee_effects.c
@@ -411,9 +411,6 @@ static void downsample_radiance_cb(void *vedata, int level)
DRW_draw_pass(psl->color_downsample_ps);
}
-/**
- * Simple down-sampling algorithm. Reconstruct mip chain up to mip level.
- */
void EEVEE_effects_downsample_radiance_buffer(EEVEE_Data *vedata, GPUTexture *texture_src)
{
EEVEE_PassList *psl = vedata->psl;
@@ -430,9 +427,6 @@ void EEVEE_effects_downsample_radiance_buffer(EEVEE_Data *vedata, GPUTexture *te
DRW_stats_group_end();
}
-/**
- * Simple down-sampling algorithm for cube-map. Reconstruct mip chain up to mip level.
- */
void EEVEE_downsample_cube_buffer(EEVEE_Data *vedata, GPUTexture *texture_src, int level)
{
EEVEE_FramebufferList *fbl = vedata->fbl;
diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c
index fad9d21b660..fc9b8b0cde4 100644
--- a/source/blender/draw/engines/eevee/eevee_engine.c
+++ b/source/blender/draw/engines/eevee/eevee_engine.c
@@ -629,6 +629,7 @@ DrawEngineType draw_engine_eevee_type = {
&eevee_data_size,
&eevee_engine_init,
&eevee_engine_free,
+ NULL, /* instance_free */
&eevee_cache_init,
&EEVEE_cache_populate,
&eevee_cache_finish,
diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.c b/source/blender/draw/engines/eevee/eevee_lightcache.c
index 9a85037ac77..bcbe17fdabc 100644
--- a/source/blender/draw/engines/eevee/eevee_lightcache.c
+++ b/source/blender/draw/engines/eevee/eevee_lightcache.c
@@ -806,7 +806,6 @@ wmJob *EEVEE_lightbake_job_create(struct wmWindowManager *wm,
return wm_job;
}
-/* MUST run on the main thread. */
void *EEVEE_lightbake_job_data_alloc(struct Main *bmain,
struct ViewLayer *view_layer,
struct Scene *scene,
@@ -1484,8 +1483,6 @@ void EEVEE_lightbake_job(void *custom_data, short *stop, short *do_update, float
EEVEE_volumes_free_smoke_textures();
}
-/* This is to update the world irradiance and reflection contribution from
- * within the viewport drawing (does not have the overhead of a full light cache rebuild.) */
void EEVEE_lightbake_update_world_quick(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
const Scene *scene)
diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.h b/source/blender/draw/engines/eevee/eevee_lightcache.h
index fde0c80ab37..ccd53f6c037 100644
--- a/source/blender/draw/engines/eevee/eevee_lightcache.h
+++ b/source/blender/draw/engines/eevee/eevee_lightcache.h
@@ -33,7 +33,9 @@ struct Scene;
struct SceneEEVEE;
struct ViewLayer;
-/* Light Bake */
+/**
+ * Light Bake.
+ */
struct wmJob *EEVEE_lightbake_job_create(struct wmWindowManager *wm,
struct wmWindow *win,
struct Main *bmain,
@@ -41,6 +43,9 @@ struct wmJob *EEVEE_lightbake_job_create(struct wmWindowManager *wm,
struct Scene *scene,
int delay,
int frame);
+/**
+ * MUST run on the main thread.
+ */
void *EEVEE_lightbake_job_data_alloc(struct Main *bmain,
struct ViewLayer *view_layer,
struct Scene *scene,
@@ -50,11 +55,17 @@ void EEVEE_lightbake_job_data_free(void *custom_data);
void EEVEE_lightbake_update(void *custom_data);
void EEVEE_lightbake_job(void *custom_data, short *stop, short *do_update, float *progress);
+/**
+ * This is to update the world irradiance and reflection contribution from
+ * within the viewport drawing (does not have the overhead of a full light cache rebuild.)
+ */
void EEVEE_lightbake_update_world_quick(struct EEVEE_ViewLayerData *sldata,
struct EEVEE_Data *vedata,
const Scene *scene);
-/* Light Cache */
+/**
+ * Light Cache.
+ */
struct LightCache *EEVEE_lightcache_create(const int grid_len,
const int cube_len,
const int cube_size,
diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c
index ab083253499..c51fc18a406 100644
--- a/source/blender/draw/engines/eevee/eevee_lightprobes.c
+++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c
@@ -202,7 +202,6 @@ void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
}
}
-/* Only init the passes useful for rendering the light cache. */
void EEVEE_lightbake_cache_init(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
GPUTexture *rt_color,
@@ -871,7 +870,6 @@ static void lightbake_render_scene_face(int face, EEVEE_BakeRenderData *user_dat
DRW_draw_pass(psl->transparent_pass);
}
-/* Render the scene to the probe_rt texture. */
void EEVEE_lightbake_render_scene(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
struct GPUFrameBuffer *face_fb[6],
@@ -969,13 +967,13 @@ static void eevee_lightbake_render_scene_to_planars(EEVEE_ViewLayerData *sldata,
sldata->probes->planar_data,
sldata->probes->num_planar);
}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name Filtering
* \{ */
-/* Glossy filter rt_color to light_cache->cube_tx.tex at index probe_idx */
void EEVEE_lightbake_filter_glossy(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
struct GPUTexture *rt_color,
@@ -1064,7 +1062,6 @@ void EEVEE_lightbake_filter_glossy(EEVEE_ViewLayerData *sldata,
}
}
-/* Diffuse filter rt_color to light_cache->grid_tx.tex at index grid_offset */
void EEVEE_lightbake_filter_diffuse(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
struct GPUTexture *rt_color,
@@ -1117,7 +1114,6 @@ void EEVEE_lightbake_filter_diffuse(EEVEE_ViewLayerData *sldata,
GPU_framebuffer_viewport_reset(fb);
}
-/* Filter rt_depth to light_cache->grid_tx.tex at index grid_offset */
void EEVEE_lightbake_filter_visibility(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
struct GPUTexture *UNUSED(rt_depth),
diff --git a/source/blender/draw/engines/eevee/eevee_lights.c b/source/blender/draw/engines/eevee/eevee_lights.c
index afaf604322c..4ed968e2935 100644
--- a/source/blender/draw/engines/eevee/eevee_lights.c
+++ b/source/blender/draw/engines/eevee/eevee_lights.c
@@ -28,7 +28,6 @@
#include "eevee_private.h"
-/* Reconstruct local obmat from EEVEE_light. (normalized) */
void eevee_light_matrix_get(const EEVEE_Light *evli, float r_mat[4][4])
{
copy_v3_v3(r_mat[0], evli->rightvec);
diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c
index 582540529a6..a0522ad94d2 100644
--- a/source/blender/draw/engines/eevee/eevee_materials.c
+++ b/source/blender/draw/engines/eevee/eevee_materials.c
@@ -76,9 +76,6 @@ struct GPUTexture *EEVEE_materials_get_util_tex(void)
return e_data.util_tex;
}
-/**
- * ssr_id can be null to disable ssr contribution.
- */
void EEVEE_material_bind_resources(DRWShadingGroup *shgrp,
GPUMaterial *gpumat,
EEVEE_ViewLayerData *sldata,
diff --git a/source/blender/draw/engines/eevee/eevee_motion_blur.c b/source/blender/draw/engines/eevee/eevee_motion_blur.c
index 1eff2a3af24..703518a32ec 100644
--- a/source/blender/draw/engines/eevee/eevee_motion_blur.c
+++ b/source/blender/draw/engines/eevee/eevee_motion_blur.c
@@ -29,6 +29,7 @@
#include "BKE_animsys.h"
#include "BKE_camera.h"
+#include "BKE_duplilist.h"
#include "BKE_object.h"
#include "BKE_screen.h"
@@ -318,6 +319,14 @@ void EEVEE_motion_blur_cache_populate(EEVEE_ViewLayerData *UNUSED(sldata),
return;
}
+ const DupliObject *dup = DRW_object_get_dupli(ob);
+ if (dup != NULL && dup->ob->data != dup->ob_data) {
+ /* Geometry instances do not support motion blur correctly yet. The #key used in
+ * #motion_blur_deform_data_get has to take ids of instances (#DupliObject.persistent_id) into
+ * account. Otherwise it can't find matching geometry instances at different points in time. */
+ return;
+ }
+
EEVEE_ObjectMotionData *mb_data = EEVEE_motion_blur_object_data_get(
&effects->motion_blur, ob, false);
diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h
index f51b4fa0127..f0d518a58b1 100644
--- a/source/blender/draw/engines/eevee/eevee_private.h
+++ b/source/blender/draw/engines/eevee/eevee_private.h
@@ -992,6 +992,8 @@ typedef struct EEVEE_Data {
EEVEE_TextureList *txl;
EEVEE_PassList *psl;
EEVEE_StorageList *stl;
+ void *instance_data;
+
char info[GPU_INFO_SIZE];
} EEVEE_Data;
@@ -1071,6 +1073,7 @@ typedef struct EEVEE_PrivateData {
} EEVEE_PrivateData; /* Transient data */
/* eevee_data.c */
+
void EEVEE_motion_blur_data_init(EEVEE_MotionBlurData *mb);
void EEVEE_motion_blur_data_free(EEVEE_MotionBlurData *mb);
void EEVEE_view_layer_data_free(void *storage);
@@ -1095,6 +1098,7 @@ EEVEE_WorldEngineData *EEVEE_world_data_ensure(World *wo);
void eevee_id_update(void *vedata, ID *id);
/* eevee_materials.c */
+
struct GPUTexture *EEVEE_materials_get_util_tex(void); /* XXX */
void EEVEE_materials_init(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
@@ -1119,6 +1123,9 @@ void EEVEE_update_noise(EEVEE_PassList *psl, EEVEE_FramebufferList *fbl, const d
void EEVEE_material_renderpasses_init(EEVEE_Data *vedata);
void EEVEE_material_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, uint tot_samples);
void EEVEE_material_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+/**
+ * \param ssr_id: Can be null to disable SSR contribution.
+ */
void EEVEE_material_bind_resources(DRWShadingGroup *shgrp,
struct GPUMaterial *gpumat,
EEVEE_ViewLayerData *sldata,
@@ -1128,20 +1135,34 @@ void EEVEE_material_bind_resources(DRWShadingGroup *shgrp,
bool use_ssrefraction,
bool use_alpha_blend);
/* eevee_lights.c */
+
+/**
+ * Reconstruct local `obmat` from EEVEE_light. (normalized).
+ */
void eevee_light_matrix_get(const EEVEE_Light *evli, float r_mat[4][4]);
void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_lights_cache_add(EEVEE_ViewLayerData *sldata, struct Object *ob);
void EEVEE_lights_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
/* eevee_shadows.c */
+
void eevee_contact_shadow_setup(const Light *la, EEVEE_Shadow *evsh);
void EEVEE_shadows_init(EEVEE_ViewLayerData *sldata);
void EEVEE_shadows_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+/**
+ * Make that object update shadow casting lights inside its influence bounding box.
+ */
void EEVEE_shadows_caster_register(EEVEE_ViewLayerData *sldata, struct Object *ob);
void EEVEE_shadows_update(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_shadows_cube_add(EEVEE_LightsInfo *linfo, EEVEE_Light *evli, struct Object *ob);
+/**
+ * Return true if sample has changed and light needs to be updated.
+ */
bool EEVEE_shadows_cube_setup(EEVEE_LightsInfo *linfo, const EEVEE_Light *evli, int sample_ofs);
void EEVEE_shadows_cascade_add(EEVEE_LightsInfo *linfo, EEVEE_Light *evli, struct Object *ob);
+/**
+ * This refresh lights shadow buffers.
+ */
void EEVEE_shadows_draw(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, struct DRWView *view);
void EEVEE_shadows_draw_cubemap(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, int cube_index);
void EEVEE_shadows_draw_cascades(EEVEE_ViewLayerData *sldata,
@@ -1152,6 +1173,13 @@ void EEVEE_shadow_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, u
void EEVEE_shadow_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
/* eevee_sampling.c */
+
+/**
+ * Special ball distribution:
+ * Point are distributed in a way that when they are orthogonally
+ * projected into any plane, the resulting distribution is (close to)
+ * a uniform disc distribution.
+ */
void EEVEE_sample_ball(int sample_ofs, float radius, float rsample[3]);
void EEVEE_sample_rectangle(int sample_ofs,
const float x_axis[3],
@@ -1168,6 +1196,7 @@ void EEVEE_sample_ellipse(int sample_ofs,
void EEVEE_random_rotation_m4(int sample_ofs, float scale, float r_mat[4][4]);
/* eevee_shaders.c */
+
void EEVEE_shaders_material_shaders_init(void);
struct DRWShaderLibrary *EEVEE_shader_lib_get(void);
struct GPUShader *EEVEE_shaders_bloom_blit_get(bool high_quality);
@@ -1234,18 +1263,28 @@ struct GPUShader *EEVEE_shaders_probe_planar_display_sh_get(void);
struct GPUShader *EEVEE_shaders_update_noise_sh_get(void);
struct GPUShader *EEVEE_shaders_velocity_resolve_sh_get(void);
struct GPUShader *EEVEE_shaders_taa_resolve_sh_get(EEVEE_EffectsFlag enabled_effects);
+/**
+ * Configure a default node-tree with the given material.
+ */
struct bNodeTree *EEVEE_shader_default_surface_nodetree(Material *ma);
+/**
+ * Configure a default node-tree with the given world.
+ */
struct bNodeTree *EEVEE_shader_default_world_nodetree(World *wo);
Material *EEVEE_material_default_diffuse_get(void);
Material *EEVEE_material_default_glossy_get(void);
Material *EEVEE_material_default_error_get(void);
World *EEVEE_world_default_get(void);
+/**
+ * \note Compilation is not deferred.
+ */
struct GPUMaterial *EEVEE_material_default_get(struct Scene *scene, Material *ma, int options);
struct GPUMaterial *EEVEE_material_get(
EEVEE_Data *vedata, struct Scene *scene, Material *ma, World *wo, int options);
void EEVEE_shaders_free(void);
/* eevee_lightprobes.c */
+
bool EEVEE_lightprobes_obj_visibility_cb(bool vis_in, void *user_data);
void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
@@ -1255,6 +1294,9 @@ void EEVEE_lightprobes_refresh(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_lightprobes_refresh_planar(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_lightprobes_free(void);
+/**
+ * Only initialize the passes useful for rendering the light cache.
+ */
void EEVEE_lightbake_cache_init(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
GPUTexture *rt_color,
@@ -1262,12 +1304,18 @@ void EEVEE_lightbake_cache_init(EEVEE_ViewLayerData *sldata,
void EEVEE_lightbake_render_world(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
struct GPUFrameBuffer *face_fb[6]);
+/**
+ * Render the scene to the `probe_rt` texture.
+ */
void EEVEE_lightbake_render_scene(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
struct GPUFrameBuffer *face_fb[6],
const float pos[3],
float near_clip,
float far_clip);
+/**
+ * Glossy filter `rt_color` to `light_cache->cube_tx.tex` at index `probe_idx`.
+ */
void EEVEE_lightbake_filter_glossy(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
struct GPUTexture *rt_color,
@@ -1277,12 +1325,18 @@ void EEVEE_lightbake_filter_glossy(EEVEE_ViewLayerData *sldata,
int maxlevel,
float filter_quality,
float firefly_fac);
+/**
+ * Diffuse filter `rt_color` to `light_cache->grid_tx.tex` at index `grid_offset`.
+ */
void EEVEE_lightbake_filter_diffuse(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
struct GPUTexture *rt_color,
struct GPUFrameBuffer *fb,
int grid_offset,
float intensity);
+/**
+ * Filter `rt_depth` to `light_cache->grid_tx.tex` at index `grid_offset`.
+ */
void EEVEE_lightbake_filter_visibility(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
struct GPUTexture *rt_depth,
@@ -1301,6 +1355,7 @@ void EEVEE_lightprobes_planar_data_from_object(Object *ob,
EEVEE_LightProbeVisTest *vis_test);
/* eevee_depth_of_field.c */
+
int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, Object *camera);
void EEVEE_depth_of_field_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_depth_of_field_draw(EEVEE_Data *vedata);
@@ -1312,6 +1367,7 @@ int EEVEE_depth_of_field_sample_count_get(EEVEE_EffectsInfo *effects,
int *r_ring_count);
/* eevee_bloom.c */
+
int EEVEE_bloom_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_bloom_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_bloom_draw(EEVEE_Data *vedata);
@@ -1319,6 +1375,7 @@ void EEVEE_bloom_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, ui
void EEVEE_bloom_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
/* eevee_cryptomatte.c */
+
void EEVEE_cryptomatte_renderpasses_init(EEVEE_Data *vedata);
void EEVEE_cryptomatte_output_init(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
@@ -1332,6 +1389,11 @@ void EEVEE_cryptomatte_object_hair_cache_populate(EEVEE_Data *vedata,
EEVEE_ViewLayerData *sldata,
Object *ob);
void EEVEE_cryptomatte_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+/**
+ * Register the render passes needed for cryptomatte
+ * normally this is done in `EEVEE_render_update_passes`, but it has been placed here to keep
+ * related code side-by-side for clarity.
+ */
void EEVEE_cryptomatte_update_passes(struct RenderEngine *engine,
struct Scene *scene,
struct ViewLayer *view_layer);
@@ -1407,6 +1469,17 @@ void EEVEE_renderpasses_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ve
void EEVEE_renderpasses_output_accumulate(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
bool post_effect);
+/**
+ * Post-process data to construct a specific render-pass
+ *
+ * This method will create a shading group to perform the post-processing for the given
+ * `renderpass_type`. The post-processing will be done and the result will be stored in the
+ * `vedata->txl->renderpass` texture.
+ *
+ * Only invoke this function for passes that need post-processing.
+ *
+ * After invoking this function the active frame-buffer is set to `vedata->fbl->renderpass_fb`.
+ */
void EEVEE_renderpasses_postprocess(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
eViewLayerEEVEEPassType renderpass_type,
@@ -1414,6 +1487,10 @@ void EEVEE_renderpasses_postprocess(EEVEE_ViewLayerData *sldata,
void EEVEE_renderpasses_draw(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_renderpasses_draw_debug(EEVEE_Data *vedata);
bool EEVEE_renderpasses_only_first_sample_pass_active(EEVEE_Data *vedata);
+/**
+ * Calculate the hash for an AOV. The least significant bit is used to store the AOV
+ * type the rest of the bits are used for the name hash.
+ */
int EEVEE_renderpasses_aov_hash(const ViewLayerAOV *aov);
/* eevee_temporal_sampling.c */
@@ -1425,11 +1502,16 @@ void EEVEE_temporal_sampling_offset_calc(const double ht_point[2],
const float filter_size,
float r_offset[2]);
void EEVEE_temporal_sampling_matrices_calc(EEVEE_EffectsInfo *effects, const double ht_point[2]);
+/**
+ * Update the matrices based on the current sample.
+ * \note `DRW_MAT_PERS` and `DRW_MAT_VIEW` needs to read the original matrices.
+ */
void EEVEE_temporal_sampling_update_matrices(EEVEE_Data *vedata);
void EEVEE_temporal_sampling_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_temporal_sampling_draw(EEVEE_Data *vedata);
/* eevee_volumes.c */
+
void EEVEE_volumes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_volumes_set_jitter(EEVEE_ViewLayerData *sldata, uint current_sample);
void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
@@ -1447,18 +1529,29 @@ void EEVEE_volumes_free_smoke_textures(void);
void EEVEE_volumes_free(void);
/* eevee_effects.c */
+
void EEVEE_effects_init(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
Object *camera,
const bool minimal);
void EEVEE_effects_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_effects_draw_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+/**
+ * Simple down-sampling algorithm. Reconstruct mip chain up to mip level.
+ */
void EEVEE_effects_downsample_radiance_buffer(EEVEE_Data *vedata, struct GPUTexture *texture_src);
void EEVEE_create_minmax_buffer(EEVEE_Data *vedata, struct GPUTexture *depth_src, int layer);
+/**
+ * Simple down-sampling algorithm for cube-map. Reconstruct mip chain up to mip level.
+ */
void EEVEE_downsample_cube_buffer(EEVEE_Data *vedata, struct GPUTexture *texture_src, int level);
void EEVEE_draw_effects(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
/* eevee_render.c */
+
+/**
+ * Return true if initialized properly.
+ */
bool EEVEE_render_init(EEVEE_Data *vedata,
struct RenderEngine *engine,
struct Depsgraph *depsgraph);
@@ -1469,6 +1562,9 @@ void EEVEE_render_modules_init(EEVEE_Data *vedata,
struct RenderEngine *engine,
struct Depsgraph *depsgraph);
void EEVEE_render_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+/**
+ * Used by light cache. in this case engine is NULL.
+ */
void EEVEE_render_cache(void *vedata,
struct Object *ob,
struct RenderEngine *engine,
diff --git a/source/blender/draw/engines/eevee/eevee_render.c b/source/blender/draw/engines/eevee/eevee_render.c
index 5db0ca70dc9..9e7a67060da 100644
--- a/source/blender/draw/engines/eevee/eevee_render.c
+++ b/source/blender/draw/engines/eevee/eevee_render.c
@@ -46,7 +46,6 @@
#include "eevee_private.h"
-/* Return true if init properly. */
bool EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, struct Depsgraph *depsgraph)
{
EEVEE_Data *vedata = (EEVEE_Data *)ved;
@@ -194,7 +193,6 @@ void EEVEE_render_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
EEVEE_cryptomatte_cache_init(sldata, vedata);
}
-/* Used by light cache. in this case engine is NULL. */
void EEVEE_render_cache(void *vedata,
struct Object *ob,
struct RenderEngine *engine,
diff --git a/source/blender/draw/engines/eevee/eevee_renderpasses.c b/source/blender/draw/engines/eevee/eevee_renderpasses.c
index aa42deb13fa..3ebfc8a8f0f 100644
--- a/source/blender/draw/engines/eevee/eevee_renderpasses.c
+++ b/source/blender/draw/engines/eevee/eevee_renderpasses.c
@@ -75,8 +75,6 @@ bool EEVEE_renderpasses_only_first_sample_pass_active(EEVEE_Data *vedata)
return (g_data->render_passes & ~EEVEE_RENDERPASSES_POST_PROCESS_ON_FIRST_SAMPLE) == 0;
}
-/* Calculate the hash for an AOV. The least significant bit is used to store the AOV
- * type the rest of the bits are used for the name hash. */
int EEVEE_renderpasses_aov_hash(const ViewLayerAOV *aov)
{
int hash = BLI_hash_string(aov->name) << 1;
@@ -257,15 +255,6 @@ void EEVEE_renderpasses_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ve
}
}
-/* Post-process data to construct a specific render-pass
- *
- * This method will create a shading group to perform the post-processing for the given
- * `renderpass_type`. The post-processing will be done and the result will be stored in the
- * `vedata->txl->renderpass` texture.
- *
- * Only invoke this function for passes that need post-processing.
- *
- * After invoking this function the active frame-buffer is set to `vedata->fbl->renderpass_fb`. */
void EEVEE_renderpasses_postprocess(EEVEE_ViewLayerData *UNUSED(sldata),
EEVEE_Data *vedata,
eViewLayerEEVEEPassType renderpass_type,
diff --git a/source/blender/draw/engines/eevee/eevee_sampling.c b/source/blender/draw/engines/eevee/eevee_sampling.c
index da4bd20106c..99d14bd2c82 100644
--- a/source/blender/draw/engines/eevee/eevee_sampling.c
+++ b/source/blender/draw/engines/eevee/eevee_sampling.c
@@ -24,12 +24,6 @@
#include "BLI_rand.h"
-/**
- * Special ball distribution:
- * Point are distributed in a way that when they are orthogonally
- * projected into any plane, the resulting distribution is (close to)
- * a uniform disc distribution.
- */
void EEVEE_sample_ball(int sample_ofs, float radius, float rsample[3])
{
double ht_point[3];
diff --git a/source/blender/draw/engines/eevee/eevee_shaders.c b/source/blender/draw/engines/eevee/eevee_shaders.c
index 56ae7185b51..adede7676d5 100644
--- a/source/blender/draw/engines/eevee/eevee_shaders.c
+++ b/source/blender/draw/engines/eevee/eevee_shaders.c
@@ -830,6 +830,7 @@ struct GPUShader *EEVEE_shaders_subsurface_translucency_sh_get()
}
/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Volumes
* \{ */
@@ -1274,7 +1275,6 @@ Material *EEVEE_material_default_error_get(void)
return e_data.error_mat;
}
-/* Configure a default nodetree with the given material. */
struct bNodeTree *EEVEE_shader_default_surface_nodetree(Material *ma)
{
/* WARNING: This function is not threadsafe. Which is not a problem for the moment. */
@@ -1302,7 +1302,6 @@ struct bNodeTree *EEVEE_shader_default_surface_nodetree(Material *ma)
return e_data.surface.ntree;
}
-/* Configure a default nodetree with the given world. */
struct bNodeTree *EEVEE_shader_default_world_nodetree(World *wo)
{
/* WARNING: This function is not threadsafe. Which is not a problem for the moment. */
@@ -1493,7 +1492,6 @@ static struct GPUMaterial *eevee_material_get_ex(
return mat;
}
-/* NOTE: Compilation is not deferred. */
struct GPUMaterial *EEVEE_material_default_get(struct Scene *scene, Material *ma, int options)
{
Material *def_ma = (ma && (options & VAR_MAT_VOLUME)) ? BKE_material_default_volume() :
diff --git a/source/blender/draw/engines/eevee/eevee_shadows.c b/source/blender/draw/engines/eevee/eevee_shadows.c
index ee1a6652809..d8a40fd13cc 100644
--- a/source/blender/draw/engines/eevee/eevee_shadows.c
+++ b/source/blender/draw/engines/eevee/eevee_shadows.c
@@ -123,7 +123,6 @@ void EEVEE_shadows_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
}
}
-/* Make that object update shadow casting lights inside its influence bounding box. */
void EEVEE_shadows_caster_register(EEVEE_ViewLayerData *sldata, Object *ob)
{
EEVEE_LightsInfo *linfo = sldata->lights;
@@ -300,7 +299,6 @@ void EEVEE_shadows_update(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
}
}
-/* this refresh lights shadow buffers */
void EEVEE_shadows_draw(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, DRWView *view)
{
EEVEE_LightsInfo *linfo = sldata->lights;
diff --git a/source/blender/draw/engines/eevee/eevee_shadows_cube.c b/source/blender/draw/engines/eevee/eevee_shadows_cube.c
index 89caa0dd193..ed9f05df13c 100644
--- a/source/blender/draw/engines/eevee/eevee_shadows_cube.c
+++ b/source/blender/draw/engines/eevee/eevee_shadows_cube.c
@@ -95,7 +95,6 @@ start:
add_v3_v3(ws_sample_pos, jitter);
}
-/* Return true if sample has changed and light needs to be updated. */
bool EEVEE_shadows_cube_setup(EEVEE_LightsInfo *linfo, const EEVEE_Light *evli, int sample_ofs)
{
EEVEE_Shadow *shdw_data = linfo->shadow_data + (int)evli->shadow_id;
diff --git a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c
index b03172a1270..361fa2704c9 100644
--- a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c
+++ b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c
@@ -196,8 +196,6 @@ void EEVEE_temporal_sampling_matrices_calc(EEVEE_EffectsInfo *effects, const dou
DRW_view_update_sub(effects->taa_view, viewmat, winmat);
}
-/* Update the matrices based on the current sample.
- * NOTE: `DRW_MAT_PERS` and `DRW_MAT_VIEW` needs to read the original matrices. */
void EEVEE_temporal_sampling_update_matrices(EEVEE_Data *vedata)
{
EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
diff --git a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl
index 41d6db7f726..1061b2f91a2 100644
--- a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl
@@ -283,7 +283,7 @@ void occlusion_eval(OcclusionData data,
bent_normal = N;
}
else {
- /* Note: using pow(visibility, 6.0) produces NaN (see T87369). */
+ /* NOTE: using pow(visibility, 6.0) produces NaN (see T87369). */
float tmp = saturate(pow6(visibility));
bent_normal = normalize(mix(bent_normal, N, tmp));
}
@@ -337,7 +337,7 @@ float diffuse_occlusion(
* radius1 : First cap’s radius (arc length in radians)
* radius2 : Second caps’ radius (in radians)
* dist : Distance between caps (radians between centers of caps)
- * Note: Result is divided by pi to save one multiply.
+ * NOTE: Result is divided by pi to save one multiply.
*/
float spherical_cap_intersection(float radius1, float radius2, float dist)
{
diff --git a/source/blender/draw/engines/eevee/shaders/effect_dof_bokeh_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_dof_bokeh_frag.glsl
index 5fd00986adc..051a08d25e6 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_dof_bokeh_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_dof_bokeh_frag.glsl
@@ -50,10 +50,10 @@ float circle_to_polygon_angle(float sides_count, float theta)
float ratio = (local_theta - halfside_angle) / halfside_angle;
float halfside_len = polygon_sides_length(sides_count) * 0.5;
- float oposite = ratio * halfside_len;
+ float opposite = ratio * halfside_len;
/* NOTE: atan(y_over_x) has output range [-M_PI_2..M_PI_2]. */
- float final_local_theta = atan(oposite / adjacent);
+ float final_local_theta = atan(opposite / adjacent);
return side * side_angle + final_local_theta;
}
diff --git a/source/blender/draw/engines/eevee/shaders/effect_dof_gather_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_dof_gather_frag.glsl
index c09365cdcb4..db9ae0f7034 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_dof_gather_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_dof_gather_frag.glsl
@@ -2,8 +2,8 @@
/**
* Gather pass: Convolve foreground and background parts in separate passes.
*
- * Using the min&max CoC tile buffer, we select the best appropriate method to blur the scene color.
- * A fast gather path is taken if there is not many CoC variation inside the tile.
+ * Using the min&max CoC tile buffer, we select the best appropriate method to blur the scene
+ * color. A fast gather path is taken if there is not many CoC variation inside the tile.
*
* We sample using an octaweb sampling pattern. We randomize the kernel center and each ring
* rotation to ensure maximum coverage.
diff --git a/source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl b/source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl
index 3c49caf11a9..c54621f123d 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl
@@ -24,7 +24,7 @@ out vec4 FragColor;
*/
vec3 clip_to_aabb(vec3 color, vec3 minimum, vec3 maximum, vec3 average)
{
- /* note: only clips towards aabb center (but fast!) */
+ /* NOTE: only clips towards aabb center (but fast!) */
vec3 center = 0.5 * (maximum + minimum);
vec3 extents = 0.5 * (maximum - minimum);
vec3 dist = color - center;
diff --git a/source/blender/draw/engines/external/external_engine.c b/source/blender/draw/engines/external/external_engine.c
index cc548a53a8e..1d899c3935b 100644
--- a/source/blender/draw/engines/external/external_engine.c
+++ b/source/blender/draw/engines/external/external_engine.c
@@ -88,6 +88,8 @@ typedef struct EXTERNAL_Data {
EXTERNAL_TextureList *txl;
EXTERNAL_PassList *psl;
EXTERNAL_StorageList *stl;
+ void *instance_data;
+
char info[GPU_INFO_SIZE];
} EXTERNAL_Data;
@@ -451,6 +453,7 @@ DrawEngineType draw_engine_external_type = {
&external_data_size,
&external_engine_init,
&external_engine_free,
+ NULL, /* instance_free */
&external_cache_init,
&external_cache_populate,
&external_cache_finish,
diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_data.c b/source/blender/draw/engines/gpencil/gpencil_draw_data.c
index 4636b9e949a..8aba1090b58 100644
--- a/source/blender/draw/engines/gpencil/gpencil_draw_data.c
+++ b/source/blender/draw/engines/gpencil/gpencil_draw_data.c
@@ -176,11 +176,6 @@ static MaterialGPencilStyle *gpencil_viewport_material_overrides(
return gp_style;
}
-/**
- * Creates a linked list of material pool containing all materials assigned for a given object.
- * We merge the material pools together if object does not contain a huge amount of materials.
- * Also return an offset to the first material of the object in the ubo.
- */
GPENCIL_MaterialPool *gpencil_material_pool_create(GPENCIL_PrivateData *pd, Object *ob, int *ofs)
{
GPENCIL_MaterialPool *matpool = pd->last_material_pool;
@@ -429,9 +424,6 @@ void gpencil_light_pool_populate(GPENCIL_LightPool *lightpool, Object *ob)
}
}
-/**
- * Creates a single pool containing all lights assigned (light linked) for a given object.
- */
GPENCIL_LightPool *gpencil_light_pool_create(GPENCIL_PrivateData *pd, Object *UNUSED(ob))
{
GPENCIL_LightPool *lightpool = pd->last_light_pool;
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c
index 50e32040522..9bc340a2786 100644
--- a/source/blender/draw/engines/gpencil/gpencil_engine.c
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.c
@@ -990,6 +990,7 @@ DrawEngineType draw_engine_gpencil_type = {
&GPENCIL_data_size,
&GPENCIL_engine_init,
&GPENCIL_engine_free,
+ NULL, /* instance_free */
&GPENCIL_cache_init,
&GPENCIL_cache_populate,
&GPENCIL_cache_finish,
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.h b/source/blender/draw/engines/gpencil/gpencil_engine.h
index 328e60cf60b..29a9c0211be 100644
--- a/source/blender/draw/engines/gpencil/gpencil_engine.h
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.h
@@ -392,6 +392,11 @@ GPENCIL_tLayer *gpencil_layer_cache_add(GPENCIL_PrivateData *pd,
GPENCIL_tObject *tgp_ob);
GPENCIL_tLayer *gpencil_layer_cache_get(GPENCIL_tObject *tgp_ob, int number);
+/**
+ * Creates a linked list of material pool containing all materials assigned for a given object.
+ * We merge the material pools together if object does not contain a huge amount of materials.
+ * Also return an offset to the first material of the object in the UBO.
+ */
GPENCIL_MaterialPool *gpencil_material_pool_create(GPENCIL_PrivateData *pd, Object *ob, int *ofs);
void gpencil_material_resources_get(GPENCIL_MaterialPool *first_pool,
int mat_id,
@@ -402,6 +407,9 @@ void gpencil_material_resources_get(GPENCIL_MaterialPool *first_pool,
void gpencil_light_ambient_add(GPENCIL_LightPool *lightpool, const float color[3]);
void gpencil_light_pool_populate(GPENCIL_LightPool *lightpool, Object *ob);
GPENCIL_LightPool *gpencil_light_pool_add(GPENCIL_PrivateData *pd);
+/**
+ * Creates a single pool containing all lights assigned (light linked) for a given object.
+ */
GPENCIL_LightPool *gpencil_light_pool_create(GPENCIL_PrivateData *pd, Object *ob);
/* effects */
@@ -436,6 +444,10 @@ void GPENCIL_cache_finish(void *vedata);
void GPENCIL_draw_scene(void *vedata);
/* render */
+
+/**
+ * Initialize render data.
+ */
void GPENCIL_render_init(struct GPENCIL_Data *ved,
struct RenderEngine *engine,
struct RenderLayer *render_layer,
diff --git a/source/blender/draw/engines/gpencil/gpencil_render.c b/source/blender/draw/engines/gpencil/gpencil_render.c
index b597a786e86..26a14c433b3 100644
--- a/source/blender/draw/engines/gpencil/gpencil_render.c
+++ b/source/blender/draw/engines/gpencil/gpencil_render.c
@@ -33,7 +33,6 @@
#include "gpencil_engine.h"
-/* init render data */
void GPENCIL_render_init(GPENCIL_Data *vedata,
RenderEngine *engine,
struct RenderLayer *render_layer,
diff --git a/source/blender/draw/engines/image/image_drawing_mode.hh b/source/blender/draw/engines/image/image_drawing_mode_image_space.hh
index d81b0971982..26f4bc28106 100644
--- a/source/blender/draw/engines/image/image_drawing_mode.hh
+++ b/source/blender/draw/engines/image/image_drawing_mode_image_space.hh
@@ -26,7 +26,7 @@
namespace blender::draw::image_engine {
-class DefaultDrawingMode : public AbstractDrawingMode {
+class ImageSpaceDrawingMode : public AbstractDrawingMode {
private:
DRWPass *create_image_pass() const
{
@@ -50,19 +50,13 @@ class DefaultDrawingMode : public AbstractDrawingMode {
GPUBatch *geom = DRW_cache_quad_get();
- const bool is_tiled_texture = image && image->source == IMA_SRC_TILED;
- if (is_tiled_texture) {
- const float translate_x = image_mat[3][0];
- const float translate_y = image_mat[3][1];
- LISTBASE_FOREACH (ImageTile *, tile, &image->tiles) {
- const int tile_x = ((tile->tile_number - 1001) % 10);
- const int tile_y = ((tile->tile_number - 1001) / 10);
- image_mat[3][0] = (float)tile_x + translate_x;
- image_mat[3][1] = (float)tile_y + translate_y;
- DRW_shgroup_call_obmat(grp, geom, image_mat);
- }
- }
- else {
+ const float translate_x = image_mat[3][0];
+ const float translate_y = image_mat[3][1];
+ LISTBASE_FOREACH (ImageTile *, tile, &image->tiles) {
+ const int tile_x = ((tile->tile_number - 1001) % 10);
+ const int tile_y = ((tile->tile_number - 1001) / 10);
+ image_mat[3][0] = (float)tile_x + translate_x;
+ image_mat[3][1] = (float)tile_y + translate_y;
DRW_shgroup_call_obmat(grp, geom, image_mat);
}
}
diff --git a/source/blender/draw/engines/image/image_engine.cc b/source/blender/draw/engines/image/image_engine.cc
index 491fbec978b..be5946f34eb 100644
--- a/source/blender/draw/engines/image/image_engine.cc
+++ b/source/blender/draw/engines/image/image_engine.cc
@@ -41,7 +41,7 @@
#include "GPU_batch.h"
-#include "image_drawing_mode.hh"
+#include "image_drawing_mode_image_space.hh"
#include "image_engine.h"
#include "image_private.hh"
#include "image_space_image.hh"
@@ -63,12 +63,18 @@ static std::unique_ptr<AbstractSpaceAccessor> space_accessor_from_context(
return nullptr;
}
+template<
+ /** \brief Drawing mode to use.
+ *
+ * Useful during development to switch between drawing implementations.
+ */
+ typename DrawingMode = ImageSpaceDrawingMode>
class ImageEngine {
private:
const DRWContextState *draw_ctx;
IMAGE_Data *vedata;
std::unique_ptr<AbstractSpaceAccessor> space;
- DefaultDrawingMode drawing_mode;
+ DrawingMode drawing_mode;
public:
ImageEngine(const DRWContextState *draw_ctx, IMAGE_Data *vedata)
@@ -185,6 +191,7 @@ DrawEngineType draw_engine_image_type = {
&IMAGE_data_size, /* vedata_size */
&IMAGE_engine_init, /* engine_init */
&IMAGE_engine_free, /* engine_free */
+ nullptr, /* instance_free */
&IMAGE_cache_init, /* cache_init */
&IMAGE_cache_populate, /* cache_populate */
nullptr, /* cache_finish */
diff --git a/source/blender/draw/engines/overlay/overlay_armature.c b/source/blender/draw/engines/overlay/overlay_armature.c
index 1da682ff01b..2345a110134 100644
--- a/source/blender/draw/engines/overlay/overlay_armature.c
+++ b/source/blender/draw/engines/overlay/overlay_armature.c
@@ -26,6 +26,7 @@
#include "DNA_armature_types.h"
#include "DNA_constraint_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_view3d_types.h"
@@ -39,6 +40,7 @@
#include "BKE_armature.h"
#include "BKE_deform.h"
#include "BKE_modifier.h"
+#include "BKE_object.h"
#include "DEG_depsgraph_query.h"
@@ -52,6 +54,8 @@
#include "overlay_private.h"
+#include "draw_cache_impl.h"
+
#define BONE_VAR(eBone, pchan, var) ((eBone) ? (eBone->var) : (pchan->var))
#define BONE_FLAG(eBone, pchan) ((eBone) ? (eBone->flag) : (pchan->bone->flag))
@@ -100,9 +104,6 @@ typedef struct ArmatureDrawContext {
const ThemeWireColor *bcolor; /* pchan color */
} ArmatureDrawContext;
-/**
- * Return true if armature should be handled by the pose mode engine.
- */
bool OVERLAY_armature_is_pose_mode(Object *ob, const DRWContextState *draw_ctx)
{
Object *active_ob = draw_ctx->obact;
@@ -535,13 +536,22 @@ static void drw_shgroup_bone_custom_solid(ArmatureDrawContext *ctx,
const float outline_color[4],
Object *custom)
{
+ /* The custom object is not an evaluated object, so its object->data field hasn't been replaced
+ * by #data_eval. This is bad since it gives preference to an object's evaluated mesh over any
+ * other data type, but supporting all evaluated geometry components would require a much larger
+ * refactor of this area. */
+ Mesh *mesh = BKE_object_get_evaluated_mesh(custom);
+ if (mesh == NULL) {
+ return;
+ }
+
/* TODO(fclem): arg... less than ideal but we never iter on this object
* to assure batch cache is valid. */
- drw_batch_cache_validate(custom);
+ DRW_mesh_batch_cache_validate(mesh);
- struct GPUBatch *surf = DRW_cache_object_surface_get(custom);
- struct GPUBatch *edges = DRW_cache_object_edge_detection_get(custom, NULL);
- struct GPUBatch *ledges = DRW_cache_object_loose_edges_get(custom);
+ struct GPUBatch *surf = DRW_mesh_batch_cache_get_surface(mesh);
+ struct GPUBatch *edges = DRW_mesh_batch_cache_get_edge_detection(mesh, NULL);
+ struct GPUBatch *ledges = DRW_mesh_batch_cache_get_loose_edges(mesh);
BoneInstanceData inst_data;
DRWCallBuffer *buf;
@@ -578,12 +588,16 @@ static void drw_shgroup_bone_custom_wire(ArmatureDrawContext *ctx,
const float color[4],
Object *custom)
{
+ /* See comments in #drw_shgroup_bone_custom_solid. */
+ Mesh *mesh = BKE_object_get_evaluated_mesh(custom);
+ if (mesh == NULL) {
+ return;
+ }
/* TODO(fclem): arg... less than ideal but we never iter on this object
* to assure batch cache is valid. */
- drw_batch_cache_validate(custom);
-
- struct GPUBatch *geom = DRW_cache_object_all_edges_get(custom);
+ DRW_mesh_batch_cache_validate(mesh);
+ struct GPUBatch *geom = DRW_mesh_batch_cache_get_all_edges(mesh);
if (geom) {
DRWCallBuffer *buf = custom_bone_instance_shgroup(ctx, ctx->custom_wire, geom);
BoneInstanceData inst_data;
@@ -1906,6 +1920,7 @@ static void draw_bone_name(ArmatureDrawContext *ctx,
DRW_TEXT_CACHE_GLOBALSPACE | DRW_TEXT_CACHE_STRING_PTR,
color);
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -2314,3 +2329,5 @@ void OVERLAY_pose_draw(OVERLAY_Data *vedata)
DRW_draw_pass(psl->armature_ps[1]);
}
}
+
+/** \} */
diff --git a/source/blender/draw/engines/overlay/overlay_engine.c b/source/blender/draw/engines/overlay/overlay_engine.c
index 2bdceb5f3db..12db2bd02cf 100644
--- a/source/blender/draw/engines/overlay/overlay_engine.c
+++ b/source/blender/draw/engines/overlay/overlay_engine.c
@@ -703,6 +703,7 @@ DrawEngineType draw_engine_overlay_type = {
&overlay_data_size,
&OVERLAY_engine_init,
&OVERLAY_engine_free,
+ NULL, /* instance_free */
&OVERLAY_cache_init,
&OVERLAY_cache_populate,
&OVERLAY_cache_finish,
diff --git a/source/blender/draw/engines/overlay/overlay_image.c b/source/blender/draw/engines/overlay/overlay_image.c
index 2e9a9bc5c64..0608725d342 100644
--- a/source/blender/draw/engines/overlay/overlay_image.c
+++ b/source/blender/draw/engines/overlay/overlay_image.c
@@ -462,8 +462,6 @@ void OVERLAY_image_cache_finish(OVERLAY_Data *vedata)
DRW_pass_sort_shgroup_z(psl->image_empties_back_ps);
}
-/* This function draws images that needs the view transform applied.
- * It draws these images directly into the scene color buffer. */
void OVERLAY_image_scene_background_draw(OVERLAY_Data *vedata)
{
OVERLAY_PassList *psl = vedata->psl;
diff --git a/source/blender/draw/engines/overlay/overlay_private.h b/source/blender/draw/engines/overlay/overlay_private.h
index def278f98df..8e7c3094062 100644
--- a/source/blender/draw/engines/overlay/overlay_private.h
+++ b/source/blender/draw/engines/overlay/overlay_private.h
@@ -510,6 +510,9 @@ void OVERLAY_xray_fade_draw(OVERLAY_Data *vedata);
void OVERLAY_xray_depth_copy(OVERLAY_Data *vedata);
void OVERLAY_xray_depth_infront_copy(OVERLAY_Data *vedata);
+/**
+ * Return true if armature should be handled by the pose mode engine.
+ */
bool OVERLAY_armature_is_pose_mode(Object *ob, const struct DRWContextState *draw_ctx);
void OVERLAY_armature_cache_init(OVERLAY_Data *vedata);
void OVERLAY_armature_cache_populate(OVERLAY_Data *vedata, Object *ob);
@@ -631,6 +634,10 @@ void OVERLAY_image_empty_cache_populate(OVERLAY_Data *vedata, Object *ob);
void OVERLAY_image_cache_finish(OVERLAY_Data *vedata);
void OVERLAY_image_draw(OVERLAY_Data *vedata);
void OVERLAY_image_background_draw(OVERLAY_Data *vedata);
+/**
+ * This function draws images that needs the view transform applied.
+ * It draws these images directly into the scene color buffer.
+ */
void OVERLAY_image_scene_background_draw(OVERLAY_Data *vedata);
void OVERLAY_image_in_front_draw(OVERLAY_Data *vedata);
diff --git a/source/blender/draw/engines/overlay/overlay_wireframe.c b/source/blender/draw/engines/overlay/overlay_wireframe.c
index fde376beeb2..449130c4c5b 100644
--- a/source/blender/draw/engines/overlay/overlay_wireframe.c
+++ b/source/blender/draw/engines/overlay/overlay_wireframe.c
@@ -237,7 +237,21 @@ void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata,
if (dupli && !init_dupli) {
if (dupli->wire_shgrp && dupli->wire_geom) {
if (dupli->base_flag == ob->base_flag) {
- DRW_shgroup_call(dupli->wire_shgrp, dupli->wire_geom, ob);
+ /* Check for the special cases used below, assign specific theme colors to the shaders. */
+ OVERLAY_ExtraCallBuffers *cb = OVERLAY_extra_call_buffer_get(vedata, ob);
+ if (dupli->wire_shgrp == cb->extra_loose_points) {
+ float *color;
+ DRW_object_wire_theme_get(ob, draw_ctx->view_layer, &color);
+ OVERLAY_extra_loose_points(cb, dupli->wire_geom, ob->obmat, color);
+ }
+ else if (dupli->wire_shgrp == cb->extra_wire) {
+ float *color;
+ DRW_object_wire_theme_get(ob, draw_ctx->view_layer, &color);
+ OVERLAY_extra_wire(cb, dupli->wire_geom, ob->obmat, color);
+ }
+ else {
+ DRW_shgroup_call(dupli->wire_shgrp, dupli->wire_geom, ob);
+ }
return;
}
}
@@ -268,6 +282,9 @@ void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata,
}
}
+ DRWShadingGroup *shgrp = NULL;
+ struct GPUBatch *geom = NULL;
+
/* Don't do that in edit Mesh mode, unless there is a modifier preview. */
if (use_wire && (!is_mesh || (!is_edit_mode || has_edit_mesh_cage))) {
const bool is_sculpt_mode = ((ob->mode & OB_MODE_SCULPT) != 0) && (ob->sculpt != NULL);
@@ -275,8 +292,7 @@ void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata,
!DRW_state_is_image_render();
const bool use_coloring = (use_wire && !is_edit_mode && !is_sculpt_mode &&
!has_edit_mesh_cage);
- DRWShadingGroup *shgrp = NULL;
- struct GPUBatch *geom = DRW_cache_object_face_wireframe_get(ob);
+ geom = DRW_cache_object_face_wireframe_get(ob);
if (geom || use_sculpt_pbvh) {
if (use_sculpt_pbvh) {
@@ -300,11 +316,6 @@ void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata,
DRW_shgroup_call(shgrp, geom, ob);
}
}
-
- if (dupli) {
- dupli->wire_shgrp = shgrp;
- dupli->wire_geom = geom;
- }
}
else if (is_mesh && (!is_edit_mode || has_edit_mesh_cage)) {
OVERLAY_ExtraCallBuffers *cb = OVERLAY_extra_call_buffer_get(vedata, ob);
@@ -313,18 +324,25 @@ void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata,
/* Draw loose geometry. */
if (is_mesh_verts_only) {
- struct GPUBatch *geom = DRW_cache_mesh_all_verts_get(ob);
+ geom = DRW_cache_mesh_all_verts_get(ob);
if (geom) {
OVERLAY_extra_loose_points(cb, geom, ob->obmat, color);
+ shgrp = cb->extra_loose_points;
}
}
else {
- struct GPUBatch *geom = DRW_cache_mesh_loose_edges_get(ob);
+ geom = DRW_cache_mesh_loose_edges_get(ob);
if (geom) {
OVERLAY_extra_wire(cb, geom, ob->obmat, color);
+ shgrp = cb->extra_wire;
}
}
}
+
+ if (dupli) {
+ dupli->wire_shgrp = shgrp;
+ dupli->wire_geom = geom;
+ }
}
void OVERLAY_wireframe_draw(OVERLAY_Data *data)
diff --git a/source/blender/draw/engines/select/select_debug_engine.c b/source/blender/draw/engines/select/select_debug_engine.c
index e9437c5ab92..f66eabdcdcc 100644
--- a/source/blender/draw/engines/select/select_debug_engine.c
+++ b/source/blender/draw/engines/select/select_debug_engine.c
@@ -120,6 +120,7 @@ DrawEngineType draw_engine_debug_select_type = {
&select_debug_data_size,
&select_debug_engine_init,
&select_debug_engine_free,
+ NULL, /* instance_free */
NULL,
NULL,
NULL,
diff --git a/source/blender/draw/engines/select/select_engine.c b/source/blender/draw/engines/select/select_engine.c
index 20edd78597b..7f9645013ce 100644
--- a/source/blender/draw/engines/select/select_engine.c
+++ b/source/blender/draw/engines/select/select_engine.c
@@ -363,6 +363,7 @@ DrawEngineType draw_engine_select_type = {
&select_data_size,
&select_engine_init,
&select_engine_free,
+ NULL, /* instance_free */
&select_cache_init,
&select_cache_populate,
NULL,
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_transparent_accum_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_transparent_accum_frag.glsl
index fd4d00d96dd..3f113fd4b2e 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_transparent_accum_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_transparent_accum_frag.glsl
@@ -11,7 +11,7 @@
layout(location = 0) out vec4 transparentAccum;
layout(location = 1) out vec4 revealageAccum;
-/* Note: Blending will be skipped on objectId because output is a non-normalized integer buffer. */
+/* NOTE: Blending will be skipped on objectId because output is a non-normalized integer buffer. */
layout(location = 2) out uint objectId;
/* Special function only to be used with calculate_transparent_weight(). */
diff --git a/source/blender/draw/engines/workbench/workbench_effect_antialiasing.c b/source/blender/draw/engines/workbench/workbench_effect_antialiasing.c
index 8206add7412..f4014fac41f 100644
--- a/source/blender/draw/engines/workbench/workbench_effect_antialiasing.c
+++ b/source/blender/draw/engines/workbench/workbench_effect_antialiasing.c
@@ -371,7 +371,6 @@ void workbench_antialiasing_cache_init(WORKBENCH_Data *vedata)
}
}
-/* Return true if render is not cached. */
bool workbench_antialiasing_setup(WORKBENCH_Data *vedata)
{
WORKBENCH_PrivateData *wpd = vedata->stl->wpd;
diff --git a/source/blender/draw/engines/workbench/workbench_engine.c b/source/blender/draw/engines/workbench/workbench_engine.c
index 4706aeb4477..5bc2c53e253 100644
--- a/source/blender/draw/engines/workbench/workbench_engine.c
+++ b/source/blender/draw/engines/workbench/workbench_engine.c
@@ -473,8 +473,6 @@ void workbench_cache_finish(void *ved)
}
}
-/* Used by viewport rendering & final rendering.
- * Do one render loop iteration (i.e: One TAA sample). */
void workbench_draw_sample(void *ved)
{
WORKBENCH_Data *vedata = ved;
@@ -629,6 +627,7 @@ DrawEngineType draw_engine_workbench = {
&workbench_data_size,
&workbench_engine_init,
&workbench_engine_free,
+ NULL, /* instance_free */
&workbench_cache_init,
&workbench_cache_populate,
&workbench_cache_finish,
diff --git a/source/blender/draw/engines/workbench/workbench_materials.c b/source/blender/draw/engines/workbench/workbench_materials.c
index aaa1a5a6ff6..d70633eaa85 100644
--- a/source/blender/draw/engines/workbench/workbench_materials.c
+++ b/source/blender/draw/engines/workbench/workbench_materials.c
@@ -244,7 +244,6 @@ DRWShadingGroup *workbench_material_setup_ex(WORKBENCH_PrivateData *wpd,
}
}
-/* If ima is null, search appropriate image node but will fallback to purple texture otherwise. */
DRWShadingGroup *workbench_image_setup_ex(WORKBENCH_PrivateData *wpd,
Object *ob,
int mat_nr,
diff --git a/source/blender/draw/engines/workbench/workbench_private.h b/source/blender/draw/engines/workbench/workbench_private.h
index e17bd7d9956..42c873c7691 100644
--- a/source/blender/draw/engines/workbench/workbench_private.h
+++ b/source/blender/draw/engines/workbench/workbench_private.h
@@ -414,6 +414,10 @@ void workbench_opaque_cache_init(WORKBENCH_Data *data);
/* workbench_transparent.c */
void workbench_transparent_engine_init(WORKBENCH_Data *data);
void workbench_transparent_cache_init(WORKBENCH_Data *data);
+/**
+ * Redraw the transparent passes but with depth test
+ * to output correct outline IDs and depth.
+ */
void workbench_transparent_draw_depth_pass(WORKBENCH_Data *data);
/* workbench_shadow.c */
@@ -463,6 +467,9 @@ int workbench_antialiasing_sample_count_get(WORKBENCH_PrivateData *wpd);
void workbench_antialiasing_engine_init(WORKBENCH_Data *vedata);
void workbench_antialiasing_cache_init(WORKBENCH_Data *vedata);
void workbench_antialiasing_view_updated(WORKBENCH_Data *vedata);
+/**
+ * Return true if render is not cached.
+ */
bool workbench_antialiasing_setup(WORKBENCH_Data *vedata);
void workbench_antialiasing_draw_pass(WORKBENCH_Data *vedata);
@@ -491,6 +498,9 @@ DRWShadingGroup *workbench_material_setup_ex(WORKBENCH_PrivateData *wpd,
eV3DShadingColorType color_type,
eWORKBENCH_DataType datatype,
bool *r_transp);
+/**
+ * If `ima` is null, search appropriate image node but will fallback to purple texture otherwise.
+ */
DRWShadingGroup *workbench_image_setup_ex(WORKBENCH_PrivateData *wpd,
Object *ob,
int mat_nr,
@@ -535,6 +545,10 @@ void workbench_engine_init(void *ved);
void workbench_cache_init(void *ved);
void workbench_cache_populate(void *ved, Object *ob);
void workbench_cache_finish(void *ved);
+/**
+ * Used by viewport rendering & final rendering.
+ * Do one render loop iteration (i.e: One TAA sample).
+ */
void workbench_draw_sample(void *ved);
void workbench_draw_finish(void *ved);
diff --git a/source/blender/draw/engines/workbench/workbench_transparent.c b/source/blender/draw/engines/workbench/workbench_transparent.c
index ad855cb284c..3be005b43d0 100644
--- a/source/blender/draw/engines/workbench/workbench_transparent.c
+++ b/source/blender/draw/engines/workbench/workbench_transparent.c
@@ -149,8 +149,6 @@ void workbench_transparent_cache_init(WORKBENCH_Data *vedata)
}
}
-/* Redraw the transparent passes but with depth test
- * to output correct outline IDs and depth. */
void workbench_transparent_draw_depth_pass(WORKBENCH_Data *data)
{
WORKBENCH_PrivateData *wpd = data->stl->wpd;
diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h
index c1cab931f6a..961aed3f284 100644
--- a/source/blender/draw/intern/DRW_render.h
+++ b/source/blender/draw/intern/DRW_render.h
@@ -121,6 +121,8 @@ typedef struct DrawEngineType {
void (*engine_init)(void *vedata);
void (*engine_free)(void);
+ void (*instance_free)(void *instance_data);
+
void (*cache_init)(void *vedata);
void (*cache_populate)(void *vedata, struct Object *ob);
void (*cache_finish)(void *vedata);
@@ -145,9 +147,11 @@ typedef enum {
DRW_TEX_MIPMAP = (1 << 3),
} DRWTextureFlag;
-/* Textures from DRW_texture_pool_query_* have the options
- * DRW_TEX_FILTER for color float textures, and no options
- * for depth textures and integer textures. */
+/**
+ * Textures from `DRW_texture_pool_query_*` have the options
+ * #DRW_TEX_FILTER for color float textures, and no options
+ * for depth textures and integer textures.
+ */
struct GPUTexture *DRW_texture_pool_query_2d(int w,
int h,
eGPUTextureFormat format,
@@ -286,11 +290,17 @@ void DRW_shader_free(struct GPUShader *shader);
DRWShaderLibrary *DRW_shader_library_create(void);
-/* Warning: Each library must be added after all its dependencies. */
+/**
+ * \warning Each library must be added after all its dependencies.
+ */
void DRW_shader_library_add_file(DRWShaderLibrary *lib, char *lib_code, const char *lib_name);
#define DRW_SHADER_LIB_ADD(lib, lib_name) \
DRW_shader_library_add_file(lib, datatoc_##lib_name##_glsl, STRINGIFY(lib_name) ".glsl")
+/**
+ * \return an allocN'ed string containing the shader code with its dependencies prepended.
+ * Caller must free the string with #MEM_freeN after use.
+ */
char *DRW_shader_library_create_shader_string(const DRWShaderLibrary *lib,
const char *shader_code);
@@ -304,11 +314,14 @@ void DRW_shader_library_free(DRWShaderLibrary *lib);
} while (0)
/* Batches */
-/* DRWState is a bitmask that stores the current render state and the desired render state. Based
+
+/**
+ * DRWState is a bit-mask that stores the current render state and the desired render state. Based
* on the differences the minimum state changes can be invoked to setup the desired render state.
*
* The Write Stencil, Stencil test, Depth test and Blend state options are mutual exclusive
- * therefore they aren't ordered as a bit mask. */
+ * therefore they aren't ordered as a bit mask.
+ */
typedef enum {
/** Write mask */
DRW_STATE_WRITE_DEPTH = (1 << 0),
@@ -406,7 +419,9 @@ DRWShadingGroup *DRW_shgroup_transform_feedback_create(struct GPUShader *shader,
void DRW_shgroup_add_material_resources(DRWShadingGroup *grp, struct GPUMaterial *material);
-/* return final visibility */
+/**
+ * Return final visibility.
+ */
typedef bool(DRWCallVisibilityFn)(bool vis_in, void *user_data);
void DRW_shgroup_call_ex(DRWShadingGroup *shgroup,
@@ -416,11 +431,15 @@ void DRW_shgroup_call_ex(DRWShadingGroup *shgroup,
bool bypass_culling,
void *user_data);
-/* If ob is NULL, unit modelmatrix is assumed and culling is bypassed. */
+/**
+ * If ob is NULL, unit modelmatrix is assumed and culling is bypassed.
+ */
#define DRW_shgroup_call(shgroup, geom, ob) \
DRW_shgroup_call_ex(shgroup, ob, NULL, geom, false, NULL)
-/* Same as DRW_shgroup_call but override the obmat. Not culled. */
+/**
+ * Same as #DRW_shgroup_call but override the `obmat`. Not culled.
+ */
#define DRW_shgroup_call_obmat(shgroup, geom, obmat) \
DRW_shgroup_call_ex(shgroup, NULL, obmat, geom, false, NULL)
@@ -429,12 +448,17 @@ void DRW_shgroup_call_ex(DRWShadingGroup *shgroup,
#define DRW_shgroup_call_with_callback(shgroup, geom, ob, user_data) \
DRW_shgroup_call_ex(shgroup, ob, NULL, geom, false, user_data)
-/* Same as DRW_shgroup_call but bypass culling even if ob is not NULL. */
+/**
+ * Same as #DRW_shgroup_call but bypass culling even if ob is not NULL.
+ */
#define DRW_shgroup_call_no_cull(shgroup, geom, ob) \
DRW_shgroup_call_ex(shgroup, ob, NULL, geom, true, NULL)
void DRW_shgroup_call_range(
DRWShadingGroup *shgroup, Object *ob, struct GPUBatch *geom, uint v_sta, uint v_ct);
+/**
+ * A count of 0 instance will use the default number of instance in the batch.
+ */
void DRW_shgroup_call_instance_range(
DRWShadingGroup *shgroup, Object *ob, struct GPUBatch *geom, uint i_sta, uint i_ct);
@@ -445,12 +469,17 @@ void DRW_shgroup_call_compute(DRWShadingGroup *shgroup,
void DRW_shgroup_call_procedural_points(DRWShadingGroup *sh, Object *ob, uint point_count);
void DRW_shgroup_call_procedural_lines(DRWShadingGroup *sh, Object *ob, uint line_count);
void DRW_shgroup_call_procedural_triangles(DRWShadingGroup *sh, Object *ob, uint tri_count);
-/* Warning: Only use with Shaders that have IN_PLACE_INSTANCES defined. */
+/**
+ * \warning Only use with Shaders that have `IN_PLACE_INSTANCES` defined.
+ * TODO: Should be removed.
+ */
void DRW_shgroup_call_instances(DRWShadingGroup *shgroup,
Object *ob,
struct GPUBatch *geom,
uint count);
-/* Warning: Only use with Shaders that have INSTANCED_ATTR defined. */
+/**
+ * \warning Only use with Shaders that have INSTANCED_ATTR defined.
+ */
void DRW_shgroup_call_instances_with_attrs(DRWShadingGroup *shgroup,
Object *ob,
struct GPUBatch *geom,
@@ -475,13 +504,20 @@ void DRW_buffer_add_entry_array(DRWCallBuffer *callbuf, const void *attr[], uint
DRW_buffer_add_entry_array(buffer, array, (sizeof(array) / sizeof(*array))); \
} while (0)
-/* Can only be called during iter phase. */
+/**
+ * Can only be called during iteration phase.
+ */
uint32_t DRW_object_resource_id_get(Object *ob);
+/**
+ * State is added to #Pass.state while drawing.
+ * Use to temporarily enable draw options.
+ */
void DRW_shgroup_state_enable(DRWShadingGroup *shgroup, DRWState state);
void DRW_shgroup_state_disable(DRWShadingGroup *shgroup, DRWState state);
-/* Reminders:
+/**
+ * Reminders:
* - (compare_mask & reference) is what is tested against (compare_mask & stencil_value)
* stencil_value being the value stored in the stencil buffer.
* - (write-mask & reference) is what gets written if the test condition is fulfilled.
@@ -490,10 +526,14 @@ void DRW_shgroup_stencil_set(DRWShadingGroup *shgroup,
uint write_mask,
uint reference,
uint compare_mask);
-/* TODO: remove this function. Obsolete version. mask is actually reference value. */
+/**
+ * TODO: remove this function. Obsolete version. mask is actually reference value.
+ */
void DRW_shgroup_stencil_mask(DRWShadingGroup *shgroup, uint mask);
-/* Issue a clear command. */
+/**
+ * Issue a clear command.
+ */
void DRW_shgroup_clear_framebuffer(DRWShadingGroup *shgroup,
eGPUFrameBufferBits channels,
uchar r,
@@ -539,7 +579,6 @@ void DRW_shgroup_uniform_vec4(DRWShadingGroup *shgroup,
const char *name,
const float *value,
int arraysize);
-/* Boolean are expected to be 4bytes longs for opengl! */
void DRW_shgroup_uniform_bool(DRWShadingGroup *shgroup,
const char *name,
const int *value,
@@ -562,10 +601,14 @@ void DRW_shgroup_uniform_ivec4(DRWShadingGroup *shgroup,
int arraysize);
void DRW_shgroup_uniform_mat3(DRWShadingGroup *shgroup, const char *name, const float (*value)[3]);
void DRW_shgroup_uniform_mat4(DRWShadingGroup *shgroup, const char *name, const float (*value)[4]);
-/* Only to be used when image load store is supported (GPU_shader_image_load_store_support()). */
+/**
+ * Only to be used when image load store is supported (#GPU_shader_image_load_store_support()).
+ */
void DRW_shgroup_uniform_image(DRWShadingGroup *shgroup, const char *name, const GPUTexture *tex);
void DRW_shgroup_uniform_image_ref(DRWShadingGroup *shgroup, const char *name, GPUTexture **tex);
+
/* Store value instead of referencing it. */
+
void DRW_shgroup_uniform_int_copy(DRWShadingGroup *shgroup, const char *name, const int value);
void DRW_shgroup_uniform_ivec2_copy(DRWShadingGroup *shgroup, const char *name, const int *value);
void DRW_shgroup_uniform_ivec3_copy(DRWShadingGroup *shgroup, const char *name, const int *value);
@@ -585,14 +628,29 @@ void DRW_shgroup_vertex_buffer(DRWShadingGroup *shgroup,
bool DRW_shgroup_is_empty(DRWShadingGroup *shgroup);
-/* Passes */
+/* Passes. */
+
DRWPass *DRW_pass_create(const char *name, DRWState state);
+/**
+ * Create an instance of the original pass that will execute the same drawcalls but with its own
+ * #DRWState.
+ */
DRWPass *DRW_pass_create_instance(const char *name, DRWPass *original, DRWState state);
+/**
+ * Link two passes so that they are both rendered if the first one is being drawn.
+ */
void DRW_pass_link(DRWPass *first, DRWPass *second);
void DRW_pass_foreach_shgroup(DRWPass *pass,
void (*callback)(void *userData, DRWShadingGroup *shgroup),
void *userData);
+/**
+ * Sort Shading groups by decreasing Z of their first draw call.
+ * This is useful for order dependent effect such as alpha-blending.
+ */
void DRW_pass_sort_shgroup_z(DRWPass *pass);
+/**
+ * Reverse Shading group submission order.
+ */
void DRW_pass_sort_shgroup_reverse(DRWPass *pass);
bool DRW_pass_is_empty(DRWPass *pass);
@@ -601,56 +659,113 @@ bool DRW_pass_is_empty(DRWPass *pass);
#define DRW_PASS_INSTANCE_CREATE(pass, original, state) \
(pass = DRW_pass_create_instance(#pass, (original), state))
-/* Views */
+/* Views. */
+
+/**
+ * Create a view with culling.
+ */
DRWView *DRW_view_create(const float viewmat[4][4],
const float winmat[4][4],
const float (*culling_viewmat)[4],
const float (*culling_winmat)[4],
DRWCallVisibilityFn *visibility_fn);
+/**
+ * Create a view with culling done by another view.
+ */
DRWView *DRW_view_create_sub(const DRWView *parent_view,
const float viewmat[4][4],
const float winmat[4][4]);
+/**
+ * Update matrices of a view created with #DRW_view_create.
+ */
void DRW_view_update(DRWView *view,
const float viewmat[4][4],
const float winmat[4][4],
const float (*culling_viewmat)[4],
const float (*culling_winmat)[4]);
+/**
+ * Update matrices of a view created with #DRW_view_create_sub.
+ */
void DRW_view_update_sub(DRWView *view, const float viewmat[4][4], const float winmat[4][4]);
+/**
+ * \return default view if it is a viewport render.
+ */
const DRWView *DRW_view_default_get(void);
+/**
+ * MUST only be called once per render and only in render mode. Sets default view.
+ */
void DRW_view_default_set(DRWView *view);
+/**
+ * \warning Only use in render AND only if you are going to set view_default again.
+ */
void DRW_view_reset(void);
+/**
+ * Set active view for rendering.
+ */
void DRW_view_set_active(DRWView *view);
const DRWView *DRW_view_get_active(void);
+/**
+ * This only works if DRWPasses have been tagged with DRW_STATE_CLIP_PLANES,
+ * and if the shaders have support for it (see usage of gl_ClipDistance).
+ * \note planes must be in world space.
+ */
void DRW_view_clip_planes_set(DRWView *view, float (*planes)[4], int plane_len);
void DRW_view_camtexco_set(DRWView *view, float texco[4]);
/* For all getters, if view is NULL, default view is assumed. */
+
void DRW_view_winmat_get(const DRWView *view, float mat[4][4], bool inverse);
void DRW_view_viewmat_get(const DRWView *view, float mat[4][4], bool inverse);
void DRW_view_persmat_get(const DRWView *view, float mat[4][4], bool inverse);
+/**
+ * \return world space frustum corners.
+ */
void DRW_view_frustum_corners_get(const DRWView *view, BoundBox *corners);
+/**
+ * \return world space frustum sides as planes.
+ * See #draw_frustum_culling_planes_calc() for the plane order.
+ */
void DRW_view_frustum_planes_get(const DRWView *view, float planes[6][4]);
-/* These are in view-space, so negative if in perspective.
- * Extract near and far clip distance from the projection matrix. */
+/**
+ * These are in view-space, so negative if in perspective.
+ * Extract near and far clip distance from the projection matrix.
+ */
float DRW_view_near_distance_get(const DRWView *view);
float DRW_view_far_distance_get(const DRWView *view);
bool DRW_view_is_persp_get(const DRWView *view);
/* Culling, return true if object is inside view frustum. */
+
+/**
+ * \return True if the given BoundSphere intersect the current view frustum.
+ * bsphere must be in world space.
+ */
bool DRW_culling_sphere_test(const DRWView *view, const BoundSphere *bsphere);
+/**
+ * \return True if the given BoundBox intersect the current view frustum.
+ * bbox must be in world space.
+ */
bool DRW_culling_box_test(const DRWView *view, const BoundBox *bbox);
+/**
+ * \return True if the view frustum is inside or intersect the given plane.
+ * plane must be in world space.
+ */
bool DRW_culling_plane_test(const DRWView *view, const float plane[4]);
+/**
+ * Return True if the given box intersect the current view frustum.
+ * This function will have to be replaced when world space bb per objects is implemented.
+ */
bool DRW_culling_min_max_test(const DRWView *view, float obmat[4][4], float min[3], float max[3]);
void DRW_culling_frustum_corners_get(const DRWView *view, BoundBox *corners);
void DRW_culling_frustum_planes_get(const DRWView *view, float planes[6][4]);
-/* Viewport */
+/* Viewport. */
const float *DRW_viewport_size_get(void);
const float *DRW_viewport_invert_size_get(void);
@@ -670,18 +785,35 @@ void DRW_render_object_iter(void *vedata,
struct Object *ob,
struct RenderEngine *engine,
struct Depsgraph *depsgraph));
+/**
+ * Must run after all instance datas have been added.
+ */
void DRW_render_instance_buffer_finish(void);
+/**
+ * \warning Changing frame might free the #ViewLayerEngineData.
+ */
void DRW_render_set_time(struct RenderEngine *engine,
struct Depsgraph *depsgraph,
int frame,
float subframe);
+/**
+ * \warning only use for custom pipeline. 99% of the time, you don't want to use this.
+ */
void DRW_render_viewport_size_set(const int size[2]);
+/**
+ * Assume a valid GL context is bound (and that the gl_context_mutex has been acquired).
+ * This function only setup DST and execute the given function.
+ * \warning similar to DRW_render_to_image you cannot use default lists (dfbl & dtxl).
+ */
void DRW_custom_pipeline(DrawEngineType *draw_engine_type,
struct Depsgraph *depsgraph,
void (*callback)(void *vedata, void *user_data),
void *user_data);
+/**
+ * Used when the render engine want to redo another cache populate inside the same render frame.
+ */
void DRW_cache_restart(void);
/* ViewLayers */
@@ -699,11 +831,26 @@ DrawData *DRW_drawdata_ensure(ID *id,
size_t size,
DrawDataInitCb init_cb,
DrawDataFreeCb free_cb);
+/**
+ * Return NULL if not a dupli or a pointer of pointer to the engine data.
+ */
void **DRW_duplidata_get(void *vedata);
-/* Settings */
+/* Settings. */
+
bool DRW_object_is_renderable(const struct Object *ob);
+/**
+ * Does `ob` needs to be rendered in edit mode.
+ *
+ * When using duplicate linked meshes, objects that are not in edit-mode will be drawn as
+ * it is in edit mode, when another object with the same mesh is in edit mode.
+ * This will not be the case when one of the objects are influenced by modifiers.
+ */
bool DRW_object_is_in_edit_mode(const struct Object *ob);
+/**
+ * Return whether this object is visible depending if
+ * we are rendering or drawing in the viewport.
+ */
int DRW_object_visibility_in_active_context(const struct Object *ob);
bool DRW_object_is_flat_normal(const struct Object *ob);
bool DRW_object_use_hide_faces(const struct Object *ob);
@@ -715,31 +862,76 @@ struct Object *DRW_object_get_dupli_parent(const struct Object *ob);
struct DupliObject *DRW_object_get_dupli(const struct Object *ob);
/* Draw commands */
+
void DRW_draw_pass(DRWPass *pass);
+/**
+ * Draw only a subset of shgroups. Used in special situations as grease pencil strokes.
+ */
void DRW_draw_pass_subset(DRWPass *pass, DRWShadingGroup *start_group, DRWShadingGroup *end_group);
void DRW_draw_callbacks_pre_scene(void);
void DRW_draw_callbacks_post_scene(void);
+/**
+ * Reset state to not interfere with other UI draw-call.
+ */
void DRW_state_reset_ex(DRWState state);
void DRW_state_reset(void);
+/**
+ * Use with care, intended so selection code can override passes depth settings,
+ * which is important for selection to work properly.
+ *
+ * Should be set in main draw loop, cleared afterwards
+ */
void DRW_state_lock(DRWState state);
-/* Selection */
+/* Selection. */
+
void DRW_select_load_id(uint id);
-/* Draw State */
+/* Draw State. */
+
+/**
+ * When false, drawing doesn't output to a pixel buffer
+ * eg: Occlusion queries, or when we have setup a context to draw in already.
+ */
bool DRW_state_is_fbo(void);
+/**
+ * For when engines need to know if this is drawing for selection or not.
+ */
bool DRW_state_is_select(void);
bool DRW_state_is_material_select(void);
bool DRW_state_is_depth(void);
+/**
+ * Whether we are rendering for an image
+ */
bool DRW_state_is_image_render(void);
+/**
+ * Whether we are rendering only the render engine,
+ * or if we should also render the mode engines.
+ */
bool DRW_state_is_scene_render(void);
+/**
+ * Whether we are rendering simple opengl render
+ */
bool DRW_state_is_opengl_render(void);
bool DRW_state_is_playback(void);
+/**
+ * Is the user navigating the region.
+ */
bool DRW_state_is_navigating(void);
+/**
+ * Should text draw in this mode?
+ */
bool DRW_state_show_text(void);
+/**
+ * Should draw support elements
+ * Objects center, selection outline, probe data, ...
+ */
bool DRW_state_draw_support(void);
+/**
+ * Whether we should render the background
+ */
bool DRW_state_draw_background(void);
/* Avoid too many lookups while drawing */
diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c
index 7b66026f7ad..03fb3b92277 100644
--- a/source/blender/draw/intern/draw_cache.c
+++ b/source/blender/draw/intern/draw_cache.c
@@ -47,6 +47,10 @@
#include "draw_cache_impl.h"
#include "draw_manager.h"
+/* -------------------------------------------------------------------- */
+/** \name Internal Defines
+ * \{ */
+
#define VCLASS_LIGHT_AREA_SHAPE (1 << 0)
#define VCLASS_LIGHT_SPOT_SHAPE (1 << 1)
#define VCLASS_LIGHT_SPOT_BLEND (1 << 2)
@@ -77,6 +81,12 @@
#define DRW_SPHERE_SHAPE_LATITUDE_HIGH 80
#define DRW_SPHERE_SHAPE_LONGITUDE_HIGH 60
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Internal Types
+ * \{ */
+
typedef struct Vert {
float pos[3];
int class;
@@ -163,6 +173,8 @@ void DRW_shape_cache_free(void)
}
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Procedural Batches
* \{ */
@@ -354,7 +366,6 @@ static GPUVertBuf *sphere_wire_vbo(const float rad, int flag)
}
/* Quads */
-/* Use this one for rendering fullscreen passes. For 3D objects use DRW_cache_quad_get(). */
GPUBatch *DRW_cache_fullscreen_quad_get(void)
{
if (!SHC.drw_fullscreen_quad) {
@@ -388,7 +399,6 @@ GPUBatch *DRW_cache_fullscreen_quad_get(void)
return SHC.drw_fullscreen_quad;
}
-/* Just a regular quad with 4 vertices. */
GPUBatch *DRW_cache_quad_get(void)
{
if (!SHC.drw_quad) {
@@ -409,7 +419,6 @@ GPUBatch *DRW_cache_quad_get(void)
return SHC.drw_quad;
}
-/* Just a regular quad with 4 vertices - wires. */
GPUBatch *DRW_cache_quad_wires_get(void)
{
if (!SHC.drw_quad_wires) {
@@ -430,7 +439,6 @@ GPUBatch *DRW_cache_quad_wires_get(void)
return SHC.drw_quad_wires;
}
-/* Grid */
GPUBatch *DRW_cache_grid_get(void)
{
if (!SHC.drw_grid) {
@@ -769,6 +777,8 @@ GPUBatch *DRW_cache_normal_arrow_get(void)
return SHC.drw_normal_arrow;
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Dummy VBO's
*
@@ -911,7 +921,6 @@ GPUBatch *DRW_cache_object_surface_get(Object *ob)
}
}
-/* Returns the vertbuf used by shaded surface batch. */
GPUVertBuf *DRW_cache_object_pos_vertbuf_get(Object *ob)
{
Mesh *me = BKE_object_get_evaluated_mesh(ob);
@@ -1260,7 +1269,6 @@ GPUBatch *DRW_cache_empty_capsule_cap_get(void)
#undef NSEGMENTS
}
-/* Force Field */
GPUBatch *DRW_cache_field_wind_get(void)
{
#define CIRCLE_RESOL 32
@@ -1336,7 +1344,6 @@ GPUBatch *DRW_cache_field_vortex_get(void)
#undef SPIRAL_RESOL
}
-/* Screen-aligned circle. */
GPUBatch *DRW_cache_field_curve_get(void)
{
#define CIRCLE_RESOL 32
@@ -1425,7 +1432,6 @@ GPUBatch *DRW_cache_field_cone_limit_get(void)
#undef CIRCLE_RESOL
}
-/* Screen-aligned dashed circle */
GPUBatch *DRW_cache_field_sphere_limit_get(void)
{
#define CIRCLE_RESOL 32
@@ -2872,7 +2878,6 @@ GPUBatch *DRW_cache_mesh_surface_edges_get(Object *ob)
return DRW_mesh_batch_cache_get_surface_edges(ob->data);
}
-/* Return list of batches with length equal to max(1, totcol). */
GPUBatch **DRW_cache_mesh_surface_shaded_get(Object *ob,
struct GPUMaterial **gpumat_array,
uint gpumat_array_len)
@@ -2881,7 +2886,6 @@ GPUBatch **DRW_cache_mesh_surface_shaded_get(Object *ob,
return DRW_mesh_batch_cache_get_surface_shaded(ob->data, gpumat_array, gpumat_array_len);
}
-/* Return list of batches with length equal to max(1, totcol). */
GPUBatch **DRW_cache_mesh_surface_texpaint_get(Object *ob)
{
BLI_assert(ob->type == OB_MESH);
@@ -3078,7 +3082,6 @@ GPUBatch *DRW_cache_surf_loose_edges_get(Object *ob)
return NULL;
}
-/* Return list of batches */
GPUBatch **DRW_cache_surf_surface_shaded_get(Object *ob,
struct GPUMaterial **gpumat_array,
uint gpumat_array_len)
@@ -3148,6 +3151,8 @@ GPUBatch *DRW_cache_pointcloud_surface_get(Object *object)
return DRW_pointcloud_batch_cache_get_surface(object);
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Volume
* \{ */
@@ -3275,7 +3280,6 @@ GPUBatch *DRW_cache_particles_get_prim(int type)
return NULL;
}
-/* 3D cursor */
GPUBatch *DRW_cache_cursor_get(bool crosshair_lines)
{
GPUBatch **drw_cursor = crosshair_lines ? &SHC.drw_cursor : &SHC.drw_cursor_only_circle;
@@ -3450,6 +3454,26 @@ void drw_batch_cache_generate_requested(Object *ob)
}
}
+void drw_batch_cache_generate_requested_evaluated_mesh(Object *ob)
+{
+ /* NOTE: Logic here is duplicated from #drw_batch_cache_generate_requested. */
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const Scene *scene = draw_ctx->scene;
+ const enum eContextObjectMode mode = CTX_data_mode_enum_ex(
+ draw_ctx->object_edit, draw_ctx->obact, draw_ctx->object_mode);
+ const bool is_paint_mode = ELEM(
+ mode, CTX_MODE_SCULPT, CTX_MODE_PAINT_TEXTURE, CTX_MODE_PAINT_VERTEX, CTX_MODE_PAINT_WEIGHT);
+
+ const bool use_hide = ((ob->type == OB_MESH) &&
+ ((is_paint_mode && (ob == draw_ctx->obact) &&
+ DRW_object_use_hide_faces(ob)) ||
+ ((mode == CTX_MODE_EDIT_MESH) && DRW_object_is_in_edit_mode(ob))));
+
+ Mesh *mesh = BKE_object_get_evaluated_mesh(ob);
+ DRW_mesh_batch_cache_create_requested(DST.task_graph, ob, mesh, scene, is_paint_mode, use_hide);
+}
+
void drw_batch_cache_generate_requested_delayed(Object *ob)
{
BLI_gset_add(DST.delayed_extraction, ob);
diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h
index 5863ada2ccf..7fcd86669ec 100644
--- a/source/blender/draw/intern/draw_cache.h
+++ b/source/blender/draw/intern/draw_cache.h
@@ -36,7 +36,9 @@ struct Volume;
struct VolumeGrid;
struct bGPDstroke;
-/* Shape resolution level of detail */
+/**
+ * Shape resolution level of detail.
+ */
typedef enum eDRWLevelOfDetail {
DRW_LOD_LOW = 0,
DRW_LOD_MEDIUM = 1,
@@ -52,9 +54,15 @@ struct GPUBatch *DRW_cache_cursor_get(bool crosshair_lines);
/* Common Shapes */
struct GPUBatch *DRW_cache_groundline_get(void);
+/* Grid */
struct GPUBatch *DRW_cache_grid_get(void);
+/**
+ * Use this one for rendering full-screen passes. For 3D objects use #DRW_cache_quad_get().
+ */
struct GPUBatch *DRW_cache_fullscreen_quad_get(void);
+/* Just a regular quad with 4 vertices. */
struct GPUBatch *DRW_cache_quad_get(void);
+/* Just a regular quad with 4 vertices - wires. */
struct GPUBatch *DRW_cache_quad_wires_get(void);
struct GPUBatch *DRW_cache_cube_get(void);
struct GPUBatch *DRW_cache_normal_arrow_get(void);
@@ -62,9 +70,11 @@ struct GPUBatch *DRW_cache_normal_arrow_get(void);
struct GPUBatch *DRW_cache_sphere_get(const eDRWLevelOfDetail level_of_detail);
/* Dummy VBOs */
+
struct GPUBatch *DRW_gpencil_dummy_buffer_get(void);
/* Common Object */
+
struct GPUBatch *DRW_cache_object_all_edges_get(struct Object *ob);
struct GPUBatch *DRW_cache_object_edge_detection_get(struct Object *ob, bool *r_is_manifold);
struct GPUBatch *DRW_cache_object_surface_get(struct Object *ob);
@@ -75,6 +85,9 @@ struct GPUBatch **DRW_cache_object_surface_material_get(struct Object *ob,
struct GPUBatch *DRW_cache_object_face_wireframe_get(struct Object *ob);
int DRW_cache_object_material_count_get(struct Object *ob);
+/**
+ * Returns the vertbuf used by shaded surface batch.
+ */
struct GPUVertBuf *DRW_cache_object_pos_vertbuf_get(struct Object *ob);
/* Empties */
@@ -89,15 +102,23 @@ struct GPUBatch *DRW_cache_empty_capsule_cap_get(void);
struct GPUBatch *DRW_cache_empty_capsule_body_get(void);
/* Force Field */
+
struct GPUBatch *DRW_cache_field_wind_get(void);
struct GPUBatch *DRW_cache_field_force_get(void);
struct GPUBatch *DRW_cache_field_vortex_get(void);
+
+/* Screen-aligned circle. */
+
struct GPUBatch *DRW_cache_field_curve_get(void);
struct GPUBatch *DRW_cache_field_tube_limit_get(void);
struct GPUBatch *DRW_cache_field_cone_limit_get(void);
+
+/* Screen-aligned dashed circle */
+
struct GPUBatch *DRW_cache_field_sphere_limit_get(void);
/* Lights */
+
struct GPUBatch *DRW_cache_light_point_lines_get(void);
struct GPUBatch *DRW_cache_light_sun_lines_get(void);
struct GPUBatch *DRW_cache_light_spot_lines_get(void);
@@ -106,6 +127,7 @@ struct GPUBatch *DRW_cache_light_area_square_lines_get(void);
struct GPUBatch *DRW_cache_light_spot_volume_get(void);
/* Camera */
+
struct GPUBatch *DRW_cache_camera_frame_get(void);
struct GPUBatch *DRW_cache_camera_volume_get(void);
struct GPUBatch *DRW_cache_camera_volume_wire_get(void);
@@ -114,14 +136,17 @@ struct GPUBatch *DRW_cache_camera_tria_get(void);
struct GPUBatch *DRW_cache_camera_distances_get(void);
/* Speaker */
+
struct GPUBatch *DRW_cache_speaker_get(void);
/* Probe */
+
struct GPUBatch *DRW_cache_lightprobe_cube_get(void);
struct GPUBatch *DRW_cache_lightprobe_grid_get(void);
struct GPUBatch *DRW_cache_lightprobe_planar_get(void);
/* Bones */
+
struct GPUBatch *DRW_cache_bone_octahedral_get(void);
struct GPUBatch *DRW_cache_bone_octahedral_wire_get(void);
struct GPUBatch *DRW_cache_bone_box_get(void);
@@ -136,15 +161,22 @@ struct GPUBatch *DRW_cache_bone_dof_sphere_get(void);
struct GPUBatch *DRW_cache_bone_dof_lines_get(void);
/* Meshes */
+
struct GPUBatch *DRW_cache_mesh_all_verts_get(struct Object *ob);
struct GPUBatch *DRW_cache_mesh_all_edges_get(struct Object *ob);
struct GPUBatch *DRW_cache_mesh_loose_edges_get(struct Object *ob);
struct GPUBatch *DRW_cache_mesh_edge_detection_get(struct Object *ob, bool *r_is_manifold);
struct GPUBatch *DRW_cache_mesh_surface_get(struct Object *ob);
struct GPUBatch *DRW_cache_mesh_surface_edges_get(struct Object *ob);
+/**
+ * Return list of batches with length equal to `max(1, totcol)`.
+ */
struct GPUBatch **DRW_cache_mesh_surface_shaded_get(struct Object *ob,
struct GPUMaterial **gpumat_array,
uint gpumat_array_len);
+/**
+ * Return list of batches with length equal to `max(1, totcol)`.
+ */
struct GPUBatch **DRW_cache_mesh_surface_texpaint_get(struct Object *ob);
struct GPUBatch *DRW_cache_mesh_surface_texpaint_single_get(struct Object *ob);
struct GPUBatch *DRW_cache_mesh_surface_vertpaint_get(struct Object *ob);
@@ -154,19 +186,27 @@ struct GPUBatch *DRW_cache_mesh_surface_mesh_analysis_get(struct Object *ob);
struct GPUBatch *DRW_cache_mesh_face_wireframe_get(struct Object *ob);
/* Curve */
+
struct GPUBatch *DRW_cache_curve_edge_wire_get(struct Object *ob);
+
/* edit-mode */
+
struct GPUBatch *DRW_cache_curve_edge_normal_get(struct Object *ob);
struct GPUBatch *DRW_cache_curve_edge_overlay_get(struct Object *ob);
struct GPUBatch *DRW_cache_curve_vert_overlay_get(struct Object *ob);
/* Font */
+
struct GPUBatch *DRW_cache_text_edge_wire_get(struct Object *ob);
/* Surface */
+
struct GPUBatch *DRW_cache_surf_surface_get(struct Object *ob);
struct GPUBatch *DRW_cache_surf_edge_wire_get(struct Object *ob);
struct GPUBatch *DRW_cache_surf_loose_edges_get(struct Object *ob);
+
+/* Return list of batches */
+
struct GPUBatch **DRW_cache_surf_surface_shaded_get(struct Object *ob,
struct GPUMaterial **gpumat_array,
uint gpumat_array_len);
@@ -174,11 +214,13 @@ struct GPUBatch *DRW_cache_surf_face_wireframe_get(struct Object *ob);
struct GPUBatch *DRW_cache_surf_edge_detection_get(struct Object *ob, bool *r_is_manifold);
/* Lattice */
+
struct GPUBatch *DRW_cache_lattice_verts_get(struct Object *ob);
struct GPUBatch *DRW_cache_lattice_wire_get(struct Object *ob, bool use_weight);
struct GPUBatch *DRW_cache_lattice_vert_overlay_get(struct Object *ob);
/* Particles */
+
struct GPUBatch *DRW_cache_particles_get_hair(struct Object *object,
struct ParticleSystem *psys,
struct ModifierData *md);
@@ -196,6 +238,7 @@ struct GPUBatch *DRW_cache_particles_get_edit_tip_points(struct Object *object,
struct GPUBatch *DRW_cache_particles_get_prim(int type);
/* Metaball */
+
struct GPUBatch *DRW_cache_mball_surface_get(struct Object *ob);
struct GPUBatch **DRW_cache_mball_surface_shaded_get(struct Object *ob,
struct GPUMaterial **gpumat_array,
@@ -204,6 +247,7 @@ struct GPUBatch *DRW_cache_mball_face_wireframe_get(struct Object *ob);
struct GPUBatch *DRW_cache_mball_edge_detection_get(struct Object *ob, bool *r_is_manifold);
/* Hair */
+
struct GPUBatch *DRW_cache_hair_surface_get(struct Object *ob);
struct GPUBatch **DRW_cache_hair_surface_shaded_get(struct Object *ob,
struct GPUMaterial **gpumat_array,
@@ -212,10 +256,12 @@ struct GPUBatch *DRW_cache_hair_face_wireframe_get(struct Object *ob);
struct GPUBatch *DRW_cache_hair_edge_detection_get(struct Object *ob, bool *r_is_manifold);
/* PointCloud */
+
struct GPUBatch *DRW_cache_pointcloud_get_dots(struct Object *obj);
struct GPUBatch *DRW_cache_pointcloud_surface_get(struct Object *obj);
/* Volume */
+
typedef struct DRWVolumeGrid {
struct DRWVolumeGrid *next, *prev;
@@ -240,6 +286,7 @@ struct GPUBatch *DRW_cache_volume_face_wireframe_get(struct Object *ob);
struct GPUBatch *DRW_cache_volume_selection_surface_get(struct Object *ob);
/* GPencil */
+
struct GPUBatch *DRW_cache_gpencil_strokes_get(struct Object *ob, int cfra);
struct GPUBatch *DRW_cache_gpencil_fills_get(struct Object *ob, int cfra);
struct GPUBatch *DRW_cache_gpencil_edit_lines_get(struct Object *ob, int cfra);
@@ -252,6 +299,9 @@ struct GPUBatch *DRW_cache_gpencil_sbuffer_fill_get(struct Object *ob);
struct GPUBatch *DRW_cache_gpencil_face_wireframe_get(struct Object *ob);
struct bGPDstroke *DRW_cache_gpencil_sbuffer_stroke_data_get(struct Object *ob);
+/**
+ * Sbuffer batches are temporary. We need to clear it after drawing.
+ */
void DRW_cache_gpencil_sbuffer_clear(struct Object *ob);
#ifdef __cplusplus
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.cc b/source/blender/draw/intern/draw_cache_extract_mesh.cc
index f3b72503907..485b803310c 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh.cc
+++ b/source/blender/draw/intern/draw_cache_extract_mesh.cc
@@ -56,6 +56,7 @@ namespace blender::draw {
/* ---------------------------------------------------------------------- */
/** \name Mesh Elements Extract Struct
* \{ */
+
using TaskId = int;
using TaskLen = int;
@@ -158,6 +159,7 @@ class ExtractorRunDatas : public Vector<ExtractorRunData> {
/* ---------------------------------------------------------------------- */
/** \name ExtractTaskData
* \{ */
+
struct ExtractTaskData {
const MeshRenderData *mr = nullptr;
MeshBatchCache *cache = nullptr;
@@ -495,6 +497,7 @@ static struct TaskNode *extract_task_node_create(struct TaskGraph *task_graph,
/* ---------------------------------------------------------------------- */
/** \name Task Node - Update Mesh Render Data
* \{ */
+
struct MeshRenderDataUpdateTaskData {
MeshRenderData *mr = nullptr;
MeshBufferCache *cache = nullptr;
@@ -778,6 +781,8 @@ static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
#endif
}
+/** \} */
+
} // namespace blender::draw
extern "C" {
@@ -814,5 +819,3 @@ void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
}
} // extern "C"
-
-/** \} */
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c
index abfbeabef6b..8b0fbf86360 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c
+++ b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c
@@ -174,8 +174,8 @@ void mesh_render_data_update_loose_geom(MeshRenderData *mr,
/** \name Polygons sorted per material
*
* Contains polygon indices sorted based on their material.
- *
* \{ */
+
static void mesh_render_data_polys_sorted_load(MeshRenderData *mr, const MeshBufferCache *cache);
static void mesh_render_data_polys_sorted_ensure(MeshRenderData *mr, MeshBufferCache *cache);
static void mesh_render_data_polys_sorted_build(MeshRenderData *mr, MeshBufferCache *cache);
@@ -335,9 +335,6 @@ static int *mesh_render_data_mat_tri_len_build(MeshRenderData *mr)
/** \name Mesh/BMesh Interface (indirect, partially cached access to complex data).
* \{ */
-/**
- * Part of the creation of the #MeshRenderData that happens in a thread.
- */
void mesh_render_data_update_looptris(MeshRenderData *mr,
const eMRIterType iter_type,
const eMRDataType data_flag)
@@ -440,10 +437,6 @@ void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_
}
}
-/**
- * \param is_mode_active: When true, use the modifiers from the edit-data,
- * otherwise don't use modifiers as they are not from this object.
- */
MeshRenderData *mesh_render_data_create(Mesh *me,
const bool is_editmode,
const bool is_paint_mode,
diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h
index 220a7f37c3d..80b8c0506e7 100644
--- a/source/blender/draw/intern/draw_cache_impl.h
+++ b/source/blender/draw/intern/draw_cache_impl.h
@@ -47,7 +47,10 @@ struct bGPdata;
extern "C" {
#endif
-/* Expose via BKE callbacks */
+/* -------------------------------------------------------------------- */
+/** \name Expose via BKE callbacks
+ * \{ */
+
void DRW_mball_batch_cache_dirty_tag(struct MetaBall *mb, int mode);
void DRW_mball_batch_cache_validate(struct MetaBall *mb);
void DRW_mball_batch_cache_free(struct MetaBall *mb);
@@ -82,15 +85,34 @@ void DRW_volume_batch_cache_dirty_tag(struct Volume *volume, int mode);
void DRW_volume_batch_cache_validate(struct Volume *volume);
void DRW_volume_batch_cache_free(struct Volume *volume);
-/* Garbage collection */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Garbage Collection
+ * \{ */
+
void DRW_batch_cache_free_old(struct Object *ob, int ctime);
+/**
+ * Thread safety need to be assured by caller. Don't call this during drawing.
+ * \note For now this only free the shading batches / VBO if any cd layers is not needed anymore.
+ */
void DRW_mesh_batch_cache_free_old(struct Mesh *me, int ctime);
-/* Generic */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Generic
+ * \{ */
+
void DRW_vertbuf_create_wiredata(struct GPUVertBuf *vbo, const int vert_len);
-/* Curve */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Curve
+ * \{ */
+
void DRW_curve_batch_cache_create_requested(struct Object *ob, const struct Scene *scene);
int DRW_curve_material_count_get(struct Curve *cu);
@@ -107,7 +129,12 @@ struct GPUBatch **DRW_curve_batch_cache_get_surface_shaded(struct Curve *cu,
uint gpumat_array_len);
struct GPUBatch *DRW_curve_batch_cache_get_wireframes_face(struct Curve *cu);
-/* Metaball */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Metaball
+ * \{ */
+
int DRW_metaball_material_count_get(struct MetaBall *mb);
struct GPUBatch *DRW_metaball_batch_cache_get_triangles_with_normals(struct Object *ob);
@@ -119,7 +146,12 @@ struct GPUBatch *DRW_metaball_batch_cache_get_wireframes_face(struct Object *ob)
struct GPUBatch *DRW_metaball_batch_cache_get_edge_detection(struct Object *ob,
bool *r_is_manifold);
-/* DispList */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name DispList
+ * \{ */
+
void DRW_displist_vertbuf_create_pos_and_nor(struct ListBase *lb,
struct GPUVertBuf *vbo,
const struct Scene *scene);
@@ -138,17 +170,32 @@ void DRW_displist_indexbuf_create_edges_adjacency_lines(struct ListBase *lb,
struct GPUIndexBuf *ibo,
bool *r_is_manifold);
-/* Lattice */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Lattice
+ * \{ */
+
struct GPUBatch *DRW_lattice_batch_cache_get_all_edges(struct Lattice *lt,
bool use_weight,
const int actdef);
struct GPUBatch *DRW_lattice_batch_cache_get_all_verts(struct Lattice *lt);
struct GPUBatch *DRW_lattice_batch_cache_get_edit_verts(struct Lattice *lt);
-/* Hair */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Hair
+ * \{ */
+
int DRW_hair_material_count_get(struct Hair *hair);
-/* PointCloud */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name PointCloud
+ * \{ */
+
int DRW_pointcloud_material_count_get(struct PointCloud *pointcloud);
struct GPUBatch *DRW_pointcloud_batch_cache_get_dots(struct Object *ob);
@@ -157,13 +204,26 @@ struct GPUBatch **DRW_cache_pointcloud_surface_shaded_get(struct Object *ob,
struct GPUMaterial **gpumat_array,
uint gpumat_array_len);
-/* Volume */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Volume
+ * \{ */
+
int DRW_volume_material_count_get(struct Volume *volume);
struct GPUBatch *DRW_volume_batch_cache_get_wireframes_face(struct Volume *volume);
struct GPUBatch *DRW_volume_batch_cache_get_selection_surface(struct Volume *volume);
-/* Mesh */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Mesh
+ * \{ */
+
+/**
+ * Can be called for any surface type. Mesh *me is the final mesh.
+ */
void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
struct Object *ob,
struct Mesh *me,
@@ -186,7 +246,13 @@ struct GPUBatch *DRW_mesh_batch_cache_get_surface_vertpaint(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_surface_sculpt(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_surface_weights(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_sculpt_overlays(struct Mesh *me);
-/* edit-mesh drawing */
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Edit-Mesh Drawing
+ * \{ */
+
struct GPUBatch *DRW_mesh_batch_cache_get_edit_triangles(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edit_vertices(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edit_edges(struct Mesh *me);
@@ -194,14 +260,39 @@ struct GPUBatch *DRW_mesh_batch_cache_get_edit_vnors(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edit_lnors(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edit_facedots(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edit_skin_roots(struct Mesh *me);
-/* edit-mesh selection */
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Edit-mesh Selection
+ * \{ */
+
struct GPUBatch *DRW_mesh_batch_cache_get_triangles_with_select_id(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_facedots_with_select_id(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edges_with_select_id(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_verts_with_select_id(struct Mesh *me);
-/* Object mode Wireframe overlays */
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Mode Wireframe Overlays
+ * \{ */
+
struct GPUBatch *DRW_mesh_batch_cache_get_wireframes_face(struct Mesh *me);
-/* edit-mesh UV editor */
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Edit-mesh UV Editor
+ * \{ */
+
+/**
+ * Creates the #GPUBatch for drawing the UV Stretching Area Overlay.
+ * Optional retrieves the total area or total uv area of the mesh.
+ *
+ * The `cache->tot_area` and cache->tot_uv_area` update are calculation are
+ * only valid after calling `DRW_mesh_batch_cache_create_requested`.
+ */
struct GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_area(struct Mesh *me,
float **tot_area,
float **tot_uv_area);
@@ -210,11 +301,22 @@ struct GPUBatch *DRW_mesh_batch_cache_get_edituv_faces(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edituv_edges(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edituv_verts(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edituv_facedots(struct Mesh *me);
-/* For Image UV editor. */
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name For Image UV Editor
+ * \{ */
+
struct GPUBatch *DRW_mesh_batch_cache_get_uv_edges(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edit_mesh_analysis(struct Mesh *me);
-/* For direct data access. */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name For Direct Data Access
+ * \{ */
+
struct GPUVertBuf *DRW_mesh_batch_cache_pos_vertbuf_get(struct Mesh *me);
struct GPUVertBuf *DRW_curve_batch_cache_pos_vertbuf_get(struct Curve *cu);
struct GPUVertBuf *DRW_mball_batch_cache_pos_vertbuf_get(struct Object *ob);
@@ -250,7 +352,12 @@ enum {
/* Beware to not go over 1 << 7 (it's a byte flag). */
};
-/* Particles */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Particles
+ * \{ */
+
struct GPUBatch *DRW_particles_batch_cache_get_hair(struct Object *object,
struct ParticleSystem *psys,
struct ModifierData *md);
@@ -266,6 +373,9 @@ struct GPUBatch *DRW_particles_batch_cache_get_edit_inner_points(struct Object *
struct GPUBatch *DRW_particles_batch_cache_get_edit_tip_points(struct Object *object,
struct ParticleSystem *psys,
struct PTCacheEdit *edit);
+
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/draw/intern/draw_cache_impl_gpencil.c b/source/blender/draw/intern/draw_cache_impl_gpencil.c
index e78e41b917a..483e52ed547 100644
--- a/source/blender/draw/intern/draw_cache_impl_gpencil.c
+++ b/source/blender/draw/intern/draw_cache_impl_gpencil.c
@@ -47,7 +47,10 @@
#define BEZIER_HANDLE (1 << 3)
#define COLOR_SHIFT 5
-/* ---------------------------------------------------------------------- */
+/* -------------------------------------------------------------------- */
+/** \name Internal Types
+ * \{ */
+
typedef struct GpencilBatchCache {
/** Instancing Data */
GPUVertBuf *vbo;
@@ -74,6 +77,12 @@ typedef struct GpencilBatchCache {
int cache_frame;
} GpencilBatchCache;
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Internal Utilities
+ * \{ */
+
static bool gpencil_batch_cache_valid(GpencilBatchCache *cache, bGPdata *gpd, int cfra)
{
bool valid = true;
@@ -151,6 +160,12 @@ static GpencilBatchCache *gpencil_batch_cache_get(Object *ob, int cfra)
return cache;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name BKE Callbacks
+ * \{ */
+
void DRW_gpencil_batch_cache_dirty_tag(bGPdata *gpd)
{
gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
@@ -166,7 +181,7 @@ void DRW_gpencil_batch_cache_free(bGPdata *gpd)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Vertex Formats.
+/** \name Vertex Formats
* \{ */
/* MUST match the format below. */
@@ -247,7 +262,7 @@ static GPUVertFormat *gpencil_color_format(void)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Vertex Buffers.
+/** \name Vertex Buffers
* \{ */
typedef struct gpIterData {
@@ -671,7 +686,6 @@ GPUBatch *DRW_cache_gpencil_sbuffer_fill_get(Object *ob)
return gpd->runtime.sbuffer_fill_batch;
}
-/* Sbuffer batches are temporary. We need to clear it after drawing */
void DRW_cache_gpencil_sbuffer_clear(Object *ob)
{
bGPdata *gpd = (bGPdata *)ob->data;
@@ -682,8 +696,9 @@ void DRW_cache_gpencil_sbuffer_clear(Object *ob)
/** \} */
-/* ---------------------------------------------------------------------- */
-/* Edit GPencil Batches */
+/* -------------------------------------------------------------------- */
+/** \name Edit GPencil Batches
+ * \{ */
#define GP_EDIT_POINT_SELECTED (1 << 0)
#define GP_EDIT_STROKE_SELECTED (1 << 1)
diff --git a/source/blender/draw/intern/draw_cache_impl_hair.c b/source/blender/draw/intern/draw_cache_impl_hair.c
index 41a0cca8a8f..ed0c46ad45a 100644
--- a/source/blender/draw/intern/draw_cache_impl_hair.c
+++ b/source/blender/draw/intern/draw_cache_impl_hair.c
@@ -333,7 +333,6 @@ static void hair_batch_cache_ensure_procedural_indices(Hair *hair,
prim_type, vbo, GPU_indexbuf_build(&elb), GPU_BATCH_OWNS_VBO | GPU_BATCH_OWNS_INDEX);
}
-/* Ensure all textures and buffers needed for GPU accelerated drawing. */
bool hair_ensure_procedural_data(Object *object,
ParticleHairCache **r_hair_cache,
GPUMaterial *gpu_material,
diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c
index 12c19c671ab..82b3b5aee41 100644
--- a/source/blender/draw/intern/draw_cache_impl_mesh.c
+++ b/source/blender/draw/intern/draw_cache_impl_mesh.c
@@ -535,7 +535,7 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me,
AttributeDomain domain = ATTR_DOMAIN_NUM;
if (type == CD_AUTO_FROM_NAME) {
- /* We need to deduct what exact layer is used.
+ /* We need to deduce what exact layer is used.
*
* We do it based on the specified name.
*/
@@ -1372,11 +1372,6 @@ static void edituv_request_active_uv(MeshBatchCache *cache, Mesh *me)
mesh_cd_layers_type_merge(&cache->cd_needed, cd_needed);
}
-/* Creates the GPUBatch for drawing the UV Stretching Area Overlay.
- * Optional retrieves the total area or total uv area of the mesh.
- *
- * The `cache->tot_area` and cache->tot_uv_area` update are calculation are
- * only valid after calling `DRW_mesh_batch_cache_create_requested`. */
GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_area(Mesh *me,
float **tot_area,
float **tot_uv_area)
@@ -1456,9 +1451,6 @@ GPUBatch *DRW_mesh_batch_cache_get_surface_edges(Mesh *me)
/** \name Grouped batch generation
* \{ */
-/* Thread safety need to be assured by caller. Don't call this during drawing.
- * NOTE: For now this only free the shading batches / vbo if any cd layers is
- * not needed anymore. */
void DRW_mesh_batch_cache_free_old(Mesh *me, int ctime)
{
MeshBatchCache *cache = me->runtime.batch_cache;
@@ -1526,7 +1518,6 @@ static void drw_mesh_batch_cache_check_available(struct TaskGraph *task_graph, M
}
#endif
-/* Can be called for any surface type. Mesh *me is the final mesh. */
void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
Object *ob,
Mesh *me,
diff --git a/source/blender/draw/intern/draw_cache_impl_metaball.c b/source/blender/draw/intern/draw_cache_impl_metaball.c
index 4d3a990ec72..63bffed0eaf 100644
--- a/source/blender/draw/intern/draw_cache_impl_metaball.c
+++ b/source/blender/draw/intern/draw_cache_impl_metaball.c
@@ -41,8 +41,9 @@
static void metaball_batch_cache_clear(MetaBall *mb);
-/* ---------------------------------------------------------------------- */
-/* MetaBall GPUBatch Cache */
+/* -------------------------------------------------------------------- */
+/** \name MetaBall GPUBatch Cache
+ * \{ */
typedef struct MetaBallBatchCache {
GPUBatch *batch;
@@ -175,6 +176,8 @@ static GPUIndexBuf *mball_batch_cache_get_edges_adj_lines(Object *ob, MetaBallBa
return cache->edges_adj_lines;
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Public Object/MetaBall API
* \{ */
@@ -303,3 +306,5 @@ int DRW_metaball_material_count_get(MetaBall *mb)
{
return max_ii(1, mb->totcol);
}
+
+/** \} */
diff --git a/source/blender/draw/intern/draw_cache_impl_particles.c b/source/blender/draw/intern/draw_cache_impl_particles.c
index 96bdca7d935..4583b90b144 100644
--- a/source/blender/draw/intern/draw_cache_impl_particles.c
+++ b/source/blender/draw/intern/draw_cache_impl_particles.c
@@ -1674,7 +1674,6 @@ GPUBatch *DRW_particles_batch_cache_get_edit_tip_points(Object *object,
return cache->edit_tip_points;
}
-/* Ensure all textures and buffers needed for GPU accelerated drawing. */
bool particles_ensure_procedural_data(Object *object,
ParticleSystem *psys,
ModifierData *md,
diff --git a/source/blender/draw/intern/draw_color_management.cc b/source/blender/draw/intern/draw_color_management.cc
index 70035c7c6f8..6259236e3cf 100644
--- a/source/blender/draw/intern/draw_color_management.cc
+++ b/source/blender/draw/intern/draw_color_management.cc
@@ -175,7 +175,6 @@ void DRW_viewport_colormanagement_set(GPUViewport *viewport)
blender::draw::color_management::viewport_color_management_set(*viewport);
}
-/* Draw texture to framebuffer without any color transforms */
void DRW_transform_none(GPUTexture *tex)
{
drw_state_set(DRW_STATE_WRITE_COLOR);
diff --git a/source/blender/draw/intern/draw_color_management.h b/source/blender/draw/intern/draw_color_management.h
index 9be105b88ec..7dff17b14c6 100644
--- a/source/blender/draw/intern/draw_color_management.h
+++ b/source/blender/draw/intern/draw_color_management.h
@@ -28,6 +28,9 @@ extern "C" {
struct GPUViewport;
+/**
+ * Draw texture to frame-buffer without any color transforms.
+ */
void DRW_transform_none(struct GPUTexture *tex);
void DRW_viewport_colormanagement_set(struct GPUViewport *viewport);
diff --git a/source/blender/draw/intern/draw_common.c b/source/blender/draw/intern/draw_common.c
index 2cbea2ae6d5..65afc5ed3d8 100644
--- a/source/blender/draw/intern/draw_common.c
+++ b/source/blender/draw/intern/draw_common.c
@@ -41,7 +41,9 @@
#define UI_COLOR_RGBA_FROM_U8(r, g, b, a, v4) \
ARRAY_SET_ITEMS(v4, (float)r / 255.0f, (float)g / 255.0f, (float)b / 255.0f, (float)a / 255.0f)
-/* Colors & Constant */
+/**
+ * Colors & Constant.
+ */
struct DRW_Global G_draw = {{{0}}};
static bool weight_ramp_custom = false;
@@ -287,10 +289,6 @@ DRWView *DRW_view_create_with_zoffset(const DRWView *parent_view,
/* ******************************************** COLOR UTILS ************************************ */
/* TODO: FINISH. */
-/**
- * Get the wire color theme_id of an object based on its state
- * \a r_color is a way to get a pointer to the static color var associated
- */
int DRW_object_wire_theme_get(Object *ob, ViewLayer *view_layer, float **r_color)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h
index 48a3fb209ba..6c3e0773a15 100644
--- a/source/blender/draw/intern/draw_common.h
+++ b/source/blender/draw/intern/draw_common.h
@@ -161,6 +161,10 @@ struct DRWView *DRW_view_create_with_zoffset(const struct DRWView *parent_view,
const struct RegionView3D *rv3d,
float offset);
+/**
+ * Get the wire color theme_id of an object based on its state
+ * \a r_color is a way to get a pointer to the static color var associated
+ */
int DRW_object_wire_theme_get(struct Object *ob, struct ViewLayer *view_layer, float **r_color);
float *DRW_color_background_blend_get(int theme_id);
@@ -169,13 +173,18 @@ bool DRW_object_axis_orthogonal_to_view(struct Object *ob, int axis);
/* draw_hair.c */
-/* This creates a shading group with display hairs.
- * The draw call is already added by this function, just add additional uniforms. */
+/**
+ * This creates a shading group with display hairs.
+ * The draw call is already added by this function, just add additional uniforms.
+ */
struct DRWShadingGroup *DRW_shgroup_hair_create_sub(struct Object *object,
struct ParticleSystem *psys,
struct ModifierData *md,
struct DRWShadingGroup *shgrp,
struct GPUMaterial *gpu_material);
+/**
+ * \note Only valid after #DRW_hair_update().
+ */
struct GPUVertBuf *DRW_hair_pos_buffer_get(struct Object *object,
struct ParticleSystem *psys,
struct ModifierData *md);
@@ -201,6 +210,7 @@ void DRW_smoke_free(struct FluidModifierData *fmd);
void DRW_smoke_free_velocity(struct FluidModifierData *fmd);
/* draw_common.c */
+
struct DRW_Global {
/** If needed, contains all global/Theme colors
* Add needed theme colors / values to DRW_globals_update() and update UBO
diff --git a/source/blender/draw/intern/draw_debug.c b/source/blender/draw/intern/draw_debug.c
index 59c6efe1a61..e0114a6230e 100644
--- a/source/blender/draw/intern/draw_debug.c
+++ b/source/blender/draw/intern/draw_debug.c
@@ -68,7 +68,6 @@ void DRW_debug_polygon_v3(const float (*v)[3], const int vert_len, const float c
}
}
-/* NOTE: g_modelmat is still applied on top. */
void DRW_debug_m4(const float m[4][4])
{
float v0[3] = {0.0f, 0.0f, 0.0f};
diff --git a/source/blender/draw/intern/draw_debug.h b/source/blender/draw/intern/draw_debug.h
index 149825974d4..2f1a082af96 100644
--- a/source/blender/draw/intern/draw_debug.h
+++ b/source/blender/draw/intern/draw_debug.h
@@ -29,6 +29,9 @@ void DRW_debug_modelmat(const float modelmat[4][4]);
void DRW_debug_line_v3v3(const float v1[3], const float v2[3], const float color[4]);
void DRW_debug_polygon_v3(const float (*v)[3], const int vert_len, const float color[4]);
+/**
+ * \note g_modelmat is still applied on top.
+ */
void DRW_debug_m4(const float m[4][4]);
void DRW_debug_m4_as_bbox(const float m[4][4], const float color[4], const bool invert);
void DRW_debug_bbox(const BoundBox *bbox, const float color[4]);
diff --git a/source/blender/draw/intern/draw_fluid.c b/source/blender/draw/intern/draw_fluid.c
index 9cfdbf7c688..616307ca86b 100644
--- a/source/blender/draw/intern/draw_fluid.c
+++ b/source/blender/draw/intern/draw_fluid.c
@@ -589,9 +589,10 @@ void DRW_fluid_ensure_range_field(FluidModifierData *fmd)
#endif /* WITH_FLUID */
}
-/* TODO: Unify with the other #GPU_free_smoke. */
void DRW_smoke_free_velocity(FluidModifierData *fmd)
{
+ /* TODO: Unify with the other #GPU_free_smoke. */
+
if (fmd->type & MOD_FLUID_TYPE_DOMAIN && fmd->domain) {
if (fmd->domain->tex_velocity_x) {
GPU_texture_free(fmd->domain->tex_velocity_x);
diff --git a/source/blender/draw/intern/draw_hair.c b/source/blender/draw/intern/draw_hair.c
index 5c7eb083fc9..0abb00a71a9 100644
--- a/source/blender/draw/intern/draw_hair.c
+++ b/source/blender/draw/intern/draw_hair.c
@@ -203,7 +203,6 @@ static ParticleHairCache *drw_hair_particle_cache_get(Object *object,
return cache;
}
-/* NOTE: Only valid after DRW_hair_update(). */
GPUVertBuf *DRW_hair_pos_buffer_get(Object *object, ParticleSystem *psys, ModifierData *md)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
diff --git a/source/blender/draw/intern/draw_hair_private.h b/source/blender/draw/intern/draw_hair_private.h
index 289a1690fc6..d5d9a9fb299 100644
--- a/source/blender/draw/intern/draw_hair_private.h
+++ b/source/blender/draw/intern/draw_hair_private.h
@@ -93,6 +93,9 @@ typedef struct ParticleHairCache {
void particle_batch_cache_clear_hair(struct ParticleHairCache *hair_cache);
+/**
+ * Ensure all textures and buffers needed for GPU accelerated drawing.
+ */
bool particles_ensure_procedural_data(struct Object *object,
struct ParticleSystem *psys,
struct ModifierData *md,
@@ -101,6 +104,9 @@ bool particles_ensure_procedural_data(struct Object *object,
int subdiv,
int thickness_res);
+/**
+ * Ensure all textures and buffers needed for GPU accelerated drawing.
+ */
bool hair_ensure_procedural_data(struct Object *object,
struct ParticleHairCache **r_hair_cache,
struct GPUMaterial *gpu_material,
diff --git a/source/blender/draw/intern/draw_instance_data.c b/source/blender/draw/intern/draw_instance_data.c
index 29112ee4788..7e1d1208698 100644
--- a/source/blender/draw/intern/draw_instance_data.c
+++ b/source/blender/draw/intern/draw_instance_data.c
@@ -112,14 +112,6 @@ static void instancing_batch_references_remove(GPUBatch *batch)
/** \name Instance Buffer Management
* \{ */
-/**
- * This manager allows to distribute existing batches for instancing
- * attributes. This reduce the number of batches creation.
- * Querying a batch is done with a vertex format. This format should
- * be static so that its pointer never changes (because we are using
- * this pointer as identifier [we don't want to check the full format
- * that would be too slow]).
- */
GPUVertBuf *DRW_temp_buffer_request(DRWInstanceDataList *idatalist,
GPUVertFormat *format,
int *vert_len)
@@ -143,8 +135,6 @@ GPUVertBuf *DRW_temp_buffer_request(DRWInstanceDataList *idatalist,
return handle->buf;
}
-/* NOTE: Does not return a valid drawable batch until DRW_instance_buffer_finish has run.
- * Initialization is delayed because instancer or geom could still not be initialized. */
GPUBatch *DRW_temp_batch_instance_request(DRWInstanceDataList *idatalist,
GPUVertBuf *buf,
GPUBatch *instancer,
@@ -185,7 +175,6 @@ GPUBatch *DRW_temp_batch_instance_request(DRWInstanceDataList *idatalist,
return batch;
}
-/* NOTE: Use only with buf allocated via DRW_temp_buffer_request. */
GPUBatch *DRW_temp_batch_request(DRWInstanceDataList *idatalist,
GPUVertBuf *buf,
GPUPrimType prim_type)
@@ -301,9 +290,6 @@ static void DRW_instance_data_free(DRWInstanceData *idata)
BLI_mempool_destroy(idata->mempool);
}
-/**
- * Return a pointer to the next instance data space.
- */
void *DRW_instance_data_next(DRWInstanceData *idata)
{
return BLI_mempool_alloc(idata->mempool);
@@ -421,6 +407,7 @@ void DRW_instance_data_list_resize(DRWInstanceDataList *idatalist)
}
/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Sparse Uniform Buffer
* \{ */
@@ -453,7 +440,6 @@ static void drw_sparse_uniform_buffer_init(DRWSparseUniformBuf *buffer,
buffer->chunk_bytes = item_size * chunk_size;
}
-/** Allocate a chunked UBO with the specified item and chunk size. */
DRWSparseUniformBuf *DRW_sparse_uniform_buffer_new(unsigned int item_size, unsigned int chunk_size)
{
DRWSparseUniformBuf *buf = MEM_mallocN(sizeof(DRWSparseUniformBuf), __func__);
@@ -461,7 +447,6 @@ DRWSparseUniformBuf *DRW_sparse_uniform_buffer_new(unsigned int item_size, unsig
return buf;
}
-/** Flush data from ordinary memory to UBOs. */
void DRW_sparse_uniform_buffer_flush(DRWSparseUniformBuf *buffer)
{
for (int i = 0; i < buffer->num_chunks; i++) {
@@ -474,7 +459,6 @@ void DRW_sparse_uniform_buffer_flush(DRWSparseUniformBuf *buffer)
}
}
-/** Clean all buffers and free unused ones. */
void DRW_sparse_uniform_buffer_clear(DRWSparseUniformBuf *buffer, bool free_all)
{
int max_used_chunk = 0;
@@ -517,14 +501,12 @@ void DRW_sparse_uniform_buffer_clear(DRWSparseUniformBuf *buffer, bool free_all)
BLI_bitmap_set_all(buffer->chunk_used, false, buffer->num_chunks);
}
-/** Frees the buffer. */
void DRW_sparse_uniform_buffer_free(DRWSparseUniformBuf *buffer)
{
DRW_sparse_uniform_buffer_clear(buffer, true);
MEM_freeN(buffer);
}
-/** Checks if the buffer contains any allocated chunks. */
bool DRW_sparse_uniform_buffer_is_empty(DRWSparseUniformBuf *buffer)
{
return buffer->num_chunks == 0;
@@ -538,7 +520,6 @@ static GPUUniformBuf *drw_sparse_uniform_buffer_get_ubo(DRWSparseUniformBuf *buf
return NULL;
}
-/** Bind the UBO for the given chunk, if present. A NULL buffer pointer is handled as empty. */
void DRW_sparse_uniform_buffer_bind(DRWSparseUniformBuf *buffer, int chunk, int location)
{
GPUUniformBuf *ubo = drw_sparse_uniform_buffer_get_ubo(buffer, chunk);
@@ -547,7 +528,6 @@ void DRW_sparse_uniform_buffer_bind(DRWSparseUniformBuf *buffer, int chunk, int
}
}
-/** Unbind the UBO for the given chunk, if present. A NULL buffer pointer is handled as empty. */
void DRW_sparse_uniform_buffer_unbind(DRWSparseUniformBuf *buffer, int chunk)
{
GPUUniformBuf *ubo = drw_sparse_uniform_buffer_get_ubo(buffer, chunk);
@@ -556,7 +536,6 @@ void DRW_sparse_uniform_buffer_unbind(DRWSparseUniformBuf *buffer, int chunk)
}
}
-/** Returns a pointer to the given item of the given chunk, allocating memory if necessary. */
void *DRW_sparse_uniform_buffer_ensure_item(DRWSparseUniformBuf *buffer, int chunk, int item)
{
if (chunk >= buffer->num_chunks) {
diff --git a/source/blender/draw/intern/draw_instance_data.h b/source/blender/draw/intern/draw_instance_data.h
index c959a9e19d6..fb88b3dc6ec 100644
--- a/source/blender/draw/intern/draw_instance_data.h
+++ b/source/blender/draw/intern/draw_instance_data.h
@@ -38,21 +38,41 @@ typedef struct DRWInstanceData DRWInstanceData;
typedef struct DRWInstanceDataList DRWInstanceDataList;
typedef struct DRWSparseUniformBuf DRWSparseUniformBuf;
+/**
+ * Return a pointer to the next instance data space.
+ */
void *DRW_instance_data_next(DRWInstanceData *idata);
DRWInstanceData *DRW_instance_data_request(DRWInstanceDataList *idatalist, uint attr_size);
+/**
+ * This manager allows to distribute existing batches for instancing
+ * attributes. This reduce the number of batches creation.
+ * Querying a batch is done with a vertex format. This format should
+ * be static so that its pointer never changes (because we are using
+ * this pointer as identifier [we don't want to check the full format
+ * that would be too slow]).
+ */
GPUVertBuf *DRW_temp_buffer_request(DRWInstanceDataList *idatalist,
GPUVertFormat *format,
int *vert_len);
+/**
+ * \note Does not return a valid drawable batch until DRW_instance_buffer_finish has run.
+ * Initialization is delayed because instancer or geom could still not be initialized.
+ */
GPUBatch *DRW_temp_batch_instance_request(DRWInstanceDataList *idatalist,
GPUVertBuf *buf,
GPUBatch *instancer,
GPUBatch *geom);
+/**
+ * \note Use only with buf allocated via DRW_temp_buffer_request.
+ */
GPUBatch *DRW_temp_batch_request(DRWInstanceDataList *idatalist,
GPUVertBuf *buf,
GPUPrimType type);
-/* Upload all instance data to the GPU as soon as possible. */
+/**
+ * Upload all instance data to the GPU as soon as possible.
+ */
void DRW_instance_buffer_finish(DRWInstanceDataList *idatalist);
void DRW_instance_data_list_reset(DRWInstanceDataList *idatalist);
@@ -60,17 +80,43 @@ void DRW_instance_data_list_free_unused(DRWInstanceDataList *idatalist);
void DRW_instance_data_list_resize(DRWInstanceDataList *idatalist);
/* Sparse chunked UBO manager. */
+
+/**
+ * Allocate a chunked UBO with the specified item and chunk size.
+ */
DRWSparseUniformBuf *DRW_sparse_uniform_buffer_new(unsigned int item_size,
unsigned int chunk_size);
+/**
+ * Flush data from ordinary memory to UBOs.
+ */
void DRW_sparse_uniform_buffer_flush(DRWSparseUniformBuf *buffer);
+/**
+ * Clean all buffers and free unused ones.
+ */
void DRW_sparse_uniform_buffer_clear(DRWSparseUniformBuf *buffer, bool free_all);
+/**
+ * Frees the buffer.
+ */
void DRW_sparse_uniform_buffer_free(DRWSparseUniformBuf *buffer);
+/**
+ * Checks if the buffer contains any allocated chunks.
+ */
bool DRW_sparse_uniform_buffer_is_empty(DRWSparseUniformBuf *buffer);
+/**
+ * Bind the UBO for the given chunk, if present. A NULL buffer pointer is handled as empty.
+ */
void DRW_sparse_uniform_buffer_bind(DRWSparseUniformBuf *buffer, int chunk, int location);
+/**
+ * Unbind the UBO for the given chunk, if present. A NULL buffer pointer is handled as empty.
+ */
void DRW_sparse_uniform_buffer_unbind(DRWSparseUniformBuf *buffer, int chunk);
+/**
+ * Returns a pointer to the given item of the given chunk, allocating memory if necessary.
+ */
void *DRW_sparse_uniform_buffer_ensure_item(DRWSparseUniformBuf *buffer, int chunk, int item);
/* Uniform attribute UBO management. */
+
struct GHash *DRW_uniform_attrs_pool_new(void);
void DRW_uniform_attrs_pool_flush_all(struct GHash *table);
void DRW_uniform_attrs_pool_clear_all(struct GHash *table);
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index 1d9bc607590..930fb6eabef 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -173,7 +173,8 @@ static void drw_task_graph_deinit(void)
{
BLI_task_graph_work_and_wait(DST.task_graph);
- BLI_gset_free(DST.delayed_extraction, (void (*)(void *key))drw_batch_cache_generate_requested);
+ BLI_gset_free(DST.delayed_extraction,
+ (void (*)(void *key))drw_batch_cache_generate_requested_evaluated_mesh);
DST.delayed_extraction = NULL;
BLI_task_graph_work_and_wait(DST.task_graph);
@@ -203,11 +204,6 @@ bool DRW_object_is_renderable(const Object *ob)
return true;
}
-/* Does `ob` needs to be rendered in edit mode.
- *
- * When using duplicate linked meshes, objects that are not in edit-mode will be drawn as
- * it is in edit mode, when another object with the same mesh is in edit mode.
- * This will not be the case when one of the objects are influenced by modifiers. */
bool DRW_object_is_in_edit_mode(const Object *ob)
{
if (BKE_object_is_in_editmode(ob)) {
@@ -235,10 +231,6 @@ bool DRW_object_is_in_edit_mode(const Object *ob)
return false;
}
-/**
- * Return whether this object is visible depending if
- * we are rendering or drawing in the viewport.
- */
int DRW_object_visibility_in_active_context(const Object *ob)
{
const eEvaluationMode mode = DRW_state_is_scene_render() ? DAG_EVAL_RENDER : DAG_EVAL_VIEWPORT;
@@ -321,7 +313,6 @@ struct DupliObject *DRW_object_get_dupli(const Object *UNUSED(ob))
/** \name Viewport (DRW_viewport)
* \{ */
-/* WARNING: only use for custom pipeline. 99% of the time, you don't want to use this. */
void DRW_render_viewport_size_set(const int size[2])
{
DST.size[0] = size[0];
@@ -778,7 +769,6 @@ static void drw_duplidata_free(void)
}
}
-/* Return NULL if not a dupli or a pointer of pointer to the engine data */
void **DRW_duplidata_get(void *vedata)
{
if (DST.dupli_source == NULL) {
@@ -874,9 +864,6 @@ static bool id_can_have_drawdata(const ID *id)
return id_type_can_have_drawdata(GS(id->name));
}
-/* Get DrawData from the given ID-block. In order for this to work, we assume that
- * the DrawData pointer is stored in the struct in the same fashion as in IdDdtTemplate.
- */
DrawDataList *DRW_drawdatalist_from_id(ID *id)
{
/* only some ID-blocks have this info for now, so we cast the
@@ -1148,7 +1135,6 @@ static void drw_engines_draw_text(void)
}
}
-/* Draw render engine info. */
void DRW_draw_region_engine_info(int xoffset, int *yoffset, int line_height)
{
DRW_ENABLED_ENGINE_ITER (DST.view_data_active, engine, data) {
@@ -1367,6 +1353,61 @@ void DRW_notify_view_update(const DRWUpdateContext *update_ctx)
BLI_ticket_mutex_unlock(DST.gl_context_mutex);
}
+/* update a viewport which belongs to a GPUOffscreen */
+static void drw_notify_view_update_offscreen(struct Depsgraph *depsgraph,
+ RenderEngineType *engine_type,
+ ARegion *region,
+ View3D *v3d,
+ GPUViewport *viewport)
+{
+
+ if (viewport && GPU_viewport_do_update(viewport)) {
+
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph);
+ RegionView3D *rv3d = region->regiondata;
+
+ const bool gpencil_engine_needed = drw_gpencil_engine_needed(depsgraph, v3d);
+
+ /* Reset before using it. */
+ drw_state_prepare_clean_for_draw(&DST);
+
+ DST.draw_ctx = (DRWContextState){
+ .region = region,
+ .rv3d = rv3d,
+ .v3d = v3d,
+ .scene = scene,
+ .view_layer = view_layer,
+ .obact = OBACT(view_layer),
+ .engine_type = engine_type,
+ .depsgraph = depsgraph,
+ };
+
+ /* Custom lightweight initialize to avoid resetting the memory-pools. */
+ DST.viewport = viewport;
+ DST.vmempool = drw_viewport_data_ensure(DST.viewport);
+
+ /* Separate update for each stereo view. */
+ int view_count = GPU_viewport_is_stereo_get(viewport) ? 2 : 1;
+ for (int view = 0; view < view_count; view++) {
+ DST.view_data_active = DST.vmempool->view_data[view];
+
+ drw_engines_enable(view_layer, engine_type, gpencil_engine_needed);
+ drw_engines_data_validate();
+
+ DRW_ENABLED_ENGINE_ITER (DST.view_data_active, draw_engine, data) {
+ if (draw_engine->view_update) {
+ draw_engine->view_update(data);
+ }
+ }
+
+ drw_engines_disable();
+ }
+
+ drw_manager_exit(&DST);
+ }
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1549,9 +1590,6 @@ struct DRWTextStore *DRW_text_cache_ensure(void)
/** \name Main Draw Loops (DRW_draw)
* \{ */
-/* Everything starts here.
- * This function takes care of calling all cache and rendering functions
- * for each relevant engine / mode engine. */
void DRW_draw_view(const bContext *C)
{
View3D *v3d = CTX_wm_view3d(C);
@@ -1579,10 +1617,6 @@ void DRW_draw_view(const bContext *C)
}
}
-/**
- * Used for both regular and off-screen drawing.
- * Need to reset DST before calling this function
- */
void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph,
RenderEngineType *engine_type,
ARegion *region,
@@ -1729,9 +1763,6 @@ void DRW_draw_render_loop(struct Depsgraph *depsgraph,
DRW_draw_render_loop_ex(depsgraph, engine_type, region, v3d, viewport, NULL);
}
-/**
- * \param viewport: can be NULL, in this case we create one.
- */
void DRW_draw_render_loop_offscreen(struct Depsgraph *depsgraph,
RenderEngineType *engine_type,
ARegion *region,
@@ -1742,11 +1773,14 @@ void DRW_draw_render_loop_offscreen(struct Depsgraph *depsgraph,
GPUOffScreen *ofs,
GPUViewport *viewport)
{
- /* Create temporary viewport if needed. */
+ /* Create temporary viewport if needed or update the existing viewport. */
GPUViewport *render_viewport = viewport;
if (viewport == NULL) {
render_viewport = GPU_viewport_create();
}
+ else {
+ drw_notify_view_update_offscreen(depsgraph, engine_type, region, v3d, render_viewport);
+ }
GPU_viewport_bind_from_offscreen(render_viewport, ofs);
@@ -1790,7 +1824,6 @@ void DRW_draw_render_loop_offscreen(struct Depsgraph *depsgraph,
}
}
-/* Helper to check if exit object type to render. */
bool DRW_render_check_grease_pencil(Depsgraph *depsgraph)
{
if (!drw_gpencil_engine_needed(depsgraph, NULL)) {
@@ -2019,9 +2052,6 @@ void DRW_render_object_iter(
drw_task_graph_deinit();
}
-/* Assume a valid gl context is bound (and that the gl_context_mutex has been acquired).
- * This function only setup DST and execute the given function.
- * Warning: similar to DRW_render_to_image you cannot use default lists (dfbl & dtxl). */
void DRW_custom_pipeline(DrawEngineType *draw_engine_type,
struct Depsgraph *depsgraph,
void (*callback)(void *vedata, void *user_data),
@@ -2067,8 +2097,6 @@ void DRW_custom_pipeline(DrawEngineType *draw_engine_type,
drw_manager_exit(&DST);
}
-/* Used when the render engine want to redo another cache populate inside the same render frame.
- */
void DRW_cache_restart(void)
{
drw_manager_init(&DST, DST.viewport, (int[2]){UNPACK2(DST.size)});
@@ -2259,7 +2287,6 @@ static void draw_select_framebuffer_depth_only_setup(const int size[2])
}
}
-/* Must run after all instance datas have been added. */
void DRW_render_instance_buffer_finish(void)
{
BLI_assert_msg(!DST.buffer_finish_called, "DRW_render_instance_buffer_finish called twice!");
@@ -2268,7 +2295,6 @@ void DRW_render_instance_buffer_finish(void)
drw_resource_buffer_finish(DST.vmempool);
}
-/* WARNING: Changing frame might free the ViewLayerEngineData */
void DRW_render_set_time(RenderEngine *engine, Depsgraph *depsgraph, int frame, float subframe)
{
RE_engine_frame_set(engine, frame, subframe);
@@ -2276,9 +2302,6 @@ void DRW_render_set_time(RenderEngine *engine, Depsgraph *depsgraph, int frame,
DST.draw_ctx.view_layer = DEG_get_evaluated_view_layer(depsgraph);
}
-/**
- * object mode select-loop, see: ED_view3d_draw_select_loop (legacy drawing).
- */
void DRW_draw_select_loop(struct Depsgraph *depsgraph,
ARegion *region,
View3D *v3d,
@@ -2606,9 +2629,6 @@ static void drw_draw_depth_loop_impl(struct Depsgraph *depsgraph,
}
}
-/**
- * object mode select-loop, see: ED_view3d_draw_depth_loop (legacy drawing).
- */
void DRW_draw_depth_loop(struct Depsgraph *depsgraph,
ARegion *region,
View3D *v3d,
@@ -2636,9 +2656,6 @@ void DRW_draw_depth_loop(struct Depsgraph *depsgraph,
drw_draw_depth_loop_impl(depsgraph, region, v3d, viewport, false);
}
-/**
- * Converted from ED_view3d_draw_depth_gpencil (legacy drawing).
- */
void DRW_draw_depth_loop_gpencil(struct Depsgraph *depsgraph,
ARegion *region,
View3D *v3d,
@@ -2731,9 +2748,6 @@ void DRW_draw_select_id(Depsgraph *depsgraph, ARegion *region, View3D *v3d, cons
drw_manager_exit(&DST);
}
-/**
- * Clears the Depth Buffer and draws only the specified object.
- */
void DRW_draw_depth_object(
Scene *scene, ARegion *region, View3D *v3d, GPUViewport *viewport, Object *object)
{
@@ -2814,19 +2828,12 @@ void DRW_draw_depth_object(
/** \name Draw Manager State (DRW_state)
* \{ */
-/**
- * When false, drawing doesn't output to a pixel buffer
- * eg: Occlusion queries, or when we have setup a context to draw in already.
- */
bool DRW_state_is_fbo(void)
{
return ((DST.default_framebuffer != NULL) || DST.options.is_image_render) &&
!DRW_state_is_depth() && !DRW_state_is_select();
}
-/**
- * For when engines need to know if this is drawing for selection or not.
- */
bool DRW_state_is_select(void)
{
return DST.options.is_select;
@@ -2842,27 +2849,17 @@ bool DRW_state_is_depth(void)
return DST.options.is_depth;
}
-/**
- * Whether we are rendering for an image
- */
bool DRW_state_is_image_render(void)
{
return DST.options.is_image_render;
}
-/**
- * Whether we are rendering only the render engine,
- * or if we should also render the mode engines.
- */
bool DRW_state_is_scene_render(void)
{
BLI_assert(DST.options.is_scene_render ? DST.options.is_image_render : true);
return DST.options.is_scene_render;
}
-/**
- * Whether we are rendering simple opengl render
- */
bool DRW_state_is_opengl_render(void)
{
return DST.options.is_image_render && !DST.options.is_scene_render;
@@ -2877,28 +2874,18 @@ bool DRW_state_is_playback(void)
return false;
}
-/**
- * Is the user navigating the region.
- */
bool DRW_state_is_navigating(void)
{
const RegionView3D *rv3d = DST.draw_ctx.rv3d;
return (rv3d) && (rv3d->rflag & (RV3D_NAVIGATING | RV3D_PAINTING));
}
-/**
- * Should text draw in this mode?
- */
bool DRW_state_show_text(void)
{
return (DST.options.is_select) == 0 && (DST.options.is_depth) == 0 &&
(DST.options.is_scene_render) == 0 && (DST.options.draw_text) == 0;
}
-/**
- * Should draw support elements
- * Objects center, selection outline, probe data, ...
- */
bool DRW_state_draw_support(void)
{
View3D *v3d = DST.draw_ctx.v3d;
@@ -2906,9 +2893,6 @@ bool DRW_state_draw_support(void)
((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0);
}
-/**
- * Whether we should render the background
- */
bool DRW_state_draw_background(void)
{
return DST.options.draw_background;
@@ -3160,6 +3144,8 @@ void DRW_opengl_context_disable_ex(bool restore)
void DRW_opengl_context_enable(void)
{
+ /* TODO: should be replace by a more elegant alternative. */
+
if (G.background && DST.gl_context == NULL) {
WM_init_opengl();
}
@@ -3188,7 +3174,6 @@ void DRW_opengl_render_context_disable(void *re_gl_context)
BLI_ticket_mutex_unlock(DST.gl_context_mutex);
}
-/* Needs to be called AFTER DRW_opengl_render_context_enable() */
void DRW_gpu_render_context_enable(void *re_gpu_context)
{
/* If thread is main you should use DRW_opengl_context_enable(). */
@@ -3197,7 +3182,6 @@ void DRW_gpu_render_context_enable(void *re_gpu_context)
GPU_context_active_set(re_gpu_context);
}
-/* Needs to be called BEFORE DRW_opengl_render_context_disable() */
void DRW_gpu_render_context_disable(void *UNUSED(re_gpu_context))
{
GPU_flush();
@@ -3242,6 +3226,8 @@ void DRW_xr_drawing_end(void)
#endif
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Internal testing API for gtests
* \{ */
diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h
index 162fe9b5fd1..a4924711384 100644
--- a/source/blender/draw/intern/draw_manager.h
+++ b/source/blender/draw/intern/draw_manager.h
@@ -663,7 +663,12 @@ eDRWCommandType command_type_get(const uint64_t *command_type_bits, int index);
void drw_batch_cache_validate(Object *ob);
void drw_batch_cache_generate_requested(struct Object *ob);
+
+/**
+ * \warning Only evaluated mesh data is handled by this delayed generation.
+ */
void drw_batch_cache_generate_requested_delayed(Object *ob);
+void drw_batch_cache_generate_requested_evaluated_mesh(Object *ob);
void drw_resource_buffer_finish(DRWData *vmempool);
diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c
index c98ecc8ac00..e71a1298812 100644
--- a/source/blender/draw/intern/draw_manager_data.c
+++ b/source/blender/draw/intern/draw_manager_data.c
@@ -304,6 +304,7 @@ void DRW_shgroup_uniform_bool(DRWShadingGroup *shgroup,
const int *value,
int arraysize)
{
+ /* Boolean are expected to be 4bytes longs for OpenGL! */
drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_INT, value, 1, arraysize);
}
@@ -381,7 +382,6 @@ void DRW_shgroup_uniform_mat4(DRWShadingGroup *shgroup, const char *name, const
drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_FLOAT, (float *)value, 16, 1);
}
-/* Stores the int instead of a pointer. */
void DRW_shgroup_uniform_int_copy(DRWShadingGroup *shgroup, const char *name, const int value)
{
drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_INT_COPY, &value, 1, 1);
@@ -833,7 +833,6 @@ void DRW_shgroup_call_range(
drw_command_draw_range(shgroup, geom, handle, v_sta, v_ct);
}
-/* A count of 0 instance will use the default number of instance in the batch. */
void DRW_shgroup_call_instance_range(
DRWShadingGroup *shgroup, Object *ob, struct GPUBatch *geom, uint i_sta, uint i_ct)
{
@@ -888,7 +887,6 @@ void DRW_shgroup_call_procedural_triangles(DRWShadingGroup *shgroup, Object *ob,
drw_shgroup_call_procedural_add_ex(shgroup, geom, ob, tri_count * 3);
}
-/* Should be removed */
void DRW_shgroup_call_instances(DRWShadingGroup *shgroup,
Object *ob,
struct GPUBatch *geom,
@@ -1441,10 +1439,6 @@ DRWShadingGroup *DRW_shgroup_transform_feedback_create(struct GPUShader *shader,
return shgroup;
}
-/**
- * State is added to #Pass.state while drawing.
- * Use to temporarily enable draw options.
- */
void DRW_shgroup_state_enable(DRWShadingGroup *shgroup, DRWState state)
{
drw_command_set_mutable_state(shgroup, state, 0x0);
@@ -1463,7 +1457,6 @@ void DRW_shgroup_stencil_set(DRWShadingGroup *shgroup,
drw_command_set_stencil_mask(shgroup, write_mask, reference, compare_mask);
}
-/* TODO: remove this function. */
void DRW_shgroup_stencil_mask(DRWShadingGroup *shgroup, uint mask)
{
drw_command_set_stencil_mask(shgroup, 0xFF, mask, 0xFF);
@@ -1758,7 +1751,6 @@ static void draw_view_matrix_state_update(DRWViewUboStorage *storage,
storage->viewvecs[1][2] = view_vecs[3][2] - view_vecs[0][2];
}
-/* Create a view with culling. */
DRWView *DRW_view_create(const float viewmat[4][4],
const float winmat[4][4],
const float (*culling_viewmat)[4],
@@ -1785,7 +1777,6 @@ DRWView *DRW_view_create(const float viewmat[4][4],
return view;
}
-/* Create a view with culling done by another view. */
DRWView *DRW_view_create_sub(const DRWView *parent_view,
const float viewmat[4][4],
const float winmat[4][4])
@@ -1807,13 +1798,10 @@ DRWView *DRW_view_create_sub(const DRWView *parent_view,
return view;
}
-/**
- * DRWView Update:
+/* DRWView Update:
* This is meant to be done on existing views when rendering in a loop and there is no
- * need to allocate more DRWViews.
- */
+ * need to allocate more DRWViews. */
-/* Update matrices of a view created with DRW_view_create_sub. */
void DRW_view_update_sub(DRWView *view, const float viewmat[4][4], const float winmat[4][4])
{
BLI_assert(view->parent != NULL);
@@ -1824,7 +1812,6 @@ void DRW_view_update_sub(DRWView *view, const float viewmat[4][4], const float w
draw_view_matrix_state_update(&view->storage, viewmat, winmat);
}
-/* Update matrices of a view created with DRW_view_create. */
void DRW_view_update(DRWView *view,
const float viewmat[4][4],
const float winmat[4][4],
@@ -1893,13 +1880,11 @@ void DRW_view_update(DRWView *view,
#endif
}
-/* Return default view if it is a viewport render. */
const DRWView *DRW_view_default_get(void)
{
return DST.view_default;
}
-/* WARNING: Only use in render AND only if you are going to set view_default again. */
void DRW_view_reset(void)
{
DST.view_default = NULL;
@@ -1907,18 +1892,12 @@ void DRW_view_reset(void)
DST.view_previous = NULL;
}
-/* MUST only be called once per render and only in render mode. Sets default view. */
void DRW_view_default_set(DRWView *view)
{
BLI_assert(DST.view_default == NULL);
DST.view_default = view;
}
-/**
- * This only works if DRWPasses have been tagged with DRW_STATE_CLIP_PLANES,
- * and if the shaders have support for it (see usage of gl_ClipDistance).
- * NOTE: planes must be in world space.
- */
void DRW_view_clip_planes_set(DRWView *view, float (*planes)[4], int plane_len)
{
BLI_assert(plane_len <= MAX_CLIP_PLANES);
@@ -1933,14 +1912,11 @@ void DRW_view_camtexco_set(DRWView *view, float texco[4])
copy_v4_v4(view->storage.viewcamtexcofac, texco);
}
-/* Return world space frustum corners. */
void DRW_view_frustum_corners_get(const DRWView *view, BoundBox *corners)
{
memcpy(corners, &view->frustum_corners, sizeof(view->frustum_corners));
}
-/* Return world space frustum sides as planes.
- * See draw_frustum_culling_planes_calc() for the plane order. */
void DRW_view_frustum_planes_get(const DRWView *view, float planes[6][4])
{
memcpy(planes, &view->frustum_planes, sizeof(view->frustum_planes));
@@ -2022,8 +1998,6 @@ DRWPass *DRW_pass_create(const char *name, DRWState state)
return pass;
}
-/* Create an instance of the original pass that will execute the same drawcalls but with its own
- * DRWState. */
DRWPass *DRW_pass_create_instance(const char *name, DRWPass *original, DRWState state)
{
DRWPass *pass = DRW_pass_create(name, state);
@@ -2032,7 +2006,6 @@ DRWPass *DRW_pass_create_instance(const char *name, DRWPass *original, DRWState
return pass;
}
-/* Link two passes so that they are both rendered if the first one is being drawn. */
void DRW_pass_link(DRWPass *first, DRWPass *second)
{
BLI_assert(first != second);
@@ -2093,10 +2066,6 @@ static int pass_shgroup_dist_sort(const void *a, const void *b)
#undef SORT_IMPL_LINKTYPE
-/**
- * Sort Shading groups by decreasing Z of their first draw call.
- * This is useful for order dependent effect such as alpha-blending.
- */
void DRW_pass_sort_shgroup_z(DRWPass *pass)
{
const float(*viewinv)[4] = DST.view_active->storage.viewinv;
@@ -2147,9 +2116,6 @@ void DRW_pass_sort_shgroup_z(DRWPass *pass)
pass->shgroups.last = last;
}
-/**
- * Reverse Shading group submission order.
- */
void DRW_pass_sort_shgroup_reverse(DRWPass *pass)
{
pass->shgroups.last = pass->shgroups.first;
diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c
index aa01ca7a262..8dd24c01337 100644
--- a/source/blender/draw/intern/draw_manager_exec.c
+++ b/source/blender/draw/intern/draw_manager_exec.c
@@ -273,7 +273,6 @@ static void drw_stencil_state_set(uint write_mask, uint reference, uint compare_
GPU_stencil_compare_mask_set(compare_mask);
}
-/* Reset state to not interfere with other UI draw-call. */
void DRW_state_reset_ex(DRWState state)
{
DST.state = ~state;
@@ -292,12 +291,6 @@ static void drw_state_validate(void)
}
}
-/**
- * Use with care, intended so selection code can override passes depth settings,
- * which is important for selection to work properly.
- *
- * Should be set in main draw loop, cleared afterwards
- */
void DRW_state_lock(DRWState state)
{
DST.state_lock = state;
@@ -361,7 +354,6 @@ static bool draw_call_is_culled(const DRWResourceHandle *handle, DRWView *view)
return (culling->mask & view->culling_mask) != 0;
}
-/* Set active view for rendering. */
void DRW_view_set_active(DRWView *view)
{
DST.view_active = (view) ? view : DST.view_default;
@@ -435,32 +427,24 @@ static bool draw_culling_plane_test(const BoundBox *corners, const float plane[4
return false;
}
-/* Return True if the given BoundSphere intersect the current view frustum.
- * bsphere must be in world space. */
bool DRW_culling_sphere_test(const DRWView *view, const BoundSphere *bsphere)
{
view = view ? view : DST.view_default;
return draw_culling_sphere_test(&view->frustum_bsphere, view->frustum_planes, bsphere);
}
-/* Return True if the given BoundBox intersect the current view frustum.
- * bbox must be in world space. */
bool DRW_culling_box_test(const DRWView *view, const BoundBox *bbox)
{
view = view ? view : DST.view_default;
return draw_culling_box_test(view->frustum_planes, bbox);
}
-/* Return True if the view frustum is inside or intersect the given plane.
- * plane must be in world space. */
bool DRW_culling_plane_test(const DRWView *view, const float plane[4])
{
view = view ? view : DST.view_default;
return draw_culling_plane_test(&view->frustum_corners, plane);
}
-/* Return True if the given box intersect the current view frustum.
- * This function will have to be replaced when world space bb per objects is implemented. */
bool DRW_culling_min_max_test(const DRWView *view, float obmat[4][4], float min[3], float max[3])
{
view = view ? view : DST.view_default;
@@ -1169,7 +1153,6 @@ void DRW_draw_pass(DRWPass *pass)
}
}
-/* Draw only a subset of shgroups. Used in special situations as grease pencil strokes */
void DRW_draw_pass_subset(DRWPass *pass, DRWShadingGroup *start_group, DRWShadingGroup *end_group)
{
drw_draw_pass_ex(pass, start_group, end_group);
diff --git a/source/blender/draw/intern/draw_manager_profiling.c b/source/blender/draw/intern/draw_manager_profiling.c
index 87d4c34b3ed..80ea7bf654d 100644
--- a/source/blender/draw/intern/draw_manager_profiling.c
+++ b/source/blender/draw/intern/draw_manager_profiling.c
@@ -129,8 +129,6 @@ static void drw_stats_timer_start_ex(const char *name, const bool is_query)
}
}
-/* Use this to group the queries. It does NOT keep track
- * of the time, it only sum what the queries inside it. */
void DRW_stats_group_start(const char *name)
{
drw_stats_timer_start_ex(name, false);
@@ -147,7 +145,6 @@ void DRW_stats_group_end(void)
}
}
-/* NOTE: Only call this when no sub timer will be called. */
void DRW_stats_query_start(const char *name)
{
GPU_debug_group_begin(name);
diff --git a/source/blender/draw/intern/draw_manager_profiling.h b/source/blender/draw/intern/draw_manager_profiling.h
index 3842bdffaff..e7c84491bdb 100644
--- a/source/blender/draw/intern/draw_manager_profiling.h
+++ b/source/blender/draw/intern/draw_manager_profiling.h
@@ -28,9 +28,16 @@ void DRW_stats_free(void);
void DRW_stats_begin(void);
void DRW_stats_reset(void);
+/**
+ * Use this to group the queries. It does NOT keep track
+ * of the time, it only sum what the queries inside it.
+ */
void DRW_stats_group_start(const char *name);
void DRW_stats_group_end(void);
+/**
+ * \note Only call this when no sub timer will be called.
+ */
void DRW_stats_query_start(const char *name);
void DRW_stats_query_end(void);
diff --git a/source/blender/draw/intern/draw_manager_shader.c b/source/blender/draw/intern/draw_manager_shader.c
index 83d0030f89b..84440a8effe 100644
--- a/source/blender/draw/intern/draw_manager_shader.c
+++ b/source/blender/draw/intern/draw_manager_shader.c
@@ -650,8 +650,6 @@ void DRW_shader_library_add_file(DRWShaderLibrary *lib, char *lib_code, const ch
}
}
-/* Return an allocN'ed string containing the shader code with its dependencies prepended.
- * Caller must free the string with MEM_freeN after use. */
char *DRW_shader_library_create_shader_string(const DRWShaderLibrary *lib, const char *shader_code)
{
uint32_t deps = drw_shader_dependencies_get(lib, shader_code);
diff --git a/source/blender/draw/intern/draw_manager_text.c b/source/blender/draw/intern/draw_manager_text.c
index cfaa22ba7c6..5d7b2c142c2 100644
--- a/source/blender/draw/intern/draw_manager_text.c
+++ b/source/blender/draw/intern/draw_manager_text.c
@@ -223,7 +223,6 @@ void DRW_text_cache_draw(DRWTextStore *dt, ARegion *region, struct View3D *v3d)
}
}
-/* Copied from drawobject.c */
void DRW_text_edit_mesh_measure_stats(ARegion *region,
View3D *v3d,
Object *ob,
diff --git a/source/blender/draw/intern/draw_manager_text.h b/source/blender/draw/intern/draw_manager_text.h
index 883b37c52af..000a6ab5e6f 100644
--- a/source/blender/draw/intern/draw_manager_text.h
+++ b/source/blender/draw/intern/draw_manager_text.h
@@ -60,6 +60,7 @@ enum {
};
/* draw_manager.c */
+
struct DRWTextStore *DRW_text_cache_ensure(void);
#ifdef __cplusplus
diff --git a/source/blender/draw/intern/draw_select_buffer.c b/source/blender/draw/intern/draw_select_buffer.c
index d7438b7e0f0..bae07753336 100644
--- a/source/blender/draw/intern/draw_select_buffer.c
+++ b/source/blender/draw/intern/draw_select_buffer.c
@@ -47,7 +47,6 @@
/** \name Buffer of select ID's
* \{ */
-/* Main function to read a block of pixels from the select frame buffer. */
uint *DRW_select_buffer_read(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
@@ -122,10 +121,6 @@ uint *DRW_select_buffer_read(struct Depsgraph *depsgraph,
*
* \{ */
-/**
- * \param rect: The rectangle to sample indices from (min/max inclusive).
- * \returns a #BLI_bitmap the length of \a bitmap_len or NULL on failure.
- */
uint *DRW_select_buffer_bitmap_from_rect(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
@@ -165,12 +160,6 @@ uint *DRW_select_buffer_bitmap_from_rect(struct Depsgraph *depsgraph,
return bitmap_buf;
}
-/**
- * \param center: Circle center.
- * \param radius: Circle radius.
- * \param r_bitmap_len: Number of indices in the selection id buffer.
- * \returns a #BLI_bitmap the length of \a r_bitmap_len or NULL on failure.
- */
uint *DRW_select_buffer_bitmap_from_circle(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
@@ -235,12 +224,6 @@ static void drw_select_mask_px_cb(int x, int x_end, int y, void *user_data)
} while (++x != x_end);
}
-/**
- * \param poly: The polygon coordinates.
- * \param poly_len: Length of the polygon.
- * \param rect: Polygon boundaries.
- * \returns a #BLI_bitmap.
- */
uint *DRW_select_buffer_bitmap_from_poly(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
@@ -309,9 +292,6 @@ uint *DRW_select_buffer_bitmap_from_poly(struct Depsgraph *depsgraph,
*
* \{ */
-/**
- * Samples a single pixel.
- */
uint DRW_select_buffer_sample_point(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
@@ -357,11 +337,6 @@ static bool select_buffer_test_fn(const void *__restrict value, void *__restrict
return false;
}
-/**
- * Find the selection id closest to \a center.
- * \param dist: Use to initialize the distance,
- * when found, this value is set to the distance of the selection that's returned.
- */
uint DRW_select_buffer_find_nearest_to_point(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
@@ -522,4 +497,5 @@ void DRW_select_buffer_context_create(Base **bases, const uint bases_len, short
select_ctx->select_mode = select_mode;
memset(select_ctx->persmat, 0, sizeof(select_ctx->persmat));
}
+
/** \} */
diff --git a/source/blender/draw/intern/draw_texture_pool.cc b/source/blender/draw/intern/draw_texture_pool.cc
index 709bf808874..e3882d4acb6 100644
--- a/source/blender/draw/intern/draw_texture_pool.cc
+++ b/source/blender/draw/intern/draw_texture_pool.cc
@@ -40,7 +40,7 @@ struct DRWTexturePool {
int last_user_id = -1;
};
-DRWTexturePool *DRW_texture_pool_create(void)
+DRWTexturePool *DRW_texture_pool_create()
{
return new DRWTexturePool();
}
@@ -53,10 +53,6 @@ void DRW_texture_pool_free(DRWTexturePool *pool)
delete pool;
}
-/**
- * Try to find a texture corresponding to params into the texture pool.
- * If no texture was found, create one and add it to the pool.
- */
GPUTexture *DRW_texture_pool_query(
DRWTexturePool *pool, int width, int height, eGPUTextureFormat format, void *user)
{
@@ -113,7 +109,6 @@ GPUTexture *DRW_texture_pool_query(
return handle.texture;
}
-/* Resets the user bits for each texture in the pool and delete unused ones. */
void DRW_texture_pool_reset(DRWTexturePool *pool)
{
pool->last_user_id = -1;
diff --git a/source/blender/draw/intern/draw_texture_pool.h b/source/blender/draw/intern/draw_texture_pool.h
index f0b8f775c75..920d29b4cca 100644
--- a/source/blender/draw/intern/draw_texture_pool.h
+++ b/source/blender/draw/intern/draw_texture_pool.h
@@ -38,8 +38,15 @@ extern "C" {
DRWTexturePool *DRW_texture_pool_create(void);
void DRW_texture_pool_free(DRWTexturePool *pool);
+/**
+ * Try to find a texture corresponding to params into the texture pool.
+ * If no texture was found, create one and add it to the pool.
+ */
GPUTexture *DRW_texture_pool_query(
DRWTexturePool *pool, int width, int height, eGPUTextureFormat format, void *user);
+/**
+ * Resets the user bits for each texture in the pool and delete unused ones.
+ */
void DRW_texture_pool_reset(DRWTexturePool *pool);
#ifdef __cplusplus
diff --git a/source/blender/draw/intern/draw_view.c b/source/blender/draw/intern/draw_view.c
index de43d2aba0f..6fe0abf1adf 100644
--- a/source/blender/draw/intern/draw_view.c
+++ b/source/blender/draw/intern/draw_view.c
@@ -236,9 +236,6 @@ static bool is_cursor_visible_2d(const DRWContextState *draw_ctx)
/** \name Generic Cursor
* \{ */
-/**
- * \note This doesn't require the draw context to be in use.
- */
void DRW_draw_cursor_2d_ex(const ARegion *region, const float cursor[2])
{
int co[2];
@@ -286,6 +283,7 @@ void DRW_draw_cursor_2d(void)
DRW_draw_cursor_2d_ex(region, sima->cursor);
}
}
+
/** \} */
/* **************************** 3D Gizmo ******************************** */
diff --git a/source/blender/draw/intern/draw_view_data.cc b/source/blender/draw/intern/draw_view_data.cc
index 55ebbf82c29..f7304737830 100644
--- a/source/blender/draw/intern/draw_view_data.cc
+++ b/source/blender/draw/intern/draw_view_data.cc
@@ -50,11 +50,6 @@ struct DRWViewData {
Vector<ViewportEngineData *> enabled_engines;
};
-/**
- * Creates a view data with all possible engines type for this view.
- *
- * `engine_types` contains `DRWRegisteredDrawEngine`.
- * */
DRWViewData *DRW_view_data_create(ListBase *engine_types)
{
DRWViewData *view_data = new DRWViewData();
@@ -120,6 +115,12 @@ static void draw_viewport_engines_data_clear(ViewportEngineData *data)
MEM_SAFE_FREE(data->stl->storage[i]);
}
+ if (data->instance_data) {
+ BLI_assert(engine_type->instance_free != nullptr);
+ engine_type->instance_free(data->instance_data);
+ data->instance_data = nullptr;
+ }
+
MEM_SAFE_FREE(data->fbl);
MEM_SAFE_FREE(data->txl);
MEM_SAFE_FREE(data->psl);
diff --git a/source/blender/draw/intern/draw_view_data.h b/source/blender/draw/intern/draw_view_data.h
index c8176170a61..494c28cc067 100644
--- a/source/blender/draw/intern/draw_view_data.h
+++ b/source/blender/draw/intern/draw_view_data.h
@@ -63,6 +63,12 @@ typedef struct ViewportEngineData {
TextureList *txl;
PassList *psl;
StorageList *stl;
+ /**
+ * \brief Memory block that can be freely used by the draw engine.
+ * When used the draw engine must implement #DrawEngineType.instance_free callback.
+ */
+ void *instance_data;
+
char info[GPU_INFO_SIZE];
/* we may want to put this elsewhere */
@@ -100,6 +106,11 @@ typedef struct DefaultTextureList {
typedef struct DRWViewData DRWViewData;
+/**
+ * Creates a view data with all possible engines type for this view.
+ *
+ * `engine_types` contains #DRWRegisteredDrawEngine.
+ */
DRWViewData *DRW_view_data_create(ListBase *engine_types);
void DRW_view_data_free(DRWViewData *view_data);
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh.h b/source/blender/draw/intern/mesh_extractors/extract_mesh.h
index d1ffef4fe92..7d21804c08f 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh.h
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh.h
@@ -168,7 +168,9 @@ BLI_INLINE const float *bm_face_no_get(const MeshRenderData *mr, const BMFace *e
/* ---------------------------------------------------------------------- */
/** \name Mesh Elements Extract Struct
* \{ */
+
/* TODO(jbakker): move parameters inside a struct. */
+
typedef void(ExtractTriBMeshFn)(const MeshRenderData *mr,
BMLoop **elt,
const int elt_index,
@@ -241,6 +243,11 @@ typedef struct MeshExtract {
/** \} */
/* draw_cache_extract_mesh_render_data.c */
+
+/**
+ * \param is_mode_active: When true, use the modifiers from the edit-data,
+ * otherwise don't use modifiers as they are not from this object.
+ */
MeshRenderData *mesh_render_data_create(Mesh *me,
const bool is_editmode,
const bool is_paint_mode,
@@ -258,6 +265,9 @@ void mesh_render_data_update_loose_geom(MeshRenderData *mr,
void mesh_render_data_update_polys_sorted(MeshRenderData *mr,
MeshBufferCache *cache,
const eMRDataType data_flag);
+/**
+ * Part of the creation of the #MeshRenderData that happens in a thread.
+ */
void mesh_render_data_update_looptris(MeshRenderData *mr,
const eMRIterType iter_type,
const eMRDataType data_flag);
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc
index d06fb91411e..4cc9a875f79 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc
@@ -388,5 +388,3 @@ const MeshExtract extract_edituv_lines = blender::draw::create_extractor_edituv_
const MeshExtract extract_edituv_points = blender::draw::create_extractor_edituv_points();
const MeshExtract extract_edituv_fdots = blender::draw::create_extractor_edituv_fdots();
}
-
-/** \} */
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc
index ea58e1aeed8..2e8b85250f3 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc
@@ -110,10 +110,9 @@ constexpr MeshExtract create_extractor_fdots()
}
/** \} */
+
} // namespace blender::draw
extern "C" {
const MeshExtract extract_fdots = blender::draw::create_extractor_fdots();
}
-
-/** \} */
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc
index 522afcd44a1..e7dabfa9ee2 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc
@@ -173,8 +173,6 @@ static void extract_lines_adjacency_finish(const MeshRenderData *UNUSED(mr),
#undef NO_EDGE
-/** \} */
-
constexpr MeshExtract create_extractor_lines_adjacency()
{
MeshExtract extractor = {nullptr};
@@ -189,10 +187,10 @@ constexpr MeshExtract create_extractor_lines_adjacency()
return extractor;
}
+/** \} */
+
} // namespace blender::draw
extern "C" {
const MeshExtract extract_lines_adjacency = blender::draw::create_extractor_lines_adjacency();
}
-
-/** \} */
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc
index 494a43e97d1..f7eb5022cdc 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc
@@ -103,8 +103,6 @@ static void extract_lines_paint_mask_finish(const MeshRenderData *UNUSED(mr),
MEM_freeN(data->select_map);
}
-/** \} */
-
constexpr MeshExtract create_extractor_lines_paint_mask()
{
MeshExtract extractor = {nullptr};
@@ -118,10 +116,10 @@ constexpr MeshExtract create_extractor_lines_paint_mask()
return extractor;
}
+/** \} */
+
} // namespace blender::draw
extern "C" {
const MeshExtract extract_lines_paint_mask = blender::draw::create_extractor_lines_paint_mask();
}
-
-/** \} */
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc
index b801ba04162..01e14a004ed 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc
@@ -32,6 +32,7 @@ namespace blender::draw {
/* ---------------------------------------------------------------------- */
/** \name Extract Point Indices
* \{ */
+
static void extract_points_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *UNUSED(buf),
@@ -173,10 +174,10 @@ constexpr MeshExtract create_extractor_points()
return extractor;
}
+/** \} */
+
} // namespace blender::draw
extern "C" {
const MeshExtract extract_points = blender::draw::create_extractor_points();
}
-
-/** \} */
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_nor.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_nor.cc
index fed66f0057d..b2ebff08abf 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_nor.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_nor.cc
@@ -28,6 +28,7 @@ namespace blender::draw {
/* ---------------------------------------------------------------------- */
/** \name Extract Face-dots Normal and edit flag
* \{ */
+
#define NOR_AND_FLAG_DEFAULT 0
#define NOR_AND_FLAG_SELECT 1
#define NOR_AND_FLAG_ACTIVE -1
@@ -114,6 +115,7 @@ constexpr MeshExtract create_extractor_fdots_nor()
/* ---------------------------------------------------------------------- */
/** \name Extract Face-dots High Quality Normal and edit flag
* \{ */
+
static void extract_fdots_nor_hq_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *buf,
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc
index f9f66c27aaa..3c3ac7a7a0a 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc
@@ -121,6 +121,7 @@ constexpr MeshExtract create_extractor_lnor()
}
/** \} */
+
/* ---------------------------------------------------------------------- */
/** \name Extract HQ Loop Normal
* \{ */
diff --git a/source/blender/draw/intern/shaders/common_fxaa_lib.glsl b/source/blender/draw/intern/shaders/common_fxaa_lib.glsl
index 0ecfc397e95..bf59972fbaa 100644
--- a/source/blender/draw/intern/shaders/common_fxaa_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_fxaa_lib.glsl
@@ -296,7 +296,7 @@ NOTE the other tuning knobs are now in the shader function inputs!
/* (#B1#) */
float FxaaLuma(vec4 rgba)
{
- /* note: sqrt because the sampled colors are in a linear colorspace!
+ /* NOTE: sqrt because the sampled colors are in a linear colorspace!
* this approximates a perceptual conversion, which is good enough for the
* algorithm */
return sqrt(dot(rgba.rgb, vec3(0.2126, 0.7152, 0.0722)));
diff --git a/source/blender/draw/intern/shaders/common_view_lib.glsl b/source/blender/draw/intern/shaders/common_view_lib.glsl
index a980b87821a..e9912ba7d9a 100644
--- a/source/blender/draw/intern/shaders/common_view_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_view_lib.glsl
@@ -179,7 +179,7 @@ uniform mat4 ModelMatrixInverse;
* transpose(ViewMatrixInverse) * transpose(ModelMatrixInverse)
*
* Knowing that the view matrix is orthogonal, the transpose is also the inverse.
- * Note: This is only valid because we are only using the mat3 of the ViewMatrixInverse.
+ * NOTE: This is only valid because we are only using the mat3 of the ViewMatrixInverse.
* ViewMatrix * transpose(ModelMatrixInverse)
*/
#define NormalMatrix transpose(mat3(ModelMatrixInverse))
diff --git a/source/blender/editors/animation/CMakeLists.txt b/source/blender/editors/animation/CMakeLists.txt
index d9f52d90766..6fa4d94df3a 100644
--- a/source/blender/editors/animation/CMakeLists.txt
+++ b/source/blender/editors/animation/CMakeLists.txt
@@ -70,3 +70,15 @@ endif()
blender_add_lib(bf_editor_animation "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
+
+if(WITH_GTESTS)
+ set(TEST_SRC
+ keyframes_keylist_test.cc
+ )
+ set(TEST_INC
+ )
+ set(TEST_LIB
+ )
+ include(GTestTesting)
+ blender_add_test_lib(bf_editor_animation_tests "${TEST_SRC}" "${INC};${TEST_INC}" "${INC_SYS}" "${LIB};${TEST_LIB}")
+endif()
diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c
index 9f2681fbf7a..2eaa42ee578 100644
--- a/source/blender/editors/animation/anim_channels_defines.c
+++ b/source/blender/editors/animation/anim_channels_defines.c
@@ -4158,7 +4158,6 @@ static void ANIM_init_channel_typeinfo_data(void)
}
}
-/* Get type info from given channel type */
const bAnimChannelType *ANIM_channel_get_typeinfo(bAnimListElem *ale)
{
/* Sanity checks. */
@@ -4179,7 +4178,6 @@ const bAnimChannelType *ANIM_channel_get_typeinfo(bAnimListElem *ale)
/* --------------------------- */
-/* Print debug info string for the given channel */
void ANIM_channel_debug_print_info(bAnimListElem *ale, short indent_level)
{
const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
@@ -4212,11 +4210,25 @@ void ANIM_channel_debug_print_info(bAnimListElem *ale, short indent_level)
}
}
+bAction *ANIM_channel_action_get(const bAnimListElem *ale)
+{
+ if (ale->datatype == ALE_ACT) {
+ return (bAction *)ale->key_data;
+ }
+
+ if (ELEM(ale->type, ANIMTYPE_GROUP, ANIMTYPE_FCURVE)) {
+ ID *owner = ale->fcurve_owner_id;
+
+ if (owner && GS(owner->name) == ID_AC) {
+ return (bAction *)owner;
+ }
+ }
+
+ return NULL;
+}
+
/* --------------------------- */
-/* Check if some setting for a channel is enabled
- * Returns: 1 = On, 0 = Off, -1 = Invalid
- */
short ANIM_channel_setting_get(bAnimContext *ac, bAnimListElem *ale, eAnimChannel_Settings setting)
{
const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
@@ -4299,10 +4311,6 @@ short ANIM_channel_setting_get(bAnimContext *ac, bAnimListElem *ale, eAnimChanne
} \
(void)0
-/* Change value of some setting for a channel
- * - setting: eAnimChannel_Settings
- * - mode: eAnimChannels_SetFlag
- */
void ANIM_channel_setting_set(bAnimContext *ac,
bAnimListElem *ale,
eAnimChannel_Settings setting,
@@ -4376,7 +4384,6 @@ static bool achannel_is_being_renamed(const bAnimContext *ac,
return false;
}
-/* Draw the given channel */
void ANIM_channel_draw(
bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc, size_t channel_index)
{
@@ -5132,7 +5139,6 @@ static void draw_setting_widget(bAnimContext *ac,
}
}
-/* Draw UI widgets the given channel */
void ANIM_channel_draw_widgets(const bContext *C,
bAnimContext *ac,
bAnimListElem *ale,
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index 69fabd004cc..b97837a76b9 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -74,8 +74,6 @@
/* -------------------------- Selection ------------------------------------- */
-/* Set the given animation-channel as the active one for the active context */
-/* TODO: extend for animdata types... */
void ANIM_set_active_channel(bAnimContext *ac,
void *data,
eAnimCont_Types datatype,
@@ -83,6 +81,8 @@ void ANIM_set_active_channel(bAnimContext *ac,
void *channel_data,
eAnim_ChannelType channel_type)
{
+ /* TODO: extend for animdata types. */
+
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
@@ -460,7 +460,6 @@ static void anim_channels_select_set(bAnimContext *ac,
}
}
-/* Set selection state of all animation channels in the context. */
void ANIM_anim_channels_select_set(bAnimContext *ac, eAnimChannels_SetFlag sel)
{
ListBase anim_data = anim_channels_for_selection(ac);
@@ -468,7 +467,6 @@ void ANIM_anim_channels_select_set(bAnimContext *ac, eAnimChannels_SetFlag sel)
ANIM_animdata_freelist(&anim_data);
}
-/* Toggle selection state of all animation channels in the context. */
void ANIM_anim_channels_select_toggle(bAnimContext *ac)
{
ListBase anim_data = anim_channels_for_selection(ac);
@@ -588,15 +586,6 @@ static void anim_flush_channel_setting_down(bAnimContext *ac,
}
}
-/* Flush visibility (for Graph Editor) changes up/down hierarchy for changes in the given setting
- * - anim_data: list of the all the anim channels that can be chosen
- * -> filtered using ANIMFILTER_CHANNELS only, since if we took VISIBLE too,
- * then the channels under closed expanders get ignored...
- * - ale_setting: the anim channel (not in the anim_data list directly, though occurring there)
- * with the new state of the setting that we want flushed up/down the hierarchy
- * - setting: type of setting to set
- * - on: whether the visibility setting has been enabled or disabled
- */
void ANIM_flush_setting_anim_channels(bAnimContext *ac,
ListBase *anim_data,
bAnimListElem *ale_setting,
@@ -652,7 +641,6 @@ void ANIM_flush_setting_anim_channels(bAnimContext *ac,
/* -------------------------- F-Curves ------------------------------------- */
-/* Delete the given F-Curve from its AnimData block */
void ANIM_fcurve_delete_from_animdata(bAnimContext *ac, AnimData *adt, FCurve *fcu)
{
/* - if no AnimData, we've got nowhere to remove the F-Curve from
@@ -708,8 +696,6 @@ void ANIM_fcurve_delete_from_animdata(bAnimContext *ac, AnimData *adt, FCurve *f
BKE_fcurve_free(fcu);
}
-/* If the action has no F-Curves, unlink it from AnimData if it did not
- * come from a NLA Strip being tweaked. */
bool ANIM_remove_empty_action_from_animdata(struct AnimData *adt)
{
if (adt->action != NULL) {
diff --git a/source/blender/editors/animation/anim_deps.c b/source/blender/editors/animation/anim_deps.c
index 088de80bb65..7a34d8b542a 100644
--- a/source/blender/editors/animation/anim_deps.c
+++ b/source/blender/editors/animation/anim_deps.c
@@ -56,9 +56,6 @@
/* **************************** depsgraph tagging ******************************** */
-/* tags the given anim list element for refreshes (if applicable)
- * due to Animation Editor editing
- */
void ANIM_list_elem_update(Main *bmain, Scene *scene, bAnimListElem *ale)
{
ID *id;
@@ -114,8 +111,6 @@ void ANIM_list_elem_update(Main *bmain, Scene *scene, bAnimListElem *ale)
}
}
-/* tags the given ID block for refreshes (if applicable) due to
- * Animation Editor editing */
void ANIM_id_update(Main *bmain, ID *id)
{
if (id) {
@@ -276,7 +271,6 @@ static void animchan_sync_gplayer(bAnimListElem *ale)
/* ---------------- */
-/* Main call to be exported to animation editors */
void ANIM_sync_animchannels_to_data(const bContext *C)
{
bAnimContext ac;
diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c
index 993d10cf303..6589756c526 100644
--- a/source/blender/editors/animation/anim_draw.c
+++ b/source/blender/editors/animation/anim_draw.c
@@ -63,7 +63,6 @@
/* *************************************************** */
/* CURRENT FRAME DRAWING */
-/* General call for drawing current frame indicator in animation editor */
void ANIM_draw_cfra(const bContext *C, View2D *v2d, short flag)
{
Scene *scene = CTX_data_scene(C);
@@ -92,7 +91,6 @@ void ANIM_draw_cfra(const bContext *C, View2D *v2d, short flag)
/* PREVIEW RANGE 'CURTAINS' */
/* NOTE: 'Preview Range' tools are defined in `anim_ops.c`. */
-/* Draw preview range 'curtains' for highlighting where the animation data is */
void ANIM_draw_previewrange(const bContext *C, View2D *v2d, int end_frame_width)
{
Scene *scene = CTX_data_scene(C);
@@ -127,11 +125,6 @@ void ANIM_draw_previewrange(const bContext *C, View2D *v2d, int end_frame_width)
/* *************************************************** */
/* SCENE FRAME RANGE */
-/**
- * Draw frame range guides (for scene frame range) in background.
- *
- * TODO: Should we still show these when preview range is enabled?
- */
void ANIM_draw_framerange(Scene *scene, View2D *v2d)
{
/* draw darkened area outside of active timeline frame range */
@@ -168,14 +161,73 @@ void ANIM_draw_framerange(Scene *scene, View2D *v2d)
immUnbindProgram();
}
+void ANIM_draw_action_framerange(
+ AnimData *adt, bAction *action, View2D *v2d, float ymin, float ymax)
+{
+ if ((action->flag & ACT_FRAME_RANGE) == 0) {
+ return;
+ }
+
+ /* Compute the dimensions. */
+ CLAMP_MIN(ymin, v2d->cur.ymin);
+ CLAMP_MAX(ymax, v2d->cur.ymax);
+
+ if (ymin > ymax) {
+ return;
+ }
+
+ const float sfra = BKE_nla_tweakedit_remap(adt, action->frame_start, NLATIME_CONVERT_MAP);
+ const float efra = BKE_nla_tweakedit_remap(adt, action->frame_end, NLATIME_CONVERT_MAP);
+
+ /* Diagonal stripe filled area outside of the frame range. */
+ GPU_blend(GPU_BLEND_ALPHA);
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_DIAG_STRIPES);
+
+ float color[4];
+ UI_GetThemeColorShadeAlpha4fv(TH_BACK, -40, -50, color);
+
+ immUniform4f("color1", color[0], color[1], color[2], color[3]);
+ immUniform4f("color2", 0.0f, 0.0f, 0.0f, 0.0f);
+ immUniform1i("size1", 2 * U.dpi_fac);
+ immUniform1i("size2", 4 * U.dpi_fac);
+
+ if (sfra < efra) {
+ immRectf(pos, v2d->cur.xmin, ymin, sfra, ymax);
+ immRectf(pos, efra, ymin, v2d->cur.xmax, ymax);
+ }
+ else {
+ immRectf(pos, v2d->cur.xmin, ymin, v2d->cur.xmax, ymax);
+ }
+
+ immUnbindProgram();
+
+ GPU_blend(GPU_BLEND_NONE);
+
+ /* Thin lines where the actual frames are. */
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformThemeColorShade(TH_BACK, -60);
+
+ GPU_line_width(1.0f);
+
+ immBegin(GPU_PRIM_LINES, 4);
+
+ immVertex2f(pos, sfra, ymin);
+ immVertex2f(pos, sfra, ymax);
+
+ immVertex2f(pos, efra, ymin);
+ immVertex2f(pos, efra, ymax);
+
+ immEnd();
+ immUnbindProgram();
+}
+
/* *************************************************** */
/* NLA-MAPPING UTILITIES (required for drawing and also editing keyframes). */
-/**
- * Obtain the AnimData block providing NLA-mapping for the given channel (if applicable).
- *
- * TODO: do not supply return this if the animdata tells us that there is no mapping to perform.
- */
AnimData *ANIM_nla_mapping_get(bAnimContext *ac, bAnimListElem *ale)
{
/* sanity checks */
@@ -251,10 +303,6 @@ static short bezt_nlamapping_apply(KeyframeEditData *ked, BezTriple *bezt)
return 0;
}
-/* Apply/Unapply NLA mapping to all keyframes in the nominated F-Curve
- * - restore = whether to map points back to non-mapped time
- * - only_keys = whether to only adjust the location of the center point of beztriples
- */
void ANIM_nla_mapping_apply_fcurve(AnimData *adt, FCurve *fcu, bool restore, bool only_keys)
{
KeyframeEditData ked = {{NULL}};
@@ -282,7 +330,6 @@ void ANIM_nla_mapping_apply_fcurve(AnimData *adt, FCurve *fcu, bool restore, boo
/* *************************************************** */
/* UNITS CONVERSION MAPPING (required for drawing and editing keyframes) */
-/* Get flags used for normalization in ANIM_unit_mapping_get_factor. */
short ANIM_get_normalization_flags(bAnimContext *ac)
{
if (ac->sl->spacetype == SPACE_GRAPH) {
@@ -450,7 +497,6 @@ static float normalization_factor_get(Scene *scene, FCurve *fcu, short flag, flo
return factor;
}
-/* Get unit conversion factor for given ID + F-Curve */
float ANIM_unit_mapping_get_factor(Scene *scene, ID *id, FCurve *fcu, short flag, float *r_offset)
{
if (flag & ANIM_UNITCONV_NORMALIZE) {
diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c
index e1d046428a8..c1a09b9d21f 100644
--- a/source/blender/editors/animation/anim_filter.c
+++ b/source/blender/editors/animation/anim_filter.c
@@ -362,11 +362,6 @@ static bool nlaedit_get_context(bAnimContext *ac, SpaceNla *snla)
/* ----------- Public API --------------- */
-/* Obtain current anim-data context,
- * given that context info from Blender context has already been set:
- * - AnimContext to write to is provided as pointer to var on stack so that we don't have
- * allocation/freeing costs (which are not that avoidable with channels).
- */
bool ANIM_animdata_context_getdata(bAnimContext *ac)
{
SpaceLink *sl = ac->sl;
@@ -397,11 +392,6 @@ bool ANIM_animdata_context_getdata(bAnimContext *ac)
return (ok && ac->data);
}
-/* Obtain current anim-data context from Blender Context info
- * - AnimContext to write to is provided as pointer to var on stack so that we don't have
- * allocation/freeing costs (which are not that avoidable with channels).
- * - Clears data and sets the information from Blender Context which is useful
- */
bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
{
Main *bmain = CTX_data_main(C);
@@ -1900,7 +1890,8 @@ static size_t animdata_filter_gpencil(bAnimContext *ac,
if ((filter_mode & ANIMFILTER_DATA_VISIBLE) && !(ads->filterflag & ADS_FILTER_INCL_HIDDEN)) {
/* Layer visibility - we check both object and base,
* since these may not be in sync yet. */
- if ((base->flag & BASE_VISIBLE_DEPSGRAPH) == 0) {
+ if ((base->flag & BASE_VISIBLE_DEPSGRAPH) == 0 ||
+ (base->flag & BASE_VISIBLE_VIEWLAYER) == 0) {
continue;
}
@@ -3459,14 +3450,6 @@ static size_t animdata_filter_remove_duplis(ListBase *anim_data)
/* ----------- Public API --------------- */
-/**
- * This function filters the active data source to leave only animation channels suitable for
- * usage by the caller. It will return the length of the list
- *
- * \param anim_data: Is a pointer to a #ListBase,
- * to which the filtered animation channels will be placed for use.
- * \param filter_mode: how should the data be filtered - bit-mapping accessed flags.
- */
size_t ANIM_animdata_filter(bAnimContext *ac,
ListBase *anim_data,
eAnimFilter_Flags filter_mode,
diff --git a/source/blender/editors/animation/anim_ipo_utils.c b/source/blender/editors/animation/anim_ipo_utils.c
index 05837ed17b9..0315b93508b 100644
--- a/source/blender/editors/animation/anim_ipo_utils.c
+++ b/source/blender/editors/animation/anim_ipo_utils.c
@@ -43,14 +43,6 @@
/* ----------------------- Getter functions ----------------------- */
-/**
- * Write into "name" buffer, the name of the property
- * (retrieved using RNA from the curve's settings),
- * and return the icon used for the struct that this property refers to
- *
- * \warning name buffer we're writing to cannot exceed 256 chars
- * (check anim_channels_defines.c for details).
- */
int getname_anim_fcurve(char *name, ID *id, FCurve *fcu)
{
int icon = 0;
diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c
index e12433f4d4c..baf3eaae8e2 100644
--- a/source/blender/editors/animation/anim_markers.c
+++ b/source/blender/editors/animation/anim_markers.c
@@ -99,13 +99,11 @@ static ListBase *context_get_markers(Scene *scene, ScrArea *area)
/* ............. */
-/* public API for getting markers from context */
ListBase *ED_context_get_markers(const bContext *C)
{
return context_get_markers(CTX_data_scene(C), CTX_wm_area(C));
}
-/* public API for getting markers from "animation" context */
ListBase *ED_animcontext_get_markers(const bAnimContext *ac)
{
if (ac) {
@@ -116,17 +114,6 @@ ListBase *ED_animcontext_get_markers(const bAnimContext *ac)
/* --------------------------------- */
-/**
- * Apply some transformation to markers after the fact
- *
- * \param markers: List of markers to affect - this may or may not be the scene markers list,
- * so don't assume anything.
- * \param scene: Current scene (for getting current frame)
- * \param mode: (TfmMode) transform mode that this transform is for
- * \param value: From the transform code, this is `t->vec[0]`
- * (which is delta transform for grab/extend, and scale factor for scale)
- * \param side: (B/L/R) for 'extend' functionality, which side of current frame to use
- */
int ED_markers_post_apply_transform(
ListBase *markers, Scene *scene, int mode, float value, char side)
{
@@ -168,8 +155,6 @@ int ED_markers_post_apply_transform(
/* --------------------------------- */
-/* Get the marker that is closest to this point */
-/* XXX for select, the min_dist should be small */
TimeMarker *ED_markers_find_nearest_marker(ListBase *markers, float x)
{
TimeMarker *marker, *nearest = NULL;
@@ -189,7 +174,6 @@ TimeMarker *ED_markers_find_nearest_marker(ListBase *markers, float x)
return nearest;
}
-/* Return the time of the marker that occurs on a frame closest to the given time */
int ED_markers_find_nearest_marker_time(ListBase *markers, float x)
{
TimeMarker *nearest = ED_markers_find_nearest_marker(markers, x);
@@ -323,10 +307,6 @@ static void add_marker_to_cfra_elem(ListBase *lb, TimeMarker *marker, short only
cen->sel = marker->flag;
}
-/* This function makes a list of all the markers. The only_sel
- * argument is used to specify whether only the selected markers
- * are added.
- */
void ED_markers_make_cfra_list(ListBase *markers, ListBase *lb, short only_sel)
{
TimeMarker *marker;
@@ -375,7 +355,6 @@ void ED_markers_deselect_all(ListBase *markers, int action)
/* --------------------------------- */
-/* Get the first selected marker */
TimeMarker *ED_markers_get_first_selected(ListBase *markers)
{
TimeMarker *marker;
@@ -393,12 +372,11 @@ TimeMarker *ED_markers_get_first_selected(ListBase *markers)
/* --------------------------------- */
-/* Print debugging prints of list of markers
- * BSI's: do NOT make static or put in if-defs as "unused code".
- * That's too much trouble when we need to use for quick debugging!
- */
void debug_markers_print_list(ListBase *markers)
{
+ /* NOTE: do NOT make static or put in if-defs as "unused code".
+ * That's too much trouble when we need to use for quick debugging! */
+
TimeMarker *marker;
if (markers == NULL) {
@@ -564,7 +542,6 @@ static void get_marker_clip_frame_range(View2D *v2d, float xscale, int r_range[2
r_range[1] = v2d->cur.xmax + font_width_max;
}
-/* Draw Scene-Markers in time window */
void ED_markers_draw(const bContext *C, int flag)
{
ListBase *markers = ED_context_get_markers(C);
@@ -1699,7 +1676,6 @@ static void MARKER_OT_camera_bind(wmOperatorType *ot)
/* ************************** registration **********************************/
-/* called in screen_ops.c:ED_operatortypes_screen() */
void ED_operatortypes_marker(void)
{
WM_operatortype_append(MARKER_OT_add);
@@ -1716,7 +1692,6 @@ void ED_operatortypes_marker(void)
#endif
}
-/* called in screen_ops.c:ED_keymap_screen() */
void ED_keymap_marker(wmKeyConfig *keyconf)
{
WM_keymap_ensure(keyconf, "Markers", 0, 0);
diff --git a/source/blender/editors/animation/anim_motion_paths.c b/source/blender/editors/animation/anim_motion_paths.c
index 335034fef6e..d4a8e7921d6 100644
--- a/source/blender/editors/animation/anim_motion_paths.c
+++ b/source/blender/editors/animation/anim_motion_paths.c
@@ -99,12 +99,10 @@ Depsgraph *animviz_depsgraph_build(Main *bmain,
return depsgraph;
}
-/* get list of motion paths to be baked for the given object
- * - assumes the given list is ready to be used
- */
-/* TODO: it would be nice in future to be able to update objects dependent on these bones too? */
void animviz_get_object_motionpaths(Object *ob, ListBase *targets)
{
+ /* TODO: it would be nice in future to be able to update objects dependent on these bones too? */
+
MPathTarget *mpt;
/* object itself first */
@@ -356,12 +354,6 @@ static void motionpath_free_free_tree_data(ListBase *targets)
}
}
-/* Perform baking of the given object's and/or its bones' transforms to motion paths
- * - scene: current scene
- * - ob: object whose flagged motion-paths should get calculated
- * - recalc: whether we need to
- */
-/* TODO: include reports pointer? */
void animviz_calc_motionpaths(Depsgraph *depsgraph,
Main *bmain,
Scene *scene,
@@ -369,6 +361,8 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph,
eAnimvizCalcRange range,
bool restore)
{
+ /* TODO: include reports pointer? */
+
/* Sanity check. */
if (ELEM(NULL, targets, targets->first)) {
return;
diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c
index dbf379971fa..e99e4a63786 100644
--- a/source/blender/editors/animation/drivers.c
+++ b/source/blender/editors/animation/drivers.c
@@ -61,9 +61,6 @@
/* ************************************************** */
/* Animation Data Validation */
-/* Get (or add relevant data to be able to do so) F-Curve from the driver stack,
- * for the given Animation Data block. This assumes that all the destinations are valid.
- */
FCurve *verify_driver_fcurve(ID *id,
const char rna_path[],
const int array_index,
@@ -295,17 +292,6 @@ static int add_driver_with_target(ReportList *UNUSED(reports),
return (fcu != NULL);
}
-/* Main Driver Management API calls:
- * Add a new driver for the specified property on the given ID block,
- * and make it be driven by the specified target.
- *
- * This is intended to be used in conjunction with a modal "eyedropper"
- * for picking the variable that is going to be used to drive this one.
- *
- * - flag: eCreateDriverFlags
- * - driver_type: eDriver_Types
- * - mapping_type: eCreateDriver_MappingTypes
- */
int ANIM_add_driver_with_target(ReportList *reports,
ID *dst_id,
const char dst_path[],
@@ -420,10 +406,6 @@ int ANIM_add_driver_with_target(ReportList *reports,
/* --------------------------------- */
-/**
- * Main Driver Management API calls:
- * Add a new driver for the specified property on the given ID block
- */
int ANIM_add_driver(
ReportList *reports, ID *id, const char rna_path[], int array_index, short flag, int type)
{
@@ -546,9 +528,6 @@ int ANIM_add_driver(
return done_tot;
}
-/* Main Driver Management API calls:
- * Remove the driver for the specified property on the given ID block (if available)
- */
bool ANIM_remove_driver(ReportList *UNUSED(reports),
ID *id,
const char rna_path[],
@@ -603,7 +582,6 @@ bool ANIM_remove_driver(ReportList *UNUSED(reports),
/* Copy/Paste Buffer for Driver Data... */
static FCurve *channeldriver_copypaste_buf = NULL;
-/* This function frees any MEM_calloc'ed copy/paste buffer data */
void ANIM_drivers_copybuf_free(void)
{
/* free the buffer F-Curve if it exists, as if it were just another F-Curve */
@@ -613,7 +591,6 @@ void ANIM_drivers_copybuf_free(void)
channeldriver_copypaste_buf = NULL;
}
-/* Checks if there is a driver in the copy/paste buffer */
bool ANIM_driver_can_paste(void)
{
return (channeldriver_copypaste_buf != NULL);
@@ -621,9 +598,6 @@ bool ANIM_driver_can_paste(void)
/* ------------------- */
-/* Main Driver Management API calls:
- * Make a copy of the driver for the specified property on the given ID block
- */
bool ANIM_copy_driver(
ReportList *reports, ID *id, const char rna_path[], int array_index, short UNUSED(flag))
{
@@ -672,10 +646,6 @@ bool ANIM_copy_driver(
return 0;
}
-/* Main Driver Management API calls:
- * Add a new driver for the specified property on the given ID block or replace an existing one
- * with the driver + driver-curve data from the buffer
- */
bool ANIM_paste_driver(
ReportList *reports, ID *id, const char rna_path[], int array_index, short UNUSED(flag))
{
@@ -733,7 +703,6 @@ bool ANIM_paste_driver(
/* Copy/Paste Buffer for Driver Variables... */
static ListBase driver_vars_copybuf = {NULL, NULL};
-/* This function frees any MEM_calloc'ed copy/paste buffer data */
void ANIM_driver_vars_copybuf_free(void)
{
/* Free the driver variables kept in the buffer */
@@ -750,7 +719,6 @@ void ANIM_driver_vars_copybuf_free(void)
BLI_listbase_clear(&driver_vars_copybuf);
}
-/* Checks if there are driver variables in the copy/paste buffer */
bool ANIM_driver_vars_can_paste(void)
{
return (BLI_listbase_is_empty(&driver_vars_copybuf) == false);
@@ -758,7 +726,6 @@ bool ANIM_driver_vars_can_paste(void)
/* -------------------------------------------------- */
-/* Copy the given driver's variables to the buffer */
bool ANIM_driver_vars_copy(ReportList *reports, FCurve *fcu)
{
/* sanity checks */
@@ -781,7 +748,6 @@ bool ANIM_driver_vars_copy(ReportList *reports, FCurve *fcu)
return (BLI_listbase_is_empty(&driver_vars_copybuf) == false);
}
-/* Paste the variables in the buffer to the given FCurve */
bool ANIM_driver_vars_paste(ReportList *reports, FCurve *fcu, bool replace)
{
ChannelDriver *driver = (fcu) ? fcu->driver : NULL;
@@ -837,8 +803,6 @@ bool ANIM_driver_vars_paste(ReportList *reports, FCurve *fcu, bool replace)
/* -------------------------------------------------- */
-/* Create a driver & variable that reads the specified property,
- * and store it in the buffers for Paste Driver and Paste Variables. */
void ANIM_copy_as_driver(struct ID *target_id, const char *target_path, const char *var_name)
{
/* Clear copy/paste buffer first (for consistency with other copy/paste buffers). */
@@ -882,13 +846,8 @@ void ANIM_copy_as_driver(struct ID *target_id, const char *target_path, const ch
/* Add Driver - Enum Defines ------------------------- */
-/**
- * Mapping Types enum for operators.
- * \note Used by #ANIM_OT_driver_button_add and #UI_OT_eyedropper_driver.
- *
- * XXX: These names need reviewing.
- */
EnumPropertyItem prop_driver_create_mapping_types[] = {
+ /* XXX: These names need reviewing. */
{CREATEDRIVER_MAPPING_1_N,
"SINGLE_MANY",
0,
@@ -920,10 +879,10 @@ EnumPropertyItem prop_driver_create_mapping_types[] = {
};
/* Filtering callback for driver mapping types enum */
-static const EnumPropertyItem *driver_mapping_type_itemsf(bContext *C,
- PointerRNA *UNUSED(owner_ptr),
- PropertyRNA *UNUSED(owner_prop),
- bool *r_free)
+static const EnumPropertyItem *driver_mapping_type_itemf(bContext *C,
+ PointerRNA *UNUSED(owner_ptr),
+ PropertyRNA *UNUSED(owner_prop),
+ bool *r_free)
{
EnumPropertyItem *input = prop_driver_create_mapping_types;
EnumPropertyItem *item = NULL;
@@ -1080,7 +1039,7 @@ static void UNUSED_FUNCTION(ANIM_OT_driver_button_add_menu)(wmOperatorType *ot)
0,
"Mapping Type",
"Method used to match target and driven properties");
- RNA_def_enum_funcs(ot->prop, driver_mapping_type_itemsf);
+ RNA_def_enum_funcs(ot->prop, driver_mapping_type_itemf);
}
/* Add Driver Button Operator ------------------------ */
diff --git a/source/blender/editors/animation/fmodifier_ui.c b/source/blender/editors/animation/fmodifier_ui.c
index b94ee68e276..c4d8484e6a8 100644
--- a/source/blender/editors/animation/fmodifier_ui.c
+++ b/source/blender/editors/animation/fmodifier_ui.c
@@ -891,9 +891,6 @@ static void panel_register_stepped(ARegionType *region_type,
/** \name Panel Creation
* \{ */
-/**
- * Checks if the panels match the active strip / curve, rebuilds them if they don't.
- */
void ANIM_fmodifier_panels(const bContext *C,
ID *owner_id,
ListBase *fmodifiers,
@@ -969,17 +966,12 @@ static ListBase fmodifier_copypaste_buf = {NULL, NULL};
/* ---------- */
-/* free the copy/paste buffer */
void ANIM_fmodifiers_copybuf_free(void)
{
/* just free the whole buffer */
free_fmodifiers(&fmodifier_copypaste_buf);
}
-/* copy the given F-Modifiers to the buffer, returning whether anything was copied or not
- * assuming that the buffer has been cleared already with ANIM_fmodifiers_copybuf_free()
- * - active: only copy the active modifier
- */
bool ANIM_fmodifiers_copy_to_buf(ListBase *modifiers, bool active)
{
bool ok = true;
@@ -1009,9 +1001,6 @@ bool ANIM_fmodifiers_copy_to_buf(ListBase *modifiers, bool active)
return ok;
}
-/* 'Paste' the F-Modifier(s) from the buffer to the specified list
- * - replace: free all the existing modifiers to leave only the pasted ones
- */
bool ANIM_fmodifiers_paste_from_buf(ListBase *modifiers, bool replace, FCurve *curve)
{
FModifier *fcm;
diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c
index 0923d490110..145d67b7810 100644
--- a/source/blender/editors/animation/keyframes_edit.c
+++ b/source/blender/editors/animation/keyframes_edit.c
@@ -67,10 +67,6 @@
/* --------------------------- Base Functions ------------------------------------ */
-/* This function is used to loop over BezTriples in the given F-Curve, applying a given
- * operation on them, and optionally applies an F-Curve validation function afterwards.
- */
-/* TODO: make this function work on samples too. */
short ANIM_fcurve_keyframes_loop(KeyframeEditData *ked,
FCurve *fcu,
KeyframeEditFunc key_ok,
@@ -378,7 +374,6 @@ static short summary_keyframes_loop(KeyframeEditData *ked,
/* --- */
-/* This function is used to apply operation to all keyframes, regardless of the type */
short ANIM_animchannel_keyframes_loop(KeyframeEditData *ked,
bDopeSheet *ads,
bAnimListElem *ale,
@@ -416,8 +411,6 @@ short ANIM_animchannel_keyframes_loop(KeyframeEditData *ked,
return 0;
}
-/* This function is used to apply operation to all keyframes,
- * regardless of the type without needed an AnimListElem wrapper */
short ANIM_animchanneldata_keyframes_loop(KeyframeEditData *ked,
bDopeSheet *ads,
void *data,
@@ -477,8 +470,6 @@ void ANIM_animdata_keyframe_callback(bAnimContext *ac,
/* ************************************************************************** */
/* Keyframe Integrity Tools */
-/* Rearrange keyframes if some are out of order */
-/* used to be recalc_*_ipos() where * was object or action */
void ANIM_editkeyframes_refresh(bAnimContext *ac)
{
ListBase anim_data = {NULL, NULL};
@@ -620,9 +611,6 @@ static short ok_bezier_region(KeyframeEditData *ked, BezTriple *bezt)
return 0;
}
-/**
- * Called from #ok_bezier_region_lasso and #ok_bezier_channel_lasso
- */
bool keyframe_region_lasso_test(const KeyframeEdit_LassoData *data_lasso, const float xy[2])
{
if (BLI_rctf_isect_pt_v(data_lasso->rectf_scaled, xy)) {
@@ -683,9 +671,6 @@ static short ok_bezier_channel_lasso(KeyframeEditData *ked, BezTriple *bezt)
return 0;
}
-/**
- * Called from #ok_bezier_region_circle and #ok_bezier_channel_circle
- */
bool keyframe_region_circle_test(const KeyframeEdit_CircleData *data_circle, const float xy[2])
{
if (BLI_rctf_isect_pt_v(data_circle->rectf_scaled, xy)) {
@@ -787,10 +772,6 @@ KeyframeEditFunc ANIM_editkeyframes_ok(short mode)
/* ******************************************* */
/* Assorted Utility Functions */
-/**
- * Helper callback for <animeditor>_cfrasnap_exec() ->
- * used to help get the average time of all selected beztriples
- */
short bezt_calc_average(KeyframeEditData *ked, BezTriple *bezt)
{
/* only if selected */
@@ -810,8 +791,6 @@ short bezt_calc_average(KeyframeEditData *ked, BezTriple *bezt)
return 0;
}
-/* helper callback for columnselect_<animeditor>_keys() -> populate
- * list CfraElems with frame numbers from selected beztriples */
short bezt_to_cfraelem(KeyframeEditData *ked, BezTriple *bezt)
{
/* only if selected */
@@ -825,9 +804,6 @@ short bezt_to_cfraelem(KeyframeEditData *ked, BezTriple *bezt)
return 0;
}
-/* used to remap times from one range to another
- * requires: ked->data = KeyframeEditCD_Remap
- */
void bezt_remap_times(KeyframeEditData *ked, BezTriple *bezt)
{
KeyframeEditCD_Remap *rmap = (KeyframeEditCD_Remap *)ked->data;
@@ -1024,8 +1000,6 @@ static short mirror_bezier_value(KeyframeEditData *ked, BezTriple *bezt)
return 0;
}
-/* NOTE: for markers and 'value', the values to use must be supplied as the first float value. */
-/* calchandles_fcurve */
KeyframeEditFunc ANIM_editkeyframes_mirror(short mode)
{
switch (mode) {
@@ -1183,8 +1157,6 @@ static short set_bezier_free(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
return 0;
}
-/* Set all selected Bezier Handles to a single type */
-/* calchandles_fcurve */
KeyframeEditFunc ANIM_editkeyframes_handles(short mode)
{
switch (mode) {
@@ -1311,8 +1283,6 @@ static short set_bezt_sine(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
return 0;
}
-/* Set the interpolation type of the selected BezTriples in each F-Curve to the specified one */
-/* ANIM_editkeyframes_ipocurve_ipotype() ! */
KeyframeEditFunc ANIM_editkeyframes_ipo(short mode)
{
switch (mode) {
@@ -1391,7 +1361,6 @@ static short set_keytype_moving_hold(KeyframeEditData *UNUSED(ked), BezTriple *b
return 0;
}
-/* Set the interpolation type of the selected BezTriples in each F-Curve to the specified one */
KeyframeEditFunc ANIM_editkeyframes_keytype(short mode)
{
switch (mode) {
@@ -1447,7 +1416,6 @@ static short set_easingtype_easeauto(KeyframeEditData *UNUSED(ked), BezTriple *b
return 0;
}
-/* Set the easing type of the selected BezTriples in each F-Curve to the specified one */
KeyframeEditFunc ANIM_editkeyframes_easing(short mode)
{
switch (mode) {
@@ -1638,7 +1606,6 @@ static short selmap_build_bezier_less(KeyframeEditData *ked, BezTriple *bezt)
return 0;
}
-/* Get callback for building selection map */
KeyframeEditFunc ANIM_editkeyframes_buildselmap(short mode)
{
switch (mode) {
@@ -1653,7 +1620,6 @@ KeyframeEditFunc ANIM_editkeyframes_buildselmap(short mode)
/* ----------- */
-/* flush selection map values to the given beztriple */
short bezt_selmap_flush(KeyframeEditData *ked, BezTriple *bezt)
{
const char *map = ked->data;
diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c
index ec33a42af3b..dc5d71b5a1e 100644
--- a/source/blender/editors/animation/keyframes_general.c
+++ b/source/blender/editors/animation/keyframes_general.c
@@ -63,11 +63,6 @@
/* **************************************************** */
-/**
- * Only delete the nominated keyframe from provided F-Curve.
- * Not recommended to be used many times successively. For that
- * there is #delete_fcurve_keys().
- */
void delete_fcurve_key(FCurve *fcu, int index, bool do_recalc)
{
/* sanity check */
@@ -101,7 +96,6 @@ void delete_fcurve_key(FCurve *fcu, int index, bool do_recalc)
}
}
-/* Delete selected keyframes in given F-Curve */
bool delete_fcurve_keys(FCurve *fcu)
{
bool changed = false;
@@ -140,7 +134,6 @@ void clear_fcurve_keys(FCurve *fcu)
/* ---------------- */
-/* duplicate selected keyframes for the given F-Curve */
void duplicate_fcurve_keys(FCurve *fcu)
{
/* this can only work when there is an F-Curve, and also when there are some BezTriples */
@@ -176,10 +169,6 @@ void duplicate_fcurve_keys(FCurve *fcu)
/* **************************************************** */
/* Various Tools */
-/**
- * Basic F-Curve 'cleanup' function that removes 'double points' and unnecessary keyframes on
- * linear-segments only optionally clears up curve if one keyframe with default value remains.
- */
void clean_fcurve(struct bAnimContext *ac, bAnimListElem *ale, float thresh, bool cleardefault)
{
FCurve *fcu = (FCurve *)ale->key_data;
@@ -318,6 +307,44 @@ void clean_fcurve(struct bAnimContext *ac, bAnimListElem *ale, float thresh, boo
}
}
+/** Find the first segment of consecutive selected curve points, starting from \a start_index.
+ * Keys that have BEZT_FLAG_IGNORE_TAG set are treated as unselected.
+ * \param r_segment_start_idx: returns the start index of the segment.
+ * \param r_segment_len: returns the number of curve points in the segment.
+ * \return whether such a segment was found or not.*/
+static bool find_fcurve_segment(FCurve *fcu,
+ const int start_index,
+ int *r_segment_start_idx,
+ int *r_segment_len)
+{
+ *r_segment_start_idx = 0;
+ *r_segment_len = 0;
+
+ bool in_segment = false;
+
+ for (int i = start_index; i < fcu->totvert; i++) {
+ const bool point_is_selected = fcu->bezt[i].f2 & SELECT;
+ const bool point_is_ignored = fcu->bezt[i].f2 & BEZT_FLAG_IGNORE_TAG;
+
+ if (point_is_selected && !point_is_ignored) {
+ if (!in_segment) {
+ *r_segment_start_idx = i;
+ in_segment = true;
+ }
+ (*r_segment_len)++;
+ }
+ else if (in_segment) {
+ /* If the curve point is not selected then we have reached the end of the selected curve
+ * segment. */
+ return true; /* Segment found. */
+ }
+ }
+
+ /* If the last curve point was in the segment, `r_segment_len` and `r_segment_start_idx`
+ * are already updated and true is returned. */
+ return in_segment;
+}
+
/* ---------------- */
/* Check if the keyframe interpolation type is supported */
@@ -391,17 +418,9 @@ static void decimate_fcurve_segment(FCurve *fcu,
target_fcurve_verts);
}
-/**
- * F-Curve 'decimate' function that removes a certain ratio of curve
- * points that will affect the curves overall shape the least.
- * If you want to remove based on a error margin, set remove_ratio to 1 and
- * simply specify the desired error_sq_max. Otherwise, set the error margin to
- * FLT_MAX.
- */
bool decimate_fcurve(bAnimListElem *ale, float remove_ratio, float error_sq_max)
{
FCurve *fcu = (FCurve *)ale->key_data;
-
/* Check if the curve actually has any points. */
if (fcu == NULL || fcu->bezt == NULL || fcu->totvert == 0) {
return true;
@@ -409,46 +428,26 @@ bool decimate_fcurve(bAnimListElem *ale, float remove_ratio, float error_sq_max)
BezTriple *old_bezts = fcu->bezt;
- /* Only decimate the individual selected curve segments. */
- int bezt_segment_start_idx = 0;
- int bezt_segment_len = 0;
-
- bool selected;
bool can_decimate_all_selected = true;
- bool in_segment = false;
for (int i = 0; i < fcu->totvert; i++) {
- selected = fcu->bezt[i].f2 & SELECT;
- /* Make sure that the temp flag is unset as we use it to determine what to remove. */
- fcu->bezt[i].f2 &= ~BEZT_FLAG_TEMP_TAG;
-
- if (selected && !prepare_for_decimate(fcu, i)) {
- /* This keyframe is not supported, treat them as if they were unselected. */
- selected = false;
+ /* Ignore keyframes that are not supported. */
+ if (!prepare_for_decimate(fcu, i)) {
can_decimate_all_selected = false;
+ fcu->bezt[i].f2 |= BEZT_FLAG_IGNORE_TAG;
}
-
- if (selected) {
- if (!in_segment) {
- bezt_segment_start_idx = i;
- in_segment = true;
- }
- bezt_segment_len++;
- }
- else if (in_segment) {
- /* If the curve point is not selected then we have reached the end of the selected curve
- * segment. */
- decimate_fcurve_segment(
- fcu, bezt_segment_start_idx, bezt_segment_len, remove_ratio, error_sq_max);
- in_segment = false;
- bezt_segment_len = 0;
- }
+ /* Make sure that the temp flag is unset as we use it to determine what to remove. */
+ fcu->bezt[i].f2 &= ~BEZT_FLAG_TEMP_TAG;
}
- /* Did the segment run to the end of the curve? */
- if (in_segment) {
- decimate_fcurve_segment(
- fcu, bezt_segment_start_idx, bezt_segment_len, remove_ratio, error_sq_max);
+ /* Only decimate the individual selected curve segments. */
+ int segment_start_idx = 0;
+ int segment_len = 0;
+ int current_index = 0;
+
+ while (find_fcurve_segment(fcu, current_index, &segment_start_idx, &segment_len)) {
+ decimate_fcurve_segment(fcu, segment_start_idx, segment_len, remove_ratio, error_sq_max);
+ current_index = segment_start_idx + segment_len;
}
uint old_totvert = fcu->totvert;
@@ -457,6 +456,7 @@ bool decimate_fcurve(bAnimListElem *ale, float remove_ratio, float error_sq_max)
for (int i = 0; i < old_totvert; i++) {
BezTriple *bezt = (old_bezts + i);
+ bezt->f2 &= ~BEZT_FLAG_IGNORE_TAG;
if ((bezt->f2 & BEZT_FLAG_TEMP_TAG) == 0) {
insert_bezt_fcurve(fcu, bezt, 0);
}
@@ -477,8 +477,6 @@ typedef struct tSmooth_Bezt {
float y1, y2, y3; /* averaged before/new/after y-values */
} tSmooth_Bezt;
-/* Use a weighted moving-means method to reduce intensity of fluctuations */
-/* TODO: introduce scaling factor for weighting falloff */
void smooth_fcurve(FCurve *fcu)
{
int totSel = 0;
@@ -582,7 +580,6 @@ typedef struct TempFrameValCache {
float frame, val;
} TempFrameValCache;
-/* Evaluates the curves between each selected keyframe on each frame, and keys the value. */
void sample_fcurve(FCurve *fcu)
{
BezTriple *bezt, *start = NULL, *end = NULL;
@@ -691,7 +688,6 @@ typedef struct tAnimCopybufItem {
bool is_bone; /* special flag for armature bones */
} tAnimCopybufItem;
-/* This function frees any MEM_calloc'ed copy/paste buffer data */
void ANIM_fcurves_copybuf_free(void)
{
tAnimCopybufItem *aci, *acn;
@@ -722,7 +718,6 @@ void ANIM_fcurves_copybuf_free(void)
/* ------------------- */
-/* This function adds data to the keyframes copy/paste buffer, freeing existing data first */
short copy_animedit_keys(bAnimContext *ac, ListBase *anim_data)
{
bAnimListElem *ale;
@@ -1081,8 +1076,6 @@ static void paste_animedit_keys_fcurve(
calchandles_fcurve(fcu);
}
-/* ------------------- */
-
const EnumPropertyItem rna_enum_keyframe_paste_offset_items[] = {
{KEYFRAME_PASTE_OFFSET_CFRA_START,
"START",
@@ -1115,11 +1108,6 @@ const EnumPropertyItem rna_enum_keyframe_paste_merge_items[] = {
{0, NULL, 0, NULL, NULL},
};
-/**
- * This function pastes data from the keyframes copy/paste buffer
- *
- * \return Status code is whether the method FAILED to do anything
- */
short paste_animedit_keys(bAnimContext *ac,
ListBase *anim_data,
const eKeyPasteOffset offset_mode,
diff --git a/source/blender/editors/animation/keyframes_keylist.cc b/source/blender/editors/animation/keyframes_keylist.cc
index 7d08e416d0d..8dae46766fa 100644
--- a/source/blender/editors/animation/keyframes_keylist.cc
+++ b/source/blender/editors/animation/keyframes_keylist.cc
@@ -109,7 +109,7 @@ struct AnimKeylist {
#endif
};
-AnimKeylist *ED_keylist_create(void)
+AnimKeylist *ED_keylist_create()
{
AnimKeylist *keylist = new AnimKeylist();
return keylist;
diff --git a/source/blender/editors/animation/keyframes_keylist_test.cc b/source/blender/editors/animation/keyframes_keylist_test.cc
new file mode 100644
index 00000000000..17a21be5ae8
--- /dev/null
+++ b/source/blender/editors/animation/keyframes_keylist_test.cc
@@ -0,0 +1,144 @@
+/* Apache License, Version 2.0 */
+
+#include "testing/testing.h"
+
+#include "BLI_utildefines.h"
+
+#include "ED_keyframes_keylist.h"
+
+#include "DNA_anim_types.h"
+#include "DNA_curve_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BKE_fcurve.h"
+
+#include <functional>
+#include <optional>
+
+namespace blender::editor::animation::tests {
+
+const float KEYLIST_NEAR_ERROR = 0.1;
+const float FRAME_STEP = 0.005;
+
+static void build_fcurve(FCurve &fcurve)
+{
+ fcurve.totvert = 3;
+ fcurve.bezt = static_cast<BezTriple *>(
+ MEM_callocN(sizeof(BezTriple) * fcurve.totvert, "BezTriples"));
+ fcurve.bezt[0].vec[1][0] = 10.f;
+ fcurve.bezt[0].vec[1][1] = 1.f;
+ fcurve.bezt[1].vec[1][0] = 20.f;
+ fcurve.bezt[1].vec[1][1] = 2.f;
+ fcurve.bezt[2].vec[1][0] = 30.f;
+ fcurve.bezt[2].vec[1][1] = 1.f;
+}
+
+static AnimKeylist *create_test_keylist()
+{
+ FCurve *fcurve = BKE_fcurve_create();
+ build_fcurve(*fcurve);
+
+ AnimKeylist *keylist = ED_keylist_create();
+ fcurve_to_keylist(nullptr, fcurve, keylist, 0);
+ BKE_fcurve_free(fcurve);
+
+ ED_keylist_prepare_for_direct_access(keylist);
+ return keylist;
+}
+
+static void assert_act_key_column(const ActKeyColumn *column,
+ const std::optional<float> expected_frame)
+{
+ if (expected_frame.has_value()) {
+ EXPECT_NE(column, nullptr);
+ EXPECT_NEAR(column->cfra, *expected_frame, KEYLIST_NEAR_ERROR);
+ }
+ else {
+ EXPECT_EQ(column, nullptr);
+ }
+}
+
+using KeylistFindFunction = std::function<const ActKeyColumn *(const AnimKeylist *, float)>;
+
+static float check_keylist_find_range(const AnimKeylist *keylist,
+ KeylistFindFunction keylist_find_func,
+ const float frame_from,
+ const float frame_to,
+ const std::optional<float> expected_frame)
+{
+ float cfra = frame_from;
+ for (; cfra < frame_to; cfra += FRAME_STEP) {
+ const ActKeyColumn *found = keylist_find_func(keylist, cfra);
+ assert_act_key_column(found, expected_frame);
+ }
+ return cfra;
+}
+
+static float check_keylist_find_next_range(const AnimKeylist *keylist,
+ const float frame_from,
+ const float frame_to,
+ const std::optional<float> expected_frame)
+{
+ return check_keylist_find_range(
+ keylist, ED_keylist_find_next, frame_from, frame_to, expected_frame);
+}
+
+TEST(keylist, find_next)
+{
+ AnimKeylist *keylist = create_test_keylist();
+
+ float cfra = check_keylist_find_next_range(keylist, 0.0f, 9.99f, 10.0f);
+ cfra = check_keylist_find_next_range(keylist, cfra, 19.99f, 20.0f);
+ cfra = check_keylist_find_next_range(keylist, cfra, 29.99f, 30.0f);
+ cfra = check_keylist_find_next_range(keylist, cfra, 39.99f, std::nullopt);
+
+ ED_keylist_free(keylist);
+}
+
+static float check_keylist_find_prev_range(const AnimKeylist *keylist,
+ const float frame_from,
+ const float frame_to,
+ const std::optional<float> expected_frame)
+{
+ return check_keylist_find_range(
+ keylist, ED_keylist_find_prev, frame_from, frame_to, expected_frame);
+}
+
+TEST(keylist, find_prev)
+{
+ AnimKeylist *keylist = create_test_keylist();
+
+ float cfra = check_keylist_find_prev_range(keylist, 0.0f, 10.01f, std::nullopt);
+ cfra = check_keylist_find_prev_range(keylist, cfra, 20.01f, 10.0f);
+ cfra = check_keylist_find_prev_range(keylist, cfra, 30.01f, 20.0f);
+ cfra = check_keylist_find_prev_range(keylist, cfra, 49.99f, 30.0f);
+
+ ED_keylist_free(keylist);
+}
+
+static float check_keylist_find_exact_range(const AnimKeylist *keylist,
+ const float frame_from,
+ const float frame_to,
+ const std::optional<float> expected_frame)
+{
+ return check_keylist_find_range(
+ keylist, ED_keylist_find_exact, frame_from, frame_to, expected_frame);
+}
+
+TEST(keylist, find_exact)
+{
+ AnimKeylist *keylist = create_test_keylist();
+
+ float cfra = check_keylist_find_exact_range(keylist, 0.0f, 9.99f, std::nullopt);
+ cfra = check_keylist_find_exact_range(keylist, cfra, 10.01f, 10.0f);
+ cfra = check_keylist_find_exact_range(keylist, cfra, 19.99f, std::nullopt);
+ cfra = check_keylist_find_exact_range(keylist, cfra, 20.01f, 20.0f);
+ cfra = check_keylist_find_exact_range(keylist, cfra, 29.99f, std::nullopt);
+ cfra = check_keylist_find_exact_range(keylist, cfra, 30.01f, 30.0f);
+ cfra = check_keylist_find_exact_range(keylist, cfra, 49.99f, std::nullopt);
+
+ ED_keylist_free(keylist);
+}
+
+} // namespace blender::editor::animation::tests
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index 0a9f1a36a28..25d2f6c510b 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -35,6 +35,7 @@
#include "BLT_translation.h"
+#include "DNA_action_types.h"
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_constraint_types.h"
@@ -90,7 +91,6 @@ static int delete_key_using_keying_set(bContext *C, wmOperator *op, KeyingSet *k
/* ************************************************** */
/* Keyframing Setting Wrangling */
-/* Get the active settings for keyframing settings from context (specifically the given scene) */
eInsertKeyFlags ANIM_get_keyframing_flags(Scene *scene, const bool use_autokey_mode)
{
eInsertKeyFlags flag = INSERTKEY_NOFLAGS;
@@ -132,9 +132,6 @@ eInsertKeyFlags ANIM_get_keyframing_flags(Scene *scene, const bool use_autokey_m
/* ******************************************* */
/* Animation Data Validation */
-/* Get (or add relevant data to be able to do so) the Active Action for the given
- * Animation Data block, given an ID block where the Animation Data should reside.
- */
bAction *ED_id_action_ensure(Main *bmain, ID *id)
{
AnimData *adt;
@@ -176,10 +173,6 @@ bAction *ED_id_action_ensure(Main *bmain, ID *id)
return adt->action;
}
-/**
- * Find the F-Curve from the Active Action,
- * for the given Animation Data block. This assumes that all the destinations are valid.
- */
FCurve *ED_action_fcurve_find(struct bAction *act, const char rna_path[], const int array_index)
{
/* Sanity checks. */
@@ -189,10 +182,6 @@ FCurve *ED_action_fcurve_find(struct bAction *act, const char rna_path[], const
return BKE_fcurve_find(&act->curves, rna_path, array_index);
}
-/**
- * Get (or add relevant data to be able to do so) F-Curve from the Active Action,
- * for the given Animation Data block. This assumes that all the destinations are valid.
- */
FCurve *ED_action_fcurve_ensure(struct Main *bmain,
struct bAction *act,
const char group[],
@@ -294,9 +283,6 @@ static void update_autoflags_fcurve_direct(FCurve *fcu, PropertyRNA *prop)
}
}
-/* Update integer/discrete flags of the FCurve (used when creating/inserting keyframes,
- * but also through RNA when editing an ID prop, see T37103).
- */
void update_autoflags_fcurve(FCurve *fcu, bContext *C, ReportList *reports, PointerRNA *ptr)
{
PointerRNA tmp_ptr;
@@ -375,6 +361,43 @@ static eFCU_Cycle_Type remap_cyclic_keyframe_location(FCurve *fcu, float *px, fl
return type;
}
+/* Used to make curves newly added to a cyclic Action cycle with the correct period. */
+static void make_new_fcurve_cyclic(const bAction *act, FCurve *fcu)
+{
+ /* The curve must contain one (newly-added) keyframe. */
+ if (fcu->totvert != 1 || !fcu->bezt) {
+ return;
+ }
+
+ const float period = act->frame_end - act->frame_start;
+
+ if (period < 0.1f) {
+ return;
+ }
+
+ /* Move the keyframe into the range. */
+ const float frame_offset = fcu->bezt[0].vec[1][0] - act->frame_start;
+ const float fix = floorf(frame_offset / period) * period;
+
+ fcu->bezt[0].vec[0][0] -= fix;
+ fcu->bezt[0].vec[1][0] -= fix;
+ fcu->bezt[0].vec[2][0] -= fix;
+
+ /* Duplicate and offset the keyframe. */
+ fcu->bezt = MEM_reallocN(fcu->bezt, sizeof(BezTriple) * 2);
+ fcu->totvert = 2;
+
+ fcu->bezt[1] = fcu->bezt[0];
+ fcu->bezt[1].vec[0][0] += period;
+ fcu->bezt[1].vec[1][0] += period;
+ fcu->bezt[1].vec[2][0] += period;
+
+ /* Add the cycles modifier. */
+ if (!fcu->modifiers.first) {
+ add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_CYCLES, fcu);
+ }
+}
+
/* -------------- BezTriple Insertion -------------------- */
/* Change the Y position of a keyframe to match the input, adjusting handles. */
@@ -395,13 +418,6 @@ static void replace_bezt_keyframe_ypos(BezTriple *dst, const BezTriple *bezt)
/* TODO: perform some other operations? */
}
-/* This function adds a given BezTriple to an F-Curve. It will allocate
- * memory for the array if needed, and will insert the BezTriple into a
- * suitable place in chronological order.
- *
- * NOTE: any recalculate of the F-Curve that needs to be done will need to
- * be done by the caller.
- */
int insert_bezt_fcurve(FCurve *fcu, const BezTriple *bezt, eInsertKeyFlags flag)
{
int i = 0;
@@ -537,15 +553,6 @@ static void subdivide_nonauto_handles(const FCurve *fcu,
bezt->h1 = bezt->h2 = HD_ALIGN;
}
-/**
- * This function is a wrapper for #insert_bezt_fcurve(), and should be used when
- * adding a new keyframe to a curve, when the keyframe doesn't exist anywhere else yet.
- * It returns the index at which the keyframe was added.
- *
- * \param keyframe_type: The type of keyframe (#eBezTriple_KeyframeType).
- * \param flag: Optional flags (eInsertKeyFlags) for controlling how keys get added
- * and/or whether updates get done.
- */
int insert_vert_fcurve(
FCurve *fcu, float x, float y, eBezTriple_KeyframeType keyframe_type, eInsertKeyFlags flag)
{
@@ -1235,19 +1242,6 @@ static bool insert_keyframe_value(ReportList *reports,
return insert_vert_fcurve(fcu, cfra, curval, keytype, flag) >= 0;
}
-/* Secondary Keyframing API call:
- * Use this when validation of necessary animation data is not necessary,
- * since an RNA-pointer to the necessary data being keyframed,
- * and a pointer to the F-Curve to use have both been provided.
- *
- * This function can't keyframe quaternion channels on some NLA strip types.
- *
- * keytype is the "keyframe type" (eBezTriple_KeyframeType), as shown in the Dope Sheet.
- *
- * The flag argument is used for special settings that alter the behavior of
- * the keyframe insertion. These include the 'visual' keyframing modes, quick refresh,
- * and extra keyframe filtering.
- */
bool insert_keyframe_direct(ReportList *reports,
PointerRNA ptr,
PropertyRNA *prop,
@@ -1352,8 +1346,10 @@ static bool insert_keyframe_fcurve_value(Main *bmain,
/* we may not have a F-Curve when we're replacing only... */
if (fcu) {
+ const bool is_new_curve = (fcu->totvert == 0);
+
/* set color mode if the F-Curve is new (i.e. without any keyframes) */
- if ((fcu->totvert == 0) && (flag & INSERTKEY_XYZ2RGB)) {
+ if (is_new_curve && (flag & INSERTKEY_XYZ2RGB)) {
/* for Loc/Rot/Scale and also Color F-Curves, the color of the F-Curve in the Graph Editor,
* is determined by the array index for the F-Curve
*/
@@ -1366,12 +1362,26 @@ static bool insert_keyframe_fcurve_value(Main *bmain,
}
}
+ /* If the curve has only one key, make it cyclic if appropriate. */
+ const bool is_cyclic_action = (flag & INSERTKEY_CYCLE_AWARE) && BKE_action_is_cyclic(act);
+
+ if (is_cyclic_action && fcu->totvert == 1) {
+ make_new_fcurve_cyclic(act, fcu);
+ }
+
/* update F-Curve flags to ensure proper behavior for property type */
update_autoflags_fcurve_direct(fcu, prop);
/* insert keyframe */
- return insert_keyframe_value(
+ const bool success = insert_keyframe_value(
reports, ptr, prop, fcu, anim_eval_context, curval, keytype, flag);
+
+ /* If the curve is new, make it cyclic if appropriate. */
+ if (is_cyclic_action && is_new_curve) {
+ make_new_fcurve_cyclic(act, fcu);
+ }
+
+ return success;
}
return false;
@@ -1399,19 +1409,6 @@ static AnimationEvalContext nla_time_remap(const AnimationEvalContext *anim_eval
return *anim_eval_context;
}
-/**
- * Main Keyframing API call
- *
- * Use this when validation of necessary animation data is necessary, since it may not exist yet.
- *
- * The flag argument is used for special settings that alter the behavior of
- * the keyframe insertion. These include the 'visual' keyframing modes, quick refresh,
- * and extra keyframe filtering.
- *
- * index of -1 keys all array indices
- *
- * \return The number of key-frames inserted.
- */
int insert_keyframe(Main *bmain,
ReportList *reports,
ID *id,
@@ -1638,9 +1635,6 @@ static void deg_tag_after_keyframe_delete(Main *bmain, ID *id, AnimData *adt)
}
}
-/**
- * \return The number of key-frames deleted.
- */
int delete_keyframe(Main *bmain,
ReportList *reports,
ID *id,
@@ -1962,7 +1956,6 @@ void ANIM_OT_keyframe_insert(wmOperatorType *ot)
ot->prop = prop;
}
-/* Clone of 'ANIM_OT_keyframe_insert' which uses a name for the keying set instead of an enum. */
void ANIM_OT_keyframe_insert_by_name(wmOperatorType *ot)
{
PropertyRNA *prop;
@@ -2757,7 +2750,6 @@ bool autokeyframe_cfra_can_key(const Scene *scene, ID *id)
/* --------------- API/Per-Datablock Handling ------------------- */
-/* Checks if some F-Curve has a keyframe for a given frame */
bool fcurve_frame_has_keyframe(const FCurve *fcu, float frame, short filter)
{
/* quick sanity check */
@@ -2784,7 +2776,6 @@ bool fcurve_frame_has_keyframe(const FCurve *fcu, float frame, short filter)
return false;
}
-/* Returns whether the current value of a given property differs from the interpolated value. */
bool fcurve_is_changed(PointerRNA ptr,
PropertyRNA *prop,
FCurve *fcu,
@@ -2913,7 +2904,6 @@ static bool object_frame_has_keyframe(Object *ob, float frame, short filter)
/* --------------- API ------------------- */
-/* Checks whether a keyframe exists for the given ID-block one the given frame */
bool id_frame_has_keyframe(ID *id, float frame, short filter)
{
/* sanity checks */
@@ -2989,9 +2979,6 @@ bool ED_autokeyframe_pchan(
return false;
}
-/**
- * Use for auto-keyframing from the UI.
- */
bool ED_autokeyframe_property(
bContext *C, Scene *scene, PointerRNA *ptr, PropertyRNA *prop, int rnaindex, float cfra)
{
diff --git a/source/blender/editors/animation/keyingsets.c b/source/blender/editors/animation/keyingsets.c
index e1fd3b07f46..59bb60d8fa0 100644
--- a/source/blender/editors/animation/keyingsets.c
+++ b/source/blender/editors/animation/keyingsets.c
@@ -529,12 +529,10 @@ void ANIM_OT_keying_set_active_set(wmOperatorType *ot)
/* Keying Set Type Info declarations */
static ListBase keyingset_type_infos = {NULL, NULL};
-/* Built-In Keying Sets (referencing type information). */
ListBase builtin_keyingsets = {NULL, NULL};
/* --------------- */
-/* Find KeyingSet type info given a name. */
KeyingSetInfo *ANIM_keyingset_info_find_name(const char name[])
{
/* sanity checks */
@@ -546,7 +544,6 @@ KeyingSetInfo *ANIM_keyingset_info_find_name(const char name[])
return BLI_findstring(&keyingset_type_infos, name, offsetof(KeyingSetInfo, idname));
}
-/* Find builtin KeyingSet by name. */
KeyingSet *ANIM_builtin_keyingset_get_named(KeyingSet *prevKS, const char name[])
{
KeyingSet *ks, *first = NULL;
@@ -582,8 +579,6 @@ KeyingSet *ANIM_builtin_keyingset_get_named(KeyingSet *prevKS, const char name[]
/* --------------- */
-/* Add the given KeyingSetInfo to the list of type infos,
- * and create an appropriate builtin set too. */
void ANIM_keyingset_info_register(KeyingSetInfo *ksi)
{
KeyingSet *ks;
@@ -603,8 +598,6 @@ void ANIM_keyingset_info_register(KeyingSetInfo *ksi)
BLI_addtail(&keyingset_type_infos, ksi);
}
-/* Remove the given KeyingSetInfo from the list of type infos,
- * and also remove the builtin set if appropriate. */
void ANIM_keyingset_info_unregister(Main *bmain, KeyingSetInfo *ksi)
{
KeyingSet *ks, *ksn;
@@ -633,8 +626,6 @@ void ANIM_keyingset_info_unregister(Main *bmain, KeyingSetInfo *ksi)
BLI_freelinkN(&keyingset_type_infos, ksi);
}
-/* --------------- */
-
void ANIM_keyingset_infos_exit(void)
{
KeyingSetInfo *ksi, *next;
@@ -654,7 +645,6 @@ void ANIM_keyingset_infos_exit(void)
BKE_keyingsets_free(&builtin_keyingsets);
}
-/* Check if the ID appears in the paths specified by the KeyingSet */
bool ANIM_keyingset_find_id(KeyingSet *ks, ID *id)
{
/* sanity checks */
@@ -670,7 +660,6 @@ bool ANIM_keyingset_find_id(KeyingSet *ks, ID *id)
/* Getters for Active/Indices ----------------------------- */
-/* Get the active Keying Set for the Scene provided */
KeyingSet *ANIM_scene_get_active_keyingset(const Scene *scene)
{
/* if no scene, we've got no hope of finding the Keying Set */
@@ -689,7 +678,6 @@ KeyingSet *ANIM_scene_get_active_keyingset(const Scene *scene)
return BLI_findlink(&builtin_keyingsets, (-scene->active_keyingset) - 1);
}
-/* Get the index of the Keying Set provided, for the given Scene */
int ANIM_scene_get_keyingset_index(Scene *scene, KeyingSet *ks)
{
int index;
@@ -721,7 +709,6 @@ int ANIM_scene_get_keyingset_index(Scene *scene, KeyingSet *ks)
return 0;
}
-/* Get Keying Set to use for Auto-Keyframing some transforms */
KeyingSet *ANIM_get_keyingset_for_autokeying(const Scene *scene, const char *transformKSName)
{
/* get KeyingSet to use
@@ -739,7 +726,6 @@ KeyingSet *ANIM_get_keyingset_for_autokeying(const Scene *scene, const char *tra
/* Menu of All Keying Sets ----------------------------- */
-/* Dynamically populate an enum of Keying Sets */
const EnumPropertyItem *ANIM_keying_sets_enum_itemf(bContext *C,
PointerRNA *UNUSED(ptr),
PropertyRNA *UNUSED(prop),
@@ -808,14 +794,6 @@ const EnumPropertyItem *ANIM_keying_sets_enum_itemf(bContext *C,
return item;
}
-/**
- * Get the keying set from enum values generated in #ANIM_keying_sets_enum_itemf.
- *
- * Type is the Keying Set the user specified to use when calling the operator:
- * - type == 0: use scene's active Keying Set
- * - type > 0: use a user-defined Keying Set from the active scene
- * - type < 0: use a builtin Keying Set
- */
KeyingSet *ANIM_keyingset_get_from_enum_type(Scene *scene, int type)
{
KeyingSet *ks = NULL;
@@ -847,7 +825,6 @@ KeyingSet *ANIM_keyingset_get_from_idname(Scene *scene, const char *idname)
/* Polling API ----------------------------------------------- */
-/* Check if KeyingSet can be used in the current context */
bool ANIM_keyingset_context_ok_poll(bContext *C, KeyingSet *ks)
{
if ((ks->flag & KEYINGSET_ABSOLUTE) == 0) {
@@ -894,7 +871,6 @@ static void RKS_ITER_overrides_list(KeyingSetInfo *ksi,
}
}
-/* Add new data source for relative Keying Sets */
void ANIM_relative_keyingset_add_source(ListBase *dsources, ID *id, StructRNA *srna, void *data)
{
tRKS_DSource *ds;
@@ -925,14 +901,6 @@ void ANIM_relative_keyingset_add_source(ListBase *dsources, ID *id, StructRNA *s
/* KeyingSet Operations (Insert/Delete Keyframes) ------------ */
-/**
- * Given a KeyingSet and context info, validate Keying Set's paths.
- * This is only really necessary with relative/built-in KeyingSets
- * where their list of paths is dynamically generated based on the
- * current context info.
- *
- * Returns 0 if succeeded, otherwise an error code: eModifyKey_Returns
- */
eModifyKey_Returns ANIM_validate_keyingset(bContext *C, ListBase *dsources, KeyingSet *ks)
{
/* sanity check */
@@ -1017,14 +985,6 @@ static eInsertKeyFlags keyingset_apply_keying_flags(const eInsertKeyFlags base_f
return result;
}
-/**
- * Given a KeyingSet and context info (if required),
- * modify keyframes for the channels specified by the KeyingSet.
- * This takes into account many of the different combinations of using KeyingSets.
- *
- * \returns the number of channels that key-frames were added or
- * an #eModifyKey_Returns value (always a negative number).
- */
int ANIM_apply_keyingset(
bContext *C, ListBase *dsources, bAction *act, KeyingSet *ks, short mode, float cfra)
{
diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c
index 21a5c6c2865..02ecfdb4ea6 100644
--- a/source/blender/editors/armature/armature_add.c
+++ b/source/blender/editors/armature/armature_add.c
@@ -64,8 +64,6 @@
/* *************** Adding stuff in editmode *************** */
-/* default bone add, returns it selected, but without tail set */
-/* XXX should be used everywhere, now it mallocs bones still locally in functions */
EditBone *ED_armature_ebone_add(bArmature *arm, const char *name)
{
EditBone *bone = MEM_callocN(sizeof(EditBone), "eBone");
@@ -274,7 +272,6 @@ void ARMATURE_OT_click_extrude(wmOperatorType *ot)
/* props */
}
-/* adds an EditBone between the nominated locations (should be in the right space) */
EditBone *add_points_bone(Object *obedit, float head[3], float tail[3])
{
EditBone *ebo;
@@ -302,7 +299,6 @@ static EditBone *get_named_editbone(ListBase *edbo, const char *name)
return NULL;
}
-/* Call this before doing any duplications. */
void preEditBoneDuplicate(ListBase *editbones)
{
/* clear temp */
@@ -1317,9 +1313,10 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-/* following conventions from #MESH_OT_symmetrize */
void ARMATURE_OT_symmetrize(wmOperatorType *ot)
{
+ /* NOTE: following conventions from #MESH_OT_symmetrize */
+
/* subset of 'rna_enum_symmetrize_direction_items' */
static const EnumPropertyItem arm_symmetrize_direction_items[] = {
{-1, "NEGATIVE_X", 0, "-X to +X", ""},
diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c
index fd5ae6c7099..b709980cabe 100644
--- a/source/blender/editors/armature/armature_edit.c
+++ b/source/blender/editors/armature/armature_edit.c
@@ -66,9 +66,6 @@
/* NOTE: these functions are exported to the Object module to be called from the tools there */
-/**
- * See #BKE_armature_transform for object-mode transform.
- */
void ED_armature_edit_transform(bArmature *arm, const float mat[4][4], const bool do_props)
{
EditBone *ebone;
@@ -116,8 +113,6 @@ void ED_armature_transform(bArmature *arm, const float mat[4][4], const bool do_
}
}
-/* exported for use in editors/object/ */
-/* 0 == do center, 1 == center new, 2 == center cursor */
void ED_armature_origin_set(
Main *bmain, Object *ob, const float cursor[3], int centermode, int around)
{
@@ -186,9 +181,6 @@ void ED_armature_origin_set(
/** \name Bone Roll Calculate Operator
* \{ */
-/* adjust bone roll to align Z axis with vector
- * vec is in local space and is normalized
- */
float ED_armature_ebone_roll_to_vector(const EditBone *bone,
const float align_axis[3],
const bool axis_only)
diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h
index 3a6761ba915..97f8c0cf630 100644
--- a/source/blender/editors/armature/armature_intern.h
+++ b/source/blender/editors/armature/armature_intern.h
@@ -39,8 +39,10 @@ struct bArmature;
struct LinkData;
struct ListBase;
-/* ******************************************************* */
-/* Armature EditMode Operators */
+/* -------------------------------------------------------------------- */
+/** \name Armature EditMode Operators
+ * \{ */
+
void ARMATURE_OT_bone_primitive_add(struct wmOperatorType *ot);
void ARMATURE_OT_align(struct wmOperatorType *ot);
@@ -82,8 +84,12 @@ void ARMATURE_OT_layers_show_all(struct wmOperatorType *ot);
void ARMATURE_OT_armature_layers(struct wmOperatorType *ot);
void ARMATURE_OT_bone_layers(struct wmOperatorType *ot);
-/* ******************************************************* */
-/* Pose-Mode Operators */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Pose-Mode Operators
+ * \{ */
+
void POSE_OT_hide(struct wmOperatorType *ot);
void POSE_OT_reveal(struct wmOperatorType *ot);
@@ -131,8 +137,12 @@ void POSE_OT_quaternions_flip(struct wmOperatorType *ot);
void POSE_OT_bone_layers(struct wmOperatorType *ot);
-/* ******************************************************* */
-/* Pose Tool Utilities (for PoseLib, Pose Sliding, etc.) */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Pose Tool Utilities (for PoseLib, Pose Sliding, etc.)
+ * \{ */
+
/* pose_utils.c */
/* Temporary data linking PoseChannels with the F-Curves they affect */
@@ -173,21 +183,39 @@ typedef struct tPChanFCurveLink {
/* ----------- */
+/** Returns a valid pose armature for this object, else returns NULL. */
struct Object *poseAnim_object_get(struct Object *ob_);
+/** Get sets of F-Curves providing transforms for the bones in the Pose. */
void poseAnim_mapping_get(struct bContext *C, ListBase *pfLinks);
+/** Free F-Curve <-> PoseChannel links. */
void poseAnim_mapping_free(ListBase *pfLinks);
+/**
+ * Helper for apply() / reset() - refresh the data.
+ */
void poseAnim_mapping_refresh(struct bContext *C, struct Scene *scene, struct Object *ob);
+/**
+ * Reset changes made to current pose.
+ */
void poseAnim_mapping_reset(ListBase *pfLinks);
+/** Perform auto-key-framing after changes were made + confirmed. */
void poseAnim_mapping_autoKeyframe(struct bContext *C,
struct Scene *scene,
ListBase *pfLinks,
float cframe);
+/**
+ * Find the next F-Curve for a PoseChannel with matching path...
+ * - path is not just the pfl rna_path, since that path doesn't have property info yet.
+ */
LinkData *poseAnim_mapping_getNextFCurve(ListBase *fcuLinks, LinkData *prev, const char *path);
-/* ******************************************************* */
-/* PoseLib */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name PoseLib
+ * \{ */
+
/* pose_lib.c */
void POSELIB_OT_new(struct wmOperatorType *ot);
@@ -207,8 +235,12 @@ void POSELIB_OT_apply_pose(struct wmOperatorType *ot);
void POSELIB_OT_apply_pose_asset(struct wmOperatorType *ot);
void POSELIB_OT_blend_pose_asset(struct wmOperatorType *ot);
-/* ******************************************************* */
-/* Pose Sliding Tools */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Pose Sliding Tools
+ * \{ */
+
/* pose_slide.c */
void POSE_OT_push(struct wmOperatorType *ot);
@@ -220,8 +252,11 @@ void POSE_OT_blend_to_neighbors(struct wmOperatorType *ot);
void POSE_OT_propagate(struct wmOperatorType *ot);
-/* ******************************************************* */
-/* Various Armature Edit/Pose Editing API's */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Various Armature Edit/Pose Editing API's
+ * \{ */
/* Ideally, many of these defines would not be needed as everything would be strictly
* self-contained within each file,
@@ -232,7 +267,9 @@ struct EditBone *make_boneList(struct ListBase *edbo,
struct ListBase *bones,
struct Bone *actBone);
-/* duplicate method */
+/* Duplicate method. */
+
+/** Call this before doing any duplications. */
void preEditBoneDuplicate(struct ListBase *editbones);
void postEditBoneDuplicate(struct ListBase *editbones, struct Object *ob);
struct EditBone *duplicateEditBone(struct EditBone *cur_bone,
@@ -240,22 +277,37 @@ struct EditBone *duplicateEditBone(struct EditBone *cur_bone,
struct ListBase *editbones,
struct Object *ob);
-/* duplicate method (cross objects) */
-/* editbones is the target list */
+/* Duplicate method (cross objects). */
+
+/**
+ * \param editbones: The target list.
+ */
struct EditBone *duplicateEditBoneObjects(struct EditBone *cur_bone,
const char *name,
struct ListBase *editbones,
struct Object *src_ob,
struct Object *dst_ob);
+/** Adds an EditBone between the nominated locations (should be in the right space). */
struct EditBone *add_points_bone(struct Object *obedit, float head[3], float tail[3]);
void bone_free(struct bArmature *arm, struct EditBone *bone);
void armature_tag_select_mirrored(struct bArmature *arm);
+/**
+ * Helper function for tools to work on mirrored parts.
+ * it leaves mirrored bones selected then too, which is a good indication of what happened.
+ */
void armature_select_mirrored_ex(struct bArmature *arm, const int flag);
void armature_select_mirrored(struct bArmature *arm);
+/** Only works when tagged. */
void armature_tag_unselect(struct bArmature *arm);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Selection Picking
+ * \{ */
+
struct EditBone *ED_armature_pick_ebone(struct bContext *C,
const int xy[2],
bool findunsel,
@@ -291,7 +343,19 @@ struct Bone *ED_armature_pick_bone_from_selectbuffer(struct Base **bases,
bool do_nearest,
struct Base **r_base);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Iteration
+ * \{ */
+
+/**
+ * XXX: bone_looper is only to be used when we want to access settings
+ * (i.e. editability/visibility/selected) that context doesn't offer.
+ */
int bone_looper(struct Object *ob,
struct Bone *bone,
void *data,
int (*bone_func)(struct Object *, struct Bone *, void *));
+
+/** \} */
diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c
index de1c14a15ce..750c64d74a7 100644
--- a/source/blender/editors/armature/armature_naming.c
+++ b/source/blender/editors/armature/armature_naming.c
@@ -80,7 +80,6 @@ static bool editbone_unique_check(void *arg, const char *name)
return dupli && dupli != data->bone;
}
-/* If bone is already in list, pass it as param to ignore it. */
void ED_armature_ebone_unique_name(ListBase *ebones, char *name, EditBone *bone)
{
struct {
@@ -154,9 +153,6 @@ static void constraint_bone_name_fix(Object *ob,
}
}
-/* called by UI for renaming a bone */
-/* warning: make sure the original bone was not renamed yet! */
-/* seems messy, but that's what you get with not using pointers but channel names :) */
void ED_armature_bone_rename(Main *bmain,
bArmature *arm,
const char *oldnamep,
@@ -269,6 +265,7 @@ void ED_armature_bone_rename(Main *bmain,
bDeformGroup *dg = BKE_object_defgroup_find_name(ob, oldname);
if (dg) {
BLI_strncpy(dg->name, newname, MAXBONENAME);
+ DEG_id_tag_update(ob->data, ID_RECALC_GEOMETRY);
}
}
@@ -325,6 +322,7 @@ void ED_armature_bone_rename(Main *bmain,
bDeformGroup *dg = BKE_object_defgroup_find_name(ob, oldname);
if (dg) {
BLI_strncpy(dg->name, newname, MAXBONENAME);
+ DEG_id_tag_update(ob->data, ID_RECALC_GEOMETRY);
}
}
break;
@@ -393,16 +391,6 @@ typedef struct BoneFlipNameData {
char name_flip[MAXBONENAME];
} BoneFlipNameData;
-/**
- * Renames (by flipping) all selected bones at once.
- *
- * This way if we are flipping related bones (e.g., Bone.L, Bone.R) at the same time
- * all the bones are safely renamed, without conflicting with each other.
- *
- * \param arm: Armature the bones belong to
- * \param bones_names: List of BoneConflict elems.
- * \param do_strip_numbers: if set, try to get rid of dot-numbers at end of bone names.
- */
void ED_armature_bones_flip_names(Main *bmain,
bArmature *arm,
ListBase *bones_names,
diff --git a/source/blender/editors/armature/armature_ops.c b/source/blender/editors/armature/armature_ops.c
index 75b0455d026..364e778fc2e 100644
--- a/source/blender/editors/armature/armature_ops.c
+++ b/source/blender/editors/armature/armature_ops.c
@@ -33,9 +33,10 @@
/* ************************** registration **********************************/
-/* Both operators ARMATURE_OT_xxx and POSE_OT_xxx here */
void ED_operatortypes_armature(void)
{
+ /* Both operators `ARMATURE_OT_*` and `POSE_OT_*` are registered here. */
+
/* EDIT ARMATURE */
WM_operatortype_append(ARMATURE_OT_bone_primitive_add);
diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c
index cac6e9965b6..eebe8a447f7 100644
--- a/source/blender/editors/armature/armature_relations.c
+++ b/source/blender/editors/armature/armature_relations.c
@@ -269,7 +269,6 @@ static void joined_armature_fix_links(
}
}
-/* join armature exec is exported for use in object->join objects operator... */
int ED_armature_join_objects_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -929,7 +928,7 @@ static int armature_parent_set_invoke(bContext *C,
enable_connect = true;
break;
}
- else if (!(ebone->flag & BONE_CONNECTED)) {
+ if (!(ebone->flag & BONE_CONNECTED)) {
enable_connect = true;
}
}
diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c
index 937385f9ffa..5e4cb813064 100644
--- a/source/blender/editors/armature/armature_select.c
+++ b/source/blender/editors/armature/armature_select.c
@@ -139,7 +139,6 @@ Base *ED_armature_base_and_pchan_from_select_buffer(Base **bases,
return base;
}
-/* For callers that don't need the pose channel. */
Base *ED_armature_base_and_bone_from_select_buffer(Base **bases,
uint bases_len,
int hit,
@@ -1080,7 +1079,6 @@ bool ED_armature_edit_select_pick_bone(bContext *C,
return true;
}
-/* context: editmode armature in view3d */
bool ED_armature_edit_select_pick(
bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
{
@@ -1175,18 +1173,6 @@ static bool armature_edit_select_op_apply(bArmature *arm,
return changed;
}
-/**
- * Perform a selection operation on elements which have been 'touched',
- * use for lasso & border select but can be used elsewhere too.
- *
- * Tagging is done via #EditBone.temp.i using: #BONESEL_ROOT, #BONESEL_TIP, #BONESEL_BONE
- * And optionally ignoring end-points using the #BONESEL_ROOT, #BONESEL_TIP right shifted 16 bits.
- * (used when the values are clipped outside the view).
- *
- * \param sel_op: #eSelectOp type.
- *
- * \note Visibility checks must be done by the caller.
- */
bool ED_armature_edit_select_op_from_tagged(bArmature *arm, const int sel_op)
{
bool changed = false;
diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c
index 4fe4422e4e0..1c48285563d 100644
--- a/source/blender/editors/armature/armature_utils.c
+++ b/source/blender/editors/armature/armature_utils.c
@@ -45,10 +45,10 @@
#include "armature_intern.h"
-/* *************************************************************** */
-/* Validation */
+/* -------------------------------------------------------------------- */
+/** \name Validation
+ * \{ */
-/* Sync selection to parent for connected children */
void ED_armature_edit_sync_selection(ListBase *edbo)
{
EditBone *ebo;
@@ -86,10 +86,6 @@ void ED_armature_edit_validate_active(struct bArmature *arm)
}
}
-/* Update the layers_used variable after bones are moved between layer
- * NOTE: Used to be done in drawing code in 2.7, but that won't work with
- * Copy-on-Write, as drawing uses evaluated copies.
- */
void ED_armature_edit_refresh_layer_used(bArmature *arm)
{
arm->layer_used = 0;
@@ -98,11 +94,12 @@ void ED_armature_edit_refresh_layer_used(bArmature *arm)
}
}
-/* *************************************************************** */
-/* Bone Operations */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Bone Operations
+ * \{ */
-/* XXX bone_looper is only to be used when we want to access settings
- * (i.e. editability/visibility/selected) that context doesn't offer */
int bone_looper(Object *ob, Bone *bone, void *data, int (*bone_func)(Object *, Bone *, void *))
{
/* We want to apply the function bone_func to every bone
@@ -129,8 +126,11 @@ int bone_looper(Object *ob, Bone *bone, void *data, int (*bone_func)(Object *, B
return count;
}
-/* *************************************************************** */
-/* Bone Removal */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Bone Removal
+ * \{ */
void bone_free(bArmature *arm, EditBone *bone)
{
@@ -155,9 +155,6 @@ void bone_free(bArmature *arm, EditBone *bone)
BLI_freelinkN(arm->edbo, bone);
}
-/**
- * \param clear_connected: When false caller is responsible for keeping the flag in a valid state.
- */
void ED_armature_ebone_remove_ex(bArmature *arm, EditBone *exBone, bool clear_connected)
{
EditBone *curBone;
@@ -190,13 +187,6 @@ bool ED_armature_ebone_is_child_recursive(EditBone *ebone_parent, EditBone *ebon
return false;
}
-/**
- * Finds the first parent shared by \a ebone_child
- *
- * \param ebone_child: Children bones to search
- * \param ebone_child_tot: Size of the ebone_child array
- * \return The shared parent or NULL.
- */
EditBone *ED_armature_ebone_find_shared_parent(EditBone *ebone_child[], const uint ebone_child_tot)
{
#define EBONE_TEMP_UINT(ebone) (*((uint *)(&((ebone)->temp))))
@@ -284,20 +274,17 @@ void ED_armature_ebone_from_mat4(EditBone *ebone, const float mat[4][4])
ED_armature_ebone_from_mat3(ebone, mat3);
}
-/**
- * Return a pointer to the bone of the given name
- */
EditBone *ED_armature_ebone_find_name(const ListBase *edbo, const char *name)
{
return BLI_findstring(edbo, name, offsetof(EditBone, name));
}
-/* *************************************************************** */
-/* Mirroring */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Mirroring
+ * \{ */
-/**
- * \see #BKE_pose_channel_get_mirrored (pose-mode, matching function)
- */
EditBone *ED_armature_ebone_get_mirrored(const ListBase *edbo, EditBone *ebo)
{
char name_flip[MAXBONENAME];
@@ -317,8 +304,6 @@ EditBone *ED_armature_ebone_get_mirrored(const ListBase *edbo, EditBone *ebo)
/* ------------------------------------- */
-/* helper function for tools to work on mirrored parts.
- * it leaves mirrored bones selected then too, which is a good indication of what happened */
void armature_select_mirrored_ex(bArmature *arm, const int flag)
{
BLI_assert((flag & ~(BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL)) == 0);
@@ -375,7 +360,6 @@ void armature_tag_select_mirrored(bArmature *arm)
}
}
-/* only works when tagged */
void armature_tag_unselect(bArmature *arm)
{
EditBone *curBone;
@@ -465,8 +449,6 @@ void ED_armature_ebone_transform_mirror_update(bArmature *arm, EditBone *ebo, bo
}
}
-/* if editbone (partial) selected, copy data */
-/* context; editmode armature, with mirror editing enabled */
void ED_armature_edit_transform_mirror_update(Object *obedit)
{
bArmature *arm = obedit->data;
@@ -475,8 +457,11 @@ void ED_armature_edit_transform_mirror_update(Object *obedit)
}
}
-/* *************************************************************** */
-/* Armature EditMode Conversions */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Armature EditMode Conversions
+ * \{ */
/* converts Bones to EditBone list, used for tools as well */
static EditBone *make_boneList_recursive(ListBase *edbo,
@@ -688,7 +673,6 @@ static void armature_finalize_restpose(ListBase *bonelist, ListBase *editbonelis
}
}
-/* put EditMode back in Object */
void ED_armature_from_edit(Main *bmain, bArmature *arm)
{
EditBone *eBone, *neBone;
@@ -838,7 +822,6 @@ void ED_armature_edit_free(struct bArmature *arm)
}
}
-/* Put armature in EditMode */
void ED_armature_to_edit(bArmature *arm)
{
ED_armature_edit_free(arm);
@@ -846,10 +829,11 @@ void ED_armature_to_edit(bArmature *arm)
arm->act_edbone = make_boneList(arm->edbo, &arm->bonebase, arm->act_bone);
}
-/* *************************************************************** */
-/* Used by Undo for Armature EditMode. */
+/** \} */
-/* free's bones and their properties */
+/* -------------------------------------------------------------------- */
+/** \name Used by Undo for Armature EditMode
+ * \{ */
void ED_armature_ebone_listbase_free(ListBase *lb, const bool do_id_user)
{
@@ -908,10 +892,14 @@ void ED_armature_ebone_listbase_temp_clear(ListBase *lb)
}
}
-/* *************************************************************** */
-/* Low level selection functions which hide connected-parent
- * flag behavior which gets tricky to handle in selection operators.
- * (no flushing in ED_armature_ebone_select.*, that should be explicit) */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Low Level Selection Functions
+ *
+ * which hide connected-parent flag behavior which gets tricky to handle in selection operators.
+ * (no flushing in `ED_armature_ebone_select.*`, that should be explicit).
+ * \{ */
int ED_armature_ebone_selectflag_get(const EditBone *ebone)
{
@@ -964,3 +952,5 @@ void ED_armature_ebone_select_set(EditBone *ebone, bool select)
}
ED_armature_ebone_selectflag_set(ebone, flag);
}
+
+/** \} */
diff --git a/source/blender/editors/armature/editarmature_undo.c b/source/blender/editors/armature/editarmature_undo.c
index 832e75b2a8b..9117dfe892f 100644
--- a/source/blender/editors/armature/editarmature_undo.c
+++ b/source/blender/editors/armature/editarmature_undo.c
@@ -244,7 +244,6 @@ static void armature_undosys_foreach_ID_ref(UndoStep *us_p,
}
}
-/* Export for ED_undo_sys. */
void ED_armature_undosys_type(UndoType *ut)
{
ut->name = "Edit Armature";
diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c
index 20d7baa39ed..772fe8f3196 100644
--- a/source/blender/editors/armature/pose_edit.c
+++ b/source/blender/editors/armature/pose_edit.c
@@ -72,9 +72,10 @@
# include "PIL_time_utildefines.h"
#endif
-/* matches logic with ED_operator_posemode_context() */
Object *ED_pose_object_from_context(bContext *C)
{
+ /* NOTE: matches logic with #ED_operator_posemode_context(). */
+
ScrArea *area = CTX_wm_area(C);
Object *ob;
@@ -90,7 +91,6 @@ Object *ED_pose_object_from_context(bContext *C)
return ob;
}
-/* This function is used to process the necessary updates for */
bool ED_object_posemode_enter_ex(struct Main *bmain, Object *ob)
{
BLI_assert(!ID_IS_LINKED(ob));
@@ -195,11 +195,6 @@ static eAnimvizCalcRange pose_path_convert_range(ePosePathCalcRange range)
return ANIMVIZ_CALC_RANGE_FULL;
}
-/* For the object with pose/action: update paths for those that have got them
- * This should selectively update paths that exist...
- *
- * To be called from various tools that do incremental updates
- */
void ED_pose_recalculate_paths(bContext *C, Scene *scene, Object *ob, ePosePathCalcRange range)
{
/* Transform doesn't always have context available to do update. */
diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c
index e5b8983af93..17347aa57fe 100644
--- a/source/blender/editors/armature/pose_select.c
+++ b/source/blender/editors/armature/pose_select.c
@@ -108,7 +108,6 @@ void ED_pose_bone_select_tag_update(Object *ob)
DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
}
-/* Utility method for changing the selection status of a bone */
void ED_pose_bone_select(Object *ob, bPoseChannel *pchan, bool select)
{
bArmature *arm;
@@ -238,10 +237,6 @@ void ED_armature_pose_select_pick_bone(ViewLayer *view_layer,
}
}
-/**
- * Called for mode-less pose selection.
- * assumes the active object is still on old situation.
- */
bool ED_armature_pose_select_pick_with_buffer(ViewLayer *view_layer,
View3D *v3d,
Base *base,
@@ -269,14 +264,6 @@ bool ED_armature_pose_select_pick_with_buffer(ViewLayer *view_layer,
return nearBone != NULL;
}
-/**
- * While in weight-paint mode, a single pose may be active as well.
- * While not common, it's possible we have multiple armatures deforming a mesh.
- *
- * This function de-selects all other objects, and selects the new base.
- * It can't be set to the active object because we need
- * to keep this set to the weight paint object.
- */
void ED_armature_pose_select_in_wpaint_mode(ViewLayer *view_layer, Base *base_select)
{
BLI_assert(base_select && (base_select->object->type == OB_ARMATURE));
@@ -323,9 +310,6 @@ void ED_armature_pose_select_in_wpaint_mode(ViewLayer *view_layer, Base *base_se
}
}
-/* 'select_mode' is usual SEL_SELECT/SEL_DESELECT/SEL_TOGGLE/SEL_INVERT.
- * When true, 'ignore_visibility' makes this func also affect invisible bones
- * (hidden or on hidden layers). */
bool ED_pose_deselect_all(Object *ob, int select_mode, const bool ignore_visibility)
{
bArmature *arm = ob->data;
diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c
index 70d6fa93104..7c52e4fafdd 100644
--- a/source/blender/editors/armature/pose_transform.c
+++ b/source/blender/editors/armature/pose_transform.c
@@ -787,7 +787,7 @@ static int pose_copy_exec(bContext *C, wmOperator *op)
* any datablock expansion?
*/
Main *temp_bmain = BKE_main_new();
- STRNCPY(temp_bmain->name, BKE_main_blendfile_path_from_global());
+ STRNCPY(temp_bmain->filepath, BKE_main_blendfile_path_from_global());
Object ob_copy = *ob;
ob_copy.adt = NULL;
@@ -856,7 +856,7 @@ static int pose_paste_exec(bContext *C, wmOperator *op)
/* Read copy buffer .blend file. */
char str[FILE_MAX];
Main *tmp_bmain = BKE_main_new();
- STRNCPY(tmp_bmain->name, BKE_main_blendfile_path_from_global());
+ STRNCPY(tmp_bmain->filepath, BKE_main_blendfile_path_from_global());
BLI_join_dirfile(str, sizeof(str), BKE_tempdir_base(), "copybuffer_pose.blend");
if (!BKE_copybuffer_read(tmp_bmain, str, op->reports, FILTER_ID_OB)) {
diff --git a/source/blender/editors/armature/pose_utils.c b/source/blender/editors/armature/pose_utils.c
index 500b9663a6c..19a5348dbc0 100644
--- a/source/blender/editors/armature/pose_utils.c
+++ b/source/blender/editors/armature/pose_utils.c
@@ -132,9 +132,6 @@ static void fcurves_to_pchan_links_get(ListBase *pfLinks,
}
}
-/**
- * Returns a valid pose armature for this object, else returns NULL.
- */
Object *poseAnim_object_get(Object *ob_)
{
Object *ob = BKE_object_pose_armature_get(ob_);
@@ -144,9 +141,6 @@ Object *poseAnim_object_get(Object *ob_)
return NULL;
}
-/**
- * Get sets of F-Curves providing transforms for the bones in the Pose.
- */
void poseAnim_mapping_get(bContext *C, ListBase *pfLinks)
{
/* for each Pose-Channel which gets affected, get the F-Curves for that channel
@@ -192,7 +186,6 @@ void poseAnim_mapping_get(bContext *C, ListBase *pfLinks)
}
}
-/* Free F-Curve <-> PoseChannel links. */
void poseAnim_mapping_free(ListBase *pfLinks)
{
tPChanFCurveLink *pfl, *pfln = NULL;
@@ -219,7 +212,6 @@ void poseAnim_mapping_free(ListBase *pfLinks)
/* ------------------------- */
-/* helper for apply() / reset() - refresh the data */
void poseAnim_mapping_refresh(bContext *C, Scene *UNUSED(scene), Object *ob)
{
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
@@ -231,7 +223,6 @@ void poseAnim_mapping_refresh(bContext *C, Scene *UNUSED(scene), Object *ob)
}
}
-/* reset changes made to current pose */
void poseAnim_mapping_reset(ListBase *pfLinks)
{
tPChanFCurveLink *pfl;
@@ -268,7 +259,6 @@ void poseAnim_mapping_reset(ListBase *pfLinks)
}
}
-/* perform auto-key-framing after changes were made + confirmed */
void poseAnim_mapping_autoKeyframe(bContext *C, Scene *scene, ListBase *pfLinks, float cframe)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -337,9 +327,6 @@ void poseAnim_mapping_autoKeyframe(bContext *C, Scene *scene, ListBase *pfLinks,
/* ------------------------- */
-/* find the next F-Curve for a PoseChannel with matching path...
- * - path is not just the pfl rna_path, since that path doesn't have property info yet
- */
LinkData *poseAnim_mapping_getNextFCurve(ListBase *fcuLinks, LinkData *prev, const char *path)
{
LinkData *first = (prev) ? prev->next : (fcuLinks) ? fcuLinks->first : NULL;
diff --git a/source/blender/editors/asset/CMakeLists.txt b/source/blender/editors/asset/CMakeLists.txt
index b9ef8e82bba..2391f4af14d 100644
--- a/source/blender/editors/asset/CMakeLists.txt
+++ b/source/blender/editors/asset/CMakeLists.txt
@@ -24,6 +24,7 @@ set(INC
../../makesdna
../../makesrna
../../windowmanager
+ ../../../../intern/clog
../../../../intern/guardedalloc
)
@@ -34,6 +35,7 @@ set(SRC
intern/asset_catalog.cc
intern/asset_filter.cc
intern/asset_handle.cc
+ intern/asset_indexer.cc
intern/asset_library_reference.cc
intern/asset_library_reference_enum.cc
intern/asset_list.cc
diff --git a/source/blender/editors/asset/ED_asset_catalog.h b/source/blender/editors/asset/ED_asset_catalog.h
index 451ec0d5984..be99de01173 100644
--- a/source/blender/editors/asset/ED_asset_catalog.h
+++ b/source/blender/editors/asset/ED_asset_catalog.h
@@ -16,6 +16,8 @@
/** \file
* \ingroup edasset
+ *
+ * Supplement for `ED_asset_catalog.hh`. Part of the same API but usable in C.
*/
#pragma once
diff --git a/source/blender/editors/asset/ED_asset_catalog.hh b/source/blender/editors/asset/ED_asset_catalog.hh
index 8da8fc0d6c9..d4df15561d0 100644
--- a/source/blender/editors/asset/ED_asset_catalog.hh
+++ b/source/blender/editors/asset/ED_asset_catalog.hh
@@ -16,10 +16,17 @@
/** \file
* \ingroup edasset
+ *
+ * UI/Editor level API for catalog operations, creating richer functionality than the BKE catalog
+ * API provides (which this uses internally).
+ *
+ * Note that `ED_asset_catalog.h` is part of this API.
*/
#pragma once
+#include <optional>
+
#include "BKE_asset_catalog.hh"
#include "BLI_string_ref.hh"
@@ -37,6 +44,18 @@ void ED_asset_catalog_remove(AssetLibrary *library, const blender::bke::CatalogI
void ED_asset_catalog_rename(AssetLibrary *library,
blender::bke::CatalogID catalog_id,
blender::StringRefNull new_name);
-void ED_asset_catalog_move(AssetLibrary *library,
- blender::bke::CatalogID src_catalog_id,
- blender::bke::CatalogID dst_parent_catalog_id);
+/**
+ * Reinsert catalog identified by \a src_catalog_id as child to catalog identified by \a
+ * dst_parent_catalog_id. If \a dst_parent_catalog_id is not set, the catalog is moved to the root
+ * level of the tree.
+ * The name of the reinserted catalog is made unique within the parent. Note that moving a catalog
+ * to the same level it was before will also change its name, since the name uniqueness check isn't
+ * smart enough to ignore the item to be reinserted. So the caller is expected to handle this case
+ * to avoid unwanted renames.
+ *
+ * Nothing is done (debug builds run into an assert) if the given catalog IDs can't be identified.
+ */
+void ED_asset_catalog_move(
+ AssetLibrary *library,
+ blender::bke::CatalogID src_catalog_id,
+ std::optional<blender::bke::CatalogID> dst_parent_catalog_id = std::nullopt);
diff --git a/source/blender/editors/asset/ED_asset_filter.h b/source/blender/editors/asset/ED_asset_filter.h
index 340c4c9dbe7..3b92baea117 100644
--- a/source/blender/editors/asset/ED_asset_filter.h
+++ b/source/blender/editors/asset/ED_asset_filter.h
@@ -16,6 +16,8 @@
/** \file
* \ingroup edasset
+ *
+ * Functions for filtering assets.
*/
#pragma once
@@ -27,6 +29,18 @@ extern "C" {
struct AssetFilterSettings;
struct AssetHandle;
+/**
+ * Compare \a asset against the settings of \a filter.
+ *
+ * Individual filter parameters are ORed with the asset properties. That means:
+ * * The asset type must be one of the ID types filtered by, and
+ * * The asset must contain at least one of the tags filtered by.
+ * However for an asset to be matching it must have one match in each of the parameters. I.e. one
+ * matching type __and__ at least one matching tag.
+ *
+ * \returns True if the asset should be visible with these filter settings (parameters match).
+ * Otherwise returns false (mismatch).
+ */
bool ED_asset_filter_matches_asset(const struct AssetFilterSettings *filter,
const struct AssetHandle *asset);
diff --git a/source/blender/editors/asset/ED_asset_handle.h b/source/blender/editors/asset/ED_asset_handle.h
index efb99410d3d..dce851164a5 100644
--- a/source/blender/editors/asset/ED_asset_handle.h
+++ b/source/blender/editors/asset/ED_asset_handle.h
@@ -16,6 +16,12 @@
/** \file
* \ingroup edasset
+ *
+ * Asset-handle is a temporary design, not part of the core asset system design.
+ *
+ * Currently asset-list items are just file directory items (#FileDirEntry). So an asset-handle
+ * just wraps a pointer to this. We try to abstract away the fact that it's just a file entry,
+ * although that doesn't always work (see #rna_def_asset_handle()).
*/
#pragma once
diff --git a/source/blender/editors/asset/ED_asset_indexer.h b/source/blender/editors/asset/ED_asset_indexer.h
new file mode 100644
index 00000000000..33558d8cda5
--- /dev/null
+++ b/source/blender/editors/asset/ED_asset_indexer.h
@@ -0,0 +1,50 @@
+/*
+ * 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 edasset
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ED_file_indexer.h"
+
+/**
+ * File Indexer Service for indexing asset files.
+ *
+ * Opening and parsing a large collection of asset files inside a library can take a lot of time.
+ * To reduce the time it takes the files are indexed.
+ *
+ * - Index files are created for each blend file in the asset library, even when the blend file
+ * doesn't contain any assets.
+ * - Indexes are stored in an persistent cache folder (`BKE_appdir_folder_caches` +
+ * `asset_library_indexes/{asset_library_dir}/{asset_index_file.json}`).
+ * - The content of the indexes are used when:
+ * - Index exists and can be opened
+ * - Last modification date is earlier than the file it represents.
+ * - The index file version is the latest.
+ * - Blend files without any assets can be determined by the size of the index file for some
+ * additional performance.
+ */
+extern const FileIndexerType file_indexer_asset;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/editors/asset/ED_asset_library.h b/source/blender/editors/asset/ED_asset_library.h
index 905d097d223..62a7d6ffa9b 100644
--- a/source/blender/editors/asset/ED_asset_library.h
+++ b/source/blender/editors/asset/ED_asset_library.h
@@ -26,9 +26,27 @@
extern "C" {
#endif
+/**
+ * Return an index that can be used to uniquely identify \a library, assuming
+ * that all relevant indices were created with this function.
+ */
int ED_asset_library_reference_to_enum_value(const AssetLibraryReference *library);
+/**
+ * Return an asset library reference matching the index returned by
+ * #ED_asset_library_reference_to_enum_value().
+ */
AssetLibraryReference ED_asset_library_reference_from_enum_value(int value);
-const struct EnumPropertyItem *ED_asset_library_reference_to_rna_enum_itemf(void);
+/**
+ * Translate all available asset libraries to an RNA enum, whereby the enum values match the result
+ * of #ED_asset_library_reference_to_enum_value() for any given library.
+ *
+ * Since this is meant for UI display, skips non-displayable libraries, that is, libraries with an
+ * empty name or path.
+ *
+ * \param include_local_library: Whether to include the "Current File" library or not.
+ */
+const struct EnumPropertyItem *ED_asset_library_reference_to_rna_enum_itemf(
+ bool include_local_library);
#ifdef __cplusplus
}
diff --git a/source/blender/editors/asset/ED_asset_list.h b/source/blender/editors/asset/ED_asset_list.h
index 61d7729b651..669bb6dbe36 100644
--- a/source/blender/editors/asset/ED_asset_list.h
+++ b/source/blender/editors/asset/ED_asset_list.h
@@ -31,21 +31,47 @@ struct ID;
struct bContext;
struct wmNotifier;
+/**
+ * Invoke asset list reading, potentially in a parallel job. Won't wait until the job is done,
+ * and may return earlier.
+ */
void ED_assetlist_storage_fetch(const struct AssetLibraryReference *library_reference,
const struct bContext *C);
void ED_assetlist_ensure_previews_job(const struct AssetLibraryReference *library_reference,
struct bContext *C);
void ED_assetlist_clear(const struct AssetLibraryReference *library_reference, struct bContext *C);
bool ED_assetlist_storage_has_list_for_library(const AssetLibraryReference *library_reference);
+/**
+ * Tag all asset lists in the storage that show main data as needing an update (re-fetch).
+ *
+ * This only tags the data. If the asset list is visible on screen, the space is still responsible
+ * for ensuring the necessary redraw. It can use #ED_assetlist_listen() to check if the asset-list
+ * needs a redraw for a given notifier.
+ */
void ED_assetlist_storage_tag_main_data_dirty(void);
+/**
+ * Remapping of ID pointers within the asset lists. Typically called when an ID is deleted to clear
+ * all references to it (\a id_new is null then).
+ */
void ED_assetlist_storage_id_remap(struct ID *id_old, struct ID *id_new);
+/**
+ * Can't wait for static deallocation to run. There's nested data allocated with our guarded
+ * allocator, it will complain about unfreed memory on exit.
+ */
void ED_assetlist_storage_exit(void);
struct ImBuf *ED_assetlist_asset_image_get(const AssetHandle *asset_handle);
const char *ED_assetlist_library_path(const struct AssetLibraryReference *library_reference);
+/**
+ * \return True if the region needs a UI redraw.
+ */
bool ED_assetlist_listen(const struct AssetLibraryReference *library_reference,
const struct wmNotifier *notifier);
+/**
+ * \return The number of assets stored in the asset list for \a library_reference, or -1 if there
+ * is no list fetched for it.
+ */
int ED_assetlist_size(const struct AssetLibraryReference *library_reference);
#ifdef __cplusplus
diff --git a/source/blender/editors/asset/ED_asset_temp_id_consumer.h b/source/blender/editors/asset/ED_asset_temp_id_consumer.h
index 9a47e435612..0848f4225bd 100644
--- a/source/blender/editors/asset/ED_asset_temp_id_consumer.h
+++ b/source/blender/editors/asset/ED_asset_temp_id_consumer.h
@@ -16,6 +16,11 @@
/** \file
* \ingroup edasset
+ *
+ * API to abstract away details for temporary loading of an ID from an asset. If the ID is stored
+ * in the current file (or more precisely, in the #Main given when requesting an ID) no loading is
+ * performed and the ID is returned. Otherwise it's imported for temporary access using the
+ * `BLO_library_temp` API.
*/
#pragma once
diff --git a/source/blender/editors/asset/intern/asset_catalog.cc b/source/blender/editors/asset/intern/asset_catalog.cc
index 9634665be7b..f6c02f86f0a 100644
--- a/source/blender/editors/asset/intern/asset_catalog.cc
+++ b/source/blender/editors/asset/intern/asset_catalog.cc
@@ -122,7 +122,7 @@ void ED_asset_catalog_rename(::AssetLibrary *library,
void ED_asset_catalog_move(::AssetLibrary *library,
const CatalogID src_catalog_id,
- const CatalogID dst_parent_catalog_id)
+ const std::optional<CatalogID> dst_parent_catalog_id)
{
bke::AssetCatalogService *catalog_service = BKE_asset_library_get_catalog_service(library);
if (!catalog_service) {
@@ -131,9 +131,24 @@ void ED_asset_catalog_move(::AssetLibrary *library,
}
AssetCatalog *src_catalog = catalog_service->find_catalog(src_catalog_id);
- AssetCatalog *dst_catalog = catalog_service->find_catalog(dst_parent_catalog_id);
+ if (!src_catalog) {
+ BLI_assert_unreachable();
+ return;
+ }
+ AssetCatalog *dst_catalog = dst_parent_catalog_id ?
+ catalog_service->find_catalog(*dst_parent_catalog_id) :
+ nullptr;
+ if (!dst_catalog && dst_parent_catalog_id) {
+ BLI_assert_unreachable();
+ return;
+ }
- const AssetCatalogPath new_path = dst_catalog->path / StringRef(src_catalog->path.name());
+ std::string unique_name = catalog_name_ensure_unique(
+ *catalog_service, src_catalog->path.name(), dst_catalog ? dst_catalog->path.c_str() : "");
+ /* If a destination catalog was given, construct the path using that. Otherwise, the path is just
+ * the name of the catalog to be moved, which means it ends up at the root level. */
+ const AssetCatalogPath new_path = dst_catalog ? (dst_catalog->path / unique_name) :
+ AssetCatalogPath{unique_name};
const AssetCatalogPath clean_new_path = new_path.cleanup();
if (new_path == src_catalog->path || clean_new_path == src_catalog->path) {
@@ -158,7 +173,7 @@ void ED_asset_catalogs_save_from_main_path(::AssetLibrary *library, const Main *
/* Since writing to disk also means loading any on-disk changes, it may be a good idea to store
* an undo step. */
catalog_service->undo_push();
- catalog_service->write_to_disk(bmain->name);
+ catalog_service->write_to_disk(bmain->filepath);
}
void ED_asset_catalogs_set_save_catalogs_when_file_is_saved(const bool should_save)
diff --git a/source/blender/editors/asset/intern/asset_filter.cc b/source/blender/editors/asset/intern/asset_filter.cc
index c22bbc923eb..70e3e2f55ea 100644
--- a/source/blender/editors/asset/intern/asset_filter.cc
+++ b/source/blender/editors/asset/intern/asset_filter.cc
@@ -27,18 +27,6 @@
#include "ED_asset_filter.h"
#include "ED_asset_handle.h"
-/**
- * Compare \a asset against the settings of \a filter.
- *
- * Individual filter parameters are ORed with the asset properties. That means:
- * * The asset type must be one of the ID types filtered by, and
- * * The asset must contain at least one of the tags filtered by.
- * However for an asset to be matching it must have one match in each of the parameters. I.e. one
- * matching type __and__ at least one matching tag.
- *
- * \returns True if the asset should be visible with these filter settings (parameters match).
- * Otherwise returns false (mismatch).
- */
bool ED_asset_filter_matches_asset(const AssetFilterSettings *filter, const AssetHandle *asset)
{
ID_Type asset_type = ED_asset_handle_get_id_type(asset);
diff --git a/source/blender/editors/asset/intern/asset_handle.cc b/source/blender/editors/asset/intern/asset_handle.cc
index 363bd9226da..a2029d3cc50 100644
--- a/source/blender/editors/asset/intern/asset_handle.cc
+++ b/source/blender/editors/asset/intern/asset_handle.cc
@@ -16,12 +16,6 @@
/** \file
* \ingroup edasset
- *
- * Asset-handle is a temporary design, not part of the core asset system design.
- *
- * Currently asset-list items are just file directory items (#FileDirEntry). So an asset-handle is
- * just wraps a pointer to this. We try to abstract away the fact that it's just a file entry,
- * although that doesn't always work (see #rna_def_asset_handle()).
*/
#include <string>
diff --git a/source/blender/editors/asset/intern/asset_indexer.cc b/source/blender/editors/asset/intern/asset_indexer.cc
new file mode 100644
index 00000000000..4107d28b5e3
--- /dev/null
+++ b/source/blender/editors/asset/intern/asset_indexer.cc
@@ -0,0 +1,781 @@
+/*
+ * 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 edasset
+ */
+
+#include <fstream>
+#include <iomanip>
+#include <optional>
+
+#include "ED_asset_indexer.h"
+
+#include "DNA_asset_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BLI_fileops.h"
+#include "BLI_hash.hh"
+#include "BLI_linklist.h"
+#include "BLI_path_util.h"
+#include "BLI_serialize.hh"
+#include "BLI_set.hh"
+#include "BLI_string_ref.hh"
+#include "BLI_uuid.h"
+
+#include "BKE_appdir.h"
+#include "BKE_asset.h"
+#include "BKE_asset_catalog.hh"
+#include "BKE_preferences.h"
+
+#include "CLG_log.h"
+
+static CLG_LogRef LOG = {"ed.asset"};
+
+namespace blender::ed::asset::index {
+
+using namespace blender::io::serialize;
+using namespace blender::bke;
+
+/**
+ * \file asset_indexer.cc
+ * \brief Indexer for asset libraries.
+ *
+ * Indexes are stored per input file. Each index can contain zero to multiple asset entries.
+ * The indexes are grouped together per asset library. They are stored in
+ * #BKE_appdir_folder_caches +
+ * /asset-library-indices/<asset-library-hash>/<asset-index-hash>_<asset_file>.index.json.
+ *
+ * The structure of an index file is
+ * \code
+ * {
+ * "version": <file version number>,
+ * "entries": [{
+ * "name": "<asset name>",
+ * "catalog_id": "<catalog_id>",
+ * "catalog_name": "<catalog_name>",
+ * "description": "<description>",
+ * "author": "<author>",
+ * "tags": ["<tag>"]
+ * }]
+ * }
+ * \endcode
+ *
+ * NOTE: entries, author, description and tags are optional attributes.
+ *
+ * NOTE: File browser uses name and idcode separate. Inside the index they are joined together like
+ * #ID.name.
+ * NOTE: File browser group name isn't stored in the index as it is a translatable name.
+ */
+constexpr StringRef ATTRIBUTE_VERSION("version");
+constexpr StringRef ATTRIBUTE_ENTRIES("entries");
+constexpr StringRef ATTRIBUTE_ENTRIES_NAME("name");
+constexpr StringRef ATTRIBUTE_ENTRIES_CATALOG_ID("catalog_id");
+constexpr StringRef ATTRIBUTE_ENTRIES_CATALOG_NAME("catalog_name");
+constexpr StringRef ATTRIBUTE_ENTRIES_DESCRIPTION("description");
+constexpr StringRef ATTRIBUTE_ENTRIES_AUTHOR("author");
+constexpr StringRef ATTRIBUTE_ENTRIES_TAGS("tags");
+
+/** Abstract class for #BlendFile and #AssetIndexFile. */
+class AbstractFile {
+ public:
+ virtual ~AbstractFile() = default;
+
+ virtual const char *get_file_path() const = 0;
+
+ bool exists() const
+ {
+ return BLI_exists(get_file_path());
+ }
+
+ size_t get_file_size() const
+ {
+ return BLI_file_size(get_file_path());
+ }
+};
+
+/**
+ * \brief Reference to a blend file that can be indexed.
+ */
+class BlendFile : public AbstractFile {
+ StringRefNull file_path_;
+
+ public:
+ BlendFile(StringRefNull file_path) : file_path_(file_path)
+ {
+ }
+
+ uint64_t hash() const
+ {
+ DefaultHash<StringRefNull> hasher;
+ return hasher(file_path_);
+ }
+
+ std::string get_filename() const
+ {
+ char filename[FILE_MAX];
+ BLI_split_file_part(get_file_path(), filename, sizeof(filename));
+ return std::string(filename);
+ }
+
+ const char *get_file_path() const override
+ {
+ return file_path_.c_str();
+ }
+};
+
+/**
+ * \brief Single entry inside a #AssetIndexFile for reading.
+ */
+struct AssetEntryReader {
+ private:
+ /**
+ * \brief Lookup table containing the elements of the entry.
+ */
+ ObjectValue::Lookup lookup;
+
+ StringRefNull get_name_with_idcode() const
+ {
+ return lookup.lookup(ATTRIBUTE_ENTRIES_NAME)->as_string_value()->value();
+ }
+
+ public:
+ AssetEntryReader(const ObjectValue &entry) : lookup(entry.create_lookup())
+ {
+ }
+
+ ID_Type get_idcode() const
+ {
+ const StringRefNull name_with_idcode = get_name_with_idcode();
+ return GS(name_with_idcode.c_str());
+ }
+
+ StringRef get_name() const
+ {
+ const StringRefNull name_with_idcode = get_name_with_idcode();
+ return name_with_idcode.substr(2);
+ }
+
+ bool has_description() const
+ {
+ return lookup.contains(ATTRIBUTE_ENTRIES_DESCRIPTION);
+ }
+
+ StringRefNull get_description() const
+ {
+ return lookup.lookup(ATTRIBUTE_ENTRIES_DESCRIPTION)->as_string_value()->value();
+ }
+
+ bool has_author() const
+ {
+ return lookup.contains(ATTRIBUTE_ENTRIES_AUTHOR);
+ }
+
+ StringRefNull get_author() const
+ {
+ return lookup.lookup(ATTRIBUTE_ENTRIES_AUTHOR)->as_string_value()->value();
+ }
+
+ StringRefNull get_catalog_name() const
+ {
+ return lookup.lookup(ATTRIBUTE_ENTRIES_CATALOG_NAME)->as_string_value()->value();
+ }
+
+ CatalogID get_catalog_id() const
+ {
+ const std::string &catalog_id =
+ lookup.lookup(ATTRIBUTE_ENTRIES_CATALOG_ID)->as_string_value()->value();
+ CatalogID catalog_uuid(catalog_id);
+ return catalog_uuid;
+ }
+
+ void add_tags_to_meta_data(AssetMetaData *asset_data) const
+ {
+ const ObjectValue::LookupValue *value_ptr = lookup.lookup_ptr(ATTRIBUTE_ENTRIES_TAGS);
+ if (value_ptr == nullptr) {
+ return;
+ }
+
+ const ArrayValue *array_value = (*value_ptr)->as_array_value();
+ const ArrayValue::Items &elements = array_value->elements();
+ for (const ArrayValue::Item &item : elements) {
+ const StringRefNull tag_name = item->as_string_value()->value();
+ BKE_asset_metadata_tag_add(asset_data, tag_name.c_str());
+ }
+ }
+};
+
+struct AssetEntryWriter {
+ private:
+ ObjectValue::Items &attributes;
+
+ public:
+ AssetEntryWriter(ObjectValue &entry) : attributes(entry.elements())
+ {
+ }
+
+ /**
+ * \brief add id + name to the attributes.
+ *
+ * NOTE: id and name are encoded like #ID.name
+ */
+ void add_id_name(const short idcode, const StringRefNull name)
+ {
+ char idcode_prefix[2];
+ /* Similar to `BKE_libblock_alloc`. */
+ *((short *)idcode_prefix) = idcode;
+ std::string name_with_idcode = std::string(idcode_prefix, sizeof(idcode_prefix)) + name;
+
+ attributes.append_as(std::pair(ATTRIBUTE_ENTRIES_NAME, new StringValue(name_with_idcode)));
+ }
+
+ void add_catalog_id(const CatalogID &catalog_id)
+ {
+ char catalog_id_str[UUID_STRING_LEN];
+ BLI_uuid_format(catalog_id_str, catalog_id);
+ attributes.append_as(std::pair(ATTRIBUTE_ENTRIES_CATALOG_ID, new StringValue(catalog_id_str)));
+ }
+
+ void add_catalog_name(const StringRefNull catalog_name)
+ {
+ attributes.append_as(std::pair(ATTRIBUTE_ENTRIES_CATALOG_NAME, new StringValue(catalog_name)));
+ }
+
+ void add_description(const StringRefNull description)
+ {
+ attributes.append_as(std::pair(ATTRIBUTE_ENTRIES_DESCRIPTION, new StringValue(description)));
+ }
+
+ void add_author(const StringRefNull author)
+ {
+ attributes.append_as(std::pair(ATTRIBUTE_ENTRIES_AUTHOR, new StringValue(author)));
+ }
+
+ void add_tags(const ListBase /* AssetTag */ *asset_tags)
+ {
+ ArrayValue *tags = new ArrayValue();
+ attributes.append_as(std::pair(ATTRIBUTE_ENTRIES_TAGS, tags));
+ ArrayValue::Items &tag_items = tags->elements();
+
+ LISTBASE_FOREACH (AssetTag *, tag, asset_tags) {
+ tag_items.append_as(new StringValue(tag->name));
+ }
+ }
+};
+
+static void init_value_from_file_indexer_entry(AssetEntryWriter &result,
+ const FileIndexerEntry *indexer_entry)
+{
+ const BLODataBlockInfo &datablock_info = indexer_entry->datablock_info;
+
+ result.add_id_name(indexer_entry->idcode, datablock_info.name);
+
+ const AssetMetaData &asset_data = *datablock_info.asset_data;
+ result.add_catalog_id(asset_data.catalog_id);
+ result.add_catalog_name(asset_data.catalog_simple_name);
+
+ if (asset_data.description != nullptr) {
+ result.add_description(asset_data.description);
+ }
+ if (asset_data.author != nullptr) {
+ result.add_author(asset_data.author);
+ }
+
+ if (!BLI_listbase_is_empty(&asset_data.tags)) {
+ result.add_tags(&asset_data.tags);
+ }
+
+ /* TODO: asset_data.IDProperties */
+}
+
+static void init_value_from_file_indexer_entries(ObjectValue &result,
+ const FileIndexerEntries &indexer_entries)
+{
+ ArrayValue *entries = new ArrayValue();
+ ArrayValue::Items &items = entries->elements();
+
+ for (LinkNode *ln = indexer_entries.entries; ln; ln = ln->next) {
+ const FileIndexerEntry *indexer_entry = static_cast<const FileIndexerEntry *>(ln->link);
+ /* We also get non asset types (brushes, workspaces), when browsing using the asset browser. */
+ if (indexer_entry->datablock_info.asset_data == nullptr) {
+ continue;
+ }
+ ObjectValue *entry_value = new ObjectValue();
+ AssetEntryWriter entry(*entry_value);
+ init_value_from_file_indexer_entry(entry, indexer_entry);
+ items.append_as(entry_value);
+ }
+
+ /* When no entries to index, we should not store the entries attribute as this would make the
+ * size bigger than the #MIN_FILE_SIZE_WITH_ENTRIES. */
+ if (items.is_empty()) {
+ delete entries;
+ return;
+ }
+
+ ObjectValue::Items &attributes = result.elements();
+ attributes.append_as(std::pair(ATTRIBUTE_ENTRIES, entries));
+}
+
+static void init_indexer_entry_from_value(FileIndexerEntry &indexer_entry,
+ const AssetEntryReader &entry)
+{
+ indexer_entry.idcode = entry.get_idcode();
+
+ const std::string &name = entry.get_name();
+ BLI_strncpy(
+ indexer_entry.datablock_info.name, name.c_str(), sizeof(indexer_entry.datablock_info.name));
+
+ AssetMetaData *asset_data = BKE_asset_metadata_create();
+ indexer_entry.datablock_info.asset_data = asset_data;
+
+ if (entry.has_description()) {
+ const std::string &description = entry.get_description();
+ char *description_c_str = static_cast<char *>(MEM_mallocN(description.length() + 1, __func__));
+ BLI_strncpy(description_c_str, description.c_str(), description.length() + 1);
+ asset_data->description = description_c_str;
+ }
+ if (entry.has_author()) {
+ const std::string &author = entry.get_author();
+ char *author_c_str = static_cast<char *>(MEM_mallocN(author.length() + 1, __func__));
+ BLI_strncpy(author_c_str, author.c_str(), author.length() + 1);
+ asset_data->author = author_c_str;
+ }
+
+ const std::string &catalog_name = entry.get_catalog_name();
+ BLI_strncpy(asset_data->catalog_simple_name,
+ catalog_name.c_str(),
+ sizeof(asset_data->catalog_simple_name));
+
+ asset_data->catalog_id = entry.get_catalog_id();
+
+ entry.add_tags_to_meta_data(asset_data);
+}
+
+static int init_indexer_entries_from_value(FileIndexerEntries &indexer_entries,
+ const ObjectValue &value)
+{
+ const ObjectValue::Lookup attributes = value.create_lookup();
+ const ObjectValue::LookupValue *entries_value = attributes.lookup_ptr(ATTRIBUTE_ENTRIES);
+ BLI_assert(entries_value != nullptr);
+
+ if (entries_value == nullptr) {
+ return 0;
+ }
+
+ int num_entries_read = 0;
+ const ArrayValue::Items elements = (*entries_value)->as_array_value()->elements();
+ for (ArrayValue::Item element : elements) {
+ const AssetEntryReader asset_entry(*element->as_object_value());
+
+ FileIndexerEntry *entry = static_cast<FileIndexerEntry *>(
+ MEM_callocN(sizeof(FileIndexerEntry), __func__));
+ init_indexer_entry_from_value(*entry, asset_entry);
+
+ BLI_linklist_prepend(&indexer_entries.entries, entry);
+ num_entries_read += 1;
+ }
+
+ return num_entries_read;
+}
+
+/**
+ * \brief References the asset library directory.
+ *
+ * The #AssetLibraryIndex instance is used to keep track of unused file indices. When reading any
+ * used indices are removed from the list and when reading is finished the unused
+ * indices are removed.
+ */
+struct AssetLibraryIndex {
+ /**
+ * Tracks indices that haven't been used yet.
+ *
+ * Contains absolute paths to the indices.
+ */
+ Set<std::string> unused_file_indices;
+
+ /**
+ * \brief Absolute path where the indices of `library` are stored.
+ *
+ * \NOTE: includes trailing directory separator.
+ */
+ std::string indices_base_path;
+
+ std::string library_path;
+
+ public:
+ AssetLibraryIndex(const StringRef library_path) : library_path(library_path)
+ {
+ init_indices_base_path();
+ }
+
+ uint64_t hash() const
+ {
+ DefaultHash<StringRefNull> hasher;
+ return hasher(get_library_file_path());
+ }
+
+ StringRefNull get_library_file_path() const
+ {
+ return library_path;
+ }
+
+ /**
+ * \brief Initializes #AssetLibraryIndex.indices_base_path.
+ *
+ * `BKE_appdir_folder_caches/asset-library-indices/<asset-library-name-hash>/`
+ */
+ void init_indices_base_path()
+ {
+ char index_path[FILE_MAX];
+ BKE_appdir_folder_caches(index_path, sizeof(index_path));
+
+ BLI_path_append(index_path, sizeof(index_path), "asset-library-indices");
+
+ std::stringstream ss;
+ ss << std::setfill('0') << std::setw(16) << std::hex << hash() << "/";
+ BLI_path_append(index_path, sizeof(index_path), ss.str().c_str());
+
+ indices_base_path = std::string(index_path);
+ }
+
+ /**
+ * \return absolute path to the index file of the given `asset_file`.
+ *
+ * `{indices_base_path}/{asset-file_hash}_{asset-file-filename}.index.json`.
+ */
+ std::string index_file_path(const BlendFile &asset_file) const
+ {
+ std::stringstream ss;
+ ss << indices_base_path;
+ ss << std::setfill('0') << std::setw(16) << std::hex << asset_file.hash() << "_"
+ << asset_file.get_filename() << ".index.json";
+ return ss.str();
+ }
+
+ /**
+ * Initialize to keep track of unused file indices.
+ */
+ void init_unused_index_files()
+ {
+ const char *index_path = indices_base_path.c_str();
+ if (!BLI_is_dir(index_path)) {
+ return;
+ }
+ struct direntry *dir_entries = nullptr;
+ int num_entries = BLI_filelist_dir_contents(index_path, &dir_entries);
+ for (int i = 0; i < num_entries; i++) {
+ struct direntry *entry = &dir_entries[i];
+ if (BLI_str_endswith(entry->relname, ".index.json")) {
+ unused_file_indices.add_as(std::string(entry->path));
+ }
+ }
+
+ BLI_filelist_free(dir_entries, num_entries);
+ }
+
+ void mark_as_used(const std::string &filename)
+ {
+ unused_file_indices.remove(filename);
+ }
+
+ int remove_unused_index_files() const
+ {
+ int num_files_deleted = 0;
+ for (const std::string &unused_index : unused_file_indices) {
+ const char *file_path = unused_index.c_str();
+ CLOG_INFO(&LOG, 2, "Remove unused index file [%s].", file_path);
+ BLI_delete(file_path, false, false);
+ num_files_deleted++;
+ }
+
+ return num_files_deleted;
+ }
+};
+
+/**
+ * Instance of this class represents the contents of an asset index file.
+ *
+ * \code
+ * {
+ * "version": {version},
+ * "entries": ...
+ * }
+ * \endcode
+ */
+struct AssetIndex {
+ /**
+ * \brief Version to store in new index files.
+ *
+ * Versions are written to each index file. When reading the version is checked against
+ * `CURRENT_VERSION` to make sure we can use the index. Developer should increase
+ * `CURRENT_VERSION` when changes are made to the structure of the stored index.
+ */
+ static const int CURRENT_VERSION = 1;
+
+ /**
+ * Version number to use when version couldn't be read from an index file.
+ */
+ const int UNKNOWN_VERSION = -1;
+
+ /**
+ * `blender::io::serialize::Value` representing the contents of an index file.
+ *
+ * Value is used over #ObjectValue as the contents of the index could be corrupted and doesn't
+ * represent an object. In case corrupted files are detected the `get_version` would return
+ * `UNKNOWN_VERSION`.
+ */
+ std::unique_ptr<Value> contents;
+
+ /**
+ * Constructor for when creating/updating an asset index file.
+ * #AssetIndex.contents are filled from the given \p indexer_entries.
+ */
+ AssetIndex(const FileIndexerEntries &indexer_entries)
+ {
+ std::unique_ptr<ObjectValue> root = std::make_unique<ObjectValue>();
+ ObjectValue::Items &root_attributes = root->elements();
+ root_attributes.append_as(std::pair(ATTRIBUTE_VERSION, new IntValue(CURRENT_VERSION)));
+ init_value_from_file_indexer_entries(*root, indexer_entries);
+
+ contents = std::move(root);
+ }
+
+ /**
+ * Constructor when reading an asset index file.
+ * #AssetIndex.contents are read from the given \p value.
+ */
+ AssetIndex(std::unique_ptr<Value> &value) : contents(std::move(value))
+ {
+ }
+
+ int get_version() const
+ {
+ const ObjectValue *root = contents->as_object_value();
+ if (root == nullptr) {
+ return UNKNOWN_VERSION;
+ }
+ const ObjectValue::Lookup attributes = root->create_lookup();
+ const ObjectValue::LookupValue *version_value = attributes.lookup_ptr(ATTRIBUTE_VERSION);
+ if (version_value == nullptr) {
+ return UNKNOWN_VERSION;
+ }
+ return (*version_value)->as_int_value()->value();
+ }
+
+ bool is_latest_version() const
+ {
+ return get_version() == CURRENT_VERSION;
+ }
+
+ /**
+ * Extract the contents of this index into the given \p indexer_entries.
+ *
+ * \return The number of entries read from the given entries.
+ */
+ int extract_into(FileIndexerEntries &indexer_entries) const
+ {
+ const ObjectValue *root = contents->as_object_value();
+ const int num_entries_read = init_indexer_entries_from_value(indexer_entries, *root);
+ return num_entries_read;
+ }
+};
+
+class AssetIndexFile : public AbstractFile {
+ public:
+ AssetLibraryIndex &library_index;
+ /**
+ * Asset index files with a size smaller than this attribute would be considered to not contain
+ * any entries.
+ */
+ const size_t MIN_FILE_SIZE_WITH_ENTRIES = 32;
+ std::string filename;
+
+ AssetIndexFile(AssetLibraryIndex &library_index, BlendFile &asset_filename)
+ : library_index(library_index), filename(library_index.index_file_path(asset_filename))
+ {
+ }
+
+ void mark_as_used()
+ {
+ library_index.mark_as_used(filename);
+ }
+
+ const char *get_file_path() const override
+ {
+ return filename.c_str();
+ }
+
+ /**
+ * Returns whether the index file is older than the given asset file.
+ */
+ bool is_older_than(BlendFile &asset_file) const
+ {
+ return BLI_file_older(get_file_path(), asset_file.get_file_path());
+ }
+
+ /**
+ * Check whether the index file contains entries without opening the file.
+ */
+ bool constains_entries() const
+ {
+ const size_t file_size = get_file_size();
+ return file_size >= MIN_FILE_SIZE_WITH_ENTRIES;
+ }
+
+ std::unique_ptr<AssetIndex> read_contents() const
+ {
+ JsonFormatter formatter;
+ std::ifstream is;
+ is.open(filename);
+ std::unique_ptr<Value> read_data = formatter.deserialize(is);
+ is.close();
+
+ return std::make_unique<AssetIndex>(read_data);
+ }
+
+ bool ensure_parent_path_exists() const
+ {
+ /* `BLI_make_existing_file` only ensures parent path, otherwise than expected from the name of
+ * the function. */
+ return BLI_make_existing_file(get_file_path());
+ }
+
+ void write_contents(AssetIndex &content)
+ {
+ JsonFormatter formatter;
+ if (!ensure_parent_path_exists()) {
+ CLOG_ERROR(&LOG, "Index not created: couldn't create folder [%s].", get_file_path());
+ return;
+ }
+
+ std::ofstream os;
+ os.open(filename, std::ios::out | std::ios::trunc);
+ formatter.serialize(os, *content.contents);
+ os.close();
+ }
+};
+
+static eFileIndexerResult read_index(const char *filename,
+ FileIndexerEntries *entries,
+ int *r_read_entries_len,
+ void *user_data)
+{
+ AssetLibraryIndex &library_index = *static_cast<AssetLibraryIndex *>(user_data);
+ BlendFile asset_file(filename);
+ AssetIndexFile asset_index_file(library_index, asset_file);
+
+ if (!asset_index_file.exists()) {
+ return FILE_INDEXER_NEEDS_UPDATE;
+ }
+
+ /* Mark index as used, even when it will be recreated. When not done it would remove the index
+ * when the indexing has finished (see `AssetLibraryIndex.remove_unused_index_files`), thereby
+ * removing the newly created index.
+ */
+ asset_index_file.mark_as_used();
+
+ if (asset_index_file.is_older_than(asset_file)) {
+ CLOG_INFO(
+ &LOG,
+ 3,
+ "Asset index file [%s] needs to be refreshed as it is older than the asset file [%s].",
+ asset_index_file.filename.c_str(),
+ filename);
+ return FILE_INDEXER_NEEDS_UPDATE;
+ }
+
+ if (!asset_index_file.constains_entries()) {
+ CLOG_INFO(&LOG,
+ 3,
+ "Asset file index is to small to contain any entries. [%s]",
+ asset_index_file.filename.c_str());
+ *r_read_entries_len = 0;
+ return FILE_INDEXER_ENTRIES_LOADED;
+ }
+
+ std::unique_ptr<AssetIndex> contents = asset_index_file.read_contents();
+ if (!contents->is_latest_version()) {
+ CLOG_INFO(&LOG,
+ 3,
+ "Asset file index is ignored; expected version %d but file is version %d [%s].",
+ AssetIndex::CURRENT_VERSION,
+ contents->get_version(),
+ asset_index_file.filename.c_str());
+ return FILE_INDEXER_NEEDS_UPDATE;
+ }
+
+ const int read_entries_len = contents->extract_into(*entries);
+ CLOG_INFO(&LOG, 1, "Read %d entries from asset index for [%s].", read_entries_len, filename);
+ *r_read_entries_len = read_entries_len;
+
+ return FILE_INDEXER_ENTRIES_LOADED;
+}
+
+static void update_index(const char *filename, FileIndexerEntries *entries, void *user_data)
+{
+ AssetLibraryIndex &library_index = *static_cast<AssetLibraryIndex *>(user_data);
+ BlendFile asset_file(filename);
+ AssetIndexFile asset_index_file(library_index, asset_file);
+ CLOG_INFO(&LOG,
+ 1,
+ "Update asset index for [%s] store index in [%s].",
+ asset_file.get_file_path(),
+ asset_index_file.get_file_path());
+
+ AssetIndex content(*entries);
+ asset_index_file.write_contents(content);
+}
+
+static void *init_user_data(const char *root_directory, size_t root_directory_maxlen)
+{
+ AssetLibraryIndex *library_index = OBJECT_GUARDED_NEW(
+ AssetLibraryIndex,
+ StringRef(root_directory, BLI_strnlen(root_directory, root_directory_maxlen)));
+ library_index->init_unused_index_files();
+ return library_index;
+}
+
+static void free_user_data(void *user_data)
+{
+ OBJECT_GUARDED_DELETE(user_data, AssetLibraryIndex);
+}
+
+static void filelist_finished(void *user_data)
+{
+ AssetLibraryIndex &library_index = *static_cast<AssetLibraryIndex *>(user_data);
+ const int num_indices_removed = library_index.remove_unused_index_files();
+ if (num_indices_removed > 0) {
+ CLOG_INFO(&LOG, 1, "Removed %d unused indices.", num_indices_removed);
+ }
+}
+
+constexpr FileIndexerType asset_indexer()
+{
+ FileIndexerType indexer = {nullptr};
+ indexer.read_index = read_index;
+ indexer.update_index = update_index;
+ indexer.init_user_data = init_user_data;
+ indexer.free_user_data = free_user_data;
+ indexer.filelist_finished = filelist_finished;
+ return indexer;
+}
+
+} // namespace blender::ed::asset::index
+
+extern "C" {
+const FileIndexerType file_indexer_asset = blender::ed::asset::index::asset_indexer();
+}
diff --git a/source/blender/editors/asset/intern/asset_library_reference_enum.cc b/source/blender/editors/asset/intern/asset_library_reference_enum.cc
index 1a2d3f5837a..05526f222a5 100644
--- a/source/blender/editors/asset/intern/asset_library_reference_enum.cc
+++ b/source/blender/editors/asset/intern/asset_library_reference_enum.cc
@@ -35,10 +35,6 @@
#include "ED_asset_library.h"
-/**
- * Return an index that can be used to uniquely identify \a library, assuming
- * that all relevant indices were created with this function.
- */
int ED_asset_library_reference_to_enum_value(const AssetLibraryReference *library)
{
/* Simple case: Predefined repository, just set the value. */
@@ -57,10 +53,6 @@ int ED_asset_library_reference_to_enum_value(const AssetLibraryReference *librar
return ASSET_LIBRARY_LOCAL;
}
-/**
- * Return an asset library reference matching the index returned by
- * #ED_asset_library_reference_to_enum_value().
- */
AssetLibraryReference ED_asset_library_reference_from_enum_value(int value)
{
AssetLibraryReference library;
@@ -92,31 +84,27 @@ AssetLibraryReference ED_asset_library_reference_from_enum_value(int value)
return library;
}
-/**
- * Translate all available asset libraries to an RNA enum, whereby the enum values match the result
- * of #ED_asset_library_reference_to_enum_value() for any given library.
- *
- * Since this is meant for UI display, skips non-displayable libraries, that is, libraries with an
- * empty name or path.
- */
-const EnumPropertyItem *ED_asset_library_reference_to_rna_enum_itemf()
+const EnumPropertyItem *ED_asset_library_reference_to_rna_enum_itemf(
+ const bool include_local_library)
{
- const EnumPropertyItem predefined_items[] = {
- /* For the future. */
- // {ASSET_REPO_BUNDLED, "BUNDLED", 0, "Bundled", "Show the default user assets"},
- {ASSET_LIBRARY_LOCAL,
- "LOCAL",
- ICON_BLENDER,
- "Current File",
- "Show the assets currently available in this Blender session"},
- {0, nullptr, 0, nullptr, nullptr},
- };
-
EnumPropertyItem *item = nullptr;
int totitem = 0;
- /* Add predefined items. */
- RNA_enum_items_add(&item, &totitem, predefined_items);
+ if (include_local_library) {
+ const EnumPropertyItem predefined_items[] = {
+ /* For the future. */
+ // {ASSET_REPO_BUNDLED, "BUNDLED", 0, "Bundled", "Show the default user assets"},
+ {ASSET_LIBRARY_LOCAL,
+ "LOCAL",
+ ICON_CURRENT_FILE,
+ "Current File",
+ "Show the assets currently available in this Blender session"},
+ {0, nullptr, 0, nullptr, nullptr},
+ };
+
+ /* Add predefined items. */
+ RNA_enum_items_add(&item, &totitem, predefined_items);
+ }
/* Add separator if needed. */
if (!BLI_listbase_is_empty(&U.asset_libraries)) {
diff --git a/source/blender/editors/asset/intern/asset_list.cc b/source/blender/editors/asset/intern/asset_list.cc
index c1b1e33d428..1bfdd83b8e3 100644
--- a/source/blender/editors/asset/intern/asset_list.cc
+++ b/source/blender/editors/asset/intern/asset_list.cc
@@ -44,10 +44,15 @@
#include "../space_file/filelist.h"
#include "ED_asset_handle.h"
+#include "ED_asset_indexer.h"
#include "ED_asset_list.h"
#include "ED_asset_list.hh"
#include "asset_library_reference.hh"
+/* Enable asset indexing. Currently disabled as ID properties aren't indexed yet and is needed for
+ * object snapping. See {D12990}. */
+//#define SPACE_FILE_ENABLE_ASSET_INDEXING
+
namespace blender::ed::asset {
/* -------------------------------------------------------------------- */
@@ -169,6 +174,10 @@ void AssetList::setup()
"",
"");
+#ifdef SPACE_FILE_ENABLE_ASSET_INDEXING
+ filelist_setindexer(files, &file_indexer_asset);
+#endif
+
char path[FILE_MAXDIR] = "";
if (user_library) {
BLI_strncpy(path, user_library->path, sizeof(path));
@@ -309,6 +318,7 @@ StringRef AssetList::filepath() const
{
return filelist_dir(filelist_);
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -425,10 +435,6 @@ AssetListStorage::AssetListMap &AssetListStorage::global_storage()
using namespace blender::ed::asset;
-/**
- * Invoke asset list reading, potentially in a parallel job. Won't wait until the job is done,
- * and may return earlier.
- */
void ED_assetlist_storage_fetch(const AssetLibraryReference *library_reference, const bContext *C)
{
AssetListStorage::fetch_library(*library_reference, *C);
@@ -523,9 +529,6 @@ const char *ED_assetlist_library_path(const AssetLibraryReference *library_refer
return nullptr;
}
-/**
- * \return True if the region needs a UI redraw.
- */
bool ED_assetlist_listen(const AssetLibraryReference *library_reference,
const wmNotifier *notifier)
{
@@ -536,10 +539,6 @@ bool ED_assetlist_listen(const AssetLibraryReference *library_reference,
return false;
}
-/**
- * \return The number of assets stored in the asset list for \a library_reference, or -1 if there
- * is no list fetched for it.
- */
int ED_assetlist_size(const AssetLibraryReference *library_reference)
{
AssetList *list = AssetListStorage::lookup_list(*library_reference);
@@ -549,31 +548,16 @@ int ED_assetlist_size(const AssetLibraryReference *library_reference)
return -1;
}
-/**
- * Tag all asset lists in the storage that show main data as needing an update (re-fetch).
- *
- * This only tags the data. If the asset list is visible on screen, the space is still responsible
- * for ensuring the necessary redraw. It can use #ED_assetlist_listen() to check if the asset-list
- * needs a redraw for a given notifier.
- */
void ED_assetlist_storage_tag_main_data_dirty()
{
AssetListStorage::tagMainDataDirty();
}
-/**
- * Remapping of ID pointers within the asset lists. Typically called when an ID is deleted to clear
- * all references to it (\a id_new is null then).
- */
void ED_assetlist_storage_id_remap(ID *id_old, ID *id_new)
{
AssetListStorage::remapID(id_old, id_new);
}
-/**
- * Can't wait for static deallocation to run. There's nested data allocated with our guarded
- * allocator, it will complain about unfreed memory on exit.
- */
void ED_assetlist_storage_exit()
{
AssetListStorage::destruct();
diff --git a/source/blender/editors/asset/intern/asset_ops.cc b/source/blender/editors/asset/intern/asset_ops.cc
index f7c567c89f6..e4edff19a21 100644
--- a/source/blender/editors/asset/intern/asset_ops.cc
+++ b/source/blender/editors/asset/intern/asset_ops.cc
@@ -19,12 +19,23 @@
*/
#include "BKE_asset_library.hh"
+#include "BKE_bpath.h"
#include "BKE_context.h"
+#include "BKE_global.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
+#include "BKE_preferences.h"
#include "BKE_report.h"
+#include "BLI_fileops.h"
+#include "BLI_fnmatch.h"
+#include "BLI_path_util.h"
+#include "BLI_set.hh"
+
#include "ED_asset.h"
+#include "ED_asset_catalog.hh"
+#include "ED_screen.h"
+#include "ED_util.h"
/* XXX needs access to the file list, should all be done via the asset system in future. */
#include "ED_fileselect.h"
@@ -33,6 +44,10 @@
#include "WM_api.h"
+#include "DNA_space_types.h"
+
+#include "BLO_writefile.h"
+
using namespace blender;
/* -------------------------------------------------------------------- */
@@ -377,8 +392,14 @@ static void ASSET_OT_clear(wmOperatorType *ot)
/* -------------------------------------------------------------------- */
-static bool asset_list_refresh_poll(bContext *C)
+static bool asset_library_refresh_poll(bContext *C)
{
+ if (ED_operator_asset_browsing_active(C)) {
+ return true;
+ }
+
+ /* While not inside an Asset Browser, check if there's a asset list stored for the active asset
+ * library (stored in the workspace, obtained via context). */
const AssetLibraryReference *library = CTX_wm_asset_library_ref(C);
if (!library) {
return false;
@@ -387,23 +408,38 @@ static bool asset_list_refresh_poll(bContext *C)
return ED_assetlist_storage_has_list_for_library(library);
}
-static int asset_list_refresh_exec(bContext *C, wmOperator *UNUSED(unused))
+static int asset_library_refresh_exec(bContext *C, wmOperator *UNUSED(unused))
{
- const AssetLibraryReference *library = CTX_wm_asset_library_ref(C);
- ED_assetlist_clear(library, C);
+ /* Execution mode #1: Inside the Asset Browser. */
+ if (ED_operator_asset_browsing_active(C)) {
+ SpaceFile *sfile = CTX_wm_space_file(C);
+ ED_fileselect_clear(CTX_wm_manager(C), sfile);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, nullptr);
+ }
+ else {
+ /* Execution mode #2: Outside the Asset Browser, use the asset list. */
+ const AssetLibraryReference *library = CTX_wm_asset_library_ref(C);
+ ED_assetlist_clear(library, C);
+ }
+
return OPERATOR_FINISHED;
}
-static void ASSET_OT_list_refresh(struct wmOperatorType *ot)
+/**
+ * This operator currently covers both cases, the File/Asset Browser file list and the asset list
+ * used for the asset-view template. Once the asset list design is used by the Asset Browser, this
+ * can be simplified to just that case.
+ */
+static void ASSET_OT_library_refresh(struct wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Refresh Asset List";
- ot->description = "Trigger a reread of the assets";
- ot->idname = "ASSET_OT_list_refresh";
+ ot->name = "Refresh Asset Library";
+ ot->description = "Reread assets and asset catalogs from the asset library on disk";
+ ot->idname = "ASSET_OT_library_refresh";
/* api callbacks */
- ot->exec = asset_list_refresh_exec;
- ot->poll = asset_list_refresh_poll;
+ ot->exec = asset_library_refresh_exec;
+ ot->poll = asset_library_refresh_poll;
}
/* -------------------------------------------------------------------- */
@@ -601,7 +637,7 @@ static bool asset_catalogs_save_poll(bContext *C)
}
const Main *bmain = CTX_data_main(C);
- if (!bmain->name[0]) {
+ if (!bmain->filepath[0]) {
CTX_wm_operator_poll_msg_set(C, "Cannot save asset catalogs before the Blender file is saved");
return false;
}
@@ -643,7 +679,274 @@ static void ASSET_OT_catalogs_save(struct wmOperatorType *ot)
/* -------------------------------------------------------------------- */
-void ED_operatortypes_asset(void)
+static bool could_be_asset_bundle(const Main *bmain);
+static const bUserAssetLibrary *selected_asset_library(struct wmOperator *op);
+static bool is_contained_in_selected_asset_library(struct wmOperator *op, const char *filepath);
+static bool set_filepath_for_asset_lib(const Main *bmain, struct wmOperator *op);
+static bool has_external_files(Main *bmain, struct ReportList *reports);
+
+static bool asset_bundle_install_poll(bContext *C)
+{
+ /* This operator only works when the asset browser is set to Current File. */
+ const SpaceFile *sfile = CTX_wm_space_file(C);
+ if (sfile == nullptr) {
+ return false;
+ }
+ if (!ED_fileselect_is_local_asset_library(sfile)) {
+ return false;
+ }
+
+ const Main *bmain = CTX_data_main(C);
+ if (!could_be_asset_bundle(bmain)) {
+ return false;
+ }
+
+ /* Check whether this file is already located inside any asset library. */
+ const struct bUserAssetLibrary *asset_lib = BKE_preferences_asset_library_containing_path(
+ &U, bmain->filepath);
+ if (asset_lib) {
+ return false;
+ }
+
+ return true;
+}
+
+static int asset_bundle_install_invoke(struct bContext *C,
+ struct wmOperator *op,
+ const struct wmEvent * /*event*/)
+{
+ Main *bmain = CTX_data_main(C);
+ if (has_external_files(bmain, op->reports)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ WM_event_add_fileselect(C, op);
+
+ /* Make the "Save As" dialog box default to "${ASSET_LIB_ROOT}/${CURRENT_FILE}.blend". */
+ if (!set_filepath_for_asset_lib(bmain, op)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int asset_bundle_install_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ if (has_external_files(bmain, op->reports)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Check file path, copied from #wm_file_write(). */
+ char filepath[PATH_MAX];
+ RNA_string_get(op->ptr, "filepath", filepath);
+ const size_t len = strlen(filepath);
+
+ if (len == 0) {
+ BKE_report(op->reports, RPT_ERROR, "Path is empty, cannot save");
+ return OPERATOR_CANCELLED;
+ }
+
+ if (len >= FILE_MAX) {
+ BKE_report(op->reports, RPT_ERROR, "Path too long, cannot save");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Check that the destination is actually contained in the selected asset library. */
+ if (!is_contained_in_selected_asset_library(op, filepath)) {
+ BKE_reportf(op->reports, RPT_ERROR, "Selected path is outside of the selected asset library");
+ return OPERATOR_CANCELLED;
+ }
+
+ WM_cursor_wait(true);
+ bke::AssetCatalogService *cat_service = get_catalog_service(C);
+ /* Store undo step, such that on a failed save the 'prepare_to_merge_on_write' call can be
+ * un-done. */
+ cat_service->undo_push();
+ cat_service->prepare_to_merge_on_write();
+
+ const int operator_result = WM_operator_name_call(
+ C, "WM_OT_save_mainfile", WM_OP_EXEC_DEFAULT, op->ptr);
+ WM_cursor_wait(false);
+
+ if (operator_result != OPERATOR_FINISHED) {
+ cat_service->undo();
+ return operator_result;
+ }
+
+ const bUserAssetLibrary *lib = selected_asset_library(op);
+ BLI_assert_msg(lib, "If the asset library is not known, how did we get here?");
+ BKE_reportf(op->reports,
+ RPT_INFO,
+ R"(Saved "%s" to asset library "%s")",
+ BLI_path_basename(bmain->filepath),
+ lib->name);
+ return OPERATOR_FINISHED;
+}
+
+static const EnumPropertyItem *rna_asset_library_reference_itemf(bContext *UNUSED(C),
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
+{
+ const EnumPropertyItem *items = ED_asset_library_reference_to_rna_enum_itemf(false);
+ if (!items) {
+ *r_free = false;
+ }
+
+ *r_free = true;
+ return items;
+}
+
+static void ASSET_OT_bundle_install(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Copy to Asset Library";
+ ot->description =
+ "Copy the current .blend file into an Asset Library. Only works on standalone .blend files "
+ "(i.e. when no other files are referenced)";
+ ot->idname = "ASSET_OT_bundle_install";
+
+ /* api callbacks */
+ ot->exec = asset_bundle_install_exec;
+ ot->invoke = asset_bundle_install_invoke;
+ ot->poll = asset_bundle_install_poll;
+
+ ot->prop = RNA_def_property(ot->srna, "asset_library_ref", PROP_ENUM, PROP_NONE);
+ RNA_def_property_flag(ot->prop, PROP_HIDDEN);
+ RNA_def_enum_funcs(ot->prop, rna_asset_library_reference_itemf);
+
+ WM_operator_properties_filesel(ot,
+ FILE_TYPE_FOLDER | FILE_TYPE_BLENDER,
+ FILE_BLENDER,
+ FILE_SAVE,
+ WM_FILESEL_FILEPATH,
+ FILE_DEFAULTDISPLAY,
+ FILE_SORT_DEFAULT);
+}
+
+/* Cheap check to see if this is an "asset bundle" just by checking main file name.
+ * A proper check will be done in the exec function, to ensure that no external files will be
+ * referenced. */
+static bool could_be_asset_bundle(const Main *bmain)
+{
+ return fnmatch("*_bundle.blend", bmain->filepath, FNM_CASEFOLD) == 0;
+}
+
+static const bUserAssetLibrary *selected_asset_library(struct wmOperator *op)
+{
+ const int enum_value = RNA_enum_get(op->ptr, "asset_library_ref");
+ const AssetLibraryReference lib_ref = ED_asset_library_reference_from_enum_value(enum_value);
+ const bUserAssetLibrary *lib = BKE_preferences_asset_library_find_from_index(
+ &U, lib_ref.custom_library_index);
+ return lib;
+}
+
+static bool is_contained_in_selected_asset_library(struct wmOperator *op, const char *filepath)
+{
+ const bUserAssetLibrary *lib = selected_asset_library(op);
+ if (!lib) {
+ return false;
+ }
+ return BLI_path_contains(lib->path, filepath);
+}
+
+/**
+ * Set the "filepath" RNA property based on selected "asset_library_ref".
+ * \return true if ok, false if error.
+ */
+static bool set_filepath_for_asset_lib(const Main *bmain, struct wmOperator *op)
+{
+ /* Find the directory path of the selected asset library. */
+ const bUserAssetLibrary *lib = selected_asset_library(op);
+ if (lib == nullptr) {
+ return false;
+ }
+
+ /* Concatenate the filename of the current blend file. */
+ const char *blend_filename = BLI_path_basename(bmain->filepath);
+ if (blend_filename == nullptr || blend_filename[0] == '\0') {
+ return false;
+ }
+
+ char file_path[PATH_MAX];
+ BLI_join_dirfile(file_path, sizeof(file_path), lib->path, blend_filename);
+ RNA_string_set(op->ptr, "filepath", file_path);
+
+ return true;
+}
+
+struct FileCheckCallbackInfo {
+ struct ReportList *reports;
+ Set<std::string> external_files;
+};
+
+static bool external_file_check_callback(BPathForeachPathData *bpath_data,
+ char * /*path_dst*/,
+ const char *path_src)
+{
+ FileCheckCallbackInfo *callback_info = static_cast<FileCheckCallbackInfo *>(
+ bpath_data->user_data);
+ callback_info->external_files.add(std::string(path_src));
+ return false;
+}
+
+/**
+ * Do a check on any external files (.blend, textures, etc.) being used.
+ * The ASSET_OT_bundle_install operator only works on standalone .blend files
+ * (catalog definition files are fine, though).
+ *
+ * \return true when there are external files, false otherwise.
+ */
+static bool has_external_files(Main *bmain, struct ReportList *reports)
+{
+ struct FileCheckCallbackInfo callback_info = {reports, Set<std::string>()};
+
+ eBPathForeachFlag flag = static_cast<eBPathForeachFlag>(
+ BKE_BPATH_FOREACH_PATH_SKIP_PACKED /* Packed files are fine. */
+ | BKE_BPATH_FOREACH_PATH_SKIP_MULTIFILE /* Only report multi-files once, it's enough. */
+ | BKE_BPATH_TRAVERSE_SKIP_WEAK_REFERENCES); /* Only care about actually used files. */
+
+ BPathForeachPathData bpath_data = {
+ /* bmain */ bmain,
+ /* callback_function */ &external_file_check_callback,
+ /* flag */ flag,
+ /* user_data */ &callback_info,
+ /* absolute_base_path */ nullptr,
+ };
+ BKE_bpath_foreach_path_main(&bpath_data);
+
+ if (callback_info.external_files.is_empty()) {
+ /* No external dependencies. */
+ return false;
+ }
+
+ if (callback_info.external_files.size() == 1) {
+ /* Only one external dependency, report it directly. */
+ BKE_reportf(callback_info.reports,
+ RPT_ERROR,
+ "Unable to copy bundle due to external dependency: \"%s\"",
+ callback_info.external_files.begin()->c_str());
+ return true;
+ }
+
+ /* Multiple external dependencies, report the aggregate and put details on console. */
+ BKE_reportf(
+ callback_info.reports,
+ RPT_ERROR,
+ "Unable to copy bundle due to %ld external dependencies; more details on the console",
+ callback_info.external_files.size());
+ printf("Unable to copy bundle due to %ld external dependencies:\n",
+ callback_info.external_files.size());
+ for (const std::string &path : callback_info.external_files) {
+ printf(" \"%s\"\n", path.c_str());
+ }
+ return true;
+}
+
+/* -------------------------------------------------------------------- */
+
+void ED_operatortypes_asset()
{
WM_operatortype_append(ASSET_OT_mark);
WM_operatortype_append(ASSET_OT_clear);
@@ -654,6 +957,7 @@ void ED_operatortypes_asset(void)
WM_operatortype_append(ASSET_OT_catalog_undo);
WM_operatortype_append(ASSET_OT_catalog_redo);
WM_operatortype_append(ASSET_OT_catalog_undo_push);
+ WM_operatortype_append(ASSET_OT_bundle_install);
- WM_operatortype_append(ASSET_OT_list_refresh);
+ WM_operatortype_append(ASSET_OT_library_refresh);
}
diff --git a/source/blender/editors/curve/curve_intern.h b/source/blender/editors/curve/curve_intern.h
index 8ecf41162e9..03ddeebde42 100644
--- a/source/blender/editors/curve/curve_intern.h
+++ b/source/blender/editors/curve/curve_intern.h
@@ -71,7 +71,13 @@ typedef enum eCurveElem_Types {
} eCurveElem_Types;
/* internal select utils */
+/**
+ * Returns 1 in case (de)selection was successful.
+ */
bool select_beztriple(BezTriple *bezt, bool selstatus, uint8_t flag, eVisible_Types hidden);
+/**
+ * Returns 1 in case (de)selection was successful.
+ */
bool select_bpoint(BPoint *bp, bool selstatus, uint8_t flag, bool hidden);
void FONT_OT_text_insert(struct wmOperatorType *ot);
@@ -146,7 +152,14 @@ void ed_editnurb_translate_flag(struct ListBase *editnurb,
uint8_t flag,
const float vec[3],
bool is_2d);
+/**
+ * Only for #OB_SURF.
+ */
bool ed_editnurb_extrude_flag(struct EditNurb *editnurb, const uint8_t flag);
+/**
+ * \param axis: is in world-space.
+ * \param cent: is in object-space.
+ */
bool ed_editnurb_spin(float viewmat[4][4],
struct View3D *v3d,
struct Object *obedit,
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index 3b05975d22d..a034e4bb10e 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -1074,7 +1074,6 @@ static void curve_rename_fcurves(Curve *cu, ListBase *orig_curves)
}
}
-/* return 0 if animation data wasn't changed, 1 otherwise */
int ED_curve_updateAnimPaths(Main *bmain, Curve *cu)
{
AnimData *adt = BKE_animdata_from_id(&cu->id);
@@ -1247,7 +1246,6 @@ static void remap_hooks_and_vertex_parents(Main *bmain, Object *obedit)
}
}
-/* load editNurb in object */
void ED_curve_editnurb_load(Main *bmain, Object *obedit)
{
ListBase *editnurb = object_editcurve_get(obedit);
@@ -1285,7 +1283,6 @@ void ED_curve_editnurb_load(Main *bmain, Object *obedit)
}
}
-/* make copy in cu->editnurb */
void ED_curve_editnurb_make(Object *obedit)
{
Curve *cu = (Curve *)obedit->data;
@@ -1991,7 +1988,6 @@ static void ed_curve_delete_selected(Object *obedit, View3D *v3d)
}
}
-/* only for OB_SURF */
bool ed_editnurb_extrude_flag(EditNurb *editnurb, const uint8_t flag)
{
BPoint *bp, *bpn, *newbp;
@@ -3859,11 +3855,6 @@ static int set_spline_type_exec(bContext *C, wmOperator *op)
const bool use_handles = RNA_boolean_get(op->ptr, "use_handles");
const int type = RNA_enum_get(op->ptr, "type");
- if (ELEM(type, CU_CARDINAL, CU_BSPLINE)) {
- BKE_report(op->reports, RPT_ERROR, "Not yet implemented");
- continue;
- }
-
LISTBASE_FOREACH (Nurb *, nu, editnurb) {
if (ED_curve_nurb_select_check(v3d, nu)) {
const int pntsu_prev = nu->pntsu;
@@ -3907,8 +3898,6 @@ void CURVE_OT_spline_type_set(wmOperatorType *ot)
static const EnumPropertyItem type_items[] = {
{CU_POLY, "POLY", 0, "Poly", ""},
{CU_BEZIER, "BEZIER", 0, "Bezier", ""},
- // {CU_CARDINAL, "CARDINAL", 0, "Cardinal", ""},
- // {CU_BSPLINE, "B_SPLINE", 0, "B-Spline", ""},
{CU_NURBS, "NURBS", 0, "NURBS", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -4909,10 +4898,6 @@ bool ED_curve_editnurb_select_pick(
/** \name Spin Operator
* \{ */
-/**
- * \param axis: is in world-space.
- * \param cent: is in object-space.
- */
bool ed_editnurb_spin(
float viewmat[4][4], View3D *v3d, Object *obedit, const float axis[3], const float cent[3])
{
@@ -6804,10 +6789,6 @@ void CURVE_OT_shade_flat(wmOperatorType *ot)
/** \name Join Operator
* \{ */
-/**
- * This is used externally, by #OBJECT_OT_join.
- * TODO: shape keys - as with meshes.
- */
int ED_curve_join_objects_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -6856,9 +6837,9 @@ int ED_curve_join_objects_exec(bContext *C, wmOperator *op)
/* Compensate for different bevel depth. */
bool do_radius = false;
float compensate_radius = 0.0f;
- if (cu->ext2 != 0.0f && cu_active->ext2 != 0.0f) {
+ if (cu->bevel_radius != 0.0f && cu_active->bevel_radius != 0.0f) {
float compensate_scale = mat4_to_scale(cmat);
- compensate_radius = cu->ext2 / cu_active->ext2 * compensate_scale;
+ compensate_radius = cu->bevel_radius / cu_active->bevel_radius * compensate_scale;
do_radius = true;
}
diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c
index 784f67ac4f1..403ace56e3b 100644
--- a/source/blender/editors/curve/editcurve_paint.c
+++ b/source/blender/editors/curve/editcurve_paint.c
@@ -144,7 +144,7 @@ static float stroke_elem_radius_from_pressure(const struct CurveDrawData *cdd,
const float pressure)
{
const Curve *cu = cdd->vc.obedit->data;
- return ((pressure * cdd->radius.range) + cdd->radius.min) * cu->ext2;
+ return ((pressure * cdd->radius.range) + cdd->radius.min) * cu->bevel_radius;
}
static float stroke_elem_radius(const struct CurveDrawData *cdd, const struct StrokeElem *selem)
@@ -364,7 +364,7 @@ static void curve_draw_stroke_3d(const struct bContext *UNUSED(C),
Object *obedit = cdd->vc.obedit;
Curve *cu = obedit->data;
- if (cu->ext2 > 0.0f) {
+ if (cu->bevel_radius > 0.0f) {
BLI_mempool_iter iter;
const struct StrokeElem *selem;
diff --git a/source/blender/editors/curve/editcurve_select.c b/source/blender/editors/curve/editcurve_select.c
index a76e73d3cf1..1229b7eacc8 100644
--- a/source/blender/editors/curve/editcurve_select.c
+++ b/source/blender/editors/curve/editcurve_select.c
@@ -60,7 +60,6 @@
/** \name Utilities
* \{ */
-/* returns 1 in case (de)selection was successful */
bool select_beztriple(BezTriple *bezt, bool selstatus, uint8_t flag, eVisible_Types hidden)
{
if ((bezt->hide == 0) || (hidden == HIDDEN)) {
@@ -80,7 +79,6 @@ bool select_beztriple(BezTriple *bezt, bool selstatus, uint8_t flag, eVisible_Ty
return false;
}
-/* returns 1 in case (de)selection was successful */
bool select_bpoint(BPoint *bp, bool selstatus, uint8_t flag, bool hidden)
{
if ((bp->hide == 0) || (hidden == 1)) {
diff --git a/source/blender/editors/curve/editcurve_undo.c b/source/blender/editors/curve/editcurve_undo.c
index 210411c6eb5..5619e2efc36 100644
--- a/source/blender/editors/curve/editcurve_undo.c
+++ b/source/blender/editors/curve/editcurve_undo.c
@@ -305,7 +305,6 @@ static void curve_undosys_foreach_ID_ref(UndoStep *us_p,
}
}
-/* Export for ED_undo_sys. */
void ED_curve_undosys_type(UndoType *ut)
{
ut->name = "Edit Curve";
diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c
index 6f18798bd2a..6e0aeb87318 100644
--- a/source/blender/editors/curve/editfont.c
+++ b/source/blender/editors/curve/editfont.c
@@ -71,8 +71,6 @@
static int kill_selection(Object *obedit, int ins);
-/** \} */
-
/* -------------------------------------------------------------------- */
/** \name Internal Utilities
* \{ */
@@ -2199,9 +2197,6 @@ void FONT_OT_unlink(wmOperatorType *ot)
ot->exec = font_unlink_exec;
}
-/**
- * TextBox selection
- */
bool ED_curve_editfont_select_pick(
bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
{
diff --git a/source/blender/editors/curve/editfont_undo.c b/source/blender/editors/curve/editfont_undo.c
index 21a6564edf4..45448f18675 100644
--- a/source/blender/editors/curve/editfont_undo.c
+++ b/source/blender/editors/curve/editfont_undo.c
@@ -405,7 +405,6 @@ static void font_undosys_foreach_ID_ref(UndoStep *us_p,
foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->obedit_ref));
}
-/* Export for ED_undo_sys. */
void ED_font_undosys_type(UndoType *ut)
{
ut->name = "Edit Font";
diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt
index 702fd2e375a..8d32eba1766 100644
--- a/source/blender/editors/datafiles/CMakeLists.txt
+++ b/source/blender/editors/datafiles/CMakeLists.txt
@@ -619,6 +619,7 @@ set(ICON_NAMES
outliner_ob_volume
outliner_data_volume
volume_data
+ current_file
home
documents
temp
diff --git a/source/blender/editors/gizmo_library/gizmo_draw_utils.c b/source/blender/editors/gizmo_library/gizmo_draw_utils.c
index 2ec287a62e9..1179c9140e2 100644
--- a/source/blender/editors/gizmo_library/gizmo_draw_utils.c
+++ b/source/blender/editors/gizmo_library/gizmo_draw_utils.c
@@ -44,9 +44,6 @@
/* own includes */
#include "gizmo_library_intern.h"
-/**
- * Main draw call for GizmoGeomInfo data
- */
void wm_gizmo_geometryinfo_draw(const GizmoGeomInfo *info,
const bool UNUSED(select),
const float color[4])
diff --git a/source/blender/editors/gizmo_library/gizmo_library_intern.h b/source/blender/editors/gizmo_library/gizmo_library_intern.h
index f3670708543..a75a6b9a6ef 100644
--- a/source/blender/editors/gizmo_library/gizmo_library_intern.h
+++ b/source/blender/editors/gizmo_library/gizmo_library_intern.h
@@ -78,6 +78,10 @@ void gizmo_property_value_reset(bContext *C,
void gizmo_color_get(const struct wmGizmo *gz, const bool highlight, float r_color[4]);
+/**
+ * Takes mouse coordinates and returns them in relation to the gizmo.
+ * Both 2D & 3D supported, use so we can use 2D gizmos in the 3D view.
+ */
bool gizmo_window_project_2d(bContext *C,
const struct wmGizmo *gz,
const float mval[2],
@@ -93,6 +97,9 @@ bool gizmo_window_project_3d(
#include "gizmo_geometry.h"
+/**
+ * Main draw call for #GizmoGeomInfo data
+ */
void wm_gizmo_geometryinfo_draw(const struct GizmoGeomInfo *info,
const bool select,
const float color[4]);
diff --git a/source/blender/editors/gizmo_library/gizmo_library_utils.c b/source/blender/editors/gizmo_library/gizmo_library_utils.c
index a0db2a8e627..0237c6062d1 100644
--- a/source/blender/editors/gizmo_library/gizmo_library_utils.c
+++ b/source/blender/editors/gizmo_library/gizmo_library_utils.c
@@ -175,10 +175,6 @@ void gizmo_color_get(const wmGizmo *gz, const bool highlight, float r_col[4])
/* -------------------------------------------------------------------- */
-/**
- * Takes mouse coordinates and returns them in relation to the gizmo.
- * Both 2D & 3D supported, use so we can use 2D gizmos in the 3D view.
- */
bool gizmo_window_project_2d(bContext *C,
const struct wmGizmo *gz,
const float mval[2],
diff --git a/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c
index d506af4450a..3362cf9732e 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c
@@ -448,11 +448,6 @@ static void gizmo_arrow_exit(bContext *C, wmGizmo *gz, const bool cancel)
/** \name Arrow Gizmo API
* \{ */
-/**
- * Define a custom property UI range
- *
- * \note Needs to be called before WM_gizmo_target_property_def_rna!
- */
void ED_gizmo_arrow3d_set_ui_range(wmGizmo *gz, const float min, const float max)
{
ArrowGizmo3D *arrow = (ArrowGizmo3D *)gz;
@@ -467,11 +462,6 @@ void ED_gizmo_arrow3d_set_ui_range(wmGizmo *gz, const float min, const float max
arrow->data.is_custom_range_set = true;
}
-/**
- * Define a custom factor for arrow min/max distance
- *
- * \note Needs to be called before WM_gizmo_target_property_def_rna!
- */
void ED_gizmo_arrow3d_set_range_fac(wmGizmo *gz, const float range_fac)
{
ArrowGizmo3D *arrow = (ArrowGizmo3D *)gz;
diff --git a/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c
index f286d3930e2..553ea4bbb6e 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c
@@ -59,6 +59,10 @@
#include "../gizmo_geometry.h"
#include "../gizmo_library_intern.h"
+/* -------------------------------------------------------------------- */
+/** \name Internal Types
+ * \{ */
+
typedef struct ButtonGizmo2D {
wmGizmo gizmo;
bool is_init;
@@ -69,7 +73,11 @@ typedef struct ButtonGizmo2D {
#define CIRCLE_RESOLUTION 32
+/** \} */
+
/* -------------------------------------------------------------------- */
+/** \name Internal API
+ * \{ */
static void button2d_geom_draw_backdrop(const wmGizmo *gz,
const float color[4],
diff --git a/source/blender/editors/gpencil/annotate_draw.c b/source/blender/editors/gpencil/annotate_draw.c
index 7795eed7c21..3705ea38e11 100644
--- a/source/blender/editors/gpencil/annotate_draw.c
+++ b/source/blender/editors/gpencil/annotate_draw.c
@@ -788,7 +788,6 @@ static void annotation_draw_data_all(Scene *scene,
/* ----- Annotation Sketches Drawing API ------ */
-/* draw grease-pencil sketches to specified 2d-view that uses ibuf corrections */
void ED_annotation_draw_2dimage(const bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -857,13 +856,6 @@ void ED_annotation_draw_2dimage(const bContext *C)
annotation_draw_data_all(scene, gpd, offsx, offsy, sizex, sizey, CFRA, dflag, area->spacetype);
}
-/**
- * Draw grease-pencil sketches to specified 2d-view
- * assuming that matrices are already set correctly.
- *
- * \note This gets called twice - first time with onlyv2d=true to draw 'canvas' strokes,
- * second time with onlyv2d=false for screen-aligned strokes.
- */
void ED_annotation_draw_view2d(const bContext *C, bool onlyv2d)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -900,9 +892,6 @@ void ED_annotation_draw_view2d(const bContext *C, bool onlyv2d)
scene, gpd, 0, 0, region->winx, region->winy, CFRA, dflag, area->spacetype);
}
-/* draw annotations sketches to specified 3d-view assuming that matrices are already set
- * correctly NOTE: this gets called twice - first time with only3d=true to draw 3d-strokes,
- * second time with only3d=false for screen-aligned strokes */
void ED_annotation_draw_view3d(
Scene *scene, struct Depsgraph *depsgraph, View3D *v3d, ARegion *region, bool only3d)
{
diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c
index bf53241a947..fbc44ed58d8 100644
--- a/source/blender/editors/gpencil/annotate_paint.c
+++ b/source/blender/editors/gpencil/annotate_paint.c
@@ -78,6 +78,8 @@
/* ******************************************* */
/* 'Globals' and Defines */
+#define DEPTH_INVALID 1.0f
+
/* values for tGPsdata->status */
typedef enum eGPencil_PaintStatus {
GP_STATUS_IDLING = 0, /* stroke isn't in progress yet */
@@ -324,6 +326,9 @@ static void annotation_stroke_convertcoords(tGPsdata *p,
float *depth)
{
bGPdata *gpd = p->gpd;
+ if (depth && (*depth == DEPTH_INVALID)) {
+ depth = NULL;
+ }
/* in 3d-space - pt->x/y/z are 3 side-by-side floats */
if (gpd->runtime.sbuffer_sflag & GP_STROKE_3DSPACE) {
@@ -1003,14 +1008,14 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p)
int last_valid = 0;
for (i = 0; i < gpd->runtime.sbuffer_used; i++) {
- if (depth_arr[i] != FLT_MAX) {
+ if (depth_arr[i] != DEPTH_INVALID) {
break;
}
}
first_valid = i;
for (i = gpd->runtime.sbuffer_used - 1; i >= 0; i--) {
- if (depth_arr[i] != FLT_MAX) {
+ if (depth_arr[i] != DEPTH_INVALID) {
break;
}
}
@@ -1018,14 +1023,14 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p)
/* invalidate non-endpoints, so only blend between first and last */
for (i = first_valid + 1; i < last_valid; i++) {
- depth_arr[i] = FLT_MAX;
+ depth_arr[i] = DEPTH_INVALID;
}
interp_depth = true;
}
if (interp_depth) {
- interp_sparse_array(depth_arr, gpd->runtime.sbuffer_used, FLT_MAX);
+ interp_sparse_array(depth_arr, gpd->runtime.sbuffer_used, DEPTH_INVALID);
}
}
}
@@ -1661,6 +1666,7 @@ static void annotation_paint_initstroke(tGPsdata *p,
static void annotation_paint_strokeend(tGPsdata *p)
{
ToolSettings *ts = p->scene->toolsettings;
+ const bool is_eraser = (p->gpd->runtime.sbuffer_sflag & GP_STROKE_ERASER) != 0;
/* for surface sketching, need to set the right OpenGL context stuff so that
* the conversions will project the values correctly...
*/
@@ -1676,11 +1682,11 @@ static void annotation_paint_strokeend(tGPsdata *p)
(ts->annotate_v3d_align & GP_PROJECT_DEPTH_STROKE) ?
V3D_DEPTH_GPENCIL_ONLY :
V3D_DEPTH_NO_GPENCIL,
- NULL);
+ is_eraser ? NULL : &p->depths);
}
/* check if doing eraser or not */
- if ((p->gpd->runtime.sbuffer_sflag & GP_STROKE_ERASER) == 0) {
+ if (!is_eraser) {
/* transfer stroke to frame */
annotation_stroke_newfrombuffer(p);
}
diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c
index 2160aaf705f..6f63529298c 100644
--- a/source/blender/editors/gpencil/drawgpencil.c
+++ b/source/blender/editors/gpencil/drawgpencil.c
@@ -412,7 +412,6 @@ static void gpencil_draw_strokes(tGPDdraw *tgpw)
/* ----- General Drawing ------ */
-/* wrapper to draw strokes for filling operator */
void ED_gpencil_draw_fill(tGPDdraw *tgpw)
{
gpencil_draw_strokes(tgpw);
diff --git a/source/blender/editors/gpencil/editaction_gpencil.c b/source/blender/editors/gpencil/editaction_gpencil.c
index fbdb7c8e520..046b3088360 100644
--- a/source/blender/editors/gpencil/editaction_gpencil.c
+++ b/source/blender/editors/gpencil/editaction_gpencil.c
@@ -55,7 +55,6 @@
/* ***************************************** */
/* Generics - Loopers */
-/* Loops over the gp-frames for a gp-layer, and applies the given callback */
bool ED_gpencil_layer_frames_looper(bGPDlayer *gpl,
Scene *scene,
bool (*gpf_cb)(bGPDframe *, Scene *))
@@ -80,7 +79,6 @@ bool ED_gpencil_layer_frames_looper(bGPDlayer *gpl,
/* ****************************************** */
/* Data Conversion Tools */
-/* make a listing all the gp-frames in a layer as cfraelems */
void ED_gpencil_layer_make_cfra_list(bGPDlayer *gpl, ListBase *elems, bool onlysel)
{
CfraElem *ce;
@@ -106,7 +104,6 @@ void ED_gpencil_layer_make_cfra_list(bGPDlayer *gpl, ListBase *elems, bool onlys
/* ***************************************** */
/* Selection Tools */
-/* check if one of the frames in this layer is selected */
bool ED_gpencil_layer_frame_select_check(const bGPDlayer *gpl)
{
/* error checking */
@@ -145,7 +142,6 @@ static void gpencil_frame_select(bGPDframe *gpf, short select_mode)
}
}
-/* set all/none/invert select (like above, but with SELECT_* modes) */
void ED_gpencil_select_frames(bGPDlayer *gpl, short select_mode)
{
/* error checking */
@@ -159,7 +155,6 @@ void ED_gpencil_select_frames(bGPDlayer *gpl, short select_mode)
}
}
-/* set all/none/invert select */
void ED_gpencil_layer_frame_select_set(bGPDlayer *gpl, short mode)
{
/* error checking */
@@ -171,7 +166,6 @@ void ED_gpencil_layer_frame_select_set(bGPDlayer *gpl, short mode)
ED_gpencil_select_frames(gpl, mode);
}
-/* select the frame in this layer that occurs on this frame (there should only be one at most) */
void ED_gpencil_select_frame(bGPDlayer *gpl, int selx, short select_mode)
{
bGPDframe *gpf;
@@ -187,7 +181,6 @@ void ED_gpencil_select_frame(bGPDlayer *gpl, int selx, short select_mode)
}
}
-/* select the frames in this layer that occur within the bounds specified */
void ED_gpencil_layer_frames_select_box(bGPDlayer *gpl, float min, float max, short select_mode)
{
if (gpl == NULL) {
@@ -202,7 +195,6 @@ void ED_gpencil_layer_frames_select_box(bGPDlayer *gpl, float min, float max, sh
}
}
-/* select the frames in this layer that occur within the lasso/circle region specified */
void ED_gpencil_layer_frames_select_region(KeyframeEditData *ked,
bGPDlayer *gpl,
short tool,
@@ -239,7 +231,6 @@ void ED_gpencil_layer_frames_select_region(KeyframeEditData *ked,
/* ***************************************** */
/* Frame Editing Tools */
-/* Delete selected frames */
bool ED_gpencil_layer_frames_delete(bGPDlayer *gpl)
{
bool changed = false;
@@ -260,7 +251,6 @@ bool ED_gpencil_layer_frames_delete(bGPDlayer *gpl)
return changed;
}
-/* Duplicate selected frames from given gp-layer */
void ED_gpencil_layer_frames_duplicate(bGPDlayer *gpl)
{
/* error checking */
@@ -284,11 +274,6 @@ void ED_gpencil_layer_frames_duplicate(bGPDlayer *gpl)
}
}
-/**
- * Set keyframe type for selected frames from given gp-layer
- *
- * \param type: The type of keyframe (#eBezTriple_KeyframeType) to set selected frames to.
- */
void ED_gpencil_layer_frames_keytype_set(bGPDlayer *gpl, short type)
{
if (gpl == NULL) {
@@ -320,7 +305,6 @@ static int gpencil_anim_copy_firstframe = 999999999;
static int gpencil_anim_copy_lastframe = -999999999;
static int gpencil_anim_copy_cfra = 0;
-/* This function frees any MEM_calloc'ed copy/paste buffer data */
void ED_gpencil_anim_copybuf_free(void)
{
BKE_gpencil_free_layers(&gpencil_anim_copybuf);
@@ -331,11 +315,6 @@ void ED_gpencil_anim_copybuf_free(void)
gpencil_anim_copy_cfra = 0;
}
-/* This function adds data to the copy/paste buffer, freeing existing data first
- * Only the selected GP-layers get their selected keyframes copied.
- *
- * Returns whether the copy operation was successful or not
- */
bool ED_gpencil_anim_copybuf_copy(bAnimContext *ac)
{
ListBase anim_data = {NULL, NULL};
@@ -404,7 +383,6 @@ bool ED_gpencil_anim_copybuf_copy(bAnimContext *ac)
return true;
}
-/* Pastes keyframes from buffer, and reports success */
bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode)
{
ListBase anim_data = {NULL, NULL};
@@ -547,7 +525,6 @@ static bool gpencil_frame_snap_nearmarker(bGPDframe *gpf, Scene *scene)
return false;
}
-/* snap selected frames to ... */
void ED_gpencil_layer_snap_frames(bGPDlayer *gpl, Scene *scene, short mode)
{
switch (mode) {
@@ -648,8 +625,6 @@ static bool gpencil_frame_mirror_marker(bGPDframe *gpf, Scene *scene)
return false;
}
-/* mirror selected gp-frames on... */
-/* TODO: mirror over a specific time */
void ED_gpencil_layer_mirror_frames(bGPDlayer *gpl, Scene *scene, short mode)
{
switch (mode) {
diff --git a/source/blender/editors/gpencil/gpencil_add_blank.c b/source/blender/editors/gpencil/gpencil_add_blank.c
index 3aa16e54597..4e4650e575c 100644
--- a/source/blender/editors/gpencil/gpencil_add_blank.c
+++ b/source/blender/editors/gpencil/gpencil_add_blank.c
@@ -76,7 +76,6 @@ static const ColorTemplate gp_stroke_material_black = {
/* ***************************************************************** */
/* Blank API */
-/* Add a Simple empty object with one layer and one color. */
void ED_gpencil_create_blank(bContext *C, Object *ob, float UNUSED(mat[4][4]))
{
Main *bmain = CTX_data_main(C);
diff --git a/source/blender/editors/gpencil/gpencil_add_lineart.c b/source/blender/editors/gpencil/gpencil_add_lineart.c
index ac0da0ad1db..aad2d978bfb 100644
--- a/source/blender/editors/gpencil/gpencil_add_lineart.c
+++ b/source/blender/editors/gpencil/gpencil_add_lineart.c
@@ -83,7 +83,6 @@ static const ColorTemplate gp_stroke_material_black = {
/* ***************************************************************** */
/* LineArt API */
-/* Add a Simple LineArt setup. */
void ED_gpencil_create_lineart(bContext *C, Object *ob)
{
Main *bmain = CTX_data_main(C);
diff --git a/source/blender/editors/gpencil/gpencil_add_monkey.c b/source/blender/editors/gpencil/gpencil_add_monkey.c
index 8d60ef3ed12..3b952dbe7da 100644
--- a/source/blender/editors/gpencil/gpencil_add_monkey.c
+++ b/source/blender/editors/gpencil/gpencil_add_monkey.c
@@ -39,13 +39,6 @@
#include "ED_gpencil.h"
-/**
- * Populate stroke with point data from data buffers.
- * \param gps: Grease pencil stroke
- * \param array: Flat array of point data values. Each entry has #GP_PRIM_DATABUF_SIZE values.
- * \param totpoints: Total of points
- * \param mat: 4x4 transform matrix to transform points into the right coordinate space.
- */
void ED_gpencil_stroke_init_data(bGPDstroke *gps,
const float *array,
const int totpoints,
@@ -842,7 +835,6 @@ static const ColorTemplate gp_monkey_pct_pupils = {
/* ***************************************************************** */
/* Monkey API */
-/* add a 2D Suzanne (original model created by Matias Mendiola) */
void ED_gpencil_create_monkey(bContext *C, Object *ob, float mat[4][4])
{
Main *bmain = CTX_data_main(C);
diff --git a/source/blender/editors/gpencil/gpencil_add_stroke.c b/source/blender/editors/gpencil/gpencil_add_stroke.c
index 73c4e64dd9a..d9e652392b4 100644
--- a/source/blender/editors/gpencil/gpencil_add_stroke.c
+++ b/source/blender/editors/gpencil/gpencil_add_stroke.c
@@ -204,8 +204,6 @@ static const ColorTemplate gp_stroke_material_grey = {
/* ***************************************************************** */
/* Stroke API */
-/* Add a Simple stroke with colors
- * (original design created by Daniel M. Lara and Matias Mendiola). */
void ED_gpencil_create_stroke(bContext *C, Object *ob, float mat[4][4])
{
Main *bmain = CTX_data_main(C);
diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c
index 656fec565df..bf414851aed 100644
--- a/source/blender/editors/gpencil/gpencil_convert.c
+++ b/source/blender/editors/gpencil/gpencil_convert.c
@@ -1324,7 +1324,7 @@ static void gpencil_layer_to_curve(bContext *C,
cu->flag |= CU_3D;
cu->bevresol = gtd->bevel_resolution;
- cu->ext2 = gtd->bevel_depth;
+ cu->bevel_radius = gtd->bevel_depth;
gtd->inittime = ((bGPDstroke *)gpf->strokes.first)->inittime;
diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c
index db2104dfdf9..bea8126cfcc 100644
--- a/source/blender/editors/gpencil/gpencil_data.c
+++ b/source/blender/editors/gpencil/gpencil_data.c
@@ -2809,7 +2809,6 @@ static void gpencil_joined_fix_animdata_cb(ID *id, FCurve *fcu, void *user_data)
}
}
-/* join objects called from OBJECT_OT_join */
int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -3697,7 +3696,6 @@ void GPENCIL_OT_materials_copy_to_object(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
-/* Parent GPencil object to Lattice */
bool ED_gpencil_add_lattice_modifier(const bContext *C,
ReportList *reports,
Object *ob,
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index 3fc08096ab5..2a656ac3aad 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -51,6 +51,7 @@
#include "BKE_brush.h"
#include "BKE_context.h"
+#include "BKE_deform.h"
#include "BKE_global.h"
#include "BKE_gpencil.h"
#include "BKE_gpencil_curve.h"
@@ -1381,11 +1382,6 @@ void GPENCIL_OT_extrude(wmOperatorType *ot)
* from several different layers into a single layer.
* \{ */
-/**
- * list of #bGPDstroke instances
- *
- * \note is exposed within the editors/gpencil module so that other tools can use it too.
- */
ListBase gpencil_strokes_copypastebuf = {NULL, NULL};
/* Hash for hanging on to all the colors used by strokes in the buffer
@@ -1429,7 +1425,6 @@ static void gpencil_strokes_copypastebuf_colors_name_to_material_free(GHash *nam
BLI_ghash_free(name_to_ma, MEM_freeN, NULL);
}
-/* Free copy/paste buffer data */
void ED_gpencil_strokes_copybuf_free(void)
{
bGPDstroke *gps, *gpsn;
@@ -1462,10 +1457,6 @@ void ED_gpencil_strokes_copybuf_free(void)
gpencil_strokes_copypastebuf.first = gpencil_strokes_copypastebuf.last = NULL;
}
-/**
- * Ensure that destination datablock has all the colors the pasted strokes need.
- * Helper function for copy-pasting strokes
- */
GHash *gpencil_copybuf_validate_colormap(bContext *C)
{
Main *bmain = CTX_data_main(C);
@@ -2654,7 +2645,6 @@ static int gpencil_delete_selected_points(bContext *C)
return OPERATOR_CANCELLED;
}
-/* simple wrapper to external call */
int gpencil_delete_selected_point_wrap(bContext *C)
{
return gpencil_delete_selected_points(C);
@@ -3319,10 +3309,6 @@ static bool gpencil_cyclical_set_curve_edit_poll_property(const bContext *C,
return true;
}
-/**
- * Similar to #CURVE_OT_cyclic_toggle or #MASK_OT_cyclic_toggle, but with
- * option to force opened/closed strokes instead of just toggle behavior.
- */
void GPENCIL_OT_stroke_cyclical_set(wmOperatorType *ot)
{
PropertyRNA *prop;
@@ -3434,9 +3420,6 @@ static int gpencil_stroke_caps_set_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-/**
- * Change Stroke caps mode Rounded or Flat
- */
void GPENCIL_OT_stroke_caps_set(wmOperatorType *ot)
{
static const EnumPropertyItem toggle_type[] = {
@@ -3966,7 +3949,7 @@ static void gpencil_smooth_stroke(bContext *C, wmOperator *op)
/* perform smoothing */
if (smooth_position) {
- BKE_gpencil_stroke_smooth_point(gps, i, factor);
+ BKE_gpencil_stroke_smooth_point(gps, i, factor, false);
}
if (smooth_strength) {
BKE_gpencil_stroke_smooth_strength(gps, i, factor);
@@ -4587,6 +4570,9 @@ static int gpencil_stroke_separate_exec(bContext *C, wmOperator *op)
id_us_min(ob_dst->data);
ob_dst->data = (bGPdata *)gpd_dst;
+ BKE_defgroup_copy_list(&gpd_dst->vertex_group_names, &gpd_src->vertex_group_names);
+ gpd_dst->vertex_group_active_index = gpd_src->vertex_group_active_index;
+
/* Loop old data-block and separate parts. */
if (ELEM(mode, GP_SEPARATE_POINT, GP_SEPARATE_STROKE)) {
CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
@@ -5351,6 +5337,7 @@ void GPENCIL_OT_stroke_merge_by_distance(wmOperatorType *ot)
ot->srna, "use_unselected", 0, "Unselected", "Use whole stroke, not only selected points");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/editors/gpencil/gpencil_edit_curve.c b/source/blender/editors/gpencil/gpencil_edit_curve.c
index e766a410889..2d7497357f2 100644
--- a/source/blender/editors/gpencil/gpencil_edit_curve.c
+++ b/source/blender/editors/gpencil/gpencil_edit_curve.c
@@ -51,6 +51,10 @@
#include "gpencil_intern.h"
+/* -------------------------------------------------------------------- */
+/** \name Enter Edit-Mode
+ * \{ */
+
/* Poll callback for checking if there is an active layer and we are in curve edit mode. */
static bool gpencil_curve_edit_mode_poll(bContext *C)
{
@@ -135,6 +139,12 @@ void GPENCIL_OT_stroke_enter_editcurve_mode(wmOperatorType *ot)
RNA_def_property_ui_range(prop, FLT_MIN, 10.0f, 0.1f, 5);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Set Handle Type
+ * \{ */
+
static int gpencil_editcurve_set_handle_type_exec(bContext *C, wmOperator *op)
{
Object *ob = CTX_data_active_object(C);
diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c
index 9860c75f290..c3af28d4382 100644
--- a/source/blender/editors/gpencil/gpencil_fill.c
+++ b/source/blender/editors/gpencil/gpencil_fill.c
@@ -1415,7 +1415,7 @@ static void gpencil_get_depth_array(tGPDfill *tgpf)
}
else {
if (interp_depth) {
- interp_sparse_array(tgpf->depth_arr, totpoints, FLT_MAX);
+ interp_sparse_array(tgpf->depth_arr, totpoints, DEPTH_INVALID);
}
}
}
@@ -1570,7 +1570,7 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf)
float smoothfac = 1.0f;
for (int r = 0; r < 1; r++) {
for (int i = 0; i < gps->totpoints; i++) {
- BKE_gpencil_stroke_smooth_point(gps, i, smoothfac - reduce);
+ BKE_gpencil_stroke_smooth_point(gps, i, smoothfac - reduce, false);
}
reduce += 0.25f; /* reduce the factor */
}
diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h
index 3f3fd4fff39..601780ea651 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -27,6 +27,8 @@
#include "ED_numinput.h"
+#define DEPTH_INVALID 1.0f
+
/* internal exports only */
struct Material;
struct bGPDspoint;
@@ -104,6 +106,10 @@ typedef struct tGPDdraw {
} tGPDdraw;
/* Modal Operator Drawing Callbacks ------------------------ */
+
+/**
+ * Wrapper to draw strokes for filling operator.
+ */
void ED_gpencil_draw_fill(struct tGPDdraw *tgpw);
/* ***************************************************** */
@@ -229,28 +235,74 @@ typedef struct tGPDprimitive {
} tGPDprimitive;
+/**
+ * Check whether a given stroke segment is inside a circular brush
+ *
+ * \param mval: The current screen-space coordinates (midpoint) of the brush
+ * \param rad: The radius of the brush
+ *
+ * \param x0, y0: The screen-space x and y coordinates of the start of the stroke segment
+ * \param x1, y1: The screen-space x and y coordinates of the end of the stroke segment
+ */
bool gpencil_stroke_inside_circle(const float mval[2], int rad, int x0, int y0, int x1, int y1);
+/**
+ * Init settings for stroke point space conversions
+ *
+ * \param r_gsc: [out] The space conversion settings struct, populated with necessary params
+ */
void gpencil_point_conversion_init(struct bContext *C, GP_SpaceConversion *r_gsc);
+/**
+ * Convert a Grease Pencil coordinate (i.e. can be 2D or 3D) to screen-space (2D)
+ *
+ * \param[out] r_x: The screen-space x-coordinate of the point
+ * \param[out] r_y: The screen-space y-coordinate of the point
+ *
+ * \warning This assumes that the caller has already checked
+ * whether the stroke in question can be drawn.
+ */
void gpencil_point_to_xy(const GP_SpaceConversion *gsc,
const struct bGPDstroke *gps,
const struct bGPDspoint *pt,
int *r_x,
int *r_y);
+/**
+ * Convert a Grease Pencil coordinate (i.e. can be 2D or 3D) to screen-space (2D).
+ *
+ * Just like #gpencil_point_to_xy(), except the resulting coordinates are floats not ints.
+ * Use this version to solve "stair-step" artifacts which may arise when
+ * round-tripping the calculations.
+ *
+ * \param r_x: The screen-space x-coordinate of the point.
+ * \param r_y: The screen-space y-coordinate of the point.
+ *
+ * \warning This assumes that the caller has already checked
+ * whether the stroke in question can be drawn.
+ */
void gpencil_point_to_xy_fl(const GP_SpaceConversion *gsc,
const bGPDstroke *gps,
const bGPDspoint *pt,
float *r_x,
float *r_y);
+/**
+ * Convert point to parent space
+ *
+ * \param pt: Original point
+ * \param diff_mat: Matrix with the difference between original parent matrix
+ * \param[out] r_pt: Pointer to new point after apply matrix
+ */
void gpencil_point_to_parent_space(const bGPDspoint *pt,
const float diff_mat[4][4],
bGPDspoint *r_pt);
/**
* Change points position relative to parent object
*/
+/**
+ * Change position relative to parent object
+ */
void gpencil_apply_parent(struct Depsgraph *depsgraph,
struct Object *obact,
bGPDlayer *gpl,
@@ -258,61 +310,127 @@ void gpencil_apply_parent(struct Depsgraph *depsgraph,
/**
* Change point position relative to parent object
*/
+/**
+ * Change point position relative to parent object
+ */
void gpencil_apply_parent_point(struct Depsgraph *depsgraph,
struct Object *obact,
bGPDlayer *gpl,
bGPDspoint *pt);
+/**
+ * generic based on gpencil_point_to_xy_fl
+ */
void gpencil_point_3d_to_xy(const GP_SpaceConversion *gsc,
const short flag,
const float pt[3],
float xy[2]);
+/**
+ * Project screen-space coordinates to 3D-space
+ *
+ * For use with editing tools where it is easier to perform the operations in 2D,
+ * and then later convert the transformed points back to 3D.
+ *
+ * \param screen_co: The screen-space 2D coordinates to convert to
+ * \param r_out: The resulting 3D coordinates of the input point
+ *
+ * \note We include this as a utility function, since the standard method
+ * involves quite a few steps, which are invariably always the same
+ * for all GPencil operations. So, it's nicer to just centralize these.
+ *
+ * \warning Assumes that it is getting called in a 3D view only.
+ */
bool gpencil_point_xy_to_3d(const GP_SpaceConversion *gsc,
struct Scene *scene,
const float screen_co[2],
float r_out[3]);
/* helper to convert 2d to 3d */
+
+/**
+ * Convert #tGPspoint (temporary 2D/screen-space point data used by GP modal operators)
+ * to 3D coordinates.
+ *
+ * \param point2D: The screen-space 2D point data to convert.
+ * \param depth: Depth array (via #ED_view3d_depth_read_cached()).
+ * \param r_out: The resulting 2D point data.
+ */
void gpencil_stroke_convertcoords_tpoint(struct Scene *scene,
struct ARegion *region,
struct Object *ob,
const struct tGPspoint *point2D,
float *depth,
- float out[3]);
+ float r_out[3]);
/* Poll Callbacks ------------------------------------ */
/* gpencil_utils.c */
+/**
+ * Poll callback for adding data/layers - special.
+ */
bool gpencil_add_poll(struct bContext *C);
+/**
+ * Poll callback for checking if there is an active layer.
+ */
bool gpencil_active_layer_poll(struct bContext *C);
+/**
+ * Poll callback for checking if there is an active brush.
+ */
bool gpencil_active_brush_poll(struct bContext *C);
bool gpencil_brush_create_presets_poll(bContext *C);
/* Copy/Paste Buffer --------------------------------- */
/* gpencil_edit.c */
+/**
+ * list of #bGPDstroke instances
+ *
+ * \note is exposed within the editors/gpencil module so that other tools can use it too.
+ */
extern ListBase gpencil_strokes_copypastebuf;
/* Build a map for converting between old color-names and destination-color-refs. */
+/**
+ * Ensure that destination datablock has all the colors the pasted strokes need.
+ * Helper function for copy-pasting strokes
+ */
struct GHash *gpencil_copybuf_validate_colormap(struct bContext *C);
/* Stroke Editing ------------------------------------ */
+/**
+ * Simple wrapper to external call.
+ */
int gpencil_delete_selected_point_wrap(bContext *C);
+/**
+ * Subdivide a stroke once, by adding a point half way between each pair of existing points
+ * \param gpd: Datablock
+ * \param gps: Stroke data
+ * \param subdivide: Number of times to subdivide
+ */
void gpencil_subdivide_stroke(bGPdata *gpd, bGPDstroke *gps, const int subdivide);
/* Layers Enums -------------------------------------- */
+/**
+ * Just existing layers.
+ */
const struct EnumPropertyItem *ED_gpencil_layers_enum_itemf(struct bContext *C,
struct PointerRNA *ptr,
struct PropertyRNA *prop,
bool *r_free);
+/**
+ * Existing + Option to add/use new layer.
+ */
const struct EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(struct bContext *C,
struct PointerRNA *ptr,
struct PropertyRNA *prop,
bool *r_free);
+/**
+ * Just existing Materials.
+ */
const struct EnumPropertyItem *ED_gpencil_material_enum_itemf(struct bContext *C,
struct PointerRNA *ptr,
struct PropertyRNA *prop,
@@ -405,6 +523,9 @@ void GPENCIL_OT_stroke_editcurve_set_handle_type(struct wmOperatorType *ot);
/* stroke sculpting -- */
+/**
+ * Also used for weight paint.
+ */
void GPENCIL_OT_sculpt_paint(struct wmOperatorType *ot);
void GPENCIL_OT_weight_paint(struct wmOperatorType *ot);
@@ -474,7 +595,14 @@ enum {
void GPENCIL_OT_stroke_arrange(struct wmOperatorType *ot);
void GPENCIL_OT_stroke_change_color(struct wmOperatorType *ot);
void GPENCIL_OT_stroke_apply_thickness(struct wmOperatorType *ot);
+/**
+ * Similar to #CURVE_OT_cyclic_toggle or #MASK_OT_cyclic_toggle, but with
+ * option to force opened/closed strokes instead of just toggle behavior.
+ */
void GPENCIL_OT_stroke_cyclical_set(struct wmOperatorType *ot);
+/**
+ * Change Stroke caps mode Rounded or Flat
+ */
void GPENCIL_OT_stroke_caps_set(struct wmOperatorType *ot);
void GPENCIL_OT_stroke_join(struct wmOperatorType *ot);
void GPENCIL_OT_stroke_flip(struct wmOperatorType *ot);
diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c
index 22127d7ac3b..2023ae5fe27 100644
--- a/source/blender/editors/gpencil/gpencil_interpolate.c
+++ b/source/blender/editors/gpencil/gpencil_interpolate.c
@@ -336,7 +336,7 @@ static void gpencil_interpolate_smooth_stroke(bGPDstroke *gps,
float reduce = 0.0f;
for (int r = 0; r < smooth_steps; r++) {
for (int i = 0; i < gps->totpoints - 1; i++) {
- BKE_gpencil_stroke_smooth_point(gps, i, smooth_factor - reduce);
+ BKE_gpencil_stroke_smooth_point(gps, i, smooth_factor - reduce, false);
BKE_gpencil_stroke_smooth_strength(gps, i, smooth_factor);
}
reduce += 0.25f; /* reduce the factor */
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index f0118988559..dabe2050b28 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -429,6 +429,9 @@ static void gpencil_stroke_convertcoords(tGPsdata *p,
float *depth)
{
bGPdata *gpd = p->gpd;
+ if (depth && (*depth == DEPTH_INVALID)) {
+ depth = NULL;
+ }
/* in 3d-space - pt->x/y/z are 3 side-by-side floats */
if (gpd->runtime.sbuffer_sflag & GP_STROKE_3DSPACE) {
@@ -1126,7 +1129,7 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
/* find first valid contact point */
for (i = 0; i < gpd->runtime.sbuffer_used; i++) {
- if (depth_arr[i] != FLT_MAX) {
+ if (depth_arr[i] != DEPTH_INVALID) {
break;
}
}
@@ -1138,7 +1141,7 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
}
else {
for (i = gpd->runtime.sbuffer_used - 1; i >= 0; i--) {
- if (depth_arr[i] != FLT_MAX) {
+ if (depth_arr[i] != DEPTH_INVALID) {
break;
}
}
@@ -1148,14 +1151,14 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
* first and last contact in an imaginary line between them */
for (i = 0; i < gpd->runtime.sbuffer_used; i++) {
if (!ELEM(i, first_valid, last_valid)) {
- depth_arr[i] = FLT_MAX;
+ depth_arr[i] = DEPTH_INVALID;
}
}
interp_depth = true;
}
if (interp_depth) {
- interp_sparse_array(depth_arr, gpd->runtime.sbuffer_used, FLT_MAX);
+ interp_sparse_array(depth_arr, gpd->runtime.sbuffer_used, DEPTH_INVALID);
}
}
}
@@ -1202,7 +1205,7 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
for (int r = 0; r < brush->gpencil_settings->draw_smoothlvl; r++) {
for (i = 0; i < gps->totpoints - 1; i++) {
BKE_gpencil_stroke_smooth_point(
- gps, i, brush->gpencil_settings->draw_smoothfac - reduce);
+ gps, i, brush->gpencil_settings->draw_smoothfac - reduce, false);
BKE_gpencil_stroke_smooth_strength(gps, i, brush->gpencil_settings->draw_smoothfac);
}
reduce += 0.25f; /* reduce the factor */
@@ -1214,7 +1217,7 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
float ifac = (float)brush->gpencil_settings->input_samples / 10.0f;
float sfac = interpf(1.0f, 0.2f, ifac);
for (i = 0; i < gps->totpoints - 1; i++) {
- BKE_gpencil_stroke_smooth_point(gps, i, sfac);
+ BKE_gpencil_stroke_smooth_point(gps, i, sfac, false);
BKE_gpencil_stroke_smooth_strength(gps, i, sfac);
}
}
diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c
index 7382aca9a87..8157e9d8fe7 100644
--- a/source/blender/editors/gpencil/gpencil_primitive.c
+++ b/source/blender/editors/gpencil/gpencil_primitive.c
@@ -841,7 +841,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
/* find first valid contact point */
int i;
for (i = 0; i < gps->totpoints; i++) {
- if (depth_arr[i] != FLT_MAX) {
+ if (depth_arr[i] != DEPTH_INVALID) {
break;
}
}
@@ -853,7 +853,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
}
else {
for (i = gps->totpoints - 1; i >= 0; i--) {
- if (depth_arr[i] != FLT_MAX) {
+ if (depth_arr[i] != DEPTH_INVALID) {
break;
}
}
@@ -864,14 +864,14 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
* first and last contact in an imaginary line between them */
for (i = 0; i < gps->totpoints; i++) {
if (!ELEM(i, first_valid, last_valid)) {
- depth_arr[i] = FLT_MAX;
+ depth_arr[i] = DEPTH_INVALID;
}
}
interp_depth = true;
}
if (interp_depth) {
- interp_sparse_array(depth_arr, gps->totpoints, FLT_MAX);
+ interp_sparse_array(depth_arr, gps->totpoints, DEPTH_INVALID);
}
}
}
@@ -1041,7 +1041,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
gpd->runtime.sbuffer, &gpd->runtime.sbuffer_size, &gpd->runtime.sbuffer_used, false);
/* add small offset to keep stroke over the surface */
- if ((depth_arr) && (gpd->zdepth_offset > 0.0f)) {
+ if ((depth_arr) && (gpd->zdepth_offset > 0.0f) && (depth_arr[i] != DEPTH_INVALID)) {
depth_arr[i] *= (1.0f - (gpd->zdepth_offset / 1000.0f));
}
diff --git a/source/blender/editors/gpencil/gpencil_sculpt_paint.c b/source/blender/editors/gpencil/gpencil_sculpt_paint.c
index e9a6beab798..186c45c9f39 100644
--- a/source/blender/editors/gpencil/gpencil_sculpt_paint.c
+++ b/source/blender/editors/gpencil/gpencil_sculpt_paint.c
@@ -337,7 +337,7 @@ static bool gpencil_brush_smooth_apply(tGP_BrushEditData *gso,
/* perform smoothing */
if (gso->brush->gpencil_settings->sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_POSITION) {
- BKE_gpencil_stroke_smooth_point(gps, pt_index, inf);
+ BKE_gpencil_stroke_smooth_point(gps, pt_index, inf, false);
}
if (gso->brush->gpencil_settings->sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_STRENGTH) {
BKE_gpencil_stroke_smooth_strength(gps, pt_index, inf);
@@ -2134,7 +2134,6 @@ static int gpencil_sculpt_brush_modal(bContext *C, wmOperator *op, const wmEvent
return OPERATOR_RUNNING_MODAL;
}
-/* Also used for weight paint. */
void GPENCIL_OT_sculpt_paint(wmOperatorType *ot)
{
/* identifiers */
diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c
index 6ad2fffc773..ed8d2996b6a 100644
--- a/source/blender/editors/gpencil/gpencil_select.c
+++ b/source/blender/editors/gpencil/gpencil_select.c
@@ -248,6 +248,7 @@ static void select_all_curve_points(bGPdata *gpd, bGPDstroke *gps, bGPDcurve *gp
/* -------------------------------------------------------------------- */
/** \name Select All Operator
* \{ */
+
static bool gpencil_select_all_poll(bContext *C)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
diff --git a/source/blender/editors/gpencil/gpencil_trace.h b/source/blender/editors/gpencil/gpencil_trace.h
index 25d8dac2734..7c62288f65d 100644
--- a/source/blender/editors/gpencil/gpencil_trace.h
+++ b/source/blender/editors/gpencil/gpencil_trace.h
@@ -59,16 +59,48 @@ struct bGPDframe;
#define GPENCIL_TRACE_MODE_SINGLE 0
#define GPENCIL_TRACE_MODE_SEQUENCE 1
+/**
+ * Print trace bitmap for debugging.
+ * \param f: Output handle. Use `stderr` for printing
+ * \param bm: Trace bitmap
+ */
void ED_gpencil_trace_bitmap_print(FILE *f, const potrace_bitmap_t *bm);
+/**
+ * Return new un-initialized trace bitmap
+ * \param w: Width in pixels
+ * \param h: Height in pixels
+ * \return Trace bitmap
+ */
potrace_bitmap_t *ED_gpencil_trace_bitmap_new(int32_t w, int32_t h);
+/**
+ * Free a trace bitmap
+ * \param bm: Trace bitmap
+ */
void ED_gpencil_trace_bitmap_free(const potrace_bitmap_t *bm);
+/**
+ * Invert the given bitmap (Black to White)
+ * \param bm: Trace bitmap
+ */
void ED_gpencil_trace_bitmap_invert(const potrace_bitmap_t *bm);
+/**
+ * Convert image to BW bitmap for tracing
+ * \param ibuf: ImBuf of the image
+ * \param bm: Trace bitmap
+ */
void ED_gpencil_trace_image_to_bitmap(struct ImBuf *ibuf,
const potrace_bitmap_t *bm,
const float threshold);
+/**
+ * Convert Potrace Bitmap to Grease Pencil strokes
+ * \param st: Data with traced data
+ * \param ob: Target grease pencil object
+ * \param offset: Offset to center
+ * \param scale: Scale of the output
+ * \param sample: Sample distance to distribute points
+ */
void ED_gpencil_trace_data_to_strokes(struct Main *bmain,
potrace_state_t *st,
struct Object *ob,
diff --git a/source/blender/editors/gpencil/gpencil_trace_utils.c b/source/blender/editors/gpencil/gpencil_trace_utils.c
index 970afc3ff6b..f5690904fcf 100644
--- a/source/blender/editors/gpencil/gpencil_trace_utils.c
+++ b/source/blender/editors/gpencil/gpencil_trace_utils.c
@@ -46,11 +46,6 @@
#include "gpencil_trace.h"
-/**
- * Print trace bitmap for debugging.
- * \param f: Output handle. Use `stderr` for printing
- * \param bm: Trace bitmap
- */
void ED_gpencil_trace_bitmap_print(FILE *f, const potrace_bitmap_t *bm)
{
int32_t x, y;
@@ -77,12 +72,6 @@ void ED_gpencil_trace_bitmap_print(FILE *f, const potrace_bitmap_t *bm)
}
}
-/**
- * Return new un-initialized trace bitmap
- * \param w: Width in pixels
- * \param h: Height in pixels
- * \return Trace bitmap
- */
potrace_bitmap_t *ED_gpencil_trace_bitmap_new(int32_t w, int32_t h)
{
potrace_bitmap_t *bm;
@@ -104,10 +93,6 @@ potrace_bitmap_t *ED_gpencil_trace_bitmap_new(int32_t w, int32_t h)
return bm;
}
-/**
- * Free a trace bitmap
- * \param bm: Trace bitmap
- */
void ED_gpencil_trace_bitmap_free(const potrace_bitmap_t *bm)
{
if (bm != NULL) {
@@ -116,10 +101,6 @@ void ED_gpencil_trace_bitmap_free(const potrace_bitmap_t *bm)
MEM_SAFE_FREE(bm);
}
-/**
- * Invert the given bitmap (Black to White)
- * \param bm: Trace bitmap
- */
void ED_gpencil_trace_bitmap_invert(const potrace_bitmap_t *bm)
{
int32_t dy = bm->dy;
@@ -162,11 +143,6 @@ static void pixel_at_index(const ImBuf *ibuf, const int32_t idx, float r_col[4])
}
}
-/**
- * Convert image to BW bitmap for tracing
- * \param ibuf: ImBuf of the image
- * \param bm: Trace bitmap
- */
void ED_gpencil_trace_image_to_bitmap(ImBuf *ibuf,
const potrace_bitmap_t *bm,
const float threshold)
@@ -231,14 +207,6 @@ static void add_bezier(bGPDstroke *gps,
}
}
-/**
- * Convert Potrace Bitmap to Grease Pencil strokes
- * \param st: Data with traced data
- * \param ob: Target grease pencil object
- * \param offset: Offset to center
- * \param scale: Scale of the output
- * \param sample: Sample distance to distribute points
- */
void ED_gpencil_trace_data_to_strokes(Main *bmain,
potrace_state_t *st,
Object *ob,
diff --git a/source/blender/editors/gpencil/gpencil_undo.c b/source/blender/editors/gpencil/gpencil_undo.c
index 99b8b672327..ec70febc80c 100644
--- a/source/blender/editors/gpencil/gpencil_undo.c
+++ b/source/blender/editors/gpencil/gpencil_undo.c
@@ -62,9 +62,6 @@ int ED_gpencil_session_active(void)
return (BLI_listbase_is_empty(&undo_nodes) == false);
}
-/**
- * \param step: eUndoStepDir.
- */
int ED_undo_gpencil_step(bContext *C, const int step)
{
bGPdata **gpd_ptr = NULL, *new_gpd = NULL;
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index 86df452f49a..f082af979a1 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -96,11 +96,6 @@
/* ******************************************************** */
/* Context Wrangling... */
-/**
- * Get pointer to active Grease Pencil data-block,
- * and an RNA-pointer to trace back to whatever owns it,
- * when context info is not available.
- */
bGPdata **ED_gpencil_data_get_pointers_direct(ScrArea *area, Object *ob, PointerRNA *r_ptr)
{
/* if there's an active area, check if the particular editor may
@@ -130,11 +125,6 @@ bGPdata **ED_gpencil_data_get_pointers_direct(ScrArea *area, Object *ob, Pointer
return NULL;
}
-/**
- * Get pointer to active Grease Pencil data-block for annotations,
- * and an RNA-pointer to trace back to whatever owns it,
- * when context info is not available.
- */
bGPdata **ED_annotation_data_get_pointers_direct(ID *screen_id,
ScrArea *area,
Scene *scene,
@@ -233,10 +223,6 @@ bGPdata **ED_annotation_data_get_pointers_direct(ID *screen_id,
return NULL;
}
-/**
- * Get pointer to active Grease Pencil data-block,
- * and an RNA-pointer to trace back to whatever owns it.
- */
bGPdata **ED_gpencil_data_get_pointers(const bContext *C, PointerRNA *r_ptr)
{
ScrArea *area = CTX_wm_area(C);
@@ -245,10 +231,6 @@ bGPdata **ED_gpencil_data_get_pointers(const bContext *C, PointerRNA *r_ptr)
return ED_gpencil_data_get_pointers_direct(area, ob, r_ptr);
}
-/**
- * Get pointer to active Grease Pencil data-block,
- * and an RNA-pointer to trace back to whatever owns it.
- */
bGPdata **ED_annotation_data_get_pointers(const bContext *C, PointerRNA *r_ptr)
{
ID *screen_id = (ID *)CTX_wm_screen(C);
@@ -259,23 +241,18 @@ bGPdata **ED_annotation_data_get_pointers(const bContext *C, PointerRNA *r_ptr)
}
/* -------------------------------------------------------- */
-/* Get the active Grease Pencil data-block, when context is not available */
bGPdata *ED_gpencil_data_get_active_direct(ScrArea *area, Object *ob)
{
bGPdata **gpd_ptr = ED_gpencil_data_get_pointers_direct(area, ob, NULL);
return (gpd_ptr) ? *(gpd_ptr) : NULL;
}
-/* Get the active Grease Pencil data-block, when context is not available */
bGPdata *ED_annotation_data_get_active_direct(ID *screen_id, ScrArea *area, Scene *scene)
{
bGPdata **gpd_ptr = ED_annotation_data_get_pointers_direct(screen_id, area, scene, NULL);
return (gpd_ptr) ? *(gpd_ptr) : NULL;
}
-/**
- * Get the active Grease Pencil data-block
- */
bGPdata *ED_gpencil_data_get_active(const bContext *C)
{
Object *ob = CTX_data_active_object(C);
@@ -285,24 +262,12 @@ bGPdata *ED_gpencil_data_get_active(const bContext *C)
return ob->data;
}
-/**
- * Get the active Grease Pencil data-block
- * \note This is the original (#G.main) copy of the data-block, stored in files.
- * Do not use for reading evaluated copies of GP Objects data.
- */
bGPdata *ED_annotation_data_get_active(const bContext *C)
{
bGPdata **gpd_ptr = ED_annotation_data_get_pointers(C, NULL);
return (gpd_ptr) ? *(gpd_ptr) : NULL;
}
-/**
- * Get the evaluated copy of the active Grease Pencil data-block (where applicable)
- * - For the 3D View (i.e. "GP Objects"), this gives the evaluated copy of the GP data-block
- * (i.e. a copy of the active GP data-block for the active object, where modifiers have been
- * applied). This is needed to correctly work with "Copy-on-Write".
- * - For all other editors (i.e. "GP Annotations"), this just gives the active data-block
- * like for #ED_gpencil_data_get_active()
- */
+
bGPdata *ED_gpencil_data_get_active_evaluated(const bContext *C)
{
ScrArea *area = CTX_wm_area(C);
@@ -316,10 +281,6 @@ bGPdata *ED_gpencil_data_get_active_evaluated(const bContext *C)
/* -------------------------------------------------------- */
-/**
- * Utility to check whether the r_ptr output of ED_gpencil_data_get_pointers()
- * is for annotation usage.
- */
bool ED_gpencil_data_owner_is_annotation(PointerRNA *owner_ptr)
{
/* Key Assumption: If the pointer is an object, we're dealing with a GP Object's data.
@@ -330,7 +291,6 @@ bool ED_gpencil_data_owner_is_annotation(PointerRNA *owner_ptr)
/* ******************************************************** */
/* Keyframe Indicator Checks */
-/* Check whether there's an active GP keyframe on the current frame */
bool ED_gpencil_has_keyframe_v3d(Scene *UNUSED(scene), Object *ob, int cfra)
{
if (ob && ob->data && (ob->type == OB_GPENCIL)) {
@@ -351,7 +311,6 @@ bool ED_gpencil_has_keyframe_v3d(Scene *UNUSED(scene), Object *ob, int cfra)
/* ******************************************************** */
/* Poll Callbacks */
-/* poll callback for adding data/layers - special */
bool gpencil_add_poll(bContext *C)
{
Object *ob = CTX_data_active_object(C);
@@ -363,7 +322,6 @@ bool gpencil_add_poll(bContext *C)
return (gpd != NULL);
}
-/* poll callback for checking if there is an active layer */
bool gpencil_active_layer_poll(bContext *C)
{
Object *ob = CTX_data_active_object(C);
@@ -376,7 +334,6 @@ bool gpencil_active_layer_poll(bContext *C)
return (gpl != NULL);
}
-/* poll callback for checking if there is an active brush */
bool gpencil_active_brush_poll(bContext *C)
{
ToolSettings *ts = CTX_data_tool_settings(C);
@@ -391,7 +348,6 @@ bool gpencil_active_brush_poll(bContext *C)
/* Dynamic Enums of GP Layers */
/* NOTE: These include an option to create a new layer and use that... */
-/* Just existing layers */
const EnumPropertyItem *ED_gpencil_layers_enum_itemf(bContext *C,
PointerRNA *UNUSED(ptr),
PropertyRNA *UNUSED(prop),
@@ -429,7 +385,6 @@ const EnumPropertyItem *ED_gpencil_layers_enum_itemf(bContext *C,
return item;
}
-/* Existing + Option to add/use new layer */
const EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(bContext *C,
PointerRNA *UNUSED(ptr),
PropertyRNA *UNUSED(prop),
@@ -482,7 +437,6 @@ 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),
@@ -519,15 +473,6 @@ const EnumPropertyItem *ED_gpencil_material_enum_itemf(bContext *C,
/* ******************************************************** */
/* Brush Tool Core */
-/**
- * Check whether a given stroke segment is inside a circular brush
- *
- * \param mval: The current screen-space coordinates (midpoint) of the brush
- * \param rad: The radius of the brush
- *
- * \param x0, y0: The screen-space x and y coordinates of the start of the stroke segment
- * \param x1, y1: The screen-space x and y coordinates of the end of the stroke segment
- */
bool gpencil_stroke_inside_circle(const float mval[2], int rad, int x0, int y0, int x1, int y1)
{
/* simple within-radius check for now */
@@ -577,8 +522,6 @@ bool ED_gpencil_layer_has_selected_stroke(const bGPDlayer *gpl, const bool is_mu
/* ******************************************************** */
/* Stroke Validity Testing */
-/* Check whether given stroke can be edited given the supplied context */
-/* TODO: do we need additional flags for screenspace vs dataspace? */
bool ED_gpencil_stroke_can_use_direct(const ScrArea *area, const bGPDstroke *gps)
{
/* sanity check */
@@ -603,14 +546,12 @@ bool ED_gpencil_stroke_can_use_direct(const ScrArea *area, const bGPDstroke *gps
return true;
}
-/* Check whether given stroke can be edited in the current context */
bool ED_gpencil_stroke_can_use(const bContext *C, const bGPDstroke *gps)
{
ScrArea *area = CTX_wm_area(C);
return ED_gpencil_stroke_can_use_direct(area, gps);
}
-/* Check whether given stroke can be edited for the current color */
bool ED_gpencil_stroke_material_editable(Object *ob, const bGPDlayer *gpl, const bGPDstroke *gps)
{
/* check if the color is editable */
@@ -628,7 +569,6 @@ bool ED_gpencil_stroke_material_editable(Object *ob, const bGPDlayer *gpl, const
return true;
}
-/* Check whether given stroke is visible for the current material. */
bool ED_gpencil_stroke_material_visible(Object *ob, const bGPDstroke *gps)
{
/* check if the color is editable */
@@ -646,11 +586,6 @@ bool ED_gpencil_stroke_material_visible(Object *ob, const bGPDstroke *gps)
/* ******************************************************** */
/* Space Conversion */
-/**
- * Init settings for stroke point space conversions
- *
- * \param r_gsc: [out] The space conversion settings struct, populated with necessary params
- */
void gpencil_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc)
{
ScrArea *area = CTX_wm_area(C);
@@ -691,13 +626,6 @@ void gpencil_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc)
}
}
-/**
- * Convert point to parent space
- *
- * \param pt: Original point
- * \param diff_mat: Matrix with the difference between original parent matrix
- * \param[out] r_pt: Pointer to new point after apply matrix
- */
void gpencil_point_to_parent_space(const bGPDspoint *pt,
const float diff_mat[4][4],
bGPDspoint *r_pt)
@@ -708,9 +636,6 @@ void gpencil_point_to_parent_space(const bGPDspoint *pt,
copy_v3_v3(&r_pt->x, fpt);
}
-/**
- * Change position relative to parent object
- */
void gpencil_apply_parent(Depsgraph *depsgraph, Object *obact, bGPDlayer *gpl, bGPDstroke *gps)
{
bGPDspoint *pt;
@@ -731,9 +656,6 @@ void gpencil_apply_parent(Depsgraph *depsgraph, Object *obact, bGPDlayer *gpl, b
}
}
-/**
- * Change point position relative to parent object
- */
void gpencil_apply_parent_point(Depsgraph *depsgraph,
Object *obact,
bGPDlayer *gpl,
@@ -752,15 +674,6 @@ void gpencil_apply_parent_point(Depsgraph *depsgraph,
copy_v3_v3(&pt->x, fpt);
}
-/**
- * Convert a Grease Pencil coordinate (i.e. can be 2D or 3D) to screenspace (2D)
- *
- * \param[out] r_x: The screen-space x-coordinate of the point
- * \param[out] r_y: The screen-space y-coordinate of the point
- *
- * \warning This assumes that the caller has already checked
- * whether the stroke in question can be drawn.
- */
void gpencil_point_to_xy(
const GP_SpaceConversion *gsc, const bGPDstroke *gps, const bGPDspoint *pt, int *r_x, int *r_y)
{
@@ -803,19 +716,6 @@ void gpencil_point_to_xy(
}
}
-/**
- * Convert a Grease Pencil coordinate (i.e. can be 2D or 3D) to screenspace (2D).
- *
- * Just like #gpencil_point_to_xy(), except the resulting coordinates are floats not ints.
- * Use this version to solve "stair-step" artifacts which may arise when
- * roundtripping the calculations.
- *
- * \param r_x: The screen-space x-coordinate of the point.
- * \param r_y: The screen-space y-coordinate of the point.
- *
- * \warning This assumes that the caller has already checked
- * whether the stroke in question can be drawn.
- */
void gpencil_point_to_xy_fl(const GP_SpaceConversion *gsc,
const bGPDstroke *gps,
const bGPDspoint *pt,
@@ -873,9 +773,6 @@ void gpencil_point_to_xy_fl(const GP_SpaceConversion *gsc,
}
}
-/**
- * generic based on gpencil_point_to_xy_fl
- */
void gpencil_point_3d_to_xy(const GP_SpaceConversion *gsc,
const short flag,
const float pt[3],
@@ -930,21 +827,6 @@ void gpencil_point_3d_to_xy(const GP_SpaceConversion *gsc,
}
}
-/**
- * Project screenspace coordinates to 3D-space
- *
- * For use with editing tools where it is easier to perform the operations in 2D,
- * and then later convert the transformed points back to 3D.
- *
- * \param screen_co: The screenspace 2D coordinates to convert to
- * \param r_out: The resulting 3D coordinates of the input point
- *
- * \note We include this as a utility function, since the standard method
- * involves quite a few steps, which are invariably always the same
- * for all GPencil operations. So, it's nicer to just centralize these.
- *
- * \warning Assumes that it is getting called in a 3D view only.
- */
bool gpencil_point_xy_to_3d(const GP_SpaceConversion *gsc,
Scene *scene,
const float screen_co[2],
@@ -974,14 +856,6 @@ bool gpencil_point_xy_to_3d(const GP_SpaceConversion *gsc,
return false;
}
-/**
- * Convert tGPspoint (temporary 2D/screenspace point data used by GP modal operators)
- * to 3D coordinates.
- *
- * \param point2D: The screen-space 2D point data to convert.
- * \param depth: Depth array (via #ED_view3d_depth_read_cached()).
- * \param r_out: The resulting 2D point data.
- */
void gpencil_stroke_convertcoords_tpoint(Scene *scene,
ARegion *region,
Object *ob,
@@ -991,6 +865,10 @@ void gpencil_stroke_convertcoords_tpoint(Scene *scene,
{
ToolSettings *ts = scene->toolsettings;
+ if (depth && (*depth == DEPTH_INVALID)) {
+ depth = NULL;
+ }
+
int mval_i[2];
round_v2i_v2fl(mval_i, &point2D->x);
@@ -1023,10 +901,6 @@ void gpencil_stroke_convertcoords_tpoint(Scene *scene,
}
}
-/**
- * Get drawing reference point for conversion or projection of the stroke
- * \param r_vec: Reference point found
- */
void ED_gpencil_drawing_reference_get(const Scene *scene,
const Object *ob,
char align_flag,
@@ -1094,9 +968,6 @@ void ED_gpencil_project_stroke_to_view(bContext *C, bGPDlayer *gpl, bGPDstroke *
}
}
-/**
- * Reproject all points of the stroke to a plane locked to axis to avoid stroke offset
- */
void ED_gpencil_project_stroke_to_plane(const Scene *scene,
const Object *ob,
const RegionView3D *rv3d,
@@ -1175,7 +1046,6 @@ void ED_gpencil_project_stroke_to_plane(const Scene *scene,
}
}
-/* Reproject selected strokes */
void ED_gpencil_stroke_reproject(Depsgraph *depsgraph,
const GP_SpaceConversion *gsc,
SnapObjectContext *sctx,
@@ -1316,10 +1186,6 @@ void ED_gpencil_stroke_reproject(Depsgraph *depsgraph,
}
}
-/**
- * Reproject given point to a plane locked to axis to avoid stroke offset
- * \param pt: Point to affect (used for input & output).
- */
void ED_gpencil_project_point_to_plane(const Scene *scene,
const Object *ob,
bGPDlayer *gpl,
@@ -1402,12 +1268,6 @@ void ED_gpencil_project_point_to_plane(const Scene *scene,
/* XXX: Check if these functions duplicate stuff in blenkernel,
* and/or whether we should just deduplicate. */
-/**
- * Subdivide a stroke once, by adding a point half way between each pair of existing points
- * \param gpd: Datablock
- * \param gps: Stroke data
- * \param subdivide: Number of times to subdivide
- */
void gpencil_subdivide_stroke(bGPdata *gpd, bGPDstroke *gps, const int subdivide)
{
bGPDspoint *temp_points;
@@ -1501,7 +1361,6 @@ void gpencil_subdivide_stroke(bGPdata *gpd, bGPDstroke *gps, const int subdivide
BKE_gpencil_stroke_geometry_update(gpd, gps);
}
-/* Reset parent matrix for all layers. */
void ED_gpencil_reset_layers_parent(Depsgraph *depsgraph, Object *obact, bGPdata *gpd)
{
bGPDspoint *pt;
@@ -1551,7 +1410,6 @@ void ED_gpencil_reset_layers_parent(Depsgraph *depsgraph, Object *obact, bGPdata
/* ******************************************************** */
/* GP Object Stuff */
-/* Helper function to create new OB_GPENCIL Object */
Object *ED_gpencil_add_object(bContext *C, const float loc[3], ushort local_view_bits)
{
const float rot[3] = {0.0f};
@@ -1564,7 +1422,6 @@ Object *ED_gpencil_add_object(bContext *C, const float loc[3], ushort local_view
return ob;
}
-/* Helper function to create default colors and drawing brushes */
void ED_gpencil_add_defaults(bContext *C, Object *ob)
{
Main *bmain = CTX_data_main(C);
@@ -1596,7 +1453,6 @@ void ED_gpencil_add_defaults(bContext *C, Object *ob)
/* ******************************************************** */
/* Vertex Groups */
-/* assign points to vertex group */
void ED_gpencil_vgroup_assign(bContext *C, Object *ob, float weight)
{
bGPdata *gpd = (bGPdata *)ob->data;
@@ -1650,7 +1506,6 @@ void ED_gpencil_vgroup_assign(bContext *C, Object *ob, float weight)
CTX_DATA_END;
}
-/* remove points from vertex group */
void ED_gpencil_vgroup_remove(bContext *C, Object *ob)
{
bGPdata *gpd = (bGPdata *)ob->data;
@@ -1703,7 +1558,6 @@ void ED_gpencil_vgroup_remove(bContext *C, Object *ob)
CTX_DATA_END;
}
-/* select points of vertex group */
void ED_gpencil_vgroup_select(bContext *C, Object *ob)
{
bGPdata *gpd = (bGPdata *)ob->data;
@@ -1758,7 +1612,6 @@ void ED_gpencil_vgroup_select(bContext *C, Object *ob)
CTX_DATA_END;
}
-/* unselect points of vertex group */
void ED_gpencil_vgroup_deselect(bContext *C, Object *ob)
{
bGPdata *gpd = (bGPdata *)ob->data;
@@ -1839,7 +1692,6 @@ static bool gpencil_check_cursor_region(bContext *C, const int mval_i[2])
return false;
}
-/* draw eraser cursor */
void ED_gpencil_brush_draw_eraser(Brush *brush, int x, int y)
{
short radius = (short)brush->size;
@@ -2075,7 +1927,6 @@ static void gpencil_brush_cursor_draw(bContext *C, int x, int y, void *customdat
immUnbindProgram();
}
-/* Turn brush cursor in on/off */
void ED_gpencil_toggle_brush_cursor(bContext *C, bool enable, void *customdata)
{
Scene *scene = CTX_data_scene(C);
@@ -2103,7 +1954,6 @@ void ED_gpencil_toggle_brush_cursor(bContext *C, bool enable, void *customdata)
}
}
-/* set object modes */
void ED_gpencil_setup_modes(bContext *C, bGPdata *gpd, int newmode)
{
if (!gpd) {
@@ -2190,9 +2040,6 @@ static void gpencil_stroke_convertcoords(ARegion *region,
}
}
-/**
- * Convert 2d #tGPspoint to 3d #bGPDspoint.
- */
void ED_gpencil_tpoint_to_point(ARegion *region,
float origin[3],
const tGPspoint *tpt,
@@ -2210,9 +2057,6 @@ void ED_gpencil_tpoint_to_point(ARegion *region,
pt->uv_rot = tpt->uv_rot;
}
-/**
- * Recalculate UV for any stroke using the material.
- */
void ED_gpencil_update_color_uv(Main *bmain, Material *mat)
{
Material *gps_ma = NULL;
@@ -2420,7 +2264,6 @@ static float gpencil_calc_factor(const float p2d_a1[2],
return f;
}
-/* extend selection to stroke intersections */
int ED_gpencil_select_stroke_segment(bGPdata *gpd,
bGPDlayer *gpl,
bGPDstroke *gps,
@@ -2801,10 +2644,6 @@ void ED_gpencil_select_curve_toggle_all(bContext *C, int action)
}
}
-/**
- * Ensure the #tGPspoint buffer (while drawing stroke)
- * size is enough to save all points of the stroke.
- */
tGPspoint *ED_gpencil_sbuffer_ensure(tGPspoint *buffer_array,
int *buffer_size,
int *buffer_used,
@@ -2855,9 +2694,6 @@ void ED_gpencil_sbuffer_update_eval(bGPdata *gpd, Object *ob_eval)
gpd_eval->runtime.cp_points = gpd->runtime.cp_points;
}
-/**
- * Tag all scene grease pencil object to update.
- */
void ED_gpencil_tag_scene_gpencil(Scene *scene)
{
/* Mark all grease pencil data-blocks of the scene. */
@@ -3106,7 +2942,6 @@ void ED_gpencil_sbuffer_vertex_color_set(Depsgraph *depsgraph,
}
}
-/* Get the bigger 2D bound box points. */
void ED_gpencil_projected_2d_bound_box(const GP_SpaceConversion *gsc,
const bGPDstroke *gps,
const float diff_mat[4][4],
@@ -3140,7 +2975,6 @@ void ED_gpencil_projected_2d_bound_box(const GP_SpaceConversion *gsc,
}
}
-/* Check if the stroke collides with brush. */
bool ED_gpencil_stroke_check_collision(const GP_SpaceConversion *gsc,
bGPDstroke *gps,
const float mouse[2],
@@ -3167,15 +3001,6 @@ bool ED_gpencil_stroke_check_collision(const GP_SpaceConversion *gsc,
return BLI_rcti_isect(&rect_stroke, &rect_mouse, NULL);
}
-/**
- * Check if a point is inside of the stroke.
- *
- * \param gps: Stroke to check.
- * \param gsc: Space conversion data.
- * \param mouse: Mouse position.
- * \param diff_mat: View matrix.
- * \return True if the point is inside.
- */
bool ED_gpencil_stroke_point_is_inside(const bGPDstroke *gps,
const GP_SpaceConversion *gsc,
const int mouse[2],
@@ -3214,7 +3039,6 @@ bool ED_gpencil_stroke_point_is_inside(const bGPDstroke *gps,
return hit;
}
-/* Get extremes of stroke in 2D using current view. */
void ED_gpencil_stroke_extremes_to2d(const GP_SpaceConversion *gsc,
const float diff_mat[4][4],
bGPDstroke *gps,
@@ -3329,7 +3153,6 @@ bGPDstroke *ED_gpencil_stroke_nearest_to_ends(bContext *C,
return gps_rtn;
}
-/* Join two stroke using a contact point index and trimming the rest. */
bGPDstroke *ED_gpencil_stroke_join_and_trim(
bGPdata *gpd, bGPDframe *gpf, bGPDstroke *gps, bGPDstroke *gps_dst, const int pt_index)
{
@@ -3399,7 +3222,6 @@ bGPDstroke *ED_gpencil_stroke_join_and_trim(
return gps_final;
}
-/* Close if the distance between extremes is below threshold. */
void ED_gpencil_stroke_close_by_distance(bGPDstroke *gps, const float threshold)
{
if (gps == NULL) {
@@ -3416,7 +3238,6 @@ void ED_gpencil_stroke_close_by_distance(bGPDstroke *gps, const float threshold)
}
}
-/* Merge two layers. */
void ED_gpencil_layer_merge(bGPdata *gpd,
bGPDlayer *gpl_src,
bGPDlayer *gpl_dst,
diff --git a/source/blender/editors/include/BIF_glutil.h b/source/blender/editors/include/BIF_glutil.h
index 0a1cf643f37..8f2a189e35e 100644
--- a/source/blender/editors/include/BIF_glutil.h
+++ b/source/blender/editors/include/BIF_glutil.h
@@ -46,6 +46,12 @@ typedef struct IMMDrawPixelsTexState {
/* To be used before calling immDrawPixelsTex
* Default shader is GPU_SHADER_2D_IMAGE_COLOR
* Returns a shader to be able to set uniforms */
+/**
+ * To be used before calling #immDrawPixelsTex
+ * Default shader is #GPU_SHADER_2D_IMAGE_COLOR
+ * You can still set uniforms with:
+ * `GPU_shader_uniform_int(shader, GPU_shader_get_uniform(shader, "name"), 0);`
+ */
IMMDrawPixelsTexState immDrawPixelsTexSetup(int builtin);
/**
@@ -101,6 +107,20 @@ void immDrawPixelsTexScaled(IMMDrawPixelsTexState *state,
float xzoom,
float yzoom,
const float color[4]);
+/**
+ * Use the currently bound shader.
+ *
+ * Use #immDrawPixelsTexSetup to bind the shader you
+ * want before calling #immDrawPixelsTex.
+ *
+ * If using a special shader double check it uses the same
+ * attributes "pos" "texCoord" and uniform "image".
+ *
+ * If color is NULL then use white by default
+ *
+ * Be also aware that this function unbinds the shader when
+ * it's finished.
+ */
void immDrawPixelsTexScaled_clipping(IMMDrawPixelsTexState *state,
float x,
float y,
@@ -135,6 +155,9 @@ void ED_draw_imbuf(struct ImBuf *ibuf,
struct ColorManagedDisplaySettings *display_settings,
float zoom_x,
float zoom_y);
+/**
+ * Draw given image buffer on a screen using GLSL for display transform.
+ */
void ED_draw_imbuf_clipping(struct ImBuf *ibuf,
float x,
float y,
@@ -169,6 +192,9 @@ void ED_draw_imbuf_ctx_clipping(const struct bContext *C,
int ED_draw_imbuf_method(struct ImBuf *ibuf);
+/**
+ * Don't move to `GPU_immediate_util.h` because this uses user-prefs and isn't very low level.
+ */
void immDrawBorderCorners(unsigned int pos, const struct rcti *border, float zoomx, float zoomy);
#ifdef __cplusplus
diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h
index e9601220f2e..3294316f880 100644
--- a/source/blender/editors/include/ED_anim_api.h
+++ b/source/blender/editors/include/ED_anim_api.h
@@ -63,7 +63,9 @@ struct PropertyRNA;
/* ANIMATION CHANNEL FILTERING */
/* anim_filter.c */
-/* --------------- Context --------------------- */
+/* -------------------------------------------------------------------- */
+/** \name Context
+ * \{ */
/* This struct defines a structure used for animation-specific
* 'context' information
@@ -126,7 +128,11 @@ typedef enum eAnimCont_Types {
ANIMCONT_TIMELINE = 10, /* "timeline" editor (bDopeSheet) */
} eAnimCont_Types;
-/* --------------- Channels -------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Channels
+ * \{ */
/* This struct defines a structure used for quick and uniform access for
* channels of animation data
@@ -281,7 +287,11 @@ typedef enum eAnim_Update_Flags {
#define ANIM_UPDATE_DEFAULT (ANIM_UPDATE_DEPS | ANIM_UPDATE_ORDER | ANIM_UPDATE_HANDLES)
#define ANIM_UPDATE_DEFAULT_NOHANDLES (ANIM_UPDATE_DEFAULT & ~ANIM_UPDATE_HANDLES)
-/* ----------------- Filtering -------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Filtering
+ * \{ */
/* filtering flags - under what circumstances should a channel be returned */
typedef enum eAnimFilter_Flags {
@@ -334,7 +344,12 @@ typedef enum eAnimFilter_Flags {
ANIMFILTER_TMP_IGNORE_ONLYSEL = (1u << 31),
} eAnimFilter_Flags;
-/* ---------- Flag Checking Macros ------------ */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Flag Checking Macros
+ * \{ */
+
/* XXX check on all of these flags again. */
/* Dopesheet only */
@@ -421,7 +436,11 @@ typedef enum eAnimFilter_Flags {
/* AnimData - NLA mostly... */
#define SEL_ANIMDATA(adt) (adt->flag & ADT_UI_SELECTED)
-/* -------------- Channel Defines -------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Channel Defines
+ * \{ */
/* channel heights */
#define ACHANNEL_FIRST_TOP(ac) \
@@ -439,7 +458,11 @@ typedef enum eAnimFilter_Flags {
/* channel toggle-buttons */
#define ACHANNEL_BUTTON_WIDTH (0.8f * U.widget_unit)
-/* -------------- NLA Channel Defines -------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name NLA Channel Defines
+ * \{ */
/* NLA channel heights */
#define NLACHANNEL_FIRST_TOP(ac) \
@@ -459,10 +482,19 @@ typedef enum eAnimFilter_Flags {
/* channel toggle-buttons */
#define NLACHANNEL_BUTTON_WIDTH (0.8f * U.widget_unit)
-/* ---------------- API -------------------- */
+/** \} */
-/* Obtain list of filtered Animation channels to operate on.
- * Returns the number of channels in the list
+/* -------------------------------------------------------------------- */
+/** \name Public API
+ * \{ */
+
+/**
+ * This function filters the active data source to leave only animation channels suitable for
+ * usage by the caller. It will return the length of the list
+ *
+ * \param anim_data: Is a pointer to a #ListBase,
+ * to which the filtered animation channels will be placed for use.
+ * \param filter_mode: how should the data be filtered - bit-mapping accessed flags.
*/
size_t ANIM_animdata_filter(bAnimContext *ac,
ListBase *anim_data,
@@ -470,18 +502,27 @@ size_t ANIM_animdata_filter(bAnimContext *ac,
void *data,
eAnimCont_Types datatype);
-/* Obtain current anim-data context from Blender Context info.
- * Returns whether the operation was successful.
+/**
+ * Obtain current anim-data context from Blender Context info
+ * - AnimContext to write to is provided as pointer to var on stack so that we don't have
+ * allocation/freeing costs (which are not that avoidable with channels).
+ * - Clears data and sets the information from Blender Context which is useful
+ * \return whether the operation was successful.
*/
bool ANIM_animdata_get_context(const struct bContext *C, bAnimContext *ac);
-/* Obtain current anim-data context (from Animation Editor) given
- * that Blender Context info has already been set.
- * Returns whether the operation was successful.
+/**
+ * Obtain current anim-data context,
+ * given that context info from Blender context has already been set:
+ * - AnimContext to write to is provided as pointer to var on stack so that we don't have
+ * allocation/freeing costs (which are not that avoidable with channels).
+ * \return whether the operation was successful.
*/
bool ANIM_animdata_context_getdata(bAnimContext *ac);
-/* Acts on bAnimListElem eAnim_Update_Flags */
+/**
+ * Acts on bAnimListElem eAnim_Update_Flags.
+ */
void ANIM_animdata_update(bAnimContext *ac, ListBase *anim_data);
void ANIM_animdata_freelist(ListBase *anim_data);
@@ -490,7 +531,11 @@ void ANIM_animdata_freelist(ListBase *anim_data);
/* ANIMATION CHANNELS LIST */
/* anim_channels_*.c */
-/* ------------------------ Drawing TypeInfo -------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Drawing TypeInfo
+ * \{ */
/* role or level of animchannel in the hierarchy */
typedef enum eAnimChannel_Role {
@@ -569,18 +614,35 @@ typedef struct bAnimChannelType {
void *(*setting_ptr)(bAnimListElem *ale, eAnimChannel_Settings setting, short *type);
} bAnimChannelType;
-/* ------------------------ Drawing API -------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Drawing API
+ * \{ */
-/* Get typeinfo for the given channel */
+/**
+ * Get type info from given channel type.
+ */
const bAnimChannelType *ANIM_channel_get_typeinfo(bAnimListElem *ale);
-/* Print debugging info about a given channel */
+/**
+ * Print debug info string for the given channel.
+ */
void ANIM_channel_debug_print_info(bAnimListElem *ale, short indent_level);
-/* Draw the given channel */
+/**
+ * Retrieves the Action associated with this animation channel.
+ */
+bAction *ANIM_channel_action_get(const bAnimListElem *ale);
+
+/**
+ * Draw the given channel.
+ */
void ANIM_channel_draw(
bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc, size_t channel_index);
-/* Draw the widgets for the given channel */
+/**
+ * Draw UI widgets the given channel.
+ */
void ANIM_channel_draw_widgets(const struct bContext *C,
bAnimContext *ac,
bAnimListElem *ale,
@@ -588,27 +650,30 @@ void ANIM_channel_draw_widgets(const struct bContext *C,
rctf *rect,
size_t channel_index);
-/* ------------------------ Editing API -------------------------- */
+/** \} */
-/* Check if some setting for a channel is enabled
- * Returns: 1 = On, 0 = Off, -1 = Invalid
- *
- * - setting: eAnimChannel_Settings
+/* -------------------------------------------------------------------- */
+/** \name Editing API
+ * \{ */
+
+/**
+ * Check if some setting for a channel is enabled
+ * Returns: 1 = On, 0 = Off, -1 = Invalid.
*/
short ANIM_channel_setting_get(bAnimContext *ac,
bAnimListElem *ale,
eAnimChannel_Settings setting);
-/* Change value of some setting for a channel
- * - setting: eAnimChannel_Settings
- * - mode: eAnimChannels_SetFlag
+/**
+ * Change value of some setting for a channel.
*/
void ANIM_channel_setting_set(bAnimContext *ac,
bAnimListElem *ale,
eAnimChannel_Settings setting,
eAnimChannels_SetFlag mode);
-/* Flush visibility (for Graph Editor) changes up/down hierarchy for changes in the given setting
+/**
+ * Flush visibility (for Graph Editor) changes up/down hierarchy for changes in the given setting
* - anim_data: list of the all the anim channels that can be chosen
* -> filtered using ANIMFILTER_CHANNELS only, since if we took VISIBLE too,
* then the channels under closed expanders get ignored...
@@ -623,13 +688,19 @@ void ANIM_flush_setting_anim_channels(bAnimContext *ac,
eAnimChannel_Settings setting,
eAnimChannels_SetFlag mode);
-/* Select or deselect animation channels */
+/**
+ * Set selection state of all animation channels in the context.
+ */
void ANIM_anim_channels_select_set(bAnimContext *ac, eAnimChannels_SetFlag sel);
-/* Toggle selection of animation channels */
+/**
+ * Toggle selection state of all animation channels in the context.
+ */
void ANIM_anim_channels_select_toggle(bAnimContext *ac);
-/* Set the 'active' channel of type channel_type, in the given action */
+/**
+ * Set the given animation-channel as the active one for the active context.
+ */
void ANIM_set_active_channel(bAnimContext *ac,
void *data,
eAnimCont_Types datatype,
@@ -637,18 +708,31 @@ void ANIM_set_active_channel(bAnimContext *ac,
void *channel_data,
eAnim_ChannelType channel_type);
-/* Delete the F-Curve from the given AnimData block (if possible),
- * as appropriate according to animation context */
+/**
+ * Delete the F-Curve from the given AnimData block (if possible),
+ * as appropriate according to animation context.
+ */
void ANIM_fcurve_delete_from_animdata(bAnimContext *ac, struct AnimData *adt, struct FCurve *fcu);
-/* Unlink the action from animdata if it's empty. */
+/**
+ * Unlink the action from animdata if it's empty.
+ *
+ * If the action has no F-Curves, unlink it from AnimData if it did not
+ * come from a NLA Strip being tweaked.
+ */
bool ANIM_remove_empty_action_from_animdata(struct AnimData *adt);
/* ************************************************ */
/* DRAWING API */
/* anim_draw.c */
-/* ---------- Current Frame Drawing ---------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Current Frame Drawing
+ *
+ * Main call to draw current-frame indicator in an Animation Editor.
+ * \{ */
/* flags for Current Frame Drawing */
typedef enum eAnimEditDraw_CurrentFrame {
@@ -660,23 +744,54 @@ typedef enum eAnimEditDraw_CurrentFrame {
DRAWCFRA_WIDE = (1 << 1),
} eAnimEditDraw_CurrentFrame;
-/* main call to draw current-frame indicator in an Animation Editor */
+/**
+ * General call for drawing current frame indicator in animation editor.
+ */
void ANIM_draw_cfra(const struct bContext *C, struct View2D *v2d, short flag);
-/* ------------- Preview Range Drawing -------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Preview Range Drawing
+ *
+ * Main call to draw preview range curtains.
+ * \{ */
-/* main call to draw preview range curtains */
+/**
+ * Draw preview range 'curtains' for highlighting where the animation data is.
+ */
void ANIM_draw_previewrange(const struct bContext *C, struct View2D *v2d, int end_frame_width);
-/* -------------- Frame Range Drawing --------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Frame Range Drawing
+ *
+ * Main call to draw normal frame range indicators.
+ * \{ */
-/* main call to draw normal frame range indicators */
+/**
+ * Draw frame range guides (for scene frame range) in background.
+ *
+ * TODO: Should we still show these when preview range is enabled?
+ */
void ANIM_draw_framerange(struct Scene *scene, struct View2D *v2d);
+/**
+ * Draw manually set intended playback frame range guides for the action in the background.
+ * Allows specifying a subset of the Y range of the view.
+ */
+void ANIM_draw_action_framerange(
+ struct AnimData *adt, struct bAction *action, struct View2D *v2d, float ymin, float ymax);
+
/* ************************************************* */
/* F-MODIFIER TOOLS */
-/* ------------- UI Panel Drawing -------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name UI Panel Drawing
+ * \{ */
bool ANIM_nla_context_track_ptr(const struct bContext *C, struct PointerRNA *r_ptr);
bool ANIM_nla_context_strip_ptr(const struct bContext *C, struct PointerRNA *r_ptr);
@@ -690,6 +805,9 @@ typedef bool (*PanelTypePollFn)(const struct bContext *C, struct PanelType *pt);
/* Avoid including "UI_interface.h" here. */
typedef void (*uiListPanelIDFromDataFunc)(void *data_link, char *r_idname);
+/**
+ * Checks if the panels match the active strip / curve, rebuilds them if they don't.
+ */
void ANIM_fmodifier_panels(const struct bContext *C,
struct ID *owner_id,
struct ListBase *fmodifiers,
@@ -702,49 +820,93 @@ void ANIM_modifier_panels_register_graph_only(struct ARegionType *region_type,
const char *modifier_panel_prefix,
PanelTypePollFn poll_function);
-/* ------------- Copy/Paste Buffer -------------- */
+/** \} */
-/* free the copy/paste buffer */
+/* -------------------------------------------------------------------- */
+/** \name Copy/Paste Buffer
+ * \{ */
+
+/**
+ * Free the copy/paste buffer.
+ */
void ANIM_fmodifiers_copybuf_free(void);
-/* copy the given F-Modifiers to the buffer, returning whether anything was copied or not
- * assuming that the buffer has been cleared already with ANIM_fmodifiers_copybuf_free()
- * - active: only copy the active modifier
+/**
+ * Copy the given F-Modifiers to the buffer, returning whether anything was copied or not
+ * assuming that the buffer has been cleared already with #ANIM_fmodifiers_copybuf_free()
+ * \param active: Only copy the active modifier.
*/
bool ANIM_fmodifiers_copy_to_buf(ListBase *modifiers, bool active);
-/* 'Paste' the F-Modifier(s) from the buffer to the specified list
- * - replace: free all the existing modifiers to leave only the pasted ones
+/**
+ * 'Paste' the F-Modifier(s) from the buffer to the specified list
+ * \param replace: Free all the existing modifiers to leave only the pasted ones.
*/
bool ANIM_fmodifiers_paste_from_buf(ListBase *modifiers, bool replace, struct FCurve *curve);
/* ************************************************* */
/* ASSORTED TOOLS */
-/* ------------ Animation F-Curves <-> Icons/Names Mapping ------------ */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Animation F-Curves <-> Icons/Names Mapping
+ * \{ */
+
/* anim_ipo_utils.c */
-/* Get icon + name for channel-list displays for F-Curve */
+/**
+ * Get icon + name for channel-list displays for F-Curve.
+ *
+ * Write into "name" buffer, the name of the property
+ * (retrieved using RNA from the curve's settings),
+ * and return the icon used for the struct that this property refers to
+ *
+ * \warning name buffer we're writing to cannot exceed 256 chars
+ * (check anim_channels_defines.c for details).
+ */
int getname_anim_fcurve(char *name, struct ID *id, struct FCurve *fcu);
-/* Automatically determine a color for the nth F-Curve */
+/**
+ * Automatically determine a color for the nth F-Curve.
+ */
void getcolor_fcurve_rainbow(int cur, int tot, float out[3]);
-/* ----------------- NLA Drawing ----------------------- */
-/* NOTE: Technically, this is not in the animation module (it's in space_nla)
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name NLA Drawing
+ *
+ * \note Technically, this is not in the animation module (it's in space_nla)
* but these are sometimes needed by various animation API's.
- */
+ * \{ */
-/* Get color to use for NLA Action channel's background */
+/**
+ * Get color to use for NLA Action channel's background.
+ * \note color returned includes fine-tuned alpha!
+ */
void nla_action_get_color(struct AnimData *adt, struct bAction *act, float color[4]);
-/* ----------------- NLA-Mapping ----------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name NLA-Mapping
+ * \{ */
+
/* anim_draw.c */
-/* Obtain the AnimData block providing NLA-scaling for the given channel if applicable */
+/**
+ * Obtain the AnimData block providing NLA-mapping for the given channel (if applicable).
+ *
+ * TODO: do not supply return this if the animdata tells us that there is no mapping to perform.
+ */
struct AnimData *ANIM_nla_mapping_get(bAnimContext *ac, bAnimListElem *ale);
-/* Apply/Unapply NLA mapping to all keyframes in the nominated F-Curve */
+/**
+ * Apply/Unapply NLA mapping to all keyframes in the nominated F-Curve
+ * \param restore: Whether to map points back to non-mapped time.
+ * \param only_keys: Whether to only adjust the location of the center point of beztriples.
+ */
void ANIM_nla_mapping_apply_fcurve(struct AnimData *adt,
struct FCurve *fcu,
bool restore,
@@ -752,11 +914,18 @@ void ANIM_nla_mapping_apply_fcurve(struct AnimData *adt,
/* ..... */
-/* Perform auto-blending/extend refreshes after some operations */
-/* NOTE: defined in space_nla/nla_edit.c, not in animation/ */
+/**
+ * Perform validation & auto-blending/extend refreshes after some operations
+ * \note defined in space_nla/nla_edit.c, not in animation/
+ */
void ED_nla_postop_refresh(bAnimContext *ac);
-/* ------------- Unit Conversion Mappings ------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Unit Conversion Mappings
+ * \{ */
+
/* anim_draw.c */
/* flags for conversion mapping */
@@ -778,16 +947,24 @@ typedef enum eAnimUnitConv_Flags {
ANIM_UNITCONV_NORMALIZE_FREEZE = (1 << 6),
} eAnimUnitConv_Flags;
-/* Normalization flags from Space Graph passing to ANIM_unit_mapping_get_factor */
+/**
+ * Get flags used for normalization in ANIM_unit_mapping_get_factor.
+ */
short ANIM_get_normalization_flags(bAnimContext *ac);
-
-/* Get unit conversion factor for given ID + F-Curve */
+/**
+ * Get unit conversion factor for given ID + F-Curve.
+ */
float ANIM_unit_mapping_get_factor(
struct Scene *scene, struct ID *id, struct FCurve *fcu, short flag, float *r_offset);
-/* ------------- Utility macros ----------------------- */
+/** \} */
-/* provide access to Keyframe Type info in BezTriple
+/* -------------------------------------------------------------------- */
+/** \name Utility macros
+ * \{ */
+
+/**
+ * Provide access to Keyframe Type info in #BezTriple.
* NOTE: this is so that we can change it from being stored in 'hide'
*/
#define BEZKEYTYPE(bezt) ((bezt)->hide)
@@ -830,18 +1007,37 @@ float ANIM_unit_mapping_get_factor(
} \
((void)0)
-/* --------- anim_deps.c, animation updates -------- */
+/** \} */
+/* anim_deps.c */
+
+/* -------------------------------------------------------------------- */
+/** \name Animation Updates
+ * \{ */
+
+/**
+ * Tags the given ID block for refreshes (if applicable) due to Animation Editor editing.
+ */
void ANIM_id_update(struct Main *bmain, struct ID *id);
+/**
+ * Tags the given anim list element for refreshes (if applicable) due to Animation Editor editing.
+ */
void ANIM_list_elem_update(struct Main *bmain, struct Scene *scene, bAnimListElem *ale);
/* data -> channels syncing */
+
+/**
+ * Main call to be exported to animation editors.
+ */
void ANIM_sync_animchannels_to_data(const struct bContext *C);
void ANIM_center_frame(struct bContext *C, int smooth_viewtx);
-/* ************************************************* */
-/* OPERATORS */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Operators
+ * \{ */
/* generic animation channels */
void ED_operatortypes_animchannels(void);
@@ -856,12 +1052,20 @@ void ED_operatormacros_graph(void);
/* space_action */
void ED_operatormacros_action(void);
-/* ************************************************ */
-/* Animation Editor Exports */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Animation Editor Exports
+ * \{ */
+
/* XXX: Should we be doing these here, or at all? */
-/* Action Editor - Action Management */
-struct AnimData *ED_actedit_animdata_from_context(struct bContext *C, struct ID **r_adt_id_owner);
+/**
+ * Action Editor - Action Management.
+ * Helper function to find the active AnimData block from the Action Editor context.
+ */
+struct AnimData *ED_actedit_animdata_from_context(const struct bContext *C,
+ struct ID **r_adt_id_owner);
void ED_animedit_unlink_action(struct bContext *C,
struct ID *id,
struct AnimData *adt,
@@ -869,7 +1073,11 @@ void ED_animedit_unlink_action(struct bContext *C,
struct ReportList *reports,
bool force_delete);
-/* Drivers Editor - Utility to set up UI correctly */
+/**
+ * Set up UI configuration for Drivers Editor
+ * (drivers editor window) and RNA (mode switching).
+ * \note Currently called from window-manager.
+ */
void ED_drivers_editor_init(struct bContext *C, struct ScrArea *area);
/* ************************************************ */
@@ -897,8 +1105,14 @@ void animviz_calc_motionpaths(struct Depsgraph *depsgraph,
eAnimvizCalcRange range,
bool restore);
+/**
+ * Get list of motion paths to be baked for the given object.
+ * - assumes the given list is ready to be used.
+ */
void animviz_get_object_motionpaths(struct Object *ob, ListBase *targets);
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h
index 868235c36e5..0053bf5c865 100644
--- a/source/blender/editors/include/ED_armature.h
+++ b/source/blender/editors/include/ED_armature.h
@@ -70,45 +70,91 @@ struct wmOperator;
(CHECK_TYPE_INLINE(ebone, EditBone *), \
(((ebone)->flag & BONE_SELECTED) && !((ebone)->flag & BONE_EDITMODE_LOCKED)))
-/* used in armature_select.c and pose_select.c */
+/* Used in `armature_select.c` and `pose_select.c`. */
+
#define BONE_SELECT_PARENT 0
#define BONE_SELECT_CHILD 1
/* armature_add.c */
+
+/**
+ * Default bone add, returns it selected, but without tail set.
+ *
+ * \note should be used everywhere, now it allocates bones still locally in functions.
+ */
struct EditBone *ED_armature_ebone_add(struct bArmature *arm, const char *name);
struct EditBone *ED_armature_ebone_add_primitive(struct Object *obedit_arm,
float length,
bool view_aligned);
/* armature_edit.c */
+
+/**
+ * Adjust bone roll to align Z axis with vector `align_axis` is in local space and is normalized.
+ */
float ED_armature_ebone_roll_to_vector(const struct EditBone *bone,
const float align_axis[3],
const bool axis_only);
+/**
+ * \param centermode: 0 == do center, 1 == center new, 2 == center cursor.
+ *
+ * \note Exported for use in `editors/object/`.
+ */
void ED_armature_origin_set(
struct Main *bmain, struct Object *ob, const float cursor[3], int centermode, int around);
+/**
+ * See #BKE_armature_transform for object-mode transform.
+ */
void ED_armature_edit_transform(struct bArmature *arm, const float mat[4][4], const bool do_props);
void ED_armature_transform(struct bArmature *arm, const float mat[4][4], const bool do_props);
/* armature_naming.c */
+
+/**
+ * Ensure the bone name is unique.
+ * If bone is already in list, pass it as argument to ignore it.
+ */
void ED_armature_ebone_unique_name(struct ListBase *ebones, char *name, struct EditBone *bone);
+
+/**
+ * Bone Rename (called by UI for renaming a bone).
+ * Seems messy, but that's what you get with not using pointers but channel names :).
+ * \warning make sure the original bone was not renamed yet!
+ */
void ED_armature_bone_rename(struct Main *bmain,
struct bArmature *arm,
const char *oldnamep,
const char *newnamep);
+/**
+ * Renames (by flipping) all selected bones at once.
+ *
+ * This way if we are flipping related bones (e.g., Bone.L, Bone.R) at the same time
+ * all the bones are safely renamed, without conflicting with each other.
+ *
+ * \param arm: Armature the bones belong to
+ * \param bones_names: List of bone conflict elements (#LinkData pointing to names).
+ * \param do_strip_numbers: if set, try to get rid of dot-numbers at end of bone names.
+ */
void ED_armature_bones_flip_names(struct Main *bmain,
struct bArmature *arm,
struct ListBase *bones_names,
const bool do_strip_numbers);
/* armature_ops.c */
+
void ED_operatortypes_armature(void);
void ED_operatormacros_armature(void);
void ED_keymap_armature(struct wmKeyConfig *keyconf);
/* armature_relations.c */
+
+/**
+ * Join armature exec is exported for use in object->join objects operator.
+ */
int ED_armature_join_objects_exec(struct bContext *C, struct wmOperator *op);
/* armature_select.c */
+
struct Base *ED_armature_base_and_ebone_from_select_buffer(struct Base **bases,
uint bases_len,
int hit,
@@ -121,6 +167,9 @@ struct Base *ED_armature_base_and_pchan_from_select_buffer(struct Base **bases,
uint bases_len,
int hit,
struct bPoseChannel **r_pchan);
+/**
+ * For callers that don't need the pose channel.
+ */
struct Base *ED_armature_base_and_bone_from_select_buffer(struct Base **bases,
uint bases_len,
int hit,
@@ -137,11 +186,27 @@ bool ED_armature_edit_select_pick_bone(struct bContext *C,
bool extend,
bool deselect,
bool toggle);
+/**
+ * Bone selection picking for armature edit-mode in the view3d.
+ */
bool ED_armature_edit_select_pick(
struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
+/**
+ * Perform a selection operation on elements which have been 'touched',
+ * use for lasso & border select but can be used elsewhere too.
+ *
+ * Tagging is done via #EditBone.temp.i using: #BONESEL_ROOT, #BONESEL_TIP, #BONESEL_BONE
+ * And optionally ignoring end-points using the #BONESEL_ROOT, #BONESEL_TIP right shifted 16 bits.
+ * (used when the values are clipped outside the view).
+ *
+ * \param sel_op: #eSelectOp type.
+ *
+ * \note Visibility checks must be done by the caller.
+ */
bool ED_armature_edit_select_op_from_tagged(struct bArmature *arm, const int sel_op);
/* armature_skinning.c */
+
#define ARM_GROUPS_NAME 1
#define ARM_GROUPS_ENVELOPE 2
#define ARM_GROUPS_AUTO 3
@@ -154,40 +219,74 @@ void ED_object_vgroup_calc_from_armature(struct ReportList *reports,
const bool mirror);
/* editarmature_undo.c */
+
+/** Export for ED_undo_sys. */
void ED_armature_undosys_type(struct UndoType *ut);
/* armature_utils.c */
+
+/** Sync selection to parent for connected children. */
void ED_armature_edit_sync_selection(struct ListBase *edbo);
void ED_armature_edit_validate_active(struct bArmature *arm);
+/**
+ * Update the layers_used variable after bones are moved between layer
+ * \note Used to be done in drawing code in 2.7, but that won't work with
+ * Copy-on-Write, as drawing uses evaluated copies.
+ */
void ED_armature_edit_refresh_layer_used(struct bArmature *arm);
+/**
+ * \param clear_connected: When false caller is responsible for keeping the flag in a valid state.
+ */
void ED_armature_ebone_remove_ex(struct bArmature *arm,
struct EditBone *exBone,
bool clear_connected);
void ED_armature_ebone_remove(struct bArmature *arm, struct EditBone *exBone);
bool ED_armature_ebone_is_child_recursive(struct EditBone *ebone_parent,
struct EditBone *ebone_child);
+/**
+ * Finds the first parent shared by \a ebone_child
+ *
+ * \param ebone_child: Children bones to search
+ * \param ebone_child_tot: Size of the ebone_child array
+ * \return The shared parent or NULL.
+ */
struct EditBone *ED_armature_ebone_find_shared_parent(struct EditBone *ebone_child[],
const unsigned int ebone_child_tot);
void ED_armature_ebone_to_mat3(struct EditBone *ebone, float r_mat[3][3]);
void ED_armature_ebone_to_mat4(struct EditBone *ebone, float r_mat[4][4]);
void ED_armature_ebone_from_mat3(struct EditBone *ebone, const float mat[3][3]);
void ED_armature_ebone_from_mat4(struct EditBone *ebone, const float mat[4][4]);
+/**
+ * Return a pointer to the bone of the given name
+ */
struct EditBone *ED_armature_ebone_find_name(const struct ListBase *edbo, const char *name);
+/**
+ * \see #BKE_pose_channel_get_mirrored (pose-mode, matching function)
+ */
struct EditBone *ED_armature_ebone_get_mirrored(const struct ListBase *edbo, struct EditBone *ebo);
void ED_armature_ebone_transform_mirror_update(struct bArmature *arm,
struct EditBone *ebo,
bool check_select);
+/**
+ * If edit-bone (partial) selected, copy data.
+ * context; edit-mode armature, with mirror editing enabled.
+ */
void ED_armature_edit_transform_mirror_update(struct Object *obedit);
+/** Put edit-mode back in Object. */
void ED_armature_from_edit(struct Main *bmain, struct bArmature *arm);
+/** Put armature in edit-mode. */
void ED_armature_to_edit(struct bArmature *arm);
void ED_armature_edit_free(struct bArmature *arm);
void ED_armature_ebone_listbase_temp_clear(struct ListBase *lb);
+
+/**
+ * Free's bones and their properties.
+ */
void ED_armature_ebone_listbase_free(struct ListBase *lb, const bool do_id_user);
void ED_armature_ebone_listbase_copy(struct ListBase *lb_dst,
struct ListBase *lb_src,
const bool do_id_user);
-/* low level selection functions which handle */
int ED_armature_ebone_selectflag_get(const struct EditBone *ebone);
void ED_armature_ebone_selectflag_set(struct EditBone *ebone, int flag);
void ED_armature_ebone_select_set(struct EditBone *ebone, bool select);
@@ -198,21 +297,29 @@ void ED_armature_ebone_selectflag_disable(struct EditBone *ebone, int flag);
struct Object *ED_pose_object_from_context(struct bContext *C);
bool ED_object_posemode_exit_ex(struct Main *bmain, struct Object *ob);
bool ED_object_posemode_exit(struct bContext *C, struct Object *ob);
+/** This function is used to process the necessary updates for. */
bool ED_object_posemode_enter_ex(struct Main *bmain, struct Object *ob);
bool ED_object_posemode_enter(struct bContext *C, struct Object *ob);
-/* Corresponds to eAnimvizCalcRange. */
+/** Corresponds to #eAnimvizCalcRange. */
typedef enum ePosePathCalcRange {
POSE_PATH_CALC_RANGE_CURRENT_FRAME,
POSE_PATH_CALC_RANGE_CHANGED,
POSE_PATH_CALC_RANGE_FULL,
} ePosePathCalcRange;
+/**
+ * For the object with pose/action: update paths for those that have got them
+ * This should selectively update paths that exist...
+ *
+ * To be called from various tools that do incremental updates.
+ */
void ED_pose_recalculate_paths(struct bContext *C,
struct Scene *scene,
struct Object *ob,
ePosePathCalcRange range);
/* pose_select.c */
+
void ED_armature_pose_select_pick_bone(struct ViewLayer *view_layer,
struct View3D *v3d,
struct Object *ob,
@@ -220,6 +327,10 @@ void ED_armature_pose_select_pick_bone(struct ViewLayer *view_layer,
bool extend,
bool deselect,
bool toggle);
+/**
+ * Called for mode-less pose selection.
+ * assumes the active object is still on old situation.
+ */
bool ED_armature_pose_select_pick_with_buffer(struct ViewLayer *view_layer,
struct View3D *v3d,
struct Base *base,
@@ -229,6 +340,14 @@ bool ED_armature_pose_select_pick_with_buffer(struct ViewLayer *view_layer,
bool deselect,
bool toggle,
bool do_nearest);
+/**
+ * While in weight-paint mode, a single pose may be active as well.
+ * While not common, it's possible we have multiple armatures deforming a mesh.
+ *
+ * This function de-selects all other objects, and selects the new base.
+ * It can't be set to the active object because we need
+ * to keep this set to the weight paint object.
+ */
void ED_armature_pose_select_in_wpaint_mode(struct ViewLayer *view_layer,
struct Base *base_select);
bool ED_pose_deselect_all_multi_ex(struct Base **bases,
@@ -236,8 +355,16 @@ bool ED_pose_deselect_all_multi_ex(struct Base **bases,
int select_mode,
const bool ignore_visibility);
bool ED_pose_deselect_all_multi(struct bContext *C, int select_mode, const bool ignore_visibility);
+/**
+ * 'select_mode' is usual SEL_SELECT/SEL_DESELECT/SEL_TOGGLE/SEL_INVERT.
+ * When true, 'ignore_visibility' makes this func also affect invisible bones
+ * (hidden or on hidden layers).
+ */
bool ED_pose_deselect_all(struct Object *ob, int select_mode, const bool ignore_visibility);
void ED_pose_bone_select_tag_update(struct Object *ob);
+/**
+ * Utility method for changing the selection status of a bone.
+ */
void ED_pose_bone_select(struct Object *ob, struct bPoseChannel *pchan, bool select);
/* meshlaplacian.c */
@@ -249,7 +376,9 @@ void ED_mesh_deform_bind_callback(struct MeshDeformModifierData *mmd,
/* Pose backups, pose_backup.c */
struct PoseBackup;
-/* Create a backup of those bones that are animated in the given action. */
+/**
+ * Create a backup of those bones that are animated in the given action.
+ */
struct PoseBackup *ED_pose_backup_create_selected_bones(
const struct Object *ob, const struct bAction *action) ATTR_WARN_UNUSED_RESULT;
struct PoseBackup *ED_pose_backup_create_all_bones(
diff --git a/source/blender/editors/include/ED_buttons.h b/source/blender/editors/include/ED_buttons.h
index af0643f0d64..79404aada41 100644
--- a/source/blender/editors/include/ED_buttons.h
+++ b/source/blender/editors/include/ED_buttons.h
@@ -30,6 +30,11 @@ struct ScrArea;
struct SpaceProperties;
struct bContext;
+/**
+ * Fills an array with the tab context values for the properties editor. -1 signals a separator.
+ *
+ * \return The total number of items in the array returned.
+ */
int ED_buttons_tabs_list(struct SpaceProperties *sbuts, short *context_tabs_array);
bool ED_buttons_tab_has_search_result(struct SpaceProperties *sbuts, const int index);
diff --git a/source/blender/editors/include/ED_clip.h b/source/blender/editors/include/ED_clip.h
index 21d8a28e2c9..6167ae3aee6 100644
--- a/source/blender/editors/include/ED_clip.h
+++ b/source/blender/editors/include/ED_clip.h
@@ -56,6 +56,9 @@ void ED_space_clip_get_zoom(struct SpaceClip *sc,
void ED_space_clip_get_aspect(struct SpaceClip *sc, float *aspx, float *aspy);
void ED_space_clip_get_aspect_dimension_aware(struct SpaceClip *sc, float *aspx, float *aspy);
+/**
+ * Return current frame number in clip space.
+ */
int ED_space_clip_get_clip_frame_number(struct SpaceClip *sc);
struct ImBuf *ED_space_clip_get_buffer(struct SpaceClip *sc);
@@ -65,9 +68,12 @@ struct ImBuf *ED_space_clip_get_stable_buffer(struct SpaceClip *sc,
float *angle);
bool ED_space_clip_get_position(struct SpaceClip *sc,
- struct ARegion *ar,
+ struct ARegion *region,
int mval[2],
float fpos[2]);
+/**
+ * Returns color in linear space, matching #ED_space_image_color_sample().
+ */
bool ED_space_clip_color_sample(struct SpaceClip *sc,
struct ARegion *region,
int mval[2],
@@ -82,10 +88,17 @@ bool ED_clip_can_select(struct bContext *C);
void ED_clip_point_undistorted_pos(struct SpaceClip *sc, const float co[2], float r_co[2]);
void ED_clip_point_stable_pos(
struct SpaceClip *sc, struct ARegion *region, float x, float y, float *xr, float *yr);
+/**
+ * \brief the reverse of #ED_clip_point_stable_pos(), gets the marker region coords.
+ * better name here? view_to_track / track_to_view or so?
+ */
void ED_clip_point_stable_pos__reverse(struct SpaceClip *sc,
struct ARegion *region,
const float co[2],
float r_co[2]);
+/**
+ * Takes `event->mval`.
+ */
void ED_clip_mouse_pos(struct SpaceClip *sc,
struct ARegion *region,
const int mval[2],
diff --git a/source/blender/editors/include/ED_curve.h b/source/blender/editors/include/ED_curve.h
index 44c5897d3a3..805d42b6fbc 100644
--- a/source/blender/editors/include/ED_curve.h
+++ b/source/blender/editors/include/ED_curve.h
@@ -43,14 +43,22 @@ struct wmKeyConfig;
struct wmOperator;
/* curve_ops.c */
+
void ED_operatortypes_curve(void);
void ED_operatormacros_curve(void);
void ED_keymap_curve(struct wmKeyConfig *keyconf);
/* editcurve.c */
+
struct ListBase *object_editcurve_get(struct Object *ob);
+/**
+ * Load editNurb in object.
+ */
void ED_curve_editnurb_load(struct Main *bmain, struct Object *obedit);
+/**
+ * Make copy in `cu->editnurb`.
+ */
void ED_curve_editnurb_make(struct Object *obedit);
void ED_curve_editnurb_free(struct Object *obedit);
@@ -65,9 +73,14 @@ int ED_curve_nurb_select_count(const struct View3D *v3d, const struct Nurb *nu);
bool ED_curve_nurb_select_all(const struct Nurb *nu);
bool ED_curve_nurb_deselect_all(const struct Nurb *nu);
+/**
+ * This is used externally, by #OBJECT_OT_join.
+ * TODO: shape keys - as with meshes.
+ */
int ED_curve_join_objects_exec(struct bContext *C, struct wmOperator *op);
/* editcurve_select.c */
+
bool ED_curve_select_check(const struct View3D *v3d, const struct EditNurb *editnurb);
bool ED_curve_deselect_all(struct EditNurb *editnurb);
bool ED_curve_deselect_all_multi_ex(struct Base **bases, int bases_len);
@@ -77,9 +90,12 @@ bool ED_curve_select_swap(struct EditNurb *editnurb, bool hide_handles);
int ED_curve_select_count(const struct View3D *v3d, const struct EditNurb *editnurb);
/* editcurve_undo.c */
+
+/** Export for ED_undo_sys */
void ED_curve_undosys_type(struct UndoType *ut);
/* editfont.c */
+
void ED_curve_editfont_load(struct Object *obedit);
void ED_curve_editfont_make(struct Object *obedit);
void ED_curve_editfont_free(struct Object *obedit);
@@ -92,14 +108,22 @@ void ED_curve_beztcpy(struct EditNurb *editnurb,
int count);
void ED_curve_bpcpy(struct EditNurb *editnurb, struct BPoint *dst, struct BPoint *src, int count);
+/**
+ * Return 0 if animation data wasn't changed, 1 otherwise.
+ */
int ED_curve_updateAnimPaths(struct Main *bmain, struct Curve *cu);
bool ED_curve_active_center(struct Curve *cu, float center[3]);
+/**
+ * TextBox selection
+ */
bool ED_curve_editfont_select_pick(
struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
/* editfont_undo.c */
+
+/** Export for ED_undo_sys. */
void ED_font_undosys_type(struct UndoType *ut);
#if 0
diff --git a/source/blender/editors/include/ED_file_indexer.h b/source/blender/editors/include/ED_file_indexer.h
new file mode 100644
index 00000000000..0afa8819def
--- /dev/null
+++ b/source/blender/editors/include/ED_file_indexer.h
@@ -0,0 +1,153 @@
+/*
+ * 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 edfile
+ */
+
+#pragma once
+
+#include "BLO_readfile.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * File indexing for the file/asset browser.
+ *
+ * This file contains an API to create indexing functionality when listing blend files in
+ * the file browser.
+ *
+ * To implement a custom indexer a `FileIndexerType` struct should be made and passed to the
+ * `filelist_setindexer` function.
+ */
+
+struct AssetLibraryReference;
+struct LinkNode;
+
+/**
+ * Result code of the `read_index` callback.
+ */
+typedef enum eFileIndexerResult {
+ /**
+ * File listing entries are loaded from the index. Reading entries from the blend file itself
+ * should be skipped.
+ */
+ FILE_INDEXER_ENTRIES_LOADED,
+
+ /**
+ * Index isn't available or not up to date. Entries should be read from the blend file and
+ * `update_index` must be called to update the index.
+ */
+ FILE_INDEXER_NEEDS_UPDATE,
+} eFileIndexerResult;
+
+/**
+ * FileIndexerEntry contains all data that is required to create a file listing entry.
+ */
+typedef struct FileIndexerEntry {
+ struct BLODataBlockInfo datablock_info;
+ short idcode;
+} FileIndexerEntry;
+
+/**
+ * Contains all entries of a blend file.
+ */
+typedef struct FileIndexerEntries {
+ struct LinkNode /* FileIndexerEntry */ *entries;
+} FileIndexerEntries;
+
+typedef void *(*FileIndexerInitUserDataFunc)(const char *root_directory,
+ size_t root_directory_maxlen);
+typedef void (*FileIndexerFreeUserDataFunc)(void *);
+typedef void (*FileIndexerFinishedFunc)(void *);
+typedef eFileIndexerResult (*FileIndexerReadIndexFunc)(const char *file_name,
+ FileIndexerEntries *entries,
+ int *r_read_entries_len,
+ void *user_data);
+typedef void (*FileIndexerUpdateIndexFunc)(const char *file_name,
+ FileIndexerEntries *entries,
+ void *user_data);
+
+typedef struct FileIndexerType {
+ /**
+ * Is called at the beginning of the file listing process. An indexer can
+ * setup needed data. The result of this function will be passed around as `user_data` parameter.
+ *
+ * This is an optional callback.
+ */
+ FileIndexerInitUserDataFunc init_user_data;
+
+ /**
+ * Is called at the end of the file listing process. An indexer can free the data that it created
+ * during the file listing process.
+ *
+ * This is an optional callback */
+ FileIndexerFreeUserDataFunc free_user_data;
+
+ /**
+ * Is called at the end of the file listing process (before the `free_user_data`) where indexes
+ * can perform clean-ups.
+ *
+ * This is an optional callback. Called when listing files completed.
+ */
+ FileIndexerFinishedFunc filelist_finished;
+
+ /**
+ * Is called for each blend file being listed to read data from the index.
+ *
+ * Read entries should be added to given `entries` parameter (type: `FileIndexerEntries`).
+ * `*r_read_entries_len` must be set to the number of read entries.
+ * and the function must return `eFileIndexerResult::FILE_INDEXER_ENTRIES_LOADED`.
+ * In this case the blend file will not be opened and the FileIndexerEntry added to `entries`
+ * will be used as the content of the file.
+ *
+ * When the index isn't available or could not be used no entries must be added to the
+ * entries field, `r_read_entries_len` must be set to `0` and the function must return
+ * `eFileIndexerResult::FILE_INDEXER_NEEDS_UPDATE`. In this case the blend file will read from
+ * the blend file and the `update_index` function will be called.
+ */
+ FileIndexerReadIndexFunc read_index;
+
+ /**
+ * Update an index of a blend file.
+ *
+ * Is called after reading entries from the file when the result of `read_index` was
+ * `eFileIndexerResult::FILE_INDEXER_NEED_UPDATE`. The callback should update the index so the
+ * next time that read_index is called it will read the entries from the index.
+ */
+ FileIndexerUpdateIndexFunc update_index;
+} FileIndexerType;
+
+/* file_indexer.cc */
+
+/** Removes all entries inside the given `indexer_entries`. */
+void ED_file_indexer_entries_clear(FileIndexerEntries *indexer_entries);
+
+/**
+ * Adds all entries from the given `datablock_infos` to the `indexer_entries`.
+ * The datablock_infos must only contain data for a single IDType. The specific IDType must be
+ * passed in the `idcode` parameter.
+ */
+void ED_file_indexer_entries_extend_from_datablock_infos(
+ FileIndexerEntries *indexer_entries,
+ const LinkNode * /* BLODataBlockInfo */ datablock_infos,
+ const int idcode);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/editors/include/ED_fileselect.h b/source/blender/editors/include/ED_fileselect.h
index 68b6e44371c..460de58bdb2 100644
--- a/source/blender/editors/include/ED_fileselect.h
+++ b/source/blender/editors/include/ED_fileselect.h
@@ -105,12 +105,26 @@ typedef struct FileSelection {
struct View2D;
struct rcti;
+/**
+ * If needed, create and return the file select parameters for the active browse mode.
+ */
struct FileSelectParams *ED_fileselect_ensure_active_params(struct SpaceFile *sfile);
+/**
+ * Get the file select parameters for the active browse mode.
+ */
struct FileSelectParams *ED_fileselect_get_active_params(const struct SpaceFile *sfile);
struct FileSelectParams *ED_fileselect_get_file_params(const struct SpaceFile *sfile);
struct FileAssetSelectParams *ED_fileselect_get_asset_params(const struct SpaceFile *sfile);
+bool ED_fileselect_is_local_asset_library(const struct SpaceFile *sfile);
void ED_fileselect_set_params_from_userdef(struct SpaceFile *sfile);
+/**
+ * Update the user-preference data for the file space. In fact, this also contains some
+ * non-FileSelectParams data, but we can safely ignore this.
+ *
+ * \param temp_win_size: If the browser was opened in a temporary window,
+ * pass its size here so we can store that in the preferences. Otherwise NULL.
+ */
void ED_fileselect_params_to_userdef(struct SpaceFile *sfile,
const int temp_win_size[2],
const bool is_maximized);
@@ -123,6 +137,10 @@ int ED_fileselect_layout_numfiles(FileLayout *layout, struct ARegion *region);
int ED_fileselect_layout_offset(FileLayout *layout, int x, int y);
FileSelection ED_fileselect_layout_offset_rect(FileLayout *layout, const struct rcti *rect);
+/**
+ * Get the currently visible bounds of the layout in screen space. Matches View2D.mask minus the
+ * top column-header row.
+ */
void ED_fileselect_layout_maskrect(const FileLayout *layout,
const struct View2D *v2d,
struct rcti *r_rect);
@@ -149,8 +167,10 @@ struct ID *ED_fileselect_active_asset_get(const struct SpaceFile *sfile);
void ED_fileselect_activate_asset_catalog(const struct SpaceFile *sfile, bUUID catalog_id);
-/* Activate and select the file that corresponds to the given ID.
- * Pass deferred=true to wait for the next refresh before activating. */
+/**
+ * Activate and select the file that corresponds to the given ID.
+ * Pass deferred=true to wait for the next refresh before activating.
+ */
void ED_fileselect_activate_by_id(struct SpaceFile *sfile,
struct ID *asset_id,
const bool deferred);
@@ -165,12 +185,18 @@ void ED_fileselect_window_params_get(const struct wmWindow *win,
struct ScrArea *ED_fileselect_handler_area_find(const struct wmWindow *win,
const struct wmOperator *file_operator);
+/* TODO: Maybe we should move this to BLI?
+ * On the other hand, it's using defines from space-file area, so not sure... */
int ED_path_extension_type(const char *path);
int ED_file_extension_icon(const char *path);
int ED_file_icon(const struct FileDirEntry *file);
void ED_file_read_bookmarks(void);
+/**
+ * Support updating the directory even when this isn't the active space
+ * needed so RNA properties update function isn't context sensitive, see T70255.
+ */
void ED_file_change_dir_ex(struct bContext *C, struct ScrArea *area);
void ED_file_change_dir(struct bContext *C);
diff --git a/source/blender/editors/include/ED_gizmo_library.h b/source/blender/editors/include/ED_gizmo_library.h
index 4d922162ee9..55beff40177 100644
--- a/source/blender/editors/include/ED_gizmo_library.h
+++ b/source/blender/editors/include/ED_gizmo_library.h
@@ -92,7 +92,17 @@ enum {
ED_GIZMO_ARROW_DRAW_FLAG_STEM = (1 << 0),
};
+/**
+ * Define a custom property UI range.
+ *
+ * \note Needs to be called before #WM_gizmo_target_property_def_rna!
+ */
void ED_gizmo_arrow3d_set_ui_range(struct wmGizmo *gz, const float min, const float max);
+/**
+ * Define a custom factor for arrow min/max distance.
+ *
+ * \note Needs to be called before #WM_gizmo_target_property_def_rna!
+ */
void ED_gizmo_arrow3d_set_range_fac(struct wmGizmo *gz, const float range_fac);
/* -------------------------------------------------------------------- */
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index 1cf15ce3a48..99164bbe439 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -116,42 +116,97 @@ typedef struct tGPspoint {
/* ----------- Grease Pencil Tools/Context ------------- */
/* Context-dependent */
+
+/**
+ * Get pointer to active Grease Pencil data-block,
+ * and an RNA-pointer to trace back to whatever owns it.
+ */
struct bGPdata **ED_gpencil_data_get_pointers(const struct bContext *C, struct PointerRNA *r_ptr);
+/**
+ * Get the active Grease Pencil data-block
+ */
struct bGPdata *ED_gpencil_data_get_active(const struct bContext *C);
+/**
+ * Get the evaluated copy of the active Grease Pencil data-block (where applicable)
+ * - For the 3D View (i.e. "GP Objects"), this gives the evaluated copy of the GP data-block
+ * (i.e. a copy of the active GP data-block for the active object, where modifiers have been
+ * applied). This is needed to correctly work with "Copy-on-Write".
+ * - For all other editors (i.e. "GP Annotations"), this just gives the active data-block
+ * like for #ED_gpencil_data_get_active()
+ */
struct bGPdata *ED_gpencil_data_get_active_evaluated(const struct bContext *C);
-/* Context independent (i.e. each required part is passed in instead) */
+/**
+ * Context independent (i.e. each required part is passed in instead).
+ *
+ * Get pointer to active Grease Pencil data-block,
+ * and an RNA-pointer to trace back to whatever owns it,
+ * when context info is not available.
+ */
struct bGPdata **ED_gpencil_data_get_pointers_direct(struct ScrArea *area,
struct Object *ob,
struct PointerRNA *r_ptr);
+/* Get the active Grease Pencil data-block, when context is not available */
struct bGPdata *ED_gpencil_data_get_active_direct(struct ScrArea *area, struct Object *ob);
+/**
+ * Get the active Grease Pencil data-block
+ * \note This is the original (#G.main) copy of the data-block, stored in files.
+ * Do not use for reading evaluated copies of GP Objects data.
+ */
struct bGPdata *ED_annotation_data_get_active(const struct bContext *C);
+/**
+ * Get pointer to active Grease Pencil data-block,
+ * and an RNA-pointer to trace back to whatever owns it.
+ */
struct bGPdata **ED_annotation_data_get_pointers(const struct bContext *C,
struct PointerRNA *r_ptr);
+/**
+ * Get pointer to active Grease Pencil data-block for annotations,
+ * and an RNA-pointer to trace back to whatever owns it,
+ * when context info is not available.
+ */
struct bGPdata **ED_annotation_data_get_pointers_direct(struct ID *screen_id,
struct ScrArea *area,
struct Scene *scene,
struct PointerRNA *r_ptr);
+/**
+ * Get the active Grease Pencil data-block, when context is not available.
+ */
struct bGPdata *ED_annotation_data_get_active_direct(struct ID *screen_id,
struct ScrArea *area,
struct Scene *scene);
+/**
+ * Utility to check whether the r_ptr output of ED_gpencil_data_get_pointers()
+ * is for annotation usage.
+ */
bool ED_gpencil_data_owner_is_annotation(struct PointerRNA *owner_ptr);
/* 3D View */
+
+/**
+ * Check whether there's an active GP keyframe on the current frame.
+ */
bool ED_gpencil_has_keyframe_v3d(struct Scene *scene, struct Object *ob, int cfra);
/* ----------- Stroke Editing Utilities ---------------- */
bool ED_gpencil_frame_has_selected_stroke(const struct bGPDframe *gpf);
bool ED_gpencil_layer_has_selected_stroke(const struct bGPDlayer *gpl, const bool is_multiedit);
+/**
+ * Check whether given stroke can be edited given the supplied context.
+ * TODO: do we need additional flags for screen-space vs data-space?.
+ */
bool ED_gpencil_stroke_can_use_direct(const struct ScrArea *area, const struct bGPDstroke *gps);
+/* Check whether given stroke can be edited in the current context */
bool ED_gpencil_stroke_can_use(const struct bContext *C, const struct bGPDstroke *gps);
+/* Check whether given stroke can be edited for the current color */
bool ED_gpencil_stroke_material_editable(struct Object *ob,
const struct bGPDlayer *gpl,
const struct bGPDstroke *gps);
+/* Check whether given stroke is visible for the current material. */
bool ED_gpencil_stroke_material_visible(struct Object *ob, const struct bGPDstroke *gps);
/* ----------- Grease Pencil Operators ----------------- */
@@ -164,13 +219,32 @@ void ED_operatormacros_gpencil(void);
/* ------------- Copy-Paste Buffers -------------------- */
/* Strokes copybuf */
+
+/**
+ * Free copy/paste buffer data.
+ */
void ED_gpencil_strokes_copybuf_free(void);
/* ------------ Grease-Pencil Drawing API ------------------ */
/* drawgpencil.c */
+/**
+ * Draw grease-pencil sketches to specified 2d-view that uses ibuf corrections.
+ */
void ED_annotation_draw_2dimage(const struct bContext *C);
+/**
+ * Draw grease-pencil sketches to specified 2d-view
+ * assuming that matrices are already set correctly.
+ *
+ * \note This gets called twice - first time with onlyv2d=true to draw 'canvas' strokes,
+ * second time with onlyv2d=false for screen-aligned strokes.
+ */
void ED_annotation_draw_view2d(const struct bContext *C, bool onlyv2d);
+/**
+ * Draw annotations sketches to specified 3d-view assuming that matrices are already set correctly.
+ * NOTE: this gets called twice - first time with only3d=true to draw 3d-strokes,
+ * second time with only3d=false for screen-aligned strokes.
+ */
void ED_annotation_draw_view3d(struct Scene *scene,
struct Depsgraph *depsgraph,
struct View3D *v3d,
@@ -184,43 +258,103 @@ void ED_annotation_draw_ex(struct Scene *scene,
const char spacetype);
/* ----------- Grease-Pencil AnimEdit API ------------------ */
+/**
+ * Loops over the gp-frames for a gp-layer, and applies the given callback.
+ */
bool ED_gpencil_layer_frames_looper(struct bGPDlayer *gpl,
struct Scene *scene,
bool (*gpf_cb)(struct bGPDframe *, struct Scene *));
+/**
+ * Make a listing all the gp-frames in a layer as cfraelems.
+ */
void ED_gpencil_layer_make_cfra_list(struct bGPDlayer *gpl, ListBase *elems, bool onlysel);
+/**
+ * Check if one of the frames in this layer is selected.
+ */
bool ED_gpencil_layer_frame_select_check(const struct bGPDlayer *gpl);
+/**
+ * Set all/none/invert select.
+ */
void ED_gpencil_layer_frame_select_set(struct bGPDlayer *gpl, short mode);
+/**
+ * Select the frames in this layer that occur within the bounds specified.
+ */
void ED_gpencil_layer_frames_select_box(struct bGPDlayer *gpl,
float min,
float max,
short select_mode);
+/**
+ * Select the frames in this layer that occur within the lasso/circle region specified.
+ */
void ED_gpencil_layer_frames_select_region(struct KeyframeEditData *ked,
struct bGPDlayer *gpl,
short tool,
short select_mode);
+/**
+ * Set all/none/invert select (like above, but with SELECT_* modes).
+ */
void ED_gpencil_select_frames(struct bGPDlayer *gpl, short select_mode);
+/**
+ * Select the frame in this layer that occurs on this frame (there should only be one at most).
+ */
void ED_gpencil_select_frame(struct bGPDlayer *gpl, int selx, short select_mode);
+/**
+ * Delete selected frames.
+ */
bool ED_gpencil_layer_frames_delete(struct bGPDlayer *gpl);
+/**
+ * Duplicate selected frames from given gp-layer.
+ */
void ED_gpencil_layer_frames_duplicate(struct bGPDlayer *gpl);
+/**
+ * Merge two layers.
+ */
void ED_gpencil_layer_merge(struct bGPdata *gpd,
struct bGPDlayer *gpl_src,
struct bGPDlayer *gpl_dst,
const bool reverse);
+/**
+ * Set keyframe type for selected frames from given gp-layer
+ *
+ * \param type: The type of keyframe (#eBezTriple_KeyframeType) to set selected frames to.
+ */
void ED_gpencil_layer_frames_keytype_set(struct bGPDlayer *gpl, short type);
-
+/**
+ * Snap selected frames to ....
+ */
void ED_gpencil_layer_snap_frames(struct bGPDlayer *gpl, struct Scene *scene, short mode);
+
+/**
+ * Mirror selected gp-frames on...
+ * TODO: mirror over a specific time.
+ */
void ED_gpencil_layer_mirror_frames(struct bGPDlayer *gpl, struct Scene *scene, short mode);
+/**
+ * This function frees any MEM_calloc'ed copy/paste buffer data.
+ */
void ED_gpencil_anim_copybuf_free(void);
+/**
+ * This function adds data to the copy/paste buffer, freeing existing data first
+ * Only the selected GP-layers get their selected keyframes copied.
+ *
+ * Returns whether the copy operation was successful or not.
+ */
bool ED_gpencil_anim_copybuf_copy(struct bAnimContext *ac);
+/**
+ * Pastes keyframes from buffer, and reports success.
+ */
bool ED_gpencil_anim_copybuf_paste(struct bAnimContext *ac, const short copy_mode);
/* ------------ Grease-Pencil Undo System ------------------ */
int ED_gpencil_session_active(void);
+/**
+ * \param step: eUndoStepDir.
+ */
int ED_undo_gpencil_step(struct bContext *C, const int step); /* eUndoStepDir. */
/* ------------ Grease-Pencil Armature ------------------ */
@@ -234,7 +368,10 @@ bool ED_gpencil_add_armature_weights(const struct bContext *C,
struct Object *ob_arm,
int mode);
-/* Add Lattice modifier using Parent operator */
+/**
+ * Add Lattice modifier using Parent operator.
+ * Parent GPencil object to Lattice.
+ */
bool ED_gpencil_add_lattice_modifier(const struct bContext *C,
struct ReportList *reports,
struct Object *ob,
@@ -246,37 +383,74 @@ bool ED_gpencil_add_lattice_modifier(const struct bContext *C,
/* ------------ Transformation Utilities ------------ */
-/* reset parent matrix for all layers */
+/**
+ * Reset parent matrix for all layers.
+ */
void ED_gpencil_reset_layers_parent(struct Depsgraph *depsgraph,
struct Object *obact,
struct bGPdata *gpd);
-/* cursor utilities */
+/* Cursor utilities. */
+
+/**
+ * Draw eraser cursor.
+ */
void ED_gpencil_brush_draw_eraser(struct Brush *brush, int x, int y);
/* ----------- Add Primitive Utilities -------------- */
-/* Number of values defining each point in the built-in data buffers for primitives. */
+/** Number of values defining each point in the built-in data buffers for primitives. */
#define GP_PRIM_DATABUF_SIZE 5
+/**
+ * Populate stroke with point data from data buffers.
+ * \param gps: Grease pencil stroke
+ * \param array: Flat array of point data values. Each entry has #GP_PRIM_DATABUF_SIZE values.
+ * \param totpoints: Total of points
+ * \param mat: 4x4 transform matrix to transform points into the right coordinate space.
+ */
void ED_gpencil_stroke_init_data(struct bGPDstroke *gps,
const float *array,
const int totpoints,
const float mat[4][4]);
+/**
+ * Add a Simple empty object with one layer and one color.
+ */
void ED_gpencil_create_blank(struct bContext *C, struct Object *ob, float mat[4][4]);
+/**
+ * Add a 2D Suzanne (original model created by Matias Mendiola).
+ */
void ED_gpencil_create_monkey(struct bContext *C, struct Object *ob, float mat[4][4]);
+/**
+ * Add a Simple stroke with colors
+ * (original design created by Daniel M. Lara and Matias Mendiola).
+ */
void ED_gpencil_create_stroke(struct bContext *C, struct Object *ob, float mat[4][4]);
+/**
+ * Add a Simple LineArt setup.
+ */
void ED_gpencil_create_lineart(struct bContext *C, struct Object *ob);
/* ------------ Object Utilities ------------ */
+/**
+ * Helper function to create new #OB_GPENCIL Object.
+ */
struct Object *ED_gpencil_add_object(struct bContext *C,
const float loc[3],
unsigned short local_view_bits);
+/**
+ * Helper function to create default colors and drawing brushes.
+ */
void ED_gpencil_add_defaults(struct bContext *C, struct Object *ob);
-/* set object modes */
+/**
+ * Set object modes.
+ */
void ED_gpencil_setup_modes(struct bContext *C, struct bGPdata *gpd, int newmode);
bool ED_object_gpencil_exit(struct Main *bmain, struct Object *ob);
+/**
+ * Reproject all points of the stroke to a plane locked to axis to avoid stroke offset
+ */
void ED_gpencil_project_stroke_to_plane(const struct Scene *scene,
const struct Object *ob,
const struct RegionView3D *rv3d,
@@ -284,6 +458,10 @@ void ED_gpencil_project_stroke_to_plane(const struct Scene *scene,
struct bGPDstroke *gps,
const float origin[3],
const int axis);
+/**
+ * Reproject given point to a plane locked to axis to avoid stroke offset
+ * \param pt: Point to affect (used for input & output).
+ */
void ED_gpencil_project_point_to_plane(const struct Scene *scene,
const struct Object *ob,
struct bGPDlayer *gpl,
@@ -291,14 +469,21 @@ void ED_gpencil_project_point_to_plane(const struct Scene *scene,
const float origin[3],
const int axis,
struct bGPDspoint *pt);
+/**
+ * Get drawing reference point for conversion or projection of the stroke
+ * \param r_vec: Reference point found
+ */
void ED_gpencil_drawing_reference_get(const struct Scene *scene,
const struct Object *ob,
char align_flag,
- float vec[3]);
+ float r_vec[3]);
void ED_gpencil_project_stroke_to_view(struct bContext *C,
struct bGPDlayer *gpl,
struct bGPDstroke *gps);
+/**
+ * Reproject selected strokes.
+ */
void ED_gpencil_stroke_reproject(struct Depsgraph *depsgraph,
const struct GP_SpaceConversion *gsc,
struct SnapObjectContext *sctx,
@@ -308,27 +493,54 @@ void ED_gpencil_stroke_reproject(struct Depsgraph *depsgraph,
const eGP_ReprojectModes mode,
const bool keep_original);
-/* set sculpt cursor */
+/**
+ * Turn brush cursor in on/off.
+ */
void ED_gpencil_toggle_brush_cursor(struct bContext *C, bool enable, void *customdata);
/* vertex groups */
+
+/**
+ * Assign points to vertex group.
+ */
void ED_gpencil_vgroup_assign(struct bContext *C, struct Object *ob, float weight);
+/**
+ * Remove points from vertex group.
+ */
void ED_gpencil_vgroup_remove(struct bContext *C, struct Object *ob);
+/**
+ * Select points of vertex group.
+ */
void ED_gpencil_vgroup_select(struct bContext *C, struct Object *ob);
+/**
+ * Unselect points of vertex group.
+ */
void ED_gpencil_vgroup_deselect(struct bContext *C, struct Object *ob);
/* join objects */
+
+/**
+ * Join objects called from OBJECT_OT_join.
+ */
int ED_gpencil_join_objects_exec(struct bContext *C, struct wmOperator *op);
/* texture coordinate utilities */
+
+/**
+ * Convert 2d #tGPspoint to 3d #bGPDspoint.
+ */
void ED_gpencil_tpoint_to_point(struct ARegion *region,
float origin[3],
const struct tGPspoint *tpt,
struct bGPDspoint *pt);
+/**
+ * Recalculate UV for any stroke using the material.
+ */
void ED_gpencil_update_color_uv(struct Main *bmain, struct Material *mat);
-/* extend selection to stroke intersections
- * returns:
+/**
+ * Extend selection to stroke intersections:
+ * \returns:
* 0 - No hit
* 1 - Hit in point A
* 2 - Hit in point B
@@ -347,17 +559,23 @@ int ED_gpencil_select_stroke_segment(struct bGPdata *gpd,
void ED_gpencil_select_toggle_all(struct bContext *C, int action);
void ED_gpencil_select_curve_toggle_all(struct bContext *C, int action);
-/* Ensure stroke sbuffer size is enough */
+/**
+ * Ensure the #tGPspoint buffer (while drawing stroke)
+ * size is enough to save all points of the stroke.
+ */
struct tGPspoint *ED_gpencil_sbuffer_ensure(struct tGPspoint *buffer_array,
int *buffer_size,
int *buffer_used,
const bool clear);
void ED_gpencil_sbuffer_update_eval(struct bGPdata *gpd, struct Object *ob_eval);
-/* Tag all scene grease pencil object to update. */
+/**
+ * Tag all scene grease pencil object to update.
+ */
void ED_gpencil_tag_scene_gpencil(struct Scene *scene);
/* Vertex color set. */
+
void ED_gpencil_fill_vertex_color_set(struct ToolSettings *ts,
struct Brush *brush,
struct bGPDstroke *gps);
@@ -376,15 +594,30 @@ void ED_gpencil_init_random_settings(struct Brush *brush,
const int mval[2],
struct GpRandomSettings *random_settings);
+/**
+ * Check if the stroke collides with brush.
+ */
bool ED_gpencil_stroke_check_collision(const struct GP_SpaceConversion *gsc,
struct bGPDstroke *gps,
const float mouse[2],
const int radius,
const float diff_mat[4][4]);
+/**
+ * Check if a point is inside of the stroke.
+ *
+ * \param gps: Stroke to check.
+ * \param gsc: Space conversion data.
+ * \param mouse: Mouse position.
+ * \param diff_mat: View matrix.
+ * \return True if the point is inside.
+ */
bool ED_gpencil_stroke_point_is_inside(const struct bGPDstroke *gps,
const struct GP_SpaceConversion *gsc,
const int mouse[2],
const float diff_mat[4][4]);
+/**
+ * Get the bigger 2D bound box points.
+ */
void ED_gpencil_projected_2d_bound_box(const struct GP_SpaceConversion *gsc,
const struct bGPDstroke *gps,
const float diff_mat[4][4],
@@ -400,18 +633,27 @@ struct bGPDstroke *ED_gpencil_stroke_nearest_to_ends(struct bContext *C,
const float ctrl2[2],
const float radius,
int *r_index);
+/**
+ * Get extremes of stroke in 2D using current view.
+ */
void ED_gpencil_stroke_extremes_to2d(const struct GP_SpaceConversion *gsc,
const float diff_mat[4][4],
struct bGPDstroke *gps,
float r_ctrl1[2],
float r_ctrl2[2]);
+/**
+ * Join two stroke using a contact point index and trimming the rest.
+ */
struct bGPDstroke *ED_gpencil_stroke_join_and_trim(struct bGPdata *gpd,
struct bGPDframe *gpf,
struct bGPDstroke *gps,
struct bGPDstroke *gps_dst,
const int pt_index);
+/**
+ * Close if the distance between extremes is below threshold.
+ */
void ED_gpencil_stroke_close_by_distance(struct bGPDstroke *gps, const float threshold);
#ifdef __cplusplus
diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h
index 1400bcf5ee3..3308ae2c178 100644
--- a/source/blender/editors/include/ED_image.h
+++ b/source/blender/editors/include/ED_image.h
@@ -48,11 +48,17 @@ float ED_space_image_zoom_level(const struct View2D *v2d, const int grid_dimensi
void ED_space_image_grid_steps(struct SpaceImage *sima,
float grid_steps[SI_GRID_STEPS_LEN],
const int grid_dimension);
+/**
+ * Calculate the increment snapping value for UV/image editor based on the zoom factor
+ * The code in here (except the offset part) is used in `grid_frag.glsl` (see `grid_res`) for
+ * drawing the grid overlay for the UV/Image editor.
+ */
float ED_space_image_increment_snap_value(const int grid_dimesnions,
const float grid_steps[SI_GRID_STEPS_LEN],
const float zoom_factor);
-/* image_edit.c, exported for transform */
+/* image_edit.c, exported for transform. */
+
struct Image *ED_space_image(const struct SpaceImage *sima);
void ED_space_image_set(struct Main *bmain,
struct SpaceImage *sima,
@@ -62,13 +68,22 @@ void ED_space_image_auto_set(const struct bContext *C, struct SpaceImage *sima);
struct Mask *ED_space_image_get_mask(const struct SpaceImage *sima);
void ED_space_image_set_mask(struct bContext *C, struct SpaceImage *sima, struct Mask *mask);
+/**
+ * Returns mouse position in image space.
+ */
bool ED_space_image_get_position(struct SpaceImage *sima,
struct ARegion *region,
int mval[2],
float fpos[2]);
+/**
+ * Returns color in linear space, matching #ED_space_node_color_sample().
+ */
bool ED_space_image_color_sample(
struct SpaceImage *sima, struct ARegion *region, int mval[2], float r_col[3], bool *r_is_data);
struct ImBuf *ED_space_image_acquire_buffer(struct SpaceImage *sima, void **r_lock, int tile);
+/**
+ * Get the #SpaceImage flag that is valid for the given ibuf.
+ */
int ED_space_image_get_display_channel_mask(struct ImBuf *ibuf);
void ED_space_image_release_buffer(struct SpaceImage *sima, struct ImBuf *ibuf, void *lock);
bool ED_space_image_has_buffer(struct SpaceImage *sima);
@@ -87,6 +102,12 @@ void ED_space_image_scopes_update(const struct bContext *C,
struct ImBuf *ibuf,
bool use_view_settings);
+/**
+ * Enable the paint cursor if it isn't already.
+ *
+ * purpose is to make sure the paint cursor is shown if paint mode is enabled in the image editor.
+ * The paint poll will ensure that the cursor is hidden when not in paint mode.
+ */
void ED_space_image_paint_update(struct Main *bmain,
struct wmWindowManager *wm,
struct Scene *scene);
@@ -95,6 +116,7 @@ void ED_image_get_uv_aspect(struct Image *ima,
struct ImageUser *iuser,
float *r_aspx,
float *r_aspy);
+/** Takes `event->mval`. */
void ED_image_mouse_pos(struct SpaceImage *sima,
const struct ARegion *region,
const int mval[2],
@@ -110,6 +132,10 @@ void ED_image_point_pos__reverse(struct SpaceImage *sima,
const struct ARegion *region,
const float co[2],
float r_co[2]);
+/**
+ * This is more a user-level functionality, for going to `next/prev` used slot,
+ * Stepping onto the last unused slot too.
+ */
bool ED_image_slot_cycle(struct Image *image, int direction);
bool ED_space_image_show_render(const struct SpaceImage *sima);
@@ -118,11 +144,17 @@ bool ED_space_image_show_uvedit(const struct SpaceImage *sima, struct Object *ob
bool ED_space_image_paint_curve(const struct bContext *C);
+/**
+ * Matches clip function.
+ */
bool ED_space_image_check_show_maskedit(struct SpaceImage *sima, struct Object *obedit);
bool ED_space_image_maskedit_poll(struct bContext *C);
bool ED_space_image_maskedit_mask_poll(struct bContext *C);
bool ED_space_image_cursor_poll(struct bContext *C);
+/**
+ * Used by node view too.
+ */
void ED_image_draw_info(struct Scene *scene,
struct ARegion *region,
bool color_manage,
@@ -161,6 +193,9 @@ typedef struct ImageFrameRange {
ListBase frames;
} ImageFrameRange;
+/**
+ * Used for both images and volume file loading.
+ */
ListBase ED_image_filesel_detect_sequences(struct Main *bmain,
struct wmOperator *op,
const bool detect_udim);
diff --git a/source/blender/editors/include/ED_info.h b/source/blender/editors/include/ED_info.h
index dde26c072d0..caf76841bcd 100644
--- a/source/blender/editors/include/ED_info.h
+++ b/source/blender/editors/include/ED_info.h
@@ -39,6 +39,11 @@ const char *ED_info_statistics_string(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer);
+/**
+ * \param v3d_local: Pass this argument to calculate view-port local statistics.
+ * Note that this must only be used for local-view, otherwise report specific statistics
+ * will be written into the global scene statistics giving incorrect results.
+ */
void ED_info_draw_stats(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,
diff --git a/source/blender/editors/include/ED_keyframes_edit.h b/source/blender/editors/include/ED_keyframes_edit.h
index e29ff3ed890..bafe68bd28d 100644
--- a/source/blender/editors/include/ED_keyframes_edit.h
+++ b/source/blender/editors/include/ED_keyframes_edit.h
@@ -39,7 +39,9 @@ struct bDopeSheet;
/* ************************************************ */
/* Common Macros and Defines */
-/* --------- Tool Flags ------------ */
+/* -------------------------------------------------------------------- */
+/** \name Tool Flags
+ * \{ */
/* bezt validation */
typedef enum eEditKeyframes_Validate {
@@ -60,7 +62,7 @@ typedef enum eEditKeyframes_Validate {
BEZT_OK_CHANNEL_CIRCLE,
} eEditKeyframes_Validate;
-/* ------------ */
+/** \} */
/* select modes */
typedef enum eEditKeyframes_Select {
@@ -120,7 +122,9 @@ typedef struct KeyframeEdit_CircleData {
/* ************************************************ */
/* Non-Destructive Editing API (keyframes_edit.c) */
-/* --- Defines for 'OK' polls + KeyframeEditData Flags --------- */
+/* -------------------------------------------------------------------- */
+/** \name Defines for 'OK' polls + KeyframeEditData Flags
+ * \{ */
/* which verts of a keyframe is active (after polling) */
typedef enum eKeyframeVertOk {
@@ -154,7 +158,11 @@ typedef enum eKeyframeIterFlags {
KEYFRAME_ITER_HANDLES_DEFAULT_INVISIBLE = (1 << 3),
} eKeyframeIterFlags;
-/* --- Generic Properties for Keyframe Edit Tools ----- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Generic Properties for Keyframe Edit Tools
+ * \{ */
typedef struct KeyframeEditData {
/* generic properties/data access */
@@ -184,14 +192,22 @@ typedef struct KeyframeEditData {
eKeyframeIterFlags iterflags;
} KeyframeEditData;
-/* ------- Function Pointer Typedefs ---------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Function Pointer Typedefs
+ * \{ */
/* callback function that refreshes the F-Curve after use */
typedef void (*FcuEditFunc)(struct FCurve *fcu);
/* callback function that operates on the given BezTriple */
typedef short (*KeyframeEditFunc)(KeyframeEditData *ked, struct BezTriple *bezt);
-/* ------- Custom Data Type Defines ------------------ */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Custom Data Type Defines
+ * \{ */
/* Custom data for remapping one range to another in a fixed way */
typedef struct KeyframeEditCD_Remap {
@@ -222,18 +238,28 @@ typedef enum eKeyMergeMode {
KEYFRAME_PASTE_MERGE_OVER_RANGE_ALL,
} eKeyMergeMode;
-/* ---------------- Looping API --------------------- */
+/** \} */
-/* functions for looping over keyframes */
-/* function for working with F-Curve data only
- * (i.e. when filters have been chosen to explicitly use this) */
+/* -------------------------------------------------------------------- */
+/** \name Looping API
+ *
+ * Functions for looping over keyframes.
+ * \{ */
+
+/**
+ * This function is used to loop over BezTriples in the given F-Curve, applying a given
+ * operation on them, and optionally applies an F-Curve validation function afterwards.
+ *
+ * function for working with F-Curve data only
+ * (i.e. when filters have been chosen to explicitly use this).
+ */
short ANIM_fcurve_keyframes_loop(KeyframeEditData *ked,
struct FCurve *fcu,
KeyframeEditFunc key_ok,
KeyframeEditFunc key_cb,
FcuEditFunc fcu_cb);
-/* function for working with any type (i.e. one of the known types) of animation channel
- * - filterflag is bDopeSheet->flag (DOPESHEET_FILTERFLAG)
+/**
+ * Function for working with any type (i.e. one of the known types) of animation channel.
*/
short ANIM_animchannel_keyframes_loop(KeyframeEditData *ked,
struct bDopeSheet *ads,
@@ -241,8 +267,9 @@ short ANIM_animchannel_keyframes_loop(KeyframeEditData *ked,
KeyframeEditFunc key_ok,
KeyframeEditFunc key_cb,
FcuEditFunc fcu_cb);
-/* same as above, except bAnimListElem wrapper is not needed...
- * - keytype is eAnim_KeyType
+/**
+ * Same as above, except bAnimListElem wrapper is not needed.
+ * \param keytype: is #eAnim_KeyType.
*/
short ANIM_animchanneldata_keyframes_loop(KeyframeEditData *ked,
struct bDopeSheet *ads,
@@ -252,55 +279,92 @@ short ANIM_animchanneldata_keyframes_loop(KeyframeEditData *ked,
KeyframeEditFunc key_cb,
FcuEditFunc fcu_cb);
-/* Calls callback_fn() for each keyframe in each fcurve in the filtered animation context.
- * Assumes the callback updates keys. */
+/**
+ * Calls callback_fn() for each keyframe in each fcurve in the filtered animation context.
+ * Assumes the callback updates keys.
+ */
void ANIM_animdata_keyframe_callback(struct bAnimContext *ac,
eAnimFilter_Flags filter,
KeyframeEditFunc callback_fn);
-/* functions for making sure all keyframes are in good order */
+/**
+ * Functions for making sure all keyframes are in good order.
+ */
void ANIM_editkeyframes_refresh(struct bAnimContext *ac);
-/* ----------- BezTriple Callback Getters ---------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name BezTriple Callback Getters
+ * \{ */
/* accessories */
KeyframeEditFunc ANIM_editkeyframes_ok(short mode);
/* edit */
KeyframeEditFunc ANIM_editkeyframes_snap(short mode);
+/**
+ * \note for markers and 'value', the values to use must be supplied as the first float value.
+ */
KeyframeEditFunc ANIM_editkeyframes_mirror(short mode);
KeyframeEditFunc ANIM_editkeyframes_select(short mode);
+/**
+ * Set all selected Bezier Handles to a single type.
+ */
KeyframeEditFunc ANIM_editkeyframes_handles(short mode);
+/**
+ * Set the interpolation type of the selected BezTriples in each F-Curve to the specified one.
+ */
KeyframeEditFunc ANIM_editkeyframes_ipo(short mode);
KeyframeEditFunc ANIM_editkeyframes_keytype(short mode);
KeyframeEditFunc ANIM_editkeyframes_easing(short mode);
-/* -------- BezTriple Callbacks (Selection Map) ---------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name BezTriple Callbacks (Selection Map)
+ * \{ */
-/* Get a callback to populate the selection settings map
- * requires: ked->custom = char[] of length fcurve->totvert
+/**
+ * Get a callback to populate the selection settings map
+ * requires: ked->custom = char[] of length fcurve->totvert.
*/
KeyframeEditFunc ANIM_editkeyframes_buildselmap(short mode);
-/* Change the selection status of the keyframe based on the map entry for this vert
- * requires: ked->custom = char[] of length fcurve->totvert
+/**
+ * Change the selection status of the keyframe based on the map entry for this vert
+ * requires: ked->custom = char[] of length fcurve->totvert.
*/
short bezt_selmap_flush(KeyframeEditData *ked, struct BezTriple *bezt);
-/* ----------- BezTriple Callback (Assorted Utilities) ---------- */
+/** \} */
-/* used to calculate the average location of all relevant BezTriples by summing their locations */
+/* -------------------------------------------------------------------- */
+/** \name BezTriple Callback (Assorted Utilities)
+ * \{ */
+
+/**
+ * Used to calculate the average location of all relevant BezTriples by summing their locations.
+ */
short bezt_calc_average(KeyframeEditData *ked, struct BezTriple *bezt);
-/* used to extract a set of cfra-elems from the keyframes */
+/**
+ * Used to extract a set of cfra-elems from the keyframes.
+ */
short bezt_to_cfraelem(KeyframeEditData *ked, struct BezTriple *bezt);
-/* used to remap times from one range to another
- * requires: ked->custom = KeyframeEditCD_Remap
+/**
+ * Used to remap times from one range to another.
+ * requires: `ked->custom = KeyframeEditCD_Remap`.
*/
void bezt_remap_times(KeyframeEditData *ked, struct BezTriple *bezt);
-/* ------ 1.5-D Region Testing Utilities (Lasso/Circle Select) ------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name 1.5-D Region Testing Utilities (Lasso/Circle Select)
+ * \{ */
+
/* XXX: These are temporary,
* until we can unify GP/Mask Keyframe handling and standard FCurve Keyframe handling */
@@ -321,6 +385,9 @@ void clean_fcurve(struct bAnimContext *ac,
float thresh,
bool cleardefault);
bool decimate_fcurve(struct bAnimListElem *ale, float remove_ratio, float error_sq_max);
+/**
+ * Use a weighted moving-means method to reduce intensity of fluctuations.
+ */
void smooth_fcurve(struct FCurve *fcu);
void sample_fcurve(struct FCurve *fcu);
@@ -336,6 +403,8 @@ short paste_animedit_keys(struct bAnimContext *ac,
/* ************************************************ */
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h
index 673f629d6ef..d539c7b688c 100644
--- a/source/blender/editors/include/ED_keyframing.h
+++ b/source/blender/editors/include/ED_keyframing.h
@@ -53,22 +53,28 @@ struct PropertyRNA;
struct NlaKeyframingContext;
-/* ************ Keyframing Management **************** */
+/* -------------------------------------------------------------------- */
+/** \name Key-Framing Management
+ * \{ */
-/* Get the active settings for keyframing settings from context (specifically the given scene)
- * - use_autokey_mode: include settings from keyframing mode in the result (i.e. replace only).
+/**
+ * Get the active settings for key-framing settings from context (specifically the given scene)
+ * \param use_autokey_mode: include settings from key-framing mode in the result
+ * (i.e. replace only).
*/
eInsertKeyFlags ANIM_get_keyframing_flags(struct Scene *scene, const bool use_autokey_mode);
/* -------- */
-/* Get (or add relevant data to be able to do so) the Active Action for the given
+/**
+ * Get (or add relevant data to be able to do so) the Active Action for the given
* Animation Data block, given an ID block where the Animation Data should reside.
*/
struct bAction *ED_id_action_ensure(struct Main *bmain, struct ID *id);
-/* Get (or add relevant data to be able to do so) F-Curve from the given Action.
- * This assumes that all the destinations are valid.
+/**
+ * Get (or add relevant data to be able to do so) F-Curve from the Active Action,
+ * for the given Animation Data block. This assumes that all the destinations are valid.
*/
struct FCurve *ED_action_fcurve_ensure(struct Main *bmain,
struct bAction *act,
@@ -77,15 +83,21 @@ struct FCurve *ED_action_fcurve_ensure(struct Main *bmain,
const char rna_path[],
const int array_index);
+/**
+ * Find the F-Curve from the Active Action,
+ * for the given Animation Data block. This assumes that all the destinations are valid.
+ */
struct FCurve *ED_action_fcurve_find(struct bAction *act,
const char rna_path[],
const int array_index);
/* -------- */
-/* Lesser Keyframing API call:
- * Update integer/discrete flags of the FCurve (used when creating/inserting keyframes,
- * but also through RNA when editing an ID prop, see T37103).
+/**
+ * \brief Lesser Key-framing API call.
+ *
+ * Update integer/discrete flags of the FCurve (used when creating/inserting keyframes,
+ * but also through RNA when editing an ID prop, see T37103).
*/
void update_autoflags_fcurve(struct FCurve *fcu,
struct bContext *C,
@@ -94,16 +106,34 @@ void update_autoflags_fcurve(struct FCurve *fcu,
/* -------- */
-/* Lesser Keyframing API call:
- * Use this when validation of necessary animation data isn't necessary as it already
- * exists, and there is a beztriple that can be directly copied into the array.
+/**
+ * \brief Lesser Key-framing API call.
+ *
+ * Use this when validation of necessary animation data isn't necessary as it already
+ * exists, and there is a #BezTriple that can be directly copied into the array.
+ *
+ * This function adds a given #BezTriple to an F-Curve. It will allocate
+ * memory for the array if needed, and will insert the #BezTriple into a
+ * suitable place in chronological order.
+ *
+ * \note any recalculate of the F-Curve that needs to be done will need to be done by the caller.
*/
int insert_bezt_fcurve(struct FCurve *fcu, const struct BezTriple *bezt, eInsertKeyFlags flag);
-/* Main Keyframing API call:
- * Use this when validation of necessary animation data isn't necessary as it
- * already exists. It will insert a keyframe using the current value being keyframed.
- * Returns the index at which a keyframe was added (or -1 if failed)
+/**
+ * \brief Main Key-framing API call.
+ *
+ * Use this when validation of necessary animation data isn't necessary as it
+ * already exists. It will insert a keyframe using the current value being keyframed.
+ * Returns the index at which a keyframe was added (or -1 if failed).
+ *
+ * This function is a wrapper for #insert_bezt_fcurve(), and should be used when
+ * adding a new keyframe to a curve, when the keyframe doesn't exist anywhere else yet.
+ * It returns the index at which the keyframe was added.
+ *
+ * \param keyframe_type: The type of keyframe (#eBezTriple_KeyframeType).
+ * \param flag: Optional flags (#eInsertKeyFlags) for controlling how keys get added
+ * and/or whether updates get done.
*/
int insert_vert_fcurve(struct FCurve *fcu,
float x,
@@ -113,9 +143,21 @@ int insert_vert_fcurve(struct FCurve *fcu,
/* -------- */
-/* Secondary Keyframing API calls:
- * Use this to insert a keyframe using the current value being keyframed, in the
- * nominated F-Curve (no creation of animation data performed). Returns success.
+/**
+ * \brief Secondary Insert Key-framing API call.
+ *
+ * Use this when validation of necessary animation data is not necessary,
+ * since an RNA-pointer to the necessary data being keyframed,
+ * and a pointer to the F-Curve to use have both been provided.
+ *
+ * This function can't keyframe quaternion channels on some NLA strip types.
+ *
+ * \param keytype: The "keyframe type" (eBezTriple_KeyframeType), as shown in the Dope Sheet.
+ *
+ * \param flag: Used for special settings that alter the behavior of the keyframe insertion.
+ * These include the 'visual' key-framing modes, quick refresh,
+ * and extra keyframe filtering.
+ * \return Success.
*/
bool insert_keyframe_direct(struct ReportList *reports,
struct PointerRNA ptr,
@@ -128,9 +170,17 @@ bool insert_keyframe_direct(struct ReportList *reports,
/* -------- */
-/* Main Keyframing API calls:
+/**
+ * \brief Main Insert Key-framing API call.
+ *
* Use this to create any necessary animation data, and then insert a keyframe
- * using the current value being keyframed, in the relevant place. Returns success.
+ * using the current value being keyframed, in the relevant place.
+ *
+ * \param flag: Used for special settings that alter the behavior of the keyframe insertion.
+ * These include the 'visual' key-framing modes, quick refresh, and extra keyframe filtering.
+ *
+ * \param array_index: The index to key or -1 keys all array indices.
+ * \return The number of key-frames inserted.
*/
int insert_keyframe(struct Main *bmain,
struct ReportList *reports,
@@ -144,9 +194,13 @@ int insert_keyframe(struct Main *bmain,
struct ListBase *nla_cache,
eInsertKeyFlags flag);
-/* Main Keyframing API call:
+/**
+ * \brief Main Delete Key-Framing API call.
+ *
* Use this to delete keyframe on current frame for relevant channel.
- * Will perform checks just in case. */
+ * Will perform checks just in case.
+ * \return The number of key-frames deleted.
+ */
int delete_keyframe(struct Main *bmain,
struct ReportList *reports,
struct ID *id,
@@ -155,7 +209,11 @@ int delete_keyframe(struct Main *bmain,
int array_index,
float cfra);
-/* ************ Keying Sets ********************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Keying Sets
+ * \{ */
/* forward decl. for this struct which is declared a bit later... */
struct ExtensionRNA;
@@ -206,7 +264,9 @@ typedef struct KeyingSetInfo {
/* -------- */
-/* Add another data source for Relative Keying Sets to be evaluated with */
+/**
+ * Add another data source for Relative Keying Sets to be evaluated with.
+ */
void ANIM_relative_keyingset_add_source(ListBase *dsources,
struct ID *id,
struct StructRNA *srna,
@@ -226,13 +286,28 @@ typedef enum eModifyKey_Returns {
MODIFYKEY_MISSING_TYPEINFO = -2,
} eModifyKey_Returns;
-/* poll the current KeyingSet, updating its set of paths
- * (if "builtin"/"relative") for context changes */
+/**
+ * Given a #KeyingSet and context info, validate Keying Set's paths.
+ * This is only really necessary with relative/built-in KeyingSets
+ * where their list of paths is dynamically generated based on the
+ * current context info.
+ *
+ * \return 0 if succeeded, otherwise an error code: #eModifyKey_Returns.
+ */
eModifyKey_Returns ANIM_validate_keyingset(struct bContext *C,
ListBase *dsources,
struct KeyingSet *ks);
-/* use the specified KeyingSet to add/remove various Keyframes on the specified frame */
+/**
+ * Use the specified #KeyingSet and context info (if required)
+ * to add/remove various Keyframes on the specified frame.
+ *
+ * Modify keyframes for the channels specified by the KeyingSet.
+ * This takes into account many of the different combinations of using KeyingSets.
+ *
+ * \returns the number of channels that key-frames were added or
+ * an #eModifyKey_Returns value (always a negative number).
+ */
int ANIM_apply_keyingset(struct bContext *C,
ListBase *dsources,
struct bAction *act,
@@ -242,49 +317,88 @@ int ANIM_apply_keyingset(struct bContext *C,
/* -------- */
-/* Get the first builtin KeyingSet with the given name, which occurs after the given one
- * (or start of list if none given) */
+/**
+ * Find builtin #KeyingSet by name.
+ *
+ * \return The first builtin #KeyingSet with the given name, which occurs after the given one
+ * (or start of list if none given).
+ */
struct KeyingSet *ANIM_builtin_keyingset_get_named(struct KeyingSet *prevKS, const char name[]);
-/* Find KeyingSet type info given a name */
+/**
+ * Find KeyingSet type info given a name.
+ */
KeyingSetInfo *ANIM_keyingset_info_find_name(const char name[]);
-/* Find a given ID in the KeyingSet */
+/**
+ * Check if the ID appears in the paths specified by the #KeyingSet.
+ */
bool ANIM_keyingset_find_id(struct KeyingSet *ks, ID *id);
-/* for RNA type registrations... */
+/**
+ * Add the given KeyingSetInfo to the list of type infos,
+ * and create an appropriate builtin set too.
+ */
void ANIM_keyingset_info_register(KeyingSetInfo *ksi);
+/**
+ * Remove the given #KeyingSetInfo from the list of type infos,
+ * and also remove the builtin set if appropriate.
+ */
void ANIM_keyingset_info_unregister(struct Main *bmain, KeyingSetInfo *ksi);
/* cleanup on exit */
+/* --------------- */
+
void ANIM_keyingset_infos_exit(void);
/* -------- */
-/* Get the active KeyingSet for the given scene */
+/**
+ * Get the active Keying Set for the given scene.
+ */
struct KeyingSet *ANIM_scene_get_active_keyingset(const struct Scene *scene);
-/* Get the index of the Keying Set provided, for the given Scene */
+/**
+ * Get the index of the Keying Set provided, for the given Scene.
+ */
int ANIM_scene_get_keyingset_index(struct Scene *scene, struct KeyingSet *ks);
-/* Get Keying Set to use for Auto-Keyframing some transforms */
+/**
+ * Get Keying Set to use for Auto-Key-Framing some transforms.
+ */
struct KeyingSet *ANIM_get_keyingset_for_autokeying(const struct Scene *scene,
const char *transformKSName);
-/* Dynamically populate an enum of Keying Sets */
+/**
+ * Dynamically populate an enum of Keying Sets.
+ */
const struct EnumPropertyItem *ANIM_keying_sets_enum_itemf(struct bContext *C,
struct PointerRNA *ptr,
struct PropertyRNA *prop,
bool *r_free);
-/* Use to get the keying set from the int value used by enums. */
+/**
+ * Get the keying set from enum values generated in #ANIM_keying_sets_enum_itemf.
+ *
+ * Type is the Keying Set the user specified to use when calling the operator:
+ * \param type:
+ * - == 0: use scene's active Keying Set.
+ * - > 0: use a user-defined Keying Set from the active scene.
+ * - < 0: use a builtin Keying Set.
+ */
KeyingSet *ANIM_keyingset_get_from_enum_type(struct Scene *scene, int type);
KeyingSet *ANIM_keyingset_get_from_idname(struct Scene *scene, const char *idname);
-/* Check if KeyingSet can be used in the current context */
+/**
+ * Check if #KeyingSet can be used in the current context.
+ */
bool ANIM_keyingset_context_ok_poll(struct bContext *C, struct KeyingSet *ks);
-/* ************ Drivers ********************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Drivers
+ * \{ */
/* Flags for use by driver creation calls */
typedef enum eCreateDriverFlags {
@@ -311,7 +425,10 @@ typedef enum eCreateDriver_MappingTypes {
CREATEDRIVER_MAPPING_NONE_ALL = 4,
} eCreateDriver_MappingTypes;
-/* RNA Enum of eCreateDriver_MappingTypes, for use by the appropriate operators */
+/**
+ * Mapping Types enum for operators.
+ * \note Used by #ANIM_OT_driver_button_add and #UI_OT_eyedropper_driver.
+ */
extern EnumPropertyItem prop_driver_create_mapping_types[];
/* -------- */
@@ -323,7 +440,11 @@ typedef enum eDriverFCurveCreationMode {
DRIVER_FCURVE_EMPTY = 3 /* Add without data, for pasting. */
} eDriverFCurveCreationMode;
-/* Low-level call to add a new driver F-Curve. This shouldn't be used directly for most tools,
+/**
+ * Get (or add relevant data to be able to do so) F-Curve from the driver stack,
+ * for the given Animation Data block. This assumes that all the destinations are valid.
+ *
+ * \note This low-level function shouldn't be used directly for most tools,
* although there are special cases where this approach is preferable.
*/
struct FCurve *verify_driver_fcurve(struct ID *id,
@@ -337,16 +458,18 @@ struct FCurve *alloc_driver_fcurve(const char rna_path[],
/* -------- */
-/* Main Driver Management API calls:
- * Add a new driver for the specified property on the given ID block,
- * and make it be driven by the specified target.
+/**
+ * \brief Main Driver Management API calls
+ *
+ * Add a new driver for the specified property on the given ID block,
+ * and make it be driven by the specified target.
*
* This is intended to be used in conjunction with a modal "eyedropper"
* for picking the variable that is going to be used to drive this one.
*
- * - flag: eCreateDriverFlags
- * - driver_type: eDriver_Types
- * - mapping_type: eCreateDriver_MappingTypes
+ * \param flag: eCreateDriverFlags
+ * \param driver_type: eDriver_Types
+ * \param mapping_type: eCreateDriver_MappingTypes
*/
int ANIM_add_driver_with_target(struct ReportList *reports,
struct ID *dst_id,
@@ -361,8 +484,10 @@ int ANIM_add_driver_with_target(struct ReportList *reports,
/* -------- */
-/* Main Driver Management API calls:
- * Add a new driver for the specified property on the given ID block
+/**
+ * \brief Main Driver Management API calls.
+ *
+ * Add a new driver for the specified property on the given ID block
*/
int ANIM_add_driver(struct ReportList *reports,
struct ID *id,
@@ -371,90 +496,128 @@ int ANIM_add_driver(struct ReportList *reports,
short flag,
int type);
-/* Main Driver Management API calls:
- * Remove the driver for the specified property on the given ID block (if available)
+/**
+ * \brief Main Driver Management API calls.
+ *
+ * Remove the driver for the specified property on the given ID block (if available).
*/
bool ANIM_remove_driver(
struct ReportList *reports, struct ID *id, const char rna_path[], int array_index, short flag);
/* -------- */
-/* Clear copy-paste buffer for drivers */
+/**
+ * Clear copy-paste buffer for drivers.
+ * \note This function frees any MEM_calloc'ed copy/paste buffer data.
+ */
void ANIM_drivers_copybuf_free(void);
-/* Clear copy-paste buffer for driver variable sets */
+/**
+ * Clear copy-paste buffer for driver variable sets.
+ * \note This function frees any MEM_calloc'ed copy/paste buffer data.
+ */
void ANIM_driver_vars_copybuf_free(void);
/* -------- */
-/* Returns whether there is a driver in the copy/paste buffer to paste */
+/**
+ * Returns whether there is a driver in the copy/paste buffer to paste.
+ */
bool ANIM_driver_can_paste(void);
-/* Main Driver Management API calls:
- * Make a copy of the driver for the specified property on the given ID block
+/**
+ * \brief Main Driver Management API calls.
+ *
+ * Make a copy of the driver for the specified property on the given ID block.
*/
bool ANIM_copy_driver(
struct ReportList *reports, struct ID *id, const char rna_path[], int array_index, short flag);
-/* Main Driver Management API calls:
+/**
+ * \brief Main Driver Management API calls.
+ *
* Add a new driver for the specified property on the given ID block or replace an existing one
- * with the driver + driver-curve data from the buffer
+ * with the driver + driver-curve data from the buffer.
*/
bool ANIM_paste_driver(
struct ReportList *reports, struct ID *id, const char rna_path[], int array_index, short flag);
/* -------- */
-/* Checks if there are driver variables in the copy/paste buffer */
+/**
+ * Checks if there are driver variables in the copy/paste buffer.
+ */
bool ANIM_driver_vars_can_paste(void);
-/* Copy the given driver's variables to the buffer */
+/**
+ * Copy the given driver's variables to the buffer.
+ */
bool ANIM_driver_vars_copy(struct ReportList *reports, struct FCurve *fcu);
-/* Paste the variables in the buffer to the given FCurve */
+/**
+ * Paste the variables in the buffer to the given FCurve.
+ */
bool ANIM_driver_vars_paste(struct ReportList *reports, struct FCurve *fcu, bool replace);
/* -------- */
-/* Create a driver & variable that reads the specified property,
- * and store it in the buffers for Paste Driver and Paste Variables. */
+/**
+ * Create a driver & variable that reads the specified property,
+ * and store it in the buffers for Paste Driver and Paste Variables.
+ */
void ANIM_copy_as_driver(struct ID *target_id, const char *target_path, const char *var_name);
-/* ************ Auto-Keyframing ********************** */
-/* Notes:
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Auto-Key-Framing
+ *
+ * Notes:
* - All the defines for this (User-Pref settings and Per-Scene settings)
* are defined in DNA_userdef_types.h
- * - Scene settings take precedence over those for userprefs, with old files
- * inheriting userpref settings for the scene settings
- * - "On/Off + Mode" are stored per Scene, but "settings" are currently stored
- * as userprefs
- */
+ * - Scene settings take precedence over those for user-preferences, with old files
+ * inheriting user-preferences settings for the scene settings
+ * - "On/Off + Mode" are stored per Scene, but "settings" are currently stored as user-preferences.
+ * \{ */
-/* Auto-Keying macros for use by various tools */
-/* check if auto-keyframing is enabled (per scene takes precedence) */
+/* Auto-Keying macros for use by various tools. */
+
+/** Check if auto-key-framing is enabled (per scene takes precedence).
+ */
#define IS_AUTOKEY_ON(scene) \
((scene) ? ((scene)->toolsettings->autokey_mode & AUTOKEY_ON) : (U.autokey_mode & AUTOKEY_ON))
-/* Check the mode for auto-keyframing (per scene takes precedence). */
+/** Check the mode for auto-keyframing (per scene takes precedence). */
#define IS_AUTOKEY_MODE(scene, mode) \
((scene) ? ((scene)->toolsettings->autokey_mode == AUTOKEY_MODE_##mode) : \
(U.autokey_mode == AUTOKEY_MODE_##mode))
-/* check if a flag is set for auto-keyframing (per scene takes precedence) */
+/** Check if a flag is set for auto-key-framing (per scene takes precedence). */
#define IS_AUTOKEY_FLAG(scene, flag) \
((scene) ? (((scene)->toolsettings->autokey_flag & AUTOKEY_FLAG_##flag) || \
(U.autokey_flag & AUTOKEY_FLAG_##flag)) : \
(U.autokey_flag & AUTOKEY_FLAG_##flag))
-/* auto-keyframing feature - checks for whether anything should be done for the current frame */
+/**
+ * Auto-keyframing feature - checks for whether anything should be done for the current frame.
+ */
bool autokeyframe_cfra_can_key(const struct Scene *scene, struct ID *id);
-/* ************ Keyframe Checking ******************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Keyframe Checking
+ * \{ */
-/* Lesser Keyframe Checking API call:
- * - Used for the buttons to check for keyframes...
+/**
+ * \brief Lesser Keyframe Checking API call.
+ *
+ * Checks if some F-Curve has a keyframe for a given frame.
+ * \note Used for the buttons to check for keyframes.
*/
bool fcurve_frame_has_keyframe(const struct FCurve *fcu, float frame, short filter);
-/* Lesser Keyframe Checking API call:
+/**
+ * \brief Lesser Keyframe Checking API call.
+ *
* - Returns whether the current value of a given property differs from the interpolated value.
* - Used for button drawing.
*/
@@ -464,18 +627,19 @@ bool fcurve_is_changed(struct PointerRNA ptr,
const struct AnimationEvalContext *anim_eval_context);
/**
- * Main Keyframe Checking API call:
+ * \brief Main Keyframe Checking API call.
+ *
* Checks whether a keyframe exists for the given ID-block one the given frame.
- * - It is recommended to call this method over the other keyframe-checkers directly,
- * in case some detail of the implementation changes...
- * - frame: the value of this is quite often result of #BKE_scene_ctime_get()
+ * It is recommended to call this method over the other keyframe-checkers directly,
+ * in case some detail of the implementation changes...
+ * \param frame: The value of this is quite often result of #BKE_scene_ctime_get()
*/
bool id_frame_has_keyframe(struct ID *id, float frame, short filter);
-/* filter flags for id_cfra_has_keyframe
+/**
+ * Filter flags for #id_frame_has_keyframe.
*
- * WARNING: do not alter order of these, as also stored in files
- * (for v3d->keyflags)
+ * \warning do not alter order of these, as also stored in files (for `v3d->keyflags`).
*/
typedef enum eAnimFilterFlags {
/* general */
@@ -488,7 +652,8 @@ typedef enum eAnimFilterFlags {
ANIMFILTER_KEYS_NOSKEY = (1 << 10), /* don't include shape keys (for geometry) */
} eAnimFilterFlags;
-/* utility funcs for auto keyframe */
+/* Utility functions for auto key-frame. */
+
bool ED_autokeyframe_object(struct bContext *C,
struct Scene *scene,
struct Object *ob,
@@ -498,6 +663,9 @@ bool ED_autokeyframe_pchan(struct bContext *C,
struct Object *ob,
struct bPoseChannel *pchan,
struct KeyingSet *ks);
+/**
+ * Use for auto-key-framing from the UI.
+ */
bool ED_autokeyframe_property(struct bContext *C,
struct Scene *scene,
PointerRNA *ptr,
@@ -506,7 +674,8 @@ bool ED_autokeyframe_property(struct bContext *C,
float cfra);
/* Names for builtin keying sets so we don't confuse these with labels/text,
- * defined in python script: keyingsets_builtins.py */
+ * defined in python script: `keyingsets_builtins.py`. */
+
#define ANIM_KS_LOCATION_ID "Location"
#define ANIM_KS_ROTATION_ID "Rotation"
#define ANIM_KS_SCALING_ID "Scaling"
@@ -516,6 +685,8 @@ bool ED_autokeyframe_property(struct bContext *C,
#define ANIM_KS_WHOLE_CHARACTER_ID "WholeCharacter"
#define ANIM_KS_WHOLE_CHARACTER_SELECTED_ID "WholeCharacterSelected"
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/editors/include/ED_lattice.h b/source/blender/editors/include/ED_lattice.h
index 6982ad20f07..dc800d78007 100644
--- a/source/blender/editors/include/ED_lattice.h
+++ b/source/blender/editors/include/ED_lattice.h
@@ -33,10 +33,12 @@ struct UndoType;
struct wmKeyConfig;
/* lattice_ops.c */
+
void ED_operatortypes_lattice(void);
void ED_keymap_lattice(struct wmKeyConfig *keyconf);
/* editlattice_select.c */
+
bool ED_lattice_flags_set(struct Object *obedit, int flag);
bool ED_lattice_select_pick(
struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
@@ -45,6 +47,8 @@ bool ED_lattice_deselect_all_multi_ex(struct Base **bases, const uint bases_len)
bool ED_lattice_deselect_all_multi(struct bContext *C);
/* editlattice_undo.c */
+
+/** Export for ED_undo_sys. */
void ED_lattice_undosys_type(struct UndoType *ut);
#ifdef __cplusplus
diff --git a/source/blender/editors/include/ED_markers.h b/source/blender/editors/include/ED_markers.h
index 8c10a8e36fd..8e6961ffd6f 100644
--- a/source/blender/editors/include/ED_markers.h
+++ b/source/blender/editors/include/ED_markers.h
@@ -33,7 +33,9 @@ struct bAnimContext;
struct bContext;
struct wmKeyConfig;
-/* Drawing API ------------------------------ */
+/* -------------------------------------------------------------------- */
+/** \name Drawing API
+ * \{ */
/* flags for drawing markers */
enum {
@@ -42,37 +44,86 @@ enum {
DRAW_MARKERS_MARGIN = (1 << 2),
};
+/* Draw Scene-Markers in time window */
void ED_markers_draw(const struct bContext *C, int flag);
-/* Backend API ----------------------------- */
+/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Backend API
+ * \{ */
+
+/**
+ * Public API for getting markers from context.
+ */
ListBase *ED_context_get_markers(const struct bContext *C);
+/**
+ * Public API for getting markers from "animation" context.
+ */
ListBase *ED_animcontext_get_markers(const struct bAnimContext *ac);
+/**
+ * Apply some transformation to markers after the fact
+ *
+ * \param markers: List of markers to affect - this may or may not be the scene markers list,
+ * so don't assume anything.
+ * \param scene: Current scene (for getting current frame)
+ * \param mode: (TfmMode) transform mode that this transform is for
+ * \param value: From the transform code, this is `t->vec[0]`
+ * (which is delta transform for grab/extend, and scale factor for scale)
+ * \param side: (B/L/R) for 'extend' functionality, which side of current frame to use
+ */
int ED_markers_post_apply_transform(
ListBase *markers, struct Scene *scene, int mode, float value, char side);
+/**
+ * Get the marker that is closest to this point.
+ * XXX: for select, the min_dist should be small.
+ */
struct TimeMarker *ED_markers_find_nearest_marker(ListBase *markers, float x);
+/**
+ * Return the time of the marker that occurs on a frame closest to the given time.
+ */
int ED_markers_find_nearest_marker_time(ListBase *markers, float x);
void ED_markers_get_minmax(ListBase *markers, short sel, float *first, float *last);
+/**
+ * This function makes a list of all the markers. The only_sel
+ * argument is used to specify whether only the selected markers
+ * are added.
+ */
void ED_markers_make_cfra_list(ListBase *markers, ListBase *lb, short sel);
void ED_markers_deselect_all(ListBase *markers, int action);
+/**
+ * Get the first selected marker.
+ */
struct TimeMarker *ED_markers_get_first_selected(ListBase *markers);
-/* Operators ------------------------------ */
+/** \} */
-/* called in screen_ops.c:ED_operatortypes_screen() */
+/* -------------------------------------------------------------------- */
+/** \name Operators
+ * \{ */
+
+/**
+ * Called in screen_ops.c:ED_operatortypes_screen().
+ */
void ED_operatortypes_marker(void);
-/* called in screen_ops.c:ED_keymap_screen() */
+/**
+ * Called in screen_ops.c:ED_keymap_screen().
+ */
void ED_keymap_marker(struct wmKeyConfig *keyconf);
-/* debugging only */
+/**
+ * Debugging only: print debugging prints of list of markers.
+ */
void debug_markers_print_list(struct ListBase *markers);
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/editors/include/ED_mask.h b/source/blender/editors/include/ED_mask.h
index c2fdbc160de..3aab6882dc2 100644
--- a/source/blender/editors/include/ED_mask.h
+++ b/source/blender/editors/include/ED_mask.h
@@ -37,6 +37,7 @@ struct bContext;
struct wmKeyConfig;
/* mask_edit.c */
+
void ED_mask_deselect_all(const struct bContext *C);
void ED_operatortypes_mask(void);
@@ -44,6 +45,7 @@ void ED_keymap_mask(struct wmKeyConfig *keyconf);
void ED_operatormacros_mask(void);
/* mask_query.c */
+
void ED_mask_get_size(struct ScrArea *area, int *width, int *height);
void ED_mask_zoom(struct ScrArea *area, struct ARegion *region, float *zoomx, float *zoomy);
void ED_mask_get_aspect(struct ScrArea *area, struct ARegion *region, float *aspx, float *aspy);
@@ -52,11 +54,18 @@ void ED_mask_pixelspace_factor(struct ScrArea *area,
struct ARegion *region,
float *scalex,
float *scaley);
+/**
+ * Takes `event->mval`.
+ */
void ED_mask_mouse_pos(struct ScrArea *area,
struct ARegion *region,
const int mval[2],
float co[2]);
+/**
+ * \param x/y: input, mval space.
+ * \param xr/yr: output, mask point space.
+ */
void ED_mask_point_pos(
struct ScrArea *area, struct ARegion *region, float x, float y, float *xr, float *yr);
void ED_mask_point_pos__reverse(
@@ -69,7 +78,12 @@ bool ED_mask_selected_minmax(const struct bContext *C,
bool handles_as_control_point);
/* mask_draw.c */
+
void ED_mask_draw(const struct bContext *C, const char draw_flag, const char draw_type);
+/**
+ * Sets up the opengl context.
+ * width, height are to match the values from #ED_mask_get_size().
+ */
void ED_mask_draw_region(struct Depsgraph *depsgraph,
struct Mask *mask,
struct ARegion *region,
@@ -89,33 +103,68 @@ void ED_mask_draw_frames(
struct Mask *mask, struct ARegion *region, const int cfra, const int sfra, const int efra);
/* mask_shapekey.c */
+
void ED_mask_layer_shape_auto_key(struct MaskLayer *mask_layer, const int frame);
bool ED_mask_layer_shape_auto_key_all(struct Mask *mask, const int frame);
bool ED_mask_layer_shape_auto_key_select(struct Mask *mask, const int frame);
/* ----------- Mask AnimEdit API ------------------ */
+
+/**
+ * Loops over the mask-frames for a mask-layer, and applies the given callback.
+ */
bool ED_masklayer_frames_looper(struct MaskLayer *mask_layer,
struct Scene *scene,
bool (*mask_layer_shape_cb)(struct MaskLayerShape *,
struct Scene *));
+/**
+ * Make a listing all the mask-frames in a layer as cfraelems.
+ */
void ED_masklayer_make_cfra_list(struct MaskLayer *mask_layer, ListBase *elems, bool onlysel);
+/**
+ * Check if one of the frames in this layer is selected.
+ */
bool ED_masklayer_frame_select_check(const struct MaskLayer *mask_layer);
+/**
+ * Set all/none/invert select.
+ */
void ED_masklayer_frame_select_set(struct MaskLayer *mask_layer, short mode);
+/**
+ * Select the frames in this layer that occur within the bounds specified.
+ */
void ED_masklayer_frames_select_box(struct MaskLayer *mask_layer,
float min,
float max,
short select_mode);
+/**
+ * Select the frames in this layer that occur within the lasso/circle region specified.
+ */
void ED_masklayer_frames_select_region(struct KeyframeEditData *ked,
struct MaskLayer *mask_layer,
short tool,
short select_mode);
+/**
+ * Set all/none/invert select (like above, but with SELECT_* modes).
+ */
void ED_mask_select_frames(struct MaskLayer *mask_layer, short select_mode);
+/**
+ * Select the frame in this layer that occurs on this frame (there should only be one at most).
+ */
void ED_mask_select_frame(struct MaskLayer *mask_layer, int selx, short select_mode);
+/**
+ * Delete selected frames.
+ */
bool ED_masklayer_frames_delete(struct MaskLayer *mask_layer);
+/**
+ * Duplicate selected frames from given mask-layer.
+ */
void ED_masklayer_frames_duplicate(struct MaskLayer *mask_layer);
+/**
+ * Snap selected frames to ...
+ */
void ED_masklayer_snap_frames(struct MaskLayer *mask_layer, struct Scene *scene, short mode);
#if 0
diff --git a/source/blender/editors/include/ED_mball.h b/source/blender/editors/include/ED_mball.h
index 7648af159c9..1afd7f06a5a 100644
--- a/source/blender/editors/include/ED_mball.h
+++ b/source/blender/editors/include/ED_mball.h
@@ -37,6 +37,9 @@ void ED_operatortypes_metaball(void);
void ED_operatormacros_metaball(void);
void ED_keymap_metaball(struct wmKeyConfig *keyconf);
+/**
+ * Add meta-element primitive to meta-ball object (which is in edit mode).
+ */
struct MetaElem *ED_mball_add_primitive(struct bContext *C,
struct Object *obedit,
bool obedit_is_new,
@@ -44,17 +47,32 @@ struct MetaElem *ED_mball_add_primitive(struct bContext *C,
float dia,
int type);
+/**
+ * Select MetaElement with mouse click (user can select radius circle or stiffness circle).
+ */
bool ED_mball_select_pick(
struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
bool ED_mball_deselect_all_multi_ex(struct Base **bases, uint bases_len);
bool ED_mball_deselect_all_multi(struct bContext *C);
+/**
+ * This function is used to free all MetaElems from MetaBall.
+ */
void ED_mball_editmball_free(struct Object *obedit);
+/**
+ * This function is called, when MetaBall Object is switched from object mode to edit mode.
+ */
void ED_mball_editmball_make(struct Object *obedit);
+/**
+ * This function is called, when MetaBall Object switched from edit mode to object mode.
+ * List of MetaElements is copied from object->data->edit_elems to object->data->elems.
+ */
void ED_mball_editmball_load(struct Object *obedit);
/* editmball_undo.c */
+
+/** Export for ED_undo_sys. */
void ED_mball_undosys_type(struct UndoType *ut);
#define MBALLSEL_STIFF (1u << 30)
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index 22de6ca15bf..35838f4ce48 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -58,6 +58,17 @@ struct wmKeyConfig;
struct wmOperator;
/* editmesh_utils.c */
+
+/**
+ * \param em: Editmesh.
+ * \param use_self: Allow a vertex to point to its self (middle verts).
+ * \param use_select: Restrict to selected verts.
+ * \param respecthide: Skip hidden vertices.
+ * \param use_topology: Use topology mirror.
+ * \param maxdist: Distance for close point test.
+ * \param r_index: Optional array to write into, as an alternative to a customdata layer
+ * (length of total verts).
+ */
void EDBM_verts_mirror_cache_begin_ex(struct BMEditMesh *em,
const int axis,
const bool use_self,
@@ -86,14 +97,24 @@ void EDBM_mesh_clear(struct BMEditMesh *em);
void EDBM_selectmode_to_scene(struct bContext *C);
void EDBM_mesh_make(struct Object *ob, const int select_mode, const bool add_key_index);
+/**
+ * Should only be called on the active edit-mesh, otherwise call #BKE_editmesh_free_data.
+ */
void EDBM_mesh_free_data(struct BMEditMesh *em);
+/**
+ * \warning This can invalidate the #Mesh runtime cache of other objects (for linked duplicates).
+ * Most callers should run #DEG_id_tag_update on `ob->data`, see: T46738, T46913.
+ * This ensures #BKE_object_free_derived_caches runs on all objects that use this mesh.
+ */
void EDBM_mesh_load_ex(struct Main *bmain, struct Object *ob, bool free_data);
void EDBM_mesh_load(struct Main *bmain, struct Object *ob);
-/* flushes based on the current select mode. if in vertex select mode,
+/**
+ * flushes based on the current select mode. If in vertex select mode,
* verts select/deselect edges and faces, if in edge select mode,
* edges select/deselect faces and vertices, and in face select mode faces select/deselect
- * edges and vertices. */
+ * edges and vertices.
+ */
void EDBM_select_more(struct BMEditMesh *em, const bool use_face_step);
void EDBM_select_less(struct BMEditMesh *em, const bool use_face_step);
@@ -105,6 +126,9 @@ void EDBM_select_flush(struct BMEditMesh *em);
bool EDBM_vert_color_check(struct BMEditMesh *em);
+/**
+ * Swap is 0 or 1, if 1 it hides not selected.
+ */
bool EDBM_mesh_hide(struct BMEditMesh *em, bool swap);
bool EDBM_mesh_reveal(struct BMEditMesh *em, bool select);
@@ -114,9 +138,18 @@ struct EDBMUpdate_Params {
uint is_destructive : 1;
};
+/**
+ * So many tools call these that we better make it a generic function.
+ */
void EDBM_update(struct Mesh *me, const struct EDBMUpdate_Params *params);
+/**
+ * Bad level call from Python API.
+ */
void EDBM_update_extern(struct Mesh *me, const bool do_tessellation, const bool is_destructive);
+/**
+ * A specialized vert map used by stitch operator.
+ */
struct UvElementMap *BM_uv_element_map_create(struct BMesh *bm,
const struct Scene *scene,
const bool face_selected,
@@ -128,13 +161,23 @@ struct UvElement *BM_uv_element_get(struct UvElementMap *map,
struct BMFace *efa,
struct BMLoop *l);
+/**
+ * Can we edit UV's for this mesh?
+ */
bool EDBM_uv_check(struct BMEditMesh *em);
+/**
+ * last_sel, use em->act_face otherwise get the last selected face in the editselections
+ * at the moment, last_sel is mainly useful for making sure the space image doesn't flicker.
+ */
struct BMFace *EDBM_uv_active_face_get(struct BMEditMesh *em,
const bool sloppy,
const bool selected);
void BM_uv_vert_map_free(struct UvVertMap *vmap);
struct UvMapVert *BM_uv_vert_map_at_index(struct UvVertMap *vmap, unsigned int v);
+/**
+ * Return a new #UvVertMap from the edit-mesh.
+ */
struct UvVertMap *BM_uv_vert_map_create(struct BMesh *bm,
const bool use_select,
const bool use_winding);
@@ -156,6 +199,7 @@ void EDBM_project_snap_verts(struct bContext *C,
struct BMEditMesh *em);
/* editmesh_automerge.c */
+
void EDBM_automerge(struct Object *ob, bool update, const char hflag, const float dist);
void EDBM_automerge_and_split(struct Object *ob,
const bool split_edges,
@@ -165,9 +209,12 @@ void EDBM_automerge_and_split(struct Object *ob,
const float dist);
/* editmesh_undo.c */
+
+/** Export for ED_undo_sys. */
void ED_mesh_undosys_type(struct UndoType *ut);
/* editmesh_select.c */
+
void EDBM_select_mirrored(struct BMEditMesh *em,
const struct Mesh *me,
const int axis,
@@ -175,6 +222,17 @@ void EDBM_select_mirrored(struct BMEditMesh *em,
int *r_totmirr,
int *r_totfail);
+/**
+ * Nearest vertex under the cursor.
+ *
+ * \param dist_px_manhattan_p: (in/out), minimal distance to the nearest and at the end,
+ * actual distance.
+ * \param use_select_bias:
+ * - When true, selected vertices are given a 5 pixel bias
+ * to make them further than unselected vertices.
+ * - When false, unselected vertices are given the bias.
+ * \param use_cycle: Cycle over elements within #FIND_NEAR_CYCLE_THRESHOLD_MIN in order of index.
+ */
struct BMVert *EDBM_vert_find_nearest_ex(struct ViewContext *vc,
float *dist_px_manhattan_p,
const bool use_select_bias,
@@ -195,6 +253,13 @@ struct BMEdge *EDBM_edge_find_nearest_ex(struct ViewContext *vc,
uint *r_base_index);
struct BMEdge *EDBM_edge_find_nearest(struct ViewContext *vc, float *dist_px_manhattan_p);
+/**
+ * \param use_zbuf_single_px: Special case, when using the back-buffer selection,
+ * only use the pixel at `vc->mval` instead of using `dist_px_manhattan_p` to search over a larger
+ * region. This is needed because historically selection worked this way for a long time, however
+ * it's reasonable that some callers might want to expand the region too. So add an argument to do
+ * this,
+ */
struct BMFace *EDBM_face_find_nearest_ex(struct ViewContext *vc,
float *dist_px_manhattan,
float *r_dist_center,
@@ -230,19 +295,48 @@ bool EDBM_unified_findnearest_from_raycast(struct ViewContext *vc,
bool EDBM_select_pick(
struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
+/**
+ * When switching select mode, makes sure selection is consistent for editing
+ * also for paranoia checks to make sure edge or face mode works.
+ */
void EDBM_selectmode_set(struct BMEditMesh *em);
+/**
+ * Expand & Contract the Selection
+ * (used when changing modes and Ctrl key held)
+ *
+ * Flush the selection up:
+ * - vert -> edge
+ * - vert -> face
+ * - edge -> face
+ *
+ * Flush the selection down:
+ * - face -> edge
+ * - face -> vert
+ * - edge -> vert
+ */
void EDBM_selectmode_convert(struct BMEditMesh *em,
const short selectmode_old,
const short selectmode_new);
-/* user access this */
+/**
+ * User access this.
+ */
bool EDBM_selectmode_set_multi(struct bContext *C, const short selectmode);
+/**
+ * User facing function, does notification.
+ */
bool EDBM_selectmode_toggle_multi(struct bContext *C,
const short selectmode_new,
const int action,
const bool use_extend,
const bool use_expand);
+/**
+ * Use to disable a select-mode if its enabled, Using another mode as a fallback
+ * if the disabled mode is the only mode set.
+ *
+ * \return true if the mode is changed.
+ */
bool EDBM_selectmode_disable(struct Scene *scene,
struct BMEditMesh *em,
const short selectmode_disable,
@@ -305,12 +399,22 @@ void EDBM_preselect_elem_update_preview(struct EditMesh_PreSelElem *psel,
void EDBM_preselect_action_set(struct EditMesh_PreSelElem *psel,
eEditMesh_PreSelPreviewAction action);
eEditMesh_PreSelPreviewAction EDBM_preselect_action_get(struct EditMesh_PreSelElem *psel);
+
/* mesh_ops.c */
+
void ED_operatortypes_mesh(void);
void ED_operatormacros_mesh(void);
+/**
+ * Note mesh keymap also for other space?
+ */
void ED_keymap_mesh(struct wmKeyConfig *keyconf);
/* editface.c */
+
+/**
+ * Copy the face flags, most importantly selection from the mesh to the final derived mesh,
+ * use in object mode when selecting faces (while painting).
+ */
void paintface_flush_flags(struct bContext *C, struct Object *ob, short flag);
bool paintface_mouse_select(struct bContext *C,
struct Object *ob,
@@ -331,8 +435,17 @@ bool paintface_minmax(struct Object *ob, float r_min[3], float r_max[3]);
void paintface_hide(struct bContext *C, struct Object *ob, const bool unselected);
void paintface_reveal(struct bContext *C, struct Object *ob, const bool select);
+/**
+ * \note if the caller passes false to flush_flags,
+ * then they will need to run #paintvert_flush_flags(ob) themselves.
+ */
bool paintvert_deselect_all_visible(struct Object *ob, int action, bool flush_flags);
void paintvert_select_ungrouped(struct Object *ob, bool extend, bool flush_flags);
+/**
+ * (similar to void `paintface_flush_flags(Object *ob)`)
+ * copy the vertex flags, most importantly selection from the mesh to the final derived mesh,
+ * use in object mode when selecting vertices (while painting).
+ */
void paintvert_flush_flags(struct Object *ob);
void paintvert_tag_select_update(struct bContext *C, struct Object *ob);
@@ -360,17 +473,35 @@ void ED_mesh_mirrtopo_free(MirrTopoStore_t *mesh_topo_store);
bool ED_vgroup_sync_from_pose(struct Object *ob);
void ED_vgroup_select_by_name(struct Object *ob, const char *name);
+/**
+ * Removes out of range #MDeformWeights
+ */
void ED_vgroup_data_clamp_range(struct ID *id, const int total);
+/**
+ * Matching index only.
+ */
bool ED_vgroup_array_copy(struct Object *ob, struct Object *ob_from);
bool ED_vgroup_parray_alloc(struct ID *id,
struct MDeformVert ***dvert_arr,
int *dvert_tot,
const bool use_vert_sel);
+/**
+ * For use with tools that use ED_vgroup_parray_alloc with \a use_vert_sel == true.
+ * This finds the unselected mirror deform verts and copies the weights to them from the selected.
+ *
+ * \note \a dvert_array has mirrored weights filled in,
+ * in case cleanup operations are needed on both.
+ */
void ED_vgroup_parray_mirror_sync(struct Object *ob,
struct MDeformVert **dvert_array,
const int dvert_tot,
const bool *vgroup_validmap,
const int vgroup_tot);
+/**
+ * Fill in the pointers for mirror verts (as if all mirror verts were selected too).
+ *
+ * similar to #ED_vgroup_parray_mirror_sync but only fill in mirror points.
+ */
void ED_vgroup_parray_mirror_assign(struct Object *ob,
struct MDeformVert **dvert_array,
const int dvert_tot);
@@ -397,13 +528,23 @@ void ED_vgroup_mirror(struct Object *ob,
int *r_totmirr,
int *r_totfail);
+/**
+ * Called while not in editmode.
+ */
void ED_vgroup_vert_add(
struct Object *ob, struct bDeformGroup *dg, int vertnum, float weight, int assignmode);
+/**
+ * Mesh object mode, lattice can be in edit-mode.
+ */
void ED_vgroup_vert_remove(struct Object *ob, struct bDeformGroup *dg, int vertnum);
float ED_vgroup_vert_weight(struct Object *ob, struct bDeformGroup *dg, int vertnum);
+/**
+ * Use when adjusting the active vertex weight and apply to mirror vertices.
+ */
void ED_vgroup_vert_active_mirror(struct Object *ob, int def_nr);
/* mesh_data.c */
+
void ED_mesh_verts_add(struct Mesh *mesh, struct ReportList *reports, int count);
void ED_mesh_edges_add(struct Mesh *mesh, struct ReportList *reports, int count);
void ED_mesh_loops_add(struct Mesh *mesh, struct ReportList *reports, int count);
@@ -428,6 +569,9 @@ bool ED_mesh_uv_texture_remove_index(struct Mesh *me, const int n);
bool ED_mesh_uv_texture_remove_active(struct Mesh *me);
bool ED_mesh_uv_texture_remove_named(struct Mesh *me, const char *name);
void ED_mesh_uv_loop_reset(struct bContext *C, struct Mesh *me);
+/**
+ * Without a #bContext, called when UV-editing.
+ */
void ED_mesh_uv_loop_reset_ex(struct Mesh *me, const int layernum);
bool ED_mesh_color_ensure(struct Mesh *me, const char *name);
int ED_mesh_color_add(struct Mesh *me,
@@ -452,7 +596,9 @@ bool ED_mesh_sculpt_color_remove_named(struct Mesh *me, const char *name);
void ED_mesh_report_mirror(struct wmOperator *op, int totmirr, int totfail);
void ED_mesh_report_mirror_ex(struct wmOperator *op, int totmirr, int totfail, char selectmode);
-/* Returns the pinned mesh, the mesh from the pinned object, or the mesh from the active object. */
+/**
+ * Returns the pinned mesh, the mesh from the pinned object, or the mesh from the active object.
+ */
struct Mesh *ED_mesh_context(struct bContext *C);
/* mesh backup */
@@ -460,20 +606,30 @@ typedef struct BMBackup {
struct BMesh *bmcopy;
} BMBackup;
+/**
+ * Save a copy of the #BMesh for restoring later.
+ */
struct BMBackup EDBM_redo_state_store(struct BMEditMesh *em);
-/* restore a bmesh from backup */
+/**
+ * Restore a BMesh from backup.
+ */
void EDBM_redo_state_restore(struct BMBackup *backup, struct BMEditMesh *em, bool recalc_looptri)
ATTR_NONNULL(1, 2);
+/**
+ * Delete the backup, flushing it to an edit-mesh.
+ */
void EDBM_redo_state_restore_and_free(struct BMBackup *backup,
struct BMEditMesh *em,
bool recalc_looptri) ATTR_NONNULL(1, 2);
void EDBM_redo_state_free(struct BMBackup *backup) ATTR_NONNULL(1);
/* *** meshtools.c *** */
+
int ED_mesh_join_objects_exec(struct bContext *C, struct wmOperator *op);
int ED_mesh_shapes_join_objects_exec(struct bContext *C, struct wmOperator *op);
/* mirror lookup api */
+
/* Spatial Mirror */
void ED_mesh_mirror_spatial_table_begin(struct Object *ob,
struct BMEditMesh *em,
@@ -485,11 +641,19 @@ int ED_mesh_mirror_spatial_table_lookup(struct Object *ob,
const float co[3]);
/* Topology Mirror */
+
+/**
+ * Mode is 's' start, or 'e' end, or 'u' use if end, ob can be NULL.
+ * \note This is supposed return -1 on error,
+ * which callers are currently checking for, but is not used so far.
+ */
void ED_mesh_mirror_topo_table_begin(struct Object *ob, struct Mesh *me_eval);
void ED_mesh_mirror_topo_table_end(struct Object *ob);
-/* Retrieves mirrored cache vert, or NULL if there isn't one.
- * NOTE: calling this without ensuring the mirror cache state is bad. */
+/**
+ * Retrieves mirrored cache vert, or NULL if there isn't one.
+ * \note calling this without ensuring the mirror cache state is bad.
+ */
int mesh_get_x_mirror_vert(struct Object *ob,
struct Mesh *me_eval,
int index,
@@ -500,8 +664,16 @@ struct BMVert *editbmesh_get_x_mirror_vert(struct Object *ob,
const float co[3],
int index,
const bool use_topology);
+/**
+ * This is a Mesh-based copy of #mesh_get_x_mirror_faces().
+ */
int *mesh_get_x_mirror_faces(struct Object *ob, struct BMEditMesh *em, struct Mesh *me_eval);
+/**
+ * Wrapper for object-mode/edit-mode.
+ *
+ * call #BM_mesh_elem_table_ensure first for editmesh.
+ */
int ED_mesh_mirror_get_vert(struct Object *ob, int index);
bool ED_mesh_pick_vert(struct bContext *C,
@@ -510,8 +682,18 @@ bool ED_mesh_pick_vert(struct bContext *C,
uint dist_px,
bool use_zbuf,
uint *r_index);
+/**
+ * Face selection in object mode,
+ * currently only weight-paint and vertex-paint use this.
+ *
+ * \return boolean true == Found
+ */
bool ED_mesh_pick_face(
struct bContext *C, struct Object *ob, const int mval[2], uint dist_px, uint *r_index);
+/**
+ * Use when the back buffer stores face index values. but we want a vert.
+ * This gets the face then finds the closest vertex to mval.
+ */
bool ED_mesh_pick_face_vert(
struct bContext *C, struct Object *ob, const int mval[2], uint dist_px, uint *r_index);
diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h
index e68617f7867..5bac452c7c9 100644
--- a/source/blender/editors/include/ED_node.h
+++ b/source/blender/editors/include/ED_node.h
@@ -77,6 +77,7 @@ struct bNodeTree *ED_node_tree_get(struct SpaceNode *snode, int level);
void ED_node_set_active_viewer_key(struct SpaceNode *snode);
/* drawnode.c */
+
void ED_node_init_butfuncs(void);
void ED_init_custom_node_type(struct bNodeType *ntype);
void ED_init_custom_node_socket_type(struct bNodeSocketType *stype);
@@ -87,6 +88,12 @@ void ED_node_draw_snap(
struct View2D *v2d, const float cent[2], float size, NodeBorder border, unsigned int pos);
/* node_draw.cc */
+
+/**
+ * Draw a single node socket at default size.
+ * \note this is only called from external code, internally #node_socket_draw_nested() is used for
+ * optimized drawing of multiple/all sockets of a node.
+ */
void ED_node_socket_draw(struct bNodeSocket *sock,
const struct rcti *rect,
const float color[4],
@@ -94,22 +101,46 @@ void ED_node_socket_draw(struct bNodeSocket *sock,
void ED_node_tree_update(const struct bContext *C);
void ED_node_tag_update_id(struct ID *id);
void ED_node_tag_update_nodetree(struct Main *bmain, struct bNodeTree *ntree, struct bNode *node);
+/**
+ * Sort nodes by selection: unselected nodes first, then selected,
+ * then the active node at the very end. Relative order is kept intact.
+ */
void ED_node_sort(struct bNodeTree *ntree);
float ED_node_grid_size(void);
/* node_relationships.c */
+
+/**
+ * Test == 0, clear all intersect flags.
+ */
void ED_node_link_intersect_test(struct ScrArea *area, int test);
+/**
+ * Assumes link with #NODE_LINKFLAG_HILITE set.
+ */
void ED_node_link_insert(struct Main *bmain, struct ScrArea *area);
/* node_edit.c */
+
void ED_node_set_tree_type(struct SpaceNode *snode, struct bNodeTreeType *typeinfo);
bool ED_node_is_compositor(struct SpaceNode *snode);
bool ED_node_is_shader(struct SpaceNode *snode);
bool ED_node_is_texture(struct SpaceNode *snode);
bool ED_node_is_geometry(struct SpaceNode *snode);
+/**
+ * Assumes nothing being done in ntree yet, sets the default in/out node.
+ * Called from shading buttons or header.
+ */
void ED_node_shader_default(const struct bContext *C, struct ID *id);
+/**
+ * Assumes nothing being done in ntree yet, sets the default in/out node.
+ * Called from shading buttons or header.
+ */
void ED_node_composit_default(const struct bContext *C, struct Scene *scene);
+/**
+ * Assumes nothing being done in ntree yet, sets the default in/out node.
+ * Called from shading buttons or header.
+ */
void ED_node_texture_default(const struct bContext *C, struct Tex *tex);
bool ED_node_select_check(const ListBase *lb);
void ED_node_select_all(ListBase *lb, int action);
@@ -120,19 +151,34 @@ void ED_node_set_active(struct Main *bmain,
struct bNode *node,
bool *r_active_texture_changed);
+/**
+ * \param scene_owner: is the owner of the job,
+ * we don't use it for anything else currently so could also be a void pointer,
+ * but for now keep it an 'Scene' for consistency.
+ *
+ * \note only call from spaces `refresh` callbacks, not direct! - use with care.
+ */
void ED_node_composite_job(const struct bContext *C,
struct bNodeTree *nodetree,
struct Scene *scene_owner);
/* node_ops.c */
+
void ED_operatormacros_node(void);
/* node_view.c */
+/**
+ * Returns mouse position in image space.
+ */
bool ED_space_node_get_position(struct Main *bmain,
struct SpaceNode *snode,
struct ARegion *region,
const int mval[2],
float fpos[2]);
+/**
+ * Returns color in linear space, matching #ED_space_image_color_sample().
+ * And here we've got recursion in the comments tips...
+ */
bool ED_space_node_color_sample(struct Main *bmain,
struct SpaceNode *snode,
struct ARegion *region,
diff --git a/source/blender/editors/include/ED_numinput.h b/source/blender/editors/include/ED_numinput.h
index d5685788ce1..84fa4488374 100644
--- a/source/blender/editors/include/ED_numinput.h
+++ b/source/blender/editors/include/ED_numinput.h
@@ -94,8 +94,14 @@ struct UnitSettings;
*/
void initNumInput(NumInput *n);
+/**
+ * \param str: Must be NUM_STR_REP_LEN * (idx_max + 1) length.
+ */
void outputNumInput(NumInput *n, char *str, struct UnitSettings *unit_settings);
bool hasNumInput(const NumInput *n);
+/**
+ * \warning \a vec must be set beforehand otherwise we risk uninitialized vars.
+ */
bool applyNumInput(NumInput *n, float *vec);
bool handleNumInput(struct bContext *C, NumInput *n, const struct wmEvent *event);
diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h
index 2a557f1abd3..576c6f51362 100644
--- a/source/blender/editors/include/ED_object.h
+++ b/source/blender/editors/include/ED_object.h
@@ -56,12 +56,24 @@ struct wmOperator;
struct wmOperatorType;
/* object_edit.c */
-/* context.object */
+
+/** `context.object` */
struct Object *ED_object_context(const struct bContext *C);
-/* context.object or context.active_object */
+/**
+ * Find the correct active object per context (`context.object` or `context.active_object`)
+ * \note context can be NULL when called from a enum with #PROP_ENUM_NO_CONTEXT.
+ */
struct Object *ED_object_active_context(const struct bContext *C);
void ED_collection_hide_menu_draw(const struct bContext *C, struct uiLayout *layout);
+/**
+ * Return an array of objects:
+ * - When in the property space, return the pinned or active object.
+ * - When in edit-mode/pose-mode, return an array of objects in the mode.
+ * - Otherwise return selected objects,
+ * the callers \a filter_fn needs to check of they are editable
+ * (assuming they need to be modified).
+ */
Object **ED_object_array_in_mode_or_selected(struct bContext *C,
bool (*filter_fn)(const struct Object *ob,
void *user_data),
@@ -81,6 +93,10 @@ bool ED_object_calc_active_center(struct Object *ob, const bool select_only, flo
struct XFormObjectData_Container;
struct XFormObjectData_Container *ED_object_data_xform_container_create(void);
void ED_object_data_xform_container_destroy(struct XFormObjectData_Container *xds);
+/**
+ * This may be called multiple times with the same data.
+ * Each time, the original transformations are re-applied, instead of accumulating the changes.
+ */
void ED_object_data_xform_container_update_all(struct XFormObjectData_Container *xds,
struct Main *bmain,
struct Depsgraph *depsgraph);
@@ -130,6 +146,7 @@ void ED_operatormacros_object(void);
void ED_keymap_object(struct wmKeyConfig *keyconf);
/* object_relations.c */
+
typedef enum eParentType {
PAR_OBJECT,
PAR_ARMATURE,
@@ -163,7 +180,9 @@ extern struct EnumPropertyItem prop_clear_parent_types[];
extern struct EnumPropertyItem prop_make_parent_types[];
#endif
-/* Set the object's parent, return true if successful. */
+/**
+ * Set the object's parent, return true if successful.
+ */
bool ED_object_parent_set(struct ReportList *reports,
const struct bContext *C,
struct Scene *scene,
@@ -175,13 +194,35 @@ bool ED_object_parent_set(struct ReportList *reports,
const int vert_par[3]);
void ED_object_parent_clear(struct Object *ob, const int type);
+/**
+ * Simple API for object selection, rather than just using the flag
+ * this takes into account the 'restrict selection in 3d view' flag.
+ * deselect works always, the restriction just prevents selection
+ *
+ * \note Caller must send a `NC_SCENE | ND_OB_SELECT` notifier
+ * (or a `NC_SCENE | ND_OB_VISIBLE` in case of visibility toggling).
+ */
void ED_object_base_select(struct Base *base, eObjectSelect_Mode mode);
+/**
+ * Change active base, it includes the notifier
+ */
void ED_object_base_activate(struct bContext *C, struct Base *base);
void ED_object_base_activate_with_mode_exit_if_needed(struct bContext *C, struct Base *base);
+/**
+ * Call when the active base has changed.
+ */
void ED_object_base_active_refresh(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer);
+/**
+ * Remove base from a specific scene.
+ * \note now unlinks constraints as well.
+ */
void ED_object_base_free_and_unlink(struct Main *bmain, struct Scene *scene, struct Object *ob);
+/**
+ * Remove base from a specific scene.
+ * `ob` must not be indirectly used.
+ */
void ED_object_base_free_and_unlink_no_indirect_check(struct Main *bmain,
struct Scene *scene,
struct Object *ob);
@@ -191,7 +232,13 @@ bool ED_object_base_deselect_all_ex(struct ViewLayer *view_layer,
bool *r_any_visible);
bool ED_object_base_deselect_all(struct ViewLayer *view_layer, struct View3D *v3d, int action);
-/* single object duplicate, if (dupflag == 0), fully linked, else it uses the flags given */
+/**
+ * Single object duplicate, if `dupflag == 0`, fully linked, else it uses the flags given.
+ * Leaves selection of base/object unaltered.
+ * \note don't call this within a loop since clear_* funcs loop over the entire database.
+ * \note caller must do `DAG_relations_tag_update(bmain);`
+ * this is not done automatic since we may duplicate many objects in a batch.
+ */
struct Base *ED_object_add_duplicate(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,
@@ -211,12 +258,21 @@ enum {
EM_FREEDATA = (1 << 0),
EM_NO_CONTEXT = (1 << 1),
};
+/**
+ * \param flag:
+ * - If #EM_FREEDATA isn't in the flag, use ED_object_editmode_load directly.
+ */
bool ED_object_editmode_exit_ex(struct Main *bmain,
struct Scene *scene,
struct Object *obedit,
int flag);
bool ED_object_editmode_exit(struct bContext *C, int flag);
+/**
+ * Support freeing edit-mode data without flushing it back to the object.
+ *
+ * \return true if data was freed.
+ */
bool ED_object_editmode_free_ex(struct Main *bmain, struct Object *obedit);
bool ED_object_editmode_exit_multi_ex(struct Main *bmain,
@@ -284,6 +340,10 @@ void ED_object_rotation_from_view(struct bContext *C, float rot[3], const char a
void ED_object_base_init_transform_on_add(struct Object *object,
const float loc[3],
const float rot[3]);
+/**
+ * Uses context to figure out transform for primitive.
+ * Returns standard diameter.
+ */
float ED_object_new_primitive_matrix(struct bContext *C,
struct Object *obedit,
const float loc[3],
@@ -291,8 +351,9 @@ float ED_object_new_primitive_matrix(struct bContext *C,
const float scale[3],
float primmat[4][4]);
-/* Avoid allowing too much insane values even by typing
- * (typos can hang/crash Blender otherwise). */
+/**
+ * Avoid allowing too much insane values even by typing (typos can hang/crash Blender otherwise).
+ */
#define OBJECT_ADD_SIZE_MAXF 1.0e12f
void ED_object_add_unit_props_size(struct wmOperatorType *ot);
@@ -310,6 +371,12 @@ bool ED_object_add_generic_get_opts(struct bContext *C,
unsigned short *r_local_view_bits,
bool *r_is_view_aligned);
+/**
+ * For object add primitive operators, or for object creation when `obdata != NULL`.
+ * \param obdata: Assigned to #Object.data, with increased user count.
+ *
+ * \note Do not call undo push in this function (users of this function have to).
+ */
struct Object *ED_object_add_type_with_obdata(struct bContext *C,
const int type,
const char *name,
@@ -327,9 +394,16 @@ struct Object *ED_object_add_type(struct bContext *C,
const unsigned short local_view_bits)
ATTR_NONNULL(1) ATTR_RETURNS_NONNULL;
+/**
+ * Not an especially efficient function, only added so the single user button can be functional.
+ */
void ED_object_single_user(struct Main *bmain, struct Scene *scene, struct Object *ob);
/* object motion paths */
+
+/**
+ * Clear motion paths for all objects.
+ */
void ED_objects_clear_paths(struct bContext *C, bool only_selected);
/* Corresponds to eAnimvizCalcRange. */
@@ -339,6 +413,12 @@ typedef enum eObjectPathCalcRange {
OBJECT_PATH_CALC_RANGE_FULL,
} eObjectPathCalcRange;
+/**
+ * For the objects with animation: update paths for those that have got them
+ * This should selectively update paths that exist.
+ *
+ * To be called from various tools that do incremental updates
+ */
void ED_objects_recalculate_paths(struct bContext *C,
struct Scene *scene,
eObjectPathCalcRange range,
@@ -353,11 +433,26 @@ void ED_objects_recalculate_paths_visible(struct bContext *C,
eObjectPathCalcRange range);
/* constraints */
+/**
+ * If object is in pose-mode, return active bone constraints, else object constraints.
+ * No constraints are returned for a bone on an inactive bone-layer.
+ */
struct ListBase *ED_object_constraint_active_list(struct Object *ob);
+/**
+ * Get the constraints for the active pose bone. Bone may be on an inactive bone-layer
+ * (unlike #ED_object_constraint_active_list, such constraints are not excluded here).
+ */
struct ListBase *ED_object_pose_constraint_list(const struct bContext *C);
+/**
+ * Find the list that a given constraint belongs to,
+ * and/or also get the posechannel this is from (if applicable).
+ */
struct ListBase *ED_object_constraint_list_from_constraint(struct Object *ob,
struct bConstraint *con,
struct bPoseChannel **r_pchan);
+/**
+ * Single constraint.
+ */
struct bConstraint *ED_object_constraint_active_get(struct Object *ob);
void object_test_constraints(struct Main *bmain, struct Object *ob);
@@ -389,7 +484,17 @@ void ED_object_constraint_copy_for_pose(struct Main *bmain,
struct bConstraint *con);
/* object_modes.c */
+
+/**
+ * Checks the mode to be set is compatible with the object
+ * should be made into a generic function
+ */
bool ED_object_mode_compat_test(const struct Object *ob, eObjectMode mode);
+/**
+ * Sets the mode to a compatible state (use before entering the mode).
+ *
+ * This is so each mode's exec function can call
+ */
bool ED_object_mode_compat_set(struct bContext *C,
struct Object *ob,
eObjectMode mode,
@@ -412,11 +517,18 @@ void ED_object_posemode_set_for_weight_paint(struct bContext *C,
const bool is_mode_set);
/* object_modifier.c */
+
enum {
MODIFIER_APPLY_DATA = 1,
MODIFIER_APPLY_SHAPE,
};
+/**
+ * Add a modifier to given object, including relevant extra processing needed by some physics types
+ * (particles, simulations...).
+ *
+ * \param scene: is only used to set current frame in some cases, and may be NULL.
+ */
struct ModifierData *ED_object_modifier_add(struct ReportList *reports,
struct Main *bmain,
struct Scene *scene,
@@ -465,12 +577,25 @@ void ED_object_modifier_copy_to_object(struct bContext *C,
struct Object *ob_src,
struct ModifierData *md);
+/**
+ * If the object data of 'orig_ob' has other users, run 'callback' on
+ * each of them.
+ *
+ * If include_orig is true, the callback will run on 'orig_ob' too.
+ *
+ * If the callback ever returns true, iteration will stop and the
+ * function value will be true. Otherwise the function returns false.
+ */
bool ED_object_iter_other(struct Main *bmain,
struct Object *orig_ob,
const bool include_orig,
bool (*callback)(struct Object *ob, void *callback_data),
void *callback_data);
+/**
+ * Use with #ED_object_iter_other(). Sets the total number of levels
+ * for any multi-res modifiers on the object to the int pointed to by callback_data.
+ */
bool ED_object_multires_update_totlevels_cb(struct Object *ob, void *totlevel_v);
/* object_greasepencil_modifier.c */
@@ -546,16 +671,40 @@ void ED_object_check_force_modifiers(struct Main *bmain,
struct Scene *scene,
struct Object *object);
+/**
+ * If id is not already an Object, try to find an object that uses it as data.
+ * Prefers active, then selected, then visible/selectable.
+ */
struct Base *ED_object_find_first_by_data_id(struct ViewLayer *view_layer, struct ID *id);
+/**
+ * Select and make the target object active in the view layer.
+ * If already selected, selection isn't changed.
+ *
+ * \returns false if not found in current view layer
+ */
bool ED_object_jump_to_object(struct bContext *C, struct Object *ob, const bool reveal_hidden);
+/**
+ * Select and make the target object and bone active.
+ * Switches to Pose mode if in Object mode so the selection is visible.
+ * Un-hides the target bone and bone layer if necessary.
+ *
+ * \returns false if object not in layer, bone not found, or other error
+ */
bool ED_object_jump_to_bone(struct bContext *C,
struct Object *ob,
const char *bone_name,
const bool reveal_hidden);
/* object_facemap_ops.c */
+
+/**
+ * Called while not in edit-mode.
+ */
void ED_object_facemap_face_add(struct Object *ob, struct bFaceMap *fmap, int facenum);
+/**
+ * Called while not in edit-mode.
+ */
void ED_object_facemap_face_remove(struct Object *ob, struct bFaceMap *fmap, int facenum);
/* object_data_transform.c */
diff --git a/source/blender/editors/include/ED_outliner.h b/source/blender/editors/include/ED_outliner.h
index 1d1471f0be6..99f65010595 100644
--- a/source/blender/editors/include/ED_outliner.h
+++ b/source/blender/editors/include/ED_outliner.h
@@ -33,10 +33,21 @@ struct bContext;
bool ED_outliner_collections_editor_poll(struct bContext *C);
+/**
+ * Populates the \param objects: ListBase with all the outliner selected objects
+ * We store it as (Object *)LinkData->data
+ * \param objects: expected to be empty
+ */
void ED_outliner_selected_objects_get(const struct bContext *C, struct ListBase *objects);
+/**
+ * Get base of object under cursor. Used for eyedropper tool.
+ */
struct Base *ED_outliner_give_base_under_cursor(struct bContext *C, const int mval[2]);
+/**
+ * Functions for tagging outliner selection syncing is dirty from operators.
+ */
void ED_outliner_select_sync_from_object_tag(struct bContext *C);
void ED_outliner_select_sync_from_edit_bone_tag(struct bContext *C);
void ED_outliner_select_sync_from_pose_bone_tag(struct bContext *C);
@@ -45,9 +56,15 @@ void ED_outliner_select_sync_from_all_tag(struct bContext *C);
bool ED_outliner_select_sync_is_dirty(const struct bContext *C);
+/**
+ * Set clean outliner and mark other outliners for syncing.
+ */
void ED_outliner_select_sync_from_outliner(struct bContext *C,
struct SpaceOutliner *space_outliner);
+/**
+ * Copy sync select dirty flag from window manager to all outliners to be synced lazily on draw.
+ */
void ED_outliner_select_sync_flag_outliners(const struct bContext *C);
#ifdef __cplusplus
diff --git a/source/blender/editors/include/ED_paint.h b/source/blender/editors/include/ED_paint.h
index 6a28baa4ca1..1d1ba264de5 100644
--- a/source/blender/editors/include/ED_paint.h
+++ b/source/blender/editors/include/ED_paint.h
@@ -54,11 +54,21 @@ void ED_imapaint_bucket_fill(struct bContext *C,
const int mouse[2]);
/* paint_image_proj.c */
+
void ED_paint_data_warning(struct ReportList *reports, bool uvs, bool mat, bool tex, bool stencil);
+/**
+ * Make sure that active object has a material,
+ * and assign UVs and image layers if they do not exist.
+ */
bool ED_paint_proj_mesh_data_check(
struct Scene *scene, struct Object *ob, bool *uvs, bool *mat, bool *tex, bool *stencil);
/* image_undo.c */
+
+/**
+ * The caller is responsible for running #ED_image_undo_push_end,
+ * failure to do so causes an invalid state for the undo system.
+ */
void ED_image_undo_push_begin(const char *name, int paint_mode);
void ED_image_undo_push_begin_with_image(const char *name,
struct Image *image,
@@ -66,8 +76,12 @@ void ED_image_undo_push_begin_with_image(const char *name,
struct ImageUser *iuser);
void ED_image_undo_push_end(void);
+/**
+ * Restore painting image to previous state. Used for anchored and drag-dot style brushes.
+ */
void ED_image_undo_restore(struct UndoStep *us);
+/** Export for ED_undo_sys. */
void ED_image_undosys_type(struct UndoType *ut);
void *ED_image_paint_tile_find(struct ListBase *paint_tiles,
@@ -100,9 +114,11 @@ struct ListBase *ED_image_paint_tile_list_get(void);
(((size) + ED_IMAGE_UNDO_TILE_SIZE - 1) >> ED_IMAGE_UNDO_TILE_BITS)
/* paint_curve_undo.c */
+
void ED_paintcurve_undo_push_begin(const char *name);
void ED_paintcurve_undo_push_end(struct bContext *C);
+/** Export for ED_undo_sys. */
void ED_paintcurve_undosys_type(struct UndoType *ut);
#ifdef __cplusplus
diff --git a/source/blender/editors/include/ED_particle.h b/source/blender/editors/include/ED_particle.h
index 5318c653b6d..ce25943b40a 100644
--- a/source/blender/editors/include/ED_particle.h
+++ b/source/blender/editors/include/ED_particle.h
@@ -39,10 +39,12 @@ struct rcti;
struct wmGenericUserData;
/* particle edit mode */
+
void PE_free_ptcache_edit(struct PTCacheEdit *edit);
int PE_start_edit(struct PTCacheEdit *edit);
/* access */
+
struct PTCacheEdit *PE_get_current_from_psys(struct ParticleSystem *psys);
struct PTCacheEdit *PE_get_current(struct Depsgraph *depsgraph,
struct Scene *scene,
@@ -59,6 +61,7 @@ int PE_minmax(struct Depsgraph *depsgraph,
struct ParticleEditSettings *PE_settings(struct Scene *scene);
/* update calls */
+
void PE_hide_keys_time(struct Scene *scene, struct PTCacheEdit *edit, float cfra);
void PE_update_object(struct Depsgraph *depsgraph,
struct Scene *scene,
@@ -66,6 +69,7 @@ void PE_update_object(struct Depsgraph *depsgraph,
int useflag);
/* selection tools */
+
bool PE_mouse_particles(
struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
bool PE_box_select(struct bContext *C, const struct rcti *rect, const int sel_op);
@@ -82,6 +86,8 @@ bool PE_deselect_all_visible_ex(struct PTCacheEdit *edit);
bool PE_deselect_all_visible(struct bContext *C);
/* particle_edit_undo.c */
+
+/** Export for ED_undo_sys. */
void ED_particle_undosys_type(struct UndoType *ut);
#ifdef __cplusplus
diff --git a/source/blender/editors/include/ED_render.h b/source/blender/editors/include/ED_render.h
index 5cdcbbab42a..f60d62ed384 100644
--- a/source/blender/editors/include/ED_render.h
+++ b/source/blender/editors/include/ED_render.h
@@ -41,6 +41,7 @@ struct bContext;
struct bScreen;
struct wmWindow;
struct wmWindowManager;
+enum eIconSizes;
/* render_ops.c */
@@ -55,7 +56,14 @@ void ED_render_view_layer_changed(struct Main *bmain, struct bScreen *screen);
/* Callbacks handling data update events coming from depsgraph. */
void ED_render_id_flush_update(const struct DEGEditorUpdateContext *update_ctx, struct ID *id);
+/**
+ * Update all 3D viewport render and draw engines on changes to the scene.
+ * This is called by the dependency graph when it detects changes.
+ */
void ED_render_scene_update(const struct DEGEditorUpdateContext *update_ctx, const bool updated);
+/**
+ * Update 3D viewport render or draw engine on changes to the scene or view settings.
+ */
void ED_render_view3d_update(struct Depsgraph *depsgraph,
struct wmWindow *window,
struct ScrArea *area,
@@ -69,19 +77,22 @@ struct Scene *ED_render_job_get_current_scene(const struct bContext *C);
* pr_method:
* - PR_BUTS_RENDER: preview is rendered for buttons window
* - PR_ICON_RENDER: preview is rendered for icons. hopefully fast enough for at least 32x32
- * - PR_NODE_RENDER: preview is rendered for node editor
* - PR_ICON_DEFERRED: No render, we just ensure deferred icon data gets generated.
*/
typedef enum ePreviewRenderMethod {
PR_BUTS_RENDER = 0,
PR_ICON_RENDER = 1,
- PR_NODE_RENDER = 2,
- PR_ICON_DEFERRED = 3,
+ PR_ICON_DEFERRED = 2,
} ePreviewRenderMethod;
void ED_preview_ensure_dbase(void);
void ED_preview_free_dbase(void);
+/**
+ * Check if \a id is supported by the automatic preview render.
+ */
+bool ED_preview_id_is_supported(const struct ID *id);
+
void ED_preview_shader_job(const struct bContext *C,
void *owner,
struct ID *id,
@@ -103,6 +114,11 @@ void ED_preview_icon_job(const struct bContext *C,
int sizex,
int sizey,
const bool delay);
+
+void ED_preview_restart_queue_free(void);
+void ED_preview_restart_queue_add(struct ID *id, enum eIconSizes size);
+void ED_preview_restart_queue_work(const struct bContext *C);
+
void ED_preview_kill_jobs(struct wmWindowManager *wm, struct Main *bmain);
void ED_preview_draw(const struct bContext *C, void *idp, void *parentp, void *slot, rcti *rect);
diff --git a/source/blender/editors/include/ED_scene.h b/source/blender/editors/include/ED_scene.h
index e3abd26a4cd..e4e7a4bdfce 100644
--- a/source/blender/editors/include/ED_scene.h
+++ b/source/blender/editors/include/ED_scene.h
@@ -32,7 +32,14 @@ struct Scene *ED_scene_add(struct Main *bmain,
struct bContext *C,
struct wmWindow *win,
enum eSceneCopyMethod method) ATTR_NONNULL();
+/**
+ * \note Only call outside of area/region loops.
+ * \return true if successful.
+ */
bool ED_scene_delete(struct bContext *C, struct Main *bmain, struct Scene *scene) ATTR_NONNULL();
+/**
+ * Depsgraph updates after scene becomes active in a window.
+ */
void ED_scene_change_update(struct Main *bmain, struct Scene *scene, struct ViewLayer *layer)
ATTR_NONNULL();
bool ED_scene_view_layer_delete(struct Main *bmain,
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index eee119c0712..c65ef3e397d 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -65,33 +65,65 @@ struct wmWindow;
struct wmWindowManager;
/* regions */
+/** Only exported for WM. */
void ED_region_do_listen(struct wmRegionListenerParams *params);
+/** Only exported for WM. */
void ED_region_do_layout(struct bContext *C, struct ARegion *region);
+/** Only exported for WM. */
void ED_region_do_draw(struct bContext *C, struct ARegion *region);
void ED_region_exit(struct bContext *C, struct ARegion *region);
+/**
+ * Utility to exit and free an area-region. Screen level regions (menus/popups) need to be treated
+ * slightly differently, see #ui_region_temp_remove().
+ */
void ED_region_remove(struct bContext *C, struct ScrArea *area, struct ARegion *region);
void ED_region_pixelspace(const struct ARegion *region);
+/**
+ * Call to move a popup window (keep OpenGL context free!)
+ */
void ED_region_update_rect(struct ARegion *region);
+/**
+ * Externally called for floating regions like menus.
+ */
void ED_region_floating_init(struct ARegion *region);
void ED_region_tag_redraw(struct ARegion *region);
void ED_region_tag_redraw_partial(struct ARegion *region, const struct rcti *rct, bool rebuild);
void ED_region_tag_redraw_cursor(struct ARegion *region);
void ED_region_tag_redraw_no_rebuild(struct ARegion *region);
void ED_region_tag_refresh_ui(struct ARegion *region);
+/**
+ * Tag editor overlays to be redrawn. If in doubt about which parts need to be redrawn (partial
+ * clipping rectangle set), redraw everything.
+ */
void ED_region_tag_redraw_editor_overlays(struct ARegion *region);
+/**
+ * Set the temporary update flag for property search.
+ */
void ED_region_search_filter_update(const struct ScrArea *area, struct ARegion *region);
+/**
+ * Returns the search string if the space type and region type support property search.
+ */
const char *ED_area_region_search_filter_get(const struct ScrArea *area,
const struct ARegion *region);
void ED_region_panels_init(struct wmWindowManager *wm, struct ARegion *region);
void ED_region_panels_ex(const struct bContext *C, struct ARegion *region, const char *contexts[]);
void ED_region_panels(const struct bContext *C, struct ARegion *region);
+/**
+ * \param contexts: A NULL terminated array of context strings to match against.
+ * Matching against any of these strings will draw the panel.
+ * Can be NULL to skip context checks.
+ */
void ED_region_panels_layout_ex(const struct bContext *C,
struct ARegion *region,
struct ListBase *paneltypes,
const char *contexts[],
const char *category_override);
+/**
+ * Build the same panel list as #ED_region_panels_layout_ex and checks whether any
+ * of the panels contain a search result based on the area / region's search filter.
+ */
bool ED_region_property_search(const struct bContext *C,
struct ARegion *region,
struct ListBase *paneltypes,
@@ -107,11 +139,20 @@ void ED_region_header_layout(const struct bContext *C, struct ARegion *region);
void ED_region_header_draw(const struct bContext *C, struct ARegion *region);
void ED_region_cursor_set(struct wmWindow *win, struct ScrArea *area, struct ARegion *region);
+/**
+ * Exported to all editors, uses fading default.
+ */
void ED_region_toggle_hidden(struct bContext *C, struct ARegion *region);
+/**
+ * For use after changing visibility of regions.
+ */
void ED_region_visibility_change_update(struct bContext *C,
struct ScrArea *area,
struct ARegion *region);
/* screen_ops.c */
+/**
+ * \note Assumes that \a region itself is not a split version from previous region.
+ */
void ED_region_visibility_change_update_animated(struct bContext *C,
struct ScrArea *area,
struct ARegion *region);
@@ -129,6 +170,9 @@ void ED_region_grid_draw(struct ARegion *region, float zoomx, float zoomy, float
float ED_region_blend_alpha(struct ARegion *region);
void ED_region_visible_rect_calc(struct ARegion *region, struct rcti *rect);
const rcti *ED_region_visible_rect(ARegion *region);
+/**
+ * Overlapping regions only in the following restricted cases.
+ */
bool ED_region_is_overlap(int spacetype, int regiontype);
int ED_region_snap_size_test(const struct ARegion *region);
@@ -142,39 +186,76 @@ void ED_area_do_msg_notify_tag_refresh(struct bContext *C,
struct wmMsgSubscribeKey *msg_key,
struct wmMsgSubscribeValue *msg_val);
+/**
+ * Follow #ARegionType.message_subscribe.
+ */
void ED_area_do_mgs_subscribe_for_tool_header(const struct wmRegionMessageSubscribeParams *params);
void ED_area_do_mgs_subscribe_for_tool_ui(const struct wmRegionMessageSubscribeParams *params);
/* message bus */
+
+/**
+ * Generate subscriptions for this region.
+ */
void ED_region_message_subscribe(struct wmRegionMessageSubscribeParams *params);
/* spaces */
+
+/**
+ * \note Keymap definitions are registered only once per WM initialize,
+ * usually on file read, using the keymap the actual areas/regions add the handlers.
+ * \note Called in wm.c. */
void ED_spacetypes_keymap(struct wmKeyConfig *keyconf);
+/**
+ * Returns offset for next button in header.
+ */
int ED_area_header_switchbutton(const struct bContext *C, struct uiBlock *block, int yco);
/* areas */
+/**
+ * Called in screen_refresh, or screens_init, also area size changes.
+ */
void ED_area_init(struct wmWindowManager *wm, struct wmWindow *win, struct ScrArea *area);
void ED_area_exit(struct bContext *C, struct ScrArea *area);
int ED_screen_area_active(const struct bContext *C);
void ED_screen_global_areas_refresh(struct wmWindow *win);
void ED_screen_global_areas_sync(struct wmWindow *win);
+/** Only exported for WM. */
void ED_area_do_listen(struct wmSpaceTypeListenerParams *params);
void ED_area_tag_redraw(ScrArea *area);
void ED_area_tag_redraw_no_rebuild(ScrArea *area);
void ED_area_tag_redraw_regiontype(ScrArea *area, int type);
void ED_area_tag_refresh(ScrArea *area);
+/**
+ * Only exported for WM.
+ */
void ED_area_do_refresh(struct bContext *C, ScrArea *area);
struct AZone *ED_area_azones_update(ScrArea *area, const int mouse_xy[2]);
+/**
+ * Use NULL to disable it.
+ */
void ED_area_status_text(ScrArea *area, const char *str);
+/**
+ * \param skip_region_exit: Skip calling area exit callback. Set for opening temp spaces.
+ */
void ED_area_newspace(struct bContext *C, ScrArea *area, int type, const bool skip_region_exit);
void ED_area_prevspace(struct bContext *C, ScrArea *area);
void ED_area_swapspace(struct bContext *C, ScrArea *sa1, ScrArea *sa2);
int ED_area_headersize(void);
int ED_area_footersize(void);
+/**
+ * \return the final height of a global \a area, accounting for DPI.
+ */
int ED_area_global_size_y(const ScrArea *area);
int ED_area_global_min_size_y(const ScrArea *area);
int ED_area_global_max_size_y(const ScrArea *area);
bool ED_area_is_global(const ScrArea *area);
+/**
+ * For now we just assume all global areas are made up out of horizontal bars
+ * with the same size. A fixed size could be stored in ARegion instead if needed.
+ *
+ * \return the DPI aware height of a single bar/region in global areas.
+ */
int ED_region_global_size_y(void);
void ED_area_update_region_sizes(struct wmWindowManager *wm,
struct wmWindow *win,
@@ -204,31 +285,90 @@ ScrArea *ED_screen_areas_iter_next(const bScreen *screen, const ScrArea *area);
vert_name->next)
/* screens */
+
+/**
+ * File read, set all screens, ....
+ */
void ED_screens_init(struct Main *bmain, struct wmWindowManager *wm);
+/**
+ * Only for edge lines between areas.
+ */
void ED_screen_draw_edges(struct wmWindow *win);
+
+/**
+ * Make this screen usable.
+ * for file read and first use, for scaling window, area moves.
+ */
void ED_screen_refresh(struct wmWindowManager *wm, struct wmWindow *win);
void ED_screen_ensure_updated(struct wmWindowManager *wm,
struct wmWindow *win,
struct bScreen *screen);
void ED_screen_do_listen(struct bContext *C, struct wmNotifier *note);
+/**
+ * \brief Change the active screen.
+ *
+ * Operator call, WM + Window + screen already existed before
+ *
+ * \warning Do NOT call in area/region queues!
+ * \returns if screen changing was successful.
+ */
bool ED_screen_change(struct bContext *C, struct bScreen *screen);
void ED_screen_scene_change(struct bContext *C,
struct wmWindow *win,
struct Scene *scene,
const bool refresh_toolsystem);
+/**
+ * Called in wm_event_system.c. sets state vars in screen, cursors.
+ * event type is mouse move.
+ */
void ED_screen_set_active_region(struct bContext *C, struct wmWindow *win, const int xy[2]);
void ED_screen_exit(struct bContext *C, struct wmWindow *window, struct bScreen *screen);
+/**
+ * redraws: uses defines from `stime->redraws`
+ * \param enable: 1 - forward on, -1 - backwards on, 0 - off.
+ */
void ED_screen_animation_timer(struct bContext *C, int redraws, int sync, int enable);
void ED_screen_animation_timer_update(struct bScreen *screen, int redraws);
void ED_screen_restore_temp_type(struct bContext *C, ScrArea *area);
ScrArea *ED_screen_full_newspace(struct bContext *C, ScrArea *area, int type);
+/**
+ * \a was_prev_temp for the case previous space was a temporary full-screen as well
+ */
void ED_screen_full_prevspace(struct bContext *C, ScrArea *area);
+/**
+ * Restore a screen / area back to default operation, after temp full-screen modes.
+ */
void ED_screen_full_restore(struct bContext *C, ScrArea *area);
+/**
+ * Create a new temporary screen with a maximized, empty area.
+ * This can be closed with #ED_screen_state_toggle().
+ *
+ * Use this to just create a new maximized screen/area, rather than maximizing an existing one.
+ * Otherwise, maximize with #ED_screen_state_toggle().
+ */
bScreen *ED_screen_state_maximized_create(struct bContext *C);
+/**
+ * This function toggles: if area is maximized/full then the parent will be restored.
+ *
+ * Use #ED_screen_state_maximized_create() if you do not want the toggle behavior when changing to
+ * a maximized area. I.e. if you just want to open a new maximized screen/area, not maximize a
+ * specific area. In the former case, space data of the maximized and non-maximized area should be
+ * independent, in the latter it should be the same.
+ *
+ * \warning \a area may be freed.
+ */
struct ScrArea *ED_screen_state_toggle(struct bContext *C,
struct wmWindow *win,
struct ScrArea *area,
const short state);
+/**
+ * Wrapper to open a temporary space either as fullscreen space, or as separate window, as defined
+ * by \a display_type.
+ *
+ * \param title: Title to set for the window, if a window is spawned.
+ * \param x, y: Position of the window, if a window is spawned.
+ * \param sizex, sizey: Dimensions of the window, if a window is spawned.
+ */
ScrArea *ED_screen_temp_space_open(struct bContext *C,
const char *title,
int x,
@@ -243,8 +383,15 @@ void ED_screens_footer_tools_menu_create(struct bContext *C, struct uiLayout *la
void ED_screens_navigation_bar_tools_menu_create(struct bContext *C,
struct uiLayout *layout,
void *arg);
+/**
+ * \return true if any active area requires to see in 3D.
+ */
bool ED_screen_stereo3d_required(const struct bScreen *screen, const struct Scene *scene);
Scene *ED_screen_scene_find(const struct bScreen *screen, const struct wmWindowManager *wm);
+/**
+ * Find the scene displayed in \a screen.
+ * \note Assumes \a screen to be visible/active!
+ */
Scene *ED_screen_scene_find_with_window(const struct bScreen *screen,
const struct wmWindowManager *wm,
struct wmWindow **r_window);
@@ -253,31 +400,64 @@ ScrArea *ED_screen_area_find_with_spacedata(const bScreen *screen,
const bool only_visible);
struct wmWindow *ED_screen_window_find(const struct bScreen *screen,
const struct wmWindowManager *wm);
+/**
+ * Render the preview for a screen layout in \a screen.
+ */
void ED_screen_preview_render(const struct bScreen *screen,
int size_x,
int size_y,
unsigned int *r_rect) ATTR_NONNULL();
/* workspaces */
+
struct WorkSpace *ED_workspace_add(struct Main *bmain, const char *name) ATTR_NONNULL();
+/**
+ * \brief Change the active workspace.
+ *
+ * Operator call, WM + Window + screen already existed before
+ * Pretty similar to #ED_screen_change since changing workspace also changes screen.
+ *
+ * \warning Do NOT call in area/region queues!
+ * \returns if workspace changing was successful.
+ */
bool ED_workspace_change(struct WorkSpace *workspace_new,
struct bContext *C,
struct wmWindowManager *wm,
struct wmWindow *win) ATTR_NONNULL();
+/**
+ * Duplicate a workspace including its layouts. Does not activate the workspace, but
+ * it stores the screen-layout to be activated (BKE_workspace_temp_layout_store)
+ */
struct WorkSpace *ED_workspace_duplicate(struct WorkSpace *workspace_old,
struct Main *bmain,
struct wmWindow *win);
+/**
+ * \return if succeeded.
+ */
bool ED_workspace_delete(struct WorkSpace *workspace,
struct Main *bmain,
struct bContext *C,
struct wmWindowManager *wm) ATTR_NONNULL();
+/**
+ * Some editor data may need to be synced with scene data (3D View camera and layers).
+ * This function ensures data is synced for editors in active layout of \a workspace.
+ */
void ED_workspace_scene_data_sync(struct WorkSpaceInstanceHook *hook, Scene *scene) ATTR_NONNULL();
+/**
+ * Make sure there is a non-full-screen layout to switch to that isn't used yet by an other window.
+ * Needed for workspace or screen switching to ensure valid screens.
+ *
+ * \param layout_fallback_base: As last resort, this layout is duplicated and returned.
+ */
struct WorkSpaceLayout *ED_workspace_screen_change_ensure_unused_layout(
struct Main *bmain,
struct WorkSpace *workspace,
struct WorkSpaceLayout *layout_new,
const struct WorkSpaceLayout *layout_fallback_base,
struct wmWindow *win) ATTR_NONNULL();
+/**
+ * Empty screen, with 1 dummy area without space-data. Uses window size.
+ */
struct WorkSpaceLayout *ED_workspace_layout_add(struct Main *bmain,
struct WorkSpace *workspace,
struct wmWindow *win,
@@ -286,6 +466,10 @@ struct WorkSpaceLayout *ED_workspace_layout_duplicate(struct Main *bmain,
struct WorkSpace *workspace,
const struct WorkSpaceLayout *layout_old,
struct wmWindow *win) ATTR_NONNULL();
+/**
+ * \warning Only call outside of area/region loops!
+ * \return true if succeeded.
+ */
bool ED_workspace_layout_delete(struct WorkSpace *workspace,
struct WorkSpaceLayout *layout_old,
struct bContext *C) ATTR_NONNULL();
@@ -296,22 +480,42 @@ bool ED_workspace_layout_cycle(struct WorkSpace *workspace,
void ED_workspace_status_text(struct bContext *C, const char *str);
/* anim */
+/**
+ * Results in fully updated anim system.
+ */
void ED_update_for_newframe(struct Main *bmain, struct Depsgraph *depsgraph);
+/**
+ * Update frame rate info for viewport drawing.
+ */
void ED_refresh_viewport_fps(struct bContext *C);
+/**
+ * Toggle operator.
+ */
int ED_screen_animation_play(struct bContext *C, int sync, int mode);
+/**
+ * Find window that owns the animation timer.
+ */
bScreen *ED_screen_animation_playing(const struct wmWindowManager *wm);
bScreen *ED_screen_animation_no_scrub(const struct wmWindowManager *wm);
/* screen keymaps */
+/* called in spacetypes.c */
void ED_operatortypes_screen(void);
+/* called in spacetypes.c */
void ED_keymap_screen(struct wmKeyConfig *keyconf);
-/* workspace keymaps */
+/**
+ * Workspace key-maps.
+ */
void ED_operatortypes_workspace(void);
/* operators; context poll callbacks */
+
bool ED_operator_screenactive(struct bContext *C);
bool ED_operator_screenactive_nobackground(struct bContext *C);
+/**
+ * When mouse is over area-edge.
+ */
bool ED_operator_screen_mainwinactive(struct bContext *C);
bool ED_operator_areaactive(struct bContext *C);
bool ED_operator_regionactive(struct bContext *C);
@@ -319,14 +523,31 @@ bool ED_operator_regionactive(struct bContext *C);
bool ED_operator_scene(struct bContext *C);
bool ED_operator_scene_editable(struct bContext *C);
bool ED_operator_objectmode(struct bContext *C);
+/**
+ * Same as #ED_operator_objectmode() but additionally sets a "disabled hint". That is, a message
+ * to be displayed to the user explaining why the operator can't be used in current context.
+ */
bool ED_operator_objectmode_poll_msg(struct bContext *C);
bool ED_operator_view3d_active(struct bContext *C);
bool ED_operator_region_view3d_active(struct bContext *C);
+/**
+ * Generic for any view2d which uses anim_ops.
+ */
bool ED_operator_animview_active(struct bContext *C);
bool ED_operator_outliner_active(struct bContext *C);
bool ED_operator_outliner_active_no_editobject(struct bContext *C);
+/**
+ * \note Will return true for file spaces in either file or asset browsing mode! See
+ * #ED_operator_file_browsing_active() (file browsing only) and
+ * #ED_operator_asset_browsing_active() (asset browsing only).
+ */
bool ED_operator_file_active(struct bContext *C);
+/**
+ * \note Will only return true if the file space is in file browsing mode, not asset browsing! See
+ * #ED_operator_file_active() (file or asset browsing) and
+ * #ED_operator_asset_browsing_active() (asset browsing only).
+ */
bool ED_operator_file_browsing_active(struct bContext *C);
bool ED_operator_asset_browsing_active(struct bContext *C);
bool ED_operator_spreadsheet_active(struct bContext *C);
@@ -345,6 +566,9 @@ bool ED_operator_console_active(struct bContext *C);
bool ED_operator_object_active(struct bContext *C);
bool ED_operator_object_active_editable_ex(struct bContext *C, const Object *ob);
bool ED_operator_object_active_editable(struct bContext *C);
+/**
+ * Object must be editable and fully local (i.e. not an override).
+ */
bool ED_operator_object_active_local_editable_ex(struct bContext *C, const Object *ob);
bool ED_operator_object_active_local_editable(struct bContext *C);
bool ED_operator_object_active_editable_mesh(struct bContext *C);
@@ -363,11 +587,21 @@ bool ED_operator_editsurfcurve_region_view3d(struct bContext *C);
bool ED_operator_editfont(struct bContext *C);
bool ED_operator_editlattice(struct bContext *C);
bool ED_operator_editmball(struct bContext *C);
+/**
+ * Wrapper for #ED_space_image_show_uvedit.
+ */
bool ED_operator_uvedit(struct bContext *C);
bool ED_operator_uvedit_space_image(struct bContext *C);
bool ED_operator_uvmap(struct bContext *C);
bool ED_operator_posemode_exclusive(struct bContext *C);
+/**
+ * Object must be editable, fully local (i.e. not an override), and exclusively in Pose mode.
+ */
bool ED_operator_object_active_local_editable_posemode_exclusive(struct bContext *C);
+/**
+ * Allows for pinned pose objects to be used in the object buttons
+ * and the non-active pose object to be used in the 3D view.
+ */
bool ED_operator_posemode_context(struct bContext *C);
bool ED_operator_posemode(struct bContext *C);
bool ED_operator_posemode_local(struct bContext *C);
@@ -418,8 +652,15 @@ void ED_region_cache_draw_cached_segments(struct ARegion *region,
const int efra);
/* area_utils.c */
+
+/**
+ * Callback for #ARegionType.message_subscribe
+ */
void ED_region_generic_tools_region_message_subscribe(
const struct wmRegionMessageSubscribeParams *params);
+/**
+ * Callback for #ARegionType.snap_size
+ */
int ED_region_generic_tools_region_snap_size(const struct ARegion *region, int size, int axis);
/* area_query.c */
@@ -440,15 +681,29 @@ bool ED_region_overlap_isect_xy_with_margin(const ARegion *region,
bool ED_region_panel_category_gutter_calc_rect(const ARegion *region, rcti *r_region_gutter);
bool ED_region_panel_category_gutter_isect_xy(const ARegion *region, const int event_xy[2]);
+/**
+ * \note: This may return true for multiple overlapping regions.
+ * If it matters, check overlapped regions first (#ARegion.overlap).
+ */
bool ED_region_contains_xy(const struct ARegion *region, const int event_xy[2]);
+/**
+ * Similar to #BKE_area_find_region_xy() but when \a event_xy intersects an overlapping region,
+ * this returns the region that is visually under the cursor. E.g. when over the
+ * transparent part of the region, it returns the region underneath.
+ *
+ * The overlapping region is determined using the #ED_region_contains_xy() query.
+ */
ARegion *ED_area_find_region_xy_visual(const ScrArea *area, int regiontype, const int event_xy[2]);
/* interface_region_hud.c */
+
struct ARegionType *ED_area_type_hud(int space_type);
void ED_area_type_hud_clear(struct wmWindowManager *wm, ScrArea *area_keep);
void ED_area_type_hud_ensure(struct bContext *C, struct ScrArea *area);
-/* default keymaps, bitflags (matches order of evaluation). */
+/**
+ * Default key-maps, bit-flags (matches order of evaluation).
+ */
enum {
ED_KEYMAP_UI = (1 << 1),
ED_KEYMAP_GIZMO = (1 << 2),
@@ -462,7 +717,7 @@ enum {
ED_KEYMAP_NAVBAR = (1 << 11),
};
-/* SCREEN_OT_space_context_cycle direction */
+/** #SCREEN_OT_space_context_cycle direction. */
typedef enum eScreenCycle {
SPACE_CONTEXT_CYCLE_PREV,
SPACE_CONTEXT_CYCLE_NEXT,
diff --git a/source/blender/editors/include/ED_sculpt.h b/source/blender/editors/include/ED_sculpt.h
index 348ea503372..0cdd8873cb2 100644
--- a/source/blender/editors/include/ED_sculpt.h
+++ b/source/blender/editors/include/ED_sculpt.h
@@ -35,6 +35,7 @@ struct bContext;
struct rcti;
/* sculpt.c */
+
void ED_operatortypes_sculpt(void);
void ED_sculpt_redraw_planes_get(float planes[4][4], struct ARegion *region, struct Object *ob);
bool ED_sculpt_mask_box_select(struct bContext *C,
@@ -42,18 +43,22 @@ bool ED_sculpt_mask_box_select(struct bContext *C,
const struct rcti *rect,
bool select);
-/* transform */
+/* sculpt_transform.c */
+
void ED_sculpt_update_modal_transform(struct bContext *C, struct Object *ob);
void ED_sculpt_init_transform(struct bContext *C, struct Object *ob);
void ED_sculpt_end_transform(struct bContext *C, struct Object *ob);
/* sculpt_undo.c */
+
+/** Export for ED_undo_sys. */
void ED_sculpt_undosys_type(struct UndoType *ut);
void ED_sculpt_undo_geometry_begin(struct Object *ob, const char *name);
void ED_sculpt_undo_geometry_end(struct Object *ob);
/* Face sets. */
+
int ED_sculpt_face_sets_find_next_available_id(struct Mesh *mesh);
void ED_sculpt_face_sets_initialize_none_to_id(struct Mesh *mesh, const int new_id);
@@ -62,7 +67,7 @@ int ED_sculpt_face_sets_active_update_and_get(struct bContext *C,
const float mval[2]);
/* Undo for changes happening on a base mesh for multires sculpting.
- * if there is no multires sculpt active regular undo is used. */
+ * if there is no multi-res sculpt active regular undo is used. */
void ED_sculpt_undo_push_multires_mesh_begin(struct bContext *C, const char *str);
void ED_sculpt_undo_push_multires_mesh_end(struct bContext *C, const char *str);
diff --git a/source/blender/editors/include/ED_select_utils.h b/source/blender/editors/include/ED_select_utils.h
index 049ea7a092f..4656099799b 100644
--- a/source/blender/editors/include/ED_select_utils.h
+++ b/source/blender/editors/include/ED_select_utils.h
@@ -60,8 +60,17 @@ enum {
#define SEL_OP_USE_PRE_DESELECT(sel_op) (ELEM(sel_op, SEL_OP_SET))
#define SEL_OP_CAN_DESELECT(sel_op) (!ELEM(sel_op, SEL_OP_ADD))
-/* Use when we've de-selected all first for 'SEL_OP_SET' */
+/**
+ * Use when we've de-selected all first for 'SEL_OP_SET'.
+ * 1: select, 0: deselect, -1: pass.
+ */
int ED_select_op_action(const eSelectOp sel_op, const bool is_select, const bool is_inside);
+/**
+ * Use when we've de-selected all items first (for modes that need it).
+ *
+ * \note In some cases changing selection needs to perform other checks,
+ * so it's more straightforward to deselect all, then select.
+ */
int ED_select_op_action_deselected(const eSelectOp sel_op,
const bool is_select,
const bool is_inside);
@@ -72,6 +81,9 @@ bool ED_select_similar_compare_float_tree(const struct KDTree_1d *tree,
const float thresh,
const int compare);
+/**
+ * Utility to use for selection operations that run multiple times (circle select).
+ */
eSelectOp ED_select_op_modal(const eSelectOp sel_op, const bool is_first);
#ifdef __cplusplus
diff --git a/source/blender/editors/include/ED_sequencer.h b/source/blender/editors/include/ED_sequencer.h
index 606b4c9cad0..843b94cea00 100644
--- a/source/blender/editors/include/ED_sequencer.h
+++ b/source/blender/editors/include/ED_sequencer.h
@@ -40,8 +40,18 @@ bool ED_space_sequencer_maskedit_mask_poll(struct bContext *C);
bool ED_space_sequencer_check_show_maskedit(struct SpaceSeq *sseq, struct Scene *scene);
bool ED_space_sequencer_maskedit_poll(struct bContext *C);
+/**
+ * Are we displaying the seq output (not channels or histogram).
+ */
bool ED_space_sequencer_check_show_imbuf(struct SpaceSeq *sseq);
+
bool ED_space_sequencer_check_show_strip(struct SpaceSeq *sseq);
+/**
+ * Check if there is animation shown during playback.
+ *
+ * - Colors of color strips are displayed on the strip itself.
+ * - Backdrop is drawn.
+ */
bool ED_space_sequencer_has_playback_animation(const struct SpaceSeq *sseq,
const struct Scene *scene);
diff --git a/source/blender/editors/include/ED_space_api.h b/source/blender/editors/include/ED_space_api.h
index 958df8f7707..f4a69737da1 100644
--- a/source/blender/editors/include/ED_space_api.h
+++ b/source/blender/editors/include/ED_space_api.h
@@ -30,12 +30,18 @@ extern "C" {
struct ARegionType;
struct bContext;
+/* Only called once on startup. storage is global in BKE kernel listbase. */
void ED_spacetypes_init(void);
void ED_spacemacros_init(void);
/* the pluginnable API for export to editors */
-/* calls for registering default spaces */
+/* -------------------------------------------------------------------- */
+/** \name Calls for registering default spaces
+ *
+ * Calls for registering default spaces, only called once, from #ED_spacetypes_init
+ * \{ */
+
void ED_spacetype_outliner(void);
void ED_spacetype_view3d(void);
void ED_spacetype_ipo(void);
@@ -57,12 +63,18 @@ void ED_spacetype_statusbar(void);
void ED_spacetype_topbar(void);
void ED_spacetype_spreadsheet(void);
-/* calls for instancing and freeing spacetype static data
- * called in WM_init_exit */
-/* in space_file.c */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Spacetype Static Data
+ * Calls for instancing and freeing space-type static data called in #WM_init_exit
+ * \{ */
+
void ED_file_init(void);
void ED_file_exit(void);
+/** \} */
+
#define REGION_DRAW_POST_VIEW 0
#define REGION_DRAW_POST_PIXEL 1
#define REGION_DRAW_PRE_VIEW 2
diff --git a/source/blender/editors/include/ED_text.h b/source/blender/editors/include/ED_text.h
index 6e012ec1a91..33ca3ea03a6 100644
--- a/source/blender/editors/include/ED_text.h
+++ b/source/blender/editors/include/ED_text.h
@@ -36,16 +36,25 @@ struct bContext;
bool ED_text_activate_in_screen(struct bContext *C, struct Text *text);
+/**
+ * Moves the view to the cursor location, also used to make sure the view isn't outside the file.
+ */
void ED_text_scroll_to_cursor(struct SpaceText *st, struct ARegion *region, bool center);
+/**
+ * Takes a cursor (row, character) and returns x,y pixel coords.
+ */
bool ED_text_region_location_from_cursor(struct SpaceText *st,
struct ARegion *region,
const int cursor_co[2],
int r_pixel_co[2]);
/* text_undo.c */
+
+/** Export for ED_undo_sys. */
void ED_text_undosys_type(struct UndoType *ut);
+/** Use operator system to finish the undo step. */
struct UndoStep *ED_text_undo_push_init(struct bContext *C);
/* text_format.c */
diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h
index b132e559baa..f0d6072fdbc 100644
--- a/source/blender/editors/include/ED_transform.h
+++ b/source/blender/editors/include/ED_transform.h
@@ -146,6 +146,15 @@ void Transform_Properties(struct wmOperatorType *ot, int flags);
/* *** transform_orientations.c *** */
void ED_transform_calc_orientation_from_type(const struct bContext *C, float r_mat[3][3]);
+/**
+ * \note The resulting matrix may not be orthogonal,
+ * callers that depend on `r_mat` to be orthogonal should use #orthogonalize_m3.
+ *
+ * A non orthogonal matrix may be returned when:
+ * - #V3D_ORIENT_GIMBAL the result won't be orthogonal unless the object has no rotation.
+ * - #V3D_ORIENT_LOCAL may contain shear from non-uniform scale in parent/child relationships.
+ * - #V3D_ORIENT_CUSTOM may have been created from #V3D_ORIENT_LOCAL.
+ */
short ED_transform_calc_orientation_from_type_ex(const struct Scene *scene,
struct ViewLayer *view_layer,
const struct View3D *v3d,
@@ -159,6 +168,9 @@ short ED_transform_calc_orientation_from_type_ex(const struct Scene *scene,
/* transform gizmos */
void VIEW3D_GGT_xform_gizmo(struct wmGizmoGroupType *gzgt);
+/**
+ * Only poll, flag & gzmap_params differ.
+ */
void VIEW3D_GGT_xform_gizmo_context(struct wmGizmoGroupType *gzgt);
void VIEW3D_GGT_xform_cage(struct wmGizmoGroupType *gzgt);
void VIEW3D_GGT_xform_shear(struct wmGizmoGroupType *gzgt);
@@ -196,6 +208,11 @@ struct TransformCalcParams {
/* Use 'Scene.orientation_type' when zero, otherwise subtract one and use. */
ushort orientation_index;
};
+/**
+ * Centroid, bound-box, of selection.
+ *
+ * Returns total items selected.
+ */
int ED_transform_calc_gizmo_stats(const struct bContext *C,
const struct TransformCalcParams *params,
struct TransformBounds *tbounds);
diff --git a/source/blender/editors/include/ED_transform_snap_object_context.h b/source/blender/editors/include/ED_transform_snap_object_context.h
index c4da1588117..6f25a63188d 100644
--- a/source/blender/editors/include/ED_transform_snap_object_context.h
+++ b/source/blender/editors/include/ED_transform_snap_object_context.h
@@ -117,6 +117,13 @@ bool ED_transform_snap_object_project_ray(SnapObjectContext *sctx,
float r_co[3],
float r_no[3]);
+/**
+ * Fill in a list of all hits.
+ *
+ * \param ray_depth: Only depths in this range are considered, -1.0 for maximum.
+ * \param sort: Optionally sort the hits by depth.
+ * \param r_hit_list: List of #SnapObjectHitDepth (caller must free).
+ */
bool ED_transform_snap_object_project_ray_all(SnapObjectContext *sctx,
struct Depsgraph *depsgraph,
const View3D *v3d,
@@ -142,6 +149,19 @@ short ED_transform_snap_object_project_view3d_ex(struct SnapObjectContext *sctx,
struct Object **r_ob,
float r_obmat[4][4],
float r_face_nor[3]);
+/**
+ * Convenience function for performing snapping.
+ *
+ * Given a 2D region value, snap to vert/edge/face.
+ *
+ * \param sctx: Snap context.
+ * \param mval: Screenspace coordinate.
+ * \param prev_co: Coordinate for perpendicular point calculation (optional).
+ * \param dist_px: Maximum distance to snap (in pixels).
+ * \param r_loc: hit location.
+ * \param r_no: hit normal (optional).
+ * \return Snap success.
+ */
short ED_transform_snap_object_project_view3d(struct SnapObjectContext *sctx,
struct Depsgraph *depsgraph,
const ARegion *region,
@@ -155,6 +175,9 @@ short ED_transform_snap_object_project_view3d(struct SnapObjectContext *sctx,
float r_loc[3],
float r_no[3]);
+/**
+ * see: #ED_transform_snap_object_project_ray_all
+ */
bool ED_transform_snap_object_project_all_view3d_ex(SnapObjectContext *sctx,
struct Depsgraph *depsgraph,
const ARegion *region,
diff --git a/source/blender/editors/include/ED_undo.h b/source/blender/editors/include/ED_undo.h
index 059277e1466..dceecc6aab5 100644
--- a/source/blender/editors/include/ED_undo.h
+++ b/source/blender/editors/include/ED_undo.h
@@ -36,6 +36,9 @@ struct wmOperator;
struct wmOperatorType;
/* undo.c */
+/**
+ * Run from the main event loop, basic checks that undo is left in a correct state.
+ */
bool ED_undo_is_state_valid(struct bContext *C);
void ED_undo_group_begin(struct bContext *C);
void ED_undo_group_end(struct bContext *C);
@@ -52,18 +55,38 @@ void ED_OT_redo(struct wmOperatorType *ot);
void ED_OT_undo_redo(struct wmOperatorType *ot);
void ED_OT_undo_history(struct wmOperatorType *ot);
+/**
+ * UI callbacks should call this rather than calling WM_operator_repeat() themselves.
+ */
int ED_undo_operator_repeat(struct bContext *C, struct wmOperator *op);
-/* Convenience since UI callbacks use this mostly. */
+/**
+ * Convenience since UI callbacks use this mostly.
+ */
void ED_undo_operator_repeat_cb(struct bContext *C, void *arg_op, void *arg_unused);
void ED_undo_operator_repeat_cb_evt(struct bContext *C, void *arg_op, int arg_unused);
+/**
+ * Name optionally, function used to check for operator redo panel.
+ */
bool ED_undo_is_valid(const struct bContext *C, const char *undoname);
bool ED_undo_is_memfile_compatible(const struct bContext *C);
/* Unfortunate workaround for limits mixing undo systems. */
+
+/**
+ * When a property of ID changes, return false.
+ *
+ * This is to avoid changes to a property making undo pushes
+ * which are ignored by the undo-system.
+ * For example, changing a brush property isn't stored by sculpt-mode undo steps.
+ * This workaround is needed until the limitation is removed, see: T61948.
+ */
bool ED_undo_is_legacy_compatible_for_property(struct bContext *C, struct ID *id);
+/**
+ * Load all our objects from `object_array` into edit-mode, clear everything else.
+ */
void ED_undo_object_editmode_restore_helper(struct bContext *C,
struct Object **object_array,
uint object_array_len,
@@ -73,6 +96,13 @@ struct Object **ED_undo_editmode_objects_from_view_layer(struct ViewLayer *view_
uint *r_len);
struct Base **ED_undo_editmode_bases_from_view_layer(struct ViewLayer *view_layer, uint *r_len);
+/**
+ * Ideally we won't access the stack directly,
+ * this is needed for modes which handle undo themselves (bypassing #ED_undo_push).
+ *
+ * Using global isn't great, this just avoids doing inline,
+ * causing 'BKE_global.h' & 'BKE_main.h' includes.
+ */
struct UndoStack *ED_undo_stack_get(void);
/* helpers */
@@ -83,11 +113,28 @@ void ED_undo_object_set_active_or_warn(struct Scene *scene,
struct CLG_LogRef *log);
/* undo_system_types.c */
+
void ED_undosys_type_init(void);
void ED_undosys_type_free(void);
/* memfile_undo.c */
+
struct MemFile *ED_undosys_stack_memfile_get_active(struct UndoStack *ustack);
+/**
+ * If the last undo step is a memfile one, find the first #MemFileChunk matching given ID
+ * (using its session UUID), and tag it as "changed in the future".
+ *
+ * Since non-memfile undo-steps cannot automatically set this flag in the previous step as done
+ * with memfile ones, this has to be called manually by relevant undo code.
+ *
+ * \note Only current known case for this is undoing a switch from Object to Sculpt mode (see
+ * T82388).
+ *
+ * \note Calling this ID by ID is not optimal, as it will loop over all #MemFile.chunks until it
+ * finds the expected one. If this becomes an issue we'll have to add a mapping from session UUID
+ * to first #MemFileChunk in #MemFile itself
+ * (currently we only do that in #MemFileWriteData when writing a new step).
+ */
void ED_undosys_stack_memfile_id_changed_tag(struct UndoStack *ustack, struct ID *id);
#ifdef __cplusplus
diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h
index df132e6ae80..69378d436ab 100644
--- a/source/blender/editors/include/ED_util.h
+++ b/source/blender/editors/include/ED_util.h
@@ -35,8 +35,12 @@ struct Main;
struct bContext;
/* ed_util.c */
+
void ED_editors_init_for_undo(struct Main *bmain);
void ED_editors_init(struct bContext *C);
+/**
+ * Frees all edit-mode stuff.
+ */
void ED_editors_exit(struct Main *bmain, bool do_undo_system);
bool ED_editors_flush_edits_for_object_ex(struct Main *bmain,
@@ -45,9 +49,17 @@ bool ED_editors_flush_edits_for_object_ex(struct Main *bmain,
bool check_needs_flush);
bool ED_editors_flush_edits_for_object(struct Main *bmain, struct Object *ob);
+/**
+ * Flush any temp data from object editing to DNA before writing files, rendering, copying, etc.
+ */
bool ED_editors_flush_edits_ex(struct Main *bmain, bool for_render, bool check_needs_flush);
bool ED_editors_flush_edits(struct Main *bmain);
+/**
+ * Use to free ID references within runtime data (stored outside of DNA)
+ *
+ * \param new_id: may be NULL to unlink \a old_id.
+ */
void ED_spacedata_id_remap(struct ScrArea *area,
struct SpaceLink *sl,
struct ID *old_id,
@@ -56,21 +68,38 @@ void ED_spacedata_id_remap(struct ScrArea *area,
void ED_operatortypes_edutils(void);
/* Drawing */
+
+/**
+ * Callback that draws a line between the mouse and a position given as the initial argument.
+ */
void ED_region_draw_mouse_line_cb(const struct bContext *C,
struct ARegion *region,
void *arg_info);
+/**
+ * \note Keep in sync with #BKE_image_stamp_buf.
+ */
void ED_region_image_metadata_draw(
int x, int y, struct ImBuf *ibuf, const rctf *frame, float zoomx, float zoomy);
/* Slider */
+
struct tSlider;
struct tSlider *ED_slider_create(struct bContext *C);
+/**
+ * For modal operations so the percentage doesn't pop on the first mouse movement.
+ */
void ED_slider_init(struct tSlider *slider, const struct wmEvent *event);
+/**
+ * Calculate slider factor based on mouse position.
+ */
bool ED_slider_modal(struct tSlider *slider, const struct wmEvent *event);
void ED_slider_destroy(struct bContext *C, struct tSlider *slider);
+/**
+ * Return string based on the current state of the slider.
+ */
void ED_slider_status_string_get(const struct tSlider *slider,
char *status_string,
const size_t size_of_status_string);
@@ -83,6 +112,11 @@ void ED_slider_allow_overshoot_set(struct tSlider *slider, const bool value);
/* ************** XXX OLD CRUFT WARNING ************* */
+/**
+ * Now only used in 2D spaces, like time, f-curve, NLA, image, etc.
+ *
+ * \note Shift/Control are not configurable key-bindings.
+ */
void apply_keyb_grid(
int shift, int ctrl, float *val, float fac1, float fac2, float fac3, int invert);
diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h
index 884124396b9..e7b3c191d36 100644
--- a/source/blender/editors/include/ED_uvedit.h
+++ b/source/blender/editors/include/ED_uvedit.h
@@ -46,6 +46,7 @@ struct bNodeTree;
struct wmKeyConfig;
/* uvedit_ops.c */
+
void ED_operatortypes_uvedit(void);
void ED_operatormacros_uvedit(void);
void ED_keymap_uvedit(struct wmKeyConfig *keyconf);
@@ -54,6 +55,9 @@ bool ED_uvedit_minmax(const struct Scene *scene,
struct Object *obedit,
float min[2],
float max[2]);
+/**
+ * Be careful when using this, it bypasses all synchronization options.
+ */
void ED_uvedit_select_all(struct BMesh *bm);
bool ED_uvedit_minmax_multi(const struct Scene *scene,
@@ -231,12 +235,17 @@ struct BMLoop *ED_uvedit_active_vert_loop_get(struct BMesh *bm);
void ED_uvedit_active_edge_loop_set(struct BMesh *bm, struct BMLoop *l);
struct BMLoop *ED_uvedit_active_edge_loop_get(struct BMesh *bm);
+/**
+ * Intentionally don't return #UV_SELECT_ISLAND as it's not an element type.
+ * In this case return #UV_SELECT_VERTEX as a fallback.
+ */
char ED_uvedit_select_mode_get(const struct Scene *scene);
void ED_uvedit_select_sync_flush(const struct ToolSettings *ts,
struct BMEditMesh *em,
const bool select);
/* uvedit_unwrap_ops.c */
+
void ED_uvedit_live_unwrap_begin(struct Scene *scene, struct Object *obedit);
void ED_uvedit_live_unwrap_re_solve(void);
void ED_uvedit_live_unwrap_end(short cancel);
@@ -245,9 +254,11 @@ void ED_uvedit_live_unwrap(const struct Scene *scene, struct Object **objects, i
void ED_uvedit_add_simple_uvs(struct Main *bmain, const struct Scene *scene, struct Object *ob);
/* uvedit_draw.c */
+
void ED_image_draw_cursor(struct ARegion *region, const float cursor[2]);
/* uvedit_buttons.c */
+
void ED_uvedit_buttons_register(struct ARegionType *art);
/* uvedit_islands.c */
@@ -273,6 +284,9 @@ struct UVPackIsland_Params {
uint correct_aspect : 1;
};
+/**
+ * Returns true if UV coordinates lie on a valid tile in UDIM grid or tiled image.
+ */
bool uv_coords_isect_udim(const struct Image *image,
const int udim_grid[2],
const float coords[2]);
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index 008ad5b3203..6c986d8efe1 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -107,6 +107,11 @@ void ED_view3d_background_color_get(const struct Scene *scene,
bool ED_view3d_has_workbench_in_texture_color(const struct Scene *scene,
const struct Object *ob,
const struct View3D *v3d);
+/**
+ * Cursor position in `r_cursor_co`, result in `r_cursor_co`, `mval` in region coords.
+ *
+ * \note cannot use `event->mval` here, called by #object_add().
+ */
void ED_view3d_cursor3d_position(struct bContext *C,
const int mval[2],
const bool use_depth,
@@ -124,11 +129,44 @@ void ED_view3d_cursor3d_update(struct bContext *C,
struct Camera *ED_view3d_camera_data_get(struct View3D *v3d, struct RegionView3D *rv3d);
+/**
+ * Calculate the view transformation matrix from RegionView3D input.
+ * The resulting matrix is equivalent to #RegionView3D.viewinv
+ * \param mat: The view 4x4 transformation matrix to calculate.
+ * \param ofs: The view offset, normally from #RegionView3D.ofs.
+ * \param quat: The view rotation, quaternion normally from #RegionView3D.viewquat.
+ * \param dist: The view distance from ofs, normally from #RegionView3D.dist.
+ */
void ED_view3d_to_m4(float mat[4][4], const float ofs[3], const float quat[4], const float dist);
+/**
+ * Set the view transformation from a 4x4 matrix.
+ *
+ * \param mat: The view 4x4 transformation matrix to assign.
+ * \param ofs: The view offset, normally from #RegionView3D.ofs.
+ * \param quat: The view rotation, quaternion normally from #RegionView3D.viewquat.
+ * \param dist: The view distance from `ofs`, normally from #RegionView3D.dist.
+ */
void ED_view3d_from_m4(const float mat[4][4], float ofs[3], float quat[4], const float *dist);
+/**
+ * Set the #RegionView3D members from an objects transformation and optionally lens.
+ * \param ob: The object to set the view to.
+ * \param ofs: The view offset to be set, normally from #RegionView3D.ofs.
+ * \param quat: The view rotation to be set, quaternion normally from #RegionView3D.viewquat.
+ * \param dist: The view distance from `ofs `to be set, normally from #RegionView3D.dist.
+ * \param lens: The view lens angle set for cameras and lights, normally from View3D.lens.
+ */
void ED_view3d_from_object(
const struct Object *ob, float ofs[3], float quat[4], float *dist, float *lens);
+/**
+ * Set the object transformation from #RegionView3D members.
+ * \param depsgraph: The depsgraph to get the evaluated object parent
+ * for the transformation calculation.
+ * \param ob: The object which has the transformation assigned.
+ * \param ofs: The view offset, normally from #RegionView3D.ofs.
+ * \param quat: The view rotation, quaternion normally from #RegionView3D.viewquat.
+ * \param dist: The view distance from `ofs`, normally from #RegionView3D.dist.
+ */
void ED_view3d_to_object(const struct Depsgraph *depsgraph,
struct Object *ob,
const float ofs[3],
@@ -140,14 +178,24 @@ bool ED_view3d_camera_to_view_selected(struct Main *bmain,
const struct Scene *scene,
struct Object *camera_ob);
+/**
+ * Use to store the last view, before entering camera view.
+ */
void ED_view3d_lastview_store(struct RegionView3D *rv3d);
/* Depth buffer */
typedef enum {
+ /** Redraw viewport without Grease Pencil and Annotations. */
V3D_DEPTH_NO_GPENCIL = 0,
+ /** Redraw viewport with Grease Pencil and Annotations only. */
V3D_DEPTH_GPENCIL_ONLY,
+ /** Redraw viewport with active object only. */
V3D_DEPTH_OBJECT_ONLY,
+
} eV3DDepthOverrideMode;
+/**
+ * Redraw the viewport depth buffer.
+ */
void ED_view3d_depth_override(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
@@ -309,6 +357,7 @@ void ED_view3d_cursor_snap_draw_util(struct RegionView3D *rv3d,
/* view3d_iterators.c */
/* foreach iterators */
+
void meshobject_foreachScreenVert(
struct ViewContext *vc,
void (*func)(void *userData, struct MVert *eve, const float screen_co[2], int index),
@@ -328,6 +377,10 @@ void mesh_foreachScreenEdge(struct ViewContext *vc,
void *userData,
const eV3DProjTest clip_flag);
+/**
+ * A version of #mesh_foreachScreenEdge that clips the segment when
+ * there is a clipping bounding box.
+ */
void mesh_foreachScreenEdge_clip_bb_segment(struct ViewContext *vc,
void (*func)(void *userData,
struct BMEdge *eed,
@@ -352,6 +405,9 @@ void nurbs_foreachScreenVert(struct ViewContext *vc,
const float screen_co[2]),
void *userData,
const eV3DProjTest clip_flag);
+/**
+ * #ED_view3d_init_mats_rv3d must be called first.
+ */
void mball_foreachScreenElem(struct ViewContext *vc,
void (*func)(void *userData,
struct MetaElem *ml,
@@ -364,6 +420,9 @@ void lattice_foreachScreenVert(struct ViewContext *vc,
const float screen_co[2]),
void *userData,
const eV3DProjTest clip_flag);
+/**
+ * #ED_view3d_init_mats_rv3d must be called first.
+ */
void armature_foreachScreenBone(struct ViewContext *vc,
void (*func)(void *userData,
struct EditBone *ebone,
@@ -371,6 +430,10 @@ void armature_foreachScreenBone(struct ViewContext *vc,
const float screen_co_b[2]),
void *userData,
const eV3DProjTest clip_flag);
+
+/**
+ * ED_view3d_init_mats_rv3d must be called first.
+ */
void pose_foreachScreenBone(struct ViewContext *vc,
void (*func)(void *userData,
struct bPoseChannel *pchan,
@@ -381,10 +444,17 @@ void pose_foreachScreenBone(struct ViewContext *vc,
/* *** end iterators *** */
/* view3d_project.c */
+
+/**
+ * \note use #ED_view3d_ob_project_mat_get to get the projection matrix
+ */
void ED_view3d_project_float_v2_m4(const struct ARegion *region,
const float co[3],
float r_co[2],
float mat[4][4]);
+/**
+ * \note use #ED_view3d_ob_project_mat_get to get projecting mat
+ */
void ED_view3d_project_float_v3_m4(const struct ARegion *region,
const float co[3],
float r_co[3],
@@ -399,10 +469,12 @@ eV3DProjStatus ED_view3d_project_short_ex(const struct ARegion *region,
const float co[3],
short r_co[2],
const eV3DProjTest flag);
+/* --- short --- */
eV3DProjStatus ED_view3d_project_short_global(const struct ARegion *region,
const float co[3],
short r_co[2],
const eV3DProjTest flag);
+/* object space, use ED_view3d_init_mats_rv3d before calling */
eV3DProjStatus ED_view3d_project_short_object(const struct ARegion *region,
const float co[3],
short r_co[2],
@@ -415,10 +487,12 @@ eV3DProjStatus ED_view3d_project_int_ex(const struct ARegion *region,
const float co[3],
int r_co[2],
const eV3DProjTest flag);
+/* --- int --- */
eV3DProjStatus ED_view3d_project_int_global(const struct ARegion *region,
const float co[3],
int r_co[2],
const eV3DProjTest flag);
+/* object space, use ED_view3d_init_mats_rv3d before calling */
eV3DProjStatus ED_view3d_project_int_object(const struct ARegion *region,
const float co[3],
int r_co[2],
@@ -431,10 +505,14 @@ eV3DProjStatus ED_view3d_project_float_ex(const struct ARegion *region,
const float co[3],
float r_co[2],
const eV3DProjTest flag);
+/* --- float --- */
eV3DProjStatus ED_view3d_project_float_global(const struct ARegion *region,
const float co[3],
float r_co[2],
const eV3DProjTest flag);
+/**
+ * Object space, use #ED_view3d_init_mats_rv3d before calling.
+ */
eV3DProjStatus ED_view3d_project_float_object(const struct ARegion *region,
const float co[3],
float r_co[2],
@@ -443,17 +521,52 @@ eV3DProjStatus ED_view3d_project_float_object(const struct ARegion *region,
float ED_view3d_pixel_size(const struct RegionView3D *rv3d, const float co[3]);
float ED_view3d_pixel_size_no_ui_scale(const struct RegionView3D *rv3d, const float co[3]);
+/**
+ * Calculate a depth value from \a co, use with #ED_view3d_win_to_delta
+ */
float ED_view3d_calc_zfac(const struct RegionView3D *rv3d, const float co[3], bool *r_flip);
+/**
+ * Calculate a depth value from `co` (result should only be used for comparison).
+ */
float ED_view3d_calc_depth_for_comparison(const struct RegionView3D *rv3d, const float co[3]);
bool ED_view3d_clip_segment(const struct RegionView3D *rv3d, float ray_start[3], float ray_end[3]);
+/**
+ * Calculate a 3d viewpoint and direction vector from 2d window coordinates.
+ * This ray_start is located at the viewpoint, ray_normal is the direction towards mval.
+ * ray_start is clipped by the view near limit so points in front of it are always in view.
+ * In orthographic view the resulting ray_normal will match the view vector.
+ * \param region: The region (used for the window width and height).
+ * \param v3d: The 3d viewport (used for near clipping value).
+ * \param mval: The area relative 2d location (such as event->mval, converted into float[2]).
+ * \param r_ray_start: The world-space point where the ray intersects the window plane.
+ * \param r_ray_normal: The normalized world-space direction of towards mval.
+ * \param do_clip_planes: Optionally clip the start of the ray by the view clipping planes.
+ * \return success, false if the ray is totally clipped.
+ */
bool ED_view3d_win_to_ray_clipped(struct Depsgraph *depsgraph,
const struct ARegion *region,
const struct View3D *v3d,
const float mval[2],
- float ray_start[3],
- float ray_normal[3],
- const bool do_clip);
+ float r_ray_start[3],
+ float r_ray_normal[3],
+ const bool do_clip_planes);
+/**
+ * Calculate a 3d viewpoint and direction vector from 2d window coordinates.
+ * This ray_start is located at the viewpoint, ray_normal is the direction towards `mval`.
+ * ray_start is clipped by the view near limit so points in front of it are always in view.
+ * In orthographic view the resulting ray_normal will match the view vector.
+ * This version also returns the ray_co point of the ray on window plane, useful to fix precision
+ * issues especially with orthographic view, where default ray_start is set rather far away.
+ * \param region: The region (used for the window width and height).
+ * \param v3d: The 3d viewport (used for near clipping value).
+ * \param mval: The area relative 2d location (such as `event->mval`, converted into float[2]).
+ * \param r_ray_co: The world-space point where the ray intersects the window plane.
+ * \param r_ray_normal: The normalized world-space direction of towards mval.
+ * \param r_ray_start: The world-space starting point of the ray.
+ * \param do_clip_planes: Optionally clip the start of the ray by the view clipping planes.
+ * \return success, false if the ray is totally clipped.
+ */
bool ED_view3d_win_to_ray_clipped_ex(struct Depsgraph *depsgraph,
const struct ARegion *region,
const struct View3D *v3d,
@@ -461,14 +574,39 @@ bool ED_view3d_win_to_ray_clipped_ex(struct Depsgraph *depsgraph,
float r_ray_co[3],
float r_ray_normal[3],
float r_ray_start[3],
- bool do_clip);
+ bool do_clip_planes);
+/**
+ * Calculate a 3d viewpoint and direction vector from 2d window coordinates.
+ * This ray_start is located at the viewpoint, ray_normal is the direction towards `mval`.
+ * \param region: The region (used for the window width and height).
+ * \param mval: The area relative 2d location (such as `event->mval`, converted into float[2]).
+ * \param r_ray_start: The world-space point where the ray intersects the window plane.
+ * \param r_ray_normal: The normalized world-space direction of towards mval.
+ *
+ * \note Ignores view near/far clipping,
+ * to take this into account use #ED_view3d_win_to_ray_clipped.
+ */
void ED_view3d_win_to_ray(const struct ARegion *region,
const float mval[2],
float r_ray_start[3],
float r_ray_normal[3]);
+/**
+ * Calculate a normalized 3d direction vector from the viewpoint towards a global location.
+ * In orthographic view the resulting vector will match the view vector.
+ * \param rv3d: The region (used for the window width and height).
+ * \param coord: The world-space location.
+ * \param vec: The resulting normalized vector.
+ */
void ED_view3d_global_to_vector(const struct RegionView3D *rv3d,
const float coord[3],
float vec[3]);
+/**
+ * Calculate a 3d location from 2d window coordinates.
+ * \param region: The region (used for the window width and height).
+ * \param depth_pt: The reference location used to calculate the Z depth.
+ * \param mval: The area relative location (such as `event->mval` converted to floats).
+ * \param r_out: The resulting world-space location.
+ */
void ED_view3d_win_to_3d(const struct View3D *v3d,
const struct ARegion *region,
const float depth_pt[3],
@@ -484,6 +622,13 @@ bool ED_view3d_win_to_3d_on_plane(const struct ARegion *region,
const float mval[2],
const bool do_clip,
float r_out[3]);
+/**
+ * A wrapper for #ED_view3d_win_to_3d_on_plane that projects onto \a plane_fallback
+ * then maps this back to \a plane.
+ *
+ * This is intended to be used when \a plane is orthogonal to the views Z axis where
+ * projecting the \a mval doesn't work well (or fail completely when exactly aligned).
+ */
bool ED_view3d_win_to_3d_on_plane_with_fallback(const struct ARegion *region,
const float plane[4],
const float mval[2],
@@ -495,19 +640,64 @@ bool ED_view3d_win_to_3d_on_plane_int(const struct ARegion *region,
const int mval[2],
const bool do_clip,
float r_out[3]);
+/**
+ * Calculate a 3d difference vector from 2d window offset.
+ * note that #ED_view3d_calc_zfac() must be called first to determine
+ * the depth used to calculate the delta.
+ * \param region: The region (used for the window width and height).
+ * \param mval: The area relative 2d difference (such as `event->mval[0] - other_x`).
+ * \param out: The resulting world-space delta.
+ */
void ED_view3d_win_to_delta(const struct ARegion *region,
const float mval[2],
float out[3],
const float zfac);
+/**
+ * Calculate a 3d origin from 2d window coordinates.
+ * \note Orthographic views have a less obvious origin,
+ * Since far clip can be a very large value resulting in numeric precision issues,
+ * the origin in this case is close to zero coordinate.
+ *
+ * \param region: The region (used for the window width and height).
+ * \param mval: The area relative 2d location (such as event->mval converted to floats).
+ * \param out: The resulting normalized world-space direction vector.
+ */
void ED_view3d_win_to_origin(const struct ARegion *region, const float mval[2], float out[3]);
+/**
+ * Calculate a 3d direction vector from 2d window coordinates.
+ * This direction vector starts and the view in the direction of the 2d window coordinates.
+ * In orthographic view all window coordinates yield the same vector.
+ *
+ * \note doesn't rely on ED_view3d_calc_zfac
+ * for perspective view, get the vector direction to
+ * the mouse cursor as a normalized vector.
+ *
+ * \param region: The region (used for the window width and height).
+ * \param mval: The area relative 2d location (such as event->mval converted to floats).
+ * \param out: The resulting normalized world-space direction vector.
+ */
void ED_view3d_win_to_vector(const struct ARegion *region, const float mval[2], float out[3]);
+/**
+ * Calculate a 3d segment from 2d window coordinates.
+ * This ray_start is located at the viewpoint, ray_end is a far point.
+ * ray_start and ray_end are clipped by the view near and far limits
+ * so points along this line are always in view.
+ * In orthographic view all resulting segments will be parallel.
+ * \param region: The region (used for the window width and height).
+ * \param v3d: The 3d viewport (used for near and far clipping range).
+ * \param mval: The area relative 2d location (such as event->mval, converted into float[2]).
+ * \param r_ray_start: The world-space starting point of the segment.
+ * \param r_ray_end: The world-space end point of the segment.
+ * \param do_clip_planes: Optionally clip the ray by the view clipping planes.
+ * \return success, false if the segment is totally clipped.
+ */
bool ED_view3d_win_to_segment_clipped(struct Depsgraph *depsgraph,
const struct ARegion *region,
struct View3D *v3d,
const float mval[2],
float r_ray_start[3],
float r_ray_end[3],
- const bool do_clip);
+ const bool do_clip_planes);
void ED_view3d_ob_project_mat_get(const struct RegionView3D *v3d,
const struct Object *ob,
float r_pmat[4][4]);
@@ -515,6 +705,10 @@ void ED_view3d_ob_project_mat_get_from_obmat(const struct RegionView3D *rv3d,
const float obmat[4][4],
float r_pmat[4][4]);
+/**
+ * Convert between region relative coordinates (x,y) and depth component z and
+ * a point in world space.
+ */
void ED_view3d_project_v3(const struct ARegion *region,
const float world[3],
float r_region_co[3]);
@@ -527,6 +721,9 @@ bool ED_view3d_unproject_v3(
/* end */
void ED_view3d_dist_range_get(const struct View3D *v3d, float r_dist_range[2]);
+/**
+ * \note copies logic of #ED_view3d_viewplane_get(), keep in sync.
+ */
bool ED_view3d_clip_range_get(struct Depsgraph *depsgraph,
const struct View3D *v3d,
const struct RegionView3D *rv3d,
@@ -543,6 +740,9 @@ bool ED_view3d_viewplane_get(struct Depsgraph *depsgraph,
float *r_clipend,
float *r_pixsize);
+/**
+ * Use instead of: `GPU_polygon_offset(rv3d->dist, ...)` see bug T37727.
+ */
void ED_view3d_polygon_offset(const struct RegionView3D *rv3d, const float dist);
void ED_view3d_calc_camera_border(const struct Scene *scene,
@@ -572,15 +772,61 @@ void ED_view3d_clipping_calc(struct BoundBox *bb,
const struct ARegion *region,
const struct Object *ob,
const struct rcti *rect);
+/**
+ * Clamp min/max by the viewport clipping.
+ *
+ * \note This is an approximation, with the limitation that the bounding box from the (mix, max)
+ * calculation might not have any geometry inside the clipped region.
+ * Performing a clipping test on each vertex would work well enough for most cases,
+ * although it's not perfect either as edges/faces may intersect the clipping without having any
+ * of their vertices inside it.
+ * A more accurate result would be quite involved.
+ *
+ * \return True when the arguments were clamped.
+ */
bool ED_view3d_clipping_clamp_minmax(const struct RegionView3D *rv3d, float min[3], float max[3]);
void ED_view3d_clipping_local(struct RegionView3D *rv3d, const float mat[4][4]);
+/**
+ * Return true when `co` is hidden by the 3D views clipping planes.
+ *
+ * \param is_local: When true use local (object-space) #ED_view3d_clipping_local must run first,
+ * then all comparisons can be done in local-space.
+ * \return True when `co` is outside all clipping planes.
+ *
+ * \note Callers should check #RV3D_CLIPPING_ENABLED first.
+ */
bool ED_view3d_clipping_test(const struct RegionView3D *rv3d,
const float co[3],
const bool is_local);
float ED_view3d_radius_to_dist_persp(const float angle, const float radius);
float ED_view3d_radius_to_dist_ortho(const float lens, const float radius);
+/**
+ * Return a new #RegionView3D.dist value to fit the \a radius.
+ *
+ * \note Depth isn't taken into account, this will fit a flat plane exactly,
+ * but points towards the view (with a perspective projection),
+ * may be within the radius but outside the view. eg:
+ *
+ * <pre>
+ * +
+ * pt --> + /^ radius
+ * / |
+ * / |
+ * view + +
+ * \ |
+ * \ |
+ * \|
+ * +
+ * </pre>
+ *
+ * \param region: Can be NULL if \a use_aspect is false.
+ * \param persp: Allow the caller to tell what kind of perspective to use (ortho/view/camera)
+ * \param use_aspect: Increase the distance to account for non 1:1 view aspect.
+ * \param radius: The radius will be fitted exactly,
+ * typically pre-scaled by a margin (#VIEW3D_MARGIN).
+ */
float ED_view3d_radius_to_dist(const struct View3D *v3d,
const struct ARegion *region,
const struct Depsgraph *depsgraph,
@@ -588,12 +834,26 @@ float ED_view3d_radius_to_dist(const struct View3D *v3d,
const bool use_aspect,
const float radius);
-/* Back-buffer select and draw support. */
+/**
+ * Back-buffer select and draw support.
+ */
void ED_view3d_backbuf_depth_validate(struct ViewContext *vc);
+/**
+ * allow for small values [0.5 - 2.5],
+ * and large values, FLT_MAX by clamping by the area size
+ */
int ED_view3d_backbuf_sample_size_clamp(struct ARegion *region, const float dist);
void ED_view3d_select_id_validate(struct ViewContext *vc);
+/**
+ * Get the world-space 3d location from a screen-space 2d point.
+ * TODO: Implement #alphaoverride. We don't want to zoom into billboards.
+ *
+ * \param mval: Input screen-space pixel location.
+ * \param mouse_worldloc: Output world-space location.
+ * \param fallback_depth_pt: Use this points depth when no depth can be found.
+ */
bool ED_view3d_autodist(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
@@ -602,6 +862,9 @@ bool ED_view3d_autodist(struct Depsgraph *depsgraph,
const bool alphaoverride,
const float fallback_depth_pt[3]);
+/**
+ * No 4x4 sampling, run #ED_view3d_depth_override first.
+ */
bool ED_view3d_autodist_simple(struct ARegion *region,
const int mval[2],
float mouse_worldloc[3],
@@ -635,9 +898,21 @@ typedef enum {
eV3DSelectObjectFilter ED_view3d_select_filter_from_mode(const struct Scene *scene,
const struct Object *obact);
+/**
+ * Optionally cache data for multiple calls to #view3d_opengl_select
+ *
+ * just avoid GPU_select headers outside this file
+ */
void view3d_opengl_select_cache_begin(void);
void view3d_opengl_select_cache_end(void);
+/**
+ * \warning be sure to account for a negative return value
+ * This is an error, "Too many objects in select buffer"
+ * and no action should be taken (can crash blender) if this happens
+ *
+ * \note (vc->obedit == NULL) can be set to explicitly skip edit-object selection.
+ */
int view3d_opengl_select_ex(struct ViewContext *vc,
unsigned int *buffer,
unsigned int bufsize,
@@ -665,28 +940,57 @@ void ED_view3d_viewcontext_init(struct bContext *C,
struct ViewContext *vc,
struct Depsgraph *depsgraph);
void ED_view3d_viewcontext_init_object(struct ViewContext *vc, struct Object *obact);
+/**
+ * Use this call when executing an operator,
+ * event system doesn't set for each event the OpenGL drawing context.
+ */
void view3d_operator_needs_opengl(const struct bContext *C);
void view3d_region_operator_needs_opengl(struct wmWindow *win, struct ARegion *region);
-/* XXX should move to BLI_math */
+/** XXX: should move to BLI_math */
bool edge_inside_circle(const float cent[2],
float radius,
const float screen_co_a[2],
const float screen_co_b[2]);
-/* get 3d region from context, also if mouse is in header or toolbar */
+/**
+ * Get 3D region from context, also if mouse is in header or toolbar.
+ */
struct RegionView3D *ED_view3d_context_rv3d(struct bContext *C);
+/**
+ * Ideally would return an rv3d but in some cases the region is needed too
+ * so return that, the caller can then access the `region->regiondata`.
+ */
bool ED_view3d_context_user_region(struct bContext *C,
struct View3D **r_v3d,
struct ARegion **r_region);
+/**
+ * Similar to #ED_view3d_context_user_region() but does not use context. Always performs a lookup.
+ * Also works if \a v3d is not the active space.
+ */
bool ED_view3d_area_user_region(const struct ScrArea *area,
const struct View3D *v3d,
struct ARegion **r_region);
bool ED_operator_rv3d_user_region_poll(struct bContext *C);
+/**
+ * Most of the time this isn't needed since you could assume the view matrix was
+ * set while drawing, however when functions like mesh_foreachScreenVert are
+ * called by selection tools, we can't be sure this object was the last.
+ *
+ * for example, transparent objects are drawn after edit-mode and will cause
+ * the rv3d mat's to change and break selection.
+ *
+ * 'ED_view3d_init_mats_rv3d' should be called before
+ * view3d_project_short_clip and view3d_project_short_noclip in cases where
+ * these functions are not used during draw_object
+ */
void ED_view3d_init_mats_rv3d(const struct Object *ob, struct RegionView3D *rv3d);
void ED_view3d_init_mats_rv3d_gl(const struct Object *ob, struct RegionView3D *rv3d);
#ifdef DEBUG
+/**
+ * Ensure we correctly initialize.
+ */
void ED_view3d_clear_mats_rv3d(struct RegionView3D *rv3d);
void ED_view3d_check_mats_rv3d(struct RegionView3D *rv3d);
#else
@@ -705,6 +1009,9 @@ void ED_draw_object_facemap(struct Depsgraph *depsgraph,
struct RenderEngineType *ED_view3d_engine_type(const struct Scene *scene, int drawtype);
bool ED_view3d_context_activate(struct bContext *C);
+/**
+ * Set the correct matrices
+ */
void ED_view3d_draw_setup_view(const struct wmWindowManager *wm,
struct wmWindow *win,
struct Depsgraph *depsgraph,
@@ -715,13 +1022,22 @@ void ED_view3d_draw_setup_view(const struct wmWindowManager *wm,
const float winmat[4][4],
const struct rcti *rect);
+/**
+ * `mval` comes from event->mval, only use within region handlers.
+ */
struct Base *ED_view3d_give_base_under_cursor(struct bContext *C, const int mval[2]);
struct Object *ED_view3d_give_object_under_cursor(struct bContext *C, const int mval[2]);
struct Object *ED_view3d_give_material_slot_under_cursor(struct bContext *C,
const int mval[2],
int *r_material_slot);
bool ED_view3d_is_object_under_cursor(struct bContext *C, const int mval[2]);
+/**
+ * 'clip' is used to know if our clip setting has changed.
+ */
void ED_view3d_quadview_update(struct ScrArea *area, struct ARegion *region, bool do_clip);
+/**
+ * \note keep this synced with #ED_view3d_mats_rv3d_backup/#ED_view3d_mats_rv3d_restore
+ */
void ED_view3d_update_viewmat(struct Depsgraph *depsgraph,
const struct Scene *scene,
struct View3D *v3d,
@@ -744,23 +1060,48 @@ void ED_view3d_datamask(const struct bContext *C,
const struct Scene *scene,
const struct View3D *v3d,
struct CustomData_MeshMasks *r_cddata_masks);
+/**
+ * Goes over all modes and view3d settings.
+ */
void ED_view3d_screen_datamask(const struct bContext *C,
const struct Scene *scene,
const struct bScreen *screen,
struct CustomData_MeshMasks *r_cddata_masks);
bool ED_view3d_offset_lock_check(const struct View3D *v3d, const struct RegionView3D *rv3d);
+/**
+ * For viewport operators that exit camera perspective.
+ *
+ * \note This differs from simply setting `rv3d->persp = persp` because it
+ * sets the `ofs` and `dist` values of the viewport so it matches the camera,
+ * otherwise switching out of camera view may jump to a different part of the scene.
+ */
void ED_view3d_persp_switch_from_camera(const struct Depsgraph *depsgraph,
struct View3D *v3d,
struct RegionView3D *rv3d,
const char persp);
+/**
+ * Action to take when rotating the view,
+ * handle auto-perspective and logic for switching out of views.
+ *
+ * shared with NDOF.
+ */
bool ED_view3d_persp_ensure(const struct Depsgraph *depsgraph,
struct View3D *v3d,
struct ARegion *region);
-/* camera lock functions */
+/* Camera lock functions */
+
+/**
+ * \return true when the 3D Viewport is locked to its camera.
+ */
bool ED_view3d_camera_lock_check(const struct View3D *v3d, const struct RegionView3D *rv3d);
-/* copy the camera to the view before starting a view transformation */
+/**
+ * Copy the camera to the view before starting a view transformation.
+ *
+ * Apply the camera object transformation to the 3D Viewport.
+ * (needed so we can use regular 3D Viewport manipulation operators, that sync back to the camera).
+ */
void ED_view3d_camera_lock_init_ex(const struct Depsgraph *depsgraph,
struct View3D *v3d,
struct RegionView3D *rv3d,
@@ -768,7 +1109,13 @@ void ED_view3d_camera_lock_init_ex(const struct Depsgraph *depsgraph,
void ED_view3d_camera_lock_init(const struct Depsgraph *depsgraph,
struct View3D *v3d,
struct RegionView3D *rv3d);
-/* copy the view to the camera, return true if */
+/**
+ * Copy the view to the camera, return true if.
+ *
+ * Apply the 3D Viewport transformation back to the camera object.
+ *
+ * \return true if the camera is moved.
+ */
bool ED_view3d_camera_lock_sync(const struct Depsgraph *depsgraph,
struct View3D *v3d,
struct RegionView3D *rv3d);
@@ -778,6 +1125,12 @@ bool ED_view3d_camera_autokey(const struct Scene *scene,
struct bContext *C,
const bool do_rotate,
const bool do_translate);
+/**
+ * Call after modifying a locked view.
+ *
+ * \note Not every view edit currently auto-keys (numeric-pad for eg),
+ * this is complicated because of smooth-view.
+ */
bool ED_view3d_camera_lock_autokey(struct View3D *v3d,
struct RegionView3D *rv3d,
struct bContext *C,
@@ -789,14 +1142,41 @@ void ED_view3d_lock_clear(struct View3D *v3d);
#define VIEW3D_MARGIN 1.4f
#define VIEW3D_DIST_FALLBACK 1.0f
+/**
+ * This function solves the problem of having to switch between camera and non-camera views.
+ *
+ * When viewing from the perspective of \a mat, and having the view center \a ofs,
+ * this calculates a distance from \a ofs to the matrix \a mat.
+ * Using \a fallback_dist when the distance would be too small.
+ *
+ * \param mat: A matrix use for the view-point (typically the camera objects matrix).
+ * \param ofs: Orbit center (negated), matching #RegionView3D.ofs, which is typically passed in.
+ * \param fallback_dist: The distance to use if the object is too near or in front of \a ofs.
+ * \returns A newly calculated distance or the fallback.
+ */
float ED_view3d_offset_distance(const float mat[4][4],
const float ofs[3],
const float fallback_dist);
+/**
+ * Set the dist without moving the view (compensate with #RegionView3D.ofs)
+ *
+ * \note take care that #RegionView3d.viewinv is up to date, #ED_view3d_update_viewmat first.
+ */
void ED_view3d_distance_set(struct RegionView3D *rv3d, const float dist);
+/**
+ * Change the distance & offset to match the depth of \a dist_co along the view axis.
+ *
+ * \param dist_co: A world-space location to use for the new depth.
+ * \param dist_min: Resulting distances below this will be ignored.
+ * \return Success if the distance was set.
+ */
bool ED_view3d_distance_set_from_location(struct RegionView3D *rv3d,
const float dist_co[3],
const float dist_min);
+/**
+ * Could move this elsewhere, but tied into #ED_view3d_grid_scale
+ */
float ED_scene_grid_scale(const struct Scene *scene, const char **r_grid_unit);
float ED_view3d_grid_scale(const struct Scene *scene,
struct View3D *v3d,
@@ -805,14 +1185,24 @@ void ED_view3d_grid_steps(const struct Scene *scene,
struct View3D *v3d,
struct RegionView3D *rv3d,
float r_grid_steps[8]);
+/**
+ * Simulates the grid scale that is actually viewed.
+ * The actual code is seen in `object_grid_frag.glsl` (see `grid_res`).
+ * Currently the simulation is only done when RV3D_VIEW_IS_AXIS.
+ */
float ED_view3d_grid_view_scale(struct Scene *scene,
struct View3D *v3d,
struct ARegion *region,
const char **r_grid_unit);
+/**
+ * \note The info that this uses is updated in #ED_refresh_viewport_fps,
+ * which currently gets called during #SCREEN_OT_animation_step.
+ */
void ED_scene_draw_fps(const struct Scene *scene, int xoffset, int *yoffset);
-/* render */
+/* Render */
+
void ED_view3d_stop_render_preview(struct wmWindowManager *wm, struct ARegion *region);
void ED_view3d_shade_update(struct Main *bmain, struct View3D *v3d, struct ScrArea *area);
@@ -825,7 +1215,10 @@ void ED_view3d_shade_update(struct Main *bmain, struct View3D *v3d, struct ScrAr
#define XRAY_ACTIVE(v3d) (XRAY_ENABLED(v3d) && ((v3d)->shading.type < OB_MATERIAL))
/* view3d_draw_legacy.c */
-/* Try avoid using these more move out of legacy. */
+
+/**
+ * Try avoid using these more move out of legacy.
+ */
void ED_view3d_draw_bgpic_test(const struct Scene *scene,
struct Depsgraph *depsgraph,
struct ARegion *region,
@@ -834,6 +1227,7 @@ void ED_view3d_draw_bgpic_test(const struct Scene *scene,
const bool do_camera_frame);
/* view3d_gizmo_preselect_type.c */
+
void ED_view3d_gizmo_mesh_preselect_get_active(struct bContext *C,
struct wmGizmo *gz,
struct Base **r_base,
@@ -841,11 +1235,17 @@ void ED_view3d_gizmo_mesh_preselect_get_active(struct bContext *C,
void ED_view3d_gizmo_mesh_preselect_clear(struct wmGizmo *gz);
/* space_view3d.c */
+
void ED_view3d_buttons_region_layout_ex(const struct bContext *C,
struct ARegion *region,
const char *category_override);
/* view3d_view.c */
+
+/**
+ * See if current UUID is valid, otherwise set a valid UUID to v3d,
+ * Try to keep the same UUID previously used to allow users to quickly toggle back and forth.
+ */
bool ED_view3d_local_collections_set(struct Main *bmain, struct View3D *v3d);
void ED_view3d_local_collections_reset(struct bContext *C, const bool reset_all);
diff --git a/source/blender/editors/include/ED_view3d_offscreen.h b/source/blender/editors/include/ED_view3d_offscreen.h
index 8b695e61a35..1da0a282697 100644
--- a/source/blender/editors/include/ED_view3d_offscreen.h
+++ b/source/blender/editors/include/ED_view3d_offscreen.h
@@ -57,6 +57,10 @@ void ED_view3d_draw_offscreen(struct Depsgraph *depsgraph,
const bool restore_rv3d_mats,
struct GPUOffScreen *ofs,
struct GPUViewport *viewport);
+/**
+ * Creates own fake 3d views (wrapping #ED_view3d_draw_offscreen). Similar too
+ * #ED_view_draw_offscreen_imbuf_simple, but takes view/projection matrices as arguments.
+ */
void ED_view3d_draw_offscreen_simple(struct Depsgraph *depsgraph,
struct Scene *scene,
struct View3DShading *shading_override,
@@ -76,6 +80,12 @@ void ED_view3d_draw_offscreen_simple(struct Depsgraph *depsgraph,
struct GPUOffScreen *ofs,
struct GPUViewport *viewport);
+/**
+ * Utility func for ED_view3d_draw_offscreen
+ *
+ * \param ofs: Optional off-screen buffer, can be NULL.
+ * (avoids re-creating when doing multiple GL renders).
+ */
struct ImBuf *ED_view3d_draw_offscreen_imbuf(struct Depsgraph *depsgraph,
struct Scene *scene,
eDrawType drawtype,
@@ -89,6 +99,14 @@ struct ImBuf *ED_view3d_draw_offscreen_imbuf(struct Depsgraph *depsgraph,
const bool restore_rv3d_mats,
struct GPUOffScreen *ofs,
char err_out[256]);
+/**
+ * Creates own fake 3d views (wrapping #ED_view3d_draw_offscreen_imbuf)
+ *
+ * \param ofs: Optional off-screen buffer can be NULL.
+ * (avoids re-creating when doing multiple GL renders).
+ *
+ * \note used by the sequencer
+ */
struct ImBuf *ED_view3d_draw_offscreen_imbuf_simple(struct Depsgraph *depsgraph,
struct Scene *scene,
struct View3DShading *shading_override,
diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h
index c3c296f89ca..4cf606bf98d 100644
--- a/source/blender/editors/include/UI_icons.h
+++ b/source/blender/editors/include/UI_icons.h
@@ -774,7 +774,7 @@ DEF_ICON_BLANK(276)
DEF_ICON_BLANK(277)
DEF_ICON_BLANK(772)
DEF_ICON_BLANK(773)
-DEF_ICON_BLANK(774)
+DEF_ICON(CURRENT_FILE)
DEF_ICON(HOME)
DEF_ICON(DOCUMENTS)
DEF_ICON(TEMP)
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index aa0dc222614..9df5b17975a 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -258,6 +258,8 @@ enum {
#define UI_PANEL_CATEGORY_MARGIN_WIDTH (U.widget_unit * 1.0f)
+/* Both these margins should be ignored if the panel doesn't show a background (check
+ * #UI_panel_should_show_background()). */
#define UI_PANEL_MARGIN_X (U.widget_unit * 0.4f)
#define UI_PANEL_MARGIN_Y (U.widget_unit * 0.1f)
@@ -400,9 +402,8 @@ typedef enum {
/** Resize handle (resize uilist). */
UI_BTYPE_GRIP = 57 << 9,
UI_BTYPE_DECORATOR = 58 << 9,
- UI_BTYPE_DATASETROW = 59 << 9,
/* An item in a tree view. Parent items may be collapsible. */
- UI_BTYPE_TREEROW = 60 << 9,
+ UI_BTYPE_TREEROW = 59 << 9,
} eButType;
#define BUTTYPE (63 << 9)
@@ -450,6 +451,14 @@ int UI_draw_roundbox_corner_get(void);
void UI_draw_box_shadow(const struct rctf *rect, unsigned char alpha);
void UI_draw_text_underline(int pos_x, int pos_y, int len, int height, const float color[4]);
+/**
+ * Draw title and text safe areas.
+ *
+ * \note This function is to be used with the 2D dashed shader enabled.
+ *
+ * \param pos: is a #PRIM_FLOAT, 2, #GPU_FETCH_FLOAT vertex attribute.
+ * \param rect: The offsets for the view, not the zones.
+ */
void UI_draw_safe_areas(uint pos,
const struct rctf *rect,
const float title_aspect[2],
@@ -461,12 +470,27 @@ enum {
UI_SCROLL_ARROWS = 1 << 1,
UI_SCROLL_NO_OUTLINE = 1 << 2,
};
+/**
+ * Function in use for buttons and for view2d sliders.
+ */
void UI_draw_widget_scroll(struct uiWidgetColors *wcol,
const struct rcti *rect,
const struct rcti *slider,
int state);
-/* Shortening string helper. */
+/**
+ * Shortening string helper.
+ *
+ * Cut off the middle of the text to fit into the given width.
+ *
+ * \note in case this middle clipping would just remove a few chars,
+ * it rather clips right, which is more readable.
+ *
+ * If rpart_sep is not Null, the part of str starting to first occurrence of rpart_sep
+ * is preserved at all cost.
+ * Useful for strings with shortcuts
+ * (like 'AVeryLongFooBarLabelForMenuEntry|Ctrl O' -> 'AVeryLong...MenuEntry|Ctrl O').
+ */
float UI_text_clip_middle_ex(const struct uiFontStyle *fstyle,
char *str,
float okwidth,
@@ -502,9 +526,11 @@ typedef int (*uiButCompleteFunc)(struct bContext *C, char *str, void *arg);
typedef struct ARegion *(*uiButSearchCreateFn)(struct bContext *C,
struct ARegion *butregion,
struct uiButSearch *search_but);
-/* `is_first` is typically used to ignore search filtering when the menu is first opened in order
+/**
+ * `is_first` is typically used to ignore search filtering when the menu is first opened in order
* to display the full list of options. The value will be false after the button's text is edited
- * (for every call except the first). */
+ * (for every call except the first).
+ */
typedef void (*uiButSearchUpdateFn)(const struct bContext *C,
void *arg,
const char *str,
@@ -591,6 +617,7 @@ typedef void (*uiFreeArgFunc)(void *arg);
/* interface_query.c */
bool UI_but_has_tooltip_label(const uiBut *but);
bool UI_but_is_tool(const uiBut *but);
+/* file selectors are exempt from utf-8 checks */
bool UI_but_is_utf8(const uiBut *but);
#define UI_but_is_decorator(but) ((but)->type == UI_BTYPE_DECORATOR)
@@ -612,10 +639,17 @@ struct uiList *UI_list_find_mouse_over(const struct ARegion *region, const struc
typedef struct uiPopupMenu uiPopupMenu;
uiPopupMenu *UI_popup_menu_begin(struct bContext *C, const char *title, int icon) ATTR_NONNULL();
+/**
+ * Only return handler, and set optional title.
+ * \param block_name: Assigned to uiBlock.name (useful info for debugging).
+ */
uiPopupMenu *UI_popup_menu_begin_ex(struct bContext *C,
const char *title,
const char *block_name,
int icon) ATTR_NONNULL();
+/**
+ * Set the whole structure to work.
+ */
void UI_popup_menu_end(struct bContext *C, struct uiPopupMenu *pup);
bool UI_popup_menu_end_or_cancel(struct bContext *C, struct uiPopupMenu *head);
struct uiLayout *UI_popup_menu_layout(uiPopupMenu *pup);
@@ -624,7 +658,14 @@ void UI_popup_menu_reports(struct bContext *C, struct ReportList *reports) ATTR_
int UI_popup_menu_invoke(struct bContext *C, const char *idname, struct ReportList *reports)
ATTR_NONNULL(1, 2);
+/**
+ * Allow setting menu return value from externals.
+ * E.g. WM might need to do this for exiting files correctly.
+ */
void UI_popup_menu_retval_set(const uiBlock *block, const int retval, const bool enable);
+/**
+ * Setting the button makes the popup open from the button instead of the cursor.
+ */
void UI_popup_menu_but_set(uiPopupMenu *pup, struct ARegion *butregion, uiBut *but);
/* interface_region_popover.c */
@@ -636,8 +677,17 @@ int UI_popover_panel_invoke(struct bContext *C,
bool keep_open,
struct ReportList *reports);
+/**
+ * Only return handler, and set optional title.
+ *
+ * \param from_active_button: Use the active button for positioning,
+ * use when the popover is activated from an operator instead of directly from the button.
+ */
uiPopover *UI_popover_begin(struct bContext *C, int menu_width, bool from_active_button)
ATTR_NONNULL(1);
+/**
+ * Set the whole structure to work.
+ */
void UI_popover_end(struct bContext *C, struct uiPopover *pup, struct wmKeyMap *keymap);
struct uiLayout *UI_popover_layout(uiPopover *pup);
void UI_popover_once_clear(uiPopover *pup);
@@ -715,6 +765,9 @@ uiBlock *UI_block_begin(const struct bContext *C,
eUIEmbossType emboss);
void UI_block_end_ex(const struct bContext *C, uiBlock *block, const int xy[2], int r_xy[2]);
void UI_block_end(const struct bContext *C, uiBlock *block);
+/**
+ * Uses local copy of style, to scale things down, and allow widgets to change stuff.
+ */
void UI_block_draw(const struct bContext *C, struct uiBlock *block);
void UI_blocklist_update_window_matrix(const struct bContext *C, const struct ListBase *lb);
void UI_blocklist_update_view_for_buttons(const struct bContext *C, const struct ListBase *lb);
@@ -729,19 +782,36 @@ void UI_block_theme_style_set(uiBlock *block, char theme_style);
eUIEmbossType UI_block_emboss_get(uiBlock *block);
void UI_block_emboss_set(uiBlock *block, eUIEmbossType emboss);
bool UI_block_is_search_only(const uiBlock *block);
+/**
+ * Use when a block must be searched to give accurate results
+ * for the whole region but shouldn't be displayed.
+ */
void UI_block_set_search_only(uiBlock *block, bool search_only);
+/**
+ * Can be called with C==NULL.
+ */
void UI_block_free(const struct bContext *C, uiBlock *block);
-void UI_blocklist_free(const struct bContext *C, struct ListBase *lb);
-void UI_blocklist_free_inactive(const struct bContext *C, struct ListBase *lb);
-void UI_screen_free_active_but(const struct bContext *C, struct bScreen *screen);
+/**
+ * Can be called with C==NULL.
+ */
+void UI_blocklist_free(const struct bContext *C, struct ARegion *region);
+void UI_blocklist_free_inactive(const struct bContext *C, struct ARegion *region);
+
+/**
+ * Is called by notifier.
+ */
+void UI_screen_free_active_but_highlight(const struct bContext *C, struct bScreen *screen);
+void UI_region_free_active_but_all(struct bContext *context, struct ARegion *region);
void UI_block_region_set(uiBlock *block, struct ARegion *region);
void UI_block_lock_set(uiBlock *block, bool val, const char *lockstr);
void UI_block_lock_clear(uiBlock *block);
-/* Automatic aligning, horizontal or vertical. */
+/**
+ * Automatic aligning, horizontal or vertical.
+ */
void UI_block_align_begin(uiBlock *block);
void UI_block_align_end(uiBlock *block);
@@ -756,16 +826,34 @@ typedef enum {
UI_BLOCK_BOUNDS_PIE_CENTER,
} eBlockBoundsCalc;
+/**
+ * Used for various cases.
+ */
void UI_block_bounds_set_normal(struct uiBlock *block, int addval);
+/**
+ * Used for pull-downs.
+ */
void UI_block_bounds_set_text(uiBlock *block, int addval);
+/**
+ * Used for block popups.
+ */
void UI_block_bounds_set_popup(uiBlock *block, int addval, const int bounds_offset[2]);
+/**
+ * Used for menu popups.
+ */
void UI_block_bounds_set_menu(uiBlock *block, int addval, const int bounds_offset[2]);
+/**
+ * Used for centered popups, i.e. splash.
+ */
void UI_block_bounds_set_centered(uiBlock *block, int addval);
void UI_block_bounds_set_explicit(uiBlock *block, int minx, int miny, int maxx, int maxy);
int UI_blocklist_min_y_get(struct ListBase *lb);
void UI_block_direction_set(uiBlock *block, char direction);
+/**
+ * This call escapes if there's alignment flags.
+ */
void UI_block_order_flip(uiBlock *block);
void UI_block_flag_enable(uiBlock *block, int flag);
void UI_block_flag_disable(uiBlock *block, int flag);
@@ -774,7 +862,14 @@ void UI_block_translate(uiBlock *block, int x, int y);
int UI_but_return_value_get(uiBut *but);
void UI_but_drag_set_id(uiBut *but, struct ID *id);
+/**
+ * Set an image to display while dragging. This works for any drag type (`WM_DRAG_XXX`).
+ * Not to be confused with #UI_but_drag_set_image(), which sets up dragging of an image.
+ */
void UI_but_drag_attach_image(uiBut *but, struct ImBuf *imb, const float scale);
+/**
+ * \param asset: May be passed from a temporary variable, drag data only stores a copy of this.
+ */
void UI_but_drag_set_asset(uiBut *but,
const struct AssetHandle *asset,
const char *path,
@@ -786,11 +881,18 @@ void UI_but_drag_set_asset(uiBut *but,
void UI_but_drag_set_rna(uiBut *but, struct PointerRNA *ptr);
void UI_but_drag_set_path(uiBut *but, const char *path, const bool use_free);
void UI_but_drag_set_name(uiBut *but, const char *name);
+/**
+ * Value from button itself.
+ */
void UI_but_drag_set_value(uiBut *but);
void UI_but_drag_set_image(
uiBut *but, const char *path, int icon, struct ImBuf *imb, float scale, const bool use_free);
uiBut *UI_but_active_drop_name_button(const struct bContext *C);
+/**
+ * Returns true if highlighted button allows drop of names.
+ * called in region context.
+ */
bool UI_but_active_drop_name(const struct bContext *C);
bool UI_but_active_drop_color(struct bContext *C);
@@ -805,7 +907,13 @@ void UI_but_disable(uiBut *but, const char *disabled_hint);
void UI_but_type_set_menu_from_pulldown(uiBut *but);
-/* special button case, only draw it when used actively, for outliner etc */
+/**
+ * Special button case, only draw it when used actively, for outliner etc.
+ *
+ * Needed for temporarily rename buttons, such as in outliner or file-select,
+ * they should keep calling #uiDefBut to keep them alive.
+ * \return false when button removed.
+ */
bool UI_but_active_only_ex(const struct bContext *C,
struct ARegion *region,
uiBlock *block,
@@ -815,10 +923,17 @@ bool UI_but_active_only(const struct bContext *C,
struct ARegion *region,
uiBlock *block,
uiBut *but);
+/**
+ * \warning This must run after other handlers have been added,
+ * otherwise the handler won't be removed, see: T71112.
+ */
bool UI_block_active_only_flagged_buttons(const struct bContext *C,
struct ARegion *region,
struct uiBlock *block);
+/**
+ * Simulate button click.
+ */
void UI_but_execute(const struct bContext *C, struct ARegion *region, uiBut *but);
bool UI_but_online_manual_id(const uiBut *but,
@@ -1022,6 +1137,9 @@ uiBut *uiDefButO_ptr(uiBlock *block,
short height,
const char *tip);
+/**
+ * If a1==1.0 then a2 is an extra icon blending factor (alpha 0.0 - 1.0).
+ */
uiBut *uiDefIconBut(uiBlock *block,
int type,
int retval,
@@ -1207,6 +1325,7 @@ uiBut *uiDefIconButO_ptr(uiBlock *block,
uiBut *uiDefButImage(
uiBlock *block, void *imbuf, int x, int y, short width, short height, const uchar color[4]);
uiBut *uiDefButAlert(uiBlock *block, int icon, int x, int y, short width, short height);
+/* Button containing both string label and icon */
uiBut *uiDefIconTextBut(uiBlock *block,
int type,
int retval,
@@ -1477,7 +1596,10 @@ enum {
UI_TEMPLATE_ID_FILTER_AVAILABLE = 1,
};
+/***************************** ID Utilities *******************************/
+
int UI_icon_from_id(const struct ID *id);
+/** See: #BKE_report_type_str */
int UI_icon_from_report_type(int type);
int UI_icon_colorid_from_report_type(int type);
int UI_text_colorid_from_report_type(int type);
@@ -1542,6 +1664,9 @@ uiBut *uiDefBlockButN(uiBlock *block,
short height,
const char *tip);
+/**
+ * Block button containing icon.
+ */
uiBut *uiDefIconBlockBut(uiBlock *block,
uiBlockCreateFunc func,
void *arg,
@@ -1552,6 +1677,9 @@ uiBut *uiDefIconBlockBut(uiBlock *block,
short width,
short height,
const char *tip);
+/**
+ * Block button containing both string label and icon.
+ */
uiBut *uiDefIconTextBlockBut(uiBlock *block,
uiBlockCreateFunc func,
void *arg,
@@ -1572,6 +1700,11 @@ uiBut *uiDefKeyevtButS(uiBlock *block,
short height,
short *spoin,
const char *tip);
+
+/**
+ * Short pointers hard-coded.
+ * \param modkeypoin: will be set to #KM_SHIFT, #KM_ALT, #KM_CTRL, #KM_OSKEY bits.
+ */
uiBut *uiDefHotKeyevtButS(uiBlock *block,
int retval,
const char *str,
@@ -1583,6 +1716,10 @@ uiBut *uiDefHotKeyevtButS(uiBlock *block,
const short *modkeypoin,
const char *tip);
+/**
+ * \param arg: A pointer to string/name, use #UI_but_func_search_set() below to make this work.
+ * here `a1` and `a2`, if set, control thumbnail preview rows/cols.
+ */
uiBut *uiDefSearchBut(uiBlock *block,
void *arg,
int retval,
@@ -1595,6 +1732,10 @@ uiBut *uiDefSearchBut(uiBlock *block,
float a1,
float a2,
const char *tip);
+/**
+ * Same parameters as for #uiDefSearchBut, with additional operator type and properties,
+ * used by callback to call again the right op with the right options (properties values).
+ */
uiBut *uiDefSearchButO_ptr(uiBlock *block,
struct wmOperatorType *ot,
struct IDProperty *properties,
@@ -1638,6 +1779,12 @@ uiBut *uiDefAutoButR(uiBlock *block,
int y,
int width,
int height);
+/**
+ * \a check_prop callback filters functions to avoid drawing certain properties,
+ * in cases where PROP_HIDDEN flag can't be used for a property.
+ *
+ * \param prop_activate_init: Property to activate on initial popup (#UI_BUT_ACTIVATE_ON_INIT).
+ */
eAutoPropButsReturn uiDefAutoButsRNA(uiLayout *layout,
struct PointerRNA *ptr,
bool (*check_prop)(struct PointerRNA *ptr,
@@ -1648,7 +1795,19 @@ eAutoPropButsReturn uiDefAutoButsRNA(uiLayout *layout,
eButLabelAlign label_align,
const bool compact);
-/* use inside searchfunc to add items */
+/**
+ * Public function exported for functions that use #UI_BTYPE_SEARCH_MENU.
+ *
+ * Use inside searchfunc to add items.
+ *
+ * \param items: Stores the items.
+ * \param name: Text to display for the item.
+ * \param poin: Opaque pointer (for use by the caller).
+ * \param iconid: The icon, #ICON_NONE for no icon.
+ * \param state: The buttons state flag, compatible with #uiBut.flag,
+ * typically #UI_BUT_DISABLED / #UI_BUT_INACTIVE.
+ * \return false if there is nothing to add.
+ */
bool UI_search_item_add(uiSearchItems *items,
const char *name,
void *poin,
@@ -1656,6 +1815,21 @@ bool UI_search_item_add(uiSearchItems *items,
int state,
const uint8_t name_prefix_offset);
+/**
+ * \note The item-pointer (referred to below) is a per search item user pointer
+ * passed to #UI_search_item_add (stored in #uiSearchItems.pointers).
+ *
+ * \param search_create_fn: Function to create the menu.
+ * \param search_update_fn: Function to refresh search content after the search text has changed.
+ * \param arg: user value.
+ * \param free_arg: Set to true if the argument is newly allocated memory for every redraw and
+ * should be freed when the button is destroyed.
+ * \param search_arg_free_fn: When non-null, use this function to free \a arg.
+ * \param search_exec_fn: Function that executes the action, gets \a arg as the first argument.
+ * The second argument as the active item-pointer
+ * \param active: When non-null, this item-pointer item will be visible and selected,
+ * otherwise the first item will be selected.
+ */
void UI_but_func_search_set(uiBut *but,
uiButSearchCreateFn search_create_fn,
uiButSearchUpdateFn search_update_fn,
@@ -1666,21 +1840,28 @@ void UI_but_func_search_set(uiBut *but,
void *active);
void UI_but_func_search_set_context_menu(uiBut *but, uiButSearchContextMenuFn context_menu_fn);
void UI_but_func_search_set_tooltip(uiBut *but, uiButSearchTooltipFn tooltip_fn);
+/**
+ * \param search_sep_string: when not NULL, this string is used as a separator,
+ * showing the icon and highlighted text after the last instance of this string.
+ */
void UI_but_func_search_set_sep_string(uiBut *but, const char *search_sep_string);
void UI_but_func_search_set_results_are_suggestions(uiBut *but, const bool value);
-/* height in pixels, it's using hardcoded values still */
+/**
+ * Height in pixels, it's using hard-coded values still.
+ */
int UI_searchbox_size_y(void);
int UI_searchbox_size_x(void);
-/* check if a string is in an existing search box */
+/**
+ * Check if a string is in an existing search box.
+ */
int UI_search_items_find_index(uiSearchItems *items, const char *name);
+/**
+ * Adds a hint to the button which draws right aligned, grayed out and never clipped.
+ */
void UI_but_hint_drawstr_set(uiBut *but, const char *string);
-void UI_but_datasetrow_indentation_set(uiBut *but, int indentation);
-void UI_but_datasetrow_component_set(uiBut *but, uint8_t geometry_component_type);
-void UI_but_datasetrow_domain_set(uiBut *but, uint8_t attribute_domain);
-uint8_t UI_but_datasetrow_component_get(uiBut *but);
-uint8_t UI_but_datasetrow_domain_get(uiBut *but);
+
void UI_but_treerow_indentation_set(uiBut *but, int indentation);
void UI_but_node_link_set(uiBut *but, struct bNodeSocket *socket, const float draw_color[4]);
@@ -1708,7 +1889,14 @@ void UI_but_func_drawextra_set(
void UI_but_func_menu_step_set(uiBut *but, uiMenuStepFunc func);
void UI_but_func_tooltip_set(uiBut *but, uiButToolTipFunc func, void *arg, uiFreeArgFunc free_arg);
+/**
+ * Recreate tool-tip (use to update dynamic tips)
+ */
void UI_but_tooltip_refresh(struct bContext *C, uiBut *but);
+/**
+ * Removes tool-tip timer from active but
+ * (meaning tool-tip is disabled until it's re-enabled again).
+ */
void UI_but_tooltip_timer_remove(struct bContext *C, uiBut *but);
bool UI_textbutton_activate_rna(const struct bContext *C,
@@ -1717,6 +1905,10 @@ bool UI_textbutton_activate_rna(const struct bContext *C,
const char *rna_prop_id);
bool UI_textbutton_activate_but(const struct bContext *C, uiBut *but);
+/**
+ * push a new event onto event queue to activate the given button
+ * (usually a text-field) upon entering a popup
+ */
void UI_but_focus_on_enter_event(struct wmWindow *win, uiBut *but);
void UI_but_func_hold_set(uiBut *but, uiButHandleHoldFunc func, void *argN);
@@ -1754,24 +1946,58 @@ int UI_autocomplete_end(AutoComplete *autocpl, char *autoname);
void UI_panels_begin(const struct bContext *C, struct ARegion *region);
void UI_panels_end(const struct bContext *C, struct ARegion *region, int *r_x, int *r_y);
+/**
+ * Draw panels, selected (panels currently being dragged) on top.
+ */
void UI_panels_draw(const struct bContext *C, struct ARegion *region);
struct Panel *UI_panel_find_by_type(struct ListBase *lb, const struct PanelType *pt);
+/**
+ * \note \a panel should be return value from #UI_panel_find_by_type and can be NULL.
+ */
struct Panel *UI_panel_begin(struct ARegion *region,
struct ListBase *lb,
uiBlock *block,
struct PanelType *pt,
struct Panel *panel,
bool *r_open);
+/**
+ * Create the panel header button group, used to mark which buttons are part of
+ * panel headers for the panel search process that happens later. This Should be
+ * called before adding buttons for the panel's header layout.
+ */
void UI_panel_header_buttons_begin(struct Panel *panel);
+/**
+ * Finish the button group for the panel header to avoid putting panel body buttons in it.
+ */
void UI_panel_header_buttons_end(struct Panel *panel);
void UI_panel_end(struct Panel *panel, int width, int height);
+/**
+ * Set a context for this entire panel and its current layout. This should be used whenever panel
+ * callbacks that are called outside of regular drawing might require context. Currently it affects
+ * the #PanelType.reorder callback only.
+ */
+void UI_panel_context_pointer_set(struct Panel *panel, const char *name, struct PointerRNA *ptr);
+
+/**
+ * Get the panel's expansion state, taking into account
+ * expansion set from property search if it applies.
+ */
bool UI_panel_is_closed(const struct Panel *panel);
bool UI_panel_is_active(const struct Panel *panel);
+/**
+ * For button layout next to label.
+ */
void UI_panel_label_offset(const struct uiBlock *block, int *r_x, int *r_y);
+bool UI_panel_should_show_background(const struct ARegion *region,
+ const struct PanelType *panel_type);
int UI_panel_size_y(const struct Panel *panel);
bool UI_panel_is_dragging(const struct Panel *panel);
+/**
+ * Find whether a panel or any of its sub-panels contain a property that matches the search filter,
+ * depending on the search process running in #UI_block_apply_search_filter earlier.
+ */
bool UI_panel_matches_search_filter(const struct Panel *panel);
bool UI_panel_can_be_pinned(const struct Panel *panel);
@@ -1784,6 +2010,9 @@ const char *UI_panel_category_active_get(struct ARegion *region, bool set_fallba
void UI_panel_category_active_set(struct ARegion *region, const char *idname);
void UI_panel_category_active_set_default(struct ARegion *region, const char *idname);
void UI_panel_category_clear_all(struct ARegion *region);
+/**
+ * Draw vertical tabs on the left side of the region, one tab per category.
+ */
void UI_panel_category_draw_all(struct ARegion *region, const char *category_id_active);
/* Panel custom data. */
@@ -1793,17 +2022,40 @@ struct PointerRNA *UI_region_panel_custom_data_under_cursor(const struct bContex
void UI_panel_custom_data_set(struct Panel *panel, struct PointerRNA *custom_data);
/* Polyinstantiated panels for representing a list of data. */
+/**
+ * Called in situations where panels need to be added dynamically rather than
+ * having only one panel corresponding to each #PanelType.
+ */
struct Panel *UI_panel_add_instanced(const struct bContext *C,
struct ARegion *region,
struct ListBase *panels,
const char *panel_idname,
struct PointerRNA *custom_data);
+/**
+ * Remove instanced panels from the region's panel list.
+ *
+ * \note Can be called with NULL \a C, but it should be avoided because
+ * handlers might not be removed.
+ */
void UI_panels_free_instanced(const struct bContext *C, struct ARegion *region);
#define INSTANCED_PANEL_UNIQUE_STR_LEN 16
+/**
+ * Find a unique key to append to the #PanelType.idname for the lookup to the panel's #uiBlock.
+ * Needed for instanced panels, where there can be multiple with the same type and identifier.
+ */
void UI_list_panel_unique_str(struct Panel *panel, char *r_name);
typedef void (*uiListPanelIDFromDataFunc)(void *data_link, char *r_idname);
+/**
+ * Check if the instanced panels in the region's panels correspond to the list of data the panels
+ * represent. Returns false if the panels have been reordered or if the types from the list data
+ * don't match in any way.
+ *
+ * \param data: The list of data to check against the instanced panels.
+ * \param panel_idname_func: Function to find the #PanelType.idname for each item in the data list.
+ * For a readability and generality, this lookup happens separately for each type of panel list.
+ */
bool UI_panel_list_matches_data(struct ARegion *region,
struct ListBase *data,
uiListPanelIDFromDataFunc panel_idname_func);
@@ -1828,6 +2080,7 @@ void UI_popup_handlers_remove_all(struct bContext *C, struct ListBase *handlers)
* be used to reinitialize some internal state if user preferences change. */
void UI_init(void);
+/* after reading userdef file */
void UI_init_userdef(void);
void UI_reinit_font(void);
void UI_exit(void);
@@ -1943,8 +2196,18 @@ uiLayout *UI_block_layout(uiBlock *block,
const struct uiStyle *style);
void UI_block_layout_set_current(uiBlock *block, uiLayout *layout);
void UI_block_layout_resolve(uiBlock *block, int *r_x, int *r_y);
+/**
+ * Used for property search when the layout process needs to be cancelled in order to avoid
+ * computing the locations for buttons, but the layout items created while adding the buttons
+ * must still be freed.
+ */
void UI_block_layout_free(uiBlock *block);
+/**
+ * Apply property search behavior, setting panel flags and deactivating buttons that don't match.
+ *
+ * \note Must not be run after #UI_block_layout_resolve.
+ */
bool UI_block_apply_search_filter(uiBlock *block, const char *search_filter);
void UI_region_message_subscribe(struct ARegion *region, struct wmMsgBus *mbus);
@@ -1955,11 +2218,23 @@ void uiLayoutSetFunc(uiLayout *layout, uiMenuHandleFunc handlefunc, void *argv);
void uiLayoutSetContextPointer(uiLayout *layout, const char *name, struct PointerRNA *ptr);
struct bContextStore *uiLayoutGetContextStore(uiLayout *layout);
void uiLayoutContextCopy(uiLayout *layout, struct bContextStore *context);
+/**
+ * This is a bit of a hack but best keep it in one place at least.
+ */
struct wmOperatorType *UI_but_operatortype_get_from_enum_menu(struct uiBut *but,
struct PropertyRNA **r_prop);
+/**
+ * This is a bit of a hack but best keep it in one place at least.
+ */
struct MenuType *UI_but_menutype_get(uiBut *but);
+/**
+ * This is a bit of a hack but best keep it in one place at least.
+ */
struct PanelType *UI_but_paneltype_get(uiBut *but);
void UI_menutype_draw(struct bContext *C, struct MenuType *mt, struct uiLayout *layout);
+/**
+ * Used for popup panels only.
+ */
void UI_paneltype_draw(struct bContext *C, struct PanelType *pt, struct uiLayout *layout);
/* Only for convenience. */
@@ -2001,10 +2276,20 @@ eUIEmbossType uiLayoutGetEmboss(uiLayout *layout);
bool uiLayoutGetPropSep(uiLayout *layout);
bool uiLayoutGetPropDecorate(uiLayout *layout);
-/* layout specifiers */
+/* Layout create functions. */
+
uiLayout *uiLayoutRow(uiLayout *layout, bool align);
+/**
+ * See #uiLayoutColumnWithHeading().
+ */
uiLayout *uiLayoutRowWithHeading(uiLayout *layout, bool align, const char *heading);
uiLayout *uiLayoutColumn(uiLayout *layout, bool align);
+/**
+ * Variant of #uiLayoutColumn() that sets a heading label for the layout if the first item is
+ * added through #uiItemFullR(). If split layout is used and the item has no string to add to the
+ * first split-column, the heading is added there instead. Otherwise the heading inserted with a
+ * new row.
+ */
uiLayout *uiLayoutColumnWithHeading(uiLayout *layout, bool align, const char *heading);
uiLayout *uiLayoutColumnFlow(uiLayout *layout, int number, bool align);
uiLayout *uiLayoutGridFlow(uiLayout *layout,
@@ -2056,6 +2341,9 @@ void uiTemplateIDPreview(uiLayout *layout,
int cols,
int filter,
const bool hide_buttons);
+/**
+ * Version of #uiTemplateID using tabs.
+ */
void uiTemplateIDTabs(uiLayout *layout,
struct bContext *C,
struct PointerRNA *ptr,
@@ -2063,11 +2351,23 @@ void uiTemplateIDTabs(uiLayout *layout,
const char *newop,
const char *menu,
int filter);
+/**
+ * This is for selecting the type of ID-block to use,
+ * and then from the relevant type choosing the block to use.
+ *
+ * \param propname: property identifier for property that ID-pointer gets stored to.
+ * \param proptypename: property identifier for property
+ * used to determine the type of ID-pointer that can be used.
+ */
void uiTemplateAnyID(uiLayout *layout,
struct PointerRNA *ptr,
const char *propname,
const char *proptypename,
const char *text);
+/**
+ * Search menu to pick an item from a collection.
+ * A version of uiTemplateID that works for non-ID types.
+ */
void uiTemplateSearch(uiLayout *layout,
struct bContext *C,
struct PointerRNA *ptr,
@@ -2086,6 +2386,13 @@ void uiTemplateSearchPreview(uiLayout *layout,
const char *unlinkop,
const int rows,
const int cols);
+/**
+ * This is creating/editing RNA-Paths
+ *
+ * - ptr: struct which holds the path property
+ * - propname: property identifier for property that path gets stored to
+ * - root_ptr: struct that path gets built from
+ */
void uiTemplatePathBuilder(uiLayout *layout,
struct PointerRNA *ptr,
const char *propname,
@@ -2093,7 +2400,13 @@ void uiTemplatePathBuilder(uiLayout *layout,
const char *text);
void uiTemplateModifiers(uiLayout *layout, struct bContext *C);
void uiTemplateGpencilModifiers(uiLayout *layout, struct bContext *C);
+/**
+ * Check if the shader effect panels don't match the data and rebuild the panels if so.
+ */
void uiTemplateShaderFx(uiLayout *layout, struct bContext *C);
+/**
+ * Check if the constraint panels don't match the data and rebuild the panels if so.
+ */
void uiTemplateConstraints(uiLayout *layout, struct bContext *C, bool use_bone_constraints);
uiLayout *uiTemplateGpencilModifier(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr);
@@ -2120,7 +2433,13 @@ void uiTemplateColorRamp(uiLayout *layout,
struct PointerRNA *ptr,
const char *propname,
bool expand);
+/**
+ * \param icon_scale: Scale of the icon, 1x == button height.
+ */
void uiTemplateIcon(uiLayout *layout, int icon_value, float icon_scale);
+/**
+ * \param icon_scale: Scale of the icon, 1x == button height.
+ */
void uiTemplateIconView(uiLayout *layout,
struct PointerRNA *ptr,
const char *propname,
@@ -2138,7 +2457,14 @@ void uiTemplateCurveMapping(uiLayout *layout,
bool brush,
bool neg_slope,
bool tone);
+/**
+ * Template for a path creation widget intended for custom bevel profiles.
+ * This section is quite similar to #uiTemplateCurveMapping, but with reduced complexity.
+ */
void uiTemplateCurveProfile(uiLayout *layout, struct PointerRNA *ptr, const char *propname);
+/**
+ * This template now follows User Preference for type - name is not correct anymore.
+ */
void uiTemplateColorPicker(uiLayout *layout,
struct PointerRNA *ptr,
const char *propname,
@@ -2154,6 +2480,10 @@ void uiTemplateCryptoPicker(uiLayout *layout,
struct PointerRNA *ptr,
const char *propname,
int icon);
+/**
+ * \todo for now, grouping of layers is determined by dividing up the length of
+ * the array of layer bitflags
+ */
void uiTemplateLayers(uiLayout *layout,
struct PointerRNA *ptr,
const char *propname,
@@ -2188,6 +2518,11 @@ void uiTemplateOperatorSearch(uiLayout *layout);
void UI_but_func_menu_search(uiBut *but);
void uiTemplateMenuSearch(uiLayout *layout);
+/**
+ * Draw Operator property buttons for redoing execution with different settings.
+ * This function does not initialize the layout,
+ * functions can be called on the layout before and after.
+ */
void uiTemplateOperatorPropertyButs(const struct bContext *C,
uiLayout *layout,
struct wmOperator *op,
@@ -2273,6 +2608,9 @@ void uiTemplateNodeView(uiLayout *layout,
struct bNode *node,
struct bNodeSocket *input);
void uiTemplateTextureUser(uiLayout *layout, struct bContext *C);
+/**
+ * Button to quickly show texture in Properties Editor texture tab.
+ */
void uiTemplateTextureShow(uiLayout *layout,
const struct bContext *C,
struct PointerRNA *ptr,
@@ -2329,9 +2667,15 @@ void uiTemplateAssetView(struct uiLayout *layout,
const char *drag_opname,
struct PointerRNA *r_drag_op_properties);
+/**
+ * \return: A RNA pointer for the operator properties.
+ */
struct PointerRNA *UI_list_custom_activate_operator_set(struct uiList *ui_list,
const char *opname,
bool create_properties);
+/**
+ * \return: A RNA pointer for the operator properties.
+ */
struct PointerRNA *UI_list_custom_drag_operator_set(struct uiList *ui_list,
const char *opname,
bool create_properties);
@@ -2350,6 +2694,9 @@ void uiItemEnumO(uiLayout *layout,
int icon,
const char *propname,
int value);
+/**
+ * For use in cases where we have.
+ */
void uiItemEnumO_value(uiLayout *layout,
const char *name,
int icon,
@@ -2428,6 +2775,9 @@ void uiItemFullR(uiLayout *layout,
int flag,
const char *name,
int icon);
+/**
+ * Use a wrapper function since re-implementing all the logic in this function would be messy.
+ */
void uiItemFullR_with_popover(uiLayout *layout,
struct PointerRNA *ptr,
struct PropertyRNA *prop,
@@ -2491,6 +2841,11 @@ void uiItemsFullEnumO(uiLayout *layout,
struct IDProperty *properties,
wmOperatorCallContext context,
int flag);
+/**
+ * Create UI items for enum items in \a item_array.
+ *
+ * A version of #uiItemsFullEnumO that takes pre-calculated item array.
+ */
void uiItemsFullEnumO_items(uiLayout *layout,
struct wmOperatorType *ot,
struct PointerRNA ptr,
@@ -2507,33 +2862,59 @@ typedef struct uiPropertySplitWrapper {
uiLayout *decorate_column;
} uiPropertySplitWrapper;
+/**
+ * Normally, we handle the split layout in #uiItemFullR(), but there are other cases where the
+ * logic is needed. Ideally, #uiItemFullR() could just call this, but it currently has too many
+ * special needs.
+ */
uiPropertySplitWrapper uiItemPropertySplitWrapperCreate(uiLayout *parent_layout);
void uiItemL(uiLayout *layout, const char *name, int icon); /* label */
void uiItemL_ex(
uiLayout *layout, const char *name, int icon, const bool highlight, const bool redalert);
+/**
+ * Helper to add a label and creates a property split layout if needed.
+ */
uiLayout *uiItemL_respect_property_split(uiLayout *layout, const char *text, int icon);
-/* label icon for dragging */
+/**
+ * Label icon for dragging.
+ */
void uiItemLDrag(uiLayout *layout, struct PointerRNA *ptr, const char *name, int icon);
-/* menu */
+/**
+ * Menu.
+ */
void uiItemM_ptr(uiLayout *layout, struct MenuType *mt, const char *name, int icon);
void uiItemM(uiLayout *layout, const char *menuname, const char *name, int icon);
-/* menu contents */
+/**
+ * Menu contents.
+ */
void uiItemMContents(uiLayout *layout, const char *menuname);
-/* Decorators */
+
+/* Decorators. */
+
+/**
+ * Insert a decorator item for a button with the same property as \a prop.
+ * To force inserting a blank dummy element, NULL can be passed for \a ptr and \a prop.
+ */
void uiItemDecoratorR_prop(uiLayout *layout,
struct PointerRNA *ptr,
struct PropertyRNA *prop,
int index);
+/**
+ * Insert a decorator item for a button with the same property as \a prop.
+ * To force inserting a blank dummy element, NULL can be passed for \a ptr and \a propname.
+ */
void uiItemDecoratorR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int index);
-/* value */
+/** Value item */
void uiItemV(uiLayout *layout, const char *name, int icon, int argval);
-/* separator */
+/** Separator item */
void uiItemS(uiLayout *layout);
+/** Separator item */
void uiItemS_ex(uiLayout *layout, float factor);
-/* Special separator. */
+/** Flexible spacing. */
void uiItemSpacer(uiLayout *layout);
+/* popover */
void uiItemPopoverPanel_ptr(
uiLayout *layout, const struct bContext *C, struct PanelType *pt, const char *name, int icon);
void uiItemPopoverPanel(uiLayout *layout,
@@ -2548,7 +2929,13 @@ void uiItemPopoverPanelFromGroup(uiLayout *layout,
const char *context,
const char *category);
+/**
+ * Level items.
+ */
void uiItemMenuF(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc func, void *arg);
+/**
+ * Version of #uiItemMenuF that free's `argN`.
+ */
void uiItemMenuFN(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc func, void *argN);
void uiItemMenuEnumFullO_ptr(uiLayout *layout,
struct bContext *C,
@@ -2586,9 +2973,15 @@ void uiItemTabsEnumR_prop(uiLayout *layout,
bool icon_only);
/* Only for testing, inspecting layouts. */
+/**
+ * Evaluate layout items as a Python dictionary.
+ */
const char *UI_layout_introspect(uiLayout *layout);
-/* Helper to add a big icon and create a split layout for alert boxes. */
+/**
+ * Helper to add a big icon and create a split layout for alert popups.
+ * Returns the layout to place further items into the alert box.
+ */
uiLayout *uiItemsAlertBox(uiBlock *block, const int size, const eAlertIcon icon);
/* UI Operators */
@@ -2598,6 +2991,9 @@ typedef struct uiDragColorHandle {
} uiDragColorHandle;
void ED_operatortypes_ui(void);
+/**
+ * \brief User Interface Keymap
+ */
void ED_keymap_ui(struct wmKeyConfig *keyconf);
void ED_dropboxes_ui(void);
void ED_uilisttypes_ui(void);
@@ -2611,10 +3007,28 @@ bool UI_context_copy_to_selected_list(struct bContext *C,
struct ListBase *r_lb,
bool *r_use_path_from_id,
char **r_path);
+bool UI_context_copy_to_selected_check(struct PointerRNA *ptr,
+ struct PointerRNA *ptr_link,
+ struct PropertyRNA *prop,
+ const char *path,
+ bool use_path_from_id,
+ struct PointerRNA *r_ptr,
+ struct PropertyRNA **r_prop);
/* Helpers for Operators */
uiBut *UI_context_active_but_get(const struct bContext *C);
+/**
+ * Version of #UI_context_active_get() that uses the result of #CTX_wm_menu()
+ * if set. Does not traverse into parent menus, which may be wanted in some
+ * cases.
+ */
uiBut *UI_context_active_but_get_respect_menu(const struct bContext *C);
+/**
+ * Version of #UI_context_active_but_get that also returns RNA property info.
+ * Helper function for insert keyframe, reset to default, etc operators.
+ *
+ * \return active button, NULL if none found or if it doesn't contain valid RNA data.
+ */
uiBut *UI_context_active_but_prop_get(const struct bContext *C,
struct PointerRNA *r_ptr,
struct PropertyRNA **r_prop,
@@ -2623,12 +3037,18 @@ void UI_context_active_but_prop_handle(struct bContext *C);
void UI_context_active_but_clear(struct bContext *C, struct wmWindow *win, struct ARegion *region);
struct wmOperator *UI_context_active_operator_get(const struct bContext *C);
+/**
+ * Helper function for insert keyframe, reset to default, etc operators.
+ */
void UI_context_update_anim_flag(const struct bContext *C);
void UI_context_active_but_prop_get_filebrowser(const struct bContext *C,
struct PointerRNA *r_ptr,
struct PropertyRNA **r_prop,
bool *r_is_undo,
bool *r_is_userdef);
+/**
+ * For new/open operators.
+ */
void UI_context_active_but_prop_get_templateID(struct bContext *C,
struct PointerRNA *r_ptr,
struct PropertyRNA **r_prop);
@@ -2639,6 +3059,9 @@ uiBut *UI_region_but_find_rect_over(const struct ARegion *region, const struct r
uiBlock *UI_region_block_find_mouse_over(const struct ARegion *region,
const int xy[2],
bool only_clip);
+/**
+ * Try to find a search-box region opened from a button in \a button_region.
+ */
struct ARegion *UI_region_searchbox_region_get(const struct ARegion *button_region);
/* uiFontStyle.align */
@@ -2669,12 +3092,24 @@ void UI_fontstyle_draw(const struct uiFontStyle *fs,
const char *str,
const uchar col[4],
const struct uiFontStyleDraw_Params *fs_params);
+/**
+ * Drawn same as above, but at 90 degree angle.
+ */
void UI_fontstyle_draw_rotated(const struct uiFontStyle *fs,
const struct rcti *rect,
const char *str,
const uchar col[4]);
+/**
+ * Similar to #UI_fontstyle_draw
+ * but ignore alignment, shadow & no clipping rect.
+ *
+ * For drawing on-screen labels.
+ */
void UI_fontstyle_draw_simple(
const struct uiFontStyle *fs, float x, float y, const char *str, const uchar col[4]);
+/**
+ * Same as #UI_fontstyle_draw but draw a colored backdrop.
+ */
void UI_fontstyle_draw_simple_backdrop(const struct uiFontStyle *fs,
float x,
float y,
@@ -2684,15 +3119,30 @@ void UI_fontstyle_draw_simple_backdrop(const struct uiFontStyle *fs,
int UI_fontstyle_string_width(const struct uiFontStyle *fs,
const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2);
+/**
+ * Return the width of `str` with the spacing & kerning of `fs` with `aspect`
+ * (representing #uiBlock.aspect) applied.
+ *
+ * When calculating text width, the UI layout logic calculate widths without scale,
+ * only applying scale when drawing. This causes problems for fonts since kerning at
+ * smaller sizes often makes them wider than a scaled down version of the larger text.
+ * Resolve this by calculating the text at the on-screen size,
+ * returning the result scaled back to 1:1. See T92361.
+ */
int UI_fontstyle_string_width_with_block_aspect(const struct uiFontStyle *fs,
const char *str,
const float aspect) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1, 2);
int UI_fontstyle_height_max(const struct uiFontStyle *fs);
+/**
+ * Triangle 'icon' for panel header and other cases.
+ */
void UI_draw_icon_tri(float x, float y, char dir, const float[4]);
-const struct uiStyle *UI_style_get(void); /* use for fonts etc */
+/* XXX: read a style configure */
+const struct uiStyle *UI_style_get(void); /* use for fonts etc */
+/* for drawing, scaled with DPI setting */
const struct uiStyle *UI_style_get_dpi(void); /* DPI scaled settings for drawing */
/* linker workaround ack! */
@@ -2701,25 +3151,56 @@ void UI_template_fix_linking(void);
/* UI_OT_editsource helpers */
bool UI_editsource_enable_check(void);
void UI_editsource_active_but_test(uiBut *but);
+/**
+ * Remove the editsource data for \a old_but and reinsert it for \a new_but. Use when the button
+ * was reallocated, e.g. to have a new type (#ui_but_change_type()).
+ */
void UI_editsource_but_replace(const uiBut *old_but, uiBut *new_but);
+/**
+ * Adjust the view so the rectangle of \a but is in view, with some extra margin.
+ *
+ * It's important that this is only executed after buttons received their final #uiBut.rect. E.g.
+ * #UI_panels_end() modifies them, so if that is executed, this function must not be called before
+ * it.
+ *
+ * \param region: The region the button is placed in. Make sure this is actually the one the button
+ * is placed in, not just the context region.
+ */
void UI_but_ensure_in_view(const struct bContext *C, struct ARegion *region, const uiBut *but);
/* UI_butstore_ helpers */
typedef struct uiButStore uiButStore;
typedef struct uiButStoreElem uiButStoreElem;
+/**
+ * Create a new button store, the caller must manage and run #UI_butstore_free
+ */
uiButStore *UI_butstore_create(uiBlock *block);
+/**
+ * NULL all pointers, don't free since the owner needs to be able to inspect.
+ */
void UI_butstore_clear(uiBlock *block);
+/**
+ * Map freed buttons from the old block and update pointers.
+ */
void UI_butstore_update(uiBlock *block);
void UI_butstore_free(uiBlock *block, uiButStore *bs);
bool UI_butstore_is_valid(uiButStore *bs);
bool UI_butstore_is_registered(uiBlock *block, uiBut *but);
void UI_butstore_register(uiButStore *bs_handle, uiBut **but_p);
+/**
+ * Update the pointer for a registered button.
+ */
bool UI_butstore_register_update(uiBlock *block, uiBut *but_dst, const uiBut *but_src);
void UI_butstore_unregister(uiButStore *bs_handle, uiBut **but_p);
/* ui_interface_region_tooltip.c */
+
+/**
+ * \param is_label: When true, show a small tip that only shows the name, otherwise show the full
+ * tooltip.
+ */
struct ARegion *UI_tooltip_create_from_button(struct bContext *C,
struct ARegion *butregion,
uiBut *but,
@@ -2741,6 +3222,13 @@ typedef struct {
char hint[UI_MAX_DRAW_STR];
} uiSearchItemTooltipData;
+/**
+ * Create a tooltip from search-item tooltip data \a item_tooltip data.
+ * To be called from a callback set with #UI_but_func_search_set_tooltip().
+ *
+ * \param item_rect: Rectangle of the search item in search region space (#ui_searchbox_butrect())
+ * which is passed to the tooltip callback.
+ */
struct ARegion *UI_tooltip_create_from_search_item_generic(
struct bContext *C,
const struct ARegion *searchbox_region,
@@ -2759,6 +3247,10 @@ struct ARegion *UI_tooltip_create_from_search_item_generic(
/* Typical UI text */
#define UI_FSTYLE_WIDGET (const uiFontStyle *)&(UI_style_get()->widget)
+/**
+ * Returns the best "UI" precision for given floating value,
+ * so that e.g. 10.000001 rather gets drawn as '10'...
+ */
int UI_calc_float_precision(int prec, double value);
/* widget batched drawing */
@@ -2767,6 +3259,12 @@ void UI_widgetbase_draw_cache_flush(void);
void UI_widgetbase_draw_cache_end(void);
/* Use for resetting the theme. */
+/**
+ * Initialize default theme.
+ *
+ * \note When you add new colors, created & saved themes need initialized
+ * use function below, #init_userdef_do_versions.
+ */
void UI_theme_init_default(void);
void UI_style_init_default(void);
@@ -2780,12 +3278,28 @@ void UI_interface_tag_script_reload(void);
bool UI_tree_view_item_is_active(const uiTreeViewItemHandle *item);
bool UI_tree_view_item_matches(const uiTreeViewItemHandle *a, const uiTreeViewItemHandle *b);
+/**
+ * Attempt to start dragging the tree-item \a item_. This will not work if the tree item doesn't
+ * support dragging, i.e. it won't create a drag-controller upon request.
+ * \return True if dragging started successfully, otherwise false.
+ */
bool UI_tree_view_item_drag_start(struct bContext *C, uiTreeViewItemHandle *item_);
bool UI_tree_view_item_can_drop(const uiTreeViewItemHandle *item_,
const struct wmDrag *drag,
const char **r_disabled_hint);
char *UI_tree_view_item_drop_tooltip(const uiTreeViewItemHandle *item, const struct wmDrag *drag);
-bool UI_tree_view_item_drop_handle(uiTreeViewItemHandle *item_, const struct ListBase *drags);
+/**
+ * Let a tree-view item handle a drop event.
+ * \return True if the drop was handled by the tree-view item.
+ */
+bool UI_tree_view_item_drop_handle(struct bContext *C,
+ const uiTreeViewItemHandle *item_,
+ const struct ListBase *drags);
+/**
+ * Can \a item_handle be renamed right now? Not that this isn't just a mere wrapper around
+ * #AbstractTreeViewItem::can_rename(). This also checks if there is another item being renamed,
+ * and returns false if so.
+ */
bool UI_tree_view_item_can_rename(const uiTreeViewItemHandle *item_handle);
void UI_tree_view_item_begin_rename(uiTreeViewItemHandle *item_handle);
@@ -2793,6 +3307,9 @@ void UI_tree_view_item_context_menu_build(struct bContext *C,
const uiTreeViewItemHandle *item,
uiLayout *column);
+/**
+ * \param xy: Coordinate to find a tree-row item at, in window space.
+ */
uiTreeViewItemHandle *UI_block_tree_view_find_item_at(const struct ARegion *region,
const int xy[2]) ATTR_NONNULL(1, 2);
uiTreeViewItemHandle *UI_block_tree_view_find_active_item(const struct ARegion *region);
diff --git a/source/blender/editors/include/UI_interface.hh b/source/blender/editors/include/UI_interface.hh
index b14ee6c4a59..d18ec009108 100644
--- a/source/blender/editors/include/UI_interface.hh
+++ b/source/blender/editors/include/UI_interface.hh
@@ -66,6 +66,9 @@ void attribute_search_add_items(
} // namespace blender::ui
+/**
+ * Override this for all available tree types.
+ */
blender::ui::AbstractTreeView *UI_block_add_view(
uiBlock &block,
blender::StringRef idname,
diff --git a/source/blender/editors/include/UI_interface_icons.h b/source/blender/editors/include/UI_interface_icons.h
index 37cf7229ffb..242b8504ae1 100644
--- a/source/blender/editors/include/UI_interface_icons.h
+++ b/source/blender/editors/include/UI_interface_icons.h
@@ -64,23 +64,39 @@ typedef enum eAlertIcon {
struct ImBuf *UI_icon_alert_imbuf_get(eAlertIcon icon);
-/*
+/**
* Resizable Icons for Blender
*/
void UI_icons_init(void);
+/**
+ * Reload the textures for internal icons.
+ * This function will release the previous textures.
+ */
void UI_icons_reload_internal_textures(void);
+/**
+ * NOTE: returns unscaled by DPI.
+ */
int UI_icon_get_width(int icon_id);
int UI_icon_get_height(int icon_id);
bool UI_icon_get_theme_color(int icon_id, unsigned char color[4]);
+/**
+ * Note that if an ID doesn't support jobs for preview creation, \a use_job will be ignored.
+ */
void UI_icon_render_id(const struct bContext *C,
struct Scene *scene,
struct ID *id,
const enum eIconSizes size,
const bool use_job);
+/**
+ * Render size for preview images and icons
+ */
int UI_icon_preview_to_render_size(enum eIconSizes size);
+/**
+ * Draws icon with dpi scale factor.
+ */
void UI_icon_draw(float x, float y, int icon_id);
void UI_icon_draw_alpha(float x, float y, int icon_id, float alpha);
void UI_icon_draw_preview(float x, float y, int icon_id, float aspect, float alpha, int size);
diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h
index 61da496d344..98e141c65b5 100644
--- a/source/blender/editors/include/UI_resources.h
+++ b/source/blender/editors/include/UI_resources.h
@@ -351,7 +351,7 @@ typedef enum ThemeColorID {
TH_VERTEX_BEVEL,
} ThemeColorID;
-/* specific defines per space should have higher define values */
+/* Specific defines per space should have higher define values. */
struct bTheme;
@@ -362,93 +362,144 @@ struct bThemeState {
/* THE CODERS API FOR THEMES: */
-/* returns one value, not scaled */
+/**
+ * Get individual values, not scaled.
+ */
float UI_GetThemeValuef(int colorid);
+/**
+ * Get individual values, not scaled.
+ */
int UI_GetThemeValue(int colorid);
+/* Versions of #UI_GetThemeValue & #UI_GetThemeValuef, which take a space-type */
+
float UI_GetThemeValueTypef(int colorid, int spacetype);
int UI_GetThemeValueType(int colorid, int spacetype);
-/* get three color values, scaled to 0.0-1.0 range */
+/**
+ * Get three color values, scaled to 0.0-1.0 range.
+ */
void UI_GetThemeColor3fv(int colorid, float col[3]);
void UI_GetThemeColorBlend3ubv(int colorid1, int colorid2, float fac, unsigned char col[3]);
void UI_GetThemeColorBlend3f(int colorid1, int colorid2, float fac, float r_col[3]);
void UI_GetThemeColorBlend4f(int colorid1, int colorid2, float fac, float r_col[4]);
-/* get the color, range 0.0-1.0, complete with shading offset */
+/**
+ * Get the color, range 0.0-1.0, complete with shading offset.
+ */
void UI_GetThemeColorShade3fv(int colorid, int offset, float col[3]);
void UI_GetThemeColorShade3ubv(int colorid, int offset, unsigned char col[3]);
void UI_GetThemeColorShade4ubv(int colorid, int offset, unsigned char col[4]);
-/* get three color values, range 0-255,
- * complete with shading offset for the RGB components and blending. */
+/**
+ * Get three color values, range 0-255,
+ * complete with shading offset for the RGB components and blending.
+ */
void UI_GetThemeColorBlendShade3ubv(
int colorid1, int colorid2, float fac, int offset, unsigned char col[3]);
-/* get four color values, scaled to 0.0-1.0 range */
+/**
+ * Get four color values, scaled to 0.0-1.0 range.
+ */
void UI_GetThemeColor4fv(int colorid, float col[4]);
-/* get four color values from specified space type, scaled to 0.0-1.0 range */
+/**
+ * Get four color values from specified space type, scaled to 0.0-1.0 range.
+ */
void UI_GetThemeColorType4fv(int colorid, int spacetype, float col[4]);
-/* get four color values, range 0.0-1.0, complete with shading offset for the RGB components */
+/**
+ * Get four color values, range 0.0-1.0, complete with shading offset for the RGB components.
+ */
void UI_GetThemeColorShade4fv(int colorid, int offset, float col[4]);
void UI_GetThemeColorShadeAlpha4fv(int colorid, int coloffset, int alphaoffset, float col[4]);
-/* get four color values ranged between 0 and 255; includes the alpha channel */
+/**
+ * Get four color values ranged between 0 and 255; includes the alpha channel.
+ */
void UI_GetThemeColorShadeAlpha4ubv(int colorid,
int coloffset,
int alphaoffset,
unsigned char col[4]);
-/* get four color values, range 0.0-1.0,
- * complete with shading offset for the RGB components and blending. */
+/**
+ * Get four color values, range 0.0-1.0,
+ * complete with shading offset for the RGB components and blending.
+ */
void UI_GetThemeColorBlendShade3fv(
int colorid1, int colorid2, float fac, int offset, float col[3]);
void UI_GetThemeColorBlendShade4fv(
int colorid1, int colorid2, float fac, int offset, float col[4]);
-/* get the 3 or 4 byte values */
+/**
+ * Get the 3 or 4 byte values.
+ */
void UI_GetThemeColor3ubv(int colorid, unsigned char col[3]);
+/**
+ * Get the color, in char pointer.
+ */
void UI_GetThemeColor4ubv(int colorid, unsigned char col[4]);
-/* get a theme color from specified space type */
+/**
+ * Get a theme color from specified space type.
+ */
void UI_GetThemeColorType3fv(int colorid, int spacetype, float col[3]);
void UI_GetThemeColorType3ubv(int colorid, int spacetype, unsigned char col[3]);
void UI_GetThemeColorType4ubv(int colorid, int spacetype, unsigned char col[4]);
-/* get theme color for coloring monochrome icons */
+/**
+ * Get theme color for coloring monochrome icons.
+ */
bool UI_GetIconThemeColor4ubv(int colorid, unsigned char col[4]);
-/* shade a 3 byte color (same as UI_GetColorPtrBlendShade3ubv with 0.0 factor) */
+/**
+ * Shade a 3 byte color (same as UI_GetColorPtrBlendShade3ubv with 0.0 factor).
+ */
void UI_GetColorPtrShade3ubv(const unsigned char cp1[3], unsigned char col[3], int offset);
-/* get a 3 byte color, blended and shaded between two other char color pointers */
+/**
+ * Get a 3 byte color, blended and shaded between two other char color pointers.
+ */
void UI_GetColorPtrBlendShade3ubv(const unsigned char cp1[3],
const unsigned char cp2[3],
unsigned char col[3],
float fac,
int offset);
-/* sets the font color
- * (for anything fancy use UI_GetThemeColor[Fancy] then BLF_color) */
+/**
+ * Sets the font color
+ * (for anything fancy use UI_GetThemeColor[Fancy] then BLF_color).
+ */
void UI_FontThemeColor(int fontid, int colorid);
-/* Clear the frame-buffer using the input colorid. */
+/**
+ * Clear the frame-buffer using the input colorid.
+ */
void UI_ThemeClearColor(int colorid);
-/* internal (blender) usage only, for init and set active */
+/**
+ * Internal (blender) usage only, for init and set active.
+ */
void UI_SetTheme(int spacetype, int regionid);
-/* get current theme */
+/**
+ * Get current theme.
+ */
struct bTheme *UI_GetTheme(void);
+/**
+ * For the rare case we need to temp swap in a different theme (off-screen render).
+ */
void UI_Theme_Store(struct bThemeState *theme_state);
void UI_Theme_Restore(struct bThemeState *theme_state);
-/* return shadow width outside menus and popups */
+/**
+ * Return shadow width outside menus and popups.
+ */
int UI_ThemeMenuShadowWidth(void);
-/* only for buttons in theme editor! */
+/**
+ * Only for buttons in theme editor!
+ */
const unsigned char *UI_ThemeGetColorPtr(struct bTheme *btheme, int spacetype, int colorid);
void UI_make_axis_color(const unsigned char src_col[3], unsigned char dst_col[3], const char axis);
diff --git a/source/blender/editors/include/UI_tree_view.hh b/source/blender/editors/include/UI_tree_view.hh
index 0d18eedeac9..8208f8daf5d 100644
--- a/source/blender/editors/include/UI_tree_view.hh
+++ b/source/blender/editors/include/UI_tree_view.hh
@@ -17,8 +17,8 @@
/** \file
* \ingroup editorui
*
- * API for simple creation of tree UIs supporting advanced features.
- * https://wiki.blender.org/wiki/Source/Interface/Views
+ * API for simple creation of tree UIs supporting typically needed features.
+ * https://wiki.blender.org/wiki/Source/Interface/Views/Tree_Views
*/
#pragma once
@@ -36,7 +36,6 @@
#include "UI_resources.h"
struct bContext;
-struct PointerRNA;
struct uiBlock;
struct uiBut;
struct uiButTreeRow;
@@ -53,14 +52,17 @@ class AbstractTreeViewItemDragController;
/* ---------------------------------------------------------------------- */
/** \name Tree-View Item Container
+ *
+ * Base class for tree-view and tree-view items, so both can contain children.
* \{ */
/**
- * Helper base class to expose common child-item data and functionality to both #AbstractTreeView
- * and #AbstractTreeViewItem.
+ * Both the tree-view (as the root of the tree) and the items can have children. This is the base
+ * class for both, to store and manage child items. Children are owned by their parent container
+ * (tree-view or item).
*
- * That means this type can be used whenever either a #AbstractTreeView or a
- * #AbstractTreeViewItem is needed.
+ * That means this type can be used whenever either an #AbstractTreeView or an
+ * #AbstractTreeViewItem is needed, but the #TreeViewOrItem alias is a better name to use then.
*/
class TreeViewItemContainer {
friend class AbstractTreeView;
@@ -112,37 +114,10 @@ class TreeViewItemContainer {
ENUM_OPERATORS(TreeViewItemContainer::IterOptions,
TreeViewItemContainer::IterOptions::SkipCollapsed);
-/** \} */
-
-/* ---------------------------------------------------------------------- */
-/** \name Tree-View Builders
- * \{ */
-
-class TreeViewBuilder {
- uiBlock &block_;
-
- public:
- TreeViewBuilder(uiBlock &block);
-
- void build_tree_view(AbstractTreeView &tree_view);
-};
-
-class TreeViewLayoutBuilder {
- uiBlock &block_;
-
- friend TreeViewBuilder;
-
- public:
- void build_row(AbstractTreeViewItem &item) const;
- uiBlock &block() const;
- uiLayout *current_layout() const;
-
- private:
- /* Created through #TreeViewBuilder. */
- TreeViewLayoutBuilder(uiBlock &block);
-
- static void polish_layout(const uiBlock &block);
-};
+/** The container class is the base for both the tree-view and the items. This alias gives it a
+ * clearer name for handles that accept both. Use whenever something wants to act on child-items,
+ * irrespective of if they are stored at root level or as children of some other item. */
+using TreeViewOrItem = TreeViewItemContainer;
/** \} */
@@ -151,8 +126,8 @@ class TreeViewLayoutBuilder {
* \{ */
class AbstractTreeView : public TreeViewItemContainer {
- friend AbstractTreeViewItem;
- friend TreeViewBuilder;
+ friend class AbstractTreeViewItem;
+ friend class TreeViewBuilder;
/**
* Only one item can be renamed at a time. So the tree is informed about the renaming state to
@@ -169,15 +144,16 @@ class AbstractTreeView : public TreeViewItemContainer {
/** Only one item can be renamed at a time. */
bool is_renaming() const;
+
+ protected:
+ virtual void build_tree() = 0;
+
/**
* Check if the tree is fully (re-)constructed. That means, both #build_tree() and
* #update_from_old() have finished.
*/
bool is_reconstructed() const;
- protected:
- virtual void build_tree() = 0;
-
private:
/**
* Match the tree-view against an earlier version of itself (if any) and copy the old UI state
@@ -185,10 +161,10 @@ class AbstractTreeView : public TreeViewItemContainer {
* #AbstractTreeViewItem.update_from_old().
*/
void update_from_old(uiBlock &new_block);
- static void update_children_from_old_recursive(const TreeViewItemContainer &new_items,
- const TreeViewItemContainer &old_items);
+ static void update_children_from_old_recursive(const TreeViewOrItem &new_items,
+ const TreeViewOrItem &old_items);
static AbstractTreeViewItem *find_matching_child(const AbstractTreeViewItem &lookup_item,
- const TreeViewItemContainer &items);
+ const TreeViewOrItem &items);
/**
* Items may want to do additional work when state changes. But these state changes can only be
@@ -196,7 +172,6 @@ class AbstractTreeView : public TreeViewItemContainer {
* the actual state changes are done in a delayed manner through this function.
*/
void change_state_delayed();
- void build_layout_from_tree(const TreeViewLayoutBuilder &builder);
};
/** \} */
@@ -215,21 +190,18 @@ class AbstractTreeView : public TreeViewItemContainer {
class AbstractTreeViewItem : public TreeViewItemContainer {
friend class AbstractTreeView;
friend class TreeViewLayoutBuilder;
-
- public:
- using IsActiveFn = std::function<bool()>;
+ /* Higher-level API. */
+ friend class TreeViewItemAPIWrapper;
private:
bool is_open_ = false;
bool is_active_ = false;
bool is_renaming_ = false;
- IsActiveFn is_active_fn_;
-
protected:
- /** This label is used for identifying an item (together with its parent's labels). */
+ /** This label is used for identifying an item within its parent. */
std::string label_{};
- /** Every item gets a button of type during the layout building #UI_BTYPE_TREEROW. */
+ /** Every visible item gets a button of type #UI_BTYPE_TREEROW during the layout building. */
uiButTreeRow *tree_row_but_ = nullptr;
public:
@@ -238,33 +210,59 @@ class AbstractTreeViewItem : public TreeViewItemContainer {
virtual void build_row(uiLayout &row) = 0;
virtual void build_context_menu(bContext &C, uiLayout &column) const;
+ AbstractTreeView &get_tree_view() const;
+
+ void begin_renaming();
+ void toggle_collapsed();
+ void set_collapsed(bool collapsed);
+ /**
+ * Requires the tree to have completed reconstruction, see #is_reconstructed(). Otherwise we
+ * can't be sure about the item state.
+ */
+ bool is_collapsed() const;
+ /**
+ * Requires the tree to have completed reconstruction, see #is_reconstructed(). Otherwise we
+ * can't be sure about the item state.
+ */
+ bool is_active() const;
+
+ protected:
+ /**
+ * Called when the items state changes from inactive to active.
+ */
virtual void on_activate();
/**
- * Set a custom callback to check if this item should be active. There's a version without
- * arguments for checking if the item is currently in an active state.
+ * If the result is not empty, it controls whether the item should be active or not,
+ * usually depending on the data that the view represents.
*/
- virtual void is_active(IsActiveFn is_active_fn);
+ virtual std::optional<bool> should_be_active() const;
/**
* Queries if the tree-view item supports renaming in principle. Renaming may still fail, e.g. if
* another item is already being renamed.
*/
- virtual bool can_rename() const;
+ virtual bool supports_renaming() const;
/**
* Try renaming the item, or the data it represents. Can assume
- * #AbstractTreeViewItem::can_rename() returned true. Sub-classes that override this should
- * usually call this, unless they have a custom #AbstractTreeViewItem.matches().
+ * #AbstractTreeViewItem::supports_renaming() returned true. Sub-classes that override this
+ * should usually call this, unless they have a custom #AbstractTreeViewItem.matches().
*
* \return True if the renaming was successful.
*/
virtual bool rename(StringRefNull new_name);
/**
+ * Return whether the item can be collapsed. Used to disable collapsing for items with children.
+ */
+ virtual bool supports_collapsing() const;
+
+ /**
* Copy persistent state (e.g. is-collapsed flag, selection, etc.) from a matching item of
* the last redraw to this item. If sub-classes introduce more advanced state they should
* override this and make it update their state accordingly.
*/
virtual void update_from_old(const AbstractTreeViewItem &old);
+
/**
* Compare this item to \a other to check if they represent the same data.
* Used to recognize an item from a previous redraw, to be able to keep its state (e.g.
@@ -288,47 +286,28 @@ class AbstractTreeViewItem : public TreeViewItemContainer {
*/
virtual std::unique_ptr<AbstractTreeViewItemDropController> create_drop_controller() const;
- void begin_renaming();
- void end_renaming();
-
- AbstractTreeView &get_tree_view() const;
- int count_parents() const;
- void deactivate();
/**
- * Requires the tree to have completed reconstruction, see #is_reconstructed(). Otherwise we
- * can't be sure about the item state.
+ * Activates this item, deactivates other items, calls the #AbstractTreeViewItem::on_activate()
+ * function and ensures this item's parents are not collapsed (so the item is visible).
+ * Requires the tree to have completed reconstruction, see #is_reconstructed(). Otherwise the
+ * actual item state is unknown, possibly calling state-change update functions incorrectly.
*/
- bool is_active() const;
+ void activate();
+ void deactivate();
+
/**
* Can be called from the #AbstractTreeViewItem::build_row() implementation, but not earlier. The
* hovered state can't be queried reliably otherwise.
* Note that this does a linear lookup in the old block, so isn't too great performance-wise.
*/
bool is_hovered() const;
- void toggle_collapsed();
- /**
- * Requires the tree to have completed reconstruction, see #is_reconstructed(). Otherwise we
- * can't be sure about the item state.
- */
- bool is_collapsed() const;
- void set_collapsed(bool collapsed);
bool is_collapsible() const;
bool is_renaming() const;
void ensure_parents_uncollapsed();
- bool matches_including_parents(const AbstractTreeViewItem &other) const;
uiButTreeRow *tree_row_button();
- protected:
- /**
- * Activates this item, deactivates other items, calls the #AbstractTreeViewItem::on_activate()
- * function and ensures this item's parents are not collapsed (so the item is visible).
- * Requires the tree to have completed reconstruction, see #is_reconstructed(). Otherwise the
- * actual item state is unknown, possibly calling state-change update functions incorrectly.
- */
- void activate();
-
private:
static void rename_button_fn(bContext *, void *, char *);
static AbstractTreeViewItem *find_tree_item_from_rename_button(const uiBut &but);
@@ -338,13 +317,16 @@ class AbstractTreeViewItem : public TreeViewItemContainer {
/** See #AbstractTreeView::change_state_delayed() */
void change_state_delayed();
+ void end_renaming();
void add_treerow_button(uiBlock &block);
void add_indent(uiLayout &row) const;
void add_collapse_chevron(uiBlock &block) const;
void add_rename_button(uiLayout &row);
+ bool matches_including_parents(const AbstractTreeViewItem &other) const;
bool has_active_child() const;
+ int count_parents() const;
};
/** \} */
@@ -358,11 +340,18 @@ class AbstractTreeViewItem : public TreeViewItemContainer {
* custom implementation of #AbstractTreeViewItem::create_drag_controller().
*/
class AbstractTreeViewItemDragController {
+ protected:
+ AbstractTreeView &tree_view_;
+
public:
+ AbstractTreeViewItemDragController(AbstractTreeView &tree_view);
virtual ~AbstractTreeViewItemDragController() = default;
virtual int get_drag_type() const = 0;
virtual void *create_drag_data() const = 0;
+ virtual void on_drag_start();
+
+ template<class TreeViewType> inline TreeViewType &tree_view() const;
};
/**
@@ -398,7 +387,7 @@ class AbstractTreeViewItemDropController {
* Execute the logic to apply a drop of the data dragged with \a drag onto/into the item this
* controller is for.
*/
- virtual bool on_drop(const wmDrag &drag) = 0;
+ virtual bool on_drop(struct bContext *C, const wmDrag &drag) = 0;
template<class TreeViewType> inline TreeViewType &tree_view() const;
};
@@ -416,6 +405,7 @@ class AbstractTreeViewItemDropController {
*/
class BasicTreeViewItem : public AbstractTreeViewItem {
public:
+ using IsActiveFn = std::function<bool()>;
using ActivateFn = std::function<void(BasicTreeViewItem &new_active)>;
BIFIconID icon;
@@ -423,7 +413,11 @@ class BasicTreeViewItem : public AbstractTreeViewItem {
void build_row(uiLayout &row) override;
void add_label(uiLayout &layout, StringRefNull label_override = "");
- void on_activate(ActivateFn fn);
+ void set_on_activate_fn(ActivateFn fn);
+ /**
+ * Set a custom callback to check if this item should be active.
+ */
+ void set_is_active_fn(IsActiveFn fn);
protected:
/**
@@ -433,15 +427,33 @@ class BasicTreeViewItem : public AbstractTreeViewItem {
*/
ActivateFn activate_fn_;
+ IsActiveFn is_active_fn_;
+
private:
static void tree_row_click_fn(struct bContext *C, void *arg1, void *arg2);
+ std::optional<bool> should_be_active() const override;
void on_activate() override;
};
/** \} */
/* ---------------------------------------------------------------------- */
+/** \name Tree-View Builder
+ * \{ */
+
+class TreeViewBuilder {
+ uiBlock &block_;
+
+ public:
+ TreeViewBuilder(uiBlock &block);
+
+ void build_tree_view(AbstractTreeView &tree_view);
+};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
template<class ItemT, typename... Args>
inline ItemT &TreeViewItemContainer::add_tree_item(Args &&...args)
@@ -453,6 +465,13 @@ inline ItemT &TreeViewItemContainer::add_tree_item(Args &&...args)
add_tree_item(std::make_unique<ItemT>(std::forward<Args>(args)...)));
}
+template<class TreeViewType> TreeViewType &AbstractTreeViewItemDragController::tree_view() const
+{
+ static_assert(std::is_base_of<AbstractTreeView, TreeViewType>::value,
+ "Type must derive from and implement the AbstractTreeView interface");
+ return static_cast<TreeViewType &>(tree_view_);
+}
+
template<class TreeViewType> TreeViewType &AbstractTreeViewItemDropController::tree_view() const
{
static_assert(std::is_base_of<AbstractTreeView, TreeViewType>::value,
diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h
index 122e5a7d839..37246c2fe8f 100644
--- a/source/blender/editors/include/UI_view2d.h
+++ b/source/blender/editors/include/UI_view2d.h
@@ -118,21 +118,46 @@ typedef struct View2DScrollers View2DScrollers;
/* ----------------------------------------- */
/* Prototypes: */
-/* refresh and validation (of view rects) */
+/**
+ * Refresh and validation (of view rects).
+ *
+ * Initialize all relevant View2D data (including view rects if first time)
+ * and/or refresh mask sizes after view resize.
+ *
+ * - For some of these presets, it is expected that the region will have defined some
+ * additional settings necessary for the customization of the 2D viewport to its requirements
+ * - This function should only be called from region init() callbacks, where it is expected that
+ * this is called before #UI_view2d_size_update(),
+ * as this one checks that the rects are properly initialized.
+ */
void UI_view2d_region_reinit(struct View2D *v2d, short type, int winx, int winy);
void UI_view2d_curRect_validate(struct View2D *v2d);
+/**
+ * Restore 'cur' rect to standard orientation (i.e. optimal maximum view of tot).
+ * This does not take into account if zooming the view on an axis
+ * will improve the view (if allowed).
+ */
void UI_view2d_curRect_reset(struct View2D *v2d);
bool UI_view2d_area_supports_sync(struct ScrArea *area);
+/**
+ * Called by menus to activate it, or by view2d operators
+ * to make sure 'related' views stay in synchrony.
+ */
void UI_view2d_sync(struct bScreen *screen, struct ScrArea *area, struct View2D *v2dcur, int flag);
-/* Perform all required updates after `v2d->cur` as been modified.
+/**
+ * Perform all required updates after `v2d->cur` as been modified.
* This includes like validation view validation (#UI_view2d_curRect_validate).
*
- * Current intent is to use it from user code, such as view navigation and zoom operations. */
+ * Current intent is to use it from user code, such as view navigation and zoom operations.
+ */
void UI_view2d_curRect_changed(const struct bContext *C, struct View2D *v2d);
void UI_view2d_totRect_set(struct View2D *v2d, int width, int height);
+/**
+ * Change the size of the maximum viewable area (i.e. 'tot' rect).
+ */
void UI_view2d_totRect_set_resize(struct View2D *v2d, int width, int height, bool resize);
void UI_view2d_mask_from_win(const struct View2D *v2d, struct rcti *r_mask);
@@ -140,16 +165,40 @@ void UI_view2d_mask_from_win(const struct View2D *v2d, struct rcti *r_mask);
void UI_view2d_zoom_cache_reset(void);
/* view matrix operations */
+/**
+ * Set view matrices to use 'cur' rect as viewing frame for View2D drawing.
+ */
void UI_view2d_view_ortho(const struct View2D *v2d);
+/**
+ * Set view matrices to only use one axis of 'cur' only
+ *
+ * \param xaxis: if non-zero, only use cur x-axis,
+ * otherwise use cur-yaxis (mostly this will be used for x).
+ */
void UI_view2d_view_orthoSpecial(struct ARegion *region, struct View2D *v2d, const bool xaxis);
+/**
+ * Restore view matrices after drawing.
+ */
void UI_view2d_view_restore(const struct bContext *C);
/* grid drawing */
+
+/**
+ * Draw a multi-level grid in given 2d-region.
+ */
void UI_view2d_multi_grid_draw(
const struct View2D *v2d, int colorid, float step, int level_size, int totlevels);
+/**
+ * Draw a multi-level grid of dots, with a dynamic number of levels based on the fading.
+ *
+ * \param grid_color_id: The theme color used for the points. Faded dynamically based on zoom.
+ * \param min_step: The base size of the grid. At different zoom levels, the visible grid may have
+ * a larger step size.
+ * \param grid_levels: The maximum grid depth. Larger grid levels will subdivide the grid more.
+ */
void UI_view2d_dot_grid_draw(const struct View2D *v2d,
int grid_color_id,
- float step,
+ float min_step,
int grid_levels);
void UI_view2d_draw_lines_y__values(const struct View2D *v2d);
@@ -171,7 +220,9 @@ float UI_view2d_grid_resolution_x__frames_or_seconds(const struct View2D *v2d,
bool display_seconds);
float UI_view2d_grid_resolution_y__values(const struct View2D *v2d);
-/* scale indicator text drawing */
+/**
+ * Scale indicator text drawing.
+ */
void UI_view2d_draw_scale_y__values(const struct ARegion *region,
const struct View2D *v2d,
const struct rcti *rect,
@@ -193,25 +244,52 @@ void UI_view2d_draw_scale_x__frames_or_seconds(const struct ARegion *region,
bool display_seconds,
int colorid);
-/* scrollbar drawing */
+/* Scroll-bar drawing. */
+
+/**
+ * Calculate relevant scroller properties.
+ */
void UI_view2d_scrollers_calc(struct View2D *v2d,
const struct rcti *mask_custom,
struct View2DScrollers *r_scrollers);
+/**
+ * Draw scroll-bars in the given 2D-region.
+ */
void UI_view2d_scrollers_draw(struct View2D *v2d, const struct rcti *mask_custom);
-/* list view tools */
+/* List view tools. */
+
+/**
+ * Get the 'cell' (row, column) that the given 2D-view coordinates
+ * (i.e. in 'tot' rect space) lie in.
+ *
+ * \param columnwidth, rowheight: size of each 'cell'
+ * \param startx, starty: coordinates (in 'tot' rect space) that the list starts from.
+ * This should be (0,0) for most views. However, for those where the starting row was offsetted
+ * (like for Animation Editor channel lists, to make the first entry more visible), these will be
+ * the min-coordinates of the first item.
+ * \param viewx, viewy: 2D-coordinates (in 2D-view / 'tot' rect space) to get the cell for
+ * \param r_column, r_row: The 'coordinates' of the relevant 'cell'.
+ */
void UI_view2d_listview_view_to_cell(float columnwidth,
float rowheight,
float startx,
float starty,
float viewx,
float viewy,
- int *column,
- int *row);
+ int *r_column,
+ int *r_row);
+
+/* Coordinate conversion. */
-/* coordinate conversion */
float UI_view2d_region_to_view_x(const struct View2D *v2d, float x);
float UI_view2d_region_to_view_y(const struct View2D *v2d, float y);
+/**
+ * Convert from screen/region space to 2d-View space
+ *
+ * \param x, y: coordinates to convert
+ * \param r_view_x, r_view_y: resultant coordinates
+ */
void UI_view2d_region_to_view(
const struct View2D *v2d, float x, float y, float *r_view_x, float *r_view_y) ATTR_NONNULL();
void UI_view2d_region_to_view_rctf(const struct View2D *v2d,
@@ -220,9 +298,24 @@ void UI_view2d_region_to_view_rctf(const struct View2D *v2d,
float UI_view2d_view_to_region_x(const struct View2D *v2d, float x);
float UI_view2d_view_to_region_y(const struct View2D *v2d, float y);
+/**
+ * Convert from 2d-View space to screen/region space
+ * \note Coordinates are clamped to lie within bounds of region
+ *
+ * \param x, y: Coordinates to convert.
+ * \param r_region_x, r_region_y: Resultant coordinates.
+ */
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();
+/**
+ * Convert from 2d-view space to screen/region space
+ *
+ * \note Coordinates are NOT clamped to lie within bounds of region.
+ *
+ * \param x, y: Coordinates to convert.
+ * \param r_region_x, r_region_y: Resultant coordinates.
+ */
void UI_view2d_view_to_region(
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,
@@ -238,21 +331,64 @@ bool UI_view2d_view_to_region_rcti_clip(const struct View2D *v2d,
const struct rctf *rect_src,
struct rcti *rect_dst) ATTR_NONNULL();
-/* utilities */
+/* Utilities. */
+
+/**
+ * View2D data by default resides in region, so get from region stored in context.
+ */
struct View2D *UI_view2d_fromcontext(const struct bContext *C);
+/**
+ * Same as above, but it returns region-window. Utility for pull-downs or buttons.
+ */
struct View2D *UI_view2d_fromcontext_rwin(const struct bContext *C);
+/**
+ * Get scrollbar sizes of the current 2D view.
+ * The size will be zero if the view has its scrollbars disabled.
+ */
void UI_view2d_scroller_size_get(const struct View2D *v2d, float *r_x, float *r_y);
+/**
+ * Calculate the scale per-axis of the drawing-area
+ *
+ * Is used to inverse correct drawing of icons, etc. that need to follow view
+ * but not be affected by scale
+ *
+ * \param r_x, r_y: scale on each axis
+ */
void UI_view2d_scale_get(const 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);
+/**
+ * Same as `UI_view2d_scale_get() - 1.0f / x, y`.
+ */
void UI_view2d_scale_get_inverse(const struct 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(const struct View2D *v2d, float *r_x, float *r_y);
void UI_view2d_center_set(struct View2D *v2d, float x, float y);
+/**
+ * Simple pan function
+ * (0.0, 0.0) bottom left
+ * (0.5, 0.5) center
+ * (1.0, 1.0) top right.
+ */
void UI_view2d_offset(struct View2D *v2d, float xfac, float yfac);
+/**
+ * Check if mouse is within scrollers
+ *
+ * \param xy: Mouse coordinates in screen (not region) space.
+ * \param r_scroll: Return argument for the mapped view2d scroll flag.
+ *
+ * \return appropriate code for match.
+ * - 'h' = in horizontal scroller.
+ * - 'v' = in vertical scroller.
+ * - 0 = not in scroller.
+ */
char UI_view2d_mouse_in_scrollers_ex(const struct ARegion *region,
const struct View2D *v2d,
const int xy[2],
@@ -268,13 +404,18 @@ char UI_view2d_rect_in_scrollers(const struct ARegion *region,
const struct View2D *v2d,
const struct rcti *rect) ATTR_NONNULL(1, 2, 3);
-/* cached text drawing in v2d, to allow pixel-aligned draw as post process */
+/**
+ * Cached text drawing in v2d, to allow pixel-aligned draw as post process.
+ */
void UI_view2d_text_cache_add(struct View2D *v2d,
float x,
float y,
const char *str,
size_t str_len,
const unsigned char col[4]);
+/**
+ * No clip (yet).
+ */
void UI_view2d_text_cache_add_rectf(struct View2D *v2d,
const struct rctf *rect_view,
const char *str,
@@ -282,10 +423,15 @@ void UI_view2d_text_cache_add_rectf(struct View2D *v2d,
const unsigned char col[4]);
void UI_view2d_text_cache_draw(struct ARegion *region);
-/* operators */
+/* Operators. */
+
void ED_operatortypes_view2d(void);
void ED_keymap_view2d(struct wmKeyConfig *keyconf);
+/**
+ * Will start timer if appropriate.
+ * the arguments are the desired situation.
+ */
void UI_view2d_smooth_view(struct bContext *C,
struct ARegion *region,
const struct rctf *cur,
@@ -294,13 +440,16 @@ void UI_view2d_smooth_view(struct bContext *C,
#define UI_MARKER_MARGIN_Y (42 * UI_DPI_FAC)
#define UI_TIME_SCRUB_MARGIN_Y (23 * UI_DPI_FAC)
-/* Gizmo Types */
+/* Gizmo Types. */
/* view2d_gizmo_navigate.c */
-/* Caller passes in own idname. */
+
+/**
+ * Caller defines the name for gizmo group.
+ */
void VIEW2D_GGT_navigate_impl(struct wmGizmoGroupType *gzgt, const char *idname);
-/* Edge pan */
+/* Edge pan. */
/**
* Custom-data for view panning operators.
@@ -361,11 +510,15 @@ void UI_view2d_edge_pan_init(struct bContext *C,
void UI_view2d_edge_pan_reset(struct View2DEdgePanData *vpd);
-/* Apply transform to view (i.e. adjust 'cur' rect). */
+/**
+ * Apply transform to view (i.e. adjust 'cur' rect).
+ */
void UI_view2d_edge_pan_apply(struct bContext *C, struct View2DEdgePanData *vpd, const int xy[2])
ATTR_NONNULL(1, 2, 3);
-/* Apply transform to view using mouse events. */
+/**
+ * Apply transform to view using mouse events.
+ */
void UI_view2d_edge_pan_apply_event(struct bContext *C,
struct View2DEdgePanData *vpd,
const struct wmEvent *event);
@@ -382,7 +535,9 @@ void UI_view2d_edge_pan_operator_properties_ex(struct wmOperatorType *ot,
float delay,
float zoom_influence);
-/* Initialize panning data with operator settings. */
+/**
+ * Initialize panning data with operator settings.
+ */
void UI_view2d_edge_pan_operator_init(struct bContext *C,
struct View2DEdgePanData *vpd,
struct wmOperator *op);
diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt
index 2a8f40b2631..bc3075f9de8 100644
--- a/source/blender/editors/interface/CMakeLists.txt
+++ b/source/blender/editors/interface/CMakeLists.txt
@@ -73,7 +73,7 @@ set(SRC
interface_template_asset_view.cc
interface_template_list.cc
interface_template_attribute_search.cc
- interface_template_search_menu.c
+ interface_template_search_menu.cc
interface_template_search_operator.c
interface_templates.c
interface_undo.c
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index c59c2d5d517..df508b87ce4 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -25,7 +25,7 @@
#include <float.h>
#include <limits.h>
#include <math.h>
-#include <stddef.h> /* offsetof() */
+#include <stddef.h> /* `offsetof()` */
#include <string.h>
#include "MEM_guardedalloc.h"
@@ -37,6 +37,7 @@
#include "DNA_workspace_types.h"
#include "BLI_alloca.h"
+#include "BLI_ghash.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_rect.h"
@@ -201,7 +202,6 @@ float ui_block_to_window_scale(const ARegion *region, uiBlock *block)
return max_y - min_y;
}
-/* for mouse cursor */
void ui_window_to_block_fl(const ARegion *region, uiBlock *block, float *r_x, float *r_y)
{
const int getsizex = BLI_rcti_size_x(&region->winrct) + 1;
@@ -355,10 +355,6 @@ static void ui_update_window_matrix(const wmWindow *window, const ARegion *regio
}
}
-/**
- * Popups will add a margin to #ARegion.winrct for shadow,
- * for interactivity (point-inside tests for eg), we want the winrct without the margin added.
- */
void ui_region_winrct_get_no_margin(const struct ARegion *region, struct rcti *r_rect)
{
uiBlock *block = region->uiblocks.first;
@@ -599,7 +595,6 @@ static void ui_block_bounds_calc_popup(
}
}
-/* used for various cases */
void UI_block_bounds_set_normal(uiBlock *block, int addval)
{
if (block == NULL) {
@@ -610,14 +605,12 @@ void UI_block_bounds_set_normal(uiBlock *block, int addval)
block->bounds_type = UI_BLOCK_BOUNDS;
}
-/* Used for pull-downs. */
void UI_block_bounds_set_text(uiBlock *block, int addval)
{
block->bounds = addval;
block->bounds_type = UI_BLOCK_BOUNDS_TEXT;
}
-/* used for block popups */
void UI_block_bounds_set_popup(uiBlock *block, int addval, const int bounds_offset[2])
{
block->bounds = addval;
@@ -632,7 +625,6 @@ void UI_block_bounds_set_popup(uiBlock *block, int addval, const int bounds_offs
}
}
-/* used for menu popups */
void UI_block_bounds_set_menu(uiBlock *block, int addval, const int bounds_offset[2])
{
block->bounds = addval;
@@ -645,7 +637,6 @@ void UI_block_bounds_set_menu(uiBlock *block, int addval, const int bounds_offse
}
}
-/* used for centered popups, i.e. splash */
void UI_block_bounds_set_centered(uiBlock *block, int addval)
{
block->bounds = addval;
@@ -987,11 +978,6 @@ static bool ui_but_update_from_old_block(const bContext *C,
return found_active;
}
-/**
- * Needed for temporarily rename buttons, such as in outliner or file-select,
- * they should keep calling #uiDefBut to keep them alive.
- * \return false when button removed.
- */
bool UI_but_active_only_ex(
const bContext *C, ARegion *region, uiBlock *block, uiBut *but, const bool remove_on_failure)
{
@@ -1039,10 +1025,6 @@ bool UI_but_active_only(const bContext *C, ARegion *region, uiBlock *block, uiBu
return UI_but_active_only_ex(C, region, block, but, true);
}
-/**
- * \warning This must run after other handlers have been added,
- * otherwise the handler won't be removed, see: T71112.
- */
bool UI_block_active_only_flagged_buttons(const bContext *C, ARegion *region, uiBlock *block)
{
/* Running this command before end-block has run, means buttons that open menus
@@ -1073,7 +1055,6 @@ bool UI_block_active_only_flagged_buttons(const bContext *C, ARegion *region, ui
return done;
}
-/* simulate button click */
void UI_but_execute(const bContext *C, ARegion *region, uiBut *but)
{
void *active_back;
@@ -1186,9 +1167,6 @@ static void ui_menu_block_set_keyaccels(uiBlock *block)
}
}
-/* XXX, this code will shorten any allocated string to 'UI_MAX_NAME_STR'
- * since this is really long its unlikely to be an issue,
- * but this could be supported */
void ui_but_add_shortcut(uiBut *but, const char *shortcut_str, const bool do_strip)
{
if (do_strip && (but->flag & UI_BUT_HAS_SEP_CHAR)) {
@@ -1855,11 +1833,6 @@ static void ui_but_validate(const uiBut *but)
}
#endif
-/**
- * Check if the operator \a ot poll is successful with the context given by \a but (optionally).
- * \param but: The button that might store context. Can be NULL for convenience (e.g. if there is
- * no button to take context from, but we still want to poll the operator).
- */
bool ui_but_context_poll_operator_ex(bContext *C,
const uiBut *but,
const wmOperatorCallParams *optype_params)
@@ -2015,7 +1988,6 @@ static bool ui_but_pixelrect_in_view(const ARegion *region, const rcti *rect)
return BLI_rcti_isect(&region->winrct, &rect_winspace, NULL);
}
-/* uses local copy of style, to scale things down, and allow widgets to change stuff */
void UI_block_draw(const bContext *C, uiBlock *block)
{
uiStyle style = *UI_style_get_dpi(); /* XXX pass on as arg */
@@ -2061,24 +2033,11 @@ void UI_block_draw(const bContext *C, uiBlock *block)
ui_draw_menu_back(&style, block, &rect);
}
else if (block->panel) {
- bool show_background = region->alignment != RGN_ALIGN_FLOAT;
- if (show_background) {
- if (block->panel->type && (block->panel->type->flag & PANEL_TYPE_NO_HEADER)) {
- if (region->regiontype == RGN_TYPE_TOOLS) {
- /* We never want a background around active tools. */
- show_background = false;
- }
- else {
- /* Without a header there is no background except for region overlap. */
- show_background = region->overlap != 0;
- }
- }
- }
ui_draw_aligned_panel(&style,
block,
&rect,
UI_panel_category_is_visible(region),
- show_background,
+ UI_panel_should_show_background(region, block->panel->type),
region->flag & RGN_FLAG_SEARCH_FILTER_ACTIVE);
}
@@ -2150,11 +2109,6 @@ void UI_region_message_subscribe(ARegion *region, struct wmMsgBus *mbus)
/* ************* EVENTS ************* */
-/**
- * Check if the button is pushed, this is only meaningful for some button types.
- *
- * \return (0 == UNSELECT), (1 == SELECT), (-1 == DO-NOTHING)
- */
int ui_but_is_pushed_ex(uiBut *but, double *value)
{
int is_push = 0;
@@ -2290,7 +2244,6 @@ void UI_block_lock_clear(uiBlock *block)
* this either works with the pointed to data, or can work with
* an edit override pointer while dragging for example */
-/* for buttons pointing to color for example */
void ui_but_v3_get(uiBut *but, float vec[3])
{
if (but->editvec) {
@@ -2338,7 +2291,6 @@ void ui_but_v3_get(uiBut *but, float vec[3])
}
}
-/* for buttons pointing to color for example */
void ui_but_v3_set(uiBut *but, const float vec[3])
{
if (but->editvec) {
@@ -2450,9 +2402,6 @@ bool ui_but_is_unit(const uiBut *but)
return true;
}
-/**
- * Check if this button is similar enough to be grouped with another.
- */
bool ui_but_is_compatible(const uiBut *but_a, const uiBut *but_b)
{
if (but_a->type != but_b->type) {
@@ -2488,9 +2437,6 @@ bool ui_but_is_rna_valid(uiBut *but)
return false;
}
-/**
- * Checks if the button supports cycling next/previous menu items (ctrl+mouse-wheel).
- */
bool ui_but_supports_cycling(const uiBut *but)
{
return (ELEM(but->type, UI_BTYPE_ROW, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER, UI_BTYPE_LISTBOX) ||
@@ -2697,7 +2643,6 @@ static double ui_get_but_scale_unit(uiBut *but, double value)
return BKE_scene_unit_scale(unit, RNA_SUBTYPE_UNIT_VALUE(unit_type), value);
}
-/* str will be overwritten */
void ui_but_convert_to_unit_alt_name(uiBut *but, char *str, size_t maxlen)
{
if (!ui_but_is_unit(but)) {
@@ -2789,12 +2734,6 @@ static float ui_get_but_step_unit(uiBut *but, float step_default)
return (float)step_final;
}
-/**
- * \param float_precision: For number buttons the precision
- * to use or -1 to fallback to the button default.
- * \param use_exp_float: Use exponent representation of floats
- * when out of reasonable range (outside of 1e3/1e-3).
- */
void ui_but_string_get_ex(uiBut *but,
char *str,
const size_t maxlen,
@@ -2920,12 +2859,6 @@ void ui_but_string_get(uiBut *but, char *str, const size_t maxlen)
ui_but_string_get_ex(but, str, maxlen, -1, false, NULL);
}
-/**
- * A version of #ui_but_string_get_ex for dynamic buffer sizes
- * (where #ui_but_string_get_max_length returns 0).
- *
- * \param r_str_size: size of the returned string (including terminator).
- */
char *ui_but_string_get_dynamic(uiBut *but, int *r_str_size)
{
char *str = NULL;
@@ -3284,9 +3217,10 @@ void ui_but_range_set_hard(uiBut *but)
}
}
-/* NOTE: this could be split up into functions which handle arrays and not. */
void ui_but_range_set_soft(uiBut *but)
{
+ /* This could be split up into functions which handle arrays and not. */
+
/* Ideally we would not limit this, but practically it's more than
* enough. Worst case is very long vectors won't use a smart soft-range,
* which isn't so bad. */
@@ -3461,7 +3395,6 @@ static void ui_but_free(const bContext *C, uiBut *but)
MEM_freeN(but);
}
-/* can be called with C==NULL */
void UI_block_free(const bContext *C, uiBlock *block)
{
UI_butstore_clear(block);
@@ -3520,23 +3453,35 @@ void UI_blocklist_draw(const bContext *C, const ListBase *lb)
}
}
-/* can be called with C==NULL */
-void UI_blocklist_free(const bContext *C, ListBase *lb)
+void UI_blocklist_free(const bContext *C, ARegion *region)
{
+ ListBase *lb = &region->uiblocks;
uiBlock *block;
while ((block = BLI_pophead(lb))) {
UI_block_free(C, block);
}
+ if (region->runtime.block_name_map != NULL) {
+ BLI_ghash_free(region->runtime.block_name_map, NULL, NULL);
+ region->runtime.block_name_map = NULL;
+ }
}
-void UI_blocklist_free_inactive(const bContext *C, ListBase *lb)
+void UI_blocklist_free_inactive(const bContext *C, ARegion *region)
{
+ ListBase *lb = &region->uiblocks;
+
LISTBASE_FOREACH_MUTABLE (uiBlock *, block, lb) {
if (!block->handle) {
if (block->active) {
block->active = false;
}
else {
+ if (region->runtime.block_name_map != NULL) {
+ uiBlock *b = BLI_ghash_lookup(region->runtime.block_name_map, block->name);
+ if (b == block) {
+ BLI_ghash_remove(region->runtime.block_name_map, b->name, NULL, NULL);
+ }
+ }
BLI_remlink(lb, block);
UI_block_free(C, block);
}
@@ -3552,7 +3497,10 @@ void UI_block_region_set(uiBlock *block, ARegion *region)
/* each listbase only has one block with this name, free block
* if is already there so it can be rebuilt from scratch */
if (lb) {
- oldblock = BLI_findstring(lb, block->name, offsetof(uiBlock, name));
+ if (region->runtime.block_name_map == NULL) {
+ region->runtime.block_name_map = BLI_ghash_str_new(__func__);
+ }
+ oldblock = (uiBlock *)BLI_ghash_lookup(region->runtime.block_name_map, block->name);
if (oldblock) {
oldblock->active = false;
@@ -3562,6 +3510,7 @@ void UI_block_region_set(uiBlock *block, ARegion *region)
/* at the beginning of the list! for dynamical menus/blocks */
BLI_addhead(lb, block);
+ BLI_ghash_reinsert(region->runtime.block_name_map, block->name, block, NULL, NULL);
}
block->oldblock = oldblock;
@@ -3633,10 +3582,6 @@ bool UI_block_is_search_only(const uiBlock *block)
return block->flag & UI_BLOCK_SEARCH_ONLY;
}
-/**
- * Use when a block must be searched to give accurate results
- * for the whole region but shouldn't be displayed.
- */
void UI_block_set_search_only(uiBlock *block, bool search_only)
{
SET_FLAG_FROM_TEST(block->flag, search_only, UI_BLOCK_SEARCH_ONLY);
@@ -3977,10 +3922,6 @@ static void ui_but_alloc_info(const eButType type,
alloc_size = sizeof(uiButCurveProfile);
alloc_str = "uiButCurveProfile";
break;
- case UI_BTYPE_DATASETROW:
- alloc_size = sizeof(uiButDatasetRow);
- alloc_str = "uiButDatasetRow";
- break;
case UI_BTYPE_TREEROW:
alloc_size = sizeof(uiButTreeRow);
alloc_str = "uiButTreeRow";
@@ -4012,13 +3953,6 @@ static uiBut *ui_but_alloc(const eButType type)
return MEM_callocN(alloc_size, alloc_str);
}
-/**
- * Reallocate the button (new address is returned) for a new button type.
- * This should generally be avoided and instead the correct type be created right away.
- *
- * \note Only the #uiBut data can be kept. If the old button used a derived type (e.g. #uiButTab),
- * the data that is not inside #uiBut will be lost.
- */
uiBut *ui_but_change_type(uiBut *but, eButType new_type)
{
if (but->type == new_type) {
@@ -4183,7 +4117,6 @@ static uiBut *ui_def_but(uiBlock *block,
UI_BTYPE_BLOCK,
UI_BTYPE_BUT_MENU,
UI_BTYPE_SEARCH_MENU,
- UI_BTYPE_DATASETROW,
UI_BTYPE_TREEROW,
UI_BTYPE_POPOVER)) {
but->drawflag |= (UI_BUT_TEXT_LEFT | UI_BUT_ICON_LEFT);
@@ -4253,9 +4186,6 @@ void ui_def_but_icon(uiBut *but, const int icon, const int flag)
}
}
-/**
- * Avoid using this where possible since it's better not to ask for an icon in the first place.
- */
void ui_def_but_icon_clear(uiBut *but)
{
but->icon = ICON_NONE;
@@ -5309,7 +5239,6 @@ uiBut *uiDefButO(uiBlock *block,
return uiDefButO_ptr(block, type, ot, opcontext, str, x, y, width, height, tip);
}
-/* if a1==1.0 then a2 is an extra icon blending factor (alpha 0.0 - 1.0) */
uiBut *uiDefIconBut(uiBlock *block,
int type,
int retval,
@@ -5689,7 +5618,6 @@ uiBut *uiDefIconButO(uiBlock *block,
return uiDefIconButO_ptr(block, type, ot, opcontext, icon, x, y, width, height, tip);
}
-/* Button containing both string label and icon */
uiBut *uiDefIconTextBut(uiBlock *block,
int type,
int retval,
@@ -6120,7 +6048,6 @@ void UI_block_direction_set(uiBlock *block, char direction)
block->direction = direction;
}
-/* this call escapes if there's alignment flags */
void UI_block_order_flip(uiBlock *block)
{
float centy, miny = 10000, maxy = -10000;
@@ -6224,19 +6151,12 @@ void UI_but_drag_set_id(uiBut *but, ID *id)
but->dragpoin = (void *)id;
}
-/**
- * Set an image to display while dragging. This works for any drag type (`WM_DRAG_XXX`).
- * Not to be confused with #UI_but_drag_set_image(), which sets up dragging of an image.
- */
void UI_but_drag_attach_image(uiBut *but, struct ImBuf *imb, const float scale)
{
but->imb = imb;
but->imb_scale = scale;
}
-/**
- * \param asset: May be passed from a temporary variable, drag data only stores a copy of this.
- */
void UI_but_drag_set_asset(uiBut *but,
const AssetHandle *asset,
const char *path,
@@ -6298,7 +6218,6 @@ void UI_but_drag_set_name(uiBut *but, const char *name)
but->dragpoin = (void *)name;
}
-/* value from button itself */
void UI_but_drag_set_value(uiBut *but)
{
but->dragtype = WM_DRAG_VALUE;
@@ -6561,7 +6480,6 @@ uiBut *uiDefIconMenuBut(uiBlock *block,
return but;
}
-/* Block button containing both string label and icon */
uiBut *uiDefIconTextBlockBut(uiBlock *block,
uiBlockCreateFunc func,
void *arg,
@@ -6590,7 +6508,6 @@ uiBut *uiDefIconTextBlockBut(uiBlock *block,
return but;
}
-/* Block button containing icon */
uiBut *uiDefIconBlockBut(uiBlock *block,
uiBlockCreateFunc func,
void *arg,
@@ -6643,8 +6560,6 @@ uiBut *uiDefKeyevtButS(uiBlock *block,
return but;
}
-/* short pointers hardcoded */
-/* modkeypoin will be set to KM_SHIFT, KM_ALT, KM_CTRL, KM_OSKEY bits */
uiBut *uiDefHotKeyevtButS(uiBlock *block,
int retval,
const char *str,
@@ -6675,8 +6590,6 @@ uiBut *uiDefHotKeyevtButS(uiBlock *block,
return but;
}
-/* arg is pointer to string/name, use UI_but_func_search_set() below to make this work */
-/* here a1 and a2, if set, control thumbnail preview rows/cols */
uiBut *uiDefSearchBut(uiBlock *block,
void *arg,
int retval,
@@ -6702,21 +6615,6 @@ uiBut *uiDefSearchBut(uiBlock *block,
return but;
}
-/**
- * \note The item-pointer (referred to below) is a per search item user pointer
- * passed to #UI_search_item_add (stored in #uiSearchItems.pointers).
- *
- * \param search_create_fn: Function to create the menu.
- * \param search_update_fn: Function to refresh search content after the search text has changed.
- * \param arg: user value.
- * \param free_arg: Set to true if the argument is newly allocated memory for every redraw and
- * should be freed when the button is destroyed.
- * \param search_arg_free_fn: When non-null, use this function to free \a arg.
- * \param search_exec_fn: Function that executes the action, gets \a arg as the first argument.
- * The second argument as the active item-pointer
- * \param active: When non-null, this item-pointer item will be visible and selected,
- * otherwise the first item will be selected.
- */
void UI_but_func_search_set(uiBut *but,
uiButSearchCreateFn search_create_fn,
uiButSearchUpdateFn search_update_fn,
@@ -6783,10 +6681,6 @@ void UI_but_func_search_set_context_menu(uiBut *but, uiButSearchContextMenuFn co
but_search->item_context_menu_fn = context_menu_fn;
}
-/**
- * \param search_sep_string: when not NULL, this string is used as a separator,
- * showing the icon and highlighted text after the last instance of this string.
- */
void UI_but_func_search_set_sep_string(uiBut *but, const char *search_sep_string)
{
uiButSearch *but_search = (uiButSearch *)but;
@@ -6839,7 +6733,7 @@ static void operator_enum_search_update_fn(const struct bContext *C,
StringSearch *search = BLI_string_search_new();
for (const EnumPropertyItem *item = all_items; item->identifier; item++) {
- BLI_string_search_add(search, item->name, (void *)item);
+ BLI_string_search_add(search, item->name, (void *)item, 0);
}
const EnumPropertyItem **filtered_items;
@@ -6883,10 +6777,6 @@ static void operator_enum_search_exec_fn(struct bContext *UNUSED(C), void *but,
}
}
-/**
- * Same parameters as for uiDefSearchBut, with additional operator type and properties,
- * used by callback to call again the right op with the right options (properties values).
- */
uiBut *uiDefSearchButO_ptr(uiBlock *block,
wmOperatorType *ot,
IDProperty *properties,
@@ -6924,15 +6814,6 @@ uiBut *uiDefSearchButO_ptr(uiBlock *block,
return but;
}
-void UI_but_datasetrow_indentation_set(uiBut *but, int indentation)
-{
- uiButDatasetRow *but_dataset = (uiButDatasetRow *)but;
- BLI_assert(but->type == UI_BTYPE_DATASETROW);
-
- but_dataset->indentation = indentation;
- BLI_assert(indentation >= 0);
-}
-
void UI_but_treerow_indentation_set(uiBut *but, int indentation)
{
uiButTreeRow *but_row = (uiButTreeRow *)but;
@@ -6942,46 +6823,11 @@ void UI_but_treerow_indentation_set(uiBut *but, int indentation)
BLI_assert(indentation >= 0);
}
-/**
- * Adds a hint to the button which draws right aligned, grayed out and never clipped.
- */
void UI_but_hint_drawstr_set(uiBut *but, const char *string)
{
ui_but_add_shortcut(but, string, false);
}
-void UI_but_datasetrow_component_set(uiBut *but, uint8_t geometry_component_type)
-{
- uiButDatasetRow *but_dataset_row = (uiButDatasetRow *)but;
- BLI_assert(but->type == UI_BTYPE_DATASETROW);
-
- but_dataset_row->geometry_component_type = geometry_component_type;
-}
-
-void UI_but_datasetrow_domain_set(uiBut *but, uint8_t attribute_domain)
-{
- uiButDatasetRow *but_dataset_row = (uiButDatasetRow *)but;
- BLI_assert(but->type == UI_BTYPE_DATASETROW);
-
- but_dataset_row->attribute_domain = attribute_domain;
-}
-
-uint8_t UI_but_datasetrow_component_get(uiBut *but)
-{
- uiButDatasetRow *but_dataset_row = (uiButDatasetRow *)but;
- BLI_assert(but->type == UI_BTYPE_DATASETROW);
-
- return but_dataset_row->geometry_component_type;
-}
-
-uint8_t UI_but_datasetrow_domain_get(uiBut *but)
-{
- uiButDatasetRow *but_dataset_row = (uiButDatasetRow *)but;
- BLI_assert(but->type == UI_BTYPE_DATASETROW);
-
- return but_dataset_row->attribute_domain;
-}
-
void UI_but_node_link_set(uiBut *but, bNodeSocket *socket, const float draw_color[4])
{
but->flag |= UI_BUT_NODE_LINK;
@@ -7008,10 +6854,6 @@ void UI_but_number_precision_set(uiBut *but, float precision)
BLI_assert(precision > -2);
}
-/**
- * push a new event onto event queue to activate the given button
- * (usually a text-field) upon entering a popup
- */
void UI_but_focus_on_enter_event(wmWindow *win, uiBut *but)
{
wmEvent event;
@@ -7314,7 +7156,6 @@ void UI_init(void)
ui_resources_init();
}
-/* after reading userdef file */
void UI_init_userdef(void)
{
/* Initialize UI variables from values set in the preferences. */
diff --git a/source/blender/editors/interface/interface_align.c b/source/blender/editors/interface/interface_align.c
index 3149675ac04..35af557a560 100644
--- a/source/blender/editors/interface/interface_align.c
+++ b/source/blender/editors/interface/interface_align.c
@@ -377,13 +377,6 @@ static void ui_block_align_but_to_region(uiBut *but, const ARegion *region)
}
}
-/**
- * Compute the alignment of all 'align groups' of buttons in given block.
- *
- * This is using an order-independent algorithm,
- * i.e. alignment of buttons should be OK regardless of order in which
- * they are added to the block.
- */
void ui_block_align_calc(uiBlock *block, const ARegion *region)
{
int num_buttons = 0;
diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c
index 3101b3222c4..1d6623f3490 100644
--- a/source/blender/editors/interface/interface_anim.c
+++ b/source/blender/editors/interface/interface_anim.c
@@ -180,10 +180,6 @@ void ui_but_anim_decorate_update_from_flag(uiButDecorator *decorator_but)
but->flag = (but->flag & ~flag_copy) | (flag & flag_copy);
}
-/**
- * \a str can be NULL to only perform check if \a but has an expression at all.
- * \return if button has an expression.
- */
bool ui_but_anim_expression_get(uiBut *but, char *str, size_t maxlen)
{
FCurve *fcu;
@@ -241,7 +237,6 @@ bool ui_but_anim_expression_set(uiBut *but, const char *str)
return false;
}
-/* create new expression for button (i.e. a "scripted driver"), if it can be created... */
bool ui_but_anim_expression_create(uiBut *but, const char *str)
{
bContext *C = but->block->evil_C;
diff --git a/source/blender/editors/interface/interface_button_group.c b/source/blender/editors/interface/interface_button_group.c
index 7054498d469..6449e1eb329 100644
--- a/source/blender/editors/interface/interface_button_group.c
+++ b/source/blender/editors/interface/interface_button_group.c
@@ -28,10 +28,6 @@
/** \name Button Groups
* \{ */
-/**
- * Every function that adds a set of buttons must create another group,
- * then #ui_def_but adds buttons to the current group (the last).
- */
void ui_block_new_button_group(uiBlock *block, uiButtonGroupFlag flag)
{
/* Don't create a new group if there is a "lock" on new groups. */
diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c
index 72e7203c6ea..190b2d12ed9 100644
--- a/source/blender/editors/interface/interface_context_menu.c
+++ b/source/blender/editors/interface/interface_context_menu.c
@@ -1242,9 +1242,6 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but, const wmEvent *ev
/** \name Panel Context Menu
* \{ */
-/**
- * menu to show when right clicking on the panel header
- */
void ui_popup_context_menu_for_panel(bContext *C, ARegion *region, Panel *panel)
{
bScreen *screen = CTX_wm_screen(C);
diff --git a/source/blender/editors/interface/interface_context_path.cc b/source/blender/editors/interface/interface_context_path.cc
index 3f5efd187d8..0b774b79a5c 100644
--- a/source/blender/editors/interface/interface_context_path.cc
+++ b/source/blender/editors/interface/interface_context_path.cc
@@ -80,6 +80,6 @@ void template_breadcrumbs(uiLayout &layout, Span<ContextPathItem> context_path)
}
}
-} // namespace blender::ui
-
/** \} */
+
+} // namespace blender::ui
diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c
index e45a5fc61c6..285c82b0fb3 100644
--- a/source/blender/editors/interface/interface_draw.c
+++ b/source/blender/editors/interface/interface_draw.c
@@ -194,8 +194,6 @@ void UI_draw_text_underline(int pos_x, int pos_y, int len, int height, const flo
/* ************** SPECIAL BUTTON DRAWING FUNCTIONS ************* */
-/* based on UI_draw_roundbox_gl_mode,
- * check on making a version which allows us to skip some sides */
void ui_draw_but_TAB_outline(const rcti *rect,
float rad,
uchar highlight[3],
@@ -348,14 +346,6 @@ void ui_draw_but_IMAGE(ARegion *UNUSED(region),
#endif
}
-/**
- * Draw title and text safe areas.
- *
- * \note This function is to be used with the 2D dashed shader enabled.
- *
- * \param pos: is a #PRIM_FLOAT, 2, #GPU_FETCH_FLOAT vertex attribute.
- * \param x1, x2, y1, y2: The offsets for the view, not the zones.
- */
void UI_draw_safe_areas(uint pos,
const rctf *rect,
const float title_aspect[2],
@@ -1351,7 +1341,10 @@ void ui_draw_but_COLORBAND(uiBut *but, const uiWidgetColors *UNUSED(wcol), const
immUnbindProgram();
}
-void ui_draw_but_UNITVEC(uiBut *but, const uiWidgetColors *wcol, const rcti *rect)
+void ui_draw_but_UNITVEC(uiBut *but,
+ const uiWidgetColors *wcol,
+ const rcti *rect,
+ const float radius)
{
/* sphere color */
const float diffuse[3] = {1.0f, 1.0f, 1.0f};
@@ -1368,7 +1361,7 @@ void ui_draw_but_UNITVEC(uiBut *but, const uiWidgetColors *wcol, const rcti *rec
.ymax = rect->ymax,
},
true,
- 5.0f,
+ radius,
wcol->inner,
255);
@@ -1750,9 +1743,6 @@ static bool point_draw_handles(CurveProfilePoint *point)
ELEM(point->flag, PROF_H1_SELECT, PROF_H2_SELECT);
}
-/**
- * Draws the curve profile widget. Somewhat similar to ui_draw_but_CURVE.
- */
void ui_draw_but_CURVEPROFILE(ARegion *region,
uiBut *but,
const uiWidgetColors *wcol,
diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c
index 395ecc77ef4..27fa2e5a22f 100644
--- a/source/blender/editors/interface/interface_eyedropper.c
+++ b/source/blender/editors/interface/interface_eyedropper.c
@@ -103,8 +103,10 @@ wmKeyMap *eyedropper_colorband_modal_keymap(wmKeyConfig *keyconf)
/* -------------------------------------------------------------------- */
/* Utility Functions
*/
+
/** \name Generic Shared Functions
* \{ */
+
static void eyedropper_draw_cursor_text_ex(const int x, const int y, const char *name)
{
const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
@@ -141,15 +143,6 @@ void eyedropper_draw_cursor_text_region(const int x, const int y, const char *na
eyedropper_draw_cursor_text_ex(x, y, name);
}
-/**
- * Utility to retrieve a button representing a RNA property that is currently under the cursor.
- *
- * This is to be used by any eyedroppers which fetch properties (e.g. UI_OT_eyedropper_driver).
- * Especially during modal operations (e.g. as with the eyedroppers), context cannot be relied
- * upon to provide this information, as it is not updated until the operator finishes.
- *
- * \return A button under the mouse which relates to some RNA Property, or NULL
- */
uiBut *eyedropper_get_property_button_under_mouse(bContext *C, const wmEvent *event)
{
bScreen *screen = CTX_wm_screen(C);
diff --git a/source/blender/editors/interface/interface_eyedropper_color.c b/source/blender/editors/interface/interface_eyedropper_color.c
index c3633e11f83..0ac6ea4021b 100644
--- a/source/blender/editors/interface/interface_eyedropper_color.c
+++ b/source/blender/editors/interface/interface_eyedropper_color.c
@@ -268,28 +268,28 @@ static bool eyedropper_cryptomatte_sample_fl(
return false;
}
- ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
- if (!ar) {
+ ARegion *region = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
+ if (!region) {
return false;
}
- int mval[2] = {mx - ar->winrct.xmin, my - ar->winrct.ymin};
+ int mval[2] = {mx - region->winrct.xmin, my - region->winrct.ymin};
float fpos[2] = {-1.0f, -1.0};
switch (sa->spacetype) {
case SPACE_IMAGE: {
SpaceImage *sima = sa->spacedata.first;
- ED_space_image_get_position(sima, ar, mval, fpos);
+ ED_space_image_get_position(sima, region, mval, fpos);
break;
}
case SPACE_NODE: {
Main *bmain = CTX_data_main(C);
SpaceNode *snode = sa->spacedata.first;
- ED_space_node_get_position(bmain, snode, ar, mval, fpos);
+ ED_space_node_get_position(bmain, snode, region, mval, fpos);
break;
}
case SPACE_CLIP: {
SpaceClip *sc = sa->spacedata.first;
- ED_space_clip_get_position(sc, ar, mval, fpos);
+ ED_space_clip_get_position(sc, region, mval, fpos);
break;
}
default: {
@@ -322,13 +322,6 @@ static bool eyedropper_cryptomatte_sample_fl(
return false;
}
-/**
- * \brief get the color from the screen.
- *
- * Special check for image or nodes where we MAY have HDR pixels which don't display.
- *
- * \note Exposed by 'interface_eyedropper_intern.h' for use with color band picking.
- */
void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3])
{
/* we could use some clever */
diff --git a/source/blender/editors/interface/interface_eyedropper_intern.h b/source/blender/editors/interface/interface_eyedropper_intern.h
index f9f3fcfb5d1..17bb78a7861 100644
--- a/source/blender/editors/interface/interface_eyedropper_intern.h
+++ b/source/blender/editors/interface/interface_eyedropper_intern.h
@@ -23,8 +23,18 @@
#pragma once
/* interface_eyedropper.c */
+
void eyedropper_draw_cursor_text_window(const struct wmWindow *window, const char *name);
void eyedropper_draw_cursor_text_region(const int x, const int y, const char *name);
+/**
+ * Utility to retrieve a button representing a RNA property that is currently under the cursor.
+ *
+ * This is to be used by any eyedroppers which fetch properties (e.g. UI_OT_eyedropper_driver).
+ * Especially during modal operations (e.g. as with the eyedroppers), context cannot be relied
+ * upon to provide this information, as it is not updated until the operator finishes.
+ *
+ * \return A button under the mouse which relates to some RNA Property, or NULL
+ */
uiBut *eyedropper_get_property_button_under_mouse(bContext *C, const wmEvent *event);
void datadropper_win_area_find(const struct bContext *C,
const int mval[2],
@@ -33,6 +43,14 @@ void datadropper_win_area_find(const struct bContext *C,
struct ScrArea **r_area);
/* interface_eyedropper_color.c (expose for color-band picker) */
+
+/**
+ * \brief get the color from the screen.
+ *
+ * Special check for image or nodes where we MAY have HDR pixels which don't display.
+ *
+ * \note Exposed by 'interface_eyedropper_intern.h' for use with color band picking.
+ */
void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3]);
/* Used for most eye-dropper operators. */
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 8a744a1edbe..d720b52a59e 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -439,11 +439,11 @@ typedef struct uiHandleButtonData {
float ungrab_mval[2];
#endif
- /* menu open (watch UI_screen_free_active_but) */
+ /* Menu open, see: #UI_screen_free_active_but_highlight. */
uiPopupBlockHandle *menu;
int menuretval;
- /* search box (watch UI_screen_free_active_but) */
+ /* Search box see: #UI_screen_free_active_but_highlight. */
ARegion *searchbox;
#ifdef USE_KEYNAV_LIMIT
struct uiKeyNavLock searchbox_keynav_state;
@@ -555,7 +555,6 @@ bool ui_but_is_editing(const uiBut *but)
return (data && ELEM(data->state, BUTTON_STATE_TEXT_EDITING, BUTTON_STATE_NUM_EDITING));
}
-/* assumes event type is MOUSEPAN */
void ui_pan_to_scroll(const wmEvent *event, int *type, int *val)
{
static int lastdy = 0;
@@ -594,11 +593,6 @@ static bool ui_but_find_select_in_enum__cmp(const uiBut *but_a, const uiBut *but
(but_a->rnaprop == but_b->rnaprop));
}
-/**
- * Finds the pressed button in an aligned row (typically an expanded enum).
- *
- * \param direction: Use when there may be multiple buttons pressed.
- */
uiBut *ui_but_find_select_in_enum(uiBut *but, int direction)
{
uiBut *but_iter = but;
@@ -1266,12 +1260,22 @@ static void ui_apply_but_TAB(bContext *C, uiBut *but, uiHandleButtonData *data)
static void ui_apply_but_NUM(bContext *C, uiBut *but, uiHandleButtonData *data)
{
if (data->str) {
+ /* This is intended to avoid unnecessary updates when the value stays the same, however there
+ * are issues with the current implementation. It does not work with multi-button editing
+ * (T89996) or operator popups where a number button requires an update even if the value is
+ * unchanged (T89996).
+ *
+ * Trying to detect changes at this level is not reliable. Instead it could be done at the
+ * level of RNA update/set, skipping RNA update if RNA set did not change anything, instead
+ * of skipping all button updates. */
+#if 0
double value;
/* Check if the string value is a number and cancel if it's equal to the startvalue. */
if (ui_but_string_eval_number(C, but, data->str, &value) && (value == data->startvalue)) {
data->cancel = true;
return;
}
+#endif
if (ui_but_string_set(C, but, data->str)) {
data->value = ui_but_value_get(but);
@@ -1783,7 +1787,7 @@ static bool ui_but_is_drag_toggle(const uiBut *but)
static bool ui_selectcontext_begin(bContext *C, uiBut *but, uiSelectContextStore *selctx_data)
{
- PointerRNA lptr, idptr;
+ PointerRNA lptr;
PropertyRNA *lprop;
bool success = false;
@@ -1817,68 +1821,48 @@ static bool ui_selectcontext_begin(bContext *C, uiBut *but, uiSelectContextStore
if (i >= selctx_data->elems_len) {
break;
}
+
+ if (!UI_context_copy_to_selected_check(
+ &ptr, &link->ptr, prop, path, use_path_from_id, &lptr, &lprop)) {
+ selctx_data->elems_len -= 1;
+ i -= 1;
+ continue;
+ }
+
uiSelectContextElem *other = &selctx_data->elems[i];
- /* TODO: de-duplicate copy_to_selected_button. */
- if (link->ptr.data != ptr.data) {
- if (use_path_from_id) {
- /* Path relative to ID. */
- lprop = NULL;
- RNA_id_pointer_create(link->ptr.owner_id, &idptr);
- RNA_path_resolve_property(&idptr, path, &lptr, &lprop);
- }
- else if (path) {
- /* Path relative to elements from list. */
- lprop = NULL;
- RNA_path_resolve_property(&link->ptr, path, &lptr, &lprop);
+ other->ptr = lptr;
+ if (is_array) {
+ if (rna_type == PROP_FLOAT) {
+ other->val_f = RNA_property_float_get_index(&lptr, lprop, index);
}
- else {
- lptr = link->ptr;
- lprop = prop;
+ else if (rna_type == PROP_INT) {
+ other->val_i = RNA_property_int_get_index(&lptr, lprop, index);
}
-
- /* lptr might not be the same as link->ptr! */
- if ((lptr.data != ptr.data) && (lprop == prop) && RNA_property_editable(&lptr, lprop)) {
- other->ptr = lptr;
- if (is_array) {
- if (rna_type == PROP_FLOAT) {
- other->val_f = RNA_property_float_get_index(&lptr, lprop, index);
- }
- else if (rna_type == PROP_INT) {
- other->val_i = RNA_property_int_get_index(&lptr, lprop, index);
- }
- /* ignored for now */
+ /* ignored for now */
# if 0
- else if (rna_type == PROP_BOOLEAN) {
- other->val_b = RNA_property_boolean_get_index(&lptr, lprop, index);
- }
-# endif
+ else if (rna_type == PROP_BOOLEAN) {
+ other->val_b = RNA_property_boolean_get_index(&lptr, lprop, index);
}
- else {
- if (rna_type == PROP_FLOAT) {
- other->val_f = RNA_property_float_get(&lptr, lprop);
- }
- else if (rna_type == PROP_INT) {
- other->val_i = RNA_property_int_get(&lptr, lprop);
- }
- /* ignored for now */
-# if 0
- else if (rna_type == PROP_BOOLEAN) {
- other->val_b = RNA_property_boolean_get(&lptr, lprop);
- }
- else if (rna_type == PROP_ENUM) {
- other->val_i = RNA_property_enum_get(&lptr, lprop);
- }
# endif
- }
-
- continue;
+ }
+ else {
+ if (rna_type == PROP_FLOAT) {
+ other->val_f = RNA_property_float_get(&lptr, lprop);
+ }
+ else if (rna_type == PROP_INT) {
+ other->val_i = RNA_property_int_get(&lptr, lprop);
}
+ /* ignored for now */
+# if 0
+ else if (rna_type == PROP_BOOLEAN) {
+ other->val_b = RNA_property_boolean_get(&lptr, lprop);
+ }
+ else if (rna_type == PROP_ENUM) {
+ other->val_i = RNA_property_enum_get(&lptr, lprop);
+ }
+# endif
}
-
- selctx_data->elems_len -= 1;
- i -= 1;
}
-
success = (selctx_data->elems_len != 0);
}
}
@@ -2334,9 +2318,6 @@ static void ui_apply_but(
case UI_BTYPE_LISTROW:
ui_apply_but_LISTROW(C, block, but, data);
break;
- case UI_BTYPE_DATASETROW:
- ui_apply_but_ROW(C, block, but, data);
- break;
case UI_BTYPE_TAB:
ui_apply_but_TAB(C, but, data);
break;
@@ -2985,11 +2966,6 @@ void ui_but_text_password_hide(char password_str[UI_MAX_PASSWORD_STR],
/** \name Button Text Selection/Editing
* \{ */
-/**
- * Use handling code to set a string for the button. Handles the case where the string is set for a
- * search button while the search menu is open, so the results are updated accordingly.
- * This is basically the same as pasting the string into the button.
- */
void ui_but_set_string_interactive(bContext *C, uiBut *but, const char *value)
{
button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
@@ -3555,6 +3531,12 @@ static void ui_textedit_end(bContext *C, uiBut *but, uiHandleButtonData *data)
if ((ui_searchbox_apply(but, data->searchbox) == false) &&
(ui_searchbox_find_index(data->searchbox, but->editstr) == -1) &&
!but_search->results_are_suggestions) {
+
+ if (but->flag & UI_BUT_VALUE_CLEAR) {
+ /* It is valid for _VALUE_CLEAR flavor to have no active element
+ * (it's a valid way to unlink). */
+ but->editstr[0] = '\0';
+ }
data->cancel = true;
/* ensure menu (popup) too is closed! */
@@ -8012,7 +7994,6 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
case UI_BTYPE_CHECKBOX:
case UI_BTYPE_CHECKBOX_N:
case UI_BTYPE_ROW:
- case UI_BTYPE_DATASETROW:
retval = ui_do_but_TOG(C, but, data, event);
break;
case UI_BTYPE_TREEROW:
@@ -8185,9 +8166,6 @@ static void ui_blocks_set_tooltips(ARegion *region, const bool enable)
}
}
-/**
- * Recreate tool-tip (use to update dynamic tips)
- */
void UI_but_tooltip_refresh(bContext *C, uiBut *but)
{
uiHandleButtonData *data = but->active;
@@ -8199,10 +8177,6 @@ void UI_but_tooltip_refresh(bContext *C, uiBut *but)
}
}
-/**
- * Removes tool-tip timer from active but
- * (meaning tool-tip is disabled until it's re-enabled again).
- */
void UI_but_tooltip_timer_remove(bContext *C, uiBut *but)
{
uiHandleButtonData *data = but->active;
@@ -8770,11 +8744,6 @@ uiBut *UI_context_active_but_get(const bContext *C)
return ui_context_button_active(CTX_wm_region(C), NULL);
}
-/*
- * Version of #UI_context_active_get() that uses the result of #CTX_wm_menu()
- * if set. Does not traverse into parent menus, which may be wanted in some
- * cases.
- */
uiBut *UI_context_active_but_get_respect_menu(const bContext *C)
{
ARegion *region_menu = CTX_wm_menu(C);
@@ -8798,12 +8767,6 @@ uiBlock *UI_region_block_find_mouse_over(const struct ARegion *region,
return ui_block_find_mouse_over_ex(region, xy, only_clip);
}
-/**
- * Version of #UI_context_active_but_get that also returns RNA property info.
- * Helper function for insert keyframe, reset to default, etc operators.
- *
- * \return active button, NULL if none found or if it doesn't contain valid RNA data.
- */
uiBut *UI_context_active_but_prop_get(const bContext *C,
struct PointerRNA *r_ptr,
struct PropertyRNA **r_prop,
@@ -8879,16 +8842,12 @@ wmOperator *UI_context_active_operator_get(const struct bContext *C)
return NULL;
}
-/**
- * Try to find a search-box region opened from a button in \a button_region.
- */
ARegion *UI_region_searchbox_region_get(const ARegion *button_region)
{
uiBut *but = UI_region_active_but_get(button_region);
return (but != NULL) ? but->active->searchbox : NULL;
}
-/* helper function for insert keyframe, reset to default, etc operators */
void UI_context_update_anim_flag(const bContext *C)
{
Scene *scene = CTX_data_scene(C);
@@ -8937,10 +8896,6 @@ void UI_context_update_anim_flag(const bContext *C)
}
}
-/**
- * In some cases we may want to update the view (#View2D) in-between layout definition and drawing.
- * E.g. to make sure a button is visible while editing.
- */
void ui_but_update_view_for_active(const bContext *C, const uiBlock *block)
{
uiBut *active_but = ui_block_active_but_get(block);
@@ -9000,11 +8955,6 @@ static int ui_handle_button_over(bContext *C, const wmEvent *event, ARegion *reg
return WM_UI_HANDLER_CONTINUE;
}
-/**
- * Exported to interface.c: #UI_but_active_only()
- * \note The region is only for the button.
- * The context needs to be set by the caller.
- */
void ui_but_activate_event(bContext *C, ARegion *region, uiBut *but)
{
wmWindow *win = CTX_wm_window(C);
@@ -9022,12 +8972,6 @@ void ui_but_activate_event(bContext *C, ARegion *region, uiBut *but)
ui_do_button(C, but->block, but, &event);
}
-/**
- * Simulate moving the mouse over a button (or navigating to it with arrow keys).
- *
- * exported so menus can start with a highlighted button,
- * even if the mouse isn't over it
- */
void ui_but_activate_over(bContext *C, ARegion *region, uiBut *but)
{
button_activate_init(C, region, but, BUTTON_ACTIVATE_OVER);
@@ -11267,10 +11211,6 @@ static int ui_handle_menus_recursive(bContext *C,
return retval;
}
-/**
- * Allow setting menu return value from externals.
- * E.g. WM might need to do this for exiting files correctly.
- */
void UI_popup_menu_retval_set(const uiBlock *block, const int retval, const bool enable)
{
uiPopupBlockHandle *menu = block->handle;
@@ -11344,8 +11284,7 @@ static void ui_region_handler_remove(bContext *C, void *UNUSED(userdata))
return;
}
- UI_blocklist_free(C, &region->uiblocks);
-
+ UI_blocklist_free(C, region);
bScreen *screen = CTX_wm_screen(C);
if (screen == NULL) {
return;
@@ -11669,8 +11608,19 @@ bool UI_textbutton_activate_but(const bContext *C, uiBut *actbut)
/** \name Public Utilities
* \{ */
-/* is called by notifier */
-void UI_screen_free_active_but(const bContext *C, bScreen *screen)
+void UI_region_free_active_but_all(bContext *C, ARegion *region)
+{
+ LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
+ LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
+ if (but->active == NULL) {
+ continue;
+ }
+ ui_but_active_free(C, but);
+ }
+ }
+}
+
+void UI_screen_free_active_but_highlight(const bContext *C, bScreen *screen)
{
wmWindow *win = CTX_wm_window(C);
@@ -11704,8 +11654,6 @@ uiBut *UI_but_active_drop_name_button(const bContext *C)
return NULL;
}
-/* returns true if highlighted button allows drop of names */
-/* called in region context */
bool UI_but_active_drop_name(const bContext *C)
{
return UI_but_active_drop_name_button(C) != NULL;
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index d0a7716b4dd..ca5d08ba40e 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -830,8 +830,6 @@ static void free_icons_textures(void)
}
}
-/* Reload the textures for internal icons.
- * This function will release the previous textures. */
void UI_icons_reload_internal_textures(void)
{
bTheme *btheme = UI_GetTheme();
@@ -1182,7 +1180,6 @@ static DrawInfo *icon_ensure_drawinfo(Icon *icon)
return di;
}
-/* NOTE:, returns unscaled by DPI. */
int UI_icon_get_width(int icon_id)
{
Icon *icon = BKE_icon_get(icon_id);
@@ -1242,8 +1239,6 @@ void UI_icons_init()
#endif
}
-/* Render size for preview images and icons
- */
int UI_icon_preview_to_render_size(enum eIconSizes size)
{
switch (size) {
@@ -1270,7 +1265,7 @@ static void icon_create_rect(struct PreviewImage *prv_img, enum eIconSizes size)
else if (!prv_img->rect[size]) {
prv_img->w[size] = render_size;
prv_img->h[size] = render_size;
- prv_img->flag[size] |= (PRV_CHANGED | PRV_UNFINISHED);
+ prv_img->flag[size] |= PRV_CHANGED;
prv_img->changed_timestamp[size] = 0;
prv_img->rect[size] = MEM_callocN(render_size * render_size * sizeof(uint), "prv_rect");
}
@@ -1419,6 +1414,7 @@ static void icon_set_image(const bContext *C,
const bool delay = prv_img->rect[size] != NULL;
icon_create_rect(prv_img, size);
+ prv_img->flag[size] |= PRV_RENDERING;
if (use_job && (!id || BKE_previewimg_id_supports_jobs(id))) {
/* Job (background) version */
@@ -2030,18 +2026,26 @@ static void ui_id_preview_image_render_size(
}
}
-/**
- * Note that if an ID doesn't support jobs for preview creation, \a use_job will be ignored.
- */
void UI_icon_render_id(
const bContext *C, Scene *scene, ID *id, const enum eIconSizes size, const bool use_job)
{
PreviewImage *pi = BKE_previewimg_id_ensure(id);
-
if (pi == NULL) {
return;
}
+ /* For objects, first try if a preview can created via the object data. */
+ if (GS(id->name) == ID_OB) {
+ Object *ob = (Object *)id;
+ if (ED_preview_id_is_supported(ob->data)) {
+ id = ob->data;
+ }
+ }
+
+ if (!ED_preview_id_is_supported(id)) {
+ return;
+ }
+
ui_id_preview_image_render_size(C, scene, id, pi, size, use_job);
}
@@ -2461,7 +2465,6 @@ int UI_icon_color_from_collection(const Collection *collection)
return icon;
}
-/* draws icon with dpi scale factor */
void UI_icon_draw(float x, float y, int icon_id)
{
UI_icon_draw_ex(x, y, icon_id, U.inv_dpi_fac, 1.0f, 0.0f, NULL, false);
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index 8c33e2d1cc9..dc8744aaae9 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -351,15 +351,6 @@ typedef struct uiButProgressbar {
float progress;
} uiButProgressbar;
-/** Derived struct for #UI_BTYPE_DATASETROW. */
-typedef struct uiButDatasetRow {
- uiBut but;
-
- uint8_t geometry_component_type;
- uint8_t attribute_domain;
- int indentation;
-} uiButDatasetRow;
-
/** Derived struct for #UI_BTYPE_TREEROW. */
typedef struct uiButTreeRow {
uiBut but;
@@ -629,6 +620,9 @@ extern void ui_block_to_window_rctf(const struct ARegion *region,
rctf *rct_dst,
const rctf *rct_src);
extern float ui_block_to_window_scale(const struct ARegion *region, uiBlock *block);
+/**
+ * For mouse cursor.
+ */
extern void ui_window_to_block_fl(const struct ARegion *region,
uiBlock *block,
float *x,
@@ -646,23 +640,52 @@ extern void ui_window_to_region_rctf(const struct ARegion *region,
rctf *rect_dst,
const rctf *rct_src);
extern void ui_region_to_window(const struct ARegion *region, int *x, int *y);
+/**
+ * Popups will add a margin to #ARegion.winrct for shadow,
+ * for interactivity (point-inside tests for eg), we want the winrct without the margin added.
+ */
extern void ui_region_winrct_get_no_margin(const struct ARegion *region, struct rcti *r_rect);
+/**
+ * Reallocate the button (new address is returned) for a new button type.
+ * This should generally be avoided and instead the correct type be created right away.
+ *
+ * \note Only the #uiBut data can be kept. If the old button used a derived type (e.g. #uiButTab),
+ * the data that is not inside #uiBut will be lost.
+ */
uiBut *ui_but_change_type(uiBut *but, eButType new_type);
extern double ui_but_value_get(uiBut *but);
extern void ui_but_value_set(uiBut *but, double value);
+/**
+ * For picker, while editing HSV.
+ */
extern void ui_but_hsv_set(uiBut *but);
+/**
+ * For buttons pointing to color for example.
+ */
extern void ui_but_v3_get(uiBut *but, float vec[3]);
+/**
+ * For buttons pointing to color for example.
+ */
extern void ui_but_v3_set(uiBut *but, const float vec[3]);
extern void ui_hsvcircle_vals_from_pos(
const rcti *rect, const float mx, const float my, float *r_val_rad, float *r_val_dist);
+/**
+ * Cursor in HSV circle, in float units -1 to 1, to map on radius.
+ */
extern void ui_hsvcircle_pos_from_vals(
const ColorPicker *cpicker, const rcti *rect, const float *hsv, float *xpos, float *ypos);
extern void ui_hsvcube_pos_from_vals(
const struct uiButHSVCube *hsv_but, const rcti *rect, const float *hsv, float *xp, float *yp);
+/**
+ * \param float_precision: For number buttons the precision
+ * to use or -1 to fallback to the button default.
+ * \param use_exp_float: Use exponent representation of floats
+ * when out of reasonable range (outside of 1e3/1e-3).
+ */
extern void ui_but_string_get_ex(uiBut *but,
char *str,
const size_t maxlen,
@@ -670,7 +693,16 @@ extern void ui_but_string_get_ex(uiBut *but,
const bool use_exp_float,
bool *r_use_exp_float) ATTR_NONNULL(1, 2);
extern void ui_but_string_get(uiBut *but, char *str, const size_t maxlen) ATTR_NONNULL();
+/**
+ * A version of #ui_but_string_get_ex for dynamic buffer sizes
+ * (where #ui_but_string_get_max_length returns 0).
+ *
+ * \param r_str_size: size of the returned string (including terminator).
+ */
extern char *ui_but_string_get_dynamic(uiBut *but, int *r_str_size);
+/**
+ * \param str: will be overwritten.
+ */
extern void ui_but_convert_to_unit_alt_name(uiBut *but, char *str, size_t maxlen) ATTR_NONNULL();
extern bool ui_but_string_set(struct bContext *C, uiBut *but, const char *str) ATTR_NONNULL();
extern bool ui_but_string_eval_number(struct bContext *C,
@@ -678,12 +710,22 @@ extern bool ui_but_string_eval_number(struct bContext *C,
const char *str,
double *value) ATTR_NONNULL();
extern int ui_but_string_get_max_length(uiBut *but);
-/* Clear & exit the active button's string. */
+/**
+ * Clear & exit the active button's string..
+ */
extern void ui_but_active_string_clear_and_exit(struct bContext *C, uiBut *but) ATTR_NONNULL();
+/**
+ * Use handling code to set a string for the button. Handles the case where the string is set for a
+ * search button while the search menu is open, so the results are updated accordingly.
+ * This is basically the same as pasting the string into the button.
+ */
extern void ui_but_set_string_interactive(struct bContext *C, uiBut *but, const char *value);
extern uiBut *ui_but_drag_multi_edit_get(uiBut *but);
void ui_def_but_icon(uiBut *but, const int icon, const int flag);
+/**
+ * Avoid using this where possible since it's better not to ask for an icon in the first place.
+ */
void ui_def_but_icon_clear(uiBut *but);
void ui_but_extra_operator_icons_free(uiBut *but);
@@ -696,6 +738,11 @@ void ui_but_range_set_hard(uiBut *but);
void ui_but_range_set_soft(uiBut *but);
bool ui_but_context_poll_operator(struct bContext *C, struct wmOperatorType *ot, const uiBut *but);
+/**
+ * Check if the operator \a ot poll is successful with the context given by \a but (optionally).
+ * \param but: The button that might store context. Can be NULL for convenience (e.g. if there is
+ * no button to take context from, but we still want to poll the operator).
+ */
bool ui_but_context_poll_operator_ex(struct bContext *C,
const uiBut *but,
const struct wmOperatorCallParams *optype_params);
@@ -706,10 +753,21 @@ extern PropertyScaleType ui_but_scale_type(const uiBut *but) ATTR_WARN_UNUSED_RE
extern bool ui_but_is_float(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
extern bool ui_but_is_bool(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
extern bool ui_but_is_unit(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Check if this button is similar enough to be grouped with another.
+ */
extern bool ui_but_is_compatible(const uiBut *but_a, const uiBut *but_b) ATTR_WARN_UNUSED_RESULT;
extern bool ui_but_is_rna_valid(uiBut *but) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Checks if the button supports cycling next/previous menu items (ctrl+mouse-wheel).
+ */
extern bool ui_but_supports_cycling(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Check if the button is pushed, this is only meaningful for some button types.
+ *
+ * \return (0 == UNSELECT), (1 == SELECT), (-1 == DO-NOTHING)
+ */
extern int ui_but_is_pushed_ex(uiBut *but, double *value) ATTR_WARN_UNUSED_RESULT;
extern int ui_but_is_pushed(uiBut *but) ATTR_WARN_UNUSED_RESULT;
@@ -804,6 +862,7 @@ struct uiPopupBlockHandle {
/* interface_region_*.c */
/* interface_region_tooltip.c */
+
/* exposed as public API in UI_interface.h */
/* interface_region_color_picker.c */
@@ -811,6 +870,10 @@ void ui_color_picker_rgb_to_hsv_compat(const float rgb[3], float r_cp[3]);
void ui_color_picker_rgb_to_hsv(const float rgb[3], float r_cp[3]);
void ui_color_picker_hsv_to_rgb(const float r_cp[3], float rgb[3]);
+/**
+ * Returns true if the button is for a color with gamma baked in,
+ * or if it's a color picker for such a button.
+ */
bool ui_but_is_color_gamma(uiBut *but);
void ui_scene_linear_to_perceptual_space(uiBut *but, float rgb[3]);
@@ -820,7 +883,10 @@ uiBlock *ui_block_func_COLOR(struct bContext *C, uiPopupBlockHandle *handle, voi
ColorPicker *ui_block_colorpicker_create(struct uiBlock *block);
/* interface_region_search.c */
-/* Search-box for string button. */
+
+/**
+ * Search-box for string button.
+ */
struct ARegion *ui_searchbox_create_generic(struct bContext *C,
struct ARegion *butregion,
uiButSearch *search_but);
@@ -831,8 +897,14 @@ struct ARegion *ui_searchbox_create_menu(struct bContext *C,
struct ARegion *butregion,
uiButSearch *search_but);
+/**
+ * x and y in screen-coords.
+ */
bool ui_searchbox_inside(struct ARegion *region, const int xy[2]) ATTR_NONNULL(1, 2);
int ui_searchbox_find_index(struct ARegion *region, const char *name);
+/**
+ * Region is the search box itself.
+ */
void ui_searchbox_update(struct bContext *C, struct ARegion *region, uiBut *but, const bool reset);
int ui_searchbox_autocomplete(struct bContext *C, struct ARegion *region, uiBut *but, char *str);
bool ui_searchbox_event(struct bContext *C,
@@ -840,16 +912,26 @@ bool ui_searchbox_event(struct bContext *C,
uiBut *but,
struct ARegion *butregion,
const struct wmEvent *event);
+/**
+ * String validated to be of correct length (but->hardmax).
+ */
bool ui_searchbox_apply(uiBut *but, struct ARegion *region);
void ui_searchbox_free(struct bContext *C, struct ARegion *region);
+/**
+ * XXX weak: search_func adds all partial matches.
+ */
void ui_but_search_refresh(uiButSearch *but);
/* interface_region_menu_popup.c */
+
int ui_but_menu_step(uiBut *but, int direction);
bool ui_but_menu_step_poll(const uiBut *but);
uiBut *ui_popup_menu_memory_get(struct uiBlock *block);
void ui_popup_menu_memory_set(uiBlock *block, struct uiBut *but);
+/**
+ * Called for creating new popups and refreshing existing ones.
+ */
uiBlock *ui_popup_block_refresh(struct bContext *C,
uiPopupBlockHandle *handle,
struct ARegion *butregion,
@@ -869,6 +951,7 @@ uiPopupBlockHandle *ui_popup_menu_create(struct bContext *C,
void *arg);
/* interface_region_popover.c */
+
uiPopupBlockHandle *ui_popover_panel_create(struct bContext *C,
struct ARegion *butregion,
uiBut *but,
@@ -876,6 +959,10 @@ uiPopupBlockHandle *ui_popover_panel_create(struct bContext *C,
void *arg);
/* interface_region_menu_pie.c */
+
+/**
+ * Set up data for defining a new pie menu level and add button that invokes it.
+ */
void ui_pie_menu_level_create(uiBlock *block,
struct wmOperatorType *ot,
const char *propname,
@@ -886,6 +973,10 @@ void ui_pie_menu_level_create(uiBlock *block,
int flag);
/* interface_region_popup.c */
+
+/**
+ * Translate any popup regions (so we can drag them).
+ */
void ui_popup_translate(struct ARegion *region, const int mdiff[2]);
void ui_popup_block_free(struct bContext *C, uiPopupBlockHandle *handle);
void ui_popup_block_scrolltest(struct uiBlock *block);
@@ -893,10 +984,19 @@ void ui_popup_block_scrolltest(struct uiBlock *block);
/* end interface_region_*.c */
/* interface_panel.c */
+
+/**
+ * Handle region panel events like opening and closing panels, changing categories, etc.
+ *
+ * \note Could become a modal key-map.
+ */
extern int ui_handler_panel_region(struct bContext *C,
const struct wmEvent *event,
struct ARegion *region,
const uiBut *active_but);
+/**
+ * Draw a panel integrated in buttons-window, tool/property lists etc.
+ */
extern void ui_draw_aligned_panel(const struct uiStyle *style,
const uiBlock *block,
const rcti *rect,
@@ -906,14 +1006,20 @@ extern void ui_draw_aligned_panel(const struct uiStyle *style,
void ui_panel_tag_search_filter_match(struct Panel *panel);
/* interface_draw.c */
+
extern void ui_draw_dropshadow(
const rctf *rct, float radius, float aspect, float alpha, int select);
+/**
+ * Draws in resolution of 48x4 colors.
+ */
void ui_draw_gradient(const rcti *rect,
const float hsv[3],
const eButGradientType type,
const float alpha);
+/* based on UI_draw_roundbox_gl_mode,
+ * check on making a version which allows us to skip some sides */
void ui_draw_but_TAB_outline(const rcti *rect,
float rad,
uchar highlight[3],
@@ -931,11 +1037,17 @@ void ui_draw_but_VECTORSCOPE(struct ARegion *region,
const struct uiWidgetColors *wcol,
const rcti *rect);
void ui_draw_but_COLORBAND(uiBut *but, const struct uiWidgetColors *wcol, const rcti *rect);
-void ui_draw_but_UNITVEC(uiBut *but, const struct uiWidgetColors *wcol, const rcti *rect);
+void ui_draw_but_UNITVEC(uiBut *but,
+ const struct uiWidgetColors *wcol,
+ const rcti *rect,
+ const float radius);
void ui_draw_but_CURVE(struct ARegion *region,
uiBut *but,
const struct uiWidgetColors *wcol,
const rcti *rect);
+/**
+ * Draws the curve profile widget. Somewhat similar to ui_draw_but_CURVE.
+ */
void ui_draw_but_CURVEPROFILE(struct ARegion *region,
uiBut *but,
const struct uiWidgetColors *wcol,
@@ -950,8 +1062,19 @@ void ui_draw_but_TRACKPREVIEW(struct ARegion *region,
const rcti *rect);
/* interface_undo.c */
+
+/**
+ * Start the undo stack.
+ *
+ * \note The current state should be pushed immediately after calling this.
+ */
struct uiUndoStack_Text *ui_textedit_undo_stack_create(void);
void ui_textedit_undo_stack_destroy(struct uiUndoStack_Text *undo_stack);
+/**
+ * Push the information in the arguments to a new state in the undo stack.
+ *
+ * \note Currently the total length of the undo stack is not limited.
+ */
void ui_textedit_undo_push(struct uiUndoStack_Text *undo_stack,
const char *text,
int cursor_index);
@@ -960,10 +1083,25 @@ const char *ui_textedit_undo(struct uiUndoStack_Text *undo_stack,
int *r_cursor_index);
/* interface_handlers.c */
+
extern void ui_handle_afterfunc_add_operator(struct wmOperatorType *ot,
wmOperatorCallContext opcontext);
+/**
+ * Assumes event type is MOUSEPAN.
+ */
extern void ui_pan_to_scroll(const struct wmEvent *event, int *type, int *val);
+/**
+ * Exported to interface.c: #UI_but_active_only()
+ * \note The region is only for the button.
+ * The context needs to be set by the caller.
+ */
extern void ui_but_activate_event(struct bContext *C, struct ARegion *region, uiBut *but);
+/**
+ * Simulate moving the mouse over a button (or navigating to it with arrow keys).
+ *
+ * exported so menus can start with a highlighted button,
+ * even if the mouse isn't over it
+ */
extern void ui_but_activate_over(struct bContext *C, struct ARegion *region, uiBut *but);
extern void ui_but_execute_begin(struct bContext *C,
struct ARegion *region,
@@ -974,13 +1112,25 @@ extern void ui_but_execute_end(struct bContext *C,
uiBut *but,
void *active_back);
extern void ui_but_active_free(const struct bContext *C, uiBut *but);
+/**
+ * In some cases we may want to update the view (#View2D) in-between layout definition and drawing.
+ * E.g. to make sure a button is visible while editing.
+ */
extern void ui_but_update_view_for_active(const struct bContext *C, const uiBlock *block);
extern int ui_but_menu_direction(uiBut *but);
extern void ui_but_text_password_hide(char password_str[128], uiBut *but, const bool restore);
+/**
+ * Finds the pressed button in an aligned row (typically an expanded enum).
+ *
+ * \param direction: Use when there may be multiple buttons pressed.
+ */
extern uiBut *ui_but_find_select_in_enum(uiBut *but, int direction);
bool ui_but_is_editing(const uiBut *but);
float ui_block_calc_pie_segment(struct uiBlock *block, const float event_xy[2]);
+/* XXX, this code will shorten any allocated string to 'UI_MAX_NAME_STR'
+ * since this is really long its unlikely to be an issue,
+ * but this could be supported */
void ui_but_add_shortcut(uiBut *but, const char *shortcut_str, const bool do_strip);
void ui_but_clipboard_free(void);
bool ui_but_rna_equals(const uiBut *a, const uiBut *b);
@@ -1045,6 +1195,9 @@ void ui_draw_widget_menu_back_color(const rcti *rect, bool use_shadow, const flo
void ui_draw_widget_menu_back(const rcti *rect, bool use_shadow);
void ui_draw_tooltip_background(const struct uiStyle *style, uiBlock *block, rcti *rect);
+/**
+ * Conversion from old to new buttons, so still messy.
+ */
extern void ui_draw_but(const struct bContext *C,
struct ARegion *region,
struct uiStyle *style,
@@ -1065,6 +1218,15 @@ typedef enum {
* get clipped before the normal text. */
UI_MENU_ITEM_SEPARATOR_HINT,
} uiMenuItemSeparatorType;
+/**
+ * Helper call to draw a menu item without a button.
+ *
+ * \param state: The state of the button,
+ * typically #UI_ACTIVE, #UI_BUT_DISABLED, #UI_BUT_INACTIVE.
+ * \param separator_type: The kind of separator which controls if and how the string is clipped.
+ * \param r_xmax: The right hand position of the text, this takes into the icon,
+ * padding and text clipping when there is not enough room to display the full text.
+ */
void ui_draw_menu_item(const struct uiFontStyle *fstyle,
rcti *rect,
const char *name,
@@ -1078,6 +1240,10 @@ void ui_draw_preview_item(const struct uiFontStyle *fstyle,
int iconid,
int state,
eFontStyle_Align text_align);
+/**
+ * Version of #ui_draw_preview_item() that does not draw the menu background and item text based on
+ * state. It just draws the preview and text directly.
+ */
void ui_draw_preview_item_stateless(const struct uiFontStyle *fstyle,
rcti *rect,
const char *name,
@@ -1087,59 +1253,102 @@ void ui_draw_preview_item_stateless(const struct uiFontStyle *fstyle,
#define UI_TEXT_MARGIN_X 0.4f
#define UI_POPUP_MARGIN (UI_DPI_FAC * 12)
-/* Margin at top of screen for popups. Note this value must be sufficient
- * to draw a popover arrow to avoid cropping it. */
+/**
+ * Margin at top of screen for popups.
+ * Note this value must be sufficient to draw a popover arrow to avoid cropping it.
+ */
#define UI_POPUP_MENU_TOP (int)(10 * UI_DPI_FAC)
#define UI_PIXEL_AA_JITTER 8
extern const float ui_pixel_jitter[UI_PIXEL_AA_JITTER][2];
/* interface_style.c */
+
+/**
+ * Called on each startup.blend read,
+ * reading without #uiFont will create one.
+ */
void uiStyleInit(void);
/* interface_icons.c */
+
void ui_icon_ensure_deferred(const struct bContext *C, const int icon_id, const bool big);
int ui_id_icon_get(const struct bContext *C, struct ID *id, const bool big);
/* interface_icons_event.c */
+
void icon_draw_rect_input(
float x, float y, int w, int h, float alpha, short event_type, short event_value);
/* resources.c */
+
void ui_resources_init(void);
void ui_resources_free(void);
/* interface_layout.c */
+
void ui_layout_add_but(uiLayout *layout, uiBut *but);
void ui_layout_remove_but(uiLayout *layout, const uiBut *but);
+/**
+ * \return true if the button was successfully replaced.
+ */
bool ui_layout_replace_but_ptr(uiLayout *layout, const void *old_but_ptr, uiBut *new_but);
+/**
+ * \note May reallocate \a but, so the possibly new address is returned.
+ */
uiBut *ui_but_add_search(uiBut *but,
PointerRNA *ptr,
PropertyRNA *prop,
PointerRNA *searchptr,
PropertyRNA *searchprop);
+/**
+ * Check all buttons defined in this layout,
+ * and set any button flagged as UI_BUT_LIST_ITEM as active/selected.
+ * Needed to handle correctly text colors of active (selected) list item.
+ */
void ui_layout_list_set_labels_active(uiLayout *layout);
/* menu callback */
void ui_item_menutype_func(struct bContext *C, struct uiLayout *layout, void *arg_mt);
void ui_item_paneltype_func(struct bContext *C, struct uiLayout *layout, void *arg_pt);
/* interface_button_group.c */
+
+/**
+ * Every function that adds a set of buttons must create another group,
+ * then #ui_def_but adds buttons to the current group (the last).
+ */
void ui_block_new_button_group(uiBlock *block, uiButtonGroupFlag flag);
void ui_button_group_add_but(uiBlock *block, uiBut *but);
void ui_button_group_replace_but_ptr(uiBlock *block, const void *old_but_ptr, uiBut *new_but);
void ui_block_free_button_groups(uiBlock *block);
/* interface_align.c */
+
bool ui_but_can_align(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
int ui_but_align_opposite_to_area_align_get(const struct ARegion *region) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Compute the alignment of all 'align groups' of buttons in given block.
+ *
+ * This is using an order-independent algorithm,
+ * i.e. alignment of buttons should be OK regardless of order in which
+ * they are added to the block.
+ */
void ui_block_align_calc(uiBlock *block, const struct ARegion *region);
/* interface_anim.c */
+
void ui_but_anim_flag(uiBut *but, const struct AnimationEvalContext *anim_eval_context);
void ui_but_anim_copy_driver(struct bContext *C);
void ui_but_anim_paste_driver(struct bContext *C);
+/**
+ * \a str can be NULL to only perform check if \a but has an expression at all.
+ * \return if button has an expression.
+ */
bool ui_but_anim_expression_get(uiBut *but, char *str, size_t maxlen);
bool ui_but_anim_expression_set(uiBut *but, const char *str);
+/**
+ * Create new expression for button (i.e. a "scripted driver"), if it can be created.
+ */
bool ui_but_anim_expression_create(uiBut *but, const char *str);
void ui_but_anim_autokey(struct bContext *C, uiBut *but, struct Scene *scene, float cfra);
@@ -1147,9 +1356,15 @@ void ui_but_anim_decorate_cb(struct bContext *C, void *arg_but, void *arg_dummy)
void ui_but_anim_decorate_update_from_flag(uiButDecorator *but);
/* interface_query.c */
+
bool ui_but_is_editable(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
bool ui_but_is_editable_as_text(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
bool ui_but_is_toggle(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Can we mouse over the button or is it hidden/disabled/layout.
+ * \note ctrl is kind of a hack currently,
+ * so that non-embossed UI_BTYPE_TEXT button behaves as a label when ctrl is not pressed.
+ */
bool ui_but_is_interactive(const uiBut *but, const bool labeledit) ATTR_WARN_UNUSED_RESULT;
bool ui_but_is_popover_once_compat(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
bool ui_but_has_array_value(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
@@ -1180,6 +1395,9 @@ uiBut *ui_tree_row_find_mouse_over(const struct ARegion *region, const int xy[2]
uiBut *ui_tree_row_find_active(const struct ARegion *region);
typedef bool (*uiButFindPollFn)(const uiBut *but, const void *customdata);
+/**
+ * x and y are only used in case event is NULL.
+ */
uiBut *ui_but_find_mouse_over_ex(const struct ARegion *region,
const int xy[2],
const bool labeledit,
@@ -1226,41 +1444,56 @@ bool ui_region_contains_point_px(const struct ARegion *region, const int xy[2])
ATTR_NONNULL(1, 2) ATTR_WARN_UNUSED_RESULT;
bool ui_region_contains_rect_px(const struct ARegion *region, const rcti *rect_px);
+/**
+ * Check if the cursor is over any popups.
+ */
struct ARegion *ui_screen_region_find_mouse_over_ex(struct bScreen *screen, const int xy[2])
ATTR_NONNULL(1, 2);
struct ARegion *ui_screen_region_find_mouse_over(struct bScreen *screen,
const struct wmEvent *event);
/* interface_context_menu.c */
+
bool ui_popup_context_menu_for_button(struct bContext *C, uiBut *but, const struct wmEvent *event);
+/**
+ * menu to show when right clicking on the panel header
+ */
void ui_popup_context_menu_for_panel(struct bContext *C,
struct ARegion *region,
struct Panel *panel);
/* interface_eyedropper.c */
+
struct wmKeyMap *eyedropper_modal_keymap(struct wmKeyConfig *keyconf);
struct wmKeyMap *eyedropper_colorband_modal_keymap(struct wmKeyConfig *keyconf);
/* interface_eyedropper_color.c */
+
void UI_OT_eyedropper_color(struct wmOperatorType *ot);
/* interface_eyedropper_colorband.c */
+
void UI_OT_eyedropper_colorramp(struct wmOperatorType *ot);
void UI_OT_eyedropper_colorramp_point(struct wmOperatorType *ot);
/* interface_eyedropper_datablock.c */
+
void UI_OT_eyedropper_id(struct wmOperatorType *ot);
/* interface_eyedropper_depth.c */
+
void UI_OT_eyedropper_depth(struct wmOperatorType *ot);
/* interface_eyedropper_driver.c */
+
void UI_OT_eyedropper_driver(struct wmOperatorType *ot);
/* interface_eyedropper_gpencil_color.c */
+
void UI_OT_eyedropper_gpencil_color(struct wmOperatorType *ot);
/* interface_template_asset_view.cc */
+
struct uiListType *UI_UL_asset_view(void);
/**
@@ -1286,12 +1519,15 @@ void ui_rna_collection_search_update_fn(const struct bContext *C,
const bool is_first);
/* interface_ops.c */
+
bool ui_jump_to_target_button_poll(struct bContext *C);
/* interface_queries.c */
+
void ui_interface_tag_script_reload_queries(void);
/* interface_view.cc */
+
void ui_block_free_views(struct uiBlock *block);
uiTreeViewHandle *ui_block_view_find_matching_in_old_block(const uiBlock *new_block,
const uiTreeViewHandle *new_view);
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index b792c59481c..cbdb284c66b 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -1464,11 +1464,6 @@ BLI_INLINE bool ui_layout_is_radial(const uiLayout *layout)
((layout->item.type == ITEM_LAYOUT_ROOT) && (layout->root->type == UI_LAYOUT_PIEMENU));
}
-/**
- * Create UI items for enum items in \a item_array.
- *
- * A version of #uiItemsFullEnumO that takes pre-calculated item array.
- */
void uiItemsFullEnumO_items(uiLayout *layout,
wmOperatorType *ot,
PointerRNA ptr,
@@ -1691,7 +1686,6 @@ void uiItemsEnumO(uiLayout *layout, const char *opname, const char *propname)
uiItemsFullEnumO(layout, opname, propname, NULL, layout->root->opcontext, 0);
}
-/* for use in cases where we have */
void uiItemEnumO_value(uiLayout *layout,
const char *name,
int icon,
@@ -2466,9 +2460,6 @@ void uiItemR(
uiItemFullR(layout, ptr, prop, RNA_NO_INDEX, 0, flag, name, icon);
}
-/**
- * Use a wrapper function since re-implementing all the logic in this function would be messy.
- */
void uiItemFullR_with_popover(uiLayout *layout,
PointerRNA *ptr,
PropertyRNA *prop,
@@ -2722,9 +2713,6 @@ static void ui_rna_collection_search_arg_free_fn(void *ptr)
MEM_freeN(ptr);
}
-/**
- * \note May reallocate \a but, so the possibly new address is returned.
- */
uiBut *ui_but_add_search(
uiBut *but, PointerRNA *ptr, PropertyRNA *prop, PointerRNA *searchptr, PropertyRNA *searchprop)
{
@@ -2869,7 +2857,6 @@ void uiItemPointerR(uiLayout *layout,
uiItemPointerR_prop(layout, ptr, prop, searchptr, searchprop, name, icon);
}
-/* menu item */
void ui_item_menutype_func(bContext *C, uiLayout *layout, void *arg_mt)
{
MenuType *mt = (MenuType *)arg_mt;
@@ -3015,10 +3002,6 @@ void uiItemMContents(uiLayout *layout, const char *menuname)
UI_menutype_draw(C, mt, layout);
}
-/**
- * Insert a decorator item for a button with the same property as \a prop.
- * To force inserting a blank dummy element, NULL can be passed for \a ptr and \a prop.
- */
void uiItemDecoratorR_prop(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index)
{
uiBlock *block = layout->root->block;
@@ -3077,10 +3060,6 @@ void uiItemDecoratorR_prop(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop,
}
}
-/**
- * Insert a decorator item for a button with the same property as \a prop.
- * To force inserting a blank dummy element, NULL can be passed for \a ptr and \a propname.
- */
void uiItemDecoratorR(uiLayout *layout, PointerRNA *ptr, const char *propname, int index)
{
PropertyRNA *prop = NULL;
@@ -3099,7 +3078,6 @@ void uiItemDecoratorR(uiLayout *layout, PointerRNA *ptr, const char *propname, i
uiItemDecoratorR_prop(layout, ptr, prop, index);
}
-/* popover */
void uiItemPopoverPanel_ptr(
uiLayout *layout, const bContext *C, PanelType *pt, const char *name, int icon)
{
@@ -3241,11 +3219,6 @@ void uiItemL(uiLayout *layout, const char *name, int icon)
uiItemL_(layout, name, icon);
}
-/**
- * Normally, we handle the split layout in #uiItemFullR(), but there are other cases where the
- * logic is needed. Ideally, #uiItemFullR() could just call this, but it currently has too many
- * special needs.
- */
uiPropertySplitWrapper uiItemPropertySplitWrapperCreate(uiLayout *parent_layout)
{
uiPropertySplitWrapper split_wrapper = {NULL};
@@ -3261,9 +3234,6 @@ uiPropertySplitWrapper uiItemPropertySplitWrapperCreate(uiLayout *parent_layout)
return split_wrapper;
}
-/*
- * Helper to add a label and creates a property split layout if needed.
- */
uiLayout *uiItemL_respect_property_split(uiLayout *layout, const char *text, int icon)
{
if (layout->item.flag & UI_ITEM_PROP_SEP) {
@@ -3297,7 +3267,6 @@ void uiItemLDrag(uiLayout *layout, PointerRNA *ptr, const char *name, int icon)
}
}
-/* value item */
void uiItemV(uiLayout *layout, const char *name, int icon, int argval)
{
/* label */
@@ -3342,7 +3311,6 @@ void uiItemV(uiLayout *layout, const char *name, int icon, int argval)
}
}
-/* separator item */
void uiItemS_ex(uiLayout *layout, float factor)
{
uiBlock *block = layout->root->block;
@@ -3370,13 +3338,11 @@ void uiItemS_ex(uiLayout *layout, float factor)
"");
}
-/* separator item */
void uiItemS(uiLayout *layout)
{
uiItemS_ex(layout, 1.0f);
}
-/* Flexible spacing. */
void uiItemSpacer(uiLayout *layout)
{
uiBlock *block = layout->root->block;
@@ -3409,7 +3375,6 @@ void uiItemSpacer(uiLayout *layout)
"");
}
-/* level items */
void uiItemMenuF(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc func, void *arg)
{
if (!func) {
@@ -3419,9 +3384,6 @@ void uiItemMenuF(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc
ui_item_menu(layout, name, icon, func, arg, NULL, "", false);
}
-/**
- * Version of #uiItemMenuF that free's `argN`.
- */
void uiItemMenuFN(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc func, void *argN)
{
if (!func) {
@@ -4730,7 +4692,6 @@ static void ui_layout_heading_set(uiLayout *layout, const char *heading)
}
}
-/* layout create functions */
uiLayout *uiLayoutRow(uiLayout *layout, bool align)
{
uiLayout *litem = MEM_callocN(sizeof(uiLayout), "uiLayoutRow");
@@ -4744,9 +4705,6 @@ uiLayout *uiLayoutRow(uiLayout *layout, bool align)
return litem;
}
-/**
- * See #uiLayoutColumnWithHeading().
- */
uiLayout *uiLayoutRowWithHeading(uiLayout *layout, bool align, const char *heading)
{
uiLayout *litem = uiLayoutRow(layout, align);
@@ -4767,12 +4725,6 @@ uiLayout *uiLayoutColumn(uiLayout *layout, bool align)
return litem;
}
-/**
- * Variant of #uiLayoutColumn() that sets a heading label for the layout if the first item is
- * added through #uiItemFullR(). If split layout is used and the item has no string to add to the
- * first split-column, the heading is added there instead. Otherwise the heading inserted with a
- * new row.
- */
uiLayout *uiLayoutColumnWithHeading(uiLayout *layout, bool align, const char *heading)
{
uiLayout *litem = uiLayoutColumn(layout, align);
@@ -4862,11 +4814,6 @@ uiLayout *uiLayoutBox(uiLayout *layout)
return (uiLayout *)ui_layout_box(layout, UI_BTYPE_ROUNDBOX);
}
-/**
- * Check all buttons defined in this layout,
- * and set any button flagged as UI_BUT_LIST_ITEM as active/selected.
- * Needed to handle correctly text colors of active (selected) list item.
- */
void ui_layout_list_set_labels_active(uiLayout *layout)
{
LISTBASE_FOREACH (uiButtonItem *, bitem, &layout->items) {
@@ -5214,11 +5161,6 @@ static bool block_search_filter_tag_buttons(uiBlock *block, const char *search_f
return has_result;
}
-/**
- * Apply property search behavior, setting panel flags and deactivating buttons that don't match.
- *
- * \note Must not be run after #UI_block_layout_resolve.
- */
bool UI_block_apply_search_filter(uiBlock *block, const char *search_filter)
{
if (search_filter == NULL || search_filter[0] == '\0') {
@@ -5643,9 +5585,6 @@ void ui_layout_remove_but(uiLayout *layout, const uiBut *but)
BLI_freelinkN(&layout->items, bitem);
}
-/**
- * \return true if the button was successfully replaced.
- */
bool ui_layout_replace_but_ptr(uiLayout *layout, const void *old_but_ptr, uiBut *new_but)
{
uiButtonItem *bitem = ui_layout_find_button_item(layout, old_but_ptr);
@@ -5683,11 +5622,6 @@ void uiLayoutSetFunc(uiLayout *layout, uiMenuHandleFunc handlefunc, void *argv)
layout->root->argv = argv;
}
-/**
- * Used for property search when the layout process needs to be cancelled in order to avoid
- * computing the locations for buttons, but the layout items created while adding the buttons
- * must still be freed.
- */
void UI_block_layout_free(uiBlock *block)
{
LISTBASE_FOREACH_MUTABLE (uiLayoutRoot *, root, &block->layouts) {
@@ -5759,7 +5693,6 @@ void uiLayoutSetContextFromBut(uiLayout *layout, uiBut *but)
}
}
-/* this is a bit of a hack but best keep it in one place at least */
wmOperatorType *UI_but_operatortype_get_from_enum_menu(uiBut *but, PropertyRNA **r_prop)
{
if (r_prop != NULL) {
@@ -5777,7 +5710,6 @@ wmOperatorType *UI_but_operatortype_get_from_enum_menu(uiBut *but, PropertyRNA *
return NULL;
}
-/* this is a bit of a hack but best keep it in one place at least */
MenuType *UI_but_menutype_get(uiBut *but)
{
if (but->menu_create_func == ui_item_menutype_func) {
@@ -5786,7 +5718,6 @@ MenuType *UI_but_menutype_get(uiBut *but)
return NULL;
}
-/* this is a bit of a hack but best keep it in one place at least */
PanelType *UI_but_paneltype_get(uiBut *but)
{
if (but->menu_create_func == ui_item_paneltype_func) {
@@ -5886,9 +5817,6 @@ static void ui_paneltype_draw_impl(bContext *C, PanelType *pt, uiLayout *layout,
}
}
-/**
- * Used for popup panels only.
- */
void UI_paneltype_draw(bContext *C, PanelType *pt, uiLayout *layout)
{
if (layout->context) {
@@ -6009,9 +5937,6 @@ static void ui_layout_introspect_items(DynStr *ds, ListBase *lb)
BLI_dynstr_append(ds, "]");
}
-/**
- * Evaluate layout items as a Python dictionary.
- */
const char *UI_layout_introspect(uiLayout *layout)
{
DynStr *ds = BLI_dynstr_new();
@@ -6031,10 +5956,6 @@ const char *UI_layout_introspect(uiLayout *layout)
/** \name Alert Box with Big Icon
* \{ */
-/**
- * Helper to add a big icon and create a split layout for alert popups.
- * Returns the layout to place further items into the alert box.
- */
uiLayout *uiItemsAlertBox(uiBlock *block, const int size, const eAlertIcon icon)
{
const uiStyle *style = UI_style_get_dpi();
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index c962a1107ae..35b621b0272 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -26,7 +26,8 @@
#include "MEM_guardedalloc.h"
#include "DNA_armature_types.h"
-#include "DNA_object_types.h" /* for OB_DATA_SUPPORT_ID */
+#include "DNA_modifier_types.h" /* for handling geometry nodes properties */
+#include "DNA_object_types.h" /* for OB_DATA_SUPPORT_ID */
#include "DNA_screen_types.h"
#include "DNA_text_types.h"
@@ -846,6 +847,9 @@ bool UI_context_copy_to_selected_list(bContext *C,
else if (RNA_struct_is_a(ptr->type, &RNA_Keyframe)) {
*r_lb = CTX_data_collection_get(C, "selected_editable_keyframes");
}
+ else if (RNA_struct_is_a(ptr->type, &RNA_Action)) {
+ *r_lb = CTX_data_collection_get(C, "selected_editable_actions");
+ }
else if (RNA_struct_is_a(ptr->type, &RNA_NlaStrip)) {
*r_lb = CTX_data_collection_get(C, "selected_nla_strips");
}
@@ -982,6 +986,97 @@ bool UI_context_copy_to_selected_list(bContext *C,
return true;
}
+bool UI_context_copy_to_selected_check(PointerRNA *ptr,
+ PointerRNA *ptr_link,
+ PropertyRNA *prop,
+ const char *path,
+ bool use_path_from_id,
+ PointerRNA *r_ptr,
+ PropertyRNA **r_prop)
+{
+ PointerRNA idptr;
+ PropertyRNA *lprop;
+ PointerRNA lptr;
+
+ if (ptr_link->data == ptr->data) {
+ return false;
+ }
+
+ if (use_path_from_id) {
+ /* Path relative to ID. */
+ lprop = NULL;
+ RNA_id_pointer_create(ptr_link->owner_id, &idptr);
+ RNA_path_resolve_property(&idptr, path, &lptr, &lprop);
+ }
+ else if (path) {
+ /* Path relative to elements from list. */
+ lprop = NULL;
+ RNA_path_resolve_property(ptr_link, path, &lptr, &lprop);
+ }
+ else {
+ lptr = *ptr_link;
+ lprop = prop;
+ }
+
+ if (lptr.data == ptr->data) {
+ /* temp_ptr might not be the same as ptr_link! */
+ return false;
+ }
+
+ /* Skip non-existing properties on link. This was previously covered with the `lprop != prop`
+ * check but we are now more permissive when it comes to ID properties, see below. */
+ if (lprop == NULL) {
+ return false;
+ }
+
+ if (RNA_property_type(lprop) != RNA_property_type(prop)) {
+ return false;
+ }
+
+ /* Check property pointers matching.
+ * For ID properties, these pointers match:
+ * - If the property is API defined on an existing class (and they are equally named).
+ * - Never for ID properties on specific ID (even if they are equally named).
+ * - Never for NodesModifierSettings properties (even if they are equally named).
+ *
+ * Be permissive on ID properties in the following cases:
+ * - #NodesModifierSettings properties
+ * - (special check: only if the node-group matches, since the 'Input_n' properties are name
+ * based and similar on potentially very different node-groups).
+ * - ID properties on specific ID
+ * - (no special check, copying seems OK [even if type does not match -- does not do anything
+ * then])
+ */
+ bool ignore_prop_eq = RNA_property_is_idprop(lprop) && RNA_property_is_idprop(prop);
+ if (RNA_struct_is_a(lptr.type, &RNA_NodesModifier) &&
+ RNA_struct_is_a(ptr->type, &RNA_NodesModifier)) {
+ ignore_prop_eq = false;
+
+ NodesModifierData *nmd_link = (NodesModifierData *)lptr.data;
+ NodesModifierData *nmd_src = (NodesModifierData *)ptr->data;
+ if (nmd_link->node_group == nmd_src->node_group) {
+ ignore_prop_eq = true;
+ }
+ }
+
+ if ((lprop != prop) && !ignore_prop_eq) {
+ return false;
+ }
+
+ if (!RNA_property_editable(&lptr, lprop)) {
+ return false;
+ }
+
+ if (r_ptr) {
+ *r_ptr = lptr;
+ }
+ if (r_prop) {
+ *r_prop = lprop;
+ }
+
+ return true;
+}
+
/**
* Called from both exec & poll.
*
@@ -992,7 +1087,7 @@ bool UI_context_copy_to_selected_list(bContext *C,
static bool copy_to_selected_button(bContext *C, bool all, bool poll)
{
Main *bmain = CTX_data_main(C);
- PointerRNA ptr, lptr, idptr;
+ PointerRNA ptr, lptr;
PropertyRNA *prop, *lprop;
bool success = false;
int index;
@@ -1022,32 +1117,8 @@ static bool copy_to_selected_button(bContext *C, bool all, bool poll)
continue;
}
- if (use_path_from_id) {
- /* Path relative to ID. */
- lprop = NULL;
- RNA_id_pointer_create(link->ptr.owner_id, &idptr);
- RNA_path_resolve_property(&idptr, path, &lptr, &lprop);
- }
- else if (path) {
- /* Path relative to elements from list. */
- lprop = NULL;
- RNA_path_resolve_property(&link->ptr, path, &lptr, &lprop);
- }
- else {
- lptr = link->ptr;
- lprop = prop;
- }
-
- if (lptr.data == ptr.data) {
- /* lptr might not be the same as link->ptr! */
- continue;
- }
-
- if (lprop != prop) {
- continue;
- }
-
- if (!RNA_property_editable(&lptr, lprop)) {
+ if (!UI_context_copy_to_selected_check(
+ &ptr, &link->ptr, prop, path, use_path_from_id, &lptr, &lprop)) {
continue;
}
@@ -1340,10 +1411,6 @@ void UI_editsource_active_but_test(uiBut *but)
BLI_ghash_insert(ui_editsource_info->hash, but, but_store);
}
-/**
- * Remove the editsource data for \a old_but and reinsert it for \a new_but. Use when the button
- * was reallocated, e.g. to have a new type (#ui_but_change_type()).
- */
void UI_editsource_but_replace(const uiBut *old_but, uiBut *new_but)
{
uiEditSourceButStore *but_store = BLI_ghash_lookup(ui_editsource_info->hash, old_but);
@@ -1405,7 +1472,7 @@ static int editsource_exec(bContext *C, wmOperator *op)
int ret;
/* needed else the active button does not get tested */
- UI_screen_free_active_but(C, CTX_wm_screen(C));
+ UI_screen_free_active_but_highlight(C, CTX_wm_screen(C));
// printf("%s: begin\n", __func__);
@@ -1977,7 +2044,7 @@ static int ui_tree_view_drop_invoke(bContext *C, wmOperator *UNUSED(op), const w
const ARegion *region = CTX_wm_region(C);
uiTreeViewItemHandle *hovered_tree_item = UI_block_tree_view_find_item_at(region, event->xy);
- if (!UI_tree_view_item_drop_handle(hovered_tree_item, event->customdata)) {
+ if (!UI_tree_view_item_drop_handle(C, hovered_tree_item, event->customdata)) {
return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
}
@@ -2082,9 +2149,6 @@ void ED_operatortypes_ui(void)
WM_operatortype_append(UI_OT_eyedropper_gpencil_color);
}
-/**
- * \brief User Interface Keymap
- */
void ED_keymap_ui(wmKeyConfig *keyconf)
{
WM_keymap_ensure(keyconf, "User Interface", 0, 0);
diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c
index 6acbaf03476..bc1d3387ad7 100644
--- a/source/blender/editors/interface/interface_panel.c
+++ b/source/blender/editors/interface/interface_panel.c
@@ -273,10 +273,6 @@ static Panel *panel_add_instanced(ARegion *region,
return panel;
}
-/**
- * Called in situations where panels need to be added dynamically rather than
- * having only one panel corresponding to each #PanelType.
- */
Panel *UI_panel_add_instanced(const bContext *C,
ARegion *region,
ListBase *panels,
@@ -301,10 +297,6 @@ Panel *UI_panel_add_instanced(const bContext *C,
return new_panel;
}
-/**
- * Find a unique key to append to the #PanelType.idname for the lookup to the panel's #uiBlock.
- * Needed for instanced panels, where there can be multiple with the same type and identifier.
- */
void UI_list_panel_unique_str(Panel *panel, char *r_name)
{
/* The panel sort-order will be unique for a specific panel type because the instanced
@@ -334,12 +326,6 @@ static void panel_delete(const bContext *C, ARegion *region, ListBase *panels, P
MEM_freeN(panel);
}
-/**
- * Remove instanced panels from the region's panel list.
- *
- * \note Can be called with NULL \a C, but it should be avoided because
- * handlers might not be removed.
- */
void UI_panels_free_instanced(const bContext *C, ARegion *region)
{
/* Delete panels with the instanced flag. */
@@ -361,15 +347,6 @@ void UI_panels_free_instanced(const bContext *C, ARegion *region)
}
}
-/**
- * Check if the instanced panels in the region's panels correspond to the list of data the panels
- * represent. Returns false if the panels have been reordered or if the types from the list data
- * don't match in any way.
- *
- * \param data: The list of data to check against the instanced panels.
- * \param panel_idname_func: Function to find the #PanelType.idname for each item in the data list.
- * For a readability and generality, this lookup happens separately for each type of panel list.
- */
bool UI_panel_list_matches_data(ARegion *region,
ListBase *data,
uiListPanelIDFromDataFunc panel_idname_func)
@@ -486,8 +463,12 @@ static void reorder_instanced_panel_list(bContext *C, ARegion *region, Panel *dr
/* Set the bit to tell the interface to instanced the list. */
drag_panel->flag |= PNL_INSTANCED_LIST_ORDER_CHANGED;
+ CTX_store_set(C, drag_panel->runtime.context);
+
/* Finally, move this panel's list item to the new index in its list. */
drag_panel->type->reorder(C, drag_panel, move_to_index);
+
+ CTX_store_set(C, NULL);
}
/**
@@ -697,9 +678,6 @@ Panel *UI_panel_find_by_type(ListBase *lb, const PanelType *pt)
return NULL;
}
-/**
- * \note \a panel should be return value from #UI_panel_find_by_type and can be NULL.
- */
Panel *UI_panel_begin(
ARegion *region, ListBase *lb, uiBlock *block, PanelType *pt, Panel *panel, bool *r_open)
{
@@ -779,11 +757,6 @@ Panel *UI_panel_begin(
return panel;
}
-/**
- * Create the panel header button group, used to mark which buttons are part of
- * panel headers for the panel search process that happens later. This Should be
- * called before adding buttons for the panel's header layout.
- */
void UI_panel_header_buttons_begin(Panel *panel)
{
uiBlock *block = panel->runtime.block;
@@ -791,9 +764,6 @@ void UI_panel_header_buttons_begin(Panel *panel)
ui_block_new_button_group(block, UI_BUTTON_GROUP_LOCK | UI_BUTTON_GROUP_PANEL_HEADER);
}
-/**
- * Finish the button group for the panel header to avoid putting panel body buttons in it.
- */
void UI_panel_header_buttons_end(Panel *panel)
{
uiBlock *block = panel->runtime.block;
@@ -923,10 +893,6 @@ static void panel_matches_search_filter_recursive(const Panel *panel, bool *filt
}
}
-/**
- * Find whether a panel or any of its sub-panels contain a property that matches the search filter,
- * depending on the search process running in #UI_block_apply_search_filter earlier.
- */
bool UI_panel_matches_search_filter(const Panel *panel)
{
bool search_filter_matches = false;
@@ -1018,10 +984,6 @@ static void region_panels_remove_invisible_layouts(ARegion *region)
}
}
-/**
- * Get the panel's expansion state, taking into account
- * expansion set from property search if it applies.
- */
bool UI_panel_is_closed(const Panel *panel)
{
/* Header-less panels can never be closed, otherwise they could disappear. */
@@ -1047,9 +1009,6 @@ bool UI_panel_is_active(const Panel *panel)
/** \name Drawing
* \{ */
-/**
- * Draw panels, selected (panels currently being dragged) on top.
- */
void UI_panels_draw(const bContext *C, ARegion *region)
{
/* Draw in reverse order, because #uiBlocks are added in reverse order
@@ -1071,7 +1030,6 @@ void UI_panels_draw(const bContext *C, ARegion *region)
#define PNL_ICON UI_UNIT_X /* Could be UI_UNIT_Y too. */
-/* For button layout next to label. */
void UI_panel_label_offset(const uiBlock *block, int *r_x, int *r_y)
{
Panel *panel = block->panel;
@@ -1118,7 +1076,8 @@ static void panel_draw_highlight_border(const Panel *panel,
}
const bTheme *btheme = UI_GetTheme();
- const float radius = btheme->tui.panel_roundness * U.widget_unit * 0.5f;
+ const float aspect = panel->runtime.block->aspect;
+ const float radius = (btheme->tui.panel_roundness * U.widget_unit * 0.5f) / aspect;
UI_draw_roundbox_corner_set(UI_CNR_ALL);
float color[4];
@@ -1241,7 +1200,8 @@ static void panel_draw_aligned_backdrop(const Panel *panel,
}
const bTheme *btheme = UI_GetTheme();
- const float radius = btheme->tui.panel_roundness * U.widget_unit * 0.5f;
+ const float aspect = panel->runtime.block->aspect;
+ const float radius = btheme->tui.panel_roundness * U.widget_unit * 0.5f / aspect;
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
GPU_blend(GPU_BLEND_ALPHA);
@@ -1288,9 +1248,6 @@ static void panel_draw_aligned_backdrop(const Panel *panel,
immUnbindProgram();
}
-/**
- * Draw a panel integrated in buttons-window, tool/property lists etc.
- */
void ui_draw_aligned_panel(const uiStyle *style,
const uiBlock *block,
const rcti *rect,
@@ -1328,6 +1285,24 @@ void ui_draw_aligned_panel(const uiStyle *style,
}
}
+bool UI_panel_should_show_background(const ARegion *region, const PanelType *panel_type)
+{
+ if (region->alignment == RGN_ALIGN_FLOAT) {
+ return false;
+ }
+
+ if (panel_type && panel_type->flag & PANEL_TYPE_NO_HEADER) {
+ if (region->regiontype == RGN_TYPE_TOOLS) {
+ /* We never want a background around active tools. */
+ return false;
+ }
+ /* Without a header there is no background except for region overlap. */
+ return region->overlap != 0;
+ }
+
+ return true;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1337,9 +1312,6 @@ void ui_draw_aligned_panel(const uiStyle *style,
#define TABS_PADDING_BETWEEN_FACTOR 4.0f
#define TABS_PADDING_TEXT_FACTOR 6.0f
-/**
- * Draw vertical tabs on the left side of the region, one tab per category.
- */
void UI_panel_category_draw_all(ARegion *region, const char *category_id_active)
{
// #define USE_FLAT_INACTIVE
@@ -1740,17 +1712,22 @@ static bool uiAlignPanelStep(ARegion *region, const float factor, const bool dra
const int region_offset_x = panel_region_offset_x_get(region);
for (int i = 0; i < active_panels_len; i++) {
PanelSort *ps = &panel_sort[i];
- const bool no_header = ps->panel->type->flag & PANEL_TYPE_NO_HEADER;
+ const bool show_background = UI_panel_should_show_background(region, ps->panel->type);
ps->panel->runtime.region_ofsx = region_offset_x;
- ps->new_offset_x = region_offset_x + (no_header ? 0 : UI_PANEL_MARGIN_X);
+ ps->new_offset_x = region_offset_x + (show_background ? UI_PANEL_MARGIN_X : 0);
}
/* Y offset. */
for (int i = 0, y = 0; i < active_panels_len; i++) {
PanelSort *ps = &panel_sort[i];
+ const bool show_background = UI_panel_should_show_background(region, ps->panel->type);
+
y -= get_panel_real_size_y(ps->panel);
- y -= UI_PANEL_MARGIN_Y;
+ /* Separate panel boxes a bit further (if they are drawn). */
+ if (show_background) {
+ y -= UI_PANEL_MARGIN_Y;
+ }
ps->new_offset_y = y;
/* The header still draws offset by the size of closed panels, so apply the offset here. */
if (UI_panel_is_closed(ps->panel)) {
@@ -1796,6 +1773,7 @@ static void ui_panels_size(ARegion *region, int *r_x, int *r_y)
{
int sizex = 0;
int sizey = 0;
+ bool has_panel_with_background = false;
/* Compute size taken up by panels, for setting in view2d. */
LISTBASE_FOREACH (Panel *, panel, &region->panels) {
@@ -1805,6 +1783,9 @@ static void ui_panels_size(ARegion *region, int *r_x, int *r_y)
sizex = max_ii(sizex, pa_sizex);
sizey = min_ii(sizey, pa_sizey);
+ if (UI_panel_should_show_background(region, panel->type)) {
+ has_panel_with_background = true;
+ }
}
}
@@ -1814,6 +1795,11 @@ static void ui_panels_size(ARegion *region, int *r_x, int *r_y)
if (sizey == 0) {
sizey = -UI_PANEL_WIDTH;
}
+ /* Extra margin after the list so the view scrolls a few pixels further than the panel border.
+ * Also makes the bottom match the top margin. */
+ if (has_panel_with_background) {
+ sizey -= UI_PANEL_MARGIN_Y;
+ }
*r_x = sizex;
*r_y = sizey;
@@ -2342,11 +2328,6 @@ static int ui_handle_panel_category_cycling(const wmEvent *event,
return WM_UI_HANDLER_CONTINUE;
}
-/**
- * Handle region panel events like opening and closing panels, changing categories, etc.
- *
- * \note Could become a modal key-map.
- */
int ui_handler_panel_region(bContext *C,
const wmEvent *event,
ARegion *region,
@@ -2458,6 +2439,12 @@ static void ui_panel_custom_data_set_recursive(Panel *panel, PointerRNA *custom_
}
}
+void UI_panel_context_pointer_set(Panel *panel, const char *name, PointerRNA *ptr)
+{
+ uiLayoutSetContextPointer(panel->layout, name, ptr);
+ panel->runtime.context = uiLayoutGetContextStore(panel->layout);
+}
+
void UI_panel_custom_data_set(Panel *panel, PointerRNA *custom_data)
{
BLI_assert(panel->type != NULL);
diff --git a/source/blender/editors/interface/interface_query.c b/source/blender/editors/interface/interface_query.c
index bdf93d7c82e..b486ceb8dca 100644
--- a/source/blender/editors/interface/interface_query.c
+++ b/source/blender/editors/interface/interface_query.c
@@ -69,15 +69,9 @@ bool ui_but_is_toggle(const uiBut *but)
UI_BTYPE_CHECKBOX,
UI_BTYPE_CHECKBOX_N,
UI_BTYPE_ROW,
- UI_BTYPE_DATASETROW,
UI_BTYPE_TREEROW);
}
-/**
- * Can we mouse over the button or is it hidden/disabled/layout.
- * \note ctrl is kind of a hack currently,
- * so that non-embossed UI_BTYPE_TEXT button behaves as a label when ctrl is not pressed.
- */
bool ui_but_is_interactive(const uiBut *but, const bool labeledit)
{
/* NOTE: #UI_BTYPE_LABEL is included for highlights, this allows drags. */
@@ -104,7 +98,6 @@ bool ui_but_is_interactive(const uiBut *but, const bool labeledit)
return true;
}
-/* file selectors are exempt from utf-8 checks */
bool UI_but_is_utf8(const uiBut *but)
{
if (but->rnaprop) {
@@ -284,7 +277,6 @@ static uiBut *ui_but_find(const ARegion *region,
return NULL;
}
-/* x and y are only used in case event is NULL... */
uiBut *ui_but_find_mouse_over_ex(const ARegion *region,
const int xy[2],
const bool labeledit,
@@ -798,7 +790,6 @@ bool ui_region_contains_rect_px(const ARegion *region, const rcti *rect_px)
/** \name Screen (#bScreen) Spatial
* \{ */
-/** Check if the cursor is over any popups. */
ARegion *ui_screen_region_find_mouse_over_ex(bScreen *screen, const int xy[2])
{
LISTBASE_FOREACH (ARegion *, region, &screen->regionbase) {
diff --git a/source/blender/editors/interface/interface_region_color_picker.c b/source/blender/editors/interface/interface_region_color_picker.c
index 48952c4f121..2b167c56186 100644
--- a/source/blender/editors/interface/interface_region_color_picker.c
+++ b/source/blender/editors/interface/interface_region_color_picker.c
@@ -115,8 +115,6 @@ void ui_color_picker_hsv_to_rgb(const float r_cp[3], float rgb[3])
}
}
-/* Returns true if the button is for a color with gamma baked in,
- * or if it's a color picker for such a button. */
bool ui_but_is_color_gamma(uiBut *but)
{
if (but->rnaprop) {
@@ -183,7 +181,6 @@ static void ui_color_picker_update_hsv(ColorPicker *cpicker,
cpicker->is_init = true;
}
-/* for picker, while editing hsv */
void ui_but_hsv_set(uiBut *but)
{
float rgb_perceptual[3];
diff --git a/source/blender/editors/interface/interface_region_hud.c b/source/blender/editors/interface/interface_region_hud.c
index b50daa0df21..fc4ce6180c3 100644
--- a/source/blender/editors/interface/interface_region_hud.c
+++ b/source/blender/editors/interface/interface_region_hud.c
@@ -57,6 +57,7 @@
/* -------------------------------------------------------------------- */
/** \name Utilities
* \{ */
+
struct HudRegionData {
short regionid;
};
diff --git a/source/blender/editors/interface/interface_region_menu_pie.c b/source/blender/editors/interface/interface_region_menu_pie.c
index 0ffbdd6911c..677da07d53d 100644
--- a/source/blender/editors/interface/interface_region_menu_pie.c
+++ b/source/blender/editors/interface/interface_region_menu_pie.c
@@ -305,8 +305,7 @@ int UI_pie_menu_invoke_from_rna_enum(struct bContext *C,
/** \} */
/* -------------------------------------------------------------------- */
-/**
- * \name Pie Menu Levels
+/** \name Pie Menu Levels
*
* Pie menus can't contain more than 8 items (yet).
* When using #uiItemsFullEnumO, a "More" button is created that calls
@@ -318,7 +317,6 @@ int UI_pie_menu_invoke_from_rna_enum(struct bContext *C,
* Ideally we'd have some way of handling this for all kinds of pie items, but that's tricky.
*
* - Julian (Feb 2016)
- *
* \{ */
typedef struct PieMenuLevelData {
@@ -372,9 +370,6 @@ static void ui_pie_menu_level_invoke(bContext *C, void *argN, void *arg2)
UI_pie_menu_end(C, pie);
}
-/**
- * Set up data for defining a new pie menu level and add button that invokes it.
- */
void ui_pie_menu_level_create(uiBlock *block,
wmOperatorType *ot,
const char *propname,
diff --git a/source/blender/editors/interface/interface_region_menu_popup.c b/source/blender/editors/interface/interface_region_menu_popup.c
index 408953f8d0e..a8980b8b122 100644
--- a/source/blender/editors/interface/interface_region_menu_popup.c
+++ b/source/blender/editors/interface/interface_region_menu_popup.c
@@ -384,10 +384,6 @@ uiPopupBlockHandle *ui_popup_menu_create(
/** \name Popup Menu API with begin & end
* \{ */
-/**
- * Only return handler, and set optional title.
- * \param block_name: Assigned to uiBlock.name (useful info for debugging).
- */
uiPopupMenu *UI_popup_menu_begin_ex(bContext *C,
const char *title,
const char *block_name,
@@ -450,16 +446,12 @@ uiPopupMenu *UI_popup_menu_begin(bContext *C, const char *title, int icon)
return UI_popup_menu_begin_ex(C, title, __func__, icon);
}
-/**
- * Setting the button makes the popup open from the button instead of the cursor.
- */
void UI_popup_menu_but_set(uiPopupMenu *pup, struct ARegion *butregion, uiBut *but)
{
pup->but = but;
pup->butregion = butregion;
}
-/* set the whole structure to work */
void UI_popup_menu_end(bContext *C, uiPopupMenu *pup)
{
wmWindow *window = CTX_wm_window(C);
diff --git a/source/blender/editors/interface/interface_region_popover.c b/source/blender/editors/interface/interface_region_popover.c
index 5e7e0bfe9b5..1bb589d99fb 100644
--- a/source/blender/editors/interface/interface_region_popover.c
+++ b/source/blender/editors/interface/interface_region_popover.c
@@ -340,12 +340,6 @@ int UI_popover_panel_invoke(bContext *C, const char *idname, bool keep_open, Rep
/** \name Popup Menu API with begin & end
* \{ */
-/**
- * Only return handler, and set optional title.
- *
- * \param from_active_button: Use the active button for positioning,
- * use when the popover is activated from an operator instead of directly from the button.
- */
uiPopover *UI_popover_begin(bContext *C, int ui_menu_width, bool from_active_button)
{
uiPopover *pup = MEM_callocN(sizeof(uiPopover), "popover menu");
@@ -383,7 +377,6 @@ static void popover_keymap_fn(wmKeyMap *UNUSED(keymap), wmKeyMapItem *UNUSED(kmi
pup->block->handle->menuretval = UI_RETURN_OK;
}
-/* set the whole structure to work */
void UI_popover_end(bContext *C, uiPopover *pup, wmKeyMap *keymap)
{
wmWindow *window = CTX_wm_window(C);
diff --git a/source/blender/editors/interface/interface_region_popup.c b/source/blender/editors/interface/interface_region_popup.c
index 0e53100f91b..33ce47b281b 100644
--- a/source/blender/editors/interface/interface_region_popup.c
+++ b/source/blender/editors/interface/interface_region_popup.c
@@ -53,9 +53,6 @@
/** \name Utility Functions
* \{ */
-/**
- * Translate any popup regions (so we can drag them).
- */
void ui_popup_translate(ARegion *region, const int mdiff[2])
{
BLI_rcti_translate(&region->winrct, UNPACK2(mdiff));
@@ -554,9 +551,6 @@ static void ui_popup_block_remove(bContext *C, uiPopupBlockHandle *handle)
}
}
-/**
- * Called for creating new popups and refreshing existing ones.
- */
uiBlock *ui_popup_block_refresh(bContext *C,
uiPopupBlockHandle *handle,
ARegion *butregion,
@@ -743,7 +737,7 @@ uiBlock *ui_popup_block_refresh(bContext *C,
if (block_old) {
block->oldblock = block_old;
UI_block_update_from_old(C, block);
- UI_blocklist_free_inactive(C, &region->uiblocks);
+ UI_blocklist_free_inactive(C, region);
}
/* checks which buttons are visible, sets flags to prevent draw (do after region init) */
diff --git a/source/blender/editors/interface/interface_region_search.cc b/source/blender/editors/interface/interface_region_search.cc
index eaf1ed3693b..f4c99fb3c16 100644
--- a/source/blender/editors/interface/interface_region_search.cc
+++ b/source/blender/editors/interface/interface_region_search.cc
@@ -106,17 +106,6 @@ struct uiSearchboxData {
#define SEARCH_ITEMS 10
-/**
- * Public function exported for functions that use #UI_BTYPE_SEARCH_MENU.
- *
- * \param items: Stores the items.
- * \param name: Text to display for the item.
- * \param poin: Opaque pointer (for use by the caller).
- * \param iconid: The icon, #ICON_NONE for no icon.
- * \param state: The buttons state flag, compatible with #uiBut.flag,
- * typically #UI_BUT_DISABLED / #UI_BUT_INACTIVE.
- * \return false if there is nothing to add.
- */
bool UI_search_item_add(uiSearchItems *items,
const char *name,
void *poin,
@@ -126,7 +115,7 @@ bool UI_search_item_add(uiSearchItems *items,
{
/* hijack for autocomplete */
if (items->autocpl) {
- UI_autocomplete_update_name(items->autocpl, name);
+ UI_autocomplete_update_name(items->autocpl, name + name_prefix_offset);
return true;
}
@@ -186,12 +175,12 @@ bool UI_search_item_add(uiSearchItems *items,
return true;
}
-int UI_searchbox_size_y(void)
+int UI_searchbox_size_y()
{
return SEARCH_ITEMS * UI_UNIT_Y + 2 * UI_POPUP_MENU_TOP;
}
-int UI_searchbox_size_x(void)
+int UI_searchbox_size_x()
{
return 12 * UI_UNIT_X;
}
@@ -289,7 +278,6 @@ int ui_searchbox_find_index(ARegion *region, const char *name)
return UI_search_items_find_index(&data->items, name);
}
-/* x and y in screen-coords. */
bool ui_searchbox_inside(ARegion *region, const int xy[2])
{
uiSearchboxData *data = static_cast<uiSearchboxData *>(region->regiondata);
@@ -297,7 +285,6 @@ bool ui_searchbox_inside(ARegion *region, const int xy[2])
return BLI_rcti_isect_pt(&data->bbox, xy[0] - region->winrct.xmin, xy[1] - region->winrct.ymin);
}
-/* string validated to be of correct length (but->hardmax) */
bool ui_searchbox_apply(uiBut *but, ARegion *region)
{
uiSearchboxData *data = static_cast<uiSearchboxData *>(region->regiondata);
@@ -326,13 +313,6 @@ bool ui_searchbox_apply(uiBut *but, ARegion *region)
return true;
}
- if (but->flag & UI_BUT_VALUE_CLEAR) {
- /* It is valid for _VALUE_CLEAR flavor to have no active element
- * (it's a valid way to unlink). */
- but->editstr[0] = '\0';
-
- return true;
- }
return false;
}
@@ -477,7 +457,6 @@ static void ui_searchbox_update_fn(bContext *C,
search_but->items_update_fn(C, search_but->arg, str, items, is_first_search);
}
-/* region is the search box itself */
void ui_searchbox_update(bContext *C, ARegion *region, uiBut *but, const bool reset)
{
uiButSearch *search_but = (uiButSearch *)but;
@@ -1032,8 +1011,6 @@ ARegion *ui_searchbox_create_menu(bContext *C, ARegion *butregion, uiButSearch *
return region;
}
-/* sets red alert if button holds a string it can't find */
-/* XXX weak: search_func adds all partial matches... */
void ui_but_search_refresh(uiButSearch *search_but)
{
uiBut *but = &search_but->but;
diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.c
index 0d8bdfc5817..e146443faaa 100644
--- a/source/blender/editors/interface/interface_region_tooltip.c
+++ b/source/blender/editors/interface/interface_region_tooltip.c
@@ -1466,10 +1466,6 @@ ARegion *UI_tooltip_create_from_button_or_extra_icon(
return region;
}
-/**
- * \param is_label: When true, show a small tip that only shows the name, otherwise show the full
- * tooltip.
- */
ARegion *UI_tooltip_create_from_button(bContext *C, ARegion *butregion, uiBut *but, bool is_label)
{
return UI_tooltip_create_from_button_or_extra_icon(C, butregion, but, NULL, is_label);
@@ -1542,13 +1538,6 @@ static uiTooltipData *ui_tooltip_data_from_search_item_tooltip_data(
return data;
}
-/**
- * Create a tooltip from search-item tooltip data \a item_tooltip data.
- * To be called from a callback set with #UI_but_func_search_set_tooltip().
- *
- * \param item_rect: Rectangle of the search item in search region space (#ui_searchbox_butrect())
- * which is passed to the tooltip callback.
- */
ARegion *UI_tooltip_create_from_search_item_generic(
bContext *C,
const ARegion *searchbox_region,
diff --git a/source/blender/editors/interface/interface_style.c b/source/blender/editors/interface/interface_style.c
index 8bb1e477506..643fa128d08 100644
--- a/source/blender/editors/interface/interface_style.c
+++ b/source/blender/editors/interface/interface_style.c
@@ -219,7 +219,6 @@ void UI_fontstyle_draw(const uiFontStyle *fs,
UI_fontstyle_draw_ex(fs, rect, str, col, fs_params, BLF_DRAW_STR_DUMMY_MAX, &xofs, &yofs, NULL);
}
-/* drawn same as above, but at 90 degree angle */
void UI_fontstyle_draw_rotated(const uiFontStyle *fs,
const rcti *rect,
const char *str,
@@ -279,12 +278,6 @@ void UI_fontstyle_draw_rotated(const uiFontStyle *fs,
}
}
-/**
- * Similar to #UI_fontstyle_draw
- * but ignore alignment, shadow & no clipping rect.
- *
- * For drawing on-screen labels.
- */
void UI_fontstyle_draw_simple(
const uiFontStyle *fs, float x, float y, const char *str, const uchar col[4])
{
@@ -294,9 +287,6 @@ void UI_fontstyle_draw_simple(
BLF_draw(fs->uifont_id, str, BLF_DRAW_STR_DUMMY_MAX);
}
-/**
- * Same as #UI_fontstyle_draw but draw a colored backdrop.
- */
void UI_fontstyle_draw_simple_backdrop(const uiFontStyle *fs,
float x,
float y,
@@ -331,7 +321,7 @@ void UI_fontstyle_draw_simple_backdrop(const uiFontStyle *fs,
}
/* ************** helpers ************************ */
-/* XXX: read a style configure */
+
const uiStyle *UI_style_get(void)
{
#if 0
@@ -344,7 +334,6 @@ const uiStyle *UI_style_get(void)
#endif
}
-/* for drawing, scaled with DPI setting */
const uiStyle *UI_style_get_dpi(void)
{
const uiStyle *style = UI_style_get();
@@ -376,16 +365,6 @@ int UI_fontstyle_string_width(const uiFontStyle *fs, const char *str)
return (int)BLF_width(fs->uifont_id, str, BLF_DRAW_STR_DUMMY_MAX);
}
-/**
- * Return the width of `str` with the spacing & kerning of `fs` with `aspect`
- * (representing #uiBlock.aspect) applied.
- *
- * When calculating text width, the UI layout logic calculate widths without scale,
- * only applying scale when drawing. This causes problems for fonts since kerning at
- * smaller sizes often makes them wider than a scaled down version of the larger text.
- * Resolve this by calculating the text at the on-screen size,
- * returning the result scaled back to 1:1. See T92361.
- */
int UI_fontstyle_string_width_with_block_aspect(const uiFontStyle *fs,
const char *str,
const float aspect)
@@ -415,8 +394,6 @@ int UI_fontstyle_height_max(const uiFontStyle *fs)
/* ************** init exit ************************ */
-/* called on each startup.blend read */
-/* reading without uifont will create one */
void uiStyleInit(void)
{
const uiStyle *style = U.uistyles.first;
diff --git a/source/blender/editors/interface/interface_template_asset_view.cc b/source/blender/editors/interface/interface_template_asset_view.cc
index 7b2fb8f784e..0a3cff5fa98 100644
--- a/source/blender/editors/interface/interface_template_asset_view.cc
+++ b/source/blender/editors/interface/interface_template_asset_view.cc
@@ -227,7 +227,7 @@ void uiTemplateAssetView(uiLayout *layout,
if ((display_flags & UI_TEMPLATE_ASSET_DRAW_NO_LIBRARY) == 0) {
uiItemFullR(row, asset_library_dataptr, asset_library_prop, RNA_NO_INDEX, 0, 0, "", 0);
if (asset_library_ref.type != ASSET_LIBRARY_LOCAL) {
- uiItemO(row, "", ICON_FILE_REFRESH, "ASSET_OT_list_refresh");
+ uiItemO(row, "", ICON_FILE_REFRESH, "ASSET_OT_library_refresh");
}
}
diff --git a/source/blender/editors/interface/interface_template_attribute_search.cc b/source/blender/editors/interface/interface_template_attribute_search.cc
index 85a6147432b..6d4b7a37bff 100644
--- a/source/blender/editors/interface/interface_template_attribute_search.cc
+++ b/source/blender/editors/interface/interface_template_attribute_search.cc
@@ -106,7 +106,7 @@ void attribute_search_add_items(StringRefNull str,
continue;
}
- BLI_string_search_add(search, item->name.c_str(), (void *)item);
+ BLI_string_search_add(search, item->name.c_str(), (void *)item, 0);
}
GeometryAttributeInfo **filtered_items;
diff --git a/source/blender/editors/interface/interface_template_list.cc b/source/blender/editors/interface/interface_template_list.cc
index 845a7813da2..13e539b5095 100644
--- a/source/blender/editors/interface/interface_template_list.cc
+++ b/source/blender/editors/interface/interface_template_list.cc
@@ -1276,9 +1276,6 @@ void uiTemplateList(uiLayout *layout,
nullptr);
}
-/**
- * \return: A RNA pointer for the operator properties.
- */
PointerRNA *UI_list_custom_activate_operator_set(uiList *ui_list,
const char *opname,
bool create_properties)
@@ -1298,9 +1295,6 @@ PointerRNA *UI_list_custom_activate_operator_set(uiList *ui_list,
return dyn_data->custom_activate_opptr;
}
-/**
- * \return: A RNA pointer for the operator properties.
- */
PointerRNA *UI_list_custom_drag_operator_set(uiList *ui_list,
const char *opname,
bool create_properties)
@@ -1325,7 +1319,7 @@ PointerRNA *UI_list_custom_drag_operator_set(uiList *ui_list,
/** \name List-types Registration
* \{ */
-void ED_uilisttypes_ui(void)
+void ED_uilisttypes_ui()
{
WM_uilisttype_add(UI_UL_asset_view());
}
diff --git a/source/blender/editors/interface/interface_template_search_menu.c b/source/blender/editors/interface/interface_template_search_menu.cc
index 26250e105eb..7a079e01e61 100644
--- a/source/blender/editors/interface/interface_template_search_menu.c
+++ b/source/blender/editors/interface/interface_template_search_menu.cc
@@ -21,8 +21,8 @@
* Accessed via the #WM_OT_search_menu operator.
*/
-#include <stdio.h>
-#include <string.h>
+#include <cstdio>
+#include <cstring>
#include "MEM_guardedalloc.h"
@@ -85,16 +85,16 @@ struct MenuSearch_Context {
};
struct MenuSearch_Parent {
- struct MenuSearch_Parent *parent;
+ MenuSearch_Parent *parent;
MenuType *parent_mt;
const char *drawstr;
/** Set while writing menu items only. */
- struct MenuSearch_Parent *temp_child;
+ MenuSearch_Parent *temp_child;
};
struct MenuSearch_Item {
- struct MenuSearch_Item *next, *prev;
+ MenuSearch_Item *next, *prev;
const char *drawstr;
const char *drawwstr_full;
/** Support a single level sub-menu nesting (for operator buttons that expand). */
@@ -102,12 +102,12 @@ struct MenuSearch_Item {
int icon;
int state;
- struct MenuSearch_Parent *menu_parent;
+ MenuSearch_Parent *menu_parent;
MenuType *mt;
- enum {
- MENU_SEARCH_TYPE_OP = 1,
- MENU_SEARCH_TYPE_RNA = 2,
+ enum Type {
+ Operator = 1,
+ RNA = 2,
} type;
union {
@@ -129,8 +129,8 @@ struct MenuSearch_Item {
} rna;
};
- /** Set when we need each menu item to be able to set its own context. may be NULL. */
- struct MenuSearch_Context *wm_context;
+ /** Set when we need each menu item to be able to set its own context. may be nullptr. */
+ MenuSearch_Context *wm_context;
};
struct MenuSearch_Data {
@@ -148,15 +148,15 @@ struct MenuSearch_Data {
static int menu_item_sort_by_drawstr_full(const void *menu_item_a_v, const void *menu_item_b_v)
{
- const struct MenuSearch_Item *menu_item_a = menu_item_a_v;
- const struct MenuSearch_Item *menu_item_b = menu_item_b_v;
+ const MenuSearch_Item *menu_item_a = (MenuSearch_Item *)menu_item_a_v;
+ const MenuSearch_Item *menu_item_b = (MenuSearch_Item *)menu_item_b_v;
return strcmp(menu_item_a->drawwstr_full, menu_item_b->drawwstr_full);
}
static const char *strdup_memarena(MemArena *memarena, const char *str)
{
const uint str_size = strlen(str) + 1;
- char *str_dst = BLI_memarena_alloc(memarena, str_size);
+ char *str_dst = (char *)BLI_memarena_alloc(memarena, str_size);
memcpy(str_dst, str, str_size);
return str_dst;
}
@@ -164,50 +164,53 @@ static const char *strdup_memarena(MemArena *memarena, const char *str)
static const char *strdup_memarena_from_dynstr(MemArena *memarena, DynStr *dyn_str)
{
const uint str_size = BLI_dynstr_get_len(dyn_str) + 1;
- char *str_dst = BLI_memarena_alloc(memarena, str_size);
+ char *str_dst = (char *)BLI_memarena_alloc(memarena, str_size);
BLI_dynstr_get_cstring_ex(dyn_str, str_dst);
return str_dst;
}
-static bool menu_items_from_ui_create_item_from_button(struct MenuSearch_Data *data,
+static bool menu_items_from_ui_create_item_from_button(MenuSearch_Data *data,
MemArena *memarena,
struct MenuType *mt,
const char *drawstr_submenu,
uiBut *but,
- struct MenuSearch_Context *wm_context)
+ MenuSearch_Context *wm_context)
{
- struct MenuSearch_Item *item = NULL;
+ MenuSearch_Item *item = nullptr;
/* Use override if the name is empty, this can happen with popovers. */
- const char *drawstr_override = NULL;
+ const char *drawstr_override = nullptr;
const char *drawstr_sep = (but->flag & UI_BUT_HAS_SEP_CHAR) ?
strrchr(but->drawstr, UI_SEP_CHAR) :
- NULL;
+ nullptr;
const bool drawstr_is_empty = (drawstr_sep == but->drawstr) || (but->drawstr[0] == '\0');
- if (but->optype != NULL) {
+ if (but->optype != nullptr) {
if (drawstr_is_empty) {
drawstr_override = WM_operatortype_name(but->optype, but->opptr);
}
- item = BLI_memarena_calloc(memarena, sizeof(*item));
- item->type = MENU_SEARCH_TYPE_OP;
+ item = (MenuSearch_Item *)BLI_memarena_calloc(memarena, sizeof(*item));
+ item->type = MenuSearch_Item::Type::Operator;
item->op.type = but->optype;
item->op.opcontext = but->opcontext;
item->op.context = but->context;
item->op.opptr = but->opptr;
- but->opptr = NULL;
+ but->opptr = nullptr;
}
- else if (but->rnaprop != NULL) {
+ else if (but->rnaprop != nullptr) {
const int prop_type = RNA_property_type(but->rnaprop);
if (drawstr_is_empty) {
if (prop_type == PROP_ENUM) {
const int value_enum = (int)but->hardmax;
EnumPropertyItem enum_item;
- if (RNA_property_enum_item_from_value_gettexted(
- but->block->evil_C, &but->rnapoin, but->rnaprop, value_enum, &enum_item)) {
+ if (RNA_property_enum_item_from_value_gettexted((bContext *)but->block->evil_C,
+ &but->rnapoin,
+ but->rnaprop,
+ value_enum,
+ &enum_item)) {
drawstr_override = enum_item.name;
}
else {
@@ -229,8 +232,8 @@ static bool menu_items_from_ui_create_item_from_button(struct MenuSearch_Data *d
prop_type);
}
else {
- item = BLI_memarena_calloc(memarena, sizeof(*item));
- item->type = MENU_SEARCH_TYPE_RNA;
+ item = (MenuSearch_Item *)BLI_memarena_calloc(memarena, sizeof(*item));
+ item->type = MenuSearch_Item::Type::RNA;
item->rna.ptr = but->rnapoin;
item->rna.prop = but->rnaprop;
@@ -242,13 +245,12 @@ static bool menu_items_from_ui_create_item_from_button(struct MenuSearch_Data *d
}
}
- if (item != NULL) {
+ if (item != nullptr) {
/* Handle shared settings. */
- if (drawstr_override != NULL) {
+ if (drawstr_override != nullptr) {
const char *drawstr_suffix = drawstr_sep ? drawstr_sep : "";
- char *drawstr_alloc = BLI_string_joinN("(", drawstr_override, ")", drawstr_suffix);
- item->drawstr = strdup_memarena(memarena, drawstr_alloc);
- MEM_freeN(drawstr_alloc);
+ std::string drawstr = std::string("(") + drawstr_override + ")" + drawstr_suffix;
+ item->drawstr = strdup_memarena(memarena, drawstr.c_str());
}
else {
item->drawstr = strdup_memarena(memarena, but->drawstr);
@@ -258,7 +260,7 @@ static bool menu_items_from_ui_create_item_from_button(struct MenuSearch_Data *d
item->state = (but->flag &
(UI_BUT_DISABLED | UI_BUT_INACTIVE | UI_BUT_REDALERT | UI_BUT_HAS_SEP_CHAR));
item->mt = mt;
- item->drawstr_submenu = drawstr_submenu ? strdup_memarena(memarena, drawstr_submenu) : NULL;
+ item->drawstr_submenu = drawstr_submenu ? strdup_memarena(memarena, drawstr_submenu) : nullptr;
item->wm_context = wm_context;
@@ -272,11 +274,11 @@ static bool menu_items_from_ui_create_item_from_button(struct MenuSearch_Data *d
/**
* Populate a fake button from a menu item (use for context menu).
*/
-static bool menu_items_to_ui_button(struct MenuSearch_Item *item, uiBut *but)
+static bool menu_items_to_ui_button(MenuSearch_Item *item, uiBut *but)
{
bool changed = false;
switch (item->type) {
- case MENU_SEARCH_TYPE_OP: {
+ case MenuSearch_Item::Type::Operator: {
but->optype = item->op.type;
but->opcontext = item->op.opcontext;
but->context = item->op.context;
@@ -284,7 +286,7 @@ static bool menu_items_to_ui_button(struct MenuSearch_Item *item, uiBut *but)
changed = true;
break;
}
- case MENU_SEARCH_TYPE_RNA: {
+ case MenuSearch_Item::Type::RNA: {
const int prop_type = RNA_property_type(item->rna.prop);
but->rnapoin = item->rna.ptr;
@@ -302,12 +304,12 @@ static bool menu_items_to_ui_button(struct MenuSearch_Item *item, uiBut *but)
if (changed) {
STRNCPY(but->drawstr, item->drawstr);
char *drawstr_sep = (item->state & UI_BUT_HAS_SEP_CHAR) ? strrchr(but->drawstr, UI_SEP_CHAR) :
- NULL;
+ nullptr;
if (drawstr_sep) {
*drawstr_sep = '\0';
}
- but->icon = item->icon;
+ but->icon = (BIFIconID)item->icon;
but->str = but->strdata;
}
@@ -327,13 +329,13 @@ static void menu_types_add_from_keymap_items(bContext *C,
{
wmWindowManager *wm = CTX_wm_manager(C);
ListBase *handlers[] = {
- region ? &region->handlers : NULL,
- area ? &area->handlers : NULL,
+ region ? &region->handlers : nullptr,
+ area ? &area->handlers : nullptr,
&win->handlers,
};
for (int handler_index = 0; handler_index < ARRAY_SIZE(handlers); handler_index++) {
- if (handlers[handler_index] == NULL) {
+ if (handlers[handler_index] == nullptr) {
continue;
}
LISTBASE_FOREACH (wmEventHandler *, handler_base, handlers[handler_index]) {
@@ -345,7 +347,7 @@ static void menu_types_add_from_keymap_items(bContext *C,
continue;
}
- if (handler_base->poll == NULL || handler_base->poll(region, win->eventstate)) {
+ if (handler_base->poll == nullptr || handler_base->poll(region, win->eventstate)) {
wmEventHandler_Keymap *handler = (wmEventHandler_Keymap *)handler_base;
wmEventHandler_KeymapResult km_result;
WM_event_get_keymaps_from_handler(wm, win, handler, &km_result);
@@ -382,16 +384,16 @@ static void menu_types_add_from_keymap_items(bContext *C,
/**
* Display all operators (last). Developer-only convenience feature.
*/
-static void menu_items_from_all_operators(bContext *C, struct MenuSearch_Data *data)
+static void menu_items_from_all_operators(bContext *C, MenuSearch_Data *data)
{
/* Add to temporary list so we can sort them separately. */
- ListBase operator_items = {NULL, NULL};
+ ListBase operator_items = {nullptr, nullptr};
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);
+ wmOperatorType *ot = (wmOperatorType *)BLI_ghashIterator_getValue(&iter);
if ((ot->flag & OPTYPE_INTERNAL) && (G.debug & G_DEBUG_WM) == 0) {
continue;
@@ -400,13 +402,13 @@ static void menu_items_from_all_operators(bContext *C, struct MenuSearch_Data *d
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;
+ MenuSearch_Item *item = nullptr;
+ item = (MenuSearch_Item *)BLI_memarena_calloc(memarena, sizeof(*item));
+ item->type = MenuSearch_Item::Type::Operator;
item->op.type = ot;
item->op.opcontext = WM_OP_INVOKE_DEFAULT;
- item->op.context = NULL;
+ item->op.context = nullptr;
char idname_as_py[OP_MAX_TYPENAME];
char uiname[256];
@@ -417,7 +419,7 @@ static void menu_items_from_all_operators(bContext *C, struct MenuSearch_Data *d
item->drawwstr_full = strdup_memarena(memarena, uiname);
item->drawstr = ot_ui_name;
- item->wm_context = NULL;
+ item->wm_context = nullptr;
BLI_addtail(&operator_items, item);
}
@@ -434,7 +436,7 @@ static void menu_items_from_all_operators(bContext *C, struct MenuSearch_Data *d
* - Look up predefined editor-menus.
* - Look up key-map items which call menus.
*/
-static struct MenuSearch_Data *menu_items_from_ui_create(
+static MenuSearch_Data *menu_items_from_ui_create(
bContext *C, wmWindow *win, ScrArea *area_init, ARegion *region_init, bool include_all_areas)
{
MemArena *memarena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
@@ -444,12 +446,12 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
const uiStyle *style = UI_style_get_dpi();
/* Convert into non-ui structure. */
- struct MenuSearch_Data *data = MEM_callocN(sizeof(*data), __func__);
+ MenuSearch_Data *data = (MenuSearch_Data *)MEM_callocN(sizeof(*data), __func__);
DynStr *dyn_str = BLI_dynstr_new_memarena();
/* Use a stack of menus to handle and discover new menus in passes. */
- LinkNode *menu_stack = NULL;
+ LinkNode *menu_stack = nullptr;
/* Tag menu types not to add, either because they have already been added
* or they have been blacklisted.
@@ -466,7 +468,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
};
for (int i = 0; i < ARRAY_SIZE(idname_array); i++) {
MenuType *mt = WM_menutype_find(idname_array[i], false);
- if (mt != NULL) {
+ if (mt != nullptr) {
BLI_gset_add(menu_tagged, mt);
}
}
@@ -483,7 +485,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
for (WM_menutype_iter(&iter); (!BLI_ghashIterator_done(&iter));
(BLI_ghashIterator_step(&iter))) {
- MenuType *mt = BLI_ghashIterator_getValue(&iter);
+ MenuType *mt = (MenuType *)BLI_ghashIterator_getValue(&iter);
if (BLI_str_endswith(mt->idname, "_context_menu")) {
BLI_gset_add(menu_tagged, mt);
}
@@ -494,34 +496,33 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
};
for (int i = 0; i < ARRAY_SIZE(idname_array); i++) {
MenuType *mt = WM_menutype_find(idname_array[i], false);
- if (mt != NULL) {
- BLI_gset_remove(menu_tagged, mt, NULL);
+ if (mt != nullptr) {
+ BLI_gset_remove(menu_tagged, mt, nullptr);
}
}
}
/* Collect contexts, one for each 'ui_type'. */
- struct MenuSearch_Context *wm_contexts = NULL;
+ MenuSearch_Context *wm_contexts = nullptr;
- const EnumPropertyItem *space_type_ui_items = NULL;
+ const EnumPropertyItem *space_type_ui_items = nullptr;
int space_type_ui_items_len = 0;
bool space_type_ui_items_free = false;
/* Text used as prefix for top-bar menu items. */
- const char *global_menu_prefix = NULL;
+ const char *global_menu_prefix = nullptr;
if (include_all_areas) {
bScreen *screen = WM_window_get_active_screen(win);
/* First create arrays for ui_type. */
- PropertyRNA *prop_ui_type = NULL;
+ PropertyRNA *prop_ui_type = nullptr;
{
/* This must be a valid pointer, with only it's type checked. */
- ScrArea area_dummy = {
- /* Anything besides #SPACE_EMPTY is fine,
- * as this value is only included in the enum when set. */
- .spacetype = SPACE_TOPBAR,
- };
+ ScrArea area_dummy = {nullptr};
+ /* Anything besides #SPACE_EMPTY is fine,
+ * as this value is only included in the enum when set. */
+ area_dummy.spacetype = SPACE_TOPBAR;
PointerRNA ptr;
RNA_pointer_create(&screen->id, &RNA_Area, &area_dummy, &ptr);
prop_ui_type = RNA_struct_find_property(&ptr, "ui_type");
@@ -532,7 +533,8 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
&space_type_ui_items_len,
&space_type_ui_items_free);
- wm_contexts = BLI_memarena_calloc(memarena, sizeof(*wm_contexts) * space_type_ui_items_len);
+ wm_contexts = (MenuSearch_Context *)BLI_memarena_calloc(
+ memarena, sizeof(*wm_contexts) * space_type_ui_items_len);
for (int i = 0; i < space_type_ui_items_len; i++) {
wm_contexts[i].space_type_ui_index = -1;
}
@@ -540,7 +542,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
- if (region != NULL) {
+ if (region != nullptr) {
PointerRNA ptr;
RNA_pointer_create(&screen->id, &RNA_Area, area, &ptr);
const int space_type_ui = RNA_property_enum_get(&ptr, prop_ui_type);
@@ -573,16 +575,16 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
for (int space_type_ui_index = -1; space_type_ui_index < space_type_ui_items_len;
space_type_ui_index += 1) {
- ScrArea *area = NULL;
- ARegion *region = NULL;
- struct MenuSearch_Context *wm_context = NULL;
+ ScrArea *area = nullptr;
+ ARegion *region = nullptr;
+ MenuSearch_Context *wm_context = nullptr;
if (include_all_areas) {
if (space_type_ui_index == -1) {
/* First run without any context, to populate the top-bar without. */
- wm_context = NULL;
- area = NULL;
- region = NULL;
+ wm_context = nullptr;
+ area = nullptr;
+ region = nullptr;
}
else {
wm_context = &wm_contexts[space_type_ui_index];
@@ -607,7 +609,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
* from the buttons, however this is quite involved and can be avoided as by convention
* each space-type has a single root-menu that headers use. */
{
- const char *idname_array[2] = {NULL};
+ const char *idname_array[2] = {nullptr};
int idname_array_len = 0;
/* Use negative for global (no area) context, populate the top-bar. */
@@ -623,8 +625,8 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
case space_type: \
break
- if (area != NULL) {
- SpaceLink *sl = area->spacedata.first;
+ if (area != nullptr) {
+ SpaceLink *sl = (SpaceLink *)area->spacedata.first;
switch ((eSpace_Type)area->spacetype) {
SPACE_MENU_MAP(SPACE_VIEW3D, "VIEW3D_MT_editor_menus");
SPACE_MENU_MAP(SPACE_GRAPH, "GRAPH_MT_editor_menus");
@@ -656,7 +658,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
}
for (int i = 0; i < idname_array_len; i++) {
MenuType *mt = WM_menutype_find(idname_array[i], false);
- if (mt != NULL) {
+ if (mt != nullptr) {
/* Check if this exists because of 'include_all_areas'. */
if (BLI_gset_add(menu_tagged, mt)) {
BLI_linklist_prepend(&menu_stack, mt);
@@ -669,8 +671,8 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
bool has_keymap_menu_items = false;
- while (menu_stack != NULL) {
- MenuType *mt = BLI_linklist_pop(&menu_stack);
+ while (menu_stack != nullptr) {
+ MenuType *mt = (MenuType *)BLI_linklist_pop(&menu_stack);
if (!WM_menutype_poll(C, mt)) {
continue;
}
@@ -687,7 +689,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
UI_block_end(C, block);
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
- MenuType *mt_from_but = NULL;
+ MenuType *mt_from_but = nullptr;
/* Support menu titles with dynamic from initial labels
* (used by edit-mesh context menu). */
if (but->type == UI_BTYPE_LABEL) {
@@ -698,13 +700,13 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
but_test = but_test->prev;
}
- if (but_test == NULL) {
+ if (but_test == nullptr) {
BLI_ghash_insert(
menu_display_name_map, mt, (void *)strdup_memarena(memarena, but->drawstr));
}
}
else if (menu_items_from_ui_create_item_from_button(
- data, memarena, mt, NULL, but, wm_context)) {
+ data, memarena, mt, nullptr, but, wm_context)) {
/* pass */
}
else if ((mt_from_but = UI_but_menutype_get(but))) {
@@ -714,8 +716,8 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
}
if (!BLI_ghash_haskey(menu_parent_map, mt_from_but)) {
- struct MenuSearch_Parent *menu_parent = BLI_memarena_calloc(memarena,
- sizeof(*menu_parent));
+ MenuSearch_Parent *menu_parent = (MenuSearch_Parent *)BLI_memarena_calloc(
+ memarena, sizeof(*menu_parent));
/* Use brackets for menu key shortcuts,
* converting "Text|Some-Shortcut" to "Text (Some-Shortcut)".
* This is needed so we don't right align sub-menu contents
@@ -723,9 +725,9 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
*/
const char *drawstr_sep = but->flag & UI_BUT_HAS_SEP_CHAR ?
strrchr(but->drawstr, UI_SEP_CHAR) :
- NULL;
+ nullptr;
bool drawstr_is_empty = false;
- if (drawstr_sep != NULL) {
+ if (drawstr_sep != nullptr) {
BLI_assert(BLI_dynstr_get_len(dyn_str) == 0);
/* Detect empty string, fallback to menu name. */
const char *drawstr = but->drawstr;
@@ -760,7 +762,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
}
}
}
- else if (but->menu_create_func != NULL) {
+ else if (but->menu_create_func != nullptr) {
/* A non 'MenuType' menu button. */
/* Only expand one level deep, this is mainly for expanding operator menus. */
@@ -785,19 +787,21 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
}
if (region) {
+ BLI_ghash_remove(region->runtime.block_name_map, sub_block->name, nullptr, nullptr);
BLI_remlink(&region->uiblocks, sub_block);
}
- UI_block_free(NULL, sub_block);
+ UI_block_free(nullptr, sub_block);
}
}
if (region) {
+ BLI_ghash_remove(region->runtime.block_name_map, block->name, nullptr, nullptr);
BLI_remlink(&region->uiblocks, block);
}
- UI_block_free(NULL, block);
+ UI_block_free(nullptr, block);
/* Add key-map items as a second pass,
* so all menus are accessed from the header & top-bar before key shortcuts are expanded. */
- if ((menu_stack == NULL) && (has_keymap_menu_items == false)) {
+ if ((menu_stack == nullptr) && (has_keymap_menu_items == false)) {
has_keymap_menu_items = true;
menu_types_add_from_keymap_items(
C, win, area, region, &menu_stack, menu_to_kmi, menu_tagged);
@@ -805,33 +809,34 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
}
}
- LISTBASE_FOREACH (struct MenuSearch_Item *, item, &data->items) {
- item->menu_parent = BLI_ghash_lookup(menu_parent_map, item->mt);
+ LISTBASE_FOREACH (MenuSearch_Item *, item, &data->items) {
+ item->menu_parent = (MenuSearch_Parent *)BLI_ghash_lookup(menu_parent_map, item->mt);
}
GHASH_ITER (iter, menu_parent_map) {
- struct MenuSearch_Parent *menu_parent = BLI_ghashIterator_getValue(&iter);
- menu_parent->parent = BLI_ghash_lookup(menu_parent_map, menu_parent->parent_mt);
+ MenuSearch_Parent *menu_parent = (MenuSearch_Parent *)BLI_ghashIterator_getValue(&iter);
+ menu_parent->parent = (MenuSearch_Parent *)BLI_ghash_lookup(menu_parent_map,
+ menu_parent->parent_mt);
}
/* NOTE: currently this builds the full path for each menu item,
* that could be moved into the parent menu. */
/* Set names as full paths. */
- LISTBASE_FOREACH (struct MenuSearch_Item *, item, &data->items) {
+ LISTBASE_FOREACH (MenuSearch_Item *, item, &data->items) {
BLI_assert(BLI_dynstr_get_len(dyn_str) == 0);
if (include_all_areas) {
BLI_dynstr_appendf(dyn_str,
"%s: ",
- (item->wm_context != NULL) ?
+ (item->wm_context != nullptr) ?
space_type_ui_items[item->wm_context->space_type_ui_index].name :
global_menu_prefix);
}
- if (item->menu_parent != NULL) {
- struct MenuSearch_Parent *menu_parent = item->menu_parent;
- menu_parent->temp_child = NULL;
+ if (item->menu_parent != nullptr) {
+ MenuSearch_Parent *menu_parent = item->menu_parent;
+ menu_parent->temp_child = nullptr;
while (menu_parent && menu_parent->parent) {
menu_parent->parent->temp_child = menu_parent;
menu_parent = menu_parent->parent;
@@ -843,14 +848,14 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
}
}
else {
- const char *drawstr = BLI_ghash_lookup(menu_display_name_map, item->mt);
- if (drawstr == NULL) {
+ const char *drawstr = (const char *)BLI_ghash_lookup(menu_display_name_map, item->mt);
+ if (drawstr == nullptr) {
drawstr = CTX_IFACE_(item->mt->translation_context, item->mt->label);
}
BLI_dynstr_append(dyn_str, drawstr);
- wmKeyMapItem *kmi = BLI_ghash_lookup(menu_to_kmi, item->mt);
- if (kmi != NULL) {
+ wmKeyMapItem *kmi = (wmKeyMapItem *)BLI_ghash_lookup(menu_to_kmi, item->mt);
+ if (kmi != nullptr) {
char kmi_str[128];
WM_keymap_item_to_string(kmi, false, kmi_str, sizeof(kmi_str));
BLI_dynstr_appendf(dyn_str, " (%s)", kmi_str);
@@ -860,7 +865,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
}
/* Optional nested menu. */
- if (item->drawstr_submenu != NULL) {
+ if (item->drawstr_submenu != nullptr) {
BLI_dynstr_append(dyn_str, item->drawstr_submenu);
BLI_dynstr_append(dyn_str, " " UI_MENU_ARROW_SEP " ");
}
@@ -877,12 +882,12 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
* NOTE: we might want to keep the in-menu order, for now sort all. */
BLI_listbase_sort(&data->items, menu_item_sort_by_drawstr_full);
- BLI_ghash_free(menu_parent_map, NULL, NULL);
- BLI_ghash_free(menu_display_name_map, NULL, NULL);
+ BLI_ghash_free(menu_parent_map, nullptr, nullptr);
+ BLI_ghash_free(menu_display_name_map, nullptr, nullptr);
- BLI_ghash_free(menu_to_kmi, NULL, NULL);
+ BLI_ghash_free(menu_to_kmi, nullptr, nullptr);
- BLI_gset_free(menu_tagged, NULL);
+ BLI_gset_free(menu_tagged, nullptr);
data->memarena = memarena;
@@ -915,16 +920,16 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
static void menu_search_arg_free_fn(void *data_v)
{
- struct MenuSearch_Data *data = data_v;
- LISTBASE_FOREACH (struct MenuSearch_Item *, item, &data->items) {
+ MenuSearch_Data *data = (MenuSearch_Data *)data_v;
+ LISTBASE_FOREACH (MenuSearch_Item *, item, &data->items) {
switch (item->type) {
- case MENU_SEARCH_TYPE_OP: {
- if (item->op.opptr != NULL) {
+ case MenuSearch_Item::Type::Operator: {
+ if (item->op.opptr != nullptr) {
WM_operator_properties_free(item->op.opptr);
MEM_freeN(item->op.opptr);
}
}
- case MENU_SEARCH_TYPE_RNA: {
+ case MenuSearch_Item::Type::RNA: {
break;
}
}
@@ -937,8 +942,8 @@ static void menu_search_arg_free_fn(void *data_v)
static void menu_search_exec_fn(bContext *C, void *UNUSED(arg1), void *arg2)
{
- struct MenuSearch_Item *item = arg2;
- if (item == NULL) {
+ MenuSearch_Item *item = (MenuSearch_Item *)arg2;
+ if (item == nullptr) {
return;
}
if (item->state & UI_BUT_DISABLED) {
@@ -948,20 +953,20 @@ static void menu_search_exec_fn(bContext *C, void *UNUSED(arg1), void *arg2)
ScrArea *area_prev = CTX_wm_area(C);
ARegion *region_prev = CTX_wm_region(C);
- if (item->wm_context != NULL) {
+ if (item->wm_context != nullptr) {
CTX_wm_area_set(C, item->wm_context->area);
CTX_wm_region_set(C, item->wm_context->region);
}
switch (item->type) {
- case MENU_SEARCH_TYPE_OP: {
+ case MenuSearch_Item::Type::Operator: {
CTX_store_set(C, item->op.context);
WM_operator_name_call_ptr_with_depends_on_cursor(
C, item->op.type, item->op.opcontext, item->op.opptr, item->drawstr);
- CTX_store_set(C, NULL);
+ CTX_store_set(C, nullptr);
break;
}
- case MENU_SEARCH_TYPE_RNA: {
+ case MenuSearch_Item::Type::RNA: {
PointerRNA *ptr = &item->rna.ptr;
PropertyRNA *prop = item->rna.prop;
const int index = item->rna.index;
@@ -992,7 +997,7 @@ static void menu_search_exec_fn(bContext *C, void *UNUSED(arg1), void *arg2)
}
}
- if (item->wm_context != NULL) {
+ if (item->wm_context != nullptr) {
CTX_wm_area_set(C, area_prev);
CTX_wm_region_set(C, region_prev);
}
@@ -1004,19 +1009,19 @@ static void menu_search_update_fn(const bContext *UNUSED(C),
uiSearchItems *items,
const bool UNUSED(is_first))
{
- struct MenuSearch_Data *data = arg;
+ MenuSearch_Data *data = (MenuSearch_Data *)arg;
StringSearch *search = BLI_string_search_new();
- LISTBASE_FOREACH (struct MenuSearch_Item *, item, &data->items) {
- BLI_string_search_add(search, item->drawwstr_full, item);
+ LISTBASE_FOREACH (MenuSearch_Item *, item, &data->items) {
+ BLI_string_search_add(search, item->drawwstr_full, item, 0);
}
- struct MenuSearch_Item **filtered_items;
+ MenuSearch_Item **filtered_items;
const int filtered_amount = BLI_string_search_query(search, str, (void ***)&filtered_items);
for (int i = 0; i < filtered_amount; i++) {
- struct MenuSearch_Item *item = filtered_items[i];
+ MenuSearch_Item *item = filtered_items[i];
if (!UI_search_item_add(items, item->drawwstr_full, item, item->icon, item->state, 0)) {
break;
}
@@ -1041,8 +1046,8 @@ static bool ui_search_menu_create_context_menu(struct bContext *C,
void *active,
const struct wmEvent *event)
{
- struct MenuSearch_Data *data = arg;
- struct MenuSearch_Item *item = active;
+ MenuSearch_Data *data = (MenuSearch_Data *)arg;
+ MenuSearch_Item *item = (MenuSearch_Item *)active;
bool has_menu = false;
memset(&data->context_menu_data, 0x0, sizeof(data->context_menu_data));
@@ -1055,7 +1060,7 @@ static bool ui_search_menu_create_context_menu(struct bContext *C,
ScrArea *area_prev = CTX_wm_area(C);
ARegion *region_prev = CTX_wm_region(C);
- if (item->wm_context != NULL) {
+ if (item->wm_context != nullptr) {
CTX_wm_area_set(C, item->wm_context->area);
CTX_wm_region_set(C, item->wm_context->region);
}
@@ -1064,7 +1069,7 @@ static bool ui_search_menu_create_context_menu(struct bContext *C,
has_menu = true;
}
- if (item->wm_context != NULL) {
+ if (item->wm_context != nullptr) {
CTX_wm_area_set(C, area_prev);
CTX_wm_region_set(C, region_prev);
}
@@ -1085,8 +1090,8 @@ static struct ARegion *ui_search_menu_create_tooltip(struct bContext *C,
void *arg,
void *active)
{
- struct MenuSearch_Data *data = arg;
- struct MenuSearch_Item *item = active;
+ MenuSearch_Data *data = (MenuSearch_Data *)arg;
+ MenuSearch_Item *item = (MenuSearch_Item *)active;
memset(&data->context_menu_data, 0x0, sizeof(data->context_menu_data));
uiBut *but = &data->context_menu_data.but;
@@ -1112,21 +1117,21 @@ static struct ARegion *ui_search_menu_create_tooltip(struct bContext *C,
ScrArea *area_prev = CTX_wm_area(C);
ARegion *region_prev = CTX_wm_region(C);
- if (item->wm_context != NULL) {
+ if (item->wm_context != nullptr) {
CTX_wm_area_set(C, item->wm_context->area);
CTX_wm_region_set(C, item->wm_context->region);
}
ARegion *region_tip = UI_tooltip_create_from_button(C, region, but, false);
- if (item->wm_context != NULL) {
+ if (item->wm_context != nullptr) {
CTX_wm_area_set(C, area_prev);
CTX_wm_region_set(C, region_prev);
}
return region_tip;
}
- return NULL;
+ return nullptr;
}
/** \} */
@@ -1137,14 +1142,13 @@ static struct ARegion *ui_search_menu_create_tooltip(struct bContext *C,
void UI_but_func_menu_search(uiBut *but)
{
- bContext *C = but->block->evil_C;
+ bContext *C = (bContext *)but->block->evil_C;
wmWindow *win = CTX_wm_window(C);
ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
/* When run from top-bar scan all areas in the current window. */
const bool include_all_areas = (area && (area->spacetype == SPACE_TOPBAR));
- struct MenuSearch_Data *data = menu_items_from_ui_create(
- C, win, area, region, include_all_areas);
+ MenuSearch_Data *data = menu_items_from_ui_create(C, win, area, region, include_all_areas);
UI_but_func_search_set(but,
/* Generic callback. */
ui_searchbox_create_menu,
@@ -1153,7 +1157,7 @@ void UI_but_func_menu_search(uiBut *but)
false,
menu_search_arg_free_fn,
menu_search_exec_fn,
- NULL);
+ nullptr);
UI_but_func_search_set_context_menu(but, ui_search_menu_create_context_menu);
UI_but_func_search_set_tooltip(but, ui_search_menu_create_tooltip);
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index b30a86c5fcf..b8026cbb40c 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -435,7 +435,7 @@ static void id_search_cb(const bContext *C,
/* ID listbase */
LISTBASE_FOREACH (ID *, id, lb) {
if (id_search_allows_id(template_ui, flag, id, str)) {
- BLI_string_search_add(search, id->name + 2, id);
+ BLI_string_search_add(search, id->name + 2, id, 0);
}
}
@@ -470,7 +470,7 @@ static void id_search_cb_tagged(const bContext *C,
LISTBASE_FOREACH (ID *, id, lb) {
if (id->tag & LIB_TAG_DOIT) {
if (id_search_allows_id(template_ui, flag, id, str)) {
- BLI_string_search_add(search, id->name + 2, id);
+ BLI_string_search_add(search, id->name + 2, id, 0);
}
id->tag &= ~LIB_TAG_DOIT;
}
@@ -585,7 +585,6 @@ static uiBlock *id_search_menu(bContext *C, ARegion *region, void *arg_litem)
/* This is for browsing and editing the ID-blocks used */
-/* for new/open operators */
void UI_context_active_but_prop_get_templateID(bContext *C,
PointerRNA *r_ptr,
PropertyRNA **r_prop)
@@ -1556,9 +1555,6 @@ void uiTemplateGpencilColorPreview(uiLayout *layout,
false);
}
-/**
- * Version of #uiTemplateID using tabs.
- */
void uiTemplateIDTabs(uiLayout *layout,
bContext *C,
PointerRNA *ptr,
@@ -1592,14 +1588,6 @@ void uiTemplateIDTabs(uiLayout *layout,
/** \name ID Chooser Template
* \{ */
-/**
- * This is for selecting the type of ID-block to use,
- * and then from the relevant type choosing the block to use.
- *
- * \param propname: property identifier for property that ID-pointer gets stored to.
- * \param proptypename: property identifier for property
- * used to determine the type of ID-pointer that can be used.
- */
void uiTemplateAnyID(uiLayout *layout,
PointerRNA *ptr,
const char *propname,
@@ -1855,10 +1843,6 @@ static TemplateSearch *template_search_setup(PointerRNA *ptr,
return template_search;
}
-/**
- * Search menu to pick an item from a collection.
- * A version of uiTemplateID that works for non-ID types.
- */
void uiTemplateSearch(uiLayout *layout,
bContext *C,
PointerRNA *ptr,
@@ -1909,13 +1893,6 @@ void uiTemplateSearchPreview(uiLayout *layout,
/* ---------- */
-/**
- * This is creating/editing RNA-Paths
- *
- * - ptr: struct which holds the path property
- * - propname: property identifier for property that path gets stored to
- * - root_ptr: struct that path gets built from
- */
void uiTemplatePathBuilder(uiLayout *layout,
PointerRNA *ptr,
const char *propname,
@@ -2102,9 +2079,6 @@ static void bone_constraint_panel_id(void *md_link, char *r_name)
strcat(r_name, cti->structName);
}
-/**
- * Check if the constraint panels don't match the data and rebuild the panels if so.
- */
void uiTemplateConstraints(uiLayout *UNUSED(layout), bContext *C, bool use_bone_constraints)
{
ARegion *region = CTX_wm_region(C);
@@ -2260,8 +2234,6 @@ void uiTemplateGpencilModifiers(uiLayout *UNUSED(layout), bContext *C)
/** \} */
-/** \} */
-
#define ERROR_LIBDATA_MESSAGE TIP_("Can't edit external library data")
/* -------------------------------------------------------------------- */
@@ -2280,9 +2252,6 @@ static void shaderfx_panel_id(void *fx_v, char *r_idname)
BKE_shaderfxType_panel_id(fx->type, r_idname);
}
-/**
- * Check if the shader effect panels don't match the data and rebuild the panels if so.
- */
void uiTemplateShaderFx(uiLayout *UNUSED(layout), bContext *C)
{
ARegion *region = CTX_wm_region(C);
@@ -2564,11 +2533,6 @@ static bool ui_layout_operator_properties_only_booleans(const bContext *C,
return true;
}
-/**
- * Draw Operator property buttons for redoing execution with different settings.
- * This function does not initialize the layout,
- * functions can be called on the layout before and after.
- */
void uiTemplateOperatorPropertyButs(
const bContext *C, uiLayout *layout, wmOperator *op, eButLabelAlign label_align, short flag)
{
@@ -2727,7 +2691,12 @@ static void draw_constraint_header(uiLayout *layout, Object *ob, bConstraint *co
PointerRNA ptr;
RNA_pointer_create(&ob->id, &RNA_Constraint, con, &ptr);
- uiLayoutSetContextPointer(layout, "constraint", &ptr);
+ if (block->panel) {
+ UI_panel_context_pointer_set(block->panel, "constraint", &ptr);
+ }
+ else {
+ uiLayoutSetContextPointer(layout, "constraint", &ptr);
+ }
/* Constraint type icon. */
uiLayout *sub = uiLayoutRow(layout, false);
@@ -3532,9 +3501,6 @@ void uiTemplateColorRamp(uiLayout *layout, PointerRNA *ptr, const char *propname
/** \name Icon Template
* \{ */
-/**
- * \param icon_scale: Scale of the icon, 1x == button height.
- */
void uiTemplateIcon(uiLayout *layout, int icon_value, float icon_scale)
{
uiBlock *block = uiLayoutAbsoluteBlock(layout);
@@ -3643,9 +3609,6 @@ static uiBlock *ui_icon_view_menu_cb(bContext *C, ARegion *region, void *arg_lit
return block;
}
-/**
- * \param icon_scale: Scale of the icon, 1x == button height.
- */
void uiTemplateIconView(uiLayout *layout,
PointerRNA *ptr,
const char *propname,
@@ -4152,51 +4115,6 @@ static uiBlock *curvemap_tools_func(
0,
UICURVE_FUNC_RESET_VIEW,
"");
- uiDefIconTextBut(block,
- UI_BTYPE_BUT_MENU,
- 1,
- ICON_BLANK1,
- IFACE_("Vector Handle"),
- 0,
- yco -= UI_UNIT_Y,
- menuwidth,
- UI_UNIT_Y,
- NULL,
- 0.0,
- 0.0,
- 0,
- UICURVE_FUNC_HANDLE_VECTOR,
- "");
- uiDefIconTextBut(block,
- UI_BTYPE_BUT_MENU,
- 1,
- ICON_BLANK1,
- IFACE_("Auto Handle"),
- 0,
- yco -= UI_UNIT_Y,
- menuwidth,
- UI_UNIT_Y,
- NULL,
- 0.0,
- 0.0,
- 0,
- UICURVE_FUNC_HANDLE_AUTO,
- "");
- uiDefIconTextBut(block,
- UI_BTYPE_BUT_MENU,
- 1,
- ICON_BLANK1,
- IFACE_("Auto Clamped Handle"),
- 0,
- yco -= UI_UNIT_Y,
- menuwidth,
- UI_UNIT_Y,
- NULL,
- 0.0,
- 0.0,
- 0,
- UICURVE_FUNC_HANDLE_AUTO_ANIM,
- "");
}
if (show_extend) {
@@ -4276,6 +4194,21 @@ static uiBlock *curvemap_brush_tools_negslope_func(bContext *C, ARegion *region,
return curvemap_tools_func(C, region, cumap_v, false, UICURVE_FUNC_RESET_POS);
}
+static void curvemap_tools_handle_vector(bContext *C, void *cumap_v, void *UNUSED(arg))
+{
+ curvemap_tools_dofunc(C, cumap_v, UICURVE_FUNC_HANDLE_VECTOR);
+}
+
+static void curvemap_tools_handle_auto(bContext *C, void *cumap_v, void *UNUSED(arg))
+{
+ curvemap_tools_dofunc(C, cumap_v, UICURVE_FUNC_HANDLE_AUTO);
+}
+
+static void curvemap_tools_handle_auto_clamped(bContext *C, void *cumap_v, void *UNUSED(arg))
+{
+ curvemap_tools_dofunc(C, cumap_v, UICURVE_FUNC_HANDLE_AUTO_ANIM);
+}
+
static void curvemap_buttons_redraw(bContext *C, void *UNUSED(arg1), void *UNUSED(arg2))
{
ED_region_tag_redraw(CTX_wm_region(C));
@@ -4327,6 +4260,8 @@ static void curvemap_buttons_layout(uiLayout *layout,
uiBlock *block = uiLayoutGetBlock(layout);
+ UI_block_emboss_set(block, UI_EMBOSS);
+
if (tone) {
uiLayout *split = uiLayoutSplit(layout, 0.0f, false);
uiItemR(uiLayoutRow(split, false), ptr, "tone", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
@@ -4412,10 +4347,11 @@ static void curvemap_buttons_layout(uiLayout *layout,
}
/* operation buttons */
- uiLayoutRow(row, true);
-
- UI_block_emboss_set(block, UI_EMBOSS_NONE);
+ /* (Right aligned) */
+ uiLayout *sub = uiLayoutRow(row, true);
+ uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_RIGHT);
+ /* Zoom in */
bt = uiDefIconBut(block,
UI_BTYPE_BUT,
0,
@@ -4432,6 +4368,7 @@ static void curvemap_buttons_layout(uiLayout *layout,
TIP_("Zoom in"));
UI_but_func_set(bt, curvemap_buttons_zoom_in, cumap, NULL);
+ /* Zoom out */
bt = uiDefIconBut(block,
UI_BTYPE_BUT,
0,
@@ -4448,97 +4385,53 @@ static void curvemap_buttons_layout(uiLayout *layout,
TIP_("Zoom out"));
UI_but_func_set(bt, curvemap_buttons_zoom_out, cumap, NULL);
+ /* Clippoing button. */
+ const int icon = (cumap->flag & CUMA_DO_CLIP) ? ICON_CLIPUV_HLT : ICON_CLIPUV_DEHLT;
+ bt = uiDefIconBlockBut(
+ block, curvemap_clipping_func, cumap, 0, icon, 0, 0, dx, dx, TIP_("Clipping Options"));
+ bt->drawflag &= ~UI_BUT_ICON_LEFT;
+ UI_but_funcN_set(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
+
if (brush && neg_slope) {
- bt = uiDefIconBlockBut(block,
- curvemap_brush_tools_negslope_func,
- cumap,
- 0,
- ICON_DOWNARROW_HLT,
- 0,
- 0,
- dx,
- dx,
- TIP_("Tools"));
+ bt = uiDefIconBlockBut(
+ block, curvemap_brush_tools_negslope_func, cumap, 0, 0, 0, 0, dx, dx, TIP_("Tools"));
}
else if (brush) {
- bt = uiDefIconBlockBut(block,
- curvemap_brush_tools_func,
- cumap,
- 0,
- ICON_DOWNARROW_HLT,
- 0,
- 0,
- dx,
- dx,
- TIP_("Tools"));
+ bt = uiDefIconBlockBut(
+ block, curvemap_brush_tools_func, cumap, 0, 0, 0, 0, dx, dx, TIP_("Tools"));
}
else if (neg_slope) {
- bt = uiDefIconBlockBut(block,
- curvemap_tools_negslope_func,
- cumap,
- 0,
- ICON_DOWNARROW_HLT,
- 0,
- 0,
- dx,
- dx,
- TIP_("Tools"));
+ bt = uiDefIconBlockBut(
+ block, curvemap_tools_negslope_func, cumap, 0, 0, 0, 0, dx, dx, TIP_("Tools"));
}
else {
- bt = uiDefIconBlockBut(block,
- curvemap_tools_posslope_func,
- cumap,
- 0,
- ICON_DOWNARROW_HLT,
- 0,
- 0,
- dx,
- dx,
- TIP_("Tools"));
+ bt = uiDefIconBlockBut(
+ block, curvemap_tools_posslope_func, cumap, 0, 0, 0, 0, dx, dx, TIP_("Tools"));
}
-
UI_but_funcN_set(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
- const int icon = (cumap->flag & CUMA_DO_CLIP) ? ICON_CLIPUV_HLT : ICON_CLIPUV_DEHLT;
- bt = uiDefIconBlockBut(
- block, curvemap_clipping_func, cumap, 0, icon, 0, 0, dx, dx, TIP_("Clipping Options"));
- UI_but_funcN_set(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
-
- bt = uiDefIconBut(block,
- UI_BTYPE_BUT,
- 0,
- ICON_X,
- 0,
- 0,
- dx,
- dx,
- NULL,
- 0.0,
- 0.0,
- 0.0,
- 0.0,
- TIP_("Delete points"));
- UI_but_funcN_set(bt, curvemap_buttons_delete, MEM_dupallocN(cb), cumap);
-
- UI_block_emboss_set(block, UI_EMBOSS);
-
UI_block_funcN_set(block, rna_update_cb, MEM_dupallocN(cb), NULL);
- /* curve itself */
+ /* Curve itself. */
const int size = max_ii(uiLayoutGetWidth(layout), UI_UNIT_X);
row = uiLayoutRow(layout, false);
uiButCurveMapping *curve_but = (uiButCurveMapping *)uiDefBut(
- block, UI_BTYPE_CURVE, 0, "", 0, 0, size, 8.0f * UI_UNIT_X, cumap, 0.0f, 1.0f, 0, 0, "");
+ block, UI_BTYPE_CURVE, 0, "", 0, 0, size, 8.0f * UI_UNIT_X, cumap, 0.0f, 1.0f, -1, 0, "");
curve_but->gradient_type = bg;
- /* sliders for selected point */
+ /* Sliders for selected curve point. */
+ int i;
CurveMapPoint *cmp = NULL;
- for (int i = 0; i < cm->totpoint; i++) {
+ bool point_last_or_first = false;
+ for (i = 0; i < cm->totpoint; i++) {
if (cm->curve[i].flag & CUMA_SELECT) {
cmp = &cm->curve[i];
break;
}
}
+ if (ELEM(i, 0, cm->totpoint - 1)) {
+ point_last_or_first = true;
+ }
if (cmp) {
rctf bounds;
@@ -4550,12 +4443,75 @@ static void curvemap_buttons_layout(uiLayout *layout,
bounds.xmax = bounds.ymax = 1000.0;
}
+ UI_block_emboss_set(block, UI_EMBOSS);
+
uiLayoutRow(layout, true);
+
+ /* Curve handle buttons. */
+ bt = uiDefIconBut(block,
+ UI_BTYPE_BUT,
+ 1,
+ ICON_HANDLE_AUTO,
+ 0,
+ UI_UNIT_Y,
+ UI_UNIT_X,
+ UI_UNIT_Y,
+ NULL,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ TIP_("Auto Handle"));
+ UI_but_func_set(bt, curvemap_tools_handle_auto, cumap, NULL);
+ if (((cmp->flag & CUMA_HANDLE_AUTO_ANIM) == false) &&
+ ((cmp->flag & CUMA_HANDLE_VECTOR) == false)) {
+ bt->flag |= UI_SELECT_DRAW;
+ }
+
+ bt = uiDefIconBut(block,
+ UI_BTYPE_BUT,
+ 1,
+ ICON_HANDLE_VECTOR,
+ 0,
+ UI_UNIT_Y,
+ UI_UNIT_X,
+ UI_UNIT_Y,
+ NULL,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ TIP_("Vector Handle"));
+ UI_but_func_set(bt, curvemap_tools_handle_vector, cumap, NULL);
+ if (cmp->flag & CUMA_HANDLE_VECTOR) {
+ bt->flag |= UI_SELECT_DRAW;
+ }
+
+ bt = uiDefIconBut(block,
+ UI_BTYPE_BUT,
+ 1,
+ ICON_HANDLE_AUTOCLAMPED,
+ 0,
+ UI_UNIT_Y,
+ UI_UNIT_X,
+ UI_UNIT_Y,
+ NULL,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ TIP_("Auto Clamped"));
+ UI_but_func_set(bt, curvemap_tools_handle_auto_clamped, cumap, NULL);
+ if (cmp->flag & CUMA_HANDLE_AUTO_ANIM) {
+ bt->flag |= UI_SELECT_DRAW;
+ }
+
+ /* Curve handle position */
UI_block_funcN_set(block, curvemap_buttons_update, MEM_dupallocN(cb), cumap);
bt = uiDefButF(block,
UI_BTYPE_NUM,
0,
- "X",
+ "X:",
0,
2 * UI_UNIT_Y,
UI_UNIT_X * 10,
@@ -4571,7 +4527,7 @@ static void curvemap_buttons_layout(uiLayout *layout,
bt = uiDefButF(block,
UI_BTYPE_NUM,
0,
- "Y",
+ "Y:",
0,
1 * UI_UNIT_Y,
UI_UNIT_X * 10,
@@ -4584,6 +4540,26 @@ static void curvemap_buttons_layout(uiLayout *layout,
"");
UI_but_number_step_size_set(bt, 1);
UI_but_number_precision_set(bt, 5);
+
+ /* Curve handle delete point */
+ bt = uiDefIconBut(block,
+ UI_BTYPE_BUT,
+ 0,
+ ICON_X,
+ 0,
+ 0,
+ dx,
+ dx,
+ NULL,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ TIP_("Delete points"));
+ UI_but_funcN_set(bt, curvemap_buttons_delete, MEM_dupallocN(cb), cumap);
+ if (point_last_or_first) {
+ UI_but_flag_enable(bt, UI_BUT_DISABLED);
+ }
}
/* black/white levels */
@@ -5030,11 +5006,6 @@ static void CurveProfile_buttons_layout(uiLayout *layout, PointerRNA *ptr, RNAUp
sub = uiLayoutRow(row, true);
uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_RIGHT);
- /* Reset view, reset curve */
- bt = uiDefIconBlockBut(
- block, CurveProfile_buttons_tools, profile, 0, 0, 0, 0, UI_UNIT_X, UI_UNIT_X, TIP_("Tools"));
- UI_but_funcN_set(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
-
/* Flip path */
bt = uiDefIconBut(block,
UI_BTYPE_BUT,
@@ -5070,6 +5041,11 @@ static void CurveProfile_buttons_layout(uiLayout *layout, PointerRNA *ptr, RNAUp
TIP_("Toggle Profile Clipping"));
UI_but_funcN_set(bt, CurveProfile_clipping_toggle, MEM_dupallocN(cb), profile);
+ /* Reset view, reset curve */
+ bt = uiDefIconBlockBut(
+ block, CurveProfile_buttons_tools, profile, 0, 0, 0, 0, UI_UNIT_X, UI_UNIT_X, TIP_("Tools"));
+ UI_but_funcN_set(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
+
UI_block_funcN_set(block, rna_update_cb, MEM_dupallocN(cb), NULL);
/* The path itself */
@@ -5213,10 +5189,6 @@ static void CurveProfile_buttons_layout(uiLayout *layout, PointerRNA *ptr, RNAUp
UI_block_funcN_set(block, NULL, NULL, NULL);
}
-/**
- * Template for a path creation widget intended for custom bevel profiles.
- * This section is quite similar to #uiTemplateCurveMapping, but with reduced complexity.
- */
void uiTemplateCurveProfile(uiLayout *layout, PointerRNA *ptr, const char *propname)
{
PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
@@ -5263,7 +5235,6 @@ void uiTemplateCurveProfile(uiLayout *layout, PointerRNA *ptr, const char *propn
#define WHEEL_SIZE (5 * U.widget_unit)
-/* This template now follows User Preference for type - name is not correct anymore... */
void uiTemplateColorPicker(uiLayout *layout,
PointerRNA *ptr,
const char *propname,
@@ -5654,10 +5625,6 @@ static void handle_layer_buttons(bContext *C, void *arg1, void *arg2)
/* see view3d_header.c */
}
-/**
- * \todo for now, grouping of layers is determined by dividing up the length of
- * the array of layer bitflags
- */
void uiTemplateLayers(uiLayout *layout,
PointerRNA *ptr,
const char *propname,
diff --git a/source/blender/editors/interface/interface_undo.c b/source/blender/editors/interface/interface_undo.c
index 40f196d9b45..6916e1080b6 100644
--- a/source/blender/editors/interface/interface_undo.c
+++ b/source/blender/editors/interface/interface_undo.c
@@ -91,11 +91,6 @@ const char *ui_textedit_undo(uiUndoStack_Text *stack, int direction, int *r_curs
return ui_textedit_redo_impl(stack, r_cursor_index);
}
-/**
- * Push the information in the arguments to a new state in the undo stack.
- *
- * \note Currently the total length of the undo stack is not limited.
- */
void ui_textedit_undo_push(uiUndoStack_Text *stack, const char *text, int cursor_index)
{
/* Clear all redo actions from the current state. */
@@ -114,11 +109,7 @@ void ui_textedit_undo_push(uiUndoStack_Text *stack, const char *text, int cursor
memcpy(stack->current->text, text, text_size);
BLI_addtail(&stack->states, stack->current);
}
-/**
- * Start the undo stack.
- *
- * \note The current state should be pushed immediately after calling this.
- */
+
uiUndoStack_Text *ui_textedit_undo_stack_create(void)
{
uiUndoStack_Text *stack = MEM_mallocN(sizeof(uiUndoStack_Text), __func__);
diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c
index 1a41dc8e9fb..84ec5f939d2 100644
--- a/source/blender/editors/interface/interface_utils.c
+++ b/source/blender/editors/interface/interface_utils.c
@@ -354,12 +354,6 @@ uiBut *uiDefAutoButR(uiBlock *block,
return but;
}
-/**
- * \a check_prop callback filters functions to avoid drawing certain properties,
- * in cases where PROP_HIDDEN flag can't be used for a property.
- *
- * \param prop_activate_init: Property to activate on initial popup (#UI_BUT_ACTIVATE_ON_INIT).
- */
eAutoPropButsReturn uiDefAutoButsRNA(uiLayout *layout,
PointerRNA *ptr,
bool (*check_prop)(PointerRNA *ptr,
@@ -552,7 +546,7 @@ void ui_rna_collection_search_update_fn(const struct bContext *C,
cis->name_prefix_offset = name_prefix_offset;
cis->has_sep_char = has_sep_char;
if (!skip_filter) {
- BLI_string_search_add(search, name, cis);
+ BLI_string_search_add(search, name, cis, 0);
}
BLI_addtail(items_list, cis);
if (name != name_buf) {
@@ -593,7 +587,6 @@ void ui_rna_collection_search_update_fn(const struct bContext *C,
MEM_freeN(items_list);
}
-/***************************** ID Utilities *******************************/
int UI_icon_from_id(const ID *id)
{
if (id == NULL) {
@@ -618,7 +611,6 @@ int UI_icon_from_id(const ID *id)
return (ptr.type) ? RNA_struct_ui_icon(ptr.type) : ICON_NONE;
}
-/* see: report_type_str */
int UI_icon_from_report_type(int type)
{
if (type & RPT_ERROR_ALL) {
@@ -690,10 +682,6 @@ int UI_text_colorid_from_report_type(int type)
/********************************** Misc **************************************/
-/**
- * Returns the best "UI" precision for given floating value,
- * so that e.g. 10.000001 rather gets drawn as '10'...
- */
int UI_calc_float_precision(int prec, double value)
{
static const double pow10_neg[UI_PRECISION_FLOAT_MAX + 1] = {
@@ -839,16 +827,6 @@ static bool ui_view2d_cur_ensure_rect_in_view(View2D *v2d, const rctf *rect)
return changed;
}
-/**
- * Adjust the view so the rectangle of \a but is in view, with some extra margin.
- *
- * It's important that this is only executed after buttons received their final #uiBut.rect. E.g.
- * #UI_panels_end() modifies them, so if that is executed, this function must not be called before
- * it.
- *
- * \param region: The region the button is placed in. Make sure this is actually the one the button
- * is placed in, not just the context region.
- */
void UI_but_ensure_in_view(const bContext *C, ARegion *region, const uiBut *but)
{
View2D *v2d = &region->v2d;
@@ -892,9 +870,6 @@ struct uiButStoreElem {
uiBut **but_p;
};
-/**
- * Create a new button store, the caller must manage and run #UI_butstore_free
- */
uiButStore *UI_butstore_create(uiBlock *block)
{
uiButStore *bs_handle = MEM_callocN(sizeof(uiButStore), __func__);
@@ -966,9 +941,6 @@ void UI_butstore_unregister(uiButStore *bs_handle, uiBut **but_p)
BLI_assert(0);
}
-/**
- * Update the pointer for a registered button.
- */
bool UI_butstore_register_update(uiBlock *block, uiBut *but_dst, const uiBut *but_src)
{
bool found = false;
@@ -985,9 +957,6 @@ bool UI_butstore_register_update(uiBlock *block, uiBut *but_dst, const uiBut *bu
return found;
}
-/**
- * NULL all pointers, don't free since the owner needs to be able to inspect.
- */
void UI_butstore_clear(uiBlock *block)
{
LISTBASE_FOREACH (uiButStore *, bs_handle, &block->butstore) {
@@ -998,9 +967,6 @@ void UI_butstore_clear(uiBlock *block)
}
}
-/**
- * Map freed buttons from the old block and update pointers.
- */
void UI_butstore_update(uiBlock *block)
{
/* move this list to the new block */
diff --git a/source/blender/editors/interface/interface_view.cc b/source/blender/editors/interface/interface_view.cc
index 4e38f245155..500834f4434 100644
--- a/source/blender/editors/interface/interface_view.cc
+++ b/source/blender/editors/interface/interface_view.cc
@@ -46,7 +46,7 @@ struct ViewLink : public Link {
using TreeViewPtr = std::unique_ptr<AbstractTreeView>;
std::string idname;
- /* Note: Can't use std::get() on this until minimum macOS deployment target is 10.14. */
+ /* NOTE: Can't use std::get() on this until minimum macOS deployment target is 10.14. */
std::variant<TreeViewPtr> view;
};
@@ -56,9 +56,6 @@ template<class T> T *get_view_from_link(ViewLink &link)
return t_uptr ? t_uptr->get() : nullptr;
}
-/**
- * Override this for all available tree types.
- */
AbstractTreeView *UI_block_add_view(uiBlock &block,
StringRef idname,
std::unique_ptr<AbstractTreeView> tree_view)
@@ -79,9 +76,6 @@ void ui_block_free_views(uiBlock *block)
}
}
-/**
- * \param x, y: Coordinate to find a tree-row item at, in window space.
- */
uiTreeViewItemHandle *UI_block_tree_view_find_item_at(const ARegion *region, const int xy[2])
{
uiButTreeRow *tree_row_but = (uiButTreeRow *)ui_tree_row_find_mouse_over(region, xy);
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 7d1b7b80ccd..ad8c0842657 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -26,6 +26,7 @@
#include <string.h>
#include "DNA_brush_types.h"
+#include "DNA_screen_types.h"
#include "DNA_userdef_types.h"
#include "BLI_listbase.h"
@@ -45,6 +46,7 @@
#include "UI_interface.h"
#include "UI_interface_icons.h"
+#include "UI_view2d.h"
#include "interface_intern.h"
@@ -99,6 +101,10 @@ typedef enum {
UI_WTYPE_PULLDOWN,
UI_WTYPE_MENU_ITEM,
+ /* Same as #UI_WTYPE_MENU_ITEM, but doesn't add padding to sides for text & icon inside the
+ * widget. To be used when multiple menu items should be displayed close to each other
+ * horizontally. */
+ UI_WTYPE_MENU_ITEM_UNPADDED,
UI_WTYPE_MENU_ITEM_RADIAL,
UI_WTYPE_MENU_BACK,
@@ -114,7 +120,6 @@ typedef enum {
UI_WTYPE_LISTITEM,
UI_WTYPE_PROGRESSBAR,
UI_WTYPE_NODESOCKET,
- UI_WTYPE_DATASETROW,
UI_WTYPE_TREEROW,
} uiWidgetTypeEnum;
@@ -268,8 +273,9 @@ typedef struct uiWidgetType {
uiWidgetColors wcol;
void (*state)(struct uiWidgetType *, int state, int drawflag, eUIEmbossType emboss);
- void (*draw)(uiWidgetColors *, rcti *, int state, int roundboxalign);
- void (*custom)(uiBut *, uiWidgetColors *, rcti *, int state, int roundboxalign);
+ void (*draw)(uiWidgetColors *, rcti *, int state, int roundboxalign, const float zoom);
+ void (*custom)(
+ uiBut *, uiWidgetColors *, rcti *, int state, int roundboxalign, const float zoom);
void (*text)(const uiFontStyle *, const uiWidgetColors *, uiBut *, rcti *);
} uiWidgetType;
@@ -551,7 +557,6 @@ static void draw_anti_tria(
GPU_blend(GPU_BLEND_NONE);
}
-/* Triangle 'icon' for panel header and other cases. */
void UI_draw_icon_tri(float x, float y, char dir, const float color[4])
{
const float f3 = 0.05 * U.widget_unit;
@@ -1514,17 +1519,6 @@ static void ui_text_clip_right_ex(const uiFontStyle *fstyle,
}
}
-/**
- * Cut off the middle of the text to fit into the given width.
- *
- * \note in case this middle clipping would just remove a few chars,
- * it rather clips right, which is more readable.
- *
- * If rpart_sep is not Null, the part of str starting to first occurrence of rpart_sep
- * is preserved at all cost.
- * Useful for strings with shortcuts
- * (like 'AVeryLongFooBarLabelForMenuEntry|Ctrl O' -> 'AVeryLong...MenuEntry|Ctrl O').
- */
float UI_text_clip_middle_ex(const uiFontStyle *fstyle,
char *str,
float okwidth,
@@ -2596,6 +2590,27 @@ static void widget_state(uiWidgetType *wt, int state, int drawflag, eUIEmbossTyp
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Widget Corner Radius Calculation
+ *
+ * A lot of places of the UI like the Node Editor or panels are zoomable. In most cases we can
+ * get the zoom factor from the aspect, but in some cases like popups we need to fall back to
+ * using the the size of the element. The latter method relies on the element always being the same
+ * size.
+ * \{ */
+
+static float widget_radius_from_zoom(const float zoom, const uiWidgetColors *wcol)
+{
+ return wcol->roundness * U.widget_unit * zoom;
+}
+
+static float widget_radius_from_rcti(const rcti *rect, const uiWidgetColors *wcol)
+{
+ return wcol->roundness * BLI_rcti_size_y(rect);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Widget Types
* \{ */
@@ -2786,7 +2801,8 @@ static void widget_softshadow(const rcti *rect, int roundboxalign, const float r
immUnbindProgram();
}
-static void widget_menu_back(uiWidgetColors *wcol, rcti *rect, int flag, int direction)
+static void widget_menu_back(
+ uiWidgetColors *wcol, rcti *rect, int flag, int direction, const float zoom)
{
uiWidgetBase wtb;
int roundboxalign = UI_CNR_ALL;
@@ -2808,29 +2824,31 @@ static void widget_menu_back(uiWidgetColors *wcol, rcti *rect, int flag, int dir
}
GPU_blend(GPU_BLEND_ALPHA);
- widget_softshadow(rect, roundboxalign, wcol->roundness * U.widget_unit);
+ const float radius = widget_radius_from_zoom(zoom, wcol);
+ widget_softshadow(rect, roundboxalign, radius);
- round_box_edges(&wtb, roundboxalign, rect, wcol->roundness * U.widget_unit);
+ round_box_edges(&wtb, roundboxalign, rect, radius);
wtb.draw_emboss = false;
widgetbase_draw(&wtb, wcol);
GPU_blend(GPU_BLEND_NONE);
}
-static void ui_hsv_cursor(float x, float y)
+static void ui_hsv_cursor(const float x, const float y, const float zoom)
{
+ const float radius = zoom * 3.0f * U.pixelsize;
const uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
immUniformColor3f(1.0f, 1.0f, 1.0f);
- imm_draw_circle_fill_2d(pos, x, y, 3.0f * U.pixelsize, 8);
+ imm_draw_circle_fill_2d(pos, x, y, radius, 8);
GPU_blend(GPU_BLEND_ALPHA);
GPU_line_smooth(true);
immUniformColor3f(0.0f, 0.0f, 0.0f);
- imm_draw_circle_wire_2d(pos, x, y, 3.0f * U.pixelsize, 12);
+ imm_draw_circle_wire_2d(pos, x, y, radius, 12);
GPU_blend(GPU_BLEND_NONE);
GPU_line_smooth(false);
@@ -2851,7 +2869,6 @@ void ui_hsvcircle_vals_from_pos(
*r_val_rad = atan2f(m_delta[0], m_delta[1]) / (2.0f * (float)M_PI) + 0.5f;
}
-/* cursor in hsv circle, in float units -1 to 1, to map on radius */
void ui_hsvcircle_pos_from_vals(
const ColorPicker *cpicker, const rcti *rect, const float *hsv, float *r_xpos, float *r_ypos)
{
@@ -2978,7 +2995,8 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, const uiWidgetColors *wcol, const
float xpos, ypos;
ui_hsvcircle_pos_from_vals(cpicker, rect, hsv, &xpos, &ypos);
- ui_hsv_cursor(xpos, ypos);
+ const float zoom = 1.0f / but->block->aspect;
+ ui_hsv_cursor(xpos, ypos, zoom);
}
/** \} */
@@ -2987,7 +3005,6 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, const uiWidgetColors *wcol, const
/** \name Draw Custom Buttons
* \{ */
-/* draws in resolution of 48x4 colors */
void ui_draw_gradient(const rcti *rect,
const float hsv[3],
const eButGradientType type,
@@ -3212,7 +3229,9 @@ static void ui_draw_but_HSVCUBE(uiBut *but, const rcti *rect)
CLAMP(x, rect->xmin + 3.0f, rect->xmax - 3.0f);
CLAMP(y, rect->ymin + 3.0f, rect->ymax - 3.0f);
- ui_hsv_cursor(x, y);
+ const float zoom = 1.0f / but->block->aspect;
+
+ ui_hsv_cursor(x, y, zoom);
/* outline */
const uint pos = GPU_vertformat_attr_add(
@@ -3275,8 +3294,9 @@ static void ui_draw_but_HSV_v(uiBut *but, const rcti *rect)
x = rect->xmin + 0.5f * BLI_rcti_size_x(rect);
y = rect->ymin + v * BLI_rcti_size_y(rect);
CLAMP(y, rect->ymin + 3.0f, rect->ymax - 3.0f);
+ const float zoom = 1.0f / but->block->aspect;
- ui_hsv_cursor(x, y);
+ ui_hsv_cursor(x, y, zoom);
}
/** Separator for menus. */
@@ -3315,9 +3335,9 @@ static void ui_draw_separator(const rcti *rect, const uiWidgetColors *wcol)
* \{ */
static void widget_numbut_draw(
- uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, bool emboss)
+ uiWidgetColors *wcol, rcti *rect, const float zoom, int state, int roundboxalign, bool emboss)
{
- const float rad = wcol->roundness * BLI_rcti_size_y(rect);
+ const float rad = widget_radius_from_zoom(zoom, wcol);
const int handle_width = min_ii(BLI_rcti_size_x(rect) / 3, BLI_rcti_size_y(rect) * 0.7f);
if (state & UI_SELECT) {
@@ -3416,17 +3436,19 @@ static void widget_numbut_draw(
}
}
-static void widget_numbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
+static void widget_numbut(
+ uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
{
- widget_numbut_draw(wcol, rect, state, roundboxalign, false);
+ widget_numbut_draw(wcol, rect, zoom, state, roundboxalign, false);
}
-static void widget_menubut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
+static void widget_menubut(
+ uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign, const float zoom)
{
uiWidgetBase wtb;
widget_init(&wtb);
- const float rad = wcol->roundness * U.widget_unit;
+ const float rad = widget_radius_from_zoom(zoom, wcol);
round_box_edges(&wtb, roundboxalign, rect, rad);
/* decoration */
@@ -3465,13 +3487,16 @@ static void widget_menubut_embossn(const uiBut *UNUSED(but),
/**
* Draw number buttons still with triangles when field is not embossed
*/
-static void widget_numbut_embossn(
- const uiBut *UNUSED(but), uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
+static void widget_numbut_embossn(const uiBut *UNUSED(but),
+ uiWidgetColors *wcol,
+ rcti *rect,
+ int state,
+ int roundboxalign,
+ const float zoom)
{
- widget_numbut_draw(wcol, rect, state, roundboxalign, true);
+ widget_numbut_draw(wcol, rect, zoom, state, roundboxalign, true);
}
-/* function in use for buttons and for view2d sliders */
void UI_draw_widget_scroll(uiWidgetColors *wcol, const rcti *rect, const rcti *slider, int state)
{
uiWidgetBase wtb;
@@ -3559,8 +3584,12 @@ void UI_draw_widget_scroll(uiWidgetColors *wcol, const rcti *rect, const rcti *s
}
}
-static void widget_scroll(
- uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int UNUSED(roundboxalign))
+static void widget_scroll(uiBut *but,
+ uiWidgetColors *wcol,
+ rcti *rect,
+ int state,
+ int UNUSED(roundboxalign),
+ const float UNUSED(zoom))
{
/* calculate slider part */
const float value = (float)ui_but_value_get(but);
@@ -3617,8 +3646,12 @@ static void widget_scroll(
UI_draw_widget_scroll(wcol, rect, &rect1, state);
}
-static void widget_progressbar(
- uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
+static void widget_progressbar(uiBut *but,
+ uiWidgetColors *wcol,
+ rcti *rect,
+ int UNUSED(state),
+ int roundboxalign,
+ const float zoom)
{
uiButProgressbar *but_progressbar = (uiButProgressbar *)but;
rcti rect_prog = *rect, rect_bar = *rect;
@@ -3629,7 +3662,7 @@ static void widget_progressbar(
/* round corners */
const float value = but_progressbar->progress;
- const float ofs = wcol->roundness * BLI_rcti_size_y(&rect_prog);
+ const float ofs = widget_radius_from_zoom(zoom, wcol);
float w = value * BLI_rcti_size_x(&rect_prog);
/* Ensure minimum size. */
@@ -3648,15 +3681,19 @@ static void widget_progressbar(
widgetbase_draw(&wtb_bar, wcol);
}
-static void widget_treerow_exec(
- uiWidgetColors *wcol, rcti *rect, int state, int UNUSED(roundboxalign), int indentation)
+static void widget_treerow_exec(uiWidgetColors *wcol,
+ rcti *rect,
+ int state,
+ int UNUSED(roundboxalign),
+ int indentation,
+ const float zoom)
{
uiWidgetBase wtb;
widget_init(&wtb);
/* no outline */
wtb.draw_outline = false;
- const float rad = wcol->roundness * U.widget_unit;
+ const float rad = widget_radius_from_zoom(zoom, wcol);
round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
if ((state & UI_ACTIVE) || (state & UI_SELECT)) {
@@ -3668,23 +3705,19 @@ static void widget_treerow_exec(
}
static void widget_treerow(
- uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
+ uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
{
uiButTreeRow *tree_row = (uiButTreeRow *)but;
BLI_assert(but->type == UI_BTYPE_TREEROW);
- widget_treerow_exec(wcol, rect, state, roundboxalign, tree_row->indentation);
+ widget_treerow_exec(wcol, rect, state, roundboxalign, tree_row->indentation, zoom);
}
-static void widget_datasetrow(
- uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
-{
- uiButDatasetRow *dataset_row = (uiButDatasetRow *)but;
- BLI_assert(but->type == UI_BTYPE_DATASETROW);
- widget_treerow_exec(wcol, rect, state, roundboxalign, dataset_row->indentation);
-}
-
-static void widget_nodesocket(
- uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
+static void widget_nodesocket(uiBut *but,
+ uiWidgetColors *wcol,
+ rcti *rect,
+ int UNUSED(state),
+ int UNUSED(roundboxalign),
+ const float UNUSED(zoom))
{
const int radi = 0.25f * BLI_rcti_size_y(rect);
@@ -3719,14 +3752,14 @@ static void widget_nodesocket(
}
static void widget_numslider(
- uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
+ uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
{
uiWidgetBase wtb, wtb1;
widget_init(&wtb);
widget_init(&wtb1);
/* Backdrop first. */
- const float ofs = wcol->roundness * BLI_rcti_size_y(rect);
+ const float ofs = widget_radius_from_zoom(zoom, wcol);
const float toffs = ofs * 0.75f;
round_box_edges(&wtb, roundboxalign, rect, ofs);
@@ -3829,7 +3862,7 @@ static void widget_numslider(
#define SWATCH_KEYED_BORDER 3
static void widget_swatch(
- uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
+ uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
{
BLI_assert(but->type == UI_BTYPE_COLOR);
uiButColor *color_but = (uiButColor *)but;
@@ -3848,7 +3881,7 @@ static void widget_swatch(
uiWidgetBase wtb;
widget_init(&wtb);
- const float rad = wcol->roundness * U.widget_unit;
+ const float rad = widget_radius_from_zoom(zoom, wcol);
round_box_edges(&wtb, roundboxalign, rect, rad);
ui_but_v3_get(but, col);
@@ -3913,14 +3946,19 @@ static void widget_swatch(
}
}
-static void widget_unitvec(
- uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
+static void widget_unitvec(uiBut *but,
+ uiWidgetColors *wcol,
+ rcti *rect,
+ int UNUSED(state),
+ int UNUSED(roundboxalign),
+ const float zoom)
{
- ui_draw_but_UNITVEC(but, wcol, rect);
+ const float rad = widget_radius_from_zoom(zoom, wcol);
+ ui_draw_but_UNITVEC(but, wcol, rect, rad);
}
static void widget_icon_has_anim(
- uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
+ uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
{
if (state & (UI_BUT_ANIMATED | UI_BUT_ANIMATED_KEY | UI_BUT_DRIVEN | UI_BUT_REDALERT) &&
but->emboss != UI_EMBOSS_NONE) {
@@ -3928,14 +3966,14 @@ static void widget_icon_has_anim(
widget_init(&wtb);
wtb.draw_outline = false;
- const float rad = wcol->roundness * BLI_rcti_size_y(rect);
+ const float rad = widget_radius_from_zoom(zoom, wcol);
round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
widgetbase_draw(&wtb, wcol);
}
else if (but->type == UI_BTYPE_NUM) {
/* Draw number buttons still with left/right
* triangles when field is not embossed */
- widget_numbut_embossn(but, wcol, rect, state, roundboxalign);
+ widget_numbut_embossn(but, wcol, rect, state, roundboxalign, zoom);
}
else if (but->type == UI_BTYPE_MENU) {
/* Draw menu buttons still with down arrow. */
@@ -3943,7 +3981,8 @@ static void widget_icon_has_anim(
}
}
-static void widget_textbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
+static void widget_textbut(
+ uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
{
if (state & UI_SELECT) {
SWAP(short, wcol->shadetop, wcol->shadedown);
@@ -3952,43 +3991,46 @@ static void widget_textbut(uiWidgetColors *wcol, rcti *rect, int state, int roun
uiWidgetBase wtb;
widget_init(&wtb);
- const float rad = wcol->roundness * U.widget_unit;
+ const float rad = widget_radius_from_zoom(zoom, wcol);
round_box_edges(&wtb, roundboxalign, rect, rad);
widgetbase_draw(&wtb, wcol);
}
-static void widget_preview_tile(
- uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
+static void widget_preview_tile(uiBut *but,
+ uiWidgetColors *wcol,
+ rcti *rect,
+ int UNUSED(state),
+ int UNUSED(roundboxalign),
+ const float UNUSED(zoom))
{
const uiStyle *style = UI_style_get();
ui_draw_preview_item_stateless(
&style->widget, rect, but->drawstr, but->icon, wcol->text, UI_STYLE_TEXT_CENTER);
}
-static void widget_menuiconbut(uiWidgetColors *wcol,
- rcti *rect,
- int UNUSED(state),
- int roundboxalign)
+static void widget_menuiconbut(
+ uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign, const float zoom)
{
uiWidgetBase wtb;
widget_init(&wtb);
- const float rad = wcol->roundness * U.widget_unit;
+ const float rad = widget_radius_from_zoom(zoom, wcol);
round_box_edges(&wtb, roundboxalign, rect, rad);
/* decoration */
widgetbase_draw(&wtb, wcol);
}
-static void widget_pulldownbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
+static void widget_pulldownbut(
+ uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
{
float back[4];
UI_GetThemeColor4fv(TH_BACK, back);
if ((state & UI_ACTIVE) || (back[3] < 1.0f)) {
uiWidgetBase wtb;
- const float rad = wcol->roundness * U.widget_unit;
+ const float rad = widget_radius_from_zoom(zoom, wcol);
if (state & UI_ACTIVE) {
copy_v4_v4_uchar(wcol->inner, wcol->inner_sel);
@@ -4012,26 +4054,54 @@ static void widget_pulldownbut(uiWidgetColors *wcol, rcti *rect, int state, int
static void widget_menu_itembut(uiWidgetColors *wcol,
rcti *rect,
int UNUSED(state),
- int UNUSED(roundboxalign))
+ int UNUSED(roundboxalign),
+ const float zoom)
{
uiWidgetBase wtb;
widget_init(&wtb);
/* Padding on the sides. */
- const float padding = 0.125f * BLI_rcti_size_y(rect);
+ const float padding = zoom * 0.125f * U.widget_unit;
rect->xmin += padding;
rect->xmax -= padding;
/* No outline. */
wtb.draw_outline = false;
- const float rad = wcol->roundness * BLI_rcti_size_y(rect);
+
+ const float rad = widget_radius_from_zoom(zoom, wcol);
+
round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
widgetbase_draw(&wtb, wcol);
}
-static void widget_menu_radial_itembut(
- uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
+static void widget_menu_itembut_unpadded(uiWidgetColors *wcol,
+ rcti *rect,
+ int UNUSED(state),
+ int UNUSED(roundboxalign),
+ const float zoom)
+{
+ /* This function is used for menu items placed close to each other horizontally, e.g. the matcap
+ * preview popup or the row of collection color icons in the Outliner context menu. Don't use
+ * padding on the sides like the normal menu item. */
+
+ uiWidgetBase wtb;
+ widget_init(&wtb);
+
+ /* No outline. */
+ wtb.draw_outline = false;
+ const float rad = widget_radius_from_zoom(zoom, wcol);
+ round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
+
+ widgetbase_draw(&wtb, wcol);
+}
+
+static void widget_menu_radial_itembut(uiBut *but,
+ uiWidgetColors *wcol,
+ rcti *rect,
+ int UNUSED(state),
+ int UNUSED(roundboxalign),
+ const float zoom)
{
const float fac = but->block->pie_data.alphafac;
@@ -4040,7 +4110,7 @@ static void widget_menu_radial_itembut(
wtb.draw_emboss = false;
- const float rad = wcol->roundness * BLI_rcti_size_y(rect);
+ const float rad = widget_radius_from_zoom(zoom, wcol);
round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
wcol->inner[3] *= fac;
@@ -4056,14 +4126,15 @@ static void widget_menu_radial_itembut(
static void widget_list_itembut(uiWidgetColors *wcol,
rcti *rect,
int UNUSED(state),
- int UNUSED(roundboxalign))
+ int UNUSED(roundboxalign),
+ const float zoom)
{
uiWidgetBase wtb;
widget_init(&wtb);
/* no outline */
wtb.draw_outline = false;
- const float rad = wcol->roundness * U.widget_unit;
+ const float rad = widget_radius_from_zoom(zoom, wcol);
round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
widgetbase_draw(&wtb, wcol);
@@ -4072,7 +4143,8 @@ static void widget_list_itembut(uiWidgetColors *wcol,
static void widget_optionbut(uiWidgetColors *wcol,
rcti *rect,
int state,
- int UNUSED(roundboxalign))
+ int UNUSED(roundboxalign),
+ const float UNUSED(zoom))
{
const bool text_before_widget = (state & UI_STATE_TEXT_BEFORE_WIDGET);
rcti recttemp = *rect;
@@ -4095,7 +4167,7 @@ static void widget_optionbut(uiWidgetColors *wcol,
/* Keep one edge in place. */
BLI_rcti_translate(&recttemp, text_before_widget ? delta : -delta, 0);
- const float rad = wcol->roundness * BLI_rcti_size_y(&recttemp);
+ const float rad = widget_radius_from_rcti(&recttemp, wcol);
round_box_edges(&wtb, UI_CNR_ALL, &recttemp, rad);
/* decoration */
@@ -4142,19 +4214,24 @@ static void widget_state_label(uiWidgetType *wt, int state, int drawflag, eUIEmb
}
}
-static void widget_radiobut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
+static void widget_radiobut(
+ uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign, const float zoom)
{
uiWidgetBase wtb;
widget_init(&wtb);
- const float rad = wcol->roundness * U.widget_unit;
+ const float rad = widget_radius_from_zoom(zoom, wcol);
round_box_edges(&wtb, roundboxalign, rect, rad);
widgetbase_draw(&wtb, wcol);
}
-static void widget_box(
- uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
+static void widget_box(uiBut *but,
+ uiWidgetColors *wcol,
+ rcti *rect,
+ int UNUSED(state),
+ int roundboxalign,
+ const float zoom)
{
uiWidgetBase wtb;
widget_init(&wtb);
@@ -4170,7 +4247,7 @@ static void widget_box(
wcol->inner[3] = but->col[3];
}
- const float rad = wcol->roundness * U.widget_unit;
+ const float rad = widget_radius_from_zoom(zoom, wcol);
round_box_edges(&wtb, roundboxalign, rect, rad);
widgetbase_draw(&wtb, wcol);
@@ -4178,12 +4255,13 @@ static void widget_box(
copy_v3_v3_uchar(wcol->inner, old_col);
}
-static void widget_but(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
+static void widget_but(
+ uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign, const float zoom)
{
uiWidgetBase wtb;
widget_init(&wtb);
- const float rad = wcol->roundness * U.widget_unit;
+ const float rad = widget_radius_from_zoom(zoom, wcol);
round_box_edges(&wtb, roundboxalign, rect, rad);
widgetbase_draw(&wtb, wcol);
@@ -4204,10 +4282,9 @@ static void widget_roundbut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state),
}
#endif
-static void widget_roundbut_exec(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
+static void widget_roundbut_exec(
+ uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
{
- const float rad = wcol->roundness * U.widget_unit;
-
uiWidgetBase wtb;
widget_init(&wtb);
@@ -4216,15 +4293,18 @@ static void widget_roundbut_exec(uiWidgetColors *wcol, rcti *rect, int state, in
shape_preset_init_hold_action(&wtb.tria1, rect, 0.75f, 'r');
}
+ const float rad = widget_radius_from_zoom(zoom, wcol);
+
/* half rounded */
round_box_edges(&wtb, roundboxalign, rect, rad);
widgetbase_draw(&wtb, wcol);
}
-static void widget_tab(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
+static void widget_tab(
+ uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
{
- const float rad = wcol->roundness * U.widget_unit;
+ const float rad = widget_radius_from_zoom(zoom, wcol);
const bool is_active = (state & UI_SELECT);
/* Draw shaded outline - Disabled for now,
@@ -4421,6 +4501,12 @@ static uiWidgetType *widget_type(uiWidgetTypeEnum type)
wt.state = widget_state_menu_item;
break;
+ case UI_WTYPE_MENU_ITEM_UNPADDED:
+ wt.wcol_theme = &btheme->tui.wcol_menu_item;
+ wt.draw = widget_menu_itembut_unpadded;
+ wt.state = widget_state_menu_item;
+ break;
+
case UI_WTYPE_MENU_BACK:
wt.wcol_theme = &btheme->tui.wcol_menu_back;
wt.draw = widget_menu_back;
@@ -4476,10 +4562,6 @@ static uiWidgetType *widget_type(uiWidgetTypeEnum type)
wt.custom = widget_progressbar;
break;
- case UI_WTYPE_DATASETROW:
- wt.custom = widget_datasetrow;
- break;
-
case UI_WTYPE_TREEROW:
wt.custom = widget_treerow;
break;
@@ -4565,11 +4647,12 @@ static int widget_roundbox_set(uiBut *but, rcti *rect)
return roundbox;
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Public API
* \{ */
-/* conversion from old to new buttons, so still messy */
void ui_draw_but(const bContext *C, struct ARegion *region, uiStyle *style, uiBut *but, rcti *rect)
{
bTheme *btheme = UI_GetTheme();
@@ -4586,9 +4669,12 @@ void ui_draw_but(const bContext *C, struct ARegion *region, uiStyle *style, uiBu
case UI_BTYPE_SEPR_LINE:
ui_draw_separator(rect, &tui->wcol_menu_item);
break;
- default:
- wt = widget_type(UI_WTYPE_MENU_ITEM);
+ default: {
+ const bool use_unpadded = (but->flag & UI_BUT_ICON_PREVIEW) ||
+ ((but->flag & UI_HAS_ICON) && !but->drawstr[0]);
+ wt = widget_type(use_unpadded ? UI_WTYPE_MENU_ITEM_UNPADDED : UI_WTYPE_MENU_ITEM);
break;
+ }
}
}
else if (ELEM(but->emboss, UI_EMBOSS_NONE, UI_EMBOSS_NONE_OR_STATUS)) {
@@ -4811,11 +4897,6 @@ void ui_draw_but(const bContext *C, struct ARegion *region, uiStyle *style, uiBu
fstyle = &style->widgetlabel;
break;
- case UI_BTYPE_DATASETROW:
- wt = widget_type(UI_WTYPE_DATASETROW);
- fstyle = &style->widgetlabel;
- break;
-
case UI_BTYPE_TREEROW:
wt = widget_type(UI_WTYPE_TREEROW);
fstyle = &style->widgetlabel;
@@ -4897,12 +4978,13 @@ void ui_draw_but(const bContext *C, struct ARegion *region, uiStyle *style, uiBu
}
#endif
+ const float zoom = 1.0f / but->block->aspect;
wt->state(wt, state, drawflag, but->emboss);
if (wt->custom) {
- wt->custom(but, &wt->wcol, rect, state, roundboxalign);
+ wt->custom(but, &wt->wcol, rect, state, roundboxalign, zoom);
}
else if (wt->draw) {
- wt->draw(&wt->wcol, rect, state, roundboxalign);
+ wt->draw(&wt->wcol, rect, state, roundboxalign, zoom);
}
if (wt->text) {
@@ -4945,10 +5027,11 @@ void ui_draw_menu_back(uiStyle *UNUSED(style), uiBlock *block, rcti *rect)
wt->state(wt, 0, 0, UI_EMBOSS_UNDEFINED);
if (block) {
- wt->draw(&wt->wcol, rect, block->flag, block->direction);
+ const float zoom = 1.0f / block->aspect;
+ wt->draw(&wt->wcol, rect, block->flag, block->direction, zoom);
}
else {
- wt->draw(&wt->wcol, rect, 0, 0);
+ wt->draw(&wt->wcol, rect, 0, 0, 1.0f);
}
ui_draw_clip_tri(block, rect, wt);
@@ -5042,8 +5125,9 @@ void ui_draw_popover_back(struct ARegion *region,
wt->wcol_theme, rect, block->direction, U.widget_unit / block->aspect, mval_origin);
}
else {
+ const float zoom = 1.0f / block->aspect;
wt->state(wt, 0, 0, UI_EMBOSS_UNDEFINED);
- wt->draw(&wt->wcol, rect, 0, 0);
+ wt->draw(&wt->wcol, rect, 0, 0, zoom);
}
ui_draw_clip_tri(block, rect, wt);
@@ -5235,7 +5319,7 @@ static void ui_draw_widget_back_color(uiWidgetTypeEnum type,
if (color) {
rgba_float_to_uchar(wt->wcol.inner, color);
}
- wt->draw(&wt->wcol, &rect_copy, 0, UI_CNR_ALL);
+ wt->draw(&wt->wcol, &rect_copy, 0, UI_CNR_ALL, 1.0f);
}
void ui_draw_widget_menu_back_color(const rcti *rect, bool use_shadow, const float color[4])
{
@@ -5252,18 +5336,9 @@ void ui_draw_tooltip_background(const uiStyle *UNUSED(style), uiBlock *UNUSED(bl
uiWidgetType *wt = widget_type(UI_WTYPE_TOOLTIP);
wt->state(wt, 0, 0, UI_EMBOSS_UNDEFINED);
/* wt->draw ends up using same function to draw the tooltip as menu_back */
- wt->draw(&wt->wcol, rect, 0, 0);
+ wt->draw(&wt->wcol, rect, 0, 0, 1.0f);
}
-/**
- * Helper call to draw a menu item without a button.
- *
- * \param state: The state of the button,
- * typically #UI_ACTIVE, #UI_BUT_DISABLED, #UI_BUT_INACTIVE.
- * \param separator_type: The kind of separator which controls if and how the string is clipped.
- * \param r_xmax: The right hand position of the text, this takes into the icon,
- * padding and text clipping when there is not enough room to display the full text.
- */
void ui_draw_menu_item(const uiFontStyle *fstyle,
rcti *rect,
const char *name,
@@ -5280,7 +5355,7 @@ void ui_draw_menu_item(const uiFontStyle *fstyle,
char *cpoin = NULL;
wt->state(wt, state, 0, UI_EMBOSS_UNDEFINED);
- wt->draw(&wt->wcol, rect, 0, 0);
+ wt->draw(&wt->wcol, rect, 0, 0, 1.0f);
UI_fontstyle_set(fstyle);
@@ -5402,10 +5477,6 @@ void ui_draw_menu_item(const uiFontStyle *fstyle,
}
}
-/**
- * Version of #ui_draw_preview_item() that does not draw the menu background and item text based on
- * state. It just draws the preview and text directly.
- */
void ui_draw_preview_item_stateless(const uiFontStyle *fstyle,
rcti *rect,
const char *name,
@@ -5466,11 +5537,11 @@ void ui_draw_preview_item(const uiFontStyle *fstyle,
int state,
eFontStyle_Align text_align)
{
- uiWidgetType *wt = widget_type(UI_WTYPE_MENU_ITEM);
+ uiWidgetType *wt = widget_type(UI_WTYPE_MENU_ITEM_UNPADDED);
/* drawing button background */
wt->state(wt, state, 0, UI_EMBOSS_UNDEFINED);
- wt->draw(&wt->wcol, rect, 0, 0);
+ wt->draw(&wt->wcol, rect, 0, 0, 1.0f);
ui_draw_preview_item_stateless(fstyle, rect, name, iconid, wt->wcol.text, text_align);
}
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index d960f5e6b1d..3b511e23384 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -1035,12 +1035,6 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid)
return (const uchar *)cp;
}
-/**
- * Initialize default theme.
- *
- * \note When you add new colors, created & saved themes need initialized
- * use function below, #init_userdef_do_versions.
- */
void UI_theme_init_default(void)
{
/* we search for the theme with name Default */
@@ -1091,9 +1085,6 @@ bTheme *UI_GetTheme(void)
return U.themes.first;
}
-/**
- * For the rare case we need to temp swap in a different theme (off-screen render).
- */
void UI_Theme_Store(struct bThemeState *theme_state)
{
*theme_state = g_theme_state;
@@ -1163,21 +1154,18 @@ void UI_FontThemeColor(int fontid, int colorid)
BLF_color4ubv(fontid, color);
}
-/* get individual values, not scaled */
float UI_GetThemeValuef(int colorid)
{
const uchar *cp = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid);
return ((float)cp[0]);
}
-/* get individual values, not scaled */
int UI_GetThemeValue(int colorid)
{
const uchar *cp = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid);
return ((int)cp[0]);
}
-/* versions of the function above, which take a space-type */
float UI_GetThemeValueTypef(int colorid, int spacetype)
{
const uchar *cp = UI_ThemeGetColorPtr(theme_active, spacetype, colorid);
@@ -1190,7 +1178,6 @@ int UI_GetThemeValueType(int colorid, int spacetype)
return ((int)cp[0]);
}
-/* get the color, range 0.0-1.0 */
void UI_GetThemeColor3fv(int colorid, float col[3])
{
const uchar *cp = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid);
@@ -1217,7 +1204,6 @@ void UI_GetThemeColorType4fv(int colorid, int spacetype, float col[4])
col[3] = ((float)cp[3]) / 255.0f;
}
-/* get the color, range 0.0-1.0, complete with shading offset */
void UI_GetThemeColorShade3fv(int colorid, int offset, float col[3])
{
const uchar *cp = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid);
@@ -1350,7 +1336,6 @@ void UI_GetThemeColorBlendShade4fv(int colorid1, int colorid2, float fac, int of
col[3] = ((float)a) / 255.0f;
}
-/* get the color, in char pointer */
void UI_GetThemeColor3ubv(int colorid, uchar col[3])
{
const uchar *cp = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid);
@@ -1359,7 +1344,6 @@ void UI_GetThemeColor3ubv(int colorid, uchar col[3])
col[2] = cp[2];
}
-/* get the color, range 0.0-1.0, complete with shading offset */
void UI_GetThemeColorShade4fv(int colorid, int offset, float col[4])
{
const uchar *cp = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid);
@@ -1381,7 +1365,6 @@ void UI_GetThemeColorShade4fv(int colorid, int offset, float col[4])
col[3] = ((float)a) / 255.0f;
}
-/* get the color, in char pointer */
void UI_GetThemeColor4ubv(int colorid, uchar col[4])
{
const uchar *cp = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid);
@@ -1459,7 +1442,6 @@ void UI_GetColorPtrShade3ubv(const uchar cp[3], uchar col[3], int offset)
col[2] = b;
}
-/* get a 3 byte color, blended and shaded between two other char color pointers */
void UI_GetColorPtrBlendShade3ubv(
const uchar cp1[3], const uchar cp2[3], uchar col[3], float fac, int offset)
{
diff --git a/source/blender/editors/interface/tree_view.cc b/source/blender/editors/interface/tree_view.cc
index fcc878c440c..3010aaba5a3 100644
--- a/source/blender/editors/interface/tree_view.cc
+++ b/source/blender/editors/interface/tree_view.cc
@@ -39,8 +39,8 @@ namespace blender::ui {
/* ---------------------------------------------------------------------- */
/**
- * Add a tree-item to the container. This is the only place where items should be added, it handles
- * important invariants!
+ * Add a tree-item to the container. This is the only place where items should be added, it
+ * handles important invariants!
*/
AbstractTreeViewItem &TreeViewItemContainer::add_tree_item(
std::unique_ptr<AbstractTreeViewItem> item)
@@ -87,19 +87,6 @@ bool AbstractTreeView::is_renaming() const
return rename_buffer_ != nullptr;
}
-void AbstractTreeView::build_layout_from_tree(const TreeViewLayoutBuilder &builder)
-{
- uiLayout *prev_layout = builder.current_layout();
-
- uiLayout *box = uiLayoutBox(prev_layout);
- uiLayoutColumn(box, false);
-
- foreach_item([&builder](AbstractTreeViewItem &item) { builder.build_row(item); },
- IterOptions::SkipCollapsed);
-
- UI_block_layout_set_current(&builder.block(), prev_layout);
-}
-
void AbstractTreeView::update_from_old(uiBlock &new_block)
{
uiBlock *old_block = new_block.oldblock;
@@ -111,7 +98,10 @@ void AbstractTreeView::update_from_old(uiBlock &new_block)
uiTreeViewHandle *old_view_handle = ui_block_view_find_matching_in_old_block(
&new_block, reinterpret_cast<uiTreeViewHandle *>(this));
- BLI_assert(old_view_handle);
+ if (old_view_handle == nullptr) {
+ is_reconstructed_ = true;
+ return;
+ }
AbstractTreeView &old_view = reinterpret_cast<AbstractTreeView &>(*old_view_handle);
@@ -127,8 +117,8 @@ void AbstractTreeView::update_from_old(uiBlock &new_block)
is_reconstructed_ = true;
}
-void AbstractTreeView::update_children_from_old_recursive(const TreeViewItemContainer &new_items,
- const TreeViewItemContainer &old_items)
+void AbstractTreeView::update_children_from_old_recursive(const TreeViewOrItem &new_items,
+ const TreeViewOrItem &old_items)
{
for (const auto &new_item : new_items.children_) {
AbstractTreeViewItem *matching_old_item = find_matching_child(*new_item, old_items);
@@ -144,7 +134,7 @@ void AbstractTreeView::update_children_from_old_recursive(const TreeViewItemCont
}
AbstractTreeViewItem *AbstractTreeView::find_matching_child(
- const AbstractTreeViewItem &lookup_item, const TreeViewItemContainer &items)
+ const AbstractTreeViewItem &lookup_item, const TreeViewOrItem &items)
{
for (const auto &iter_item : items.children_) {
if (lookup_item.matches(*iter_item)) {
@@ -180,6 +170,9 @@ void AbstractTreeViewItem::tree_row_click_fn(struct bContext * /*C*/,
*tree_row_but->tree_item);
tree_item.activate();
+ /* Not only activate the item, also show its children. Maybe this should be optional, or
+ * controlled by the specific tree-view. */
+ tree_item.set_collapsed(false);
}
void AbstractTreeViewItem::add_treerow_button(uiBlock &block)
@@ -350,9 +343,14 @@ void AbstractTreeViewItem::on_activate()
/* Do nothing by default. */
}
-void AbstractTreeViewItem::is_active(IsActiveFn is_active_fn)
+std::optional<bool> AbstractTreeViewItem::should_be_active() const
{
- is_active_fn_ = is_active_fn;
+ return std::nullopt;
+}
+
+bool AbstractTreeViewItem::supports_collapsing() const
+{
+ return true;
}
std::unique_ptr<AbstractTreeViewItemDragController> AbstractTreeViewItem::create_drag_controller()
@@ -369,7 +367,7 @@ std::unique_ptr<AbstractTreeViewItemDropController> AbstractTreeViewItem::create
return nullptr;
}
-bool AbstractTreeViewItem::can_rename() const
+bool AbstractTreeViewItem::supports_renaming() const
{
/* No renaming by default. */
return false;
@@ -403,7 +401,7 @@ bool AbstractTreeViewItem::matches(const AbstractTreeViewItem &other) const
void AbstractTreeViewItem::begin_renaming()
{
AbstractTreeView &tree_view = get_tree_view();
- if (tree_view.is_renaming() || !can_rename()) {
+ if (tree_view.is_renaming() || !supports_renaming()) {
return;
}
@@ -433,7 +431,7 @@ AbstractTreeView &AbstractTreeViewItem::get_tree_view() const
int AbstractTreeViewItem::count_parents() const
{
int i = 0;
- for (TreeViewItemContainer *parent = parent_; parent; parent = parent->parent_) {
+ for (AbstractTreeViewItem *parent = parent_; parent; parent = parent->parent_) {
i++;
}
return i;
@@ -504,7 +502,10 @@ void AbstractTreeViewItem::set_collapsed(bool collapsed)
bool AbstractTreeViewItem::is_collapsible() const
{
- return !children_.is_empty();
+ if (children_.is_empty()) {
+ return false;
+ }
+ return this->supports_collapsing();
}
bool AbstractTreeViewItem::is_renaming() const
@@ -546,43 +547,69 @@ uiButTreeRow *AbstractTreeViewItem::tree_row_button()
void AbstractTreeViewItem::change_state_delayed()
{
- if (is_active_fn_()) {
+ const std::optional<bool> should_be_active = this->should_be_active();
+ if (should_be_active.has_value() && *should_be_active) {
activate();
}
}
+
/* ---------------------------------------------------------------------- */
-AbstractTreeViewItemDropController::AbstractTreeViewItemDropController(AbstractTreeView &tree_view)
+AbstractTreeViewItemDragController::AbstractTreeViewItemDragController(AbstractTreeView &tree_view)
: tree_view_(tree_view)
{
}
-/* ---------------------------------------------------------------------- */
-
-TreeViewBuilder::TreeViewBuilder(uiBlock &block) : block_(block)
+void AbstractTreeViewItemDragController::on_drag_start()
{
+ /* Do nothing by default. */
}
-void TreeViewBuilder::build_tree_view(AbstractTreeView &tree_view)
+/* ---------------------------------------------------------------------- */
+
+AbstractTreeViewItemDropController::AbstractTreeViewItemDropController(AbstractTreeView &tree_view)
+ : tree_view_(tree_view)
{
- tree_view.build_tree();
- tree_view.update_from_old(block_);
- tree_view.change_state_delayed();
- tree_view.build_layout_from_tree(TreeViewLayoutBuilder(block_));
}
/* ---------------------------------------------------------------------- */
+class TreeViewLayoutBuilder {
+ uiBlock &block_;
+
+ friend TreeViewBuilder;
+
+ public:
+ void build_from_tree(const AbstractTreeView &tree_view);
+ void build_row(AbstractTreeViewItem &item) const;
+
+ uiBlock &block() const;
+ uiLayout *current_layout() const;
+
+ private:
+ /* Created through #TreeViewBuilder. */
+ TreeViewLayoutBuilder(uiBlock &block);
+
+ static void polish_layout(const uiBlock &block);
+};
+
TreeViewLayoutBuilder::TreeViewLayoutBuilder(uiBlock &block) : block_(block)
{
}
-/**
- * Moves the button following the last added chevron closer to the list item.
- *
- * Iterates backwards over buttons until finding the tree-row button, which is assumed to be the
- * first button added for the row, and can act as a delimiter that way.
- */
+void TreeViewLayoutBuilder::build_from_tree(const AbstractTreeView &tree_view)
+{
+ uiLayout *prev_layout = current_layout();
+
+ uiLayout *box = uiLayoutBox(prev_layout);
+ uiLayoutColumn(box, false);
+
+ tree_view.foreach_item([this](AbstractTreeViewItem &item) { build_row(item); },
+ AbstractTreeView::IterOptions::SkipCollapsed);
+
+ UI_block_layout_set_current(&block(), prev_layout);
+}
+
void TreeViewLayoutBuilder::polish_layout(const uiBlock &block)
{
LISTBASE_FOREACH_BACKWARD (uiBut *, but, &block.buttons) {
@@ -642,6 +669,22 @@ uiLayout *TreeViewLayoutBuilder::current_layout() const
/* ---------------------------------------------------------------------- */
+TreeViewBuilder::TreeViewBuilder(uiBlock &block) : block_(block)
+{
+}
+
+void TreeViewBuilder::build_tree_view(AbstractTreeView &tree_view)
+{
+ tree_view.build_tree();
+ tree_view.update_from_old(block_);
+ tree_view.change_state_delayed();
+
+ TreeViewLayoutBuilder builder(block_);
+ builder.build_from_tree(tree_view);
+}
+
+/* ---------------------------------------------------------------------- */
+
BasicTreeViewItem::BasicTreeViewItem(StringRef label, BIFIconID icon_) : icon(icon_)
{
label_ = label;
@@ -670,13 +713,110 @@ void BasicTreeViewItem::on_activate()
}
}
-void BasicTreeViewItem::on_activate(ActivateFn fn)
+void BasicTreeViewItem::set_on_activate_fn(ActivateFn fn)
{
activate_fn_ = fn;
}
+void BasicTreeViewItem::set_is_active_fn(IsActiveFn is_active_fn)
+{
+ is_active_fn_ = is_active_fn;
+}
+
+std::optional<bool> BasicTreeViewItem::should_be_active() const
+{
+ if (is_active_fn_) {
+ return is_active_fn_();
+ }
+ return std::nullopt;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/**
+ * Helper for a public (C-)API, presenting higher level functionality. Has access to internal
+ * data/functionality (friend of #AbstractTreeViewItem), which is sometimes needed when
+ * functionality of the API needs to be constructed from multiple internal conditions and/or
+ * functions that on their own shouldn't be part of the API.
+ */
+class TreeViewItemAPIWrapper {
+ public:
+ static bool matches(const AbstractTreeViewItem &a, const AbstractTreeViewItem &b)
+ {
+ /* TODO should match the tree-view as well. */
+ return a.matches_including_parents(b);
+ }
+
+ static bool drag_start(bContext &C, const AbstractTreeViewItem &item)
+ {
+ const std::unique_ptr<AbstractTreeViewItemDragController> drag_controller =
+ item.create_drag_controller();
+ if (!drag_controller) {
+ return false;
+ }
+
+ WM_event_start_drag(&C,
+ ICON_NONE,
+ drag_controller->get_drag_type(),
+ drag_controller->create_drag_data(),
+ 0,
+ WM_DRAG_FREE_DATA);
+ drag_controller->on_drag_start();
+
+ return true;
+ }
+
+ static bool can_drop(const AbstractTreeViewItem &item,
+ const wmDrag &drag,
+ const char **r_disabled_hint)
+ {
+ const std::unique_ptr<AbstractTreeViewItemDropController> drop_controller =
+ item.create_drop_controller();
+ if (!drop_controller) {
+ return false;
+ }
+
+ return drop_controller->can_drop(drag, r_disabled_hint);
+ }
+
+ static std::string drop_tooltip(const AbstractTreeViewItem &item, const wmDrag &drag)
+ {
+ const std::unique_ptr<AbstractTreeViewItemDropController> drop_controller =
+ item.create_drop_controller();
+ if (!drop_controller) {
+ return {};
+ }
+
+ return drop_controller->drop_tooltip(drag);
+ }
+
+ static bool drop_handle(bContext &C, const AbstractTreeViewItem &item, const ListBase &drags)
+ {
+ std::unique_ptr<AbstractTreeViewItemDropController> drop_controller =
+ item.create_drop_controller();
+
+ const char *disabled_hint_dummy = nullptr;
+ LISTBASE_FOREACH (const wmDrag *, drag, &drags) {
+ if (drop_controller->can_drop(*drag, &disabled_hint_dummy)) {
+ return drop_controller->on_drop(&C, *drag);
+ }
+ }
+
+ return false;
+ }
+
+ static bool can_rename(const AbstractTreeViewItem &item)
+ {
+ const AbstractTreeView &tree_view = item.get_tree_view();
+ return !tree_view.is_renaming() && item.supports_renaming();
+ }
+};
+
} // namespace blender::ui
+/* ---------------------------------------------------------------------- */
+/* C-API */
+
using namespace blender::ui;
bool UI_tree_view_item_is_active(const uiTreeViewItemHandle *item_handle)
@@ -690,31 +830,13 @@ bool UI_tree_view_item_matches(const uiTreeViewItemHandle *a_handle,
{
const AbstractTreeViewItem &a = reinterpret_cast<const AbstractTreeViewItem &>(*a_handle);
const AbstractTreeViewItem &b = reinterpret_cast<const AbstractTreeViewItem &>(*b_handle);
- /* TODO should match the tree-view as well. */
- return a.matches_including_parents(b);
+ return TreeViewItemAPIWrapper::matches(a, b);
}
-/**
- * Attempt to start dragging the tree-item \a item_. This will not work if the tree item doesn't
- * support dragging, i.e. it won't create a drag-controller upon request.
- * \return True if dragging started successfully, otherwise false.
- */
bool UI_tree_view_item_drag_start(bContext *C, uiTreeViewItemHandle *item_)
{
const AbstractTreeViewItem &item = reinterpret_cast<const AbstractTreeViewItem &>(*item_);
- const std::unique_ptr<AbstractTreeViewItemDragController> drag_controller =
- item.create_drag_controller();
- if (!drag_controller) {
- return false;
- }
-
- WM_event_start_drag(C,
- ICON_NONE,
- drag_controller->get_drag_type(),
- drag_controller->create_drag_data(),
- 0,
- WM_DRAG_FREE_DATA);
- return true;
+ return TreeViewItemAPIWrapper::drag_start(*C, item);
}
bool UI_tree_view_item_can_drop(const uiTreeViewItemHandle *item_,
@@ -722,57 +844,29 @@ bool UI_tree_view_item_can_drop(const uiTreeViewItemHandle *item_,
const char **r_disabled_hint)
{
const AbstractTreeViewItem &item = reinterpret_cast<const AbstractTreeViewItem &>(*item_);
- const std::unique_ptr<AbstractTreeViewItemDropController> drop_controller =
- item.create_drop_controller();
- if (!drop_controller) {
- return false;
- }
-
- return drop_controller->can_drop(*drag, r_disabled_hint);
+ return TreeViewItemAPIWrapper::can_drop(item, *drag, r_disabled_hint);
}
char *UI_tree_view_item_drop_tooltip(const uiTreeViewItemHandle *item_, const wmDrag *drag)
{
const AbstractTreeViewItem &item = reinterpret_cast<const AbstractTreeViewItem &>(*item_);
- const std::unique_ptr<AbstractTreeViewItemDropController> drop_controller =
- item.create_drop_controller();
- if (!drop_controller) {
- return nullptr;
- }
- return BLI_strdup(drop_controller->drop_tooltip(*drag).c_str());
+ const std::string tooltip = TreeViewItemAPIWrapper::drop_tooltip(item, *drag);
+ return tooltip.empty() ? nullptr : BLI_strdup(tooltip.c_str());
}
-/**
- * Let a tree-view item handle a drop event.
- * \return True if the drop was handled by the tree-view item.
- */
-bool UI_tree_view_item_drop_handle(uiTreeViewItemHandle *item_, const ListBase *drags)
+bool UI_tree_view_item_drop_handle(bContext *C,
+ const uiTreeViewItemHandle *item_,
+ const ListBase *drags)
{
- AbstractTreeViewItem &item = reinterpret_cast<AbstractTreeViewItem &>(*item_);
- std::unique_ptr<AbstractTreeViewItemDropController> drop_controller =
- item.create_drop_controller();
-
- const char *disabled_hint_dummy = nullptr;
- LISTBASE_FOREACH (const wmDrag *, drag, drags) {
- if (drop_controller->can_drop(*drag, &disabled_hint_dummy)) {
- return drop_controller->on_drop(*drag);
- }
- }
-
- return false;
+ const AbstractTreeViewItem &item = reinterpret_cast<const AbstractTreeViewItem &>(*item_);
+ return TreeViewItemAPIWrapper::drop_handle(*C, item, *drags);
}
-/**
- * Can \a item_handle be renamed right now? Not that this isn't just a mere wrapper around
- * #AbstractTreeViewItem::can_rename(). This also checks if there is another item being renamed,
- * and returns false if so.
- */
bool UI_tree_view_item_can_rename(const uiTreeViewItemHandle *item_handle)
{
const AbstractTreeViewItem &item = reinterpret_cast<const AbstractTreeViewItem &>(*item_handle);
- const AbstractTreeView &tree_view = item.get_tree_view();
- return !tree_view.is_renaming() && item.can_rename();
+ return TreeViewItemAPIWrapper::can_rename(item);
}
void UI_tree_view_item_begin_rename(uiTreeViewItemHandle *item_handle)
diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c
index 9a6fbbf4016..b530693a7e5 100644
--- a/source/blender/editors/interface/view2d.c
+++ b/source/blender/editors/interface/view2d.c
@@ -228,16 +228,6 @@ static void view2d_masks(View2D *v2d, const rcti *mask_scroll)
/** \name View2D Refresh and Validation (Spatial)
* \{ */
-/**
- * Initialize all relevant View2D data (including view rects if first time)
- * and/or refresh mask sizes after view resize.
- *
- * - For some of these presets, it is expected that the region will have defined some
- * additional settings necessary for the customization of the 2D viewport to its requirements
- * - This function should only be called from region init() callbacks, where it is expected that
- * this is called before #UI_view2d_size_update(),
- * as this one checks that the rects are properly initialized.
- */
void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy)
{
bool tot_changed = false, do_init;
@@ -872,8 +862,6 @@ bool UI_view2d_area_supports_sync(ScrArea *area)
return ELEM(area->spacetype, SPACE_ACTION, SPACE_NLA, SPACE_SEQ, SPACE_CLIP, SPACE_GRAPH);
}
-/* Called by menus to activate it, or by view2d operators
- * to make sure 'related' views stay in synchrony */
void UI_view2d_sync(bScreen *screen, ScrArea *area, View2D *v2dcur, int flag)
{
/* don't continue if no view syncing to be done */
@@ -937,11 +925,6 @@ void UI_view2d_sync(bScreen *screen, ScrArea *area, View2D *v2dcur, int flag)
}
}
-/**
- * Restore 'cur' rect to standard orientation (i.e. optimal maximum view of tot).
- * This does not take into account if zooming the view on an axis
- * will improve the view (if allowed).
- */
void UI_view2d_curRect_reset(View2D *v2d)
{
float width, height;
@@ -991,7 +974,6 @@ void UI_view2d_curRect_reset(View2D *v2d)
/* ------------------ */
-/* Change the size of the maximum viewable area (i.e. 'tot' rect) */
void UI_view2d_totRect_set_resize(View2D *v2d, int width, int height, bool resize)
{
/* don't do anything if either value is 0 */
@@ -1110,7 +1092,6 @@ static void view2d_map_cur_using_mask(const View2D *v2d, rctf *r_curmasked)
}
}
-/* Set view matrices to use 'cur' rect as viewing frame for View2D drawing */
void UI_view2d_view_ortho(const View2D *v2d)
{
rctf curmasked;
@@ -1152,12 +1133,6 @@ void UI_view2d_view_ortho(const View2D *v2d)
wmOrtho2(curmasked.xmin, curmasked.xmax, curmasked.ymin, curmasked.ymax);
}
-/**
- * Set view matrices to only use one axis of 'cur' only
- *
- * \param xaxis: if non-zero, only use cur x-axis,
- * otherwise use cur-yaxis (mostly this will be used for x).
- */
void UI_view2d_view_orthoSpecial(ARegion *region, View2D *v2d, const bool xaxis)
{
rctf curmasked;
@@ -1184,7 +1159,6 @@ void UI_view2d_view_orthoSpecial(ARegion *region, View2D *v2d, const bool xaxis)
}
}
-/* Restore view matrices after drawing */
void UI_view2d_view_restore(const bContext *C)
{
ARegion *region = CTX_wm_region(C);
@@ -1203,7 +1177,6 @@ void UI_view2d_view_restore(const bContext *C)
/** \name Grid-Line Drawing
* \{ */
-/* Draw a multi-level grid in given 2d-region */
void UI_view2d_multi_grid_draw(
const View2D *v2d, int colorid, float step, int level_size, int totlevels)
{
@@ -1335,14 +1308,6 @@ static const DotGridLevelInfo level_info[9] = {
{0.025f, 0.6f, 0.9f},
};
-/**
- * Draw a multi-level grid of dots, with a dynamic number of levels based on the fading.
- *
- * \param grid_color_id: The theme color used for the points. Faded dynamically based on zoom.
- * \param min_step: The base size of the grid. At different zoom levels, the visible grid may have
- * a larger step size.
- * \param grid_levels: The maximum grid depth. Larger grid levels will subdivide the grid more.
- */
void UI_view2d_dot_grid_draw(const View2D *v2d,
const int grid_color_id,
const float min_step,
@@ -1400,6 +1365,7 @@ void UI_view2d_dot_grid_draw(const View2D *v2d,
immUnbindProgram();
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1414,6 +1380,8 @@ void UI_view2d_dot_grid_draw(const View2D *v2d,
*/
struct View2DScrollers {
/* focus bubbles */
+ /* focus bubbles */
+ /* focus bubbles */
int vert_min, vert_max; /* vertical scrollbar */
int hor_min, hor_max; /* horizontal scrollbar */
@@ -1423,7 +1391,6 @@ struct View2DScrollers {
/* int horfull, vertfull; */ /* UNUSED */
};
-/* Calculate relevant scroller properties */
void UI_view2d_scrollers_calc(View2D *v2d,
const rcti *mask_custom,
struct View2DScrollers *r_scrollers)
@@ -1550,7 +1517,6 @@ void UI_view2d_scrollers_calc(View2D *v2d,
}
}
-/* Draw scrollbars in the given 2d-region */
void UI_view2d_scrollers_draw(View2D *v2d, const rcti *mask_custom)
{
View2DScrollers scrollers;
@@ -1646,18 +1612,6 @@ void UI_view2d_scrollers_draw(View2D *v2d, const rcti *mask_custom)
/** \name List View Utilities
* \{ */
-/**
- * Get the 'cell' (row, column) that the given 2D-view coordinates
- * (i.e. in 'tot' rect space) lie in.
- *
- * \param columnwidth, rowheight: size of each 'cell'
- * \param startx, starty: coordinates (in 'tot' rect space) that the list starts from.
- * This should be (0,0) for most views. However, for those where the starting row was offsetted
- * (like for Animation Editor channel lists, to make the first entry more visible), these will be
- * the min-coordinates of the first item.
- * \param viewx, viewy: 2D-coordinates (in 2D-view / 'tot' rect space) to get the cell for
- * \param r_column, r_row: the 'coordinates' of the relevant 'cell'
- */
void UI_view2d_listview_view_to_cell(float columnwidth,
float rowheight,
float startx,
@@ -1705,12 +1659,6 @@ float UI_view2d_region_to_view_y(const struct View2D *v2d, float y)
(BLI_rctf_size_y(&v2d->cur) * (y - v2d->mask.ymin) / BLI_rcti_size_y(&v2d->mask)));
}
-/**
- * Convert from screen/region space to 2d-View space
- *
- * \param x, y: coordinates to convert
- * \param r_view_x, r_view_y: resultant coordinates
- */
void UI_view2d_region_to_view(
const View2D *v2d, float x, float y, float *r_view_x, float *r_view_y)
{
@@ -1744,13 +1692,6 @@ float UI_view2d_view_to_region_y(const View2D *v2d, float y)
(((y - v2d->cur.ymin) / BLI_rctf_size_y(&v2d->cur)) * BLI_rcti_size_y(&v2d->mask)));
}
-/**
- * Convert from 2d-View space to screen/region space
- * \note Coordinates are clamped to lie within bounds of region
- *
- * \param x, y: Coordinates to convert.
- * \param r_region_x, r_region_y: Resultant coordinates.
- */
bool UI_view2d_view_to_region_clip(
const View2D *v2d, float x, float y, int *r_region_x, int *r_region_y)
{
@@ -1772,14 +1713,6 @@ bool UI_view2d_view_to_region_clip(
return false;
}
-/**
- * Convert from 2d-view space to screen/region space
- *
- * \note Coordinates are NOT clamped to lie within bounds of region.
- *
- * \param x, y: Coordinates to convert.
- * \param r_region_x, r_region_y: Resultant coordinates.
- */
void UI_view2d_view_to_region(
const View2D *v2d, float x, float y, int *r_region_x, int *r_region_y)
{
@@ -1874,7 +1807,6 @@ bool UI_view2d_view_to_region_rcti_clip(const View2D *v2d, const rctf *rect_src,
/** \name Utilities
* \{ */
-/* View2D data by default resides in region, so get from region stored in context */
View2D *UI_view2d_fromcontext(const bContext *C)
{
ScrArea *area = CTX_wm_area(C);
@@ -1889,7 +1821,6 @@ View2D *UI_view2d_fromcontext(const bContext *C)
return &(region->v2d);
}
-/* Same as above, but it returns region-window. Utility for pull-downs or buttons. */
View2D *UI_view2d_fromcontext_rwin(const bContext *C)
{
ScrArea *area = CTX_wm_area(C);
@@ -1908,8 +1839,6 @@ View2D *UI_view2d_fromcontext_rwin(const bContext *C)
return &(region->v2d);
}
-/* Get scrollbar sizes of the current 2D view. The size will be zero if the view has its scrollbars
- * disabled. */
void UI_view2d_scroller_size_get(const View2D *v2d, float *r_x, float *r_y)
{
const int scroll = view2d_scroll_mapped(v2d->scroll);
@@ -1933,14 +1862,6 @@ void UI_view2d_scroller_size_get(const View2D *v2d, float *r_x, float *r_y)
}
}
-/**
- * Calculate the scale per-axis of the drawing-area
- *
- * Is used to inverse correct drawing of icons, etc. that need to follow view
- * but not be affected by scale
- *
- * \param r_x, r_y: scale on each axis
- */
void UI_view2d_scale_get(const View2D *v2d, float *r_x, float *r_y)
{
if (r_x) {
@@ -1958,9 +1879,6 @@ float UI_view2d_scale_get_y(const View2D *v2d)
{
return BLI_rcti_size_y(&v2d->mask) / BLI_rctf_size_y(&v2d->cur);
}
-/**
- * Same as `UI_view2d_scale_get() - 1.0f / x, y`.
- */
void UI_view2d_scale_get_inverse(const View2D *v2d, float *r_x, float *r_y)
{
if (r_x) {
@@ -1971,10 +1889,6 @@ void UI_view2d_scale_get_inverse(const 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(const struct View2D *v2d, float *r_x, float *r_y)
{
/* get center */
@@ -1993,12 +1907,6 @@ void UI_view2d_center_set(struct View2D *v2d, float x, float y)
UI_view2d_curRect_validate(v2d);
}
-/**
- * Simple pan function
- * (0.0, 0.0) bottom left
- * (0.5, 0.5) center
- * (1.0, 1.0) top right.
- */
void UI_view2d_offset(struct View2D *v2d, float xfac, float yfac)
{
if (xfac != -1.0f) {
@@ -2022,17 +1930,6 @@ void UI_view2d_offset(struct View2D *v2d, float xfac, float yfac)
UI_view2d_curRect_validate(v2d);
}
-/**
- * Check if mouse is within scrollers
- *
- * \param x, y: Mouse coordinates in screen (not region) space.
- * \param r_scroll: Mapped view2d scroll flag.
- *
- * \return appropriate code for match.
- * - 'h' = in horizontal scroller.
- * - 'v' = in vertical scroller.
- * - 0 = not in scroller.
- */
char UI_view2d_mouse_in_scrollers_ex(const ARegion *region,
const View2D *v2d,
const int xy[2],
@@ -2154,7 +2051,6 @@ void UI_view2d_text_cache_add(
}
}
-/* no clip (yet) */
void UI_view2d_text_cache_add_rectf(
View2D *v2d, const rctf *rect_view, const char *str, size_t str_len, const uchar col[4])
{
diff --git a/source/blender/editors/interface/view2d_gizmo_navigate.c b/source/blender/editors/interface/view2d_gizmo_navigate.c
index 3ff5b471731..2497081b412 100644
--- a/source/blender/editors/interface/view2d_gizmo_navigate.c
+++ b/source/blender/editors/interface/view2d_gizmo_navigate.c
@@ -251,7 +251,6 @@ static void WIDGETGROUP_navigate_draw_prepare(const bContext *C, wmGizmoGroup *g
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
}
-/* Caller defines the name for gizmo group. */
void VIEW2D_GGT_navigate_impl(wmGizmoGroupType *gzgt, const char *idname)
{
gzgt->name = "View2D Navigate";
diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c
index 0bca4e327cc..0d3c427bf39 100644
--- a/source/blender/editors/interface/view2d_ops.c
+++ b/source/blender/editors/interface/view2d_ops.c
@@ -1570,8 +1570,6 @@ static float smooth_view_rect_to_fac(const rctf *rect_a, const rctf *rect_b)
return min_ff(fac_max, 1.0f);
}
-/* will start timer if appropriate */
-/* the arguments are the desired situation */
void UI_view2d_smooth_view(bContext *C, ARegion *region, const rctf *cur, const int smooth_viewtx)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -1761,7 +1759,6 @@ typedef struct v2dScrollerMove {
* For now, we don't need to have a separate (internal) header for structs like this...
*/
struct View2DScrollers {
- /* focus bubbles */
int vert_min, vert_max; /* vertical scrollbar */
int hor_min, hor_max; /* horizontal scrollbar */
diff --git a/source/blender/editors/lattice/editlattice_tools.c b/source/blender/editors/lattice/editlattice_tools.c
index d503cbc87b8..15325c7648c 100644
--- a/source/blender/editors/lattice/editlattice_tools.c
+++ b/source/blender/editors/lattice/editlattice_tools.c
@@ -47,8 +47,6 @@
#include "lattice_intern.h"
-/** \} */
-
/* -------------------------------------------------------------------- */
/** \name Make Regular Operator
* \{ */
diff --git a/source/blender/editors/lattice/editlattice_undo.c b/source/blender/editors/lattice/editlattice_undo.c
index 23eaf991fd3..6d79d063a2f 100644
--- a/source/blender/editors/lattice/editlattice_undo.c
+++ b/source/blender/editors/lattice/editlattice_undo.c
@@ -278,7 +278,6 @@ static void lattice_undosys_foreach_ID_ref(UndoStep *us_p,
}
}
-/* Export for ED_undo_sys. */
void ED_lattice_undosys_type(UndoType *ut)
{
ut->name = "Edit Lattice";
diff --git a/source/blender/editors/mask/mask_draw.c b/source/blender/editors/mask/mask_draw.c
index 22232e9c87e..9504a8783a0 100644
--- a/source/blender/editors/mask/mask_draw.c
+++ b/source/blender/editors/mask/mask_draw.c
@@ -587,6 +587,35 @@ static void draw_spline_curve(const bContext *C,
}
}
+static void draw_layer_splines(const bContext *C,
+ MaskLayer *layer,
+ const char draw_flag,
+ const char draw_type,
+ const int width,
+ const int height,
+ const bool is_active)
+{
+ LISTBASE_FOREACH (MaskSpline *, spline, &layer->splines) {
+ /* draw curve itself first... */
+ draw_spline_curve(C, layer, spline, draw_flag, draw_type, is_active, width, height);
+
+ if (!(layer->visibility_flag & MASK_HIDE_SELECT)) {
+ /* ...and then handles over the curve so they're nicely visible */
+ draw_spline_points(C, layer, spline, draw_flag, draw_type);
+ }
+
+ /* show undeform for testing */
+ if (0) {
+ void *back = spline->points_deform;
+
+ spline->points_deform = NULL;
+ draw_spline_curve(C, layer, spline, draw_flag, draw_type, is_active, width, height);
+ draw_spline_points(C, layer, spline, draw_flag, draw_type);
+ spline->points_deform = back;
+ }
+ }
+}
+
static void draw_mask_layers(const bContext *C,
Mask *mask,
const char draw_flag,
@@ -600,6 +629,7 @@ static void draw_mask_layers(const bContext *C,
MaskLayer *mask_layer;
int i;
+ MaskLayer *active = NULL;
for (mask_layer = mask->masklayers.first, i = 0; mask_layer != NULL;
mask_layer = mask_layer->next, i++) {
const bool is_active = (i == mask->masklay_act);
@@ -608,26 +638,16 @@ static void draw_mask_layers(const bContext *C,
continue;
}
- LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) {
-
- /* draw curve itself first... */
- draw_spline_curve(C, mask_layer, spline, draw_flag, draw_type, is_active, width, height);
-
- if (!(mask_layer->visibility_flag & MASK_HIDE_SELECT)) {
- /* ...and then handles over the curve so they're nicely visible */
- draw_spline_points(C, mask_layer, spline, draw_flag, draw_type);
- }
+ if (is_active) {
+ active = mask_layer;
+ continue;
+ }
- /* show undeform for testing */
- if (0) {
- void *back = spline->points_deform;
+ draw_layer_splines(C, mask_layer, draw_flag, draw_type, width, height, is_active);
+ }
- spline->points_deform = NULL;
- draw_spline_curve(C, mask_layer, spline, draw_flag, draw_type, is_active, width, height);
- draw_spline_points(C, mask_layer, spline, draw_flag, draw_type);
- spline->points_deform = back;
- }
- }
+ if (active != NULL) {
+ draw_layer_splines(C, active, draw_flag, draw_type, width, height, true);
}
GPU_program_point_size(false);
@@ -666,8 +686,6 @@ static float *mask_rasterize(Mask *mask, const int width, const int height)
return buffer;
}
-/* sets up the opengl context.
- * width, height are to match the values from ED_mask_get_size() */
void ED_mask_draw_region(
Depsgraph *depsgraph,
Mask *mask_,
diff --git a/source/blender/editors/mask/mask_editaction.c b/source/blender/editors/mask/mask_editaction.c
index d9efbef4b42..3668f3bb34e 100644
--- a/source/blender/editors/mask/mask_editaction.c
+++ b/source/blender/editors/mask/mask_editaction.c
@@ -52,7 +52,6 @@
/* ***************************************** */
/* Generics - Loopers */
-/* Loops over the mask-frames for a mask-layer, and applies the given callback */
bool ED_masklayer_frames_looper(MaskLayer *mask_layer,
Scene *scene,
bool (*mask_layer_shape_cb)(MaskLayerShape *, Scene *))
@@ -80,7 +79,6 @@ bool ED_masklayer_frames_looper(MaskLayer *mask_layer,
/* ****************************************** */
/* Data Conversion Tools */
-/* make a listing all the mask-frames in a layer as cfraelems */
void ED_masklayer_make_cfra_list(MaskLayer *mask_layer, ListBase *elems, bool onlysel)
{
MaskLayerShape *mask_layer_shape;
@@ -108,7 +106,6 @@ void ED_masklayer_make_cfra_list(MaskLayer *mask_layer, ListBase *elems, bool on
/* ***************************************** */
/* Selection Tools */
-/* check if one of the frames in this layer is selected */
bool ED_masklayer_frame_select_check(const MaskLayer *mask_layer)
{
MaskLayerShape *mask_layer_shape;
@@ -150,7 +147,6 @@ static void mask_layer_shape_select(MaskLayerShape *mask_layer_shape, short sele
}
}
-/* set all/none/invert select (like above, but with SELECT_* modes) */
void ED_mask_select_frames(MaskLayer *mask_layer, short select_mode)
{
MaskLayerShape *mask_layer_shape;
@@ -167,7 +163,6 @@ void ED_mask_select_frames(MaskLayer *mask_layer, short select_mode)
}
}
-/* set all/none/invert select */
void ED_masklayer_frame_select_set(MaskLayer *mask_layer, short mode)
{
/* error checking */
@@ -179,7 +174,6 @@ void ED_masklayer_frame_select_set(MaskLayer *mask_layer, short mode)
ED_mask_select_frames(mask_layer, mode);
}
-/* select the frame in this layer that occurs on this frame (there should only be one at most) */
void ED_mask_select_frame(MaskLayer *mask_layer, int selx, short select_mode)
{
MaskLayerShape *mask_layer_shape;
@@ -195,7 +189,6 @@ void ED_mask_select_frame(MaskLayer *mask_layer, int selx, short select_mode)
}
}
-/* select the frames in this layer that occur within the bounds specified */
void ED_masklayer_frames_select_box(MaskLayer *mask_layer, float min, float max, short select_mode)
{
MaskLayerShape *mask_layer_shape;
@@ -213,7 +206,6 @@ void ED_masklayer_frames_select_box(MaskLayer *mask_layer, float min, float max,
}
}
-/* select the frames in this layer that occur within the lasso/circle region specified */
void ED_masklayer_frames_select_region(KeyframeEditData *ked,
MaskLayer *mask_layer,
short tool,
@@ -253,7 +245,6 @@ void ED_masklayer_frames_select_region(KeyframeEditData *ked,
/* ***************************************** */
/* Frame Editing Tools */
-/* Delete selected frames */
bool ED_masklayer_frames_delete(MaskLayer *mask_layer)
{
MaskLayerShape *mask_layer_shape, *mask_layer_shape_next;
@@ -278,7 +269,6 @@ bool ED_masklayer_frames_delete(MaskLayer *mask_layer)
return changed;
}
-/* Duplicate selected frames from given mask-layer */
void ED_masklayer_frames_duplicate(MaskLayer *mask_layer)
{
MaskLayerShape *mask_layer_shape, *gpfn;
@@ -344,7 +334,6 @@ static bool snap_mask_layer_nearmarker(MaskLayerShape *mask_layer_shape, Scene *
return false;
}
-/* snap selected frames to ... */
void ED_masklayer_snap_frames(MaskLayer *mask_layer, Scene *scene, short mode)
{
switch (mode) {
diff --git a/source/blender/editors/mask/mask_intern.h b/source/blender/editors/mask/mask_intern.h
index ee1784011ea..41ff14dcd5f 100644
--- a/source/blender/editors/mask/mask_intern.h
+++ b/source/blender/editors/mask/mask_intern.h
@@ -32,13 +32,18 @@ struct wmOperatorType;
/* internal exports only */
/* mask_add.c */
+
void MASK_OT_add_vertex(struct wmOperatorType *ot);
void MASK_OT_add_feather_vertex(struct wmOperatorType *ot);
void MASK_OT_primitive_circle_add(struct wmOperatorType *ot);
void MASK_OT_primitive_square_add(struct wmOperatorType *ot);
/* mask_ops.c */
+
struct Mask *ED_mask_new(struct bContext *C, const char *name);
+/**
+ * Get active layer. Will create mask/layer to be sure there's an active layer.
+ */
struct MaskLayer *ED_mask_layer_ensure(struct bContext *C, bool *r_added_mask);
void MASK_OT_new(struct wmOperatorType *ot);
@@ -55,6 +60,7 @@ void MASK_OT_hide_view_clear(struct wmOperatorType *ot);
void MASK_OT_hide_view_set(struct wmOperatorType *ot);
void MASK_OT_feather_weight_clear(struct wmOperatorType *ot);
void MASK_OT_switch_direction(struct wmOperatorType *ot);
+/* Named to match mesh recalculate normals. */
void MASK_OT_normals_make_consistent(struct wmOperatorType *ot);
void MASK_OT_handle_type_set(struct wmOperatorType *ot);
@@ -66,10 +72,13 @@ void MASK_OT_copy_splines(struct wmOperatorType *ot);
void MASK_OT_paste_splines(struct wmOperatorType *ot);
/* mask_relationships.c */
+
+/** based on #OBJECT_OT_parent_set */
void MASK_OT_parent_set(struct wmOperatorType *ot);
void MASK_OT_parent_clear(struct wmOperatorType *ot);
/* mask_select.c */
+
void MASK_OT_select(struct wmOperatorType *ot);
void MASK_OT_select_all(struct wmOperatorType *ot);
@@ -81,6 +90,7 @@ void MASK_OT_select_linked(struct wmOperatorType *ot);
void MASK_OT_select_more(struct wmOperatorType *ot);
void MASK_OT_select_less(struct wmOperatorType *ot);
+/* 'check' select */
bool ED_mask_spline_select_check(const struct MaskSpline *spline);
bool ED_mask_layer_select_check(const struct MaskLayer *mask_layer);
bool ED_mask_select_check(const struct Mask *mask);
@@ -91,6 +101,7 @@ void ED_mask_select_toggle_all(struct Mask *mask, int action);
void ED_mask_select_flush_all(struct Mask *mask);
/* mask_editor.c */
+
bool ED_maskedit_poll(struct bContext *C);
bool ED_maskedit_mask_poll(struct bContext *C);
@@ -108,6 +119,7 @@ void ED_mask_view_lock_state_restore_no_jump(const struct bContext *C,
const MaskViewLockState *state);
/* mask_query.c */
+
bool ED_mask_find_nearest_diff_point(const struct bContext *C,
struct Mask *mask,
const float normal_co[2],
diff --git a/source/blender/editors/mask/mask_ops.c b/source/blender/editors/mask/mask_ops.c
index fd5925bbd0c..8feb526c8d5 100644
--- a/source/blender/editors/mask/mask_ops.c
+++ b/source/blender/editors/mask/mask_ops.c
@@ -83,9 +83,6 @@ Mask *ED_mask_new(bContext *C, const char *name)
return mask;
}
-/**
- * Get active layer. Will create mask/layer to be sure there's an active layer.
- */
MaskLayer *ED_mask_layer_ensure(bContext *C, bool *r_added_mask)
{
Mask *mask = CTX_data_edit_mask(C);
@@ -1616,7 +1613,6 @@ static int mask_normals_make_consistent_exec(bContext *C, wmOperator *UNUSED(op)
return OPERATOR_CANCELLED;
}
-/* Named to match mesh recalculate normals. */
void MASK_OT_normals_make_consistent(wmOperatorType *ot)
{
/* identifiers */
diff --git a/source/blender/editors/mask/mask_query.c b/source/blender/editors/mask/mask_query.c
index e66c4e45e27..de80d9f04bd 100644
--- a/source/blender/editors/mask/mask_query.c
+++ b/source/blender/editors/mask/mask_query.c
@@ -489,7 +489,6 @@ bool ED_mask_feather_find_nearest(const bContext *C,
return false;
}
-/* takes event->mval */
void ED_mask_mouse_pos(ScrArea *area, ARegion *region, const int mval[2], float co[2])
{
if (area) {
@@ -523,8 +522,6 @@ void ED_mask_mouse_pos(ScrArea *area, ARegion *region, const int mval[2], float
}
}
-/* input: x/y - mval space
- * output: xr/yr - mask point space */
void ED_mask_point_pos(ScrArea *area, ARegion *region, float x, float y, float *xr, float *yr)
{
float co[2];
diff --git a/source/blender/editors/mask/mask_relationships.c b/source/blender/editors/mask/mask_relationships.c
index 9c4740b3087..259402efbf1 100644
--- a/source/blender/editors/mask/mask_relationships.c
+++ b/source/blender/editors/mask/mask_relationships.c
@@ -168,7 +168,6 @@ static int mask_parent_set_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
-/** based on #OBJECT_OT_parent_set */
void MASK_OT_parent_set(wmOperatorType *ot)
{
/* identifiers */
diff --git a/source/blender/editors/mask/mask_select.c b/source/blender/editors/mask/mask_select.c
index fe6acac7d29..dd4a557f449 100644
--- a/source/blender/editors/mask/mask_select.c
+++ b/source/blender/editors/mask/mask_select.c
@@ -52,7 +52,6 @@
/** \name Public Mask Selection API
* \{ */
-/* 'check' select */
bool ED_mask_spline_select_check(const MaskSpline *spline)
{
for (int i = 0; i < spline->tot_point; i++) {
diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c
index 648008a4779..06547c94992 100644
--- a/source/blender/editors/mesh/editface.c
+++ b/source/blender/editors/mesh/editface.c
@@ -50,8 +50,6 @@
/* own include */
-/* copy the face flags, most importantly selection from the mesh to the final derived mesh,
- * use in object mode when selecting faces (while painting) */
void paintface_flush_flags(struct bContext *C, Object *ob, short flag)
{
Mesh *me = BKE_mesh_from_object(ob);
@@ -369,7 +367,7 @@ bool paintface_minmax(Object *ob, float r_min[3], float r_max[3])
continue;
}
- ml = me->mloop + mp->totloop;
+ ml = me->mloop + mp->loopstart;
for (b = 0; b < mp->totloop; b++, ml++) {
mul_v3_m3v3(vec, bmat, mvert[ml->v].co);
add_v3_v3v3(vec, vec, ob->obmat[3]);
@@ -437,9 +435,6 @@ bool paintface_mouse_select(
return true;
}
-/* (similar to void paintface_flush_flags(Object *ob))
- * copy the vertex flags, most importantly selection from the mesh to the final derived mesh,
- * use in object mode when selecting vertices (while painting) */
void paintvert_flush_flags(Object *ob)
{
Mesh *me = BKE_mesh_from_object(ob);
@@ -492,10 +487,6 @@ void paintvert_tag_select_update(struct bContext *C, struct Object *ob)
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
}
-/**
- * \note if the caller passes false to flush_flags,
- * then they will need to run #paintvert_flush_flags(ob) themselves.
- */
bool paintvert_deselect_all_visible(Object *ob, int action, bool flush_flags)
{
Mesh *me;
diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c
index 912399c25b3..913be7d69bb 100644
--- a/source/blender/editors/mesh/editmesh_extrude.c
+++ b/source/blender/editors/mesh/editmesh_extrude.c
@@ -144,7 +144,6 @@ static bool edbm_extrude_discrete_faces(BMEditMesh *em, wmOperator *op, const ch
return true;
}
-/* extrudes individual edges */
bool edbm_extrude_edges_indiv(BMEditMesh *em,
wmOperator *op,
const char hflag,
diff --git a/source/blender/editors/mesh/editmesh_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c
index ee227c58fe7..18fe9cf7ad3 100644
--- a/source/blender/editors/mesh/editmesh_intersect.c
+++ b/source/blender/editors/mesh/editmesh_intersect.c
@@ -114,6 +114,7 @@ static void edbm_intersect_select(BMEditMesh *em, struct Mesh *me, bool do_selec
}
}
}
+ EDBM_select_flush(em);
}
EDBM_update(me,
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index cd04f40dedf..3772a37ac44 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -210,7 +210,7 @@ typedef struct KnifeBVH {
typedef struct KnifeTool_OpData {
ARegion *region; /* Region that knifetool was activated in. */
void *draw_handle; /* For drawing preview loop. */
- ViewContext vc; /* Note: _don't_ use 'mval', instead use the one we define below. */
+ ViewContext vc; /* NOTE: _don't_ use 'mval', instead use the one we define below. */
float mval[2]; /* Mouse value with snapping applied. */
Scene *scene;
@@ -4143,7 +4143,7 @@ static void knifetool_exit_ex(KnifeTool_OpData *kcd)
for (int i = 0; i < kcd->objects_len; i++) {
knifetool_free_cagecos(kcd, i);
}
- MEM_freeN(kcd->cagecos);
+ MEM_freeN((void *)kcd->cagecos);
knife_bvh_free(kcd);
/* Line-hits cleanup. */
@@ -4866,9 +4866,6 @@ static bool edbm_mesh_knife_point_isect(LinkNode *polys, const float cent_ss[2])
return false;
}
-/**
- * \param use_tag: When set, tag all faces inside the polylines.
- */
void EDBM_mesh_knife(bContext *C, ViewContext *vc, LinkNode *polys, bool use_tag, bool cut_through)
{
KnifeTool_OpData *kcd;
diff --git a/source/blender/editors/mesh/editmesh_preselect_elem.c b/source/blender/editors/mesh/editmesh_preselect_elem.c
index dfd646c767f..ab268251061 100644
--- a/source/blender/editors/mesh/editmesh_preselect_elem.c
+++ b/source/blender/editors/mesh/editmesh_preselect_elem.c
@@ -411,4 +411,5 @@ void EDBM_preselect_elem_update_preview(struct EditMesh_PreSelElem *psel,
BLI_assert(0);
}
}
+
/** \} */
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c
index e0768bcff24..7e05209f79e 100644
--- a/source/blender/editors/mesh/editmesh_select.c
+++ b/source/blender/editors/mesh/editmesh_select.c
@@ -267,17 +267,6 @@ static void findnearestvert__doClosest(void *userData,
}
}
-/**
- * Nearest vertex under the cursor.
- *
- * \param dist_px_manhattan_p: (in/out), minimal distance to the nearest and at the end,
- * actual distance.
- * \param use_select_bias:
- * - When true, selected vertices are given a 5 pixel bias
- * to make them further than unselect verts.
- * - When false, unselected vertices are given the bias.
- * \param use_cycle: Cycle over elements within #FIND_NEAR_CYCLE_THRESHOLD_MIN in order of index.
- */
BMVert *EDBM_vert_find_nearest_ex(ViewContext *vc,
float *dist_px_manhattan_p,
const bool use_select_bias,
@@ -713,13 +702,6 @@ static void findnearestface__doClosest(void *userData,
}
}
-/**
- * \param use_zbuf_single_px: Special case, when using the back-buffer selection,
- * only use the pixel at `vc->mval` instead of using `dist_px_manhattan_p` to search over a larger
- * region. This is needed because historically selection worked this way for a long time, however
- * it's reasonable that some callers might want to expand the region too. So add an argument to do
- * this,
- */
BMFace *EDBM_face_find_nearest_ex(ViewContext *vc,
float *dist_px_manhattan_p,
float *r_dist_center,
@@ -2217,8 +2199,6 @@ static void edbm_strip_selections(BMEditMesh *em)
}
}
-/* when switching select mode, makes sure selection is consistent for editing */
-/* also for paranoia checks to make sure edge or face mode works */
void EDBM_selectmode_set(BMEditMesh *em)
{
BMVert *eve;
@@ -2273,20 +2253,6 @@ void EDBM_selectmode_set(BMEditMesh *em)
}
}
-/**
- * Expand & Contract the Selection
- * (used when changing modes and Ctrl key held)
- *
- * Flush the selection up:
- * - vert -> edge
- * - vert -> face
- * - edge -> face
- *
- * Flush the selection down:
- * - face -> edge
- * - face -> vert
- * - edge -> vert
- */
void EDBM_selectmode_convert(BMEditMesh *em,
const short selectmode_old,
const short selectmode_new)
@@ -2393,7 +2359,6 @@ void EDBM_selectmode_convert(BMEditMesh *em,
}
}
-/* user facing function, does notification */
bool EDBM_selectmode_toggle_multi(bContext *C,
const short selectmode_new,
const int action,
@@ -2569,12 +2534,6 @@ bool EDBM_selectmode_set_multi(bContext *C, const short selectmode)
return changed;
}
-/**
- * Use to disable a selectmode if its enabled, Using another mode as a fallback
- * if the disabled mode is the only mode set.
- *
- * \return true if the mode is changed.
- */
bool EDBM_selectmode_disable(Scene *scene,
BMEditMesh *em,
const short selectmode_disable,
diff --git a/source/blender/editors/mesh/editmesh_select_similar.c b/source/blender/editors/mesh/editmesh_select_similar.c
index c452f7a7487..f2311eb926d 100644
--- a/source/blender/editors/mesh/editmesh_select_similar.c
+++ b/source/blender/editors/mesh/editmesh_select_similar.c
@@ -974,6 +974,7 @@ static int similar_edge_select_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1255,6 +1256,7 @@ static int similar_vert_select_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index 6cd7d912820..633e8183eb3 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -8226,7 +8226,6 @@ enum {
EDBM_CLNOR_MODAL_POINTTO_SET_USE_SELECTED = 114,
};
-/* Called in transform_ops.c, on each regeneration of key-maps. */
wmKeyMap *point_normals_modal_keymap(wmKeyConfig *keyconf)
{
static const EnumPropertyItem modal_items[] = {
diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c
index f52cd94b8dc..f22d4bbe580 100644
--- a/source/blender/editors/mesh/editmesh_undo.c
+++ b/source/blender/editors/mesh/editmesh_undo.c
@@ -915,7 +915,6 @@ static void mesh_undosys_foreach_ID_ref(UndoStep *us_p,
}
}
-/* Export for ED_undo_sys. */
void ED_mesh_undosys_type(UndoType *ut)
{
ut->name = "Edit Mesh";
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index 3ba8f601937..013d5e5a661 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -68,9 +68,6 @@
* just as the undo stack would.
* So leaving this as an interface for further work */
-/**
- * Save a copy of the #BMesh for restoring later.
- */
BMBackup EDBM_redo_state_store(BMEditMesh *em)
{
BMBackup backup;
@@ -93,9 +90,6 @@ void EDBM_redo_state_restore(BMBackup *backup, BMEditMesh *em, bool recalc_loopt
}
}
-/**
- * Delete the backup, flushing it to an edit-mesh.
- */
void EDBM_redo_state_restore_and_free(BMBackup *backup, BMEditMesh *em, bool recalc_looptri)
{
BM_mesh_data_free(em->bm);
@@ -139,11 +133,6 @@ bool EDBM_op_init(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const char *
return true;
}
-/**
- * The return value:
- * - False on error (the mesh must not be changed).
- * - True on success, executes and finishes a #BMesh operator.
- */
bool EDBM_op_finish(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const bool do_report)
{
const char *errmsg;
@@ -320,11 +309,6 @@ void EDBM_mesh_make(Object *ob, const int select_mode, const bool add_key_index)
EDBM_selectmode_flush(me->edit_mesh);
}
-/**
- * \warning This can invalidate the #Mesh runtime cache of other objects (for linked duplicates).
- * Most callers should run #DEG_id_tag_update on `ob->data`, see: T46738, T46913.
- * This ensures #BKE_object_free_derived_caches runs on all objects that use this mesh.
- */
void EDBM_mesh_load_ex(Main *bmain, Object *ob, bool free_data)
{
Mesh *me = ob->data;
@@ -363,9 +347,6 @@ void EDBM_mesh_load(Main *bmain, Object *ob)
EDBM_mesh_load_ex(bmain, ob, true);
}
-/**
- * Should only be called on the active edit-mesh, otherwise call #BKE_editmesh_free_data.
- */
void EDBM_mesh_free_data(BMEditMesh *em)
{
/* These tables aren't used yet, so it's not strictly necessary
@@ -486,9 +467,6 @@ void EDBM_flag_enable_all(BMEditMesh *em, const char hflag)
/** \name UV Vertex Map API
* \{ */
-/**
- * Return a new #UvVertMap from the edit-mesh.
- */
UvVertMap *BM_uv_vert_map_create(BMesh *bm, const bool use_select, const bool use_winding)
{
BMVert *ev;
@@ -632,7 +610,6 @@ UvMapVert *BM_uv_vert_map_at_index(UvVertMap *vmap, uint v)
return vmap->vert[v];
}
-/* A specialized vert map used by stitch operator */
UvElementMap *BM_uv_element_map_create(BMesh *bm,
const Scene *scene,
const bool face_selected,
@@ -953,10 +930,6 @@ UvElement *BM_uv_element_get(UvElementMap *map, BMFace *efa, BMLoop *l)
/** \name Data Layer Checks
* \{ */
-/**
- * last_sel, use em->act_face otherwise get the last selected face in the editselections
- * at the moment, last_sel is mainly useful for making sure the space image doesn't flicker.
- */
BMFace *EDBM_uv_active_face_get(BMEditMesh *em, const bool sloppy, const bool selected)
{
BMFace *efa = NULL;
@@ -974,7 +947,6 @@ BMFace *EDBM_uv_active_face_get(BMEditMesh *em, const bool sloppy, const bool se
return NULL;
}
-/* Can we edit UV's for this mesh? */
bool EDBM_uv_check(BMEditMesh *em)
{
/* some of these checks could be a touch overkill */
@@ -1015,20 +987,10 @@ static BMVert *cache_mirr_intptr_as_bmvert(const intptr_t *index_lookup, int ind
* \endcode
*/
-/* BM_SEARCH_MAXDIST is too big, copied from 2.6x MOC_THRESH, should become a
- * preference */
+/* BM_SEARCH_MAXDIST is too big, copied from 2.6x MOC_THRESH, should become a preference. */
#define BM_SEARCH_MAXDIST_MIRR 0.00002f
#define BM_CD_LAYER_ID "__mirror_index"
-/**
- * \param em: Editmesh.
- * \param use_self: Allow a vertex to point to its self (middle verts).
- * \param use_select: Restrict to selected verts.
- * \param respecthide: Skip hidden vertices.
- * \param use_topology: Use topology mirror.
- * \param maxdist: Distance for close point test.
- * \param r_index: Optional array to write into, as an alternative to a customdata layer
- * (length of total verts).
- */
+
void EDBM_verts_mirror_cache_begin_ex(BMEditMesh *em,
const int axis,
const bool use_self,
@@ -1255,7 +1217,6 @@ void EDBM_verts_mirror_apply(BMEditMesh *em, const int sel_from, const int sel_t
/** \name Hide/Reveal API
* \{ */
-/* swap is 0 or 1, if 1 it hides not selected */
bool EDBM_mesh_hide(BMEditMesh *em, bool swap)
{
BMIter iter;
@@ -1410,9 +1371,6 @@ void EDBM_stats_update(BMEditMesh *em)
}
}
-/**
- * So many tools call these that we better make it a generic function.
- */
void EDBM_update(Mesh *mesh, const struct EDBMUpdate_Params *params)
{
BMEditMesh *em = mesh->edit_mesh;
@@ -1459,7 +1417,6 @@ void EDBM_update(Mesh *mesh, const struct EDBMUpdate_Params *params)
#endif
}
-/* Bad level call from Python API. */
void EDBM_update_extern(struct Mesh *me, const bool do_tessellation, const bool is_destructive)
{
EDBM_update(me,
@@ -1476,7 +1433,6 @@ void EDBM_update_extern(struct Mesh *me, const bool do_tessellation, const bool
/** \name Operator Helpers
* \{ */
-/* poll call for mesh operators requiring a view3d context */
bool EDBM_view3d_poll(bContext *C)
{
if (ED_operator_editmesh(C) && ED_operator_view3d_active(C)) {
@@ -1509,11 +1465,6 @@ BMElem *EDBM_elem_from_selectmode(BMEditMesh *em, BMVert *eve, BMEdge *eed, BMFa
return ele;
}
-/**
- * Used when we want to store a single index for any vert/edge/face.
- *
- * Intended for use with operators.
- */
int EDBM_elem_to_index_any(BMEditMesh *em, BMElem *ele)
{
BMesh *bm = em->bm;
diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c
index 7391451b694..d7d1dc7dcae 100644
--- a/source/blender/editors/mesh/mesh_data.c
+++ b/source/blender/editors/mesh/mesh_data.c
@@ -208,7 +208,6 @@ static void mesh_uv_reset_mface(MPoly *mp, MLoopUV *mloopuv)
mesh_uv_reset_array(fuv, mp->totloop);
}
-/* without bContext, called in uvedit */
void ED_mesh_uv_loop_reset_ex(struct Mesh *me, const int layernum)
{
BMEditMesh *em = me->edit_mesh;
@@ -253,10 +252,11 @@ void ED_mesh_uv_loop_reset(struct bContext *C, struct Mesh *me)
WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
}
-/* NOTE: keep in sync with #ED_mesh_color_add. */
int ED_mesh_uv_texture_add(
Mesh *me, const char *name, const bool active_set, const bool do_init, ReportList *reports)
{
+ /* NOTE: keep in sync with #ED_mesh_color_add. */
+
BMEditMesh *em;
int layernum_dst;
@@ -267,7 +267,7 @@ int ED_mesh_uv_texture_add(
layernum_dst = CustomData_number_of_layers(&em->bm->ldata, CD_MLOOPUV);
if (layernum_dst >= MAX_MTFACE) {
- BKE_reportf(reports, RPT_ERROR, "Cannot add more than %i UV maps", MAX_MTFACE);
+ BKE_reportf(reports, RPT_WARNING, "Cannot add more than %i UV maps", MAX_MTFACE);
return -1;
}
@@ -287,7 +287,7 @@ int ED_mesh_uv_texture_add(
else {
layernum_dst = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
if (layernum_dst >= MAX_MTFACE) {
- BKE_reportf(reports, RPT_ERROR, "Cannot add more than %i UV maps", MAX_MTFACE);
+ BKE_reportf(reports, RPT_WARNING, "Cannot add more than %i UV maps", MAX_MTFACE);
return -1;
}
@@ -381,10 +381,11 @@ bool ED_mesh_uv_texture_remove_named(Mesh *me, const char *name)
return false;
}
-/* NOTE: keep in sync with #ED_mesh_uv_texture_add. */
int ED_mesh_color_add(
Mesh *me, const char *name, const bool active_set, const bool do_init, ReportList *reports)
{
+ /* NOTE: keep in sync with #ED_mesh_uv_texture_add. */
+
BMEditMesh *em;
int layernum;
@@ -393,7 +394,7 @@ int ED_mesh_color_add(
layernum = CustomData_number_of_layers(&em->bm->ldata, CD_MLOOPCOL);
if (layernum >= MAX_MCOL) {
- BKE_reportf(reports, RPT_ERROR, "Cannot add more than %i vertex color layers", MAX_MCOL);
+ BKE_reportf(reports, RPT_WARNING, "Cannot add more than %i vertex color layers", MAX_MCOL);
return -1;
}
@@ -411,7 +412,7 @@ int ED_mesh_color_add(
else {
layernum = CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL);
if (layernum >= MAX_MCOL) {
- BKE_reportf(reports, RPT_ERROR, "Cannot add more than %i vertex color layers", MAX_MCOL);
+ BKE_reportf(reports, RPT_WARNING, "Cannot add more than %i vertex color layers", MAX_MCOL);
return -1;
}
@@ -516,10 +517,11 @@ static bool sculpt_vertex_color_remove_poll(bContext *C)
return false;
}
-/* NOTE: keep in sync with #ED_mesh_uv_texture_add. */
int ED_mesh_sculpt_color_add(
Mesh *me, const char *name, const bool active_set, const bool do_init, ReportList *reports)
{
+ /* NOTE: keep in sync with #ED_mesh_uv_texture_add. */
+
BMEditMesh *em;
int layernum;
@@ -529,7 +531,7 @@ int ED_mesh_sculpt_color_add(
layernum = CustomData_number_of_layers(&em->bm->vdata, CD_PROP_COLOR);
if (layernum >= MAX_MCOL) {
BKE_reportf(
- reports, RPT_ERROR, "Cannot add more than %i sculpt vertex color layers", MAX_MCOL);
+ reports, RPT_WARNING, "Cannot add more than %i sculpt vertex color layers", MAX_MCOL);
return -1;
}
@@ -548,7 +550,7 @@ int ED_mesh_sculpt_color_add(
layernum = CustomData_number_of_layers(&me->vdata, CD_PROP_COLOR);
if (layernum >= MAX_MCOL) {
BKE_reportf(
- reports, RPT_ERROR, "Cannot add more than %i sculpt vertex color layers", MAX_MCOL);
+ reports, RPT_WARNING, "Cannot add more than %i sculpt vertex color layers", MAX_MCOL);
return -1;
}
@@ -905,6 +907,7 @@ static int mesh_customdata_mask_clear_exec(bContext *C, wmOperator *UNUSED(op))
void MESH_OT_customdata_mask_clear(wmOperatorType *ot)
{
+ /* NOTE: no create_mask yet */
/* identifiers */
ot->name = "Clear Sculpt Mask Data";
diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h
index abff3c70e67..bba142133a6 100644
--- a/source/blender/editors/mesh/mesh_intern.h
+++ b/source/blender/editors/mesh/mesh_intern.h
@@ -43,7 +43,7 @@ struct wmOperatorType;
* BMEdit module is for code shared with blenkernel that concerns
* the BMEditMesh structure. */
-/* Calls a bmesh op, reporting errors to the user, etc */
+/** Calls a bmesh op, reporting errors to the user, etc. */
bool EDBM_op_callf(struct BMEditMesh *em, struct wmOperator *op, const char *fmt, ...);
bool EDBM_op_call_and_selectf(struct BMEditMesh *em,
struct wmOperator *op,
@@ -51,17 +51,26 @@ bool EDBM_op_call_and_selectf(struct BMEditMesh *em,
const bool select_replace,
const char *fmt,
...);
-/* Same as above, but doesn't report errors. */
+/**
+ * Same as above, but doesn't report errors.
+ */
bool EDBM_op_call_silentf(struct BMEditMesh *em, const char *fmt, ...);
-/* these next two functions are the split version of EDBM_op_callf, so you can
- * do stuff with a bmesh operator, after initializing it but before executing
- * it.
+/**
+ * These next two functions are the split version of EDBM_op_callf, so you can
+ * do stuff with a bmesh operator, after initializing it but before executing it.
*
* execute the operator with BM_Exec_Op */
bool EDBM_op_init(
struct BMEditMesh *em, struct BMOperator *bmop, struct wmOperator *op, const char *fmt, ...);
-/* Cleans up after a bmesh operator */
+
+/**
+ * Cleans up after a bmesh operator.
+ *
+ * The return value:
+ * - False on error (the mesh must not be changed).
+ * - True on success, executes and finishes a #BMesh operator.
+ */
bool EDBM_op_finish(struct BMEditMesh *em,
struct BMOperator *bmop,
struct wmOperator *op,
@@ -69,6 +78,9 @@ bool EDBM_op_finish(struct BMEditMesh *em,
void EDBM_stats_update(struct BMEditMesh *em);
+/**
+ * Poll call for mesh operators requiring a view3d context.
+ */
bool EDBM_view3d_poll(struct bContext *C);
struct BMElem *EDBM_elem_from_selectmode(struct BMEditMesh *em,
@@ -76,6 +88,11 @@ struct BMElem *EDBM_elem_from_selectmode(struct BMEditMesh *em,
struct BMEdge *eed,
struct BMFace *efa);
+/**
+ * Used when we want to store a single index for any vert/edge/face.
+ *
+ * Intended for use with operators.
+ */
int EDBM_elem_to_index_any(struct BMEditMesh *em, struct BMElem *ele);
struct BMElem *EDBM_elem_from_index_any(struct BMEditMesh *em, uint index);
@@ -88,12 +105,16 @@ struct BMElem *EDBM_elem_from_index_any_multi(struct ViewLayer *view_layer,
uint elem_index,
struct Object **r_obedit);
+/**
+ * Extrudes individual edges.
+ */
bool edbm_extrude_edges_indiv(struct BMEditMesh *em,
struct wmOperator *op,
const char hflag,
const bool use_normal_flip);
/* *** editmesh_add.c *** */
+
void MESH_OT_primitive_plane_add(struct wmOperatorType *ot);
void MESH_OT_primitive_cube_add(struct wmOperatorType *ot);
void MESH_OT_primitive_circle_add(struct wmOperatorType *ot);
@@ -105,16 +126,20 @@ void MESH_OT_primitive_uv_sphere_add(struct wmOperatorType *ot);
void MESH_OT_primitive_ico_sphere_add(struct wmOperatorType *ot);
/* *** editmesh_add_gizmo.c *** */
+
void MESH_OT_primitive_cube_add_gizmo(struct wmOperatorType *ot);
/* *** editmesh_bevel.c *** */
+
void MESH_OT_bevel(struct wmOperatorType *ot);
struct wmKeyMap *bevel_modal_keymap(struct wmKeyConfig *keyconf);
/* *** editmesh_bisect.c *** */
+
void MESH_OT_bisect(struct wmOperatorType *ot);
/* *** editmesh_extrude.c *** */
+
void MESH_OT_extrude_repeat(struct wmOperatorType *ot);
void MESH_OT_extrude_region(struct wmOperatorType *ot);
void MESH_OT_extrude_context(struct wmOperatorType *ot);
@@ -124,15 +149,20 @@ void MESH_OT_extrude_faces_indiv(struct wmOperatorType *ot);
void MESH_OT_dupli_extrude_cursor(struct wmOperatorType *ot);
/* *** editmesh_extrude_screw.c *** */
+
void MESH_OT_screw(struct wmOperatorType *ot);
/* *** editmesh_extrude_spin.c *** */
+
void MESH_OT_spin(struct wmOperatorType *ot);
+
/* *** editmesh_extrude_spin_gizmo.c *** */
+
void MESH_GGT_spin(struct wmGizmoGroupType *gzgt);
void MESH_GGT_spin_redo(struct wmGizmoGroupType *gzgt);
/* *** editmesh_polybuild.c *** */
+
void MESH_OT_polybuild_face_at_cursor(struct wmOperatorType *ot);
void MESH_OT_polybuild_split_at_cursor(struct wmOperatorType *ot);
void MESH_OT_polybuild_dissolve_at_cursor(struct wmOperatorType *ot);
@@ -140,16 +170,22 @@ void MESH_OT_polybuild_transform_at_cursor(struct wmOperatorType *ot);
void MESH_OT_polybuild_delete_at_cursor(struct wmOperatorType *ot);
/* *** editmesh_inset.c *** */
+
void MESH_OT_inset(struct wmOperatorType *ot);
/* *** editmesh_intersect.c *** */
+
void MESH_OT_intersect(struct wmOperatorType *ot);
void MESH_OT_intersect_boolean(struct wmOperatorType *ot);
void MESH_OT_face_split_by_edges(struct wmOperatorType *ot);
/* *** editmesh_knife.c *** */
+
void MESH_OT_knife_tool(struct wmOperatorType *ot);
void MESH_OT_knife_project(struct wmOperatorType *ot);
+/**
+ * \param use_tag: When set, tag all faces inside the polylines.
+ */
void EDBM_mesh_knife(struct bContext *C,
struct ViewContext *vc,
struct LinkNode *polys,
@@ -159,13 +195,16 @@ void EDBM_mesh_knife(struct bContext *C,
struct wmKeyMap *knifetool_modal_keymap(struct wmKeyConfig *keyconf);
/* *** editmesh_loopcut.c *** */
+
void MESH_OT_loopcut(struct wmOperatorType *ot);
/* *** editmesh_rip.c *** */
+
void MESH_OT_rip(struct wmOperatorType *ot);
void MESH_OT_rip_edge(struct wmOperatorType *ot);
/* *** editmesh_select.c *** */
+
void MESH_OT_select_similar(struct wmOperatorType *ot);
void MESH_OT_select_similar_region(struct wmOperatorType *ot);
void MESH_OT_select_mode(struct wmOperatorType *ot);
@@ -265,10 +304,12 @@ void MESH_OT_smooth_normals(struct wmOperatorType *ot);
void MESH_OT_mod_weighted_strength(struct wmOperatorType *ot);
/* *** editmesh_mask_extract.c *** */
+
void MESH_OT_paint_mask_extract(struct wmOperatorType *ot);
void MESH_OT_face_set_extract(struct wmOperatorType *ot);
void MESH_OT_paint_mask_slice(struct wmOperatorType *ot);
+/** Called in transform_ops.c, on each regeneration of key-maps. */
struct wmKeyMap *point_normals_modal_keymap(wmKeyConfig *keyconf);
#if defined(WITH_FREESTYLE)
@@ -277,13 +318,13 @@ void MESH_OT_mark_freestyle_face(struct wmOperatorType *ot);
#endif
/* *** mesh_data.c *** */
+
void MESH_OT_uv_texture_add(struct wmOperatorType *ot);
void MESH_OT_uv_texture_remove(struct wmOperatorType *ot);
void MESH_OT_vertex_color_add(struct wmOperatorType *ot);
void MESH_OT_vertex_color_remove(struct wmOperatorType *ot);
void MESH_OT_sculpt_vertex_color_add(struct wmOperatorType *ot);
void MESH_OT_sculpt_vertex_color_remove(struct wmOperatorType *ot);
-/* no create_mask yet */
void MESH_OT_customdata_mask_clear(struct wmOperatorType *ot);
void MESH_OT_customdata_skin_add(struct wmOperatorType *ot);
void MESH_OT_customdata_skin_clear(struct wmOperatorType *ot);
diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c
index 94823b92c44..d616dd3bb63 100644
--- a/source/blender/editors/mesh/mesh_ops.c
+++ b/source/blender/editors/mesh/mesh_ops.c
@@ -372,7 +372,6 @@ void ED_operatormacros_mesh(void)
RNA_boolean_set(otmacro->ptr, "mirror", false);
}
-/* note mesh keymap also for other space? */
void ED_keymap_mesh(wmKeyConfig *keyconf)
{
wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Mesh", 0, 0);
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c
index 1b720f2c14d..ebe8b758aa2 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -755,11 +755,10 @@ int ED_mesh_join_objects_exec(bContext *C, wmOperator *op)
/* -------------------------------------------------------------------- */
/** \name Join as Shapes
+ *
+ * Append selected meshes vertex locations as shapes of the active mesh.
* \{ */
-/* Append selected meshes vertex locations as shapes of the active mesh,
- * return 0 if no join is made (error) and 1 of the join is done */
-
int ED_mesh_shapes_join_objects_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -876,12 +875,6 @@ BLI_INLINE void mesh_mirror_topo_table_get_meshes(Object *ob,
*r_em_mirror = em_mirror;
}
-/**
- * Mode is 's' start, or 'e' end, or 'u' use
- * if end, ob can be NULL.
- * \note This is supposed return -1 on error,
- * which callers are currently checking for, but is not used so far.
- */
void ED_mesh_mirror_topo_table_begin(Object *ob, Mesh *me_eval)
{
Mesh *me_mirror;
@@ -1012,11 +1005,6 @@ BMVert *editbmesh_get_x_mirror_vert(Object *ob,
return editbmesh_get_x_mirror_vert_spatial(ob, em, co);
}
-/**
- * Wrapper for object-mode/edit-mode.
- *
- * call #BM_mesh_elem_table_ensure first for editmesh.
- */
int ED_mesh_mirror_get_vert(Object *ob, int index)
{
Mesh *me = ob->data;
@@ -1146,7 +1134,6 @@ static bool mirror_facecmp(const void *a, const void *b)
return (mirror_facerotation((MFace *)a, (MFace *)b) == -1);
}
-/* This is a Mesh-based copy of mesh_get_x_mirror_faces() */
int *mesh_get_x_mirror_faces(Object *ob, BMEditMesh *em, Mesh *me_eval)
{
Mesh *me = ob->data;
@@ -1209,15 +1196,8 @@ int *mesh_get_x_mirror_faces(Object *ob, BMEditMesh *em, Mesh *me_eval)
return mirrorfaces;
}
-/* selection, vertex and face */
-/* returns 0 if not found, otherwise 1 */
+/* Selection (vertex and face). */
-/**
- * Face selection in object mode,
- * currently only weight-paint and vertex-paint use this.
- *
- * \return boolean true == Found
- */
bool ED_mesh_pick_face(bContext *C, Object *ob, const int mval[2], uint dist_px, uint *r_index)
{
ViewContext vc;
@@ -1280,10 +1260,6 @@ static void ed_mesh_pick_face_vert__mpoly_find(
}
}
}
-/**
- * Use when the back buffer stores face index values. but we want a vert.
- * This gets the face then finds the closest vertex to mval.
- */
bool ED_mesh_pick_face_vert(
bContext *C, Object *ob, const int mval[2], uint dist_px, uint *r_index)
{
diff --git a/source/blender/editors/metaball/editmball_undo.c b/source/blender/editors/metaball/editmball_undo.c
index f7b53b5513f..5c724ac2d01 100644
--- a/source/blender/editors/metaball/editmball_undo.c
+++ b/source/blender/editors/metaball/editmball_undo.c
@@ -253,7 +253,6 @@ static void mball_undosys_foreach_ID_ref(UndoStep *us_p,
}
}
-/* Export for ED_undo_sys. */
void ED_mball_undosys_type(UndoType *ut)
{
ut->name = "Edit MBall";
diff --git a/source/blender/editors/metaball/mball_edit.c b/source/blender/editors/metaball/mball_edit.c
index 292052b778a..bedb9d4f4f4 100644
--- a/source/blender/editors/metaball/mball_edit.c
+++ b/source/blender/editors/metaball/mball_edit.c
@@ -62,7 +62,6 @@
/** \name Edit Mode Functions
* \{ */
-/* This function is used to free all MetaElems from MetaBall */
void ED_mball_editmball_free(Object *obedit)
{
MetaBall *mb = (MetaBall *)obedit->data;
@@ -71,8 +70,6 @@ void ED_mball_editmball_free(Object *obedit)
mb->lastelem = NULL;
}
-/* This function is called, when MetaBall Object is
- * switched from object mode to edit mode */
void ED_mball_editmball_make(Object *obedit)
{
MetaBall *mb = (MetaBall *)obedit->data;
@@ -90,9 +87,6 @@ void ED_mball_editmball_make(Object *obedit)
mb->editelems = &mb->elems;
}
-/* This function is called, when MetaBall Object switched from
- * edit mode to object mode. List of MetaElements is copied
- * from object->data->edit_elems to object->data->elems. */
void ED_mball_editmball_load(Object *UNUSED(obedit))
{
}
@@ -122,9 +116,6 @@ bool ED_mball_deselect_all_multi(bContext *C)
/** \name Add Meta Primitive Utility
* \{ */
-/**
- * Add meta-element primitive to meta-ball object (which is in edit mode).
- */
MetaElem *ED_mball_add_primitive(
bContext *UNUSED(C), Object *obedit, bool obedit_is_new, float mat[4][4], float dia, int type)
{
@@ -759,8 +750,6 @@ void MBALL_OT_reveal_metaelems(wmOperatorType *ot)
/** \name Select Pick Utility
* \{ */
-/* Select MetaElement with mouse click (user can select radius circle or
- * stiffness circle) */
bool ED_mball_select_pick(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
{
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index c77db10d74b..9354171a1e4 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -130,7 +130,7 @@
/** \name Local Enum Declarations
* \{ */
-/* this is an exact copy of the define in rna_light.c
+/* This is an exact copy of the define in `rna_light.c`
* kept here because of linking order.
* Icons are only defined here */
const EnumPropertyItem rna_enum_light_type_items[] = {
@@ -331,8 +331,6 @@ void ED_object_base_init_transform_on_add(Object *object, const float loc[3], co
BKE_object_to_mat4(object, object->obmat);
}
-/* Uses context to figure out transform for primitive.
- * Returns standard diameter. */
float ED_object_new_primitive_matrix(bContext *C,
Object *obedit,
const float loc[3],
@@ -603,12 +601,6 @@ bool ED_object_add_generic_get_opts(bContext *C,
return true;
}
-/**
- * For object add primitive operators, or for object creation when `obdata != NULL`.
- * \param obdata: Assigned to #Object.data, with increased user count.
- *
- * \note Do not call undo push in this function (users of this function have to).
- */
Object *ED_object_add_type_with_obdata(bContext *C,
const int type,
const char *name,
@@ -1724,7 +1716,6 @@ static int object_instance_add_invoke(bContext *C, wmOperator *op, const wmEvent
return op->type->exec(C, op);
}
-/* only used as menu */
void OBJECT_OT_collection_instance_add(wmOperatorType *ot)
{
PropertyRNA *prop;
@@ -1994,8 +1985,7 @@ void OBJECT_OT_pointcloud_add(wmOperatorType *ot)
/* -------------------------------------------------------------------- */
/** \name Delete Object Operator
* \{ */
-/* remove base from a specific scene */
-/* NOTE: now unlinks constraints as well. */
+
void ED_object_base_free_and_unlink(Main *bmain, Scene *scene, Object *ob)
{
if (ID_REAL_USERS(ob) <= 1 && ID_EXTRA_USERS(ob) == 0 &&
@@ -2013,10 +2003,6 @@ void ED_object_base_free_and_unlink(Main *bmain, Scene *scene, Object *ob)
BKE_scene_collections_object_remove(bmain, scene, ob, true);
}
-/**
- * Remove base from a specific scene.
- * `ob` must not be indirectly used.
- */
void ED_object_base_free_and_unlink_no_indirect_check(Main *bmain, Scene *scene, Object *ob)
{
BLI_assert(!BKE_library_ID_is_indirectly_used(bmain, ob));
@@ -3115,11 +3101,11 @@ static int object_convert_exec(bContext *C, wmOperator *op)
basen = duplibase_for_convert(bmain, depsgraph, scene, view_layer, base, NULL);
newob = basen->object;
- /* Decrement original point-cloud's usage count. */
+ /* Decrement original point cloud's usage count. */
PointCloud *pointcloud = newob->data;
id_us_min(&pointcloud->id);
- /* Make a new copy of the point-cloud. */
+ /* Make a new copy of the point cloud. */
newob->data = BKE_id_copy(bmain, &pointcloud->id);
}
else {
@@ -3371,11 +3357,6 @@ static Base *object_add_duplicate_internal(Main *bmain,
return basen;
}
-/* single object duplicate, if dupflag==0, fully linked, else it uses the flags given */
-/* leaves selection of base/object unaltered.
- * NOTE: don't call this within a loop since clear_* funcs loop over the entire database.
- * NOTE: caller must do DAG_relations_tag_update(bmain);
- * this is not done automatic since we may duplicate many objects in a batch */
Base *ED_object_add_duplicate(
Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base, const eDupli_ID_Flags dupflag)
{
diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c
index 47c2998ed3d..5c3a8fc2277 100644
--- a/source/blender/editors/object/object_constraint.c
+++ b/source/blender/editors/object/object_constraint.c
@@ -80,10 +80,6 @@
/** \name Constraint Data Accessors
* \{ */
-/**
- * If object is in pose-mode, return active bone constraints, else object constraints.
- * No constraints are returned for a bone on an inactive bone-layer.
- */
ListBase *ED_object_constraint_active_list(Object *ob)
{
if (ob == NULL) {
@@ -105,10 +101,6 @@ ListBase *ED_object_constraint_active_list(Object *ob)
return NULL;
}
-/**
- * Get the constraints for the active pose bone. Bone may be on an inactive bone-layer
- * (unlike #ED_object_constraint_active_list, such constraints are not excluded here).
- */
ListBase *ED_object_pose_constraint_list(const bContext *C)
{
bPoseChannel *pose_bone = CTX_data_pointer_get(C, "pose_bone").data;
@@ -122,8 +114,6 @@ ListBase *ED_object_pose_constraint_list(const bContext *C)
return &pose_bone->constraints;
}
-/* Find the list that a given constraint belongs to,
- * and/or also get the posechannel this is from (if applicable) */
ListBase *ED_object_constraint_list_from_constraint(Object *ob,
bConstraint *con,
bPoseChannel **r_pchan)
@@ -164,7 +154,6 @@ ListBase *ED_object_constraint_list_from_constraint(Object *ob,
return NULL;
}
-/* single constraint */
bConstraint *ED_object_constraint_active_get(Object *ob)
{
return BKE_constraints_active_get(ED_object_constraint_active_list(ob));
diff --git a/source/blender/editors/object/object_data_transfer.c b/source/blender/editors/object/object_data_transfer.c
index 6251fb799c5..49149a5152f 100644
--- a/source/blender/editors/object/object_data_transfer.c
+++ b/source/blender/editors/object/object_data_transfer.c
@@ -603,7 +603,6 @@ static bool data_transfer_poll_property(const bContext *UNUSED(C),
return true;
}
-/* Transfer mesh data from active to selected objects. */
void OBJECT_OT_data_transfer(wmOperatorType *ot)
{
PropertyRNA *prop;
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index 78440f52160..38d0a044cb4 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -134,8 +134,6 @@ Object *ED_object_context(const bContext *C)
return CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
}
-/* Find the correct active object per context.
- * NOTE: context can be NULL when called from a enum with #PROP_ENUM_NO_CONTEXT. */
Object *ED_object_active_context(const bContext *C)
{
Object *ob = NULL;
@@ -148,14 +146,6 @@ Object *ED_object_active_context(const bContext *C)
return ob;
}
-/**
- * Return an array of objects:
- * - When in the property space, return the pinned or active object.
- * - When in edit-mode/pose-mode, return an array of objects in the mode.
- * - Otherwise return selected objects,
- * the callers \a filter_fn needs to check of they are editable
- * (assuming they need to be modified).
- */
Object **ED_object_array_in_mode_or_selected(bContext *C,
bool (*filter_fn)(const Object *ob, void *user_data),
void *filter_user_data,
@@ -669,10 +659,6 @@ bool ED_object_editmode_load(Main *bmain, Object *obedit)
return ED_object_editmode_load_free_ex(bmain, obedit, true, false);
}
-/**
- * \param flag:
- * - If #EM_FREEDATA isn't in the flag, use ED_object_editmode_load directly.
- */
bool ED_object_editmode_exit_ex(Main *bmain, Scene *scene, Object *obedit, int flag)
{
const bool free_data = (flag & EM_FREEDATA) != 0;
@@ -723,11 +709,6 @@ bool ED_object_editmode_exit(bContext *C, int flag)
return ED_object_editmode_exit_ex(bmain, scene, obedit, flag);
}
-/**
- * Support freeing edit-mode data without flushing it back to the object.
- *
- * \return true if data was freed.
- */
bool ED_object_editmode_free_ex(Main *bmain, Object *obedit)
{
return ED_object_editmode_load_free_ex(bmain, obedit, false, true);
@@ -1161,11 +1142,6 @@ static bool has_pose_motion_paths(Object *ob)
return ob->pose && (ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS) != 0;
}
-/* For the objects with animation: update paths for those that have got them
- * This should selectively update paths that exist...
- *
- * To be called from various tools that do incremental updates
- */
void ED_objects_recalculate_paths(bContext *C,
Scene *scene,
eObjectPathCalcRange range,
@@ -1428,7 +1404,6 @@ static void object_clear_mpath(Object *ob)
}
}
-/* Clear motion paths for all objects */
void ED_objects_clear_paths(bContext *C, bool only_selected)
{
if (only_selected) {
@@ -1663,10 +1638,10 @@ void OBJECT_OT_shade_smooth(wmOperatorType *ot)
/** \name Object Mode Set Operator
* \{ */
-static const EnumPropertyItem *object_mode_set_itemsf(bContext *C,
- PointerRNA *UNUSED(ptr),
- PropertyRNA *UNUSED(prop),
- bool *r_free)
+static const EnumPropertyItem *object_mode_set_itemf(bContext *C,
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
{
const EnumPropertyItem *input = rna_enum_object_mode_items;
EnumPropertyItem *item = NULL;
@@ -1815,7 +1790,7 @@ void OBJECT_OT_mode_set(wmOperatorType *ot)
ot->prop = RNA_def_enum(
ot->srna, "mode", rna_enum_object_mode_items, OB_MODE_OBJECT, "Mode", "");
- RNA_def_enum_funcs(ot->prop, object_mode_set_itemsf);
+ RNA_def_enum_funcs(ot->prop, object_mode_set_itemf);
RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna, "toggle", 0, "Toggle", "");
diff --git a/source/blender/editors/object/object_facemap_ops.c b/source/blender/editors/object/object_facemap_ops.c
index 92f3d28878c..f5127bd5228 100644
--- a/source/blender/editors/object/object_facemap_ops.c
+++ b/source/blender/editors/object/object_facemap_ops.c
@@ -53,7 +53,6 @@
#include "object_intern.h"
-/* called while not in editmode */
void ED_object_facemap_face_add(Object *ob, bFaceMap *fmap, int facenum)
{
int fmap_nr;
@@ -77,7 +76,6 @@ void ED_object_facemap_face_add(Object *ob, bFaceMap *fmap, int facenum)
}
}
-/* called while not in editmode */
void ED_object_facemap_face_remove(Object *ob, bFaceMap *fmap, int facenum)
{
int fmap_nr;
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index fe07ecef438..9a1b4b48464 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -45,6 +45,7 @@ enum eObject_Hook_Add_Mode {
/* internal exports only */
/* object_transform.c */
+
void OBJECT_OT_location_clear(struct wmOperatorType *ot);
void OBJECT_OT_rotation_clear(struct wmOperatorType *ot);
void OBJECT_OT_scale_clear(struct wmOperatorType *ot);
@@ -55,6 +56,7 @@ void OBJECT_OT_transform_axis_target(struct wmOperatorType *ot);
void OBJECT_OT_origin_set(struct wmOperatorType *ot);
/* object_relations.c */
+
void OBJECT_OT_parent_set(struct wmOperatorType *ot);
void OBJECT_OT_parent_no_inverse_set(struct wmOperatorType *ot);
void OBJECT_OT_parent_clear(struct wmOperatorType *ot);
@@ -67,10 +69,18 @@ void OBJECT_OT_convert_proxy_to_override(struct wmOperatorType *ot);
void OBJECT_OT_make_single_user(struct wmOperatorType *ot);
void OBJECT_OT_make_links_scene(struct wmOperatorType *ot);
void OBJECT_OT_make_links_data(struct wmOperatorType *ot);
+/**
+ * Used for drop-box.
+ * Assigns to object under cursor, only first material slot.
+ */
void OBJECT_OT_drop_named_material(struct wmOperatorType *ot);
+/**
+ * \note Only for empty-image objects, this operator is needed
+ */
void OBJECT_OT_unlink_data(struct wmOperatorType *ot);
/* object_edit.c */
+
void OBJECT_OT_hide_view_set(struct wmOperatorType *ot);
void OBJECT_OT_hide_view_clear(struct wmOperatorType *ot);
void OBJECT_OT_hide_collection(struct wmOperatorType *ot);
@@ -93,6 +103,7 @@ void OBJECT_OT_link_to_collection(struct wmOperatorType *ot);
void OBJECT_OT_transfer_mode(struct wmOperatorType *ot);
/* object_select.c */
+
void OBJECT_OT_select_all(struct wmOperatorType *ot);
void OBJECT_OT_select_random(struct wmOperatorType *ot);
void OBJECT_OT_select_by_type(struct wmOperatorType *ot);
@@ -104,6 +115,7 @@ void OBJECT_OT_select_less(struct wmOperatorType *ot);
void OBJECT_OT_select_same_collection(struct wmOperatorType *ot);
/* object_add.c */
+
void OBJECT_OT_add(struct wmOperatorType *ot);
void OBJECT_OT_add_named(struct wmOperatorType *ot);
void OBJECT_OT_transform_to_mouse(struct wmOperatorType *ot);
@@ -120,6 +132,9 @@ void OBJECT_OT_camera_add(struct wmOperatorType *ot);
void OBJECT_OT_speaker_add(struct wmOperatorType *ot);
void OBJECT_OT_hair_add(struct wmOperatorType *ot);
void OBJECT_OT_pointcloud_add(struct wmOperatorType *ot);
+/**
+ * Only used as menu.
+ */
void OBJECT_OT_collection_instance_add(struct wmOperatorType *ot);
void OBJECT_OT_data_instance_add(struct wmOperatorType *ot);
@@ -131,10 +146,15 @@ void OBJECT_OT_join_shapes(struct wmOperatorType *ot);
void OBJECT_OT_convert(struct wmOperatorType *ot);
/* object_volume.c */
+
void OBJECT_OT_volume_add(struct wmOperatorType *ot);
+/**
+ * Called by other space types too.
+ */
void OBJECT_OT_volume_import(struct wmOperatorType *ot);
/* object_hook.c */
+
void OBJECT_OT_hook_add_selob(struct wmOperatorType *ot);
void OBJECT_OT_hook_add_newob(struct wmOperatorType *ot);
void OBJECT_OT_hook_remove(struct wmOperatorType *ot);
@@ -144,6 +164,7 @@ void OBJECT_OT_hook_reset(struct wmOperatorType *ot);
void OBJECT_OT_hook_recenter(struct wmOperatorType *ot);
/* object_collection.c */
+
void COLLECTION_OT_create(struct wmOperatorType *ot);
void COLLECTION_OT_objects_remove_all(struct wmOperatorType *ot);
void COLLECTION_OT_objects_remove(struct wmOperatorType *ot);
@@ -151,6 +172,7 @@ void COLLECTION_OT_objects_add_active(struct wmOperatorType *ot);
void COLLECTION_OT_objects_remove_active(struct wmOperatorType *ot);
/* object_modifier.c */
+
bool edit_modifier_poll_generic(struct bContext *C,
struct StructRNA *rna_type,
int obtype_flag,
@@ -249,6 +271,7 @@ void CONSTRAINT_OT_objectsolver_clear_inverse(struct wmOperatorType *ot);
void CONSTRAINT_OT_followpath_path_animate(struct wmOperatorType *ot);
/* object_vgroup.c */
+
void OBJECT_OT_vertex_group_add(struct wmOperatorType *ot);
void OBJECT_OT_vertex_group_remove(struct wmOperatorType *ot);
void OBJECT_OT_vertex_group_assign(struct wmOperatorType *ot);
@@ -279,6 +302,7 @@ void OBJECT_OT_vertex_weight_normalize_active_vertex(struct wmOperatorType *ot);
void OBJECT_OT_vertex_weight_copy(struct wmOperatorType *ot);
/* object_facemap_ops.c */
+
void OBJECT_OT_face_map_add(struct wmOperatorType *ot);
void OBJECT_OT_face_map_remove(struct wmOperatorType *ot);
void OBJECT_OT_face_map_assign(struct wmOperatorType *ot);
@@ -288,9 +312,11 @@ void OBJECT_OT_face_map_deselect(struct wmOperatorType *ot);
void OBJECT_OT_face_map_move(struct wmOperatorType *ot);
/* object_warp.c */
+
void TRANSFORM_OT_vertex_warp(struct wmOperatorType *ot);
/* object_shapekey.c */
+
void OBJECT_OT_shape_key_add(struct wmOperatorType *ot);
void OBJECT_OT_shape_key_remove(struct wmOperatorType *ot);
void OBJECT_OT_shape_key_clear(struct wmOperatorType *ot);
@@ -299,6 +325,7 @@ void OBJECT_OT_shape_key_mirror(struct wmOperatorType *ot);
void OBJECT_OT_shape_key_move(struct wmOperatorType *ot);
/* object_collection.c */
+
void OBJECT_OT_collection_add(struct wmOperatorType *ot);
void OBJECT_OT_collection_link(struct wmOperatorType *ot);
void OBJECT_OT_collection_remove(struct wmOperatorType *ot);
@@ -306,18 +333,25 @@ void OBJECT_OT_collection_unlink(struct wmOperatorType *ot);
void OBJECT_OT_collection_objects_select(struct wmOperatorType *ot);
/* object_bake.c */
+
void OBJECT_OT_bake_image(wmOperatorType *ot);
void OBJECT_OT_bake(wmOperatorType *ot);
/* object_random.c */
+
void TRANSFORM_OT_vertex_random(struct wmOperatorType *ot);
/* object_remesh.cc */
+
void OBJECT_OT_voxel_remesh(struct wmOperatorType *ot);
void OBJECT_OT_voxel_size_edit(struct wmOperatorType *ot);
void OBJECT_OT_quadriflow_remesh(struct wmOperatorType *ot);
/* object_transfer_data.c */
+
+/**
+ * Transfer mesh data from active to selected objects.
+ */
void OBJECT_OT_data_transfer(struct wmOperatorType *ot);
void OBJECT_OT_datalayout_transfer(struct wmOperatorType *ot);
diff --git a/source/blender/editors/object/object_modes.c b/source/blender/editors/object/object_modes.c
index 0c1b394a916..d3f72b91366 100644
--- a/source/blender/editors/object/object_modes.c
+++ b/source/blender/editors/object/object_modes.c
@@ -111,10 +111,6 @@ static const char *object_mode_op_string(eObjectMode mode)
return NULL;
}
-/**
- * Checks the mode to be set is compatible with the object
- * should be made into a generic function
- */
bool ED_object_mode_compat_test(const Object *ob, eObjectMode mode)
{
if (mode == OB_MODE_OBJECT) {
@@ -162,11 +158,6 @@ bool ED_object_mode_compat_test(const Object *ob, eObjectMode mode)
return false;
}
-/**
- * Sets the mode to a compatible state (use before entering the mode).
- *
- * This is so each mode's exec function can call
- */
bool ED_object_mode_compat_set(bContext *C, Object *ob, eObjectMode mode, ReportList *reports)
{
bool ok;
diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c
index 21b978268d9..71ad54383a6 100644
--- a/source/blender/editors/object/object_modifier.c
+++ b/source/blender/editors/object/object_modifier.c
@@ -152,12 +152,6 @@ static void object_force_modifier_bind_simple_options(Depsgraph *depsgraph,
md_eval->mode = mode;
}
-/**
- * Add a modifier to given object, including relevant extra processing needed by some physics types
- * (particles, simulations...).
- *
- * \param scene: is only used to set current frame in some cases, and may be NULL.
- */
ModifierData *ED_object_modifier_add(
ReportList *reports, Main *bmain, Scene *scene, Object *ob, const char *name, int type)
{
@@ -264,14 +258,6 @@ static bool object_has_modifier(const Object *ob, const ModifierData *exclude, M
return false;
}
-/* If the object data of 'orig_ob' has other users, run 'callback' on
- * each of them.
- *
- * If include_orig is true, the callback will run on 'orig_ob' too.
- *
- * If the callback ever returns true, iteration will stop and the
- * function value will be true. Otherwise the function returns false.
- */
bool ED_object_iter_other(Main *bmain,
Object *orig_ob,
const bool include_orig,
@@ -314,9 +300,6 @@ static bool object_has_modifier_cb(Object *ob, void *data)
return object_has_modifier(ob, NULL, type);
}
-/* Use with ED_object_iter_other(). Sets the total number of levels
- * for any multires modifiers on the object to the int pointed to by
- * callback_data. */
bool ED_object_multires_update_totlevels_cb(Object *ob, void *totlevel_v)
{
int totlevel = *((char *)totlevel_v);
@@ -731,7 +714,7 @@ static bool modifier_apply_shape(Main *bmain,
BKE_id_free(NULL, mesh_applied);
}
else {
- /* TODO: implement for hair, point-clouds and volumes. */
+ /* TODO: implement for hair, point clouds and volumes. */
BKE_report(reports, RPT_ERROR, "Cannot apply modifier for this object type");
return false;
}
@@ -830,7 +813,7 @@ static bool modifier_apply_obdata(
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
}
else {
- /* TODO: implement for hair, point-clouds and volumes. */
+ /* TODO: implement for hair, point clouds and volumes. */
BKE_report(reports, RPT_ERROR, "Cannot apply modifier for this object type");
return false;
}
@@ -1696,6 +1679,8 @@ void OBJECT_OT_modifier_set_active(wmOperatorType *ot)
}
/** \} */
+
+/* ------------------------------------------------------------------- */
/** \name Copy Modifier To Selected Operator
* \{ */
@@ -2695,6 +2680,7 @@ void OBJECT_OT_skin_armature_create(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
edit_modifier_properties(ot);
}
+
/** \} */
/* ------------------------------------------------------------------- */
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index b51644eebf3..811f20e82be 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -1783,8 +1783,6 @@ static void single_object_users(
BKE_main_collection_sync_remap(bmain);
}
-/* not an especially efficient function, only added so the single user
- * button can be functional. */
void ED_object_single_user(Main *bmain, Scene *scene, Object *ob)
{
FOREACH_SCENE_OBJECT_BEGIN (scene, ob_iter) {
@@ -2644,10 +2642,6 @@ static int drop_named_material_invoke(bContext *C, wmOperator *op, const wmEvent
return OPERATOR_FINISHED;
}
-/**
- * Used for drop-box.
- * Assigns to object under cursor, only first material slot.
- */
void OBJECT_OT_drop_named_material(wmOperatorType *ot)
{
/* identifiers */
@@ -2706,9 +2700,6 @@ static int object_unlink_data_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-/**
- * \note Only for empty-image objects, this operator is needed
- */
void OBJECT_OT_unlink_data(wmOperatorType *ot)
{
/* identifiers */
diff --git a/source/blender/editors/object/object_remesh.cc b/source/blender/editors/object/object_remesh.cc
index 3bdf7e0d34d..719ffd36f03 100644
--- a/source/blender/editors/object/object_remesh.cc
+++ b/source/blender/editors/object/object_remesh.cc
@@ -821,7 +821,8 @@ static Mesh *remesh_symmetry_mirror(Object *ob, Mesh *mesh, eSymmetryAxes symmet
mmd.flag = 0;
mmd.flag &= MOD_MIR_AXIS_X << i;
mesh_mirror_temp = mesh_mirror;
- mesh_mirror = BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(&mmd, ob, mesh_mirror, axis);
+ mesh_mirror = BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(
+ &mmd, ob, mesh_mirror, axis, true);
if (mesh_mirror_temp != mesh_mirror) {
BKE_id_free(nullptr, mesh_mirror_temp);
}
diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c
index eb37aebcff2..a86dba15469 100644
--- a/source/blender/editors/object/object_select.c
+++ b/source/blender/editors/object/object_select.c
@@ -89,14 +89,6 @@
/** \name Public Object Selection API
* \{ */
-/**
- * Simple API for object selection, rather than just using the flag
- * this takes into account the 'restrict selection in 3d view' flag.
- * deselect works always, the restriction just prevents selection
- *
- * \note Caller must send a `NC_SCENE | ND_OB_SELECT` notifier
- * (or a `NC_SCENE | ND_OB_VISIBLE` in case of visibility toggling).
- */
void ED_object_base_select(Base *base, eObjectSelect_Mode mode)
{
if (mode == BA_INVERT) {
@@ -121,9 +113,6 @@ void ED_object_base_select(Base *base, eObjectSelect_Mode mode)
}
}
-/**
- * Call when the active base has changed.
- */
void ED_object_base_active_refresh(Main *bmain, Scene *scene, ViewLayer *view_layer)
{
WM_main_add_notifier(NC_SCENE | ND_OB_ACTIVE, scene);
@@ -134,9 +123,6 @@ void ED_object_base_active_refresh(Main *bmain, Scene *scene, ViewLayer *view_la
}
}
-/**
- * Change active base, it includes the notifier
- */
void ED_object_base_activate(bContext *C, Base *base)
{
Scene *scene = CTX_data_scene(C);
@@ -242,10 +228,6 @@ static int get_base_select_priority(Base *base)
return 1;
}
-/**
- * If id is not already an Object, try to find an object that uses it as data.
- * Prefers active, then selected, then visible/selectable.
- */
Base *ED_object_find_first_by_data_id(ViewLayer *view_layer, ID *id)
{
BLI_assert(OB_DATA_SUPPORT_ID(GS(id->name)));
@@ -279,12 +261,6 @@ Base *ED_object_find_first_by_data_id(ViewLayer *view_layer, ID *id)
return base_best;
}
-/**
- * Select and make the target object active in the view layer.
- * If already selected, selection isn't changed.
- *
- * \returns false if not found in current view layer
- */
bool ED_object_jump_to_object(bContext *C, Object *ob, const bool UNUSED(reveal_hidden))
{
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -316,13 +292,6 @@ bool ED_object_jump_to_object(bContext *C, Object *ob, const bool UNUSED(reveal_
return true;
}
-/**
- * Select and make the target object and bone active.
- * Switches to Pose mode if in Object mode so the selection is visible.
- * Un-hides the target bone and bone layer if necessary.
- *
- * \returns false if object not in layer, bone not found, or other error
- */
bool ED_object_jump_to_bone(bContext *C,
Object *ob,
const char *bone_name,
diff --git a/source/blender/editors/object/object_shader_fx.c b/source/blender/editors/object/object_shader_fx.c
index 2723d7ad1e3..043a679a0c0 100644
--- a/source/blender/editors/object/object_shader_fx.c
+++ b/source/blender/editors/object/object_shader_fx.c
@@ -402,6 +402,8 @@ void OBJECT_OT_shaderfx_add(wmOperatorType *ot)
RNA_def_property_translation_context(ot->prop, BLT_I18NCONTEXT_ID_ID);
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Generic Functions for Operators Using Names and Data Context
* \{ */
diff --git a/source/blender/editors/object/object_utils.c b/source/blender/editors/object/object_utils.c
index c7dfe911ce7..5f85f6ea0eb 100644
--- a/source/blender/editors/object/object_utils.c
+++ b/source/blender/editors/object/object_utils.c
@@ -369,10 +369,6 @@ void ED_object_data_xform_container_item_ensure(struct XFormObjectData_Container
}
}
-/**
- * This may be called multiple times with the same data.
- * Each time, the original transformations are re-applied, instead of accumulating the changes.
- */
void ED_object_data_xform_container_update_all(struct XFormObjectData_Container *xds,
struct Main *bmain,
Depsgraph *depsgraph)
diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c
index f0ab082cd9c..3e74aaeeb10 100644
--- a/source/blender/editors/object/object_vgroup.c
+++ b/source/blender/editors/object/object_vgroup.c
@@ -140,9 +140,6 @@ bool ED_vgroup_sync_from_pose(Object *ob)
return false;
}
-/**
- * Removes out of range MDeformWeights
- */
void ED_vgroup_data_clamp_range(ID *id, const int total)
{
MDeformVert **dvert_arr;
@@ -264,13 +261,6 @@ bool ED_vgroup_parray_alloc(ID *id,
return false;
}
-/**
- * For use with tools that use ED_vgroup_parray_alloc with \a use_vert_sel == true.
- * This finds the unselected mirror deform verts and copies the weights to them from the selected.
- *
- * \note \a dvert_array has mirrored weights filled in,
- * in case cleanup operations are needed on both.
- */
void ED_vgroup_parray_mirror_sync(Object *ob,
MDeformVert **dvert_array,
const int dvert_tot,
@@ -314,11 +304,6 @@ void ED_vgroup_parray_mirror_sync(Object *ob,
MEM_freeN(dvert_array_all);
}
-/**
- * Fill in the pointers for mirror verts (as if all mirror verts were selected too).
- *
- * similar to #ED_vgroup_parray_mirror_sync but only fill in mirror points.
- */
void ED_vgroup_parray_mirror_assign(Object *ob, MDeformVert **dvert_array, const int dvert_tot)
{
BMEditMesh *em = BKE_editmesh_from_object(ob);
@@ -383,7 +368,6 @@ void ED_vgroup_parray_remove_zero(MDeformVert **dvert_array,
}
}
-/* matching index only */
bool ED_vgroup_array_copy(Object *ob, Object *ob_from)
{
MDeformVert **dvert_array_from = NULL, **dvf;
@@ -575,9 +559,6 @@ static void ED_mesh_defvert_mirror_update_ob(Object *ob, int def_nr, int vidx)
}
}
-/**
- * Use when adjusting the active vertex weight and apply to mirror vertices.
- */
void ED_vgroup_vert_active_mirror(Object *ob, int def_nr)
{
Mesh *me = ob->data;
@@ -883,7 +864,6 @@ static void ED_vgroup_nr_vert_add(
}
}
-/* called while not in editmode */
void ED_vgroup_vert_add(Object *ob, bDeformGroup *dg, int vertnum, float weight, int assignmode)
{
/* add the vert to the deform group with the
@@ -912,7 +892,6 @@ void ED_vgroup_vert_add(Object *ob, bDeformGroup *dg, int vertnum, float weight,
}
}
-/* mesh object mode, lattice can be in editmode */
void ED_vgroup_vert_remove(Object *ob, bDeformGroup *dg, int vertnum)
{
/* This routine removes the vertex from the specified
@@ -2369,8 +2348,6 @@ static void dvert_mirror_op(MDeformVert *dvert,
}
}
-/* TODO: vgroup locking. */
-/* TODO: face masking. */
void ED_vgroup_mirror(Object *ob,
const bool mirror_weights,
const bool flip_vgroups,
@@ -2379,6 +2356,8 @@ void ED_vgroup_mirror(Object *ob,
int *r_totmirr,
int *r_totfail)
{
+ /* TODO: vgroup locking.
+ * TODO: face masking. */
#define VGROUP_MIRR_OP \
dvert_mirror_op(dvert, \
diff --git a/source/blender/editors/object/object_volume.c b/source/blender/editors/object/object_volume.c
index fbdee00c29c..6c92814abc0 100644
--- a/source/blender/editors/object/object_volume.c
+++ b/source/blender/editors/object/object_volume.c
@@ -158,7 +158,6 @@ static int volume_import_invoke(bContext *C, wmOperator *op, const wmEvent *UNUS
return OPERATOR_RUNNING_MODAL;
}
-/* called by other space types too */
void OBJECT_OT_volume_import(wmOperatorType *ot)
{
/* identifiers */
diff --git a/source/blender/editors/physics/dynamicpaint_ops.c b/source/blender/editors/physics/dynamicpaint_ops.c
index be6b44f87bf..80e3f934c80 100644
--- a/source/blender/editors/physics/dynamicpaint_ops.c
+++ b/source/blender/editors/physics/dynamicpaint_ops.c
@@ -92,7 +92,6 @@ static int surface_slot_add_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
-/* add surface slot */
void DPAINT_OT_surface_slot_add(wmOperatorType *ot)
{
/* identifiers */
@@ -141,7 +140,6 @@ static int surface_slot_remove_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
-/* remove surface slot */
void DPAINT_OT_surface_slot_remove(wmOperatorType *ot)
{
/* identifiers */
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index fc80767be9e..f1e6f02cb39 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -1419,7 +1419,6 @@ static void pe_iterate_lengths(Scene *scene, PTCacheEdit *edit)
BLI_task_parallel_range(0, edit->totpoint, &iter_data, iterate_lengths_iter, &settings);
}
-/* set current distances to be kept between neighboring keys */
void recalc_lengths(PTCacheEdit *edit)
{
POINT_P;
@@ -1437,7 +1436,6 @@ void recalc_lengths(PTCacheEdit *edit)
}
}
-/* calculate a tree for finding nearest emitter's vertice */
void recalc_emitter_field(Depsgraph *UNUSED(depsgraph), Object *UNUSED(ob), ParticleSystem *psys)
{
PTCacheEdit *edit = psys->edit;
@@ -5261,7 +5259,6 @@ void PARTICLE_OT_shape_cut(wmOperatorType *ot)
/** \name Particle Edit Toggle Operator
* \{ */
-/* initialize needed data for bake edit */
void PE_create_particle_edit(
Depsgraph *depsgraph, Scene *scene, Object *ob, PointCache *cache, ParticleSystem *psys)
{
diff --git a/source/blender/editors/physics/particle_edit_undo.c b/source/blender/editors/physics/particle_edit_undo.c
index 601a8385a24..804ab614c09 100644
--- a/source/blender/editors/physics/particle_edit_undo.c
+++ b/source/blender/editors/physics/particle_edit_undo.c
@@ -298,7 +298,6 @@ static void particle_undosys_foreach_ID_ref(UndoStep *us_p,
foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->object_ref));
}
-/* Export for ED_undo_sys. */
void ED_particle_undosys_type(UndoType *ut)
{
ut->name = "Edit Particle";
diff --git a/source/blender/editors/physics/physics_intern.h b/source/blender/editors/physics/physics_intern.h
index ef07d73826a..e8270c7a4aa 100644
--- a/source/blender/editors/physics/physics_intern.h
+++ b/source/blender/editors/physics/physics_intern.h
@@ -32,6 +32,7 @@ struct Scene;
struct wmOperatorType;
/* particle_edit.c */
+
void PARTICLE_OT_select_all(struct wmOperatorType *ot);
void PARTICLE_OT_select_roots(struct wmOperatorType *ot);
void PARTICLE_OT_select_tips(struct wmOperatorType *ot);
@@ -60,18 +61,28 @@ void PARTICLE_OT_edited_clear(struct wmOperatorType *ot);
void PARTICLE_OT_unify_length(struct wmOperatorType *ot);
+/**
+ * Initialize needed data for bake edit.
+ */
void PE_create_particle_edit(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
struct PointCache *cache,
struct ParticleSystem *psys);
+/**
+ * Set current distances to be kept between neighboring keys.
+ */
void recalc_lengths(struct PTCacheEdit *edit);
+/**
+ * Calculate a tree for finding nearest emitter's vertice.
+ */
void recalc_emitter_field(struct Depsgraph *depsgraph,
struct Object *ob,
struct ParticleSystem *psys);
void update_world_cos(struct Object *ob, struct PTCacheEdit *edit);
/* particle_object.c */
+
void OBJECT_OT_particle_system_add(struct wmOperatorType *ot);
void OBJECT_OT_particle_system_remove(struct wmOperatorType *ot);
@@ -92,6 +103,7 @@ void PARTICLE_OT_dupliob_move_down(struct wmOperatorType *ot);
void PARTICLE_OT_dupliob_refresh(struct wmOperatorType *ot);
/* particle_boids.c */
+
void BOID_OT_rule_add(struct wmOperatorType *ot);
void BOID_OT_rule_del(struct wmOperatorType *ot);
void BOID_OT_rule_move_up(struct wmOperatorType *ot);
@@ -103,6 +115,7 @@ void BOID_OT_state_move_up(struct wmOperatorType *ot);
void BOID_OT_state_move_down(struct wmOperatorType *ot);
/* physics_fluid.c */
+
void FLUID_OT_bake_all(struct wmOperatorType *ot);
void FLUID_OT_free_all(struct wmOperatorType *ot);
void FLUID_OT_bake_data(struct wmOperatorType *ot);
@@ -118,13 +131,21 @@ void FLUID_OT_free_guides(struct wmOperatorType *ot);
void FLUID_OT_pause_bake(struct wmOperatorType *ot);
/* dynamicpaint.c */
+
void DPAINT_OT_bake(struct wmOperatorType *ot);
+/**
+ * Add surface slot.
+ */
void DPAINT_OT_surface_slot_add(struct wmOperatorType *ot);
+/**
+ * Remove surface slot.
+ */
void DPAINT_OT_surface_slot_remove(struct wmOperatorType *ot);
void DPAINT_OT_type_toggle(struct wmOperatorType *ot);
void DPAINT_OT_output_toggle(struct wmOperatorType *ot);
/* physics_pointcache.c */
+
void PTCACHE_OT_bake_all(struct wmOperatorType *ot);
void PTCACHE_OT_free_bake_all(struct wmOperatorType *ot);
void PTCACHE_OT_bake(struct wmOperatorType *ot);
@@ -134,6 +155,7 @@ void PTCACHE_OT_add(struct wmOperatorType *ot);
void PTCACHE_OT_remove(struct wmOperatorType *ot);
/* rigidbody_object.c */
+
void RIGIDBODY_OT_object_add(struct wmOperatorType *ot);
void RIGIDBODY_OT_object_remove(struct wmOperatorType *ot);
@@ -144,10 +166,12 @@ void RIGIDBODY_OT_shape_change(struct wmOperatorType *ot);
void RIGIDBODY_OT_mass_calculate(struct wmOperatorType *ot);
/* rigidbody_constraint.c */
+
void RIGIDBODY_OT_constraint_add(struct wmOperatorType *ot);
void RIGIDBODY_OT_constraint_remove(struct wmOperatorType *ot);
/* rigidbody_world.c */
+
void RIGIDBODY_OT_world_add(struct wmOperatorType *ot);
void RIGIDBODY_OT_world_remove(struct wmOperatorType *ot);
void RIGIDBODY_OT_world_export(struct wmOperatorType *ot);
diff --git a/source/blender/editors/render/render_intern.h b/source/blender/editors/render/render_intern.h
index e1d03e6f3be..d374717664b 100644
--- a/source/blender/editors/render/render_intern.h
+++ b/source/blender/editors/render/render_intern.h
@@ -28,6 +28,7 @@ struct bContext;
struct wmOperatorType;
/* render_shading.c */
+
void OBJECT_OT_material_slot_add(struct wmOperatorType *ot);
void OBJECT_OT_material_slot_remove(struct wmOperatorType *ot);
void OBJECT_OT_material_slot_assign(struct wmOperatorType *ot);
@@ -80,10 +81,18 @@ void TEXTURE_OT_slot_paste(struct wmOperatorType *ot);
void TEXTURE_OT_slot_move(struct wmOperatorType *ot);
/* render_internal.c */
+
+/**
+ * Contextual render, using current scene, view3d?
+ */
void RENDER_OT_render(struct wmOperatorType *ot);
void RENDER_OT_shutter_curve_preset(struct wmOperatorType *ot);
/* render_view.c */
+
+/**
+ * New window uses x,y to set position.
+ */
struct ScrArea *render_view_open(struct bContext *C, int mx, int my, struct ReportList *reports);
void RENDER_OT_view_show(struct wmOperatorType *ot);
diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c
index 49e7ebf6340..29d829dc131 100644
--- a/source/blender/editors/render/render_internal.c
+++ b/source/blender/editors/render/render_internal.c
@@ -1076,7 +1076,6 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
return OPERATOR_RUNNING_MODAL;
}
-/* contextual render, using current scene, view3d? */
void RENDER_OT_render(wmOperatorType *ot)
{
PropertyRNA *prop;
diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c
index 4bf250b9d4f..409430d28f1 100644
--- a/source/blender/editors/render/render_preview.c
+++ b/source/blender/editors/render/render_preview.c
@@ -103,6 +103,8 @@
#include "ED_view3d.h"
#include "ED_view3d_offscreen.h"
+#include "UI_interface_icons.h"
+
#ifndef NDEBUG
/* Used for database init assert(). */
# include "BLI_threads.h"
@@ -212,7 +214,7 @@ static bool check_engine_supports_preview(Scene *scene)
static bool preview_method_is_render(int pr_method)
{
- return ELEM(pr_method, PR_ICON_RENDER, PR_BUTS_RENDER, PR_NODE_RENDER);
+ return ELEM(pr_method, PR_ICON_RENDER, PR_BUTS_RENDER);
}
void ED_preview_free_dbase(void)
@@ -459,7 +461,7 @@ static Scene *preview_prepare_scene(
Scene *sce;
Main *pr_main = sp->pr_main;
- memcpy(pr_main->name, BKE_main_blendfile_path(bmain), sizeof(pr_main->name));
+ memcpy(pr_main->filepath, BKE_main_blendfile_path(bmain), sizeof(pr_main->filepath));
sce = preview_get_scene(pr_main);
if (sce) {
@@ -526,15 +528,6 @@ static Scene *preview_prepare_scene(
MA_SPHERE_A :
mat->pr_type;
set_preview_visibility(pr_main, sce, view_layer, preview_type, sp->pr_method);
-
- if (sp->pr_method != PR_ICON_RENDER) {
- if (mat->nodetree && sp->pr_method == PR_NODE_RENDER) {
- /* two previews, they get copied by wmJob */
- BKE_node_preview_init_tree(mat->nodetree, sp->sizex, sp->sizey, true);
- /* WATCH: Accessing origmat is not safe! */
- BKE_node_preview_init_tree(origmat->nodetree, sp->sizex, sp->sizey, true);
- }
- }
}
else {
sce->display.render_aa = SCE_DISPLAY_AA_OFF;
@@ -570,13 +563,6 @@ static Scene *preview_prepare_scene(
sp->id_copy = NULL;
BLI_addtail(&pr_main->textures, tex);
}
-
- if (tex && tex->nodetree && sp->pr_method == PR_NODE_RENDER) {
- /* two previews, they get copied by wmJob */
- BKE_node_preview_init_tree(tex->nodetree, sp->sizex, sp->sizey, true);
- /* WATCH: Accessing origtex is not safe! */
- BKE_node_preview_init_tree(origtex->nodetree, sp->sizex, sp->sizey, true);
- }
}
else if (id_type == ID_LA) {
Light *la = NULL, *origla = (Light *)id;
@@ -606,13 +592,6 @@ static Scene *preview_prepare_scene(
}
}
}
-
- if (la && la->nodetree && sp->pr_method == PR_NODE_RENDER) {
- /* two previews, they get copied by wmJob */
- BKE_node_preview_init_tree(la->nodetree, sp->sizex, sp->sizey, true);
- /* WATCH: Accessing origla is not safe! */
- BKE_node_preview_init_tree(origla->nodetree, sp->sizex, sp->sizey, true);
- }
}
else if (id_type == ID_WO) {
World *wrld = NULL, *origwrld = (World *)id;
@@ -626,13 +605,6 @@ static Scene *preview_prepare_scene(
set_preview_visibility(pr_main, sce, view_layer, MA_SKY, sp->pr_method);
sce->world = wrld;
-
- if (wrld && wrld->nodetree && sp->pr_method == PR_NODE_RENDER) {
- /* two previews, they get copied by wmJob */
- BKE_node_preview_init_tree(wrld->nodetree, sp->sizex, sp->sizey, true);
- /* WATCH: Accessing origwrld is not safe! */
- BKE_node_preview_init_tree(origwrld->nodetree, sp->sizex, sp->sizey, true);
- }
}
return sce;
@@ -786,6 +758,11 @@ struct ObjectPreviewData {
int sizey;
};
+static bool object_preview_is_type_supported(const Object *ob)
+{
+ return OB_TYPE_IS_GEOMETRY(ob->type);
+}
+
static Object *object_preview_camera_create(Main *preview_main,
ViewLayer *view_layer,
Object *preview_object)
@@ -989,7 +966,7 @@ static void action_preview_render(IconPreview *preview, IconPreviewSize *preview
preview_sized->sizey,
IB_rect,
V3D_OFSDRAW_NONE,
- R_ALPHAPREMUL,
+ R_ADDSKY,
NULL,
NULL,
err_out);
@@ -1030,41 +1007,8 @@ static int shader_preview_break(void *spv)
return *(sp->stop);
}
-/* outside thread, called before redraw notifiers, it moves finished preview over */
-static void shader_preview_updatejob(void *spv)
+static void shader_preview_updatejob(void *UNUSED(spv))
{
- ShaderPreview *sp = spv;
-
- if (sp->pr_method == PR_NODE_RENDER) {
- if (GS(sp->id->name) == ID_MA) {
- Material *mat = (Material *)sp->id;
-
- if (sp->matcopy && mat->nodetree && sp->matcopy->nodetree) {
- ntreeLocalSync(sp->matcopy->nodetree, mat->nodetree);
- }
- }
- else if (GS(sp->id->name) == ID_TE) {
- Tex *tex = (Tex *)sp->id;
-
- if (sp->texcopy && tex->nodetree && sp->texcopy->nodetree) {
- ntreeLocalSync(sp->texcopy->nodetree, tex->nodetree);
- }
- }
- else if (GS(sp->id->name) == ID_WO) {
- World *wrld = (World *)sp->id;
-
- if (sp->worldcopy && wrld->nodetree && sp->worldcopy->nodetree) {
- ntreeLocalSync(sp->worldcopy->nodetree, wrld->nodetree);
- }
- }
- else if (GS(sp->id->name) == ID_LA) {
- Light *la = (Light *)sp->id;
-
- if (sp->lampcopy && la->nodetree && sp->lampcopy->nodetree) {
- ntreeLocalSync(sp->lampcopy->nodetree, la->nodetree);
- }
- }
- }
}
/* Renders texture directly to render buffer. */
@@ -1180,21 +1124,12 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs
sce->r.scemode |= R_NO_IMAGE_LOAD;
sce->display.render_aa = SCE_DISPLAY_AA_SAMPLES_8;
}
- else if (sp->pr_method == PR_NODE_RENDER) {
- if (idtype == ID_MA) {
- sce->r.scemode |= R_MATNODE_PREVIEW;
- }
- else if (idtype == ID_TE) {
- sce->r.scemode |= R_TEXNODE_PREVIEW;
- }
- sce->display.render_aa = SCE_DISPLAY_AA_OFF;
- }
else { /* PR_BUTS_RENDER */
sce->display.render_aa = SCE_DISPLAY_AA_SAMPLES_8;
}
/* Callbacks are cleared on GetRender(). */
- if (ELEM(sp->pr_method, PR_BUTS_RENDER, PR_NODE_RENDER)) {
+ if (sp->pr_method == PR_BUTS_RENDER) {
RE_display_update_cb(re, sp, shader_preview_update);
}
/* set this for all previews, default is react to G.is_break still */
@@ -1302,10 +1237,6 @@ static void shader_preview_free(void *customdata)
main_id_copy = (ID *)sp->lampcopy;
BLI_remlink(&pr_main->lights, sp->lampcopy);
}
- if (main_id_copy || sp->id_copy) {
- /* node previews */
- shader_preview_updatejob(sp);
- }
if (sp->own_id_copy) {
if (sp->id_copy) {
preview_id_copy_free(sp->id_copy);
@@ -1658,9 +1589,12 @@ static void icon_preview_startjob_all_sizes(void *customdata,
if (ip->id != NULL) {
switch (GS(ip->id->name)) {
case ID_OB:
- /* Much simpler than the ShaderPreview mess used for other ID types. */
- object_preview_render(ip, cur_size);
- continue;
+ if (object_preview_is_type_supported((Object *)ip->id)) {
+ /* Much simpler than the ShaderPreview mess used for other ID types. */
+ object_preview_render(ip, cur_size);
+ continue;
+ }
+ break;
case ID_AC:
action_preview_render(ip, cur_size);
continue;
@@ -1749,6 +1683,18 @@ static void icon_preview_free(void *customdata)
MEM_freeN(ip);
}
+bool ED_preview_id_is_supported(const ID *id)
+{
+ if (id == NULL) {
+ return false;
+ }
+
+ if (GS(id->name) == ID_OB) {
+ return object_preview_is_type_supported((const Object *)id);
+ }
+ return BKE_previewimg_id_get_p(id) != NULL;
+}
+
void ED_preview_icon_render(
const bContext *C, Scene *scene, ID *id, uint *rect, int sizex, int sizey)
{
@@ -1849,7 +1795,7 @@ void ED_preview_shader_job(const bContext *C,
wmJob *wm_job;
ShaderPreview *sp;
Scene *scene = CTX_data_scene(C);
- short id_type = GS(id->name);
+ const ID_Type id_type = GS(id->name);
BLI_assert(BKE_previewimg_id_supports_jobs(id));
@@ -1860,11 +1806,6 @@ void ED_preview_shader_job(const bContext *C,
return;
}
- /* Only texture node preview is supported with Cycles. */
- if (method == PR_NODE_RENDER && id_type != ID_TE) {
- return;
- }
-
ED_preview_ensure_dbase();
wm_job = WM_jobs_get(CTX_wm_manager(C),
@@ -1893,7 +1834,7 @@ void ED_preview_shader_job(const bContext *C,
* once with custom preview .blend path for external engines */
/* grease pencil use its own preview file */
- if (GS(id->name) == ID_MA) {
+ if (id_type == ID_MA) {
ma = (Material *)id;
}
@@ -1929,4 +1870,45 @@ void ED_preview_kill_jobs(wmWindowManager *wm, Main *UNUSED(bmain))
}
}
+typedef struct PreviewRestartQueueEntry {
+ struct PreviewRestartQueueEntry *next, *prev;
+
+ enum eIconSizes size;
+ ID *id;
+} PreviewRestartQueueEntry;
+
+static ListBase /* #PreviewRestartQueueEntry */ G_restart_previews_queue;
+
+void ED_preview_restart_queue_free(void)
+{
+ BLI_freelistN(&G_restart_previews_queue);
+}
+
+void ED_preview_restart_queue_add(ID *id, enum eIconSizes size)
+{
+ PreviewRestartQueueEntry *queue_entry = MEM_mallocN(sizeof(*queue_entry), __func__);
+ queue_entry->size = size;
+ queue_entry->id = id;
+ BLI_addtail(&G_restart_previews_queue, queue_entry);
+}
+
+void ED_preview_restart_queue_work(const bContext *C)
+{
+ LISTBASE_FOREACH_MUTABLE (PreviewRestartQueueEntry *, queue_entry, &G_restart_previews_queue) {
+ PreviewImage *preview = BKE_previewimg_id_get(queue_entry->id);
+ if (!preview) {
+ continue;
+ }
+ if (preview->flag[queue_entry->size] & PRV_USER_EDITED) {
+ /* Don't touch custom previews. */
+ continue;
+ }
+
+ BKE_previewimg_clear_single(preview, queue_entry->size);
+ UI_icon_render_id(C, NULL, queue_entry->id, queue_entry->size, true);
+
+ BLI_freelinkN(&G_restart_previews_queue, queue_entry);
+ }
+}
+
/** \} */
diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c
index b6e6869f4e2..54ff25ede28 100644
--- a/source/blender/editors/render/render_shading.c
+++ b/source/blender/editors/render/render_shading.c
@@ -2226,10 +2226,10 @@ void SCENE_OT_freestyle_stroke_material_create(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-#endif /* WITH_FREESTYLE */
-
/** \} */
+#endif /* WITH_FREESTYLE */
+
/* -------------------------------------------------------------------- */
/** \name Texture Slot Move Operator
* \{ */
diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.c
index 8bc2281db73..e975eab4736 100644
--- a/source/blender/editors/render/render_update.c
+++ b/source/blender/editors/render/render_update.c
@@ -68,7 +68,6 @@
/** \name Render Engines
* \{ */
-/* Update 3D viewport render or draw engine on changes to the scene or view settings. */
void ED_render_view3d_update(Depsgraph *depsgraph,
wmWindow *window,
ScrArea *area,
@@ -126,8 +125,6 @@ void ED_render_view3d_update(Depsgraph *depsgraph,
}
}
-/* Update all 3D viewport render and draw engines on changes to the scene.
- * This is called by the dependency graph when it detects changes. */
void ED_render_scene_update(const DEGEditorUpdateContext *update_ctx, const bool updated)
{
Main *bmain = update_ctx->bmain;
diff --git a/source/blender/editors/render/render_view.c b/source/blender/editors/render/render_view.c
index 7f27b6f585a..9163718ffad 100644
--- a/source/blender/editors/render/render_view.c
+++ b/source/blender/editors/render/render_view.c
@@ -132,7 +132,6 @@ static ScrArea *find_area_image_empty(bContext *C)
/********************** open image editor for render *************************/
-/* new window uses x,y to set position */
ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
{
Main *bmain = CTX_data_main(C);
diff --git a/source/blender/editors/scene/scene_edit.c b/source/blender/editors/scene/scene_edit.c
index 5195bc8303a..555ffbfd5e7 100644
--- a/source/blender/editors/scene/scene_edit.c
+++ b/source/blender/editors/scene/scene_edit.c
@@ -77,10 +77,6 @@ Scene *ED_scene_add(Main *bmain, bContext *C, wmWindow *win, eSceneCopyMethod me
return scene_new;
}
-/**
- * \note Only call outside of area/region loops
- * \return true if successful
- */
bool ED_scene_delete(bContext *C, Main *bmain, Scene *scene)
{
Scene *scene_new;
@@ -113,7 +109,6 @@ bool ED_scene_delete(bContext *C, Main *bmain, Scene *scene)
return true;
}
-/* Depsgraph updates after scene becomes active in a window. */
void ED_scene_change_update(Main *bmain, Scene *scene, ViewLayer *layer)
{
Depsgraph *depsgraph = BKE_scene_ensure_depsgraph(bmain, scene, layer);
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index 8523496bdbd..5dc6fe88663 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -140,7 +140,6 @@ void ED_region_pixelspace(const ARegion *region)
GPU_matrix_identity_set();
}
-/* only exported for WM */
void ED_region_do_listen(wmRegionListenerParams *params)
{
ARegion *region = params->region;
@@ -169,7 +168,6 @@ void ED_region_do_listen(wmRegionListenerParams *params)
}
}
-/* only exported for WM */
void ED_area_do_listen(wmSpaceTypeListenerParams *params)
{
/* no generic notes? */
@@ -178,7 +176,6 @@ void ED_area_do_listen(wmSpaceTypeListenerParams *params)
}
}
-/* only exported for WM */
void ED_area_do_refresh(bContext *C, ScrArea *area)
{
/* no generic notes? */
@@ -443,7 +440,6 @@ void ED_area_do_msg_notify_tag_refresh(
ED_area_tag_refresh(area);
}
-/* Follow ARegionType.message_subscribe */
void ED_area_do_mgs_subscribe_for_tool_header(const wmRegionMessageSubscribeParams *params)
{
struct wmMsgBus *mbus = params->message_bus;
@@ -507,7 +503,6 @@ static bool area_is_pseudo_minimized(const ScrArea *area)
return (area->winx < 3) || (area->winy < 3);
}
-/* only exported for WM */
void ED_region_do_layout(bContext *C, ARegion *region)
{
/* This is optional, only needed for dynamically sized regions. */
@@ -531,7 +526,6 @@ void ED_region_do_layout(bContext *C, ARegion *region)
region->flag &= ~RGN_FLAG_SEARCH_FILTER_UPDATE;
}
-/* only exported for WM */
void ED_region_do_draw(bContext *C, ARegion *region)
{
wmWindow *win = CTX_wm_window(C);
@@ -594,7 +588,7 @@ void ED_region_do_draw(bContext *C, ARegion *region)
memset(&region->drawrct, 0, sizeof(region->drawrct));
- UI_blocklist_free_inactive(C, &region->uiblocks);
+ UI_blocklist_free_inactive(C, region);
if (area) {
const bScreen *screen = WM_window_get_active_screen(win);
@@ -705,10 +699,6 @@ void ED_region_tag_refresh_ui(ARegion *region)
}
}
-/**
- * Tag editor overlays to be redrawn. If in doubt about which parts need to be redrawn (partial
- * clipping rectangle set), redraw everything.
- */
void ED_region_tag_redraw_editor_overlays(struct ARegion *region)
{
if (region && !(region->do_draw & (RGN_DRAWING | RGN_DRAW))) {
@@ -786,9 +776,6 @@ void ED_area_tag_refresh(ScrArea *area)
/* *************************************************************** */
-/**
- * Returns the search string if the space type and region type support property search.
- */
const char *ED_area_region_search_filter_get(const ScrArea *area, const ARegion *region)
{
/* Only the properties editor has a search string for now. */
@@ -802,9 +789,6 @@ const char *ED_area_region_search_filter_get(const ScrArea *area, const ARegion
return NULL;
}
-/**
- * Set the temporary update flag for property search.
- */
void ED_region_search_filter_update(const ScrArea *area, ARegion *region)
{
region->flag |= RGN_FLAG_SEARCH_FILTER_UPDATE;
@@ -817,7 +801,6 @@ void ED_region_search_filter_update(const ScrArea *area, ARegion *region)
/* *************************************************************** */
-/* use NULL to disable it */
void ED_area_status_text(ScrArea *area, const char *str)
{
/* happens when running transform operators in background mode */
@@ -1271,7 +1254,6 @@ static void region_overlap_fix(ScrArea *area, ARegion *region)
}
}
-/* overlapping regions only in the following restricted cases */
bool ED_region_is_overlap(int spacetype, int regiontype)
{
if (regiontype == RGN_TYPE_HUD) {
@@ -1926,7 +1908,6 @@ bool ED_area_has_shared_border(struct ScrArea *a, struct ScrArea *b)
return area_getorientation(a, b) != -1;
}
-/* called in screen_refresh, or screens_init, also area size changes */
void ED_area_init(wmWindowManager *wm, wmWindow *win, ScrArea *area)
{
WorkSpace *workspace = WM_window_get_active_workspace(win);
@@ -1985,7 +1966,7 @@ void ED_area_init(wmWindowManager *wm, wmWindow *win, ScrArea *area)
}
else {
/* prevent uiblocks to run */
- UI_blocklist_free(NULL, &region->uiblocks);
+ UI_blocklist_free(NULL, region);
}
/* Some AZones use View2D data which is only updated in region init, so call that first! */
@@ -2076,15 +2057,11 @@ static void region_update_rect(ARegion *region)
BLI_rcti_init(&region->v2d.mask, 0, region->winx - 1, 0, region->winy - 1);
}
-/**
- * Call to move a popup window (keep OpenGL context free!)
- */
void ED_region_update_rect(ARegion *region)
{
region_update_rect(region);
}
-/* externally called for floating regions like menus */
void ED_region_floating_init(ARegion *region)
{
BLI_assert(region->alignment == RGN_ALIGN_FLOAT);
@@ -2114,18 +2091,22 @@ void ED_region_cursor_set(wmWindow *win, ScrArea *area, ARegion *region)
WM_cursor_set(win, WM_CURSOR_DEFAULT);
}
-/* for use after changing visibility of regions */
void ED_region_visibility_change_update(bContext *C, ScrArea *area, ARegion *region)
{
if (region->flag & RGN_FLAG_HIDDEN) {
WM_event_remove_handlers(C, &region->handlers);
+ /* Needed to close any open pop-overs which would otherwise remain open,
+ * crashing on attempting to refresh. See: T93410.
+ *
+ * When #ED_area_init frees buttons via #UI_blocklist_free a NULL context
+ * is passed, causing the free not to remove menus or their handlers. */
+ UI_region_free_active_but_all(C, region);
}
ED_area_init(CTX_wm_manager(C), CTX_wm_window(C), area);
ED_area_tag_redraw(area);
}
-/* for quick toggle, can skip fades */
void region_toggle_hidden(bContext *C, ARegion *region, const bool do_fade)
{
ScrArea *area = CTX_wm_area(C);
@@ -2141,15 +2122,11 @@ void region_toggle_hidden(bContext *C, ARegion *region, const bool do_fade)
}
}
-/* exported to all editors, uses fading default */
void ED_region_toggle_hidden(bContext *C, ARegion *region)
{
region_toggle_hidden(C, region, true);
}
-/**
- * we swap spaces for fullscreen to keep all allocated data area vertices were set
- */
void ED_area_data_copy(ScrArea *area_dst, ScrArea *area_src, const bool do_free)
{
const char spacetype = area_dst->spacetype;
@@ -2455,9 +2432,6 @@ void ED_area_swapspace(bContext *C, ScrArea *sa1, ScrArea *sa2)
ED_area_tag_refresh(sa2);
}
-/**
- * \param skip_region_exit: Skip calling area exit callback. Set for opening temp spaces.
- */
void ED_area_newspace(bContext *C, ScrArea *area, int type, const bool skip_region_exit)
{
wmWindow *win = CTX_wm_window(C);
@@ -2622,7 +2596,6 @@ void ED_area_prevspace(bContext *C, ScrArea *area)
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_CHANGED, area);
}
-/* returns offset for next button in header */
int ED_area_header_switchbutton(const bContext *C, uiBlock *block, int yco)
{
ScrArea *area = CTX_wm_area(C);
@@ -2934,11 +2907,16 @@ static const char *region_panels_collect_categories(ARegion *region,
return NULL;
}
-/**
- * \param contexts: A NULL terminated array of context strings to match against.
- * Matching against any of these strings will draw the panel.
- * Can be NULL to skip context checks.
- */
+static int panel_draw_width_from_max_width_get(const ARegion *region,
+ const PanelType *panel_type,
+ const int max_width)
+{
+ /* With a background, we want some extra padding. */
+ return UI_panel_should_show_background(region, panel_type) ?
+ max_width - UI_PANEL_MARGIN_X * 2.0f :
+ max_width;
+}
+
void ED_region_panels_layout_ex(const bContext *C,
ARegion *region,
ListBase *paneltypes,
@@ -2982,7 +2960,6 @@ void ED_region_panels_layout_ex(const bContext *C,
}
const int width_no_header = BLI_rctf_size_x(&v2d->cur) - margin_x;
- const int width = width_no_header - UI_PANEL_MARGIN_X * 2.0f;
/* Works out to 10 * UI_UNIT_X or 20 * UI_UNIT_X. */
const int em = (region->type->prefsizex) ? 10 : 20;
@@ -3010,6 +2987,7 @@ void ED_region_panels_layout_ex(const bContext *C,
continue;
}
}
+ const int width = panel_draw_width_from_max_width_get(region, pt, width_no_header);
if (panel && UI_panel_is_dragging(panel)) {
/* Prevent View2d.tot rectangle size changes while dragging panels. */
@@ -3040,6 +3018,7 @@ void ED_region_panels_layout_ex(const bContext *C,
!STREQ(category, panel->type->category)) {
continue;
}
+ const int width = panel_draw_width_from_max_width_get(region, panel->type, width_no_header);
if (panel && UI_panel_is_dragging(panel)) {
/* Prevent View2d.tot rectangle size changes while dragging panels. */
@@ -3249,10 +3228,6 @@ static bool panel_property_search(const bContext *C,
return false;
}
-/**
- * Build the same panel list as #ED_region_panels_layout_ex and checks whether any
- * of the panels contain a search result based on the area / region's search filter.
- */
bool ED_region_property_search(const bContext *C,
ARegion *region,
ListBase *paneltypes,
@@ -3323,7 +3298,7 @@ bool ED_region_property_search(const bContext *C,
}
/* Free the panels and blocks, as they are only used for search. */
- UI_blocklist_free(C, &region->uiblocks);
+ UI_blocklist_free(C, region);
UI_panels_free_instanced(C, region);
BKE_area_region_panels_free(&region->panels);
@@ -3458,9 +3433,6 @@ int ED_area_footersize(void)
return ED_area_headersize();
}
-/**
- * \return the final height of a global \a area, accounting for DPI.
- */
int ED_area_global_size_y(const ScrArea *area)
{
BLI_assert(ED_area_is_global(area));
@@ -3510,12 +3482,6 @@ ScrArea *ED_screen_areas_iter_next(const bScreen *screen, const ScrArea *area)
return screen->areabase.first;
}
-/**
- * For now we just assume all global areas are made up out of horizontal bars
- * with the same size. A fixed size could be stored in ARegion instead if needed.
- *
- * \return the DPI aware height of a single bar/region in global areas.
- */
int ED_region_global_size_y(void)
{
return ED_area_headersize(); /* same size as header */
@@ -3841,9 +3807,6 @@ void ED_region_cache_draw_cached_segments(
}
}
-/**
- * Generate subscriptions for this region.
- */
void ED_region_message_subscribe(wmRegionMessageSubscribeParams *params)
{
ARegion *region = params->region;
diff --git a/source/blender/editors/screen/area_query.c b/source/blender/editors/screen/area_query.c
index 30e744ca174..022f8620b0b 100644
--- a/source/blender/editors/screen/area_query.c
+++ b/source/blender/editors/screen/area_query.c
@@ -140,10 +140,6 @@ bool ED_region_overlap_isect_xy_with_margin(const ARegion *region,
ED_region_overlap_isect_y_with_margin(region, event_xy[1], margin));
}
-/**
- * \note: This may return true for multiple overlapping regions. If it matters, check overlapped
- * regions first (#ARegion.overlap).
- */
bool ED_region_contains_xy(const ARegion *region, const int event_xy[2])
{
/* Only use the margin when inside the region. */
@@ -193,13 +189,6 @@ bool ED_region_contains_xy(const ARegion *region, const int event_xy[2])
return false;
}
-/**
- * Similar to #BKE_area_find_region_xy() but when \a event_xy intersects an overlapping region,
- * this returns the region that is visually under the cursor. E.g. when over the
- * transparent part of the region, it returns the region underneath.
- *
- * The overlapping region is determined using the #ED_region_contains_xy() query.
- */
ARegion *ED_area_find_region_xy_visual(const ScrArea *area,
const int regiontype,
const int event_xy[2])
diff --git a/source/blender/editors/screen/area_utils.c b/source/blender/editors/screen/area_utils.c
index 30553bb7f07..9a688ac0b05 100644
--- a/source/blender/editors/screen/area_utils.c
+++ b/source/blender/editors/screen/area_utils.c
@@ -40,9 +40,6 @@
/** \name Generic Tool System Region Callbacks
* \{ */
-/**
- * Callback for #ARegionType.message_subscribe
- */
void ED_region_generic_tools_region_message_subscribe(const wmRegionMessageSubscribeParams *params)
{
struct wmMsgBus *mbus = params->message_bus;
@@ -56,9 +53,6 @@ void ED_region_generic_tools_region_message_subscribe(const wmRegionMessageSubsc
WM_msg_subscribe_rna_anon_prop(mbus, WorkSpace, tools, &msg_sub_value_region_tag_redraw);
}
-/**
- * Callback for #ARegionType.snap_size
- */
int ED_region_generic_tools_region_snap_size(const ARegion *region, int size, int axis)
{
if (axis == 0) {
diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c
index f651fd4fb61..5f523df18d1 100644
--- a/source/blender/editors/screen/glutil.c
+++ b/source/blender/editors/screen/glutil.c
@@ -57,12 +57,6 @@ static void immDrawPixelsTexSetupAttributes(IMMDrawPixelsTexState *state)
vert_format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
}
-/**
- * To be used before calling #immDrawPixelsTex
- * Default shader is #GPU_SHADER_2D_IMAGE_COLOR
- * You can still set uniforms with:
- * `GPU_shader_uniform_int(shader, GPU_shader_get_uniform(shader, "name"), 0);`
- */
IMMDrawPixelsTexState immDrawPixelsTexSetup(int builtin)
{
IMMDrawPixelsTexState state;
@@ -78,20 +72,6 @@ IMMDrawPixelsTexState immDrawPixelsTexSetup(int builtin)
return state;
}
-/**
- * Use the currently bound shader.
- *
- * Use #immDrawPixelsTexSetup to bind the shader you
- * want before calling #immDrawPixelsTex.
- *
- * If using a special shader double check it uses the same
- * attributes "pos" "texCoord" and uniform "image".
- *
- * If color is NULL then use white by default
- *
- * Be also aware that this function unbinds the shader when
- * it's finished.
- */
void immDrawPixelsTexScaled_clipping(IMMDrawPixelsTexState *state,
float x,
float y,
@@ -363,7 +343,6 @@ void immDrawPixelsTex_clipping(IMMDrawPixelsTexState *state,
/* **** Color management helper functions for GLSL display/transform ***** */
-/* Draw given image buffer on a screen using GLSL for display transform */
void ED_draw_imbuf_clipping(ImBuf *ibuf,
float x,
float y,
@@ -577,8 +556,6 @@ int ED_draw_imbuf_method(ImBuf *ibuf)
return U.image_draw_method;
}
-/* don't move to GPU_immediate_util.h because this uses user-prefs
- * and isn't very low level */
void immDrawBorderCorners(uint pos, const rcti *border, float zoomx, float zoomy)
{
float delta_x = 4.0f * UI_DPI_FAC / zoomx;
diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c
index a8c63027254..304205d0cc4 100644
--- a/source/blender/editors/screen/screen_context.c
+++ b/source/blender/editors/screen/screen_context.c
@@ -113,6 +113,8 @@ const char *screen_context_dir[] = {
"active_gpencil_frame",
"active_annotation_layer",
"active_operator",
+ "selected_visible_actions",
+ "selected_editable_actions",
"visible_fcurves",
"editable_fcurves",
"selected_visible_fcurves",
@@ -975,6 +977,90 @@ static eContextResult screen_ctx_active_operator(const bContext *C, bContextData
}
return CTX_RESULT_NO_DATA;
}
+static eContextResult screen_ctx_sel_actions_impl(const bContext *C,
+ bContextDataResult *result,
+ bool editable)
+{
+ bAnimContext ac;
+ if (ANIM_animdata_get_context(C, &ac) && ELEM(ac.spacetype, SPACE_ACTION, SPACE_GRAPH)) {
+ /* In the Action and Shape Key editor always use the action field at the top. */
+ if (ac.spacetype == SPACE_ACTION) {
+ SpaceAction *saction = (SpaceAction *)ac.sl;
+
+ if (ELEM(saction->mode, SACTCONT_ACTION, SACTCONT_SHAPEKEY)) {
+ if (saction->action && !(editable && ID_IS_LINKED(saction->action))) {
+ CTX_data_id_list_add(result, &saction->action->id);
+ }
+
+ CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
+ return CTX_RESULT_OK;
+ }
+ }
+
+ /* Search for selected animation data items. */
+ ListBase anim_data = {NULL, NULL};
+
+ int filter = ANIMFILTER_DATA_VISIBLE;
+ bool check_selected = false;
+
+ switch (ac.spacetype) {
+ case SPACE_GRAPH:
+ filter |= ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_SEL;
+ break;
+
+ case SPACE_ACTION:
+ filter |= ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS;
+ check_selected = true;
+ break;
+ }
+
+ ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+
+ GSet *seen_set = BLI_gset_ptr_new("seen actions");
+
+ LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
+ /* In dopesheet check selection status of individual items, skipping
+ * if not selected or has no selection flag. This is needed so that
+ * selecting action or group rows without any channels works. */
+ if (check_selected && ANIM_channel_setting_get(&ac, ale, ACHANNEL_SETTING_SELECT) <= 0) {
+ continue;
+ }
+
+ bAction *action = ANIM_channel_action_get(ale);
+
+ if (action) {
+ if (editable && ID_IS_LINKED(action)) {
+ continue;
+ }
+
+ /* Add the action to the output list if not already added. */
+ if (!BLI_gset_haskey(seen_set, action)) {
+ CTX_data_id_list_add(result, &action->id);
+ BLI_gset_add(seen_set, action);
+ }
+ }
+ }
+
+ BLI_gset_free(seen_set, NULL);
+
+ ANIM_animdata_freelist(&anim_data);
+
+ CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
+ return CTX_RESULT_OK;
+ }
+ return CTX_RESULT_NO_DATA;
+}
+
+static eContextResult screen_ctx_selected_visible_actions(const bContext *C,
+ bContextDataResult *result)
+{
+ return screen_ctx_sel_actions_impl(C, result, false);
+}
+static eContextResult screen_ctx_selected_editable_actions(const bContext *C,
+ bContextDataResult *result)
+{
+ return screen_ctx_sel_actions_impl(C, result, true);
+}
static eContextResult screen_ctx_sel_edit_fcurves_(const bContext *C,
bContextDataResult *result,
const int extra_filter)
@@ -1185,6 +1271,8 @@ static void ensure_ed_screen_context_functions(void)
register_context_function("editable_gpencil_layers", screen_ctx_editable_gpencil_layers);
register_context_function("editable_gpencil_strokes", screen_ctx_editable_gpencil_strokes);
register_context_function("active_operator", screen_ctx_active_operator);
+ register_context_function("selected_visible_actions", screen_ctx_selected_visible_actions);
+ register_context_function("selected_editable_actions", screen_ctx_selected_editable_actions);
register_context_function("editable_fcurves", screen_ctx_editable_fcurves);
register_context_function("visible_fcurves", screen_ctx_visible_fcurves);
register_context_function("selected_editable_fcurves", screen_ctx_selected_editable_fcurves);
@@ -1195,7 +1283,6 @@ static void ensure_ed_screen_context_functions(void)
register_context_function("ui_list", screen_ctx_ui_list);
}
-/* Entry point for the screen context. */
int ed_screen_context(const bContext *C, const char *member, bContextDataResult *result)
{
if (CTX_data_dir(member)) {
diff --git a/source/blender/editors/screen/screen_draw.c b/source/blender/editors/screen/screen_draw.c
index ab50e327de3..e720ae4b9d8 100644
--- a/source/blender/editors/screen/screen_draw.c
+++ b/source/blender/editors/screen/screen_draw.c
@@ -162,9 +162,6 @@ static void drawscredge_area(ScrArea *area, int sizex, int sizey, float edge_thi
drawscredge_area_draw(sizex, sizey, x1, y1, x2, y2, edge_thickness);
}
-/**
- * Only for edge lines between areas.
- */
void ED_screen_draw_edges(wmWindow *win)
{
bScreen *screen = WM_window_get_active_screen(win);
@@ -231,12 +228,6 @@ void ED_screen_draw_edges(wmWindow *win)
}
}
-/**
- * Visual indication of the two areas involved in a proposed join.
- *
- * \param sa1: Area from which the resultant originates.
- * \param sa2: Target area that will be replaced.
- */
void screen_draw_join_highlight(ScrArea *sa1, ScrArea *sa2)
{
const eScreenDir dir = area_getorientation(sa1, sa2);
@@ -445,9 +436,6 @@ static void screen_preview_draw(const bScreen *screen, int size_x, int size_y)
GPU_matrix_pop();
}
-/**
- * Render the preview for a screen layout in \a screen.
- */
void ED_screen_preview_render(const bScreen *screen, int size_x, int size_y, uint *r_rect)
{
char err_out[256] = "unknown";
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c
index fa0cfd16817..5a2b53163b8 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -203,9 +203,6 @@ ScrArea *area_split(const wmWindow *win,
return newa;
}
-/**
- * Empty screen, with 1 dummy area without spacedata. Uses window size.
- */
bScreen *screen_add(Main *bmain, const char *name, const rcti *rect)
{
bScreen *screen = BKE_libblock_alloc(bmain, ID_SCR, name, 0);
@@ -274,9 +271,6 @@ void screen_data_copy(bScreen *to, bScreen *from)
}
}
-/**
- * Prepare a newly created screen for initializing it as active screen.
- */
void screen_new_activate_prepare(const wmWindow *win, bScreen *screen_new)
{
screen_new->winid = win->winid;
@@ -284,11 +278,6 @@ void screen_new_activate_prepare(const wmWindow *win, bScreen *screen_new)
screen_new->do_draw = true;
}
-/**
- * with `sa_a` as center, `sa_b` is located at: 0=W, 1=N, 2=E, 3=S
- * -1 = not valid check.
- * used with join operator.
- */
eScreenDir area_getorientation(ScrArea *sa_a, ScrArea *sa_b)
{
if (sa_a == NULL || sa_b == NULL || sa_a == sa_b) {
@@ -329,9 +318,6 @@ eScreenDir area_getorientation(ScrArea *sa_a, ScrArea *sa_b)
return -1;
}
-/**
- * Get alignment offset of adjacent areas. 'dir' value is like #area_getorientation().
- */
void area_getoffsets(
ScrArea *sa_a, ScrArea *sa_b, const eScreenDir dir, int *r_offset1, int *r_offset2)
{
@@ -536,13 +522,11 @@ static bool screen_area_join_ex(
return true;
}
-/* Join any two neighboring areas. Might involve complex changes. */
int screen_area_join(bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2)
{
return screen_area_join_ex(C, screen, sa1, sa2, false);
}
-/* Close a screen area, allowing most-aligned neighbor to take its place. */
bool screen_area_close(struct bContext *C, bScreen *screen, ScrArea *area)
{
if (area == NULL) {
@@ -640,8 +624,6 @@ void ED_screen_do_listen(bContext *C, wmNotifier *note)
}
}
-/* make this screen usable */
-/* for file read and first use, for scaling window, area moves */
void ED_screen_refresh(wmWindowManager *wm, wmWindow *win)
{
bScreen *screen = WM_window_get_active_screen(win);
@@ -681,7 +663,6 @@ void ED_screen_refresh(wmWindowManager *wm, wmWindow *win)
screen->context = ed_screen_context;
}
-/* file read, set all screens, ... */
void ED_screens_init(Main *bmain, wmWindowManager *wm)
{
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
@@ -709,10 +690,6 @@ void ED_screen_ensure_updated(wmWindowManager *wm, wmWindow *win, bScreen *scree
}
}
-/**
- * Utility to exit and free an area-region. Screen level regions (menus/popups) need to be treated
- * slightly differently, see #ui_region_temp_remove().
- */
void ED_region_remove(bContext *C, ScrArea *area, ARegion *region)
{
ED_region_exit(C, region);
@@ -862,10 +839,6 @@ static void screen_cursor_set(wmWindow *win, const int xy[2])
}
}
-/**
- * Called in wm_event_system.c. sets state vars in screen, cursors.
- * event type is mouse move.
- */
void ED_screen_set_active_region(bContext *C, wmWindow *win, const int xy[2])
{
bScreen *screen = WM_window_get_active_screen(win);
@@ -955,7 +928,7 @@ void ED_screen_set_active_region(bContext *C, wmWindow *win, const int xy[2])
* because it can undo setting the right button as active due
* to delayed notifier handling. */
if (C) {
- UI_screen_free_active_but(C, screen);
+ UI_screen_free_active_but_highlight(C, screen);
}
}
}
@@ -1126,10 +1099,6 @@ void ED_screen_global_areas_refresh(wmWindow *win)
/* -------------------------------------------------------------------- */
/* Screen changing */
-/**
- * \return the screen to activate.
- * \warning The returned screen may not always equal \a screen_new!
- */
void screen_change_prepare(
bScreen *screen_old, bScreen *screen_new, Main *bmain, bContext *C, wmWindow *win)
{
@@ -1176,14 +1145,6 @@ void screen_change_update(bContext *C, wmWindow *win, bScreen *screen)
WM_event_add_mousemove(win);
}
-/**
- * \brief Change the active screen.
- *
- * Operator call, WM + Window + screen already existed before
- *
- * \warning Do NOT call in area/region queues!
- * \returns if screen changing was successful.
- */
bool ED_screen_change(bContext *C, bScreen *screen)
{
Main *bmain = CTX_data_main(C);
@@ -1324,9 +1285,6 @@ ScrArea *ED_screen_full_newspace(bContext *C, ScrArea *area, int type)
return newsa;
}
-/**
- * \a was_prev_temp for the case previous space was a temporary fullscreen as well
- */
void ED_screen_full_prevspace(bContext *C, ScrArea *area)
{
BLI_assert(area->full);
@@ -1356,7 +1314,6 @@ void ED_screen_restore_temp_type(bContext *C, ScrArea *area)
}
}
-/* restore a screen / area back to default operation, after temp fullscreen modes */
void ED_screen_full_restore(bContext *C, ScrArea *area)
{
wmWindow *win = CTX_wm_window(C);
@@ -1463,28 +1420,11 @@ static bScreen *screen_state_to_nonnormal(bContext *C,
return screen;
}
-/**
- * Create a new temporary screen with a maximized, empty area.
- * This can be closed with #ED_screen_state_toggle().
- *
- * Use this to just create a new maximized screen/area, rather than maximizing an existing one.
- * Otherwise, maximize with #ED_screen_state_toggle().
- */
bScreen *ED_screen_state_maximized_create(bContext *C)
{
return screen_state_to_nonnormal(C, CTX_wm_window(C), NULL, SCREENMAXIMIZED);
}
-/**
- * This function toggles: if area is maximized/full then the parent will be restored.
- *
- * Use #ED_screen_state_maximized_create() if you do not want the toggle behavior when changing to
- * a maximized area. I.e. if you just want to open a new maximized screen/area, not maximize a
- * specific area. In the former case, space data of the maximized and non-maximized area should be
- * independent, in the latter it should be the same.
- *
- * \warning \a area may be freed.
- */
ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *area, const short state)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -1495,8 +1435,7 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *area, const
* switching screens with tooltip open because region and tooltip
* are no longer in the same screen */
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
- UI_blocklist_free(C, &region->uiblocks);
-
+ UI_blocklist_free(C, region);
if (region->regiontimer) {
WM_event_remove_timer(wm, NULL, region->regiontimer);
region->regiontimer = NULL;
@@ -1593,14 +1532,6 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *area, const
return screen->areabase.first;
}
-/**
- * Wrapper to open a temporary space either as fullscreen space, or as separate window, as defined
- * by \a display_type.
- *
- * \param title: Title to set for the window, if a window is spawned.
- * \param x, y: Position of the window, if a window is spawned.
- * \param sizex, sizey: Dimensions of the window, if a window is spawned.
- */
ScrArea *ED_screen_temp_space_open(bContext *C,
const char *title,
int x,
@@ -1649,7 +1580,6 @@ ScrArea *ED_screen_temp_space_open(bContext *C,
return area;
}
-/* update frame rate info for viewport drawing */
void ED_refresh_viewport_fps(bContext *C)
{
wmTimer *animtimer = CTX_wm_screen(C)->animtimer;
@@ -1675,9 +1605,6 @@ void ED_refresh_viewport_fps(bContext *C)
}
}
-/* redraws: uses defines from stime->redraws
- * enable: 1 - forward on, -1 - backwards on, 0 - off
- */
void ED_screen_animation_timer(bContext *C, int redraws, int sync, int enable)
{
bScreen *screen = CTX_wm_screen(C);
@@ -1777,7 +1704,6 @@ void ED_screen_animation_timer_update(bScreen *screen, int redraws)
}
}
-/* results in fully updated anim system */
void ED_update_for_newframe(Main *bmain, Depsgraph *depsgraph)
{
Scene *scene = DEG_get_input_scene(depsgraph);
@@ -1802,9 +1728,6 @@ void ED_update_for_newframe(Main *bmain, Depsgraph *depsgraph)
BKE_scene_graph_update_for_newframe(depsgraph);
}
-/*
- * return true if any active area requires to see in 3D
- */
bool ED_screen_stereo3d_required(const bScreen *screen, const Scene *scene)
{
const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
@@ -1880,11 +1803,6 @@ bool ED_screen_stereo3d_required(const bScreen *screen, const Scene *scene)
return false;
}
-/**
- * Find the scene displayed in \a screen.
- * \note Assumes \a screen to be visible/active!
- */
-
Scene *ED_screen_scene_find_with_window(const bScreen *screen,
const wmWindowManager *wm,
struct wmWindow **r_window)
diff --git a/source/blender/editors/screen/screen_geometry.c b/source/blender/editors/screen/screen_geometry.c
index e67c933cb8e..394a7fd7350 100644
--- a/source/blender/editors/screen/screen_geometry.c
+++ b/source/blender/editors/screen/screen_geometry.c
@@ -83,10 +83,6 @@ bool screen_geom_edge_is_horizontal(ScrEdge *se)
return (se->v1->vec.y == se->v2->vec.y);
}
-/**
- * \param bounds_rect: Either window or screen bounds.
- * Used to exclude edges along window/screen edges.
- */
ScrEdge *screen_geom_area_map_find_active_scredge(const ScrAreaMap *area_map,
const rcti *bounds_rect,
const int mx,
@@ -124,7 +120,6 @@ ScrEdge *screen_geom_area_map_find_active_scredge(const ScrAreaMap *area_map,
return NULL;
}
-/* need win size to make sure not to include edges along screen edge */
ScrEdge *screen_geom_find_active_scredge(const wmWindow *win,
const bScreen *screen,
const int mx,
@@ -249,13 +244,6 @@ static bool screen_geom_vertices_scale_pass(const wmWindow *win,
return needs_another_pass;
}
-/**
- * \brief Main screen-layout calculation function.
- *
- * * Scale areas nicely on window size and DPI changes.
- * * Ensure areas have a minimum height.
- * * Correctly set global areas to their fixed height.
- */
void screen_geom_vertices_scale(const wmWindow *win, bScreen *screen)
{
rcti window_rect, screen_rect;
@@ -303,9 +291,6 @@ void screen_geom_vertices_scale(const wmWindow *win, bScreen *screen)
}
}
-/**
- * \return 0 if no split is possible, otherwise the screen-coordinate at which to split.
- */
short screen_geom_find_area_split_point(const ScrArea *area,
const rcti *window_rect,
const eScreenAxis dir_axis,
@@ -374,9 +359,6 @@ short screen_geom_find_area_split_point(const ScrArea *area,
return x;
}
-/**
- * Select all edges that are directly or indirectly connected to \a edge.
- */
void screen_geom_select_connected_edge(const wmWindow *win, ScrEdge *edge)
{
bScreen *screen = WM_window_get_active_screen(win);
diff --git a/source/blender/editors/screen/screen_intern.h b/source/blender/editors/screen/screen_intern.h
index 47229e5e2b5..bc06e46ba96 100644
--- a/source/blender/editors/screen/screen_intern.h
+++ b/source/blender/editors/screen/screen_intern.h
@@ -61,23 +61,48 @@ typedef enum eScreenAxis {
#define AREAJOINTOLERANCEX (AREAMINX * U.dpi_fac)
#define AREAJOINTOLERANCEY (HEADERY * U.dpi_fac)
-/* Expanded interaction influence of area borders. */
+/**
+ * Expanded interaction influence of area borders.
+ */
#define BORDERPADDING ((2.0f * U.dpi_fac) + U.pixelsize)
/* area.c */
+
+/**
+ * we swap spaces for fullscreen to keep all allocated data area vertices were set
+ */
void ED_area_data_copy(ScrArea *area_dst, ScrArea *area_src, const bool do_free);
void ED_area_data_swap(ScrArea *area_dst, ScrArea *area_src);
+/* for quick toggle, can skip fades */
void region_toggle_hidden(struct bContext *C, ARegion *region, const bool do_fade);
/* screen_draw.c */
+
+/**
+ * Visual indication of the two areas involved in a proposed join.
+ *
+ * \param sa1: Area from which the resultant originates.
+ * \param sa2: Target area that will be replaced.
+ */
void screen_draw_join_highlight(struct ScrArea *sa1, struct ScrArea *sa2);
void screen_draw_split_preview(struct ScrArea *area, const eScreenAxis dir_axis, const float fac);
/* screen_edit.c */
+
+/**
+ * Empty screen, with 1 dummy area without space-data. Uses window size.
+ */
bScreen *screen_add(struct Main *bmain, const char *name, const rcti *rect);
void screen_data_copy(bScreen *to, bScreen *from);
+/**
+ * Prepare a newly created screen for initializing it as active screen.
+ */
void screen_new_activate_prepare(const wmWindow *win, bScreen *screen_new);
void screen_change_update(struct bContext *C, wmWindow *win, bScreen *screen);
+/**
+ * \return the screen to activate.
+ * \warning The returned screen may not always equal \a screen_new!
+ */
void screen_change_prepare(bScreen *screen_old,
bScreen *screen_new,
struct Main *bmain,
@@ -89,10 +114,24 @@ ScrArea *area_split(const wmWindow *win,
const eScreenAxis dir_axis,
const float fac,
const bool merge);
+/**
+ * Join any two neighboring areas. Might involve complex changes.
+ */
int screen_area_join(struct bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2);
+/**
+ * with `sa_a` as center, `sa_b` is located at: 0=W, 1=N, 2=E, 3=S
+ * -1 = not valid check.
+ * used with join operator.
+ */
eScreenDir area_getorientation(ScrArea *sa_a, ScrArea *sa_b);
+/**
+ * Get alignment offset of adjacent areas. 'dir' value is like #area_getorientation().
+ */
void area_getoffsets(
ScrArea *sa_a, ScrArea *sa_b, const eScreenDir dir, int *r_offset1, int *r_offset2);
+/**
+ * Close a screen area, allowing most-aligned neighbor to take its place.
+ */
bool screen_area_close(struct bContext *C, bScreen *screen, ScrArea *area);
void screen_area_spacelink_add(struct Scene *scene, ScrArea *area, eSpace_Type space_type);
struct AZone *ED_area_actionzone_find_xy(ScrArea *area, const int xy[2]);
@@ -105,22 +144,46 @@ ScrVert *screen_geom_vertex_add(bScreen *screen, short x, short y);
ScrEdge *screen_geom_edge_add_ex(ScrAreaMap *area_map, ScrVert *v1, ScrVert *v2);
ScrEdge *screen_geom_edge_add(bScreen *screen, ScrVert *v1, ScrVert *v2);
bool screen_geom_edge_is_horizontal(ScrEdge *se);
+/**
+ * \param bounds_rect: Either window or screen bounds.
+ * Used to exclude edges along window/screen edges.
+ */
ScrEdge *screen_geom_area_map_find_active_scredge(const struct ScrAreaMap *area_map,
const rcti *bounds_rect,
const int mx,
const int my);
+/**
+ * Need win size to make sure not to include edges along screen edge.
+ */
ScrEdge *screen_geom_find_active_scredge(const wmWindow *win,
const bScreen *screen,
const int mx,
const int my);
+/**
+ * \brief Main screen-layout calculation function.
+ *
+ * * Scale areas nicely on window size and DPI changes.
+ * * Ensure areas have a minimum height.
+ * * Correctly set global areas to their fixed height.
+ */
void screen_geom_vertices_scale(const wmWindow *win, bScreen *screen);
+/**
+ * \return 0 if no split is possible, otherwise the screen-coordinate at which to split.
+ */
short screen_geom_find_area_split_point(const ScrArea *area,
const rcti *window_rect,
const eScreenAxis dir_axis,
float fac);
+/**
+ * Select all edges that are directly or indirectly connected to \a edge.
+ */
void screen_geom_select_connected_edge(const wmWindow *win, ScrEdge *edge);
/* screen_context.c */
+
+/**
+ * Entry point for the screen context.
+ */
int ed_screen_context(const struct bContext *C,
const char *member,
struct bContextDataResult *result);
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index 66140cba9c6..d017345b523 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -165,7 +165,6 @@ static bool ED_operator_screenactive_norender(bContext *C)
return true;
}
-/* when mouse is over area-edge */
bool ED_operator_screen_mainwinactive(bContext *C)
{
if (CTX_wm_window(C) == NULL) {
@@ -219,10 +218,6 @@ bool ED_operator_objectmode(bContext *C)
return true;
}
-/**
- * Same as #ED_operator_objectmode() but additionally sets a "disabled hint". That is, a message
- * to be displayed to the user explaining why the operator can't be used in current context.
- */
bool ED_operator_objectmode_poll_msg(bContext *C)
{
if (!ED_operator_objectmode(C)) {
@@ -257,7 +252,6 @@ bool ED_operator_region_view3d_active(bContext *C)
return false;
}
-/* generic for any view2d which uses anim_ops */
bool ED_operator_animview_active(bContext *C)
{
if (ED_operator_areaactive(C)) {
@@ -289,21 +283,11 @@ bool ED_operator_outliner_active_no_editobject(bContext *C)
return false;
}
-/**
- * \note Will return true for file spaces in either file or asset browsing mode! See
- * #ED_operator_file_browsing_active() (file browsing only) and
- * #ED_operator_asset_browsing_active() (asset browsing only).
- */
bool ED_operator_file_active(bContext *C)
{
return ed_spacetype_test(C, SPACE_FILE);
}
-/**
- * \note Will only return true if the file space is in file browsing mode, not asset browsing! See
- * #ED_operator_file_active() (file or asset browsing) and
- * #ED_operator_asset_browsing_active() (asset browsing only).
- */
bool ED_operator_file_browsing_active(bContext *C)
{
if (ed_spacetype_test(C, SPACE_FILE)) {
@@ -430,7 +414,6 @@ bool ED_operator_object_active_editable(bContext *C)
return ED_operator_object_active_editable_ex(C, ob);
}
-/** Object must be editable and fully local (i.e. not an override). */
bool ED_operator_object_active_local_editable_ex(bContext *C, const Object *ob)
{
return ED_operator_object_active_editable_ex(C, ob) && !ID_IS_OVERRIDE_LIBRARY(ob);
@@ -530,7 +513,6 @@ bool ED_operator_posemode_exclusive(bContext *C)
return ed_operator_posemode_exclusive_ex(C, obact);
}
-/** Object must be editable, fully local (i.e. not an override), and exclusively in Pose mode. */
bool ED_operator_object_active_local_editable_posemode_exclusive(bContext *C)
{
Object *obact = ED_object_active_context(C);
@@ -547,8 +529,6 @@ bool ED_operator_object_active_local_editable_posemode_exclusive(bContext *C)
return true;
}
-/* allows for pinned pose objects to be used in the object buttons
- * and the non-active pose object to be used in the 3D view */
bool ED_operator_posemode_context(bContext *C)
{
Object *obpose = ED_pose_object_from_context(C);
@@ -588,7 +568,6 @@ bool ED_operator_posemode_local(bContext *C)
return false;
}
-/* wrapper for ED_space_image_show_uvedit */
bool ED_operator_uvedit(bContext *C)
{
SpaceImage *sima = CTX_wm_space_image(C);
@@ -4426,6 +4405,7 @@ static void SCREEN_OT_region_context_menu(wmOperatorType *ot)
*
* Animation Step.
* \{ */
+
static bool screen_animation_region_supports_time_follow(eSpace_Type spacetype,
eRegion_Type regiontype)
{
@@ -4812,7 +4792,6 @@ static void SCREEN_OT_animation_step(wmOperatorType *ot)
* Animation Playback with Timer.
* \{ */
-/* find window that owns the animation timer */
bScreen *ED_screen_animation_playing(const wmWindowManager *wm)
{
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
@@ -4839,7 +4818,6 @@ bScreen *ED_screen_animation_no_scrub(const wmWindowManager *wm)
return NULL;
}
-/* toggle operator */
int ED_screen_animation_play(bContext *C, int sync, int mode)
{
bScreen *screen = CTX_wm_screen(C);
@@ -5391,9 +5369,6 @@ static void region_blend_end(bContext *C, ARegion *region, const bool is_running
WM_event_remove_timer(CTX_wm_manager(C), NULL, region->regiontimer); /* frees rgi */
region->regiontimer = NULL;
}
-/**
- * \note Assumes that \a region itself is not a split version from previous region.
- */
void ED_region_visibility_change_update_animated(bContext *C, ScrArea *area, ARegion *region)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -5701,7 +5676,6 @@ static void SCREEN_OT_workspace_cycle(wmOperatorType *ot)
/** \name Assigning Operator Types
* \{ */
-/* called in spacetypes.c */
void ED_operatortypes_screen(void)
{
/* Generic UI stuff. */
@@ -5778,7 +5752,7 @@ static void keymap_modal_set(wmKeyConfig *keyconf)
static bool blend_file_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
{
if (drag->type == WM_DRAG_PATH) {
- if (drag->icon == ICON_FILE_BLEND) {
+ if (ELEM(drag->icon, ICON_FILE_BLEND, ICON_BLENDER)) {
return true;
}
}
@@ -5791,7 +5765,6 @@ static void blend_file_drop_copy(wmDrag *drag, wmDropBox *drop)
RNA_string_set(drop->ptr, "filepath", drag->path);
}
-/* called in spacetypes.c */
void ED_keymap_screen(wmKeyConfig *keyconf)
{
/* Screen Editing ------------------------------------------------ */
diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c
index 5c4ba67d72a..b26291c4d1b 100644
--- a/source/blender/editors/screen/screendump.c
+++ b/source/blender/editors/screen/screendump.c
@@ -180,8 +180,9 @@ static int screenshot_invoke(bContext *C, wmOperator *op, const wmEvent *event)
/* extension is added by 'screenshot_check' after */
char filepath[FILE_MAX] = "//screen";
- if (G.relbase_valid) {
- BLI_strncpy(filepath, BKE_main_blendfile_path_from_global(), sizeof(filepath));
+ const char *blendfile_path = BKE_main_blendfile_path_from_global();
+ if (blendfile_path[0] != '\0') {
+ BLI_strncpy(filepath, blendfile_path, sizeof(filepath));
BLI_path_extension_replace(filepath, sizeof(filepath), ""); /* strip '.blend' */
}
RNA_string_set(op->ptr, "filepath", filepath);
diff --git a/source/blender/editors/screen/workspace_edit.c b/source/blender/editors/screen/workspace_edit.c
index 4b81e713080..125b345a1ed 100644
--- a/source/blender/editors/screen/workspace_edit.c
+++ b/source/blender/editors/screen/workspace_edit.c
@@ -112,15 +112,6 @@ static WorkSpaceLayout *workspace_change_get_new_layout(Main *bmain,
bmain, workspace_new, layout_new, layout_old, win);
}
-/**
- * \brief Change the active workspace.
- *
- * Operator call, WM + Window + screen already existed before
- * Pretty similar to #ED_screen_change since changing workspace also changes screen.
- *
- * \warning Do NOT call in area/region queues!
- * \returns if workspace changing was successful.
- */
bool ED_workspace_change(WorkSpace *workspace_new, bContext *C, wmWindowManager *wm, wmWindow *win)
{
Main *bmain = CTX_data_main(C);
@@ -160,10 +151,6 @@ bool ED_workspace_change(WorkSpace *workspace_new, bContext *C, wmWindowManager
return true;
}
-/**
- * Duplicate a workspace including its layouts. Does not activate the workspace, but
- * it stores the screen-layout to be activated (BKE_workspace_temp_layout_store)
- */
WorkSpace *ED_workspace_duplicate(WorkSpace *workspace_old, Main *bmain, wmWindow *win)
{
WorkSpaceLayout *layout_active_old = BKE_workspace_active_layout_get(win->workspace_hook);
@@ -187,9 +174,6 @@ WorkSpace *ED_workspace_duplicate(WorkSpace *workspace_old, Main *bmain, wmWindo
return workspace_new;
}
-/**
- * \return if succeeded.
- */
bool ED_workspace_delete(WorkSpace *workspace, Main *bmain, bContext *C, wmWindowManager *wm)
{
if (BLI_listbase_is_single(&bmain->workspaces)) {
@@ -220,10 +204,6 @@ bool ED_workspace_delete(WorkSpace *workspace, Main *bmain, bContext *C, wmWindo
return true;
}
-/**
- * Some editor data may need to be synced with scene data (3D View camera and layers).
- * This function ensures data is synced for editors in active layout of \a workspace.
- */
void ED_workspace_scene_data_sync(WorkSpaceInstanceHook *hook, Scene *scene)
{
bScreen *screen = BKE_workspace_active_screen_get(hook);
@@ -393,7 +373,7 @@ static void workspace_append_button(uiLayout *layout,
const Main *from_main)
{
const ID *id = (ID *)workspace;
- const char *filepath = from_main->name;
+ const char *filepath = from_main->filepath;
if (strlen(filepath) == 0) {
filepath = BLO_EMBEDDED_STARTUP_BLEND;
diff --git a/source/blender/editors/screen/workspace_layout_edit.c b/source/blender/editors/screen/workspace_layout_edit.c
index 0ec32da0404..e34c4f96aa3 100644
--- a/source/blender/editors/screen/workspace_layout_edit.c
+++ b/source/blender/editors/screen/workspace_layout_edit.c
@@ -37,9 +37,6 @@
#include "screen_intern.h"
-/**
- * Empty screen, with 1 dummy area without space-data. Uses window size.
- */
WorkSpaceLayout *ED_workspace_layout_add(Main *bmain,
WorkSpace *workspace,
wmWindow *win,
@@ -129,10 +126,6 @@ static WorkSpaceLayout *workspace_layout_delete_find_new(const WorkSpaceLayout *
return NULL;
}
-/**
- * \warning Only call outside of area/region loops!
- * \return true if succeeded.
- */
bool ED_workspace_layout_delete(WorkSpace *workspace, WorkSpaceLayout *layout_old, bContext *C)
{
const bScreen *screen_old = BKE_workspace_layout_screen_get(layout_old);
@@ -183,12 +176,6 @@ static bool screen_is_used_by_other_window(const wmWindow *win, const bScreen *s
return BKE_screen_is_used(screen) && (screen->winid != win->winid);
}
-/**
- * Make sure there is a non-fullscreen layout to switch to that is not used yet by an other window.
- * Needed for workspace or screen switching to ensure valid screens.
- *
- * \param layout_fallback_base: As last resort, this layout is duplicated and returned.
- */
WorkSpaceLayout *ED_workspace_screen_change_ensure_unused_layout(
Main *bmain,
WorkSpace *workspace,
diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt
index 3b668a1bd4c..b826ff8701d 100644
--- a/source/blender/editors/sculpt_paint/CMakeLists.txt
+++ b/source/blender/editors/sculpt_paint/CMakeLists.txt
@@ -44,6 +44,7 @@ set(SRC
paint_hide.c
paint_image.c
paint_image_2d.c
+ paint_image_2d_curve_mask.cc
paint_image_proj.c
paint_mask.c
paint_ops.c
diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c
index dafc7f45e2e..265746e27cd 100644
--- a/source/blender/editors/sculpt_paint/paint_cursor.c
+++ b/source/blender/editors/sculpt_paint/paint_cursor.c
@@ -98,7 +98,6 @@ static TexSnapshot primary_snap = {0};
static TexSnapshot secondary_snap = {0};
static CursorSnapshot cursor_snap = {0};
-/* Delete overlay cursor textures to preserve memory and invalidate all overlay flags. */
void paint_cursor_delete_textures(void)
{
if (primary_snap.overlay_texture) {
diff --git a/source/blender/editors/sculpt_paint/paint_curve_undo.c b/source/blender/editors/sculpt_paint/paint_curve_undo.c
index dbe522bf304..0b59e519f70 100644
--- a/source/blender/editors/sculpt_paint/paint_curve_undo.c
+++ b/source/blender/editors/sculpt_paint/paint_curve_undo.c
@@ -147,7 +147,6 @@ static void paintcurve_undosys_foreach_ID_ref(UndoStep *us_p,
foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->pc_ref));
}
-/* Export for ED_undo_sys. */
void ED_paintcurve_undosys_type(UndoType *ut)
{
ut->name = "Paint Curve";
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index 6ba5c43f698..dc2eaacca0c 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -87,7 +87,7 @@
* Maybe it should be exposed as part of the paint operation,
* but for now just give a public interface.
*/
-static ImagePaintPartialRedraw imapaintpartial = {0, 0, 0, 0, 0};
+static ImagePaintPartialRedraw imapaintpartial = {{0}};
ImagePaintPartialRedraw *get_imapaintpartial(void)
{
@@ -103,7 +103,7 @@ void set_imapaintpartial(struct ImagePaintPartialRedraw *ippr)
void ED_imapaint_clear_partial_redraw(void)
{
- memset(&imapaintpartial, 0, sizeof(imapaintpartial));
+ BLI_rcti_init_minmax(&imapaintpartial.dirty_region);
}
void imapaint_region_tiles(
@@ -132,19 +132,9 @@ void ED_imapaint_dirty_region(
return;
}
- if (!imapaintpartial.enabled) {
- imapaintpartial.x1 = x;
- imapaintpartial.y1 = y;
- imapaintpartial.x2 = x + w;
- imapaintpartial.y2 = y + h;
- imapaintpartial.enabled = 1;
- }
- else {
- imapaintpartial.x1 = min_ii(imapaintpartial.x1, x);
- imapaintpartial.y1 = min_ii(imapaintpartial.y1, y);
- imapaintpartial.x2 = max_ii(imapaintpartial.x2, x + w);
- imapaintpartial.y2 = max_ii(imapaintpartial.y2, y + h);
- }
+ rcti rect_to_merge;
+ BLI_rcti_init(&rect_to_merge, x, x + w, y, y + h);
+ BLI_rcti_do_minmax_rcti(&imapaintpartial.dirty_region, &rect_to_merge);
imapaint_region_tiles(ibuf, x, y, w, h, &tilex, &tiley, &tilew, &tileh);
@@ -167,27 +157,30 @@ void ED_imapaint_dirty_region(
void imapaint_image_update(
SpaceImage *sima, Image *image, ImBuf *ibuf, ImageUser *iuser, short texpaint)
{
- if (imapaintpartial.x1 != imapaintpartial.x2 && imapaintpartial.y1 != imapaintpartial.y2) {
- IMB_partial_display_buffer_update_delayed(
- ibuf, imapaintpartial.x1, imapaintpartial.y1, imapaintpartial.x2, imapaintpartial.y2);
+ if (BLI_rcti_is_empty(&imapaintpartial.dirty_region)) {
+ return;
}
if (ibuf->mipmap[0]) {
ibuf->userflags |= IB_MIPMAP_INVALID;
}
+ IMB_partial_display_buffer_update_delayed(ibuf,
+ imapaintpartial.dirty_region.xmin,
+ imapaintpartial.dirty_region.ymin,
+ imapaintpartial.dirty_region.xmax,
+ imapaintpartial.dirty_region.ymax);
+
/* TODO: should set_tpage create ->rect? */
if (texpaint || (sima && sima->lock)) {
- int w = imapaintpartial.x2 - imapaintpartial.x1;
- int h = imapaintpartial.y2 - imapaintpartial.y1;
- if (w && h) {
- /* Testing with partial update in uv editor too */
- BKE_image_update_gputexture(image, iuser, imapaintpartial.x1, imapaintpartial.y1, w, h);
- }
+ const int w = BLI_rcti_size_x(&imapaintpartial.dirty_region);
+ const int h = BLI_rcti_size_y(&imapaintpartial.dirty_region);
+ /* Testing with partial update in uv editor too */
+ BKE_image_update_gputexture(
+ image, iuser, imapaintpartial.dirty_region.xmin, imapaintpartial.dirty_region.ymin, w, h);
}
}
-/* paint blur kernels. Projective painting enforces use of a 2x2 kernel due to lagging */
BlurKernel *paint_new_blur_kernel(Brush *br, bool proj)
{
int i, j;
@@ -799,11 +792,6 @@ static void toggle_paint_cursor(Scene *scene, bool enable)
}
}
-/* enable the paint cursor if it isn't already.
- *
- * purpose is to make sure the paint cursor is shown if paint
- * mode is enabled in the image editor. the paint poll will
- * ensure that the cursor is hidden when not in paint mode */
void ED_space_image_paint_update(Main *bmain, wmWindowManager *wm, Scene *scene)
{
ToolSettings *settings = scene->toolsettings;
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c
index 318180e5eb4..4c54d3b3b5e 100644
--- a/source/blender/editors/sculpt_paint/paint_image_2d.c
+++ b/source/blender/editors/sculpt_paint/paint_image_2d.c
@@ -78,12 +78,13 @@ typedef struct BrushPainterCache {
ImBuf *ibuf;
ImBuf *texibuf;
- ushort *curve_mask;
ushort *tex_mask;
ushort *tex_mask_old;
uint tex_mask_old_w;
uint tex_mask_old_h;
+ CurveMaskCache curve_mask_cache;
+
int image_size[2];
} BrushPainterCache;
@@ -169,9 +170,6 @@ static void brush_painter_2d_require_imbuf(
if (cache->ibuf) {
IMB_freeImBuf(cache->ibuf);
}
- if (cache->curve_mask) {
- MEM_freeN(cache->curve_mask);
- }
if (cache->tex_mask) {
MEM_freeN(cache->tex_mask);
}
@@ -179,7 +177,6 @@ static void brush_painter_2d_require_imbuf(
MEM_freeN(cache->tex_mask_old);
}
cache->ibuf = NULL;
- cache->curve_mask = NULL;
cache->tex_mask = NULL;
cache->lastdiameter = -1; /* force ibuf create in refresh */
cache->invert = invert;
@@ -200,9 +197,7 @@ static void brush_painter_cache_2d_free(BrushPainterCache *cache)
if (cache->texibuf) {
IMB_freeImBuf(cache->texibuf);
}
- if (cache->curve_mask) {
- MEM_freeN(cache->curve_mask);
- }
+ paint_curve_mask_cache_free_data(&cache->curve_mask_cache);
if (cache->tex_mask) {
MEM_freeN(cache->tex_mask);
}
@@ -380,92 +375,6 @@ static void brush_painter_mask_imbuf_partial_update(BrushPainter *painter,
cache->tex_mask_old_h = diameter;
}
-/* create a mask with the falloff strength */
-static ushort *brush_painter_curve_mask_init(
- ushort *mask, BrushPainter *painter, int diameter, float radius, const float pos[2])
-{
- BLI_assert_msg(MEM_allocN_len(mask) == diameter * diameter * sizeof(ushort),
- "Allocated size of mask doesn't match.");
-
- Brush *brush = painter->brush;
-
- int offset = (int)floorf(diameter / 2.0f);
-
- ushort *m;
- m = mask;
-
- int aa_samples = 1.0f / (radius * 0.20f);
- if (brush->sampling_flag & BRUSH_PAINT_ANTIALIASING) {
- aa_samples = clamp_i(aa_samples, 3, 16);
- }
- else {
- aa_samples = 1;
- }
-
- /* Temporal until we have the brush properties */
- const float hardness = 1.0f;
- const float rotation = 0.0f;
-
- float aa_offset = 1.0f / (2.0f * (float)aa_samples);
- float aa_step = 1.0f / (float)aa_samples;
-
- float bpos[2];
- bpos[0] = pos[0] - floorf(pos[0]) + offset - aa_offset;
- bpos[1] = pos[1] - floorf(pos[1]) + offset - aa_offset;
-
- const float co = cosf(DEG2RADF(rotation));
- const float si = sinf(DEG2RADF(rotation));
-
- float norm_factor = 65535.0f / (float)(aa_samples * aa_samples);
-
- for (int y = 0; y < diameter; y++) {
- for (int x = 0; x < diameter; x++, m++) {
- float total_samples = 0;
- for (int i = 0; i < aa_samples; i++) {
- for (int j = 0; j < aa_samples; j++) {
- float pixel_xy[2] = {x + (aa_step * i), y + (aa_step * j)};
- float xy_rot[2];
- sub_v2_v2(pixel_xy, bpos);
-
- xy_rot[0] = co * pixel_xy[0] - si * pixel_xy[1];
- xy_rot[1] = si * pixel_xy[0] + co * pixel_xy[1];
-
- float len = len_v2(xy_rot);
- float p = len / radius;
- if (hardness < 1.0f) {
- p = (p - hardness) / (1.0f - hardness);
- p = 1.0f - p;
- CLAMP(p, 0.0f, 1.0f);
- }
- else {
- p = 1.0;
- }
- float hardness_factor = 3.0f * p * p - 2.0f * p * p * p;
- float curve = BKE_brush_curve_strength_clamped(brush, len, radius);
- total_samples += curve * hardness_factor;
- }
- }
- *m = (ushort)(total_samples * norm_factor);
- }
- }
-
- return mask;
-}
-
-static void brush_painter_curve_mask_refresh(
- BrushPainter *painter, ImagePaintTile *tile, int diameter, float radius, const float pos[2])
-{
- BrushPainterCache *cache = &tile->cache;
-
- if (diameter != cache->lastdiameter) {
- if (cache->curve_mask != NULL) {
- MEM_freeN(cache->curve_mask);
- }
- cache->curve_mask = MEM_mallocN(sizeof(ushort) * diameter * diameter, "brush_painter_mask");
- }
- brush_painter_curve_mask_init(cache->curve_mask, painter, diameter, radius, pos);
-}
-
/* create imbuf with brush color */
static ImBuf *brush_painter_imbuf_new(
BrushPainter *painter, ImagePaintTile *tile, const int size, float pressure, float distance)
@@ -872,7 +781,7 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s,
}
/* Re-initialize the curve mask. Mask is always recreated due to the change of position. */
- brush_painter_curve_mask_refresh(painter, tile, diameter, size, pos);
+ paint_curve_mask_cache_update(&cache->curve_mask_cache, brush, diameter, size, pos);
/* detect if we need to recreate image brush buffer */
if (diameter != cache->lastdiameter || (tex_rotation != cache->last_tex_rotation) || do_random ||
@@ -1336,7 +1245,7 @@ static void paint_2d_do_making_brush(ImagePaintState *s,
&tmpbuf,
frombuf,
mask,
- tile->cache.curve_mask,
+ tile->cache.curve_mask_cache.curve_mask,
tile->cache.tex_mask,
mask_max,
region->destx,
@@ -1485,7 +1394,7 @@ static int paint_2d_op(void *state,
canvas,
frombuf,
NULL,
- tile->cache.curve_mask,
+ tile->cache.curve_mask_cache.curve_mask,
tile->cache.tex_mask,
mask_max,
region[a].destx,
@@ -1868,7 +1777,6 @@ static ImageUser *paint_2d_get_tile_iuser(ImagePaintState *s, int tile_number)
return iuser;
}
-/* this function expects linear space color values */
void paint_2d_bucket_fill(const bContext *C,
const float color[3],
Brush *br,
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d_curve_mask.cc b/source/blender/editors/sculpt_paint/paint_image_2d_curve_mask.cc
new file mode 100644
index 00000000000..8d57a3d9152
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/paint_image_2d_curve_mask.cc
@@ -0,0 +1,188 @@
+/*
+ * 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 ed
+ */
+
+#include "BLI_math.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_brush_types.h"
+
+#include "BKE_brush.h"
+
+#include "paint_intern.h"
+
+namespace blender::ed::sculpt_paint {
+
+constexpr int AntiAliasingSamplesPerTexelAxisMin = 3;
+constexpr int AntiAliasingSamplesPerTexelAxisMax = 16;
+/**
+ * \brief Number of samples to use between 0..1.
+ */
+constexpr int CurveSamplesBaseLen = 1024;
+/**
+ * \brief Number of samples to store in the cache.
+ *
+ * M_SQRT2 is used as brushes are circles and the curve_mask is square.
+ * + 1 to fix floating rounding issues.
+ */
+constexpr int CurveSamplesLen = M_SQRT2 * CurveSamplesBaseLen + 1;
+
+static int aa_samples_per_texel_axis(const Brush *brush, const float radius)
+{
+ int aa_samples = 1.0f / (radius * 0.20f);
+ if (brush->sampling_flag & BRUSH_PAINT_ANTIALIASING) {
+ aa_samples = clamp_i(
+ aa_samples, AntiAliasingSamplesPerTexelAxisMin, AntiAliasingSamplesPerTexelAxisMax);
+ }
+ else {
+ aa_samples = 1;
+ }
+ return aa_samples;
+}
+
+/* create a mask with the falloff strength */
+static void update_curve_mask(CurveMaskCache *curve_mask_cache,
+ const Brush *brush,
+ const int diameter,
+ const float radius,
+ const float cursor_position[2])
+{
+ BLI_assert(curve_mask_cache->curve_mask != nullptr);
+ int offset = (int)floorf(diameter / 2.0f);
+
+ unsigned short *m = curve_mask_cache->curve_mask;
+
+ const int aa_samples = aa_samples_per_texel_axis(brush, radius);
+ const float aa_offset = 1.0f / (2.0f * (float)aa_samples);
+ const float aa_step = 1.0f / (float)aa_samples;
+
+ float bpos[2];
+ bpos[0] = cursor_position[0] - floorf(cursor_position[0]) + offset;
+ bpos[1] = cursor_position[1] - floorf(cursor_position[1]) + offset;
+
+ float weight_factor = 65535.0f / (float)(aa_samples * aa_samples);
+
+ for (int y = 0; y < diameter; y++) {
+ for (int x = 0; x < diameter; x++, m++) {
+ float pixel_xy[2];
+ pixel_xy[0] = static_cast<float>(x) + aa_offset;
+ float total_weight = 0;
+
+ for (int i = 0; i < aa_samples; i++) {
+ pixel_xy[1] = static_cast<float>(y) + aa_offset;
+ for (int j = 0; j < aa_samples; j++) {
+ const float len = len_v2v2(pixel_xy, bpos);
+ const int sample_index = min_ii((len / radius) * CurveSamplesBaseLen,
+ CurveSamplesLen - 1);
+ const float sample_weight = curve_mask_cache->sampled_curve[sample_index];
+
+ total_weight += sample_weight;
+
+ pixel_xy[1] += aa_step;
+ }
+ pixel_xy[0] += aa_step;
+ }
+ *m = (unsigned short)(total_weight * weight_factor);
+ }
+ }
+}
+
+static bool is_sampled_curve_valid(const CurveMaskCache *curve_mask_cache, const Brush *brush)
+{
+ if (curve_mask_cache->sampled_curve == nullptr) {
+ return false;
+ }
+ return curve_mask_cache->last_curve_timestamp == brush->curve->changed_timestamp;
+}
+
+static void sampled_curve_free(CurveMaskCache *curve_mask_cache)
+{
+ MEM_SAFE_FREE(curve_mask_cache->sampled_curve);
+ curve_mask_cache->last_curve_timestamp = 0;
+}
+
+static void update_sampled_curve(CurveMaskCache *curve_mask_cache, const Brush *brush)
+{
+ if (curve_mask_cache->sampled_curve == nullptr) {
+ curve_mask_cache->sampled_curve = static_cast<float *>(
+ MEM_mallocN(CurveSamplesLen * sizeof(float), __func__));
+ }
+
+ for (int i = 0; i < CurveSamplesLen; i++) {
+ const float len = i / float(CurveSamplesBaseLen);
+ const float sample_weight = BKE_brush_curve_strength_clamped(brush, len, 1.0f);
+ curve_mask_cache->sampled_curve[i] = sample_weight;
+ }
+ curve_mask_cache->last_curve_timestamp = brush->curve->changed_timestamp;
+}
+
+static size_t diameter_to_curve_mask_size(const int diameter)
+{
+ return diameter * diameter * sizeof(ushort);
+}
+
+static bool is_curve_mask_size_valid(const CurveMaskCache *curve_mask_cache, const int diameter)
+{
+ return curve_mask_cache->curve_mask_size == diameter_to_curve_mask_size(diameter);
+}
+
+static void curve_mask_free(CurveMaskCache *curve_mask_cache)
+{
+ curve_mask_cache->curve_mask_size = 0;
+ MEM_SAFE_FREE(curve_mask_cache->curve_mask);
+}
+
+static void curve_mask_allocate(CurveMaskCache *curve_mask_cache, const int diameter)
+{
+ const size_t curve_mask_size = diameter_to_curve_mask_size(diameter);
+ curve_mask_cache->curve_mask = static_cast<unsigned short *>(
+ MEM_mallocN(curve_mask_size, __func__));
+ curve_mask_cache->curve_mask_size = curve_mask_size;
+}
+
+} // namespace blender::ed::sculpt_paint
+
+using namespace blender::ed::sculpt_paint;
+
+void paint_curve_mask_cache_free_data(CurveMaskCache *curve_mask_cache)
+{
+ sampled_curve_free(curve_mask_cache);
+ curve_mask_free(curve_mask_cache);
+}
+
+void paint_curve_mask_cache_update(CurveMaskCache *curve_mask_cache,
+ const Brush *brush,
+ const int diameter,
+ const float radius,
+ const float cursor_position[2])
+{
+ if (!is_sampled_curve_valid(curve_mask_cache, brush)) {
+ update_sampled_curve(curve_mask_cache, brush);
+ }
+
+ if (!is_curve_mask_size_valid(curve_mask_cache, diameter)) {
+ curve_mask_free(curve_mask_cache);
+ curve_mask_allocate(curve_mask_cache, diameter);
+ }
+ update_curve_mask(curve_mask_cache, brush, diameter, radius, cursor_position);
+}
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index db3e69b0953..7df5848e068 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -4134,8 +4134,9 @@ static bool project_paint_clone_face_skip(ProjPaintState *ps,
if (ps->do_material_slots) {
if (lc->slot_clone != lc->slot_last_clone) {
- if (!slot->uvname || !(lc->mloopuv_clone_base = CustomData_get_layer_named(
- &ps->me_eval->ldata, CD_MLOOPUV, lc->slot_clone->uvname))) {
+ if (!lc->slot_clone->uvname ||
+ !(lc->mloopuv_clone_base = CustomData_get_layer_named(
+ &ps->me_eval->ldata, CD_MLOOPUV, lc->slot_clone->uvname))) {
lc->mloopuv_clone_base = CustomData_get_layer(&ps->me_eval->ldata, CD_MLOOPUV);
}
lc->slot_last_clone = lc->slot_clone;
@@ -4648,13 +4649,7 @@ static void project_paint_end(ProjPaintState *ps)
/* 1 = an undo, -1 is a redo. */
static void partial_redraw_single_init(ImagePaintPartialRedraw *pr)
{
- pr->x1 = INT_MAX;
- pr->y1 = INT_MAX;
-
- pr->x2 = -1;
- pr->y2 = -1;
-
- pr->enabled = 1;
+ BLI_rcti_init_minmax(&pr->dirty_region);
}
static void partial_redraw_array_init(ImagePaintPartialRedraw *pr)
@@ -4670,16 +4665,11 @@ static bool partial_redraw_array_merge(ImagePaintPartialRedraw *pr,
ImagePaintPartialRedraw *pr_other,
int tot)
{
- bool touch = 0;
+ bool touch = false;
while (tot--) {
- pr->x1 = min_ii(pr->x1, pr_other->x1);
- pr->y1 = min_ii(pr->y1, pr_other->y1);
-
- pr->x2 = max_ii(pr->x2, pr_other->x2);
- pr->y2 = max_ii(pr->y2, pr_other->y2);
-
- if (pr->x2 != -1) {
- touch = 1;
+ BLI_rcti_do_minmax_rcti(&pr->dirty_region, &pr_other->dirty_region);
+ if (!BLI_rcti_is_empty(&pr->dirty_region)) {
+ touch = true;
}
pr++;
@@ -4702,7 +4692,7 @@ static bool project_image_refresh_tagged(ProjPaintState *ps)
/* look over each bound cell */
for (i = 0; i < PROJ_BOUNDBOX_SQUARED; i++) {
pr = &(projIma->partRedrawRect[i]);
- if (pr->x2 != -1) { /* TODO: use 'enabled' ? */
+ if (BLI_rcti_is_valid(&pr->dirty_region)) {
set_imapaintpartial(pr);
imapaint_image_update(NULL, projIma->ima, projIma->ibuf, &projIma->iuser, true);
redraw = 1;
@@ -5116,11 +5106,10 @@ static void do_projectpaint_mask_f(ProjPaintState *ps, ProjPixel *projPixel, flo
static void image_paint_partial_redraw_expand(ImagePaintPartialRedraw *cell,
const ProjPixel *projPixel)
{
- cell->x1 = min_ii(cell->x1, (int)projPixel->x_px);
- cell->y1 = min_ii(cell->y1, (int)projPixel->y_px);
-
- cell->x2 = max_ii(cell->x2, (int)projPixel->x_px + 1);
- cell->y2 = max_ii(cell->y2, (int)projPixel->y_px + 1);
+ rcti rect_to_add;
+ BLI_rcti_init(
+ &rect_to_add, projPixel->x_px, projPixel->x_px + 1, projPixel->y_px, projPixel->y_px + 1);
+ BLI_rcti_do_minmax_rcti(&cell->dirty_region, &rect_to_add);
}
static void copy_original_alpha_channel(ProjPixel *pixel, bool is_floatbuf)
@@ -6335,8 +6324,6 @@ void ED_paint_data_warning(struct ReportList *reports, bool uvs, bool mat, bool
!stencil ? " Stencil," : "");
}
-/* Make sure that active object has a material,
- * and assign UVs and image layers if they do not exist */
bool ED_paint_proj_mesh_data_check(
Scene *scene, Object *ob, bool *uvs, bool *mat, bool *tex, bool *stencil)
{
diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h
index 7341d984c91..90887b9fc39 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -23,6 +23,16 @@
#pragma once
+#include "BKE_paint.h"
+
+#include "BLI_rect.h"
+
+#include "DNA_scene_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct ARegion;
struct Brush;
struct ColorManagedDisplay;
@@ -38,13 +48,10 @@ struct Scene;
struct VPaint;
struct ViewContext;
struct bContext;
-struct rcti;
struct wmEvent;
struct wmKeyConfig;
struct wmOperator;
struct wmOperatorType;
-enum ePaintMode;
-enum ePaintSymmetryFlags;
typedef struct CoNo {
float co[3];
@@ -52,6 +59,7 @@ typedef struct CoNo {
} CoNo;
/* paint_stroke.c */
+
typedef bool (*StrokeGetLocation)(struct bContext *C, float location[3], const float mouse[2]);
typedef bool (*StrokeTestStart)(struct bContext *C, struct wmOperator *op, const float mouse[2]);
typedef void (*StrokeUpdateStep)(struct bContext *C,
@@ -70,13 +78,25 @@ struct PaintStroke *paint_stroke_new(struct bContext *C,
int event_type);
void paint_stroke_free(struct bContext *C, struct wmOperator *op);
+/**
+ * Returns zero if the stroke dots should not be spaced, non-zero otherwise.
+ */
bool paint_space_stroke_enabled(struct Brush *br, enum ePaintMode mode);
+/**
+ * Return true if the brush size can change during paint (normally used for pressure).
+ */
bool paint_supports_dynamic_size(struct Brush *br, enum ePaintMode mode);
+/**
+ * Return true if the brush size can change during paint (normally used for pressure).
+ */
bool paint_supports_dynamic_tex_coords(struct Brush *br, enum ePaintMode mode);
bool paint_supports_smooth_stroke(struct Brush *br, enum ePaintMode mode);
bool paint_supports_texture(enum ePaintMode mode);
bool paint_supports_jitter(enum ePaintMode mode);
+/**
+ * Called in paint_ops.c, on each regeneration of key-maps.
+ */
struct wmKeyMap *paint_stroke_modal_keymap(struct wmKeyConfig *keyconf);
int paint_stroke_modal(struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
int paint_stroke_exec(struct bContext *C, struct wmOperator *op);
@@ -89,14 +109,21 @@ float paint_stroke_distance_get(struct PaintStroke *stroke);
void paint_stroke_set_mode_data(struct PaintStroke *stroke, void *mode_data);
bool PAINT_brush_tool_poll(struct bContext *C);
void paint_cursor_start(struct Paint *p, bool (*poll)(struct bContext *C));
+/**
+ * Delete overlay cursor textures to preserve memory and invalidate all overlay flags.
+ */
void paint_cursor_delete_textures(void);
/* paint_vertex.c */
+
bool weight_paint_poll(struct bContext *C);
bool weight_paint_poll_ignore_tool(bContext *C);
bool weight_paint_mode_poll(struct bContext *C);
bool vertex_paint_poll(struct bContext *C);
bool vertex_paint_poll_ignore_tool(struct bContext *C);
+/**
+ * Returns true if vertex paint mode is active.
+ */
bool vertex_paint_mode_poll(struct bContext *C);
typedef void (*VPaintTransform_Callback)(const float col[3],
@@ -119,15 +146,31 @@ void PAINT_OT_vertex_paint(struct wmOperatorType *ot);
unsigned int vpaint_get_current_col(struct Scene *scene, struct VPaint *vp, bool secondary);
/* paint_vertex_color_utils.c */
+
+/**
+ * \note weight-paint has an equivalent function: #ED_wpaint_blend_tool
+ */
unsigned int ED_vpaint_blend_tool(const int tool,
const uint col,
const uint paintcol,
const int alpha_i);
+/**
+ * Apply callback to each vertex of the active vertex color layer.
+ */
bool ED_vpaint_color_transform(struct Object *ob,
VPaintTransform_Callback vpaint_tx_fn,
const void *user_data);
/* paint_vertex_weight_utils.c */
+
+/**
+ * \param weight: Typically the current weight: #MDeformWeight.weight
+ *
+ * \return The final weight, note that this is _not_ clamped from [0-1].
+ * Clamping must be done on the final #MDeformWeight.weight
+ *
+ * \note vertex-paint has an equivalent function: #ED_vpaint_blend_tool
+ */
float ED_wpaint_blend_tool(const int tool,
const float weight,
const float paintval,
@@ -140,13 +183,18 @@ struct WPaintVGroupIndex {
int active;
int mirror;
};
+/**
+ * Ensure we have data on wpaint start, add if needed.
+ */
bool ED_wpaint_ensure_data(struct bContext *C,
struct ReportList *reports,
enum eWPaintFlag flag,
struct WPaintVGroupIndex *vgroup_index);
+/** Return -1 when invalid. */
int ED_wpaint_mirror_vgroup_ensure(struct Object *ob, const int vgroup_active);
/* paint_vertex_color_ops.c */
+
void PAINT_OT_vertex_color_set(struct wmOperatorType *ot);
void PAINT_OT_vertex_color_from_weight(struct wmOperatorType *ot);
void PAINT_OT_vertex_color_smooth(struct wmOperatorType *ot);
@@ -156,6 +204,7 @@ void PAINT_OT_vertex_color_invert(struct wmOperatorType *ot);
void PAINT_OT_vertex_color_levels(struct wmOperatorType *ot);
/* paint_vertex_weight_ops.c */
+
void PAINT_OT_weight_from_bones(struct wmOperatorType *ot);
void PAINT_OT_weight_sample(struct wmOperatorType *ot);
void PAINT_OT_weight_sample_group(struct wmOperatorType *ot);
@@ -175,8 +224,7 @@ void ED_vpaint_proj_handle_free(struct VertProjHandle *vp_handle);
/* paint_image.c */
typedef struct ImagePaintPartialRedraw {
- int x1, y1, x2, y2; /* XXX, could use 'rcti' */
- int enabled;
+ rcti dirty_region;
} ImagePaintPartialRedraw;
bool image_texture_paint_poll(struct bContext *C);
@@ -200,6 +248,9 @@ void paint_2d_stroke(void *ps,
float pressure,
float distance,
float size);
+/**
+ * This function expects linear space color values.
+ */
void paint_2d_bucket_fill(const struct bContext *C,
const float color[3],
struct Brush *br,
@@ -245,14 +296,56 @@ void PAINT_OT_add_texture_paint_slot(struct wmOperatorType *ot);
void PAINT_OT_image_paint(struct wmOperatorType *ot);
void PAINT_OT_add_simple_uvs(struct wmOperatorType *ot);
+/* paint_image_2d_curve_mask.cc */
+/**
+ * \brief Caching structure for curve mask.
+ *
+ * When 2d painting images the curve mask is used as an input.
+ */
+typedef struct CurveMaskCache {
+ /**
+ * \brief Last #CurveMapping.changed_timestamp being read.
+ *
+ * When different the input cache needs to be recalculated.
+ */
+ int last_curve_timestamp;
+
+ /**
+ * \brief sampled version of the brush curve-mapping.
+ */
+ float *sampled_curve;
+
+ /**
+ * \brief Size in bytes of the curve_mask field.
+ *
+ * Used to determine if the curve_mask needs to be re-allocated.
+ */
+ size_t curve_mask_size;
+
+ /**
+ * \brief Curve mask that can be passed as curve_mask parameter when.
+ */
+ ushort *curve_mask;
+} CurveMaskCache;
+
+void paint_curve_mask_cache_free_data(CurveMaskCache *curve_mask_cache);
+void paint_curve_mask_cache_update(CurveMaskCache *curve_mask_cache,
+ const struct Brush *brush,
+ const int diameter,
+ const float radius,
+ const float cursor_position[2]);
+
/* sculpt_uv.c */
+
void SCULPT_OT_uv_sculpt_stroke(struct wmOperatorType *ot);
/* paint_utils.c */
-/* Convert the object-space axis-aligned bounding box (expressed as
+/**
+ * Convert the object-space axis-aligned bounding box (expressed as
* its minimum and maximum corners) into a screen-space rectangle,
- * returns zero if the result is empty */
+ * returns zero if the result is empty.
+ */
bool paint_convert_bb_to_rect(struct rcti *rect,
const float bb_min[3],
const float bb_max[3],
@@ -260,9 +353,11 @@ bool paint_convert_bb_to_rect(struct rcti *rect,
struct RegionView3D *rv3d,
struct Object *ob);
-/* Get four planes in object-space that describe the projection of
+/**
+ * Get four planes in object-space that describe the projection of
* screen_rect from screen into object-space (essentially converting a
- * 2D screens-space bounding box into four 3D planes) */
+ * 2D screens-space bounding box into four 3D planes).
+ */
void paint_calc_redraw_planes(float planes[4][4],
const struct ARegion *region,
struct Object *ob,
@@ -282,6 +377,9 @@ void paint_get_tex_pixel_col(const struct MTex *mtex,
bool convert,
struct ColorSpace *colorspace);
+/**
+ * Used for both 3D view and image window.
+ */
void paint_sample_color(
struct bContext *C, struct ARegion *region, int x, int y, bool texpaint_proj, bool palette);
@@ -303,6 +401,9 @@ bool mask_paint_poll(struct bContext *C);
bool paint_curve_poll(struct bContext *C);
bool facemask_paint_poll(struct bContext *C);
+/**
+ * Uses symm to selectively flip any axis of a coordinate.
+ */
void flip_v3_v3(float out[3], const float in[3], const enum ePaintSymmetryFlags symm);
void flip_qt_qt(float out[4], const float in[4], const enum ePaintSymmetryFlags symm);
@@ -360,9 +461,16 @@ typedef struct {
} BlurKernel;
enum eBlurKernelType;
-/* can be extended to other blur kernels later */
+/**
+ * Paint blur kernels. Projective painting enforces use of a 2x2 kernel due to lagging.
+ * Can be extended to other blur kernels later,
+ */
BlurKernel *paint_new_blur_kernel(struct Brush *br, bool proj);
void paint_delete_blur_kernel(BlurKernel *);
/* paint curve defines */
#define PAINT_CURVE_NUM_SEGMENTS 40
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index de01bc3a474..c87f4e0aeec 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -1007,7 +1007,6 @@ static void stroke_done(bContext *C, wmOperator *op)
paint_stroke_free(C, op);
}
-/* Returns zero if the stroke dots should not be spaced, non-zero otherwise */
bool paint_space_stroke_enabled(Brush *br, ePaintMode mode)
{
if ((br->flag & BRUSH_SPACE) == 0) {
@@ -1041,7 +1040,6 @@ static bool sculpt_is_grab_tool(Brush *br)
SCULPT_TOOL_SNAKE_HOOK);
}
-/* return true if the brush size can change during paint (normally used for pressure) */
bool paint_supports_dynamic_size(Brush *br, ePaintMode mode)
{
if (br->flag & BRUSH_ANCHORED) {
@@ -1094,7 +1092,6 @@ bool paint_supports_texture(ePaintMode mode)
mode, PAINT_MODE_SCULPT, PAINT_MODE_VERTEX, PAINT_MODE_TEXTURE_3D, PAINT_MODE_TEXTURE_2D);
}
-/* return true if the brush size can change during paint (normally used for pressure) */
bool paint_supports_dynamic_tex_coords(Brush *br, ePaintMode mode)
{
if (br->flag & BRUSH_ANCHORED) {
@@ -1115,7 +1112,6 @@ bool paint_supports_dynamic_tex_coords(Brush *br, ePaintMode mode)
#define PAINT_STROKE_MODAL_CANCEL 1
-/* Called in paint_ops.c, on each regeneration of key-maps. */
struct wmKeyMap *paint_stroke_modal_keymap(struct wmKeyConfig *keyconf)
{
static struct EnumPropertyItem modal_items[] = {
diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c
index 709e04d807d..541893f7957 100644
--- a/source/blender/editors/sculpt_paint/paint_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_utils.c
@@ -80,9 +80,6 @@
#include "paint_intern.h"
-/* Convert the object-space axis-aligned bounding box (expressed as
- * its minimum and maximum corners) into a screen-space rectangle,
- * returns zero if the result is empty */
bool paint_convert_bb_to_rect(rcti *rect,
const float bb_min[3],
const float bb_max[3],
@@ -127,9 +124,6 @@ bool paint_convert_bb_to_rect(rcti *rect,
return rect->xmin < rect->xmax && rect->ymin < rect->ymax;
}
-/* Get four planes in object-space that describe the projection of
- * screen_rect from screen into object-space (essentially converting a
- * 2D screens-space bounding box into four 3D planes) */
void paint_calc_redraw_planes(float planes[4][4],
const ARegion *region,
Object *ob,
@@ -403,7 +397,6 @@ static Image *imapaint_face_image(Object *ob, Mesh *me, int face_index)
return ima;
}
-/* Uses symm to selectively flip any axis of a coordinate. */
void flip_v3_v3(float out[3], const float in[3], const ePaintSymmetryFlags symm)
{
if (symm & PAINT_SYMM_X) {
@@ -449,7 +442,6 @@ void flip_qt_qt(float out[4], const float in[4], const ePaintSymmetryFlags symm)
axis_angle_normalized_to_quat(out, axis, angle);
}
-/* used for both 3d view and image window */
void paint_sample_color(
bContext *C, ARegion *region, int x, int y, bool texpaint_proj, bool use_palette)
{
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index fede01a614b..23e03f3e576 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -199,9 +199,6 @@ static void paint_last_stroke_update(Scene *scene, const float location[3])
ups->last_stroke_valid = true;
}
-/* polling - retrieve whether cursor should be set or operator should be done */
-
-/* Returns true if vertex paint mode is active */
bool vertex_paint_mode_poll(bContext *C)
{
Object *ob = CTX_data_active_object(C);
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c b/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c
index dbc6044d2d8..a083af14c89 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c
@@ -41,9 +41,6 @@
#define EPS_SATURATION 0.0005f
-/**
- * Apply callback to each vertex of the active vertex color layer.
- */
bool ED_vpaint_color_transform(struct Object *ob,
VPaintTransform_Callback vpaint_tx_fn,
const void *user_data)
@@ -610,9 +607,6 @@ BLI_INLINE uint mcol_alpha_sub(uint col_src, int fac)
return col_mix;
}
-/**
- * \note weight-paint has an equivalent function: #ED_wpaint_blend_tool
- */
uint ED_vpaint_blend_tool(const int tool, const uint col, const uint paintcol, const int alpha_i)
{
switch ((IMB_BlendMode)tool) {
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
index 1077f66f10c..d10a56be866 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
@@ -408,10 +408,11 @@ static int weight_sample_group_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-/* TODO: we could make this a menu into OBJECT_OT_vertex_group_set_active
- * rather than its own operator */
void PAINT_OT_weight_sample_group(wmOperatorType *ot)
{
+ /* TODO: we could make this a menu into #OBJECT_OT_vertex_group_set_active
+ * rather than its own operator */
+
PropertyRNA *prop = NULL;
/* identifiers */
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c b/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c
index 19ffa0c952d..34a27d5a5c2 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c
@@ -51,7 +51,6 @@
/** \name Weight Paint Sanity Checks
* \{ */
-/* ensure we have data on wpaint start, add if needed */
bool ED_wpaint_ensure_data(bContext *C,
struct ReportList *reports,
enum eWPaintFlag flag,
@@ -131,9 +130,9 @@ bool ED_wpaint_ensure_data(bContext *C,
return true;
}
+
/** \} */
-/* mirror_vgroup is set to -1 when invalid */
int ED_wpaint_mirror_vgroup_ensure(Object *ob, const int vgroup_active)
{
const ListBase *defbase = BKE_object_defgroup_list(ob);
@@ -277,14 +276,6 @@ BLI_INLINE float wval_exclusion(float weight, float paintval, float fac)
return temp * fac + weight * mfac;
}
-/**
- * \param weight: Typically the current weight: #MDeformWeight.weight
- *
- * \return The final weight, note that this is _not_ clamped from [0-1].
- * Clamping must be done on the final #MDeformWeight.weight
- *
- * \note vertex-paint has an equivalent function: #ED_vpaint_blend_tool
- */
float ED_wpaint_blend_tool(const int tool,
const float weight,
const float paintval,
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 7b854e886a0..b764d0e1b5b 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -102,13 +102,15 @@
#include <stdlib.h>
#include <string.h>
-/* Sculpt PBVH abstraction API
+/* -------------------------------------------------------------------- */
+/** \name Sculpt PBVH Abstraction API
*
* This is read-only, for writing use PBVH vertex iterators. There vd.index matches
* the indices used here.
*
* For multi-resolution, the same vertex in multiple grids is counted multiple times, with
- * different index for each grid. */
+ * different index for each grid.
+ * \{ */
void SCULPT_vertex_random_access_ensure(SculptSession *ss)
{
@@ -911,32 +913,18 @@ bool SCULPT_vertex_is_boundary(const SculptSession *ss, const int index)
/* Utilities */
-/**
- * Returns true when the step belongs to the stroke that is directly performed by the brush and
- * not by one of the symmetry passes.
- */
bool SCULPT_stroke_is_main_symmetry_pass(StrokeCache *cache)
{
return cache->mirror_symmetry_pass == 0 && cache->radial_symmetry_pass == 0 &&
cache->tile_pass == 0;
}
-/**
- * Return true only once per stroke on the first symmetry pass, regardless of the symmetry passes
- * enabled.
- *
- * This should be used for functionality that needs to be computed once per stroke of a particular
- * tool (allocating memory, updating random seeds...).
- */
bool SCULPT_stroke_is_first_brush_step(StrokeCache *cache)
{
return cache->first_time && cache->mirror_symmetry_pass == 0 &&
cache->radial_symmetry_pass == 0 && cache->tile_pass == 0;
}
-/**
- * Returns true on the first brush step of each symmetry pass.
- */
bool SCULPT_stroke_is_first_brush_step_of_symmetry_pass(StrokeCache *cache)
{
return cache->first_time;
@@ -1049,7 +1037,6 @@ bool SCULPT_is_symmetry_iteration_valid(char i, char symm)
return i == 0 || (symm & i && (symm != 5 || i != 3) && (symm != 6 || (!ELEM(i, 3, 5))));
}
-/* Checks if a vertex is inside the brush radius from any of its mirrored axis. */
bool SCULPT_is_vertex_inside_brush_radius_symm(const float vertex[3],
const float br_co[3],
float radius,
@@ -1083,9 +1070,13 @@ void SCULPT_tag_update_overlays(bContext *C)
}
}
-/* Sculpt Flood Fill API
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Flood Fill API
*
- * Iterate over connected vertices, starting from one or more initial vertices. */
+ * Iterate over connected vertices, starting from one or more initial vertices.
+ * \{ */
void SCULPT_floodfill_init(SculptSession *ss, SculptFloodFill *flood)
{
@@ -1196,12 +1187,13 @@ void SCULPT_floodfill_free(SculptFloodFill *flood)
flood->queue = NULL;
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Tool Capabilities
*
* Avoid duplicate checks, internal logic only,
* share logic with #rna_def_sculpt_capabilities where possible.
- *
* \{ */
static bool sculpt_tool_needs_original(const char sculpt_tool)
@@ -1261,23 +1253,24 @@ static int sculpt_brush_needs_normal(const SculptSession *ss, const Brush *brush
(brush->mtex.brush_map_mode == MTEX_MAP_MODE_AREA)) ||
sculpt_brush_use_topology_rake(ss, brush);
}
-/** \} */
static bool sculpt_brush_needs_rake_rotation(const Brush *brush)
{
return SCULPT_TOOL_HAS_RAKE(brush->sculpt_tool) && (brush->rake_factor != 0.0f);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Init/Update
+ * \{ */
+
typedef enum StrokeFlags {
CLIP_X = 1,
CLIP_Y = 2,
CLIP_Z = 4,
} StrokeFlags;
-/**
- * Initialize a #SculptOrigVertData for accessing original vertex data;
- * handles #BMesh, #Mesh, and multi-resolution.
- */
void SCULPT_orig_vert_data_unode_init(SculptOrigVertData *data, Object *ob, SculptUndoNode *unode)
{
SculptSession *ss = ob->sculpt;
@@ -1297,10 +1290,6 @@ void SCULPT_orig_vert_data_unode_init(SculptOrigVertData *data, Object *ob, Scul
}
}
-/**
- * Initialize a #SculptOrigVertData for accessing original vertex data;
- * handles #BMesh, #Mesh, and multi-resolution.
- */
void SCULPT_orig_vert_data_init(SculptOrigVertData *data, Object *ob, PBVHNode *node)
{
SculptUndoNode *unode;
@@ -1308,9 +1297,6 @@ void SCULPT_orig_vert_data_init(SculptOrigVertData *data, Object *ob, PBVHNode *
SCULPT_orig_vert_data_unode_init(data, ob, unode);
}
-/**
- * Update a #SculptOrigVertData for a particular vertex from the PBVH iterator.
- */
void SCULPT_orig_vert_data_update(SculptOrigVertData *orig_data, PBVHVertexIter *iter)
{
if (orig_data->unode->type == SCULPT_UNDO_COORDS) {
@@ -1400,11 +1386,12 @@ static void sculpt_project_v3_normal_align(SculptSession *ss,
grab_delta, ss->cache->sculpt_normal_symm, (len_signed * normal_weight) * len_view_scale);
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name SculptProjectVector
*
* Fast-path for #project_plane_v3_v3v3
- *
* \{ */
typedef struct SculptProjectVector {
@@ -1441,14 +1428,10 @@ static void sculpt_project_v3(const SculptProjectVector *spvc, const float vec[3
/** \} */
-/**********************************************************************/
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Dynamic Topology
+ * \{ */
-/* Returns true if the stroke will use dynamic topology, false
- * otherwise.
- *
- * Factors: some brushes like grab cannot do dynamic topology.
- * Others, like smooth, are better without.
- * Same goes for alt-key smoothing. */
bool SCULPT_stroke_is_dynamic_topology(const SculptSession *ss, const Brush *brush)
{
return ((BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) &&
@@ -1462,7 +1445,11 @@ bool SCULPT_stroke_is_dynamic_topology(const SculptSession *ss, const Brush *bru
SCULPT_TOOL_HAS_DYNTOPO(brush->sculpt_tool));
}
-/*** paint mesh ***/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Paint Mesh
+ * \{ */
static void paint_mesh_restore_co_task_cb(void *__restrict userdata,
const int n,
@@ -1573,7 +1560,6 @@ static void sculpt_extend_redraw_rect_previous(Object *ob, rcti *rect)
BLI_rcti_union(rect, &ss->cache->previous_r);
}
-/* Get a screen-space rectangle of the modified area. */
bool SCULPT_get_redraw_rect(ARegion *region, RegionView3D *rv3d, Object *ob, rcti *rect)
{
PBVH *pbvh = ob->sculpt->pbvh;
@@ -1918,6 +1904,8 @@ static float calc_symmetry_feather(Sculpt *sd, StrokeCache *cache)
return 1.0f / overlap;
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Calculate Normal and Center
*
@@ -2205,7 +2193,6 @@ void SCULPT_calc_area_normal(
SCULPT_pbvh_calc_area_normal(brush, ob, nodes, totnode, true, r_area_no);
}
-/* Expose 'calc_area_normal' externally. */
bool SCULPT_pbvh_calc_area_normal(const Brush *brush,
Object *ob,
PBVHNode **nodes,
@@ -2247,8 +2234,10 @@ bool SCULPT_pbvh_calc_area_normal(const Brush *brush,
return data.any_vertex_sampled;
}
-/* This calculates flatten center and area normal together,
- * amortizing the memory bandwidth and loop overhead to calculate both at the same time. */
+/**
+ * This calculates flatten center and area normal together,
+ * amortizing the memory bandwidth and loop overhead to calculate both at the same time.
+ */
static void calc_area_normal_and_center(
Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3], float r_area_co[3])
{
@@ -2308,6 +2297,10 @@ static void calc_area_normal_and_center(
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Generic Brush Utilities
+ * \{ */
+
/**
* Return modified brush strength. Includes the direction of the brush, positive
* values pull vertices, negative values push. Uses tablet pressure and a
@@ -2463,7 +2456,6 @@ static float brush_strength(const Sculpt *sd,
}
}
-/* Return a multiplier for brush strength on a particular vertex. */
float SCULPT_brush_strength_factor(SculptSession *ss,
const Brush *br,
const float brush_point[3],
@@ -2561,7 +2553,6 @@ float SCULPT_brush_strength_factor(SculptSession *ss,
return avg;
}
-/* Test AABB against sphere. */
bool SCULPT_search_sphere_cb(PBVHNode *node, void *data_v)
{
SculptSearchSphereData *data = data_v;
@@ -2608,7 +2599,6 @@ bool SCULPT_search_sphere_cb(PBVHNode *node, void *data_v)
return len_squared_v3(t) < data->radius_squared;
}
-/* 2D projection (distance to line). */
bool SCULPT_search_circle_cb(PBVHNode *node, void *data_v)
{
SculptSearchCircleData *data = data_v;
@@ -2636,9 +2626,6 @@ bool SCULPT_search_circle_cb(PBVHNode *node, void *data_v)
return dist_sq < data->radius_squared || true;
}
-/**
- * Handles clipping against a mirror modifier and #SCULPT_LOCK_X/Y/Z axis flags.
- */
void SCULPT_clip(Sculpt *sd, SculptSession *ss, float co[3], const float val[3])
{
for (int i = 0; i < 3; i++) {
@@ -2867,6 +2854,12 @@ static void update_brush_local_mat(Sculpt *sd, Object *ob)
}
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Topology Rake (Shared Utility)
+ * \{ */
+
typedef struct {
SculptSession *ss;
const float *ray_start;
@@ -2979,6 +2972,12 @@ static void bmesh_topology_rake(
}
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Mask Brush
+ * \{ */
+
static void do_mask_brush_draw_task_cb_ex(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict tls)
@@ -3050,6 +3049,8 @@ static void do_mask_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
}
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Sculpt Multires Displacement Eraser Brush
* \{ */
@@ -3118,6 +3119,7 @@ static void do_displacement_eraser_brush(Sculpt *sd, Object *ob, PBVHNode **node
/** \} */
+/* -------------------------------------------------------------------- */
/** \name Sculpt Multires Displacement Smear Brush
* \{ */
@@ -3260,6 +3262,10 @@ static void do_displacement_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Draw Brush
+ * \{ */
+
static void do_draw_brush_task_cb_ex(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict tls)
@@ -3414,6 +3420,8 @@ static void do_draw_sharp_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to
BLI_task_parallel_range(0, totnode, &data, do_draw_sharp_brush_task_cb_ex, &settings);
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Sculpt Topology Brush
* \{ */
@@ -3738,6 +3746,10 @@ static void calc_sculpt_plane(
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Crease & Blob Brush
+ * \{ */
+
/**
* Used for 'SCULPT_TOOL_CREASE' and 'SCULPT_TOOL_BLOB'
*/
@@ -4974,6 +4986,8 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
BLI_task_parallel_range(0, totnode, &data, do_flatten_brush_task_cb_ex, &settings);
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Sculpt Clay Brush
* \{ */
@@ -5506,6 +5520,8 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
BLI_task_parallel_range(0, totnode, &data, do_scrape_brush_task_cb_ex, &settings);
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Sculpt Clay Thumb Brush
* \{ */
@@ -5680,6 +5696,10 @@ static void do_clay_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Gravity Brush
+ * \{ */
+
static void do_gravity_task_cb_ex(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict tls)
@@ -5750,6 +5770,12 @@ static void do_gravity(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, fl
BLI_task_parallel_range(0, totnode, &data, do_gravity_task_cb_ex, &settings);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Brush Utilities
+ * \{ */
+
void SCULPT_vertcos_to_key(Object *ob, KeyBlock *kb, const float (*vertCos)[3])
{
Mesh *me = (Mesh *)ob->data;
@@ -5954,8 +5980,8 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
}
}
- /* Initialize automasking cache. For anchored brushes with spherical falloff, we start off with
- * zero radius, thus we have no pbvh nodes on the first brush step. */
+ /* Initialize auto-masking cache. For anchored brushes with spherical falloff,
+ * we start off with zero radius, thus we have no PBVH nodes on the first brush step. */
if (totnode ||
((brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) && (brush->flag & BRUSH_ANCHORED))) {
if (SCULPT_stroke_is_first_brush_step(ss->cache)) {
@@ -6318,7 +6344,6 @@ static void SCULPT_flush_stroke_deform_task_cb(void *__restrict userdata,
BKE_pbvh_vertex_iter_end;
}
-/* Flush displacement from deformed PBVH to original layer. */
void SCULPT_flush_stroke_deform(Sculpt *sd, Object *ob, bool is_proxy_used)
{
SculptSession *ss = ob->sculpt;
@@ -6372,10 +6397,6 @@ void SCULPT_flush_stroke_deform(Sculpt *sd, Object *ob, bool is_proxy_used)
}
}
-/**
- * Flip all the edit-data across the axis/axes specified by \a symm.
- * Used to calculate multiple modifications to the mesh when symmetry is enabled.
- */
void SCULPT_cache_calc_brushdata_symm(StrokeCache *cache,
const char symm,
const char axis,
@@ -7416,9 +7437,6 @@ float SCULPT_raycast_init(ViewContext *vc,
return dist;
}
-/* Gets the normal, location and active vertex location of the geometry under the cursor. This also
- * updates the active vertex and cursor related data of the SculptSession using the mouse position
- */
bool SCULPT_cursor_geometry_info_update(bContext *C,
SculptCursorGeometryInfo *out,
const float mouse[2],
@@ -7548,9 +7566,6 @@ bool SCULPT_cursor_geometry_info_update(bContext *C,
return true;
}
-/* Do a raycast in the tree to find the 3d brush location
- * (This allows us to ignore the GL depth buffer)
- * Returns 0 if the ray doesn't hit the mesh, non-zero otherwise. */
bool SCULPT_stroke_get_location(bContext *C, float out[3], const float mouse[2])
{
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
@@ -7714,7 +7729,6 @@ static void sculpt_restore_mesh(Sculpt *sd, Object *ob)
}
}
-/* Copy the PBVH bounding box into the object's bounding box. */
void SCULPT_update_object_bounding_box(Object *ob)
{
if (ob->runtime.bb) {
@@ -9398,6 +9412,12 @@ static void SCULPT_OT_mask_by_color(wmOperatorType *ot)
1.0f);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Operator Registration
+ * \{ */
+
void ED_operatortypes_sculpt(void)
{
WM_operatortype_append(SCULPT_OT_brush_stroke);
@@ -9436,3 +9456,5 @@ void ED_operatortypes_sculpt(void)
WM_operatortype_append(SCULPT_OT_expand);
}
+
+/** \} */
diff --git a/source/blender/editors/sculpt_paint/sculpt_boundary.c b/source/blender/editors/sculpt_paint/sculpt_boundary.c
index 37678ec276a..e238fafb063 100644
--- a/source/blender/editors/sculpt_paint/sculpt_boundary.c
+++ b/source/blender/editors/sculpt_paint/sculpt_boundary.c
@@ -487,8 +487,6 @@ static void sculpt_boundary_falloff_factor_init(SculptSession *ss,
}
}
-/* Main function to get SculptBoundary data both for brush deformation and viewport preview. Can
- * return NULL if there is no boundary from the given vertex using the given radius. */
SculptBoundary *SCULPT_boundary_data_init(Object *object,
Brush *brush,
const int initial_vertex,
@@ -946,7 +944,6 @@ static void do_boundary_brush_smooth_task_cb_ex(void *__restrict userdata,
BKE_pbvh_vertex_iter_end;
}
-/* Main Brush Function. */
void SCULPT_do_boundary_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
SculptSession *ss = ob->sculpt;
diff --git a/source/blender/editors/sculpt_paint/sculpt_cloth.c b/source/blender/editors/sculpt_paint/sculpt_cloth.c
index fa879214794..dcfd7f7bcdc 100644
--- a/source/blender/editors/sculpt_paint/sculpt_cloth.c
+++ b/source/blender/editors/sculpt_paint/sculpt_cloth.c
@@ -1052,7 +1052,6 @@ static void cloth_sim_initialize_default_node_state(SculptSession *ss,
MEM_SAFE_FREE(nodes);
}
-/* Public functions. */
SculptClothSimulation *SCULPT_cloth_brush_simulation_create(SculptSession *ss,
const float cloth_mass,
const float cloth_damping,
@@ -1195,7 +1194,6 @@ static void sculpt_cloth_ensure_constraints_in_simulation_area(Sculpt *sd,
sd, ob, nodes, totnode, ss->cache->cloth_sim, sim_location, limit);
}
-/* Main Brush Function. */
void SCULPT_do_cloth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
SculptSession *ss = ob->sculpt;
@@ -1271,7 +1269,6 @@ void SCULPT_cloth_simulation_free(struct SculptClothSimulation *cloth_sim)
MEM_SAFE_FREE(cloth_sim);
}
-/* Cursor drawing function. */
void SCULPT_cloth_simulation_limits_draw(const uint gpuattr,
const Brush *brush,
const float location[3],
diff --git a/source/blender/editors/sculpt_paint/sculpt_detail.c b/source/blender/editors/sculpt_paint/sculpt_detail.c
index edbb98b481e..9082408b8dd 100644
--- a/source/blender/editors/sculpt_paint/sculpt_detail.c
+++ b/source/blender/editors/sculpt_paint/sculpt_detail.c
@@ -57,6 +57,10 @@
#include <math.h>
#include <stdlib.h>
+/* -------------------------------------------------------------------- */
+/** \name Internal Utilities
+ * \{ */
+
typedef struct {
const float *ray_start;
bool hit;
@@ -82,6 +86,12 @@ static bool sculpt_and_dynamic_topology_poll(bContext *C)
return SCULPT_mode_poll(C) && ob->sculpt->bm;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Detail Flood Fill
+ * \{ */
+
static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op))
{
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
@@ -147,6 +157,12 @@ void SCULPT_OT_detail_flood_fill(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sample Detail Size
+ * \{ */
+
typedef enum eSculptSampleDetailModeTypes {
SAMPLE_DETAIL_DYNTOPO = 0,
SAMPLE_DETAIL_VOXEL = 1,
@@ -364,13 +380,17 @@ void SCULPT_OT_sample_detail_size(wmOperatorType *ot)
"Target sculpting workflow that is going to use the sampled size");
}
-/* Dynamic-topology detail size.
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Dynamic-topology detail size
*
* Currently, there are two operators editing the detail size:
- * - SCULPT_OT_set_detail_size uses radial control for all methods
- * - SCULPT_OT_dyntopo_detail_size_edit shows a triangle grid representation of the detail
- * resolution (for constant detail method, falls back to radial control for the remaining methods).
- */
+ * - #SCULPT_OT_set_detail_size uses radial control for all methods
+ * - #SCULPT_OT_dyntopo_detail_size_edit shows a triangle grid representation of the detail
+ * resolution (for constant detail method,
+ * falls back to radial control for the remaining methods).
+ * \{ */
static void set_brush_rc_props(PointerRNA *ptr, const char *prop)
{
@@ -429,6 +449,8 @@ void SCULPT_OT_set_detail_size(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Dyntopo Detail Size Edit Operator
* \{ */
@@ -759,3 +781,5 @@ void SCULPT_OT_dyntopo_detail_size_edit(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+
+/** \} */
diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.c b/source/blender/editors/sculpt_paint/sculpt_face_set.c
index 89e07081802..dc8cda964ea 100644
--- a/source/blender/editors/sculpt_paint/sculpt_face_set.c
+++ b/source/blender/editors/sculpt_paint/sculpt_face_set.c
@@ -73,6 +73,7 @@
#include <stdlib.h>
/* Utils. */
+
int ED_sculpt_face_sets_find_next_available_id(struct Mesh *mesh)
{
int *face_sets = CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS);
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
index 760cf632ae9..ff1a8935ba0 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
@@ -64,7 +64,6 @@
#include <math.h>
#include <stdlib.h>
-/* Filter orientation utils. */
void SCULPT_filter_to_orientation_space(float r_v[3], struct FilterCache *filter_cache)
{
switch (filter_cache->orientation) {
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index 16df1efd969..4dd2a786922 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -46,7 +46,9 @@ enum ePaintSymmetryFlags;
bool SCULPT_mode_poll(struct bContext *C);
bool SCULPT_mode_poll_view3d(struct bContext *C);
-/* checks for a brush, not just sculpt mode */
+/**
+ * Checks for a brush, not just sculpt mode.
+ */
bool SCULPT_poll(struct bContext *C);
bool SCULPT_poll_view3d(struct bContext *C);
@@ -63,9 +65,14 @@ typedef enum SculptUpdateType {
void SCULPT_flush_update_step(bContext *C, SculptUpdateType update_flags);
void SCULPT_flush_update_done(const bContext *C, Object *ob, SculptUpdateType update_flags);
+/**
+ * Flush displacement from deformed PBVH to original layer.
+ */
void SCULPT_flush_stroke_deform(struct Sculpt *sd, Object *ob, bool is_proxy_used);
-/* Should be used after modifying the mask or Face Sets IDs. */
+/**
+ * Should be used after modifying the mask or Face Sets IDs.
+ */
void SCULPT_tag_update_overlays(bContext *C);
/* Stroke */
@@ -76,7 +83,16 @@ typedef struct SculptCursorGeometryInfo {
float active_vertex_co[3];
} SculptCursorGeometryInfo;
+/**
+ * Do a ray-cast in the tree to find the 3d brush location
+ * (This allows us to ignore the GL depth buffer)
+ * Returns 0 if the ray doesn't hit the mesh, non-zero otherwise.
+ */
bool SCULPT_stroke_get_location(struct bContext *C, float out[3], const float mouse[2]);
+/**
+ * Gets the normal, location and active vertex location of the geometry under the cursor. This also
+ * updates the active vertex and cursor related data of the SculptSession using the mouse position
+ */
bool SCULPT_cursor_geometry_info_update(bContext *C,
SculptCursorGeometryInfo *out,
const float mouse[2],
@@ -95,6 +111,7 @@ float SCULPT_raycast_init(struct ViewContext *vc,
char SCULPT_mesh_symmetry_xyz_get(Object *object);
/* Sculpt PBVH abstraction API */
+
void SCULPT_vertex_random_access_ensure(struct SculptSession *ss);
int SCULPT_vertex_count_get(struct SculptSession *ss);
@@ -106,15 +123,21 @@ const float *SCULPT_vertex_color_get(SculptSession *ss, int index);
const float *SCULPT_vertex_persistent_co_get(SculptSession *ss, int index);
void SCULPT_vertex_persistent_normal_get(SculptSession *ss, int index, float no[3]);
-/* Coordinates used for manipulating the base mesh when Grab Active Vertex is enabled. */
+/**
+ * Coordinates used for manipulating the base mesh when Grab Active Vertex is enabled.
+ */
const float *SCULPT_vertex_co_for_grab_active_get(SculptSession *ss, int index);
-/* Returns the info of the limit surface when Multires is available, otherwise it returns the
- * current coordinate of the vertex. */
+/**
+ * Returns the info of the limit surface when multi-res is available,
+ * otherwise it returns the current coordinate of the vertex.
+ */
void SCULPT_vertex_limit_surface_get(SculptSession *ss, int index, float r_co[3]);
-/* Returns the pointer to the coordinates that should be edited from a brush tool iterator
- * depending on the given deformation target. */
+/**
+ * Returns the pointer to the coordinates that should be edited from a brush tool iterator
+ * depending on the given deformation target.
+ */
float *SCULPT_brush_deform_target_vertex_co_get(SculptSession *ss,
const int deform_target,
PBVHVertexIter *iter);
@@ -215,8 +238,22 @@ bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, int index);
void SCULPT_face_sets_visibility_invert(SculptSession *ss);
void SCULPT_face_sets_visibility_all_set(SculptSession *ss, bool visible);
+/**
+ * Returns true when the step belongs to the stroke that is directly performed by the brush and
+ * not by one of the symmetry passes.
+ */
bool SCULPT_stroke_is_main_symmetry_pass(struct StrokeCache *cache);
+/**
+ * Return true only once per stroke on the first symmetry pass, regardless of the symmetry passes
+ * enabled.
+ *
+ * This should be used for functionality that needs to be computed once per stroke of a particular
+ * tool (allocating memory, updating random seeds...).
+ */
bool SCULPT_stroke_is_first_brush_step(struct StrokeCache *cache);
+/**
+ * Returns true on the first brush step of each symmetry pass.
+ */
bool SCULPT_stroke_is_first_brush_step_of_symmetry_pass(struct StrokeCache *cache);
/* Sculpt Original Data */
@@ -236,8 +273,19 @@ typedef struct {
const float *col;
} SculptOrigVertData;
+/**
+ * Initialize a #SculptOrigVertData for accessing original vertex data;
+ * handles #BMesh, #Mesh, and multi-resolution.
+ */
void SCULPT_orig_vert_data_init(SculptOrigVertData *data, Object *ob, PBVHNode *node);
+/**
+ * Update a #SculptOrigVertData for a particular vertex from the PBVH iterator.
+ */
void SCULPT_orig_vert_data_update(SculptOrigVertData *orig_data, PBVHVertexIter *iter);
+/**
+ * Initialize a #SculptOrigVertData for accessing original vertex data;
+ * handles #BMesh, #Mesh, and multi-resolution.
+ */
void SCULPT_orig_vert_data_unode_init(SculptOrigVertData *data,
Object *ob,
struct SculptUndoNode *unode);
@@ -263,12 +311,18 @@ int SCULPT_plane_point_side(const float co[3], const float plane[4]);
int SCULPT_plane_trim(const struct StrokeCache *cache,
const struct Brush *brush,
const float val[3]);
+/**
+ * Handles clipping against a mirror modifier and #SCULPT_LOCK_X/Y/Z axis flags.
+ */
void SCULPT_clip(Sculpt *sd, SculptSession *ss, float co[3], const float val[3]);
float SCULPT_brush_plane_offset_get(Sculpt *sd, SculptSession *ss);
ePaintSymmetryAreas SCULPT_get_vertex_symm_area(const float co[3]);
bool SCULPT_check_vertex_pivot_symmetry(const float vco[3], const float pco[3], const char symm);
+/**
+ * Checks if a vertex is inside the brush radius from any of its mirrored axis.
+ */
bool SCULPT_is_vertex_inside_brush_radius_symm(const float vertex[3],
const float br_co[3],
float radius,
@@ -329,6 +383,14 @@ void sculpt_dynamic_topology_disable_with_undo(struct Main *bmain,
Scene *scene,
Object *ob);
+/**
+ * Returns true if the stroke will use dynamic topology, false
+ * otherwise.
+ *
+ * Factors: some brushes like grab cannot do dynamic topology.
+ * Others, like smooth, are better without.
+ * Same goes for alt-key smoothing.
+ */
bool SCULPT_stroke_is_dynamic_topology(const SculptSession *ss, const Brush *brush);
void SCULPT_dynamic_topology_triangulate(struct BMesh *bm);
@@ -391,6 +453,10 @@ void SCULPT_mask_filter_smooth_apply(
/* Brushes. */
/* Cloth Brush. */
+
+/**
+ * Main Brush Function.
+ */
void SCULPT_do_cloth_brush(struct Sculpt *sd,
struct Object *ob,
struct PBVHNode **nodes,
@@ -398,6 +464,8 @@ void SCULPT_do_cloth_brush(struct Sculpt *sd,
void SCULPT_cloth_simulation_free(struct SculptClothSimulation *cloth_sim);
+/* Public functions. */
+
struct SculptClothSimulation *SCULPT_cloth_brush_simulation_create(
struct SculptSession *ss,
const float cloth_mass,
@@ -429,6 +497,9 @@ void SCULPT_cloth_brush_ensure_nodes_constraints(struct Sculpt *sd,
float initial_location[3],
const float radius);
+/**
+ * Cursor drawing function.
+ */
void SCULPT_cloth_simulation_limits_draw(const uint gpuattr,
const struct Brush *brush,
const float location[3],
@@ -490,10 +561,21 @@ BLI_INLINE bool SCULPT_tool_needs_all_pbvh_nodes(const Brush *brush)
}
/* Pose Brush. */
+
+/**
+ * Main Brush Function.
+ */
void SCULPT_do_pose_brush(struct Sculpt *sd,
struct Object *ob,
struct PBVHNode **nodes,
int totnode);
+/**
+ * Calculate the pose origin and (Optionally the pose factor)
+ * that is used when using the pose brush.
+ *
+ * \param r_pose_origin: Must be a valid pointer.
+ * \param r_pose_factor: Optional, when set to NULL it won't be calculated.
+ */
void SCULPT_pose_calc_pose_data(struct Sculpt *sd,
struct Object *ob,
struct SculptSession *ss,
@@ -515,11 +597,17 @@ struct SculptPoseIKChain *SCULPT_pose_ik_chain_init(struct Sculpt *sd,
void SCULPT_pose_ik_chain_free(struct SculptPoseIKChain *ik_chain);
/* Boundary Brush. */
+
+/**
+ * Main function to get #SculptBoundary data both for brush deformation and viewport preview.
+ * Can return NULL if there is no boundary from the given vertex using the given radius.
+ */
struct SculptBoundary *SCULPT_boundary_data_init(Object *object,
Brush *brush,
const int initial_vertex,
const float radius);
void SCULPT_boundary_data_free(struct SculptBoundary *boundary);
+/* Main Brush Function. */
void SCULPT_do_boundary_brush(struct Sculpt *sd,
struct Object *ob,
struct PBVHNode **nodes,
@@ -532,6 +620,7 @@ void SCULPT_boundary_edges_preview_draw(const uint gpuattr,
void SCULPT_boundary_pivot_line_preview_draw(const uint gpuattr, struct SculptSession *ss);
/* Multi-plane Scrape Brush. */
+/* Main Brush Function. */
void SCULPT_do_multiplane_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
void SCULPT_multiplane_scrape_preview_draw(const uint gpuattr,
Brush *brush,
@@ -548,13 +637,20 @@ void SCULPT_do_paint_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
void SCULPT_do_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
/* Smooth Brush. */
+
+/**
+ * For bmesh: Average surrounding verts based on an orthogonality measure.
+ * Naturally converges to a quad-like structure.
+ */
void SCULPT_bmesh_four_neighbor_average(float avg[3], float direction[3], struct BMVert *v);
void SCULPT_neighbor_coords_average(SculptSession *ss, float result[3], int index);
float SCULPT_neighbor_mask_average(SculptSession *ss, int index);
void SCULPT_neighbor_color_average(SculptSession *ss, float result[4], int index);
-/* Mask the mesh boundaries smoothing only the mesh surface without using automasking. */
+/**
+ * Mask the mesh boundaries smoothing only the mesh surface without using auto-masking.
+ */
void SCULPT_neighbor_coords_average_interior(SculptSession *ss, float result[3], int index);
void SCULPT_smooth(Sculpt *sd,
@@ -852,7 +948,13 @@ bool SCULPT_brush_test_cube(SculptBrushTest *test,
const float local[4][4],
const float roundness);
bool SCULPT_brush_test_circle_sq(SculptBrushTest *test, const float co[3]);
+/**
+ * Test AABB against sphere.
+ */
bool SCULPT_search_sphere_cb(PBVHNode *node, void *data_v);
+/**
+ * 2D projection (distance to line).
+ */
bool SCULPT_search_circle_cb(PBVHNode *node, void *data_v);
SculptBrushTestFn SCULPT_brush_test_init_with_falloff_shape(SculptSession *ss,
@@ -861,6 +963,9 @@ SculptBrushTestFn SCULPT_brush_test_init_with_falloff_shape(SculptSession *ss,
const float *SCULPT_brush_frontface_normal_from_falloff_shape(SculptSession *ss,
char falloff_shape);
+/**
+ * Return a multiplier for brush strength on a particular vertex.
+ */
float SCULPT_brush_strength_factor(struct SculptSession *ss,
const struct Brush *br,
const float point[3],
@@ -871,15 +976,21 @@ float SCULPT_brush_strength_factor(struct SculptSession *ss,
const int vertex_index,
const int thread_id);
-/* Tilts a normal by the x and y tilt values using the view axis. */
+/**
+ * Tilts a normal by the x and y tilt values using the view axis.
+ */
void SCULPT_tilt_apply_to_normal(float r_normal[3],
struct StrokeCache *cache,
const float tilt_strength);
-/* Get effective surface normal with pen tilt and tilt strength applied to it. */
+/**
+ * Get effective surface normal with pen tilt and tilt strength applied to it.
+ */
void SCULPT_tilt_effective_normal_get(const SculptSession *ss, const Brush *brush, float r_no[3]);
-/* just for vertex paint. */
+/**
+ * Expose 'calc_area_normal' externally (just for vertex paint).
+ */
bool SCULPT_pbvh_calc_area_normal(const struct Brush *brush,
Object *ob,
PBVHNode **nodes,
@@ -1085,6 +1196,7 @@ typedef enum SculptTransformDisplacementMode {
SCULPT_TRANSFORM_DISPLACEMENT_INCREMENTAL = 1,
} SculptTransformDisplacementMode;
+/* Filter orientation utils. */
void SCULPT_filter_to_orientation_space(float r_v[3], struct FilterCache *filter_cache);
void SCULPT_filter_to_object_space(float r_v[3], struct FilterCache *filter_cache);
void SCULPT_filter_zero_disabled_axis_components(float r_v[3], struct FilterCache *filter_cache);
@@ -1298,6 +1410,10 @@ typedef struct FilterCache {
AutomaskingCache *automasking;
} FilterCache;
+/**
+ * Flip all the edit-data across the axis/axes specified by \a symm.
+ * Used to calculate multiple modifications to the mesh when symmetry is enabled.
+ */
void SCULPT_cache_calc_brushdata_symm(StrokeCache *cache,
const char symm,
const char axis,
@@ -1313,8 +1429,14 @@ void SCULPT_undo_push_end_ex(const bool use_nested_undo);
void SCULPT_vertcos_to_key(Object *ob, KeyBlock *kb, const float (*vertCos)[3]);
+/**
+ * Copy the PBVH bounding box into the object's bounding box.
+ */
void SCULPT_update_object_bounding_box(struct Object *ob);
+/**
+ * Get a screen-space rectangle of the modified area.
+ */
bool SCULPT_get_redraw_rect(struct ARegion *region,
struct RegionView3D *rv3d,
Object *ob,
@@ -1323,10 +1445,12 @@ bool SCULPT_get_redraw_rect(struct ARegion *region,
/* Operators. */
/* Expand. */
+
void SCULPT_OT_expand(struct wmOperatorType *ot);
void sculpt_expand_modal_keymap(struct wmKeyConfig *keyconf);
/* Gestures. */
+
void SCULPT_OT_face_set_lasso_gesture(struct wmOperatorType *ot);
void SCULPT_OT_face_set_box_gesture(struct wmOperatorType *ot);
@@ -1336,6 +1460,7 @@ void SCULPT_OT_trim_box_gesture(struct wmOperatorType *ot);
void SCULPT_OT_project_line_gesture(struct wmOperatorType *ot);
/* Face Sets. */
+
void SCULPT_OT_face_sets_randomize_colors(struct wmOperatorType *ot);
void SCULPT_OT_face_sets_change_visibility(struct wmOperatorType *ot);
void SCULPT_OT_face_sets_init(struct wmOperatorType *ot);
@@ -1343,32 +1468,41 @@ void SCULPT_OT_face_sets_create(struct wmOperatorType *ot);
void SCULPT_OT_face_sets_edit(struct wmOperatorType *ot);
/* Transform. */
+
void SCULPT_OT_set_pivot_position(struct wmOperatorType *ot);
/* Mesh Filter. */
+
void SCULPT_OT_mesh_filter(struct wmOperatorType *ot);
/* Cloth Filter. */
+
void SCULPT_OT_cloth_filter(struct wmOperatorType *ot);
/* Color Filter. */
+
void SCULPT_OT_color_filter(struct wmOperatorType *ot);
/* Mask filter and Dirty Mask. */
+
void SCULPT_OT_mask_filter(struct wmOperatorType *ot);
void SCULPT_OT_dirty_mask(struct wmOperatorType *ot);
/* Mask and Face Sets Expand. */
+
void SCULPT_OT_mask_expand(struct wmOperatorType *ot);
/* Mask Init. */
+
void SCULPT_OT_mask_init(struct wmOperatorType *ot);
/* Detail size. */
+
void SCULPT_OT_detail_flood_fill(struct wmOperatorType *ot);
void SCULPT_OT_sample_detail_size(struct wmOperatorType *ot);
void SCULPT_OT_set_detail_size(struct wmOperatorType *ot);
void SCULPT_OT_dyntopo_detail_size_edit(struct wmOperatorType *ot);
/* Dyntopo. */
+
void SCULPT_OT_dynamic_topology_toggle(struct wmOperatorType *ot);
diff --git a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c
index f78f30a2cfd..05db799cb00 100644
--- a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c
+++ b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c
@@ -229,7 +229,6 @@ static void do_multiplane_scrape_brush_task_cb_ex(void *__restrict userdata,
/* Public functions. */
-/* Main Brush Function. */
void SCULPT_do_multiplane_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
SculptSession *ss = ob->sculpt;
diff --git a/source/blender/editors/sculpt_paint/sculpt_pose.c b/source/blender/editors/sculpt_paint/sculpt_pose.c
index 587ce346428..3b939279bf9 100644
--- a/source/blender/editors/sculpt_paint/sculpt_pose.c
+++ b/source/blender/editors/sculpt_paint/sculpt_pose.c
@@ -540,13 +540,6 @@ static bool pose_face_sets_floodfill_cb(
/* Public functions. */
-/**
- * Calculate the pose origin and (Optionally the pose factor)
- * that is used when using the pose brush.
- *
- * \param r_pose_origin: Must be a valid pointer.
- * \param r_pose_factor: Optional, when set to NULL it won't be calculated.
- */
void SCULPT_pose_calc_pose_data(Sculpt *sd,
Object *ob,
SculptSession *ss,
@@ -1132,7 +1125,6 @@ static void sculpt_pose_align_pivot_local_space(float r_mat[4][4],
ortho_basis_v3v3_v3(r_mat[0], r_mat[1], r_mat[2]);
}
-/* Main Brush Function. */
void SCULPT_do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
SculptSession *ss = ob->sculpt;
diff --git a/source/blender/editors/sculpt_paint/sculpt_smooth.c b/source/blender/editors/sculpt_paint/sculpt_smooth.c
index 1bfe8e1cbf1..847f42fe9e8 100644
--- a/source/blender/editors/sculpt_paint/sculpt_smooth.c
+++ b/source/blender/editors/sculpt_paint/sculpt_smooth.c
@@ -102,8 +102,6 @@ void SCULPT_neighbor_coords_average_interior(SculptSession *ss, float result[3],
mul_v3_v3fl(result, avg, 1.0f / total);
}
-/* For bmesh: Average surrounding verts based on an orthogonality measure.
- * Naturally converges to a quad-like structure. */
void SCULPT_bmesh_four_neighbor_average(float avg[3], float direction[3], BMVert *v)
{
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index 501a1e53276..4a88b75cf25 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -1598,7 +1598,6 @@ void ED_sculpt_undo_geometry_end(struct Object *ob)
SCULPT_undo_push_end();
}
-/* Export for ED_undo_sys. */
void ED_sculpt_undosys_type(UndoType *ut)
{
ut->name = "Sculpt";
diff --git a/source/blender/editors/space_action/action_data.c b/source/blender/editors/space_action/action_data.c
index 9ff46d96207..daa973edfbf 100644
--- a/source/blender/editors/space_action/action_data.c
+++ b/source/blender/editors/space_action/action_data.c
@@ -70,8 +70,7 @@
/* ************************************************************************** */
/* ACTION CREATION */
-/* Helper function to find the active AnimData block from the Action Editor context */
-AnimData *ED_actedit_animdata_from_context(bContext *C, ID **r_adt_id_owner)
+AnimData *ED_actedit_animdata_from_context(const bContext *C, ID **r_adt_id_owner)
{
SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
Object *ob = CTX_data_active_object(C);
diff --git a/source/blender/editors/space_action/action_draw.c b/source/blender/editors/space_action/action_draw.c
index 6f1a90e56a5..0ed55ca5191 100644
--- a/source/blender/editors/space_action/action_draw.c
+++ b/source/blender/editors/space_action/action_draw.c
@@ -63,7 +63,6 @@
/* ************************************************************************* */
/* Channel List */
-/* left hand part */
void draw_channel_names(bContext *C, bAnimContext *ac, ARegion *region)
{
ListBase anim_data = {NULL, NULL};
@@ -131,7 +130,54 @@ void draw_channel_names(bContext *C, bAnimContext *ac, ARegion *region)
/* extra padding for lengths (to go under scrollers) */
#define EXTRA_SCROLL_PAD 100.0f
-/* draw keyframes in each channel */
+/* Draw manually set intended playback frame ranges for actions. */
+static void draw_channel_action_ranges(bAnimContext *ac, ListBase *anim_data, View2D *v2d)
+{
+ /* Variables for coalescing the Y region of one action. */
+ bAction *cur_action = NULL;
+ AnimData *cur_adt = NULL;
+ float cur_ymax;
+
+ /* Walk through channels, grouping contiguous spans referencing the same action. */
+ float ymax = ACHANNEL_FIRST_TOP(ac) + ACHANNEL_SKIP / 2;
+ float ystep = ACHANNEL_STEP(ac);
+ float ymin = ymax - ystep;
+
+ for (bAnimListElem *ale = anim_data->first; ale; ale = ale->next, ymax = ymin, ymin -= ystep) {
+ bAction *action = NULL;
+ AnimData *adt = NULL;
+
+ /* check if visible */
+ if (IN_RANGE(ymin, v2d->cur.ymin, v2d->cur.ymax) ||
+ IN_RANGE(ymax, v2d->cur.ymin, v2d->cur.ymax)) {
+ /* check if anything to show for this channel */
+ if (ale->datatype != ALE_NONE) {
+ action = ANIM_channel_action_get(ale);
+
+ if (action) {
+ adt = ale->adt;
+ }
+ }
+ }
+
+ /* Extend the current region, or flush and restart. */
+ if (action != cur_action || adt != cur_adt) {
+ if (cur_action) {
+ ANIM_draw_action_framerange(cur_adt, cur_action, v2d, ymax, cur_ymax);
+ }
+
+ cur_action = action;
+ cur_adt = adt;
+ cur_ymax = ymax;
+ }
+ }
+
+ /* Flush the last region. */
+ if (cur_action) {
+ ANIM_draw_action_framerange(cur_adt, cur_action, v2d, ymax, cur_ymax);
+ }
+}
+
void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *region)
{
ListBase anim_data = {NULL, NULL};
@@ -166,6 +212,13 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *region
int height = ACHANNEL_TOT_HEIGHT(ac, items);
v2d->tot.ymin = -height;
+ /* Draw the manual frame ranges for actions in the background of the dopesheet.
+ * The action editor has already drawn the range for its action so it's not needed. */
+ if (ac->datatype == ANIMCONT_DOPESHEET) {
+ draw_channel_action_ranges(ac, &anim_data, v2d);
+ }
+
+ /* Draw the background strips. */
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
diff --git a/source/blender/editors/space_action/action_intern.h b/source/blender/editors/space_action/action_intern.h
index ffe0606c98f..581356a89d0 100644
--- a/source/blender/editors/space_action/action_intern.h
+++ b/source/blender/editors/space_action/action_intern.h
@@ -41,7 +41,14 @@ void action_buttons_register(struct ARegionType *art);
/* ***************************************** */
/* action_draw.c */
+
+/**
+ * Left hand part.
+ */
void draw_channel_names(struct bContext *C, struct bAnimContext *ac, struct ARegion *region);
+/**
+ * Draw keyframes in each channel.
+ */
void draw_channel_strips(struct bAnimContext *ac,
struct SpaceAction *saction,
struct ARegion *region);
diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c
index 738eeb21e2e..4463856f40a 100644
--- a/source/blender/editors/space_action/space_action.c
+++ b/source/blender/editors/space_action/space_action.c
@@ -25,6 +25,7 @@
#include <string.h>
#include "DNA_action_types.h"
+#include "DNA_anim_types.h"
#include "DNA_collection_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -35,6 +36,7 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
+#include "BKE_nla.h"
#include "BKE_screen.h"
#include "RNA_access.h"
@@ -204,6 +206,13 @@ static void action_main_region_draw(const bContext *C, ARegion *region)
/* start and end frame */
ANIM_draw_framerange(scene, v2d);
+ /* Draw the manually set intended playback frame range highlight in the Action editor. */
+ if (ELEM(saction->mode, SACTCONT_ACTION, SACTCONT_SHAPEKEY) && saction->action) {
+ AnimData *adt = ED_actedit_animdata_from_context(C, NULL);
+
+ ANIM_draw_action_framerange(adt, saction->action, v2d, -FLT_MAX, FLT_MAX);
+ }
+
/* data */
if (ANIM_animdata_get_context(C, &ac)) {
draw_channel_strips(&ac, saction, region);
@@ -853,7 +862,6 @@ static void action_space_subtype_item_extend(bContext *UNUSED(C),
RNA_enum_items_add(item, totitem, rna_enum_space_action_mode_items);
}
-/* only called once, from space/spacetypes.c */
void ED_spacetype_action(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype action");
diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c
index 149067a94fe..035bc7e297d 100644
--- a/source/blender/editors/space_api/spacetypes.c
+++ b/source/blender/editors/space_api/spacetypes.c
@@ -70,7 +70,6 @@
#include "io_ops.h"
-/* Only called once on startup. storage is global in BKE kernel listbase. */
void ED_spacetypes_init(void)
{
/* UI unit is a variable, may be used in some space type inits. */
@@ -186,10 +185,6 @@ void ED_spacemacros_init(void)
}
}
-/**
- * \note Keymap definitions are registered only once per WM initialize,
- * usually on file read, using the keymap the actual areas/regions add the handlers.
- * \note Called in wm.c. */
void ED_spacetypes_keymap(wmKeyConfig *keyconf)
{
ED_keymap_screen(keyconf);
diff --git a/source/blender/editors/space_buttons/buttons_intern.h b/source/blender/editors/space_buttons/buttons_intern.h
index 9cb363ff0c9..5eddea2cc40 100644
--- a/source/blender/editors/space_buttons/buttons_intern.h
+++ b/source/blender/editors/space_buttons/buttons_intern.h
@@ -88,6 +88,7 @@ typedef struct ButsContextTexture {
/* internal exports only */
/* buttons_context.c */
+
void buttons_context_compute(const struct bContext *C, struct SpaceProperties *sbuts);
int buttons_context(const struct bContext *C,
const char *member,
@@ -98,12 +99,17 @@ struct ID *buttons_context_id_path(const struct bContext *C);
extern const char *buttons_context_dir[]; /* doc access */
/* buttons_texture.c */
+
void buttons_texture_context_compute(const struct bContext *C, struct SpaceProperties *sbuts);
/* buttons_ops.c */
+
void BUTTONS_OT_start_filter(struct wmOperatorType *ot);
void BUTTONS_OT_clear_filter(struct wmOperatorType *ot);
void BUTTONS_OT_toggle_pin(struct wmOperatorType *ot);
void BUTTONS_OT_file_browse(struct wmOperatorType *ot);
+/**
+ * Second operator, only difference from #BUTTONS_OT_file_browse is #WM_FILESEL_DIRECTORY.
+ */
void BUTTONS_OT_directory_browse(struct wmOperatorType *ot);
void BUTTONS_OT_context_menu(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_buttons/buttons_ops.c b/source/blender/editors/space_buttons/buttons_ops.c
index 798f4898aaa..46d6df7c69c 100644
--- a/source/blender/editors/space_buttons/buttons_ops.c
+++ b/source/blender/editors/space_buttons/buttons_ops.c
@@ -383,7 +383,6 @@ void BUTTONS_OT_file_browse(wmOperatorType *ot)
FILE_SORT_DEFAULT);
}
-/* Second operator, only difference from BUTTONS_OT_file_browse is WM_FILESEL_DIRECTORY. */
void BUTTONS_OT_directory_browse(wmOperatorType *ot)
{
/* identifiers */
diff --git a/source/blender/editors/space_buttons/buttons_texture.c b/source/blender/editors/space_buttons/buttons_texture.c
index f1debcef5a9..554edf680be 100644
--- a/source/blender/editors/space_buttons/buttons_texture.c
+++ b/source/blender/editors/space_buttons/buttons_texture.c
@@ -667,7 +667,6 @@ static void template_texture_show(bContext *C, void *data_p, void *prop_p)
}
}
-/* Button to quickly show texture in Properties Editor texture tab. */
void uiTemplateTextureShow(uiLayout *layout, const bContext *C, PointerRNA *ptr, PropertyRNA *prop)
{
/* Only show the button if there is actually a texture assigned. */
diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c
index b04291b7ab4..007a9105c76 100644
--- a/source/blender/editors/space_buttons/space_buttons.c
+++ b/source/blender/editors/space_buttons/space_buttons.c
@@ -166,11 +166,6 @@ static void buttons_main_region_init(wmWindowManager *wm, ARegion *region)
/** \name Property Editor Layout
* \{ */
-/**
- * Fills an array with the tab context values for the properties editor. -1 signals a separator.
- *
- * \return The total number of items in the array returned.
- */
int ED_buttons_tabs_list(SpaceProperties *sbuts, short *context_tabs_array)
{
int length = 0;
@@ -445,7 +440,7 @@ static void property_search_all_tabs(const bContext *C,
i,
property_search_for_context(C, region_copy, &sbuts_copy));
- UI_blocklist_free(C, &region_copy->uiblocks);
+ UI_blocklist_free(C, region_copy);
}
BKE_area_region_free(area_copy.type, region_copy);
@@ -924,7 +919,6 @@ static void buttons_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id
/** \name Space Type Initialization
* \{ */
-/* only called once, from space/spacetypes.c */
void ED_spacetype_buttons(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype buttons");
diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c
index 4bccb3664da..68444cc0313 100644
--- a/source/blender/editors/space_clip/clip_draw.c
+++ b/source/blender/editors/space_clip/clip_draw.c
@@ -1981,7 +1981,6 @@ void clip_draw_cache_and_notes(const bContext *C, SpaceClip *sc, ARegion *region
}
}
-/* draw grease pencil */
void clip_draw_grease_pencil(bContext *C, int onlyv2d)
{
SpaceClip *sc = CTX_wm_space_clip(C);
diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c
index 834ef847069..5a999b1fad7 100644
--- a/source/blender/editors/space_clip/clip_editor.c
+++ b/source/blender/editors/space_clip/clip_editor.c
@@ -223,7 +223,6 @@ void ED_space_clip_get_aspect_dimension_aware(SpaceClip *sc, float *aspx, float
}
}
-/* return current frame number in clip space */
int ED_space_clip_get_clip_frame_number(SpaceClip *sc)
{
MovieClip *clip = ED_space_clip_get_clip(sc);
@@ -272,7 +271,7 @@ ImBuf *ED_space_clip_get_stable_buffer(SpaceClip *sc, float loc[2], float *scale
}
bool ED_space_clip_get_position(struct SpaceClip *sc,
- struct ARegion *ar,
+ struct ARegion *region,
int mval[2],
float fpos[2])
{
@@ -282,13 +281,12 @@ bool ED_space_clip_get_position(struct SpaceClip *sc,
}
/* map the mouse coords to the backdrop image space */
- ED_clip_mouse_pos(sc, ar, mval, fpos);
+ ED_clip_mouse_pos(sc, region, mval, fpos);
IMB_freeImBuf(ibuf);
return true;
}
-/* Returns color in linear space, matching ED_space_image_color_sample(). */
bool ED_space_clip_color_sample(SpaceClip *sc, ARegion *region, int mval[2], float r_col[3])
{
ImBuf *ibuf;
@@ -511,10 +509,6 @@ void ED_clip_point_stable_pos(
}
}
-/**
- * \brief the reverse of #ED_clip_point_stable_pos(), gets the marker region coords.
- * better name here? view_to_track / track_to_view or so?
- */
void ED_clip_point_stable_pos__reverse(SpaceClip *sc,
ARegion *region,
const float co[2],
@@ -539,7 +533,6 @@ void ED_clip_point_stable_pos__reverse(SpaceClip *sc,
r_co[1] = (pos[1] * height * zoomy) + (float)sy;
}
-/* takes event->mval */
void ED_clip_mouse_pos(SpaceClip *sc, ARegion *region, const int mval[2], float co[2])
{
ED_clip_point_stable_pos(sc, region, mval[0], mval[1], &co[0], &co[1]);
diff --git a/source/blender/editors/space_clip/clip_intern.h b/source/blender/editors/space_clip/clip_intern.h
index 202dc00e365..20cc6e3da15 100644
--- a/source/blender/editors/space_clip/clip_intern.h
+++ b/source/blender/editors/space_clip/clip_intern.h
@@ -50,25 +50,34 @@ struct wmOperatorType;
/* internal exports only */
/* clip_buttons.c */
+
void ED_clip_buttons_register(struct ARegionType *art);
/* clip_dopesheet_draw.c */
+
void clip_draw_dopesheet_main(struct SpaceClip *sc, struct ARegion *region, struct Scene *scene);
void clip_draw_dopesheet_channels(const struct bContext *C, struct ARegion *region);
/* clip_dopesheet_ops.c */
+
void CLIP_OT_dopesheet_select_channel(struct wmOperatorType *ot);
void CLIP_OT_dopesheet_view_all(struct wmOperatorType *ot);
/* clip_draw.c */
+
void clip_draw_main(const struct bContext *C, struct SpaceClip *sc, struct ARegion *region);
+
+/* draw grease pencil */
+
void clip_draw_grease_pencil(struct bContext *C, int onlyv2d);
void clip_draw_cache_and_notes(const bContext *C, SpaceClip *sc, ARegion *region);
/* clip_editor.c */
+
void clip_start_prefetch_job(const struct bContext *C);
/* clip_graph_draw.c */
+
void clip_draw_graph(struct SpaceClip *sc, struct ARegion *region, struct Scene *scene);
/* clip_graph_ops.c */
@@ -171,6 +180,9 @@ void clip_delete_plane_track(struct bContext *C,
struct MovieClip *clip,
struct MovieTrackingPlaneTrack *plane_track);
+/**
+ * Calculate space clip offset to be centered at the given point.
+ */
void clip_view_offset_for_center_to_point(
SpaceClip *sc, const float x, const float y, float *r_offset_x, float *r_offset_y);
void clip_view_center_to_point(SpaceClip *sc, float x, float y);
@@ -178,6 +190,10 @@ void clip_view_center_to_point(SpaceClip *sc, float x, float y);
bool clip_view_calculate_view_selection(
const struct bContext *C, bool fit, float *r_offset_x, float *r_offset_y, float *r_zoom);
+/**
+ * Returns truth if lock-to-selection is enabled and possible.
+ * Locking to selection is not possible if there is no selection.
+ */
bool clip_view_has_locked_selection(const struct bContext *C);
void clip_draw_sfra_efra(struct View2D *v2d, struct Scene *scene);
diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c
index b1f8949871b..0aa7e35aed6 100644
--- a/source/blender/editors/space_clip/clip_ops.c
+++ b/source/blender/editors/space_clip/clip_ops.c
@@ -209,7 +209,7 @@ static int open_exec(bContext *C, wmOperator *op)
RNA_string_get(op->ptr, "directory", dir_only);
if (relative) {
- BLI_path_rel(dir_only, bmain->name);
+ BLI_path_rel(dir_only, bmain->filepath);
}
prop = RNA_struct_find_property(op->ptr, "files");
@@ -285,7 +285,7 @@ static int open_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)
if (clip) {
BLI_strncpy(path, clip->filepath, sizeof(path));
- BLI_path_abs(path, CTX_data_main(C)->name);
+ BLI_path_abs(path, CTX_data_main(C)->filepath);
BLI_path_parent_dir(path);
}
else {
@@ -911,6 +911,7 @@ void CLIP_OT_view_zoom_ratio(wmOperatorType *ot)
-FLT_MAX,
FLT_MAX);
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -988,6 +989,7 @@ void CLIP_OT_view_all(wmOperatorType *ot)
prop = RNA_def_boolean(ot->srna, "fit_view", 0, "Fit View", "Fit frame to the viewport");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1052,6 +1054,7 @@ void CLIP_OT_view_selected(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_LOCK_BYPASS;
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1172,6 +1175,7 @@ void CLIP_OT_change_frame(wmOperatorType *ot)
/* rna */
RNA_def_int(ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME);
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1584,6 +1588,7 @@ void CLIP_OT_rebuild_proxy(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER;
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1623,10 +1628,10 @@ void CLIP_OT_mode_set(wmOperatorType *ot)
RNA_def_enum(ot->srna, "mode", rna_enum_clip_editor_mode_items, SC_MODE_TRACKING, "Mode", "");
}
-#ifdef WITH_INPUT_NDOF
-
/** \} */
+#ifdef WITH_INPUT_NDOF
+
/* -------------------------------------------------------------------- */
/** \name NDOF Operator
* \{ */
@@ -1725,6 +1730,7 @@ void CLIP_OT_prefetch(wmOperatorType *ot)
ot->invoke = clip_prefetch_invoke;
ot->modal = clip_prefetch_modal;
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1764,6 +1770,7 @@ void CLIP_OT_set_scene_frames(wmOperatorType *ot)
ot->poll = ED_space_clip_view_clip_poll;
ot->exec = clip_set_scene_frames_exec;
}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/editors/space_clip/clip_utils.c b/source/blender/editors/space_clip/clip_utils.c
index 23dd290e13f..5f5a24a9407 100644
--- a/source/blender/editors/space_clip/clip_utils.c
+++ b/source/blender/editors/space_clip/clip_utils.c
@@ -398,7 +398,6 @@ void clip_delete_plane_track(bContext *C, MovieClip *clip, MovieTrackingPlaneTra
DEG_id_tag_update(&clip->id, 0);
}
-/* Calculate space clip offset to be centered at the given point. */
void clip_view_offset_for_center_to_point(
SpaceClip *sc, const float x, const float y, float *r_offset_x, float *r_offset_y)
{
@@ -608,8 +607,6 @@ bool clip_view_calculate_view_selection(
return true;
}
-/* Returns truth if lock-to-selection is enabled and possible.
- * Locking to selection is not possible if there is no selection. */
bool clip_view_has_locked_selection(const bContext *C)
{
SpaceClip *space_clip = CTX_wm_space_clip(C);
diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c
index e2fbb4a5a59..91083fa9682 100644
--- a/source/blender/editors/space_clip/space_clip.c
+++ b/source/blender/editors/space_clip/space_clip.c
@@ -1335,7 +1335,6 @@ static void clip_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, I
}
}
-/* only called once, from space/spacetypes.c */
void ED_spacetype_clip(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype clip");
diff --git a/source/blender/editors/space_console/space_console.c b/source/blender/editors/space_console/space_console.c
index 84be24e96ac..e66c3898d04 100644
--- a/source/blender/editors/space_console/space_console.c
+++ b/source/blender/editors/space_console/space_console.c
@@ -293,7 +293,6 @@ static void console_main_region_listener(const wmRegionListenerParams *params)
}
}
-/* only called once, from space/spacetypes.c */
void ED_spacetype_console(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype console");
diff --git a/source/blender/editors/space_file/CMakeLists.txt b/source/blender/editors/space_file/CMakeLists.txt
index 4b508f16c1e..1651269869e 100644
--- a/source/blender/editors/space_file/CMakeLists.txt
+++ b/source/blender/editors/space_file/CMakeLists.txt
@@ -17,6 +17,7 @@
set(INC
../include
+ ../asset
../../blenfont
../../blenkernel
../../blenlib
@@ -36,6 +37,7 @@ set(INC
set(SRC
asset_catalog_tree_view.cc
file_draw.c
+ file_indexer.cc
file_ops.c
file_panels.c
file_utils.c
@@ -44,6 +46,7 @@ set(SRC
fsmenu.c
space_file.c
+ file_indexer.h
file_intern.h
filelist.h
fsmenu.h
diff --git a/source/blender/editors/space_file/asset_catalog_tree_view.cc b/source/blender/editors/space_file/asset_catalog_tree_view.cc
index 41559278910..86c4b78dea4 100644
--- a/source/blender/editors/space_file/asset_catalog_tree_view.cc
+++ b/source/blender/editors/space_file/asset_catalog_tree_view.cc
@@ -33,6 +33,7 @@
#include "ED_asset.h"
#include "ED_fileselect.h"
+#include "ED_undo.h"
#include "RNA_access.h"
@@ -52,6 +53,8 @@ using namespace blender::bke;
namespace blender::ed::asset_browser {
+class AssetCatalogTreeViewAllItem;
+
class AssetCatalogTreeView : public ui::AbstractTreeView {
::AssetLibrary *asset_library_;
/** The asset catalog tree this tree-view represents. */
@@ -61,6 +64,7 @@ class AssetCatalogTreeView : public ui::AbstractTreeView {
friend class AssetCatalogTreeViewItem;
friend class AssetCatalogDropController;
+ friend class AssetCatalogTreeViewAllItem;
public:
AssetCatalogTreeView(::AssetLibrary *library,
@@ -69,11 +73,13 @@ class AssetCatalogTreeView : public ui::AbstractTreeView {
void build_tree() override;
+ void activate_catalog_by_id(CatalogID catalog_id);
+
private:
- ui::BasicTreeViewItem &build_catalog_items_recursive(ui::TreeViewItemContainer &view_parent_item,
+ ui::BasicTreeViewItem &build_catalog_items_recursive(ui::TreeViewOrItem &view_parent_item,
AssetCatalogTreeItem &catalog);
- void add_all_item();
+ AssetCatalogTreeViewAllItem &add_all_item();
void add_unassigned_item();
bool is_active_catalog(CatalogID catalog_id) const;
};
@@ -92,7 +98,7 @@ class AssetCatalogTreeViewItem : public ui::BasicTreeViewItem {
void build_row(uiLayout &row) override;
void build_context_menu(bContext &C, uiLayout &column) const override;
- bool can_rename() const override;
+ bool supports_renaming() const override;
bool rename(StringRefNull new_name) override;
/** Add drag support for catalog items. */
@@ -105,10 +111,12 @@ class AssetCatalogDragController : public ui::AbstractTreeViewItemDragController
AssetCatalogTreeItem &catalog_item_;
public:
- explicit AssetCatalogDragController(AssetCatalogTreeItem &catalog_item);
+ explicit AssetCatalogDragController(AssetCatalogTreeView &tree_view,
+ AssetCatalogTreeItem &catalog_item);
int get_drag_type() const override;
void *create_drag_data() const override;
+ void on_drag_start() override;
};
class AssetCatalogDropController : public ui::AbstractTreeViewItemDropController {
@@ -119,19 +127,26 @@ class AssetCatalogDropController : public ui::AbstractTreeViewItemDropController
bool can_drop(const wmDrag &drag, const char **r_disabled_hint) const override;
std::string drop_tooltip(const wmDrag &drag) const override;
- bool on_drop(const wmDrag &drag) override;
+ bool on_drop(struct bContext *C, const wmDrag &drag) override;
::AssetLibrary &get_asset_library() const;
- AssetCatalog *get_drag_catalog(const wmDrag &drag) const;
+ static AssetCatalog *get_drag_catalog(const wmDrag &drag, const ::AssetLibrary &asset_library);
static bool has_droppable_asset(const wmDrag &drag, const char **r_disabled_hint);
- static bool drop_assets_into_catalog(const AssetCatalogTreeView &tree_view,
+ static bool drop_assets_into_catalog(struct bContext *C,
+ const AssetCatalogTreeView &tree_view,
const wmDrag &drag,
CatalogID catalog_id,
StringRefNull simple_name = "");
+ /**
+ * \param drop_catalog_id: Can be unset to drop into the root level of the tree.
+ */
+ static bool drop_asset_catalog_into_catalog(
+ const wmDrag &drag,
+ AssetCatalogTreeView &tree_view,
+ const std::optional<CatalogID> drop_catalog_id = std::nullopt);
private:
- bool drop_asset_catalog_into_catalog(const wmDrag &drag);
std::string drop_tooltip_asset_list(const wmDrag &drag) const;
std::string drop_tooltip_asset_catalog(const wmDrag &drag) const;
};
@@ -142,6 +157,16 @@ class AssetCatalogTreeViewAllItem : public ui::BasicTreeViewItem {
using BasicTreeViewItem::BasicTreeViewItem;
void build_row(uiLayout &row) override;
+
+ struct DropController : public ui::AbstractTreeViewItemDropController {
+ DropController(AssetCatalogTreeView &tree_view);
+
+ bool can_drop(const wmDrag &drag, const char **r_disabled_hint) const override;
+ std::string drop_tooltip(const wmDrag &drag) const override;
+ bool on_drop(struct bContext *C, const wmDrag &drag) override;
+ };
+
+ std::unique_ptr<ui::AbstractTreeViewItemDropController> create_drop_controller() const override;
};
class AssetCatalogTreeViewUnassignedItem : public ui::BasicTreeViewItem {
@@ -152,7 +177,7 @@ class AssetCatalogTreeViewUnassignedItem : public ui::BasicTreeViewItem {
bool can_drop(const wmDrag &drag, const char **r_disabled_hint) const override;
std::string drop_tooltip(const wmDrag &drag) const override;
- bool on_drop(const wmDrag &drag) override;
+ bool on_drop(struct bContext *C, const wmDrag &drag) override;
};
std::unique_ptr<ui::AbstractTreeViewItemDropController> create_drop_controller() const override;
@@ -172,14 +197,13 @@ AssetCatalogTreeView::AssetCatalogTreeView(::AssetLibrary *library,
void AssetCatalogTreeView::build_tree()
{
- add_all_item();
+ AssetCatalogTreeViewAllItem &all_item = add_all_item();
+ all_item.set_collapsed(false);
if (catalog_tree_) {
- catalog_tree_->foreach_root_item([this](AssetCatalogTreeItem &item) {
- ui::BasicTreeViewItem &child_view_item = build_catalog_items_recursive(*this, item);
-
- /* Open root-level items by default. */
- child_view_item.set_collapsed(false);
+ /* Pass the "All" item on as parent of the actual catalog items. */
+ catalog_tree_->foreach_root_item([this, &all_item](AssetCatalogTreeItem &item) {
+ build_catalog_items_recursive(all_item, item);
});
}
@@ -187,11 +211,12 @@ void AssetCatalogTreeView::build_tree()
}
ui::BasicTreeViewItem &AssetCatalogTreeView::build_catalog_items_recursive(
- ui::TreeViewItemContainer &view_parent_item, AssetCatalogTreeItem &catalog)
+ ui::TreeViewOrItem &view_parent_item, AssetCatalogTreeItem &catalog)
{
ui::BasicTreeViewItem &view_item = view_parent_item.add_tree_item<AssetCatalogTreeViewItem>(
&catalog);
- view_item.is_active([this, &catalog]() { return is_active_catalog(catalog.get_catalog_id()); });
+ view_item.set_is_active_fn(
+ [this, &catalog]() { return is_active_catalog(catalog.get_catalog_id()); });
catalog.foreach_child([&view_item, this](AssetCatalogTreeItem &child) {
build_catalog_items_recursive(view_item, child);
@@ -199,18 +224,18 @@ ui::BasicTreeViewItem &AssetCatalogTreeView::build_catalog_items_recursive(
return view_item;
}
-void AssetCatalogTreeView::add_all_item()
+AssetCatalogTreeViewAllItem &AssetCatalogTreeView::add_all_item()
{
FileAssetSelectParams *params = params_;
- AssetCatalogTreeViewAllItem &item = add_tree_item<AssetCatalogTreeViewAllItem>(IFACE_("All"),
- ICON_HOME);
- item.on_activate([params](ui::BasicTreeViewItem & /*item*/) {
+ AssetCatalogTreeViewAllItem &item = add_tree_item<AssetCatalogTreeViewAllItem>(IFACE_("All"));
+ item.set_on_activate_fn([params](ui::BasicTreeViewItem & /*item*/) {
params->asset_catalog_visibility = FILE_SHOW_ASSETS_ALL_CATALOGS;
WM_main_add_notifier(NC_SPACE | ND_SPACE_ASSET_PARAMS, nullptr);
});
- item.is_active(
+ item.set_is_active_fn(
[params]() { return params->asset_catalog_visibility == FILE_SHOW_ASSETS_ALL_CATALOGS; });
+ return item;
}
void AssetCatalogTreeView::add_unassigned_item()
@@ -220,14 +245,21 @@ void AssetCatalogTreeView::add_unassigned_item()
AssetCatalogTreeViewUnassignedItem &item = add_tree_item<AssetCatalogTreeViewUnassignedItem>(
IFACE_("Unassigned"), ICON_FILE_HIDDEN);
- item.on_activate([params](ui::BasicTreeViewItem & /*item*/) {
+ item.set_on_activate_fn([params](ui::BasicTreeViewItem & /*item*/) {
params->asset_catalog_visibility = FILE_SHOW_ASSETS_WITHOUT_CATALOG;
WM_main_add_notifier(NC_SPACE | ND_SPACE_ASSET_PARAMS, nullptr);
});
- item.is_active(
+ item.set_is_active_fn(
[params]() { return params->asset_catalog_visibility == FILE_SHOW_ASSETS_WITHOUT_CATALOG; });
}
+void AssetCatalogTreeView::activate_catalog_by_id(CatalogID catalog_id)
+{
+ params_->asset_catalog_visibility = FILE_SHOW_ASSETS_FROM_CATALOG;
+ params_->catalog_id = catalog_id;
+ WM_main_add_notifier(NC_SPACE | ND_SPACE_ASSET_PARAMS, nullptr);
+}
+
bool AssetCatalogTreeView::is_active_catalog(CatalogID catalog_id) const
{
return (params_->asset_catalog_visibility == FILE_SHOW_ASSETS_FROM_CATALOG) &&
@@ -243,11 +275,8 @@ AssetCatalogTreeViewItem::AssetCatalogTreeViewItem(AssetCatalogTreeItem *catalog
void AssetCatalogTreeViewItem::on_activate()
{
- const AssetCatalogTreeView &tree_view = static_cast<const AssetCatalogTreeView &>(
- get_tree_view());
- tree_view.params_->asset_catalog_visibility = FILE_SHOW_ASSETS_FROM_CATALOG;
- tree_view.params_->catalog_id = catalog_item_.get_catalog_id();
- WM_main_add_notifier(NC_SPACE | ND_SPACE_ASSET_PARAMS, nullptr);
+ AssetCatalogTreeView &tree_view = static_cast<AssetCatalogTreeView &>(get_tree_view());
+ tree_view.activate_catalog_by_id(catalog_item_.get_catalog_id());
}
void AssetCatalogTreeViewItem::build_row(uiLayout &row)
@@ -304,7 +333,7 @@ void AssetCatalogTreeViewItem::build_context_menu(bContext &C, uiLayout &column)
UI_menutype_draw(&C, mt, &column);
}
-bool AssetCatalogTreeViewItem::can_rename() const
+bool AssetCatalogTreeViewItem::supports_renaming() const
{
return true;
}
@@ -330,7 +359,8 @@ std::unique_ptr<ui::AbstractTreeViewItemDropController> AssetCatalogTreeViewItem
std::unique_ptr<ui::AbstractTreeViewItemDragController> AssetCatalogTreeViewItem::
create_drag_controller() const
{
- return std::make_unique<AssetCatalogDragController>(catalog_item_);
+ return std::make_unique<AssetCatalogDragController>(
+ static_cast<AssetCatalogTreeView &>(get_tree_view()), catalog_item_);
}
/* ---------------------------------------------------------------------- */
@@ -344,14 +374,18 @@ AssetCatalogDropController::AssetCatalogDropController(AssetCatalogTreeView &tre
bool AssetCatalogDropController::can_drop(const wmDrag &drag, const char **r_disabled_hint) const
{
if (drag.type == WM_DRAG_ASSET_CATALOG) {
- const AssetCatalog *drag_catalog = get_drag_catalog(drag);
- /* Note: Technically it's not an issue to allow this (the catalog will just receive a new
+ const AssetCatalog *drag_catalog = get_drag_catalog(drag, get_asset_library());
+ /* NOTE: Technically it's not an issue to allow this (the catalog will just receive a new
* path and the catalog system will generate missing parents from the path). But it does
* appear broken to users, so disabling entirely. */
if (catalog_item_.catalog_path().is_contained_in(drag_catalog->path)) {
*r_disabled_hint = "Catalog cannot be dropped into itself";
return false;
}
+ if (catalog_item_.catalog_path() == drag_catalog->path.parent()) {
+ *r_disabled_hint = "Catalog is already placed inside this catalog";
+ return false;
+ }
return true;
}
if (drag.type == WM_DRAG_ASSET_LIST) {
@@ -371,7 +405,7 @@ std::string AssetCatalogDropController::drop_tooltip(const wmDrag &drag) const
std::string AssetCatalogDropController::drop_tooltip_asset_catalog(const wmDrag &drag) const
{
BLI_assert(drag.type == WM_DRAG_ASSET_CATALOG);
- const AssetCatalog *src_catalog = get_drag_catalog(drag);
+ const AssetCatalog *src_catalog = get_drag_catalog(drag, get_asset_library());
return std::string(TIP_("Move Catalog")) + " '" + src_catalog->path.name() + "' " +
TIP_("into") + " '" + catalog_item_.get_name() + "'";
@@ -393,29 +427,35 @@ std::string AssetCatalogDropController::drop_tooltip_asset_list(const wmDrag &dr
")";
}
-bool AssetCatalogDropController::on_drop(const wmDrag &drag)
+bool AssetCatalogDropController::on_drop(struct bContext *C, const wmDrag &drag)
{
if (drag.type == WM_DRAG_ASSET_CATALOG) {
- return drop_asset_catalog_into_catalog(drag);
+ return drop_asset_catalog_into_catalog(
+ drag, tree_view<AssetCatalogTreeView>(), catalog_item_.get_catalog_id());
}
- return drop_assets_into_catalog(tree_view<AssetCatalogTreeView>(),
+ return drop_assets_into_catalog(C,
+ tree_view<AssetCatalogTreeView>(),
drag,
catalog_item_.get_catalog_id(),
catalog_item_.get_simple_name());
}
-bool AssetCatalogDropController::drop_asset_catalog_into_catalog(const wmDrag &drag)
+bool AssetCatalogDropController::drop_asset_catalog_into_catalog(
+ const wmDrag &drag,
+ AssetCatalogTreeView &tree_view,
+ const std::optional<CatalogID> drop_catalog_id)
{
BLI_assert(drag.type == WM_DRAG_ASSET_CATALOG);
wmDragAssetCatalog *catalog_drag = WM_drag_get_asset_catalog_data(&drag);
- ED_asset_catalog_move(
- &get_asset_library(), catalog_drag->drag_catalog_id, catalog_item_.get_catalog_id());
+ ED_asset_catalog_move(tree_view.asset_library_, catalog_drag->drag_catalog_id, drop_catalog_id);
+ tree_view.activate_catalog_by_id(catalog_drag->drag_catalog_id);
WM_main_add_notifier(NC_ASSET | ND_ASSET_CATALOGS, nullptr);
return true;
}
-bool AssetCatalogDropController::drop_assets_into_catalog(const AssetCatalogTreeView &tree_view,
+bool AssetCatalogDropController::drop_assets_into_catalog(struct bContext *C,
+ const AssetCatalogTreeView &tree_view,
const wmDrag &drag,
CatalogID catalog_id,
StringRefNull simple_name)
@@ -426,11 +466,14 @@ bool AssetCatalogDropController::drop_assets_into_catalog(const AssetCatalogTree
return false;
}
+ bool did_update = false;
LISTBASE_FOREACH (wmDragAssetListItem *, asset_item, asset_drags) {
if (asset_item->is_external) {
/* Only internal assets can be modified! */
continue;
}
+
+ did_update = true;
BKE_asset_metadata_catalog_id_set(
asset_item->asset_data.local_id->asset_data, catalog_id, simple_name.c_str());
@@ -440,16 +483,20 @@ bool AssetCatalogDropController::drop_assets_into_catalog(const AssetCatalogTree
WM_main_add_notifier(NC_SPACE | ND_SPACE_FILE_LIST, nullptr);
}
+ if (did_update) {
+ ED_undo_push(C, "Assign Asset Catalog");
+ }
return true;
}
-AssetCatalog *AssetCatalogDropController::get_drag_catalog(const wmDrag &drag) const
+AssetCatalog *AssetCatalogDropController::get_drag_catalog(const wmDrag &drag,
+ const ::AssetLibrary &asset_library)
{
if (drag.type != WM_DRAG_ASSET_CATALOG) {
return nullptr;
}
const bke::AssetCatalogService *catalog_service = BKE_asset_library_get_catalog_service(
- &get_asset_library());
+ &asset_library);
const wmDragAssetCatalog *catalog_drag = WM_drag_get_asset_catalog_data(&drag);
return catalog_service->find_catalog(catalog_drag->drag_catalog_id);
@@ -468,7 +515,7 @@ bool AssetCatalogDropController::has_droppable_asset(const wmDrag &drag,
}
}
- *r_disabled_hint = "Only assets from this current file can be moved between catalogs";
+ *r_disabled_hint = TIP_("Only assets from this current file can be moved between catalogs");
return false;
}
@@ -479,8 +526,9 @@ bool AssetCatalogDropController::has_droppable_asset(const wmDrag &drag,
/* ---------------------------------------------------------------------- */
-AssetCatalogDragController::AssetCatalogDragController(AssetCatalogTreeItem &catalog_item)
- : catalog_item_(catalog_item)
+AssetCatalogDragController::AssetCatalogDragController(AssetCatalogTreeView &tree_view,
+ AssetCatalogTreeItem &catalog_item)
+ : ui::AbstractTreeViewItemDragController(tree_view), catalog_item_(catalog_item)
{
}
@@ -497,6 +545,12 @@ void *AssetCatalogDragController::create_drag_data() const
return drag_catalog;
}
+void AssetCatalogDragController::on_drag_start()
+{
+ AssetCatalogTreeView &tree_view_ = tree_view<AssetCatalogTreeView>();
+ tree_view_.activate_catalog_by_id(catalog_item_.get_catalog_id());
+}
+
/* ---------------------------------------------------------------------- */
void AssetCatalogTreeViewAllItem::build_row(uiLayout &row)
@@ -514,6 +568,56 @@ void AssetCatalogTreeViewAllItem::build_row(uiLayout &row)
RNA_string_set(props, "parent_path", nullptr);
}
+std::unique_ptr<ui::AbstractTreeViewItemDropController> AssetCatalogTreeViewAllItem::
+ create_drop_controller() const
+{
+ return std::make_unique<AssetCatalogTreeViewAllItem::DropController>(
+ static_cast<AssetCatalogTreeView &>(get_tree_view()));
+}
+
+AssetCatalogTreeViewAllItem::DropController::DropController(AssetCatalogTreeView &tree_view)
+ : ui::AbstractTreeViewItemDropController(tree_view)
+{
+}
+
+bool AssetCatalogTreeViewAllItem::DropController::can_drop(const wmDrag &drag,
+ const char **r_disabled_hint) const
+{
+ if (drag.type != WM_DRAG_ASSET_CATALOG) {
+ return false;
+ }
+
+ const AssetCatalog *drag_catalog = AssetCatalogDropController::get_drag_catalog(
+ drag, *tree_view<AssetCatalogTreeView>().asset_library_);
+ if (drag_catalog->path.parent() == "") {
+ *r_disabled_hint = "Catalog is already placed at the highest level";
+ return false;
+ }
+
+ return true;
+}
+
+std::string AssetCatalogTreeViewAllItem::DropController::drop_tooltip(const wmDrag &drag) const
+{
+ BLI_assert(drag.type == WM_DRAG_ASSET_CATALOG);
+ const AssetCatalog *drag_catalog = AssetCatalogDropController::get_drag_catalog(
+ drag, *tree_view<AssetCatalogTreeView>().asset_library_);
+
+ return std::string(TIP_("Move Catalog")) + " '" + drag_catalog->path.name() + "' " +
+ TIP_("to the top level of the tree");
+}
+
+bool AssetCatalogTreeViewAllItem::DropController::on_drop(struct bContext *UNUSED(C),
+ const wmDrag &drag)
+{
+ BLI_assert(drag.type == WM_DRAG_ASSET_CATALOG);
+ return AssetCatalogDropController::drop_asset_catalog_into_catalog(
+ drag,
+ tree_view<AssetCatalogTreeView>(),
+ /* No value to drop into the root level. */
+ std::nullopt);
+}
+
/* ---------------------------------------------------------------------- */
std::unique_ptr<ui::AbstractTreeViewItemDropController> AssetCatalogTreeViewUnassignedItem::
@@ -547,11 +651,12 @@ std::string AssetCatalogTreeViewUnassignedItem::DropController::drop_tooltip(
TIP_("Move asset out of any catalog");
}
-bool AssetCatalogTreeViewUnassignedItem::DropController::on_drop(const wmDrag &drag)
+bool AssetCatalogTreeViewUnassignedItem::DropController::on_drop(struct bContext *C,
+ const wmDrag &drag)
{
/* Assign to nil catalog ID. */
return AssetCatalogDropController::drop_assets_into_catalog(
- tree_view<AssetCatalogTreeView>(), drag, CatalogID{});
+ C, tree_view<AssetCatalogTreeView>(), drag, CatalogID{});
}
} // namespace blender::ed::asset_browser
@@ -586,10 +691,6 @@ void file_delete_asset_catalog_filter_settings(
OBJECT_GUARDED_SAFE_DELETE(*filter_settings, AssetCatalogFilterSettings);
}
-/**
- * \return True if the file list should update its filtered results (e.g. because filtering
- * parameters changed).
- */
bool file_set_asset_catalog_filter_settings(
FileAssetCatalogFilterSettingsHandle *filter_settings_handle,
eFileSel_Params_AssetCatalogVisibility catalog_visibility,
diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c
index e393cc41a86..44e9735866d 100644
--- a/source/blender/editors/space_file/file_draw.c
+++ b/source/blender/editors/space_file/file_draw.c
@@ -479,7 +479,7 @@ static void file_draw_preview(const SpaceFile *sfile,
const uchar light[4] = {255, 255, 255, 255};
icon_x = xco + ex - UI_UNIT_X;
icon_y = yco + ey - UI_UNIT_Y;
- UI_icon_draw_ex(icon_x, icon_y, ICON_FILE_BLEND, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false);
+ UI_icon_draw_ex(icon_x, icon_y, ICON_CURRENT_FILE, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false);
}
/* Contrasting outline around some preview types. */
@@ -1132,10 +1132,6 @@ static void file_draw_invalid_library_hint(const bContext *C,
}
}
-/**
- * Draw a string hint if the file list is invalid.
- * \return true if the list is invalid and a hint was drawn.
- */
bool file_draw_hint_if_invalid(const bContext *C, const SpaceFile *sfile, ARegion *region)
{
FileAssetSelectParams *asset_params = ED_fileselect_get_asset_params(sfile);
diff --git a/source/blender/editors/space_file/file_indexer.cc b/source/blender/editors/space_file/file_indexer.cc
new file mode 100644
index 00000000000..95e0afd7a1e
--- /dev/null
+++ b/source/blender/editors/space_file/file_indexer.cc
@@ -0,0 +1,96 @@
+/*
+ * 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 edfile
+ *
+ * This file implements the default file browser indexer and has some helper function to work with
+ * `FileIndexerEntries`.
+ */
+#include "file_indexer.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_linklist.h"
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+namespace blender::ed::file::indexer {
+
+static eFileIndexerResult read_index(const char *UNUSED(file_name),
+ FileIndexerEntries *UNUSED(entries),
+ int *UNUSED(r_read_entries_len),
+ void *UNUSED(user_data))
+{
+ return FILE_INDEXER_NEEDS_UPDATE;
+}
+
+static void update_index(const char *UNUSED(file_name),
+ FileIndexerEntries *UNUSED(entries),
+ void *UNUSED(user_data))
+{
+}
+
+constexpr FileIndexerType default_indexer()
+{
+ FileIndexerType indexer = {nullptr};
+ indexer.read_index = read_index;
+ indexer.update_index = update_index;
+ return indexer;
+}
+
+static FileIndexerEntry *file_indexer_entry_create_from_datablock_info(
+ const BLODataBlockInfo *datablock_info, const int idcode)
+{
+ FileIndexerEntry *entry = static_cast<FileIndexerEntry *>(
+ MEM_mallocN(sizeof(FileIndexerEntry), __func__));
+ entry->datablock_info = *datablock_info;
+ entry->idcode = idcode;
+ return entry;
+}
+
+} // namespace blender::ed::file::indexer
+
+extern "C" {
+
+void ED_file_indexer_entries_extend_from_datablock_infos(
+ FileIndexerEntries *indexer_entries,
+ const LinkNode * /* BLODataBlockInfo */ datablock_infos,
+ const int idcode)
+{
+ for (const LinkNode *ln = datablock_infos; ln; ln = ln->next) {
+ const BLODataBlockInfo *datablock_info = static_cast<const BLODataBlockInfo *>(ln->link);
+ FileIndexerEntry *file_indexer_entry =
+ blender::ed::file::indexer::file_indexer_entry_create_from_datablock_info(datablock_info,
+ idcode);
+ BLI_linklist_prepend(&indexer_entries->entries, file_indexer_entry);
+ }
+}
+
+static void ED_file_indexer_entry_free(void *indexer_entry)
+{
+ MEM_freeN(indexer_entry);
+}
+
+void ED_file_indexer_entries_clear(FileIndexerEntries *indexer_entries)
+{
+ BLI_linklist_free(indexer_entries->entries, ED_file_indexer_entry_free);
+ indexer_entries->entries = nullptr;
+}
+
+const FileIndexerType file_indexer_noop = blender::ed::file::indexer::default_indexer();
+}
diff --git a/source/blender/blenkernel/intern/extern_implementations.cc b/source/blender/editors/space_file/file_indexer.h
index 07a4b6fc455..ea42f10498b 100644
--- a/source/blender/blenkernel/intern/extern_implementations.cc
+++ b/source/blender/editors/space_file/file_indexer.h
@@ -14,14 +14,23 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#include "BKE_attribute_access.hh"
+/** \file
+ * \ingroup edfile
+ */
+#pragma once
+
+#include "ED_file_indexer.h"
-namespace blender::bke {
+#ifdef __cplusplus
+extern "C" {
+#endif
-template class OutputAttribute_Typed<float>;
-template class OutputAttribute_Typed<int>;
-template class OutputAttribute_Typed<float3>;
-template class OutputAttribute_Typed<bool>;
-template class OutputAttribute_Typed<ColorGeometry4f>;
+/**
+ * Default indexer to use when listing files. The implementation is a no-operation indexing. When
+ * set it won't use indexing. It is added to increase the code clarity.
+ */
+extern const FileIndexerType file_indexer_noop;
-} // namespace blender::bke
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h
index 4be5d6d8008..3fe48157a09 100644
--- a/source/blender/editors/space_file/file_intern.h
+++ b/source/blender/editors/space_file/file_intern.h
@@ -41,20 +41,30 @@ struct uiLayout;
struct View2D;
/* file_draw.c */
+
#define ATTRIBUTE_COLUMN_PADDING (0.5f * UI_UNIT_X)
-#define SMALL_SIZE_CHECK(_size) ((_size) < 64) /* Related to FileSelectParams.thumbnail_size. */
+/** Related to #FileSelectParams.thumbnail_size. */
+#define SMALL_SIZE_CHECK(_size) ((_size) < 64)
void file_calc_previews(const bContext *C, ARegion *region);
void file_draw_list(const bContext *C, ARegion *region);
+/**
+ * Draw a string hint if the file list is invalid.
+ * \return true if the list is invalid and a hint was drawn.
+ */
bool file_draw_hint_if_invalid(const bContext *C, const SpaceFile *sfile, ARegion *region);
void file_draw_check_ex(bContext *C, struct ScrArea *area);
void file_draw_check(bContext *C);
+/**
+ * For use with; #UI_block_func_set.
+ */
void file_draw_check_cb(bContext *C, void *arg1, void *arg2);
bool file_draw_check_exists(SpaceFile *sfile);
/* file_ops.h */
+
struct wmOperator;
struct wmOperatorType;
@@ -72,6 +82,10 @@ void FILE_OT_bookmark_move(struct wmOperatorType *ot);
void FILE_OT_reset_recent(wmOperatorType *ot);
void FILE_OT_hidedot(struct wmOperatorType *ot);
void FILE_OT_execute(struct wmOperatorType *ot);
+/**
+ * Variation of #FILE_OT_execute that accounts for some mouse specific handling.
+ * Otherwise calls the same logic.
+ */
void FILE_OT_mouse_execute(struct wmOperatorType *ot);
void FILE_OT_cancel(struct wmOperatorType *ot);
void FILE_OT_parent(struct wmOperatorType *ot);
@@ -79,7 +93,6 @@ void FILE_OT_directory_new(struct wmOperatorType *ot);
void FILE_OT_previous(struct wmOperatorType *ot);
void FILE_OT_next(struct wmOperatorType *ot);
void FILE_OT_refresh(struct wmOperatorType *ot);
-void FILE_OT_asset_library_refresh(struct wmOperatorType *ot);
void FILE_OT_filenum(struct wmOperatorType *ot);
void FILE_OT_delete(struct wmOperatorType *ot);
void FILE_OT_rename(struct wmOperatorType *ot);
@@ -93,6 +106,9 @@ void file_filename_enter_handle(bContext *C, void *arg_unused, void *arg_but);
int file_highlight_set(struct SpaceFile *sfile, struct ARegion *region, int mx, int my);
+/**
+ * Use to set the file selector path from some arbitrary source.
+ */
void file_sfile_filepath_set(struct SpaceFile *sfile, const char *filepath);
void file_sfile_to_operator_ex(struct Main *bmain,
struct wmOperator *op,
@@ -103,17 +119,28 @@ void file_sfile_to_operator(struct Main *bmain, struct wmOperator *op, struct Sp
void file_operator_to_sfile(struct Main *bmain, struct SpaceFile *sfile, struct wmOperator *op);
/* space_file.c */
+
extern const char *file_context_dir[]; /* doc access */
/* filesel.c */
+
void fileselect_refresh_params(struct SpaceFile *sfile);
+/**
+ * Sets #FileSelectParams.file (name of selected file)
+ */
void fileselect_file_set(SpaceFile *sfile, const int index);
bool file_attribute_column_type_enabled(const FileSelectParams *params,
FileAttributeColumnType column);
+/**
+ * Check if the region coordinate defined by \a x and \a y are inside the column header.
+ */
bool file_attribute_column_header_is_inside(const struct View2D *v2d,
const FileLayout *layout,
int x,
int y);
+/**
+ * Find the column type at region coordinate given by \a x (y doesn't matter for this).
+ */
FileAttributeColumnType file_attribute_column_type_find_isect(const View2D *v2d,
const FileSelectParams *params,
FileLayout *layout,
@@ -130,13 +157,26 @@ void file_params_smoothscroll_timer_clear(struct wmWindowManager *wm,
struct wmWindow *win,
SpaceFile *sfile);
void file_params_renamefile_clear(struct FileSelectParams *params);
+/**
+ * Set the renaming-state to #FILE_PARAMS_RENAME_POSTSCROLL_PENDING and trigger the smooth-scroll
+ * timer. To be used right after a file was renamed.
+ * Note that the caller is responsible for setting the correct rename-file info
+ * (#FileSelectParams.renamefile or #FileSelectParams.rename_id).
+ */
void file_params_invoke_rename_postscroll(struct wmWindowManager *wm,
struct wmWindow *win,
SpaceFile *sfile);
+/**
+ * To be executed whenever renaming ends (successfully or not).
+ */
void file_params_rename_end(struct wmWindowManager *wm,
struct wmWindow *win,
SpaceFile *sfile,
struct FileDirEntry *rename_file);
+/**
+ * Helper used by both main update code, and smooth-scroll timer,
+ * to try to enable rename editing from #FileSelectParams.renamefile name.
+ */
void file_params_renamefile_activate(struct SpaceFile *sfile, struct FileSelectParams *params);
typedef void *onReloadFnData;
@@ -148,20 +188,27 @@ typedef struct SpaceFile_Runtime {
onReloadFnData on_reload_custom_data;
} SpaceFile_Runtime;
-/* Register an on-reload callback function. Note that there can only be one such function at a
- * time; registering a new one will overwrite the previous one. */
+/**
+ * Register an on-reload callback function. Note that there can only be one such function at a
+ * time; registering a new one will overwrite the previous one.
+ */
void file_on_reload_callback_register(struct SpaceFile *sfile,
onReloadFn callback,
onReloadFnData custom_data);
/* file_panels.c */
+
void file_tool_props_region_panels_register(struct ARegionType *art);
void file_execute_region_panels_register(struct ARegionType *art);
void file_tools_region_panels_register(struct ARegionType *art);
/* file_utils.c */
+
void file_tile_boundbox(const ARegion *region, FileLayout *layout, const int file, rcti *r_bounds);
+/**
+ * If \a path leads to a .blend, remove the trailing slash (if needed).
+ */
void file_path_to_ui_path(const char *path, char *r_pathi, int max_size);
/* asset_catalog_tree_view.cc */
@@ -173,7 +220,8 @@ FileAssetCatalogFilterSettingsHandle *file_create_asset_catalog_filter_settings(
void file_delete_asset_catalog_filter_settings(
FileAssetCatalogFilterSettingsHandle **filter_settings_handle);
/**
- * \return True if the stored filter settings were modified.
+ * \return True if the file list should update its filtered results
+ * (e.g. because filtering parameters changed).
*/
bool file_set_asset_catalog_filter_settings(
FileAssetCatalogFilterSettingsHandle *filter_settings_handle,
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index 844514759f3..8178e54e023 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -211,6 +211,11 @@ static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen)
filelist_setrecursion(sfile->files, params->recursion_level);
}
}
+ else if (file->redirection_path) {
+ BLI_strncpy(params->dir, file->redirection_path, sizeof(params->dir));
+ BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), params->dir);
+ BLI_path_slash_ensure(params->dir);
+ }
else {
BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), params->dir);
strcat(params->dir, file->relpath);
@@ -1413,8 +1418,13 @@ int file_highlight_set(SpaceFile *sfile, ARegion *region, int mx, int my)
return 0;
}
- numfiles = filelist_files_ensure(sfile->files);
params = ED_fileselect_get_active_params(sfile);
+ /* In case #SpaceFile.browse_mode just changed, the area may be pending a refresh still, which is
+ * what creates the params for the current browse mode. See T93508. */
+ if (!params) {
+ return false;
+ }
+ numfiles = filelist_files_ensure(sfile->files);
origfile = params->highlight_file;
@@ -1684,9 +1694,6 @@ void file_operator_to_sfile(Main *bmain, SpaceFile *sfile, wmOperator *op)
/* XXX, files and dirs updates missing, not really so important though */
}
-/**
- * Use to set the file selector path from some arbitrary source.
- */
void file_sfile_filepath_set(SpaceFile *sfile, const char *filepath)
{
FileSelectParams *params = ED_fileselect_get_active_params(sfile);
@@ -1736,7 +1743,6 @@ void file_draw_check(bContext *C)
file_draw_check_ex(C, area);
}
-/* for use with; UI_block_func_set */
void file_draw_check_cb(bContext *C, void *UNUSED(arg1), void *UNUSED(arg2))
{
file_draw_check(C);
@@ -1897,10 +1903,6 @@ static int file_execute_mouse_invoke(bContext *C, wmOperator *UNUSED(op), const
return OPERATOR_FINISHED;
}
-/**
- * Variation of #FILE_OT_execute that accounts for some mouse specific handling. Otherwise calls
- * the same logic.
- */
void FILE_OT_mouse_execute(wmOperatorType *ot)
{
/* identifiers */
@@ -1956,35 +1958,6 @@ void FILE_OT_refresh(struct wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Refresh Asset Library Operator
- * \{ */
-
-static int file_asset_library_refresh_exec(bContext *C, wmOperator *UNUSED(unused))
-{
- wmWindowManager *wm = CTX_wm_manager(C);
- SpaceFile *sfile = CTX_wm_space_file(C);
-
- ED_fileselect_clear(wm, sfile);
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void FILE_OT_asset_library_refresh(struct wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Refresh Asset Library";
- ot->description = "Reread assets and asset catalogs from the asset library on disk";
- ot->idname = "FILE_OT_asset_library_refresh";
-
- /* api callbacks */
- ot->exec = file_asset_library_refresh_exec;
- ot->poll = ED_operator_asset_browsing_active;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Navigate Parent Operator
* \{ */
@@ -2490,9 +2463,10 @@ static void file_expand_directory(bContext *C)
if (params) {
if (BLI_path_is_rel(params->dir)) {
/* Use of 'default' folder here is just to avoid an error message on '//' prefix. */
+ const char *blendfile_path = BKE_main_blendfile_path(bmain);
BLI_path_abs(params->dir,
- G.relbase_valid ? BKE_main_blendfile_path(bmain) :
- BKE_appdir_folder_default_or_root());
+ (blendfile_path[0] != '\0') ? blendfile_path :
+ BKE_appdir_folder_default_or_root());
}
else if (params->dir[0] == '~') {
char tmpstr[sizeof(params->dir) - 1];
diff --git a/source/blender/editors/space_file/file_panels.c b/source/blender/editors/space_file/file_panels.c
index 0e468718a04..7da9f65a1a2 100644
--- a/source/blender/editors/space_file/file_panels.c
+++ b/source/blender/editors/space_file/file_panels.c
@@ -41,6 +41,7 @@
#include "ED_fileselect.h"
#include "UI_interface.h"
+#include "UI_interface_icons.h"
#include "UI_resources.h"
#include "WM_api.h"
@@ -246,8 +247,21 @@ static void file_panel_asset_catalog_buttons_draw(const bContext *C, Panel *pane
RNA_pointer_create(&screen->id, &RNA_FileAssetSelectParams, params, &params_ptr);
uiItemR(row, &params_ptr, "asset_library_ref", 0, "", ICON_NONE);
- if (params->asset_library_ref.type != ASSET_LIBRARY_LOCAL) {
- uiItemO(row, "", ICON_FILE_REFRESH, "FILE_OT_asset_library_refresh");
+ if (params->asset_library_ref.type == ASSET_LIBRARY_LOCAL) {
+ bContext *mutable_ctx = CTX_copy(C);
+ if (WM_operator_name_poll(mutable_ctx, "asset.bundle_install")) {
+ uiItemS(col);
+ uiItemMenuEnumO(col,
+ mutable_ctx,
+ "asset.bundle_install",
+ "asset_library_ref",
+ "Copy Bundle to Asset Library...",
+ ICON_IMPORT);
+ }
+ CTX_free(mutable_ctx);
+ }
+ else {
+ uiItemO(row, "", ICON_FILE_REFRESH, "ASSET_OT_library_refresh");
}
uiItemS(col);
diff --git a/source/blender/editors/space_file/file_utils.c b/source/blender/editors/space_file/file_utils.c
index 186bc04fafe..fbe2426021b 100644
--- a/source/blender/editors/space_file/file_utils.c
+++ b/source/blender/editors/space_file/file_utils.c
@@ -46,9 +46,6 @@ void file_tile_boundbox(const ARegion *region, FileLayout *layout, const int fil
ymax);
}
-/**
- * If \a path leads to a .blend, remove the trailing slash (if needed).
- */
void file_path_to_ui_path(const char *path, char *r_path, int max_size)
{
char tmp_path[PATH_MAX];
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index b85dadf1f8e..e4ea832fe2f 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -89,6 +89,7 @@
#include "atomic_ops.h"
+#include "file_indexer.h"
#include "file_intern.h"
#include "filelist.h"
@@ -178,7 +179,6 @@ int folderlist_clear_next(struct SpaceFile *sfile)
return 1;
}
-/* not listbase itself */
void folderlist_free(ListBase *folderlist)
{
if (folderlist) {
@@ -352,9 +352,6 @@ typedef struct FileListEntryPreview {
char path[FILE_MAX];
uint flags;
int index;
- /* Some file types load the memory from runtime data, not from disk. We just wait until it's done
- * generating (BKE_previewimg_is_finished()). */
- PreviewImage *in_memory_preview;
int icon_id;
} FileListEntryPreview;
@@ -399,6 +396,11 @@ typedef struct FileList {
FileListFilter filter_data;
+ /**
+ * File indexer to use. Attribute is always set.
+ */
+ const struct FileIndexerType *indexer;
+
struct FileListIntern filelist_intern;
struct FileListEntryCache filelist_cache;
@@ -509,6 +511,53 @@ static int compare_apply_inverted(int val, const struct FileSortData *sort_data)
}
/**
+ * If all relevant characteristics match (e.g. the file type when sorting by file types), this
+ * should be used as tiebreaker. It makes sure there's a well defined sorting even in such cases.
+ *
+ * Multiple files with the same name can appear with recursive file loading and/or when displaying
+ * IDs of different types, so these cases need to be handled.
+ *
+ * 1) Sort files by name using natural sorting.
+ * 2) If not possible (file names match) and both represent local IDs, sort by ID-type.
+ * 3) If not possible and only one is a local ID, place files representing local IDs first.
+ *
+ * TODO (not actually implemented, but should be):
+ * 4) If no file represents a local ID, sort by file path, so that files higher up the file system
+ * hierarchy are placed first.
+ */
+static int compare_tiebreaker(const FileListInternEntry *entry1, const FileListInternEntry *entry2)
+{
+ /* Case 1. */
+ {
+ const int order = BLI_strcasecmp_natural(entry1->name, entry2->name);
+ if (order) {
+ return order;
+ }
+ }
+
+ /* Case 2. */
+ if (entry1->local_data.id && entry2->local_data.id) {
+ if (entry1->blentype < entry2->blentype) {
+ return -1;
+ }
+ if (entry1->blentype > entry2->blentype) {
+ return 1;
+ }
+ }
+ /* Case 3. */
+ {
+ if (entry1->local_data.id && !entry2->local_data.id) {
+ return -1;
+ }
+ if (!entry1->local_data.id && entry2->local_data.id) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/**
* Handles inverted sorting itself (currently there's nothing to invert), so if this returns non-0,
* it should be used as-is and not inverted.
*/
@@ -568,17 +617,13 @@ static int compare_name(void *user_data, const void *a1, const void *a2)
const FileListInternEntry *entry1 = a1;
const FileListInternEntry *entry2 = a2;
const struct FileSortData *sort_data = user_data;
- char *name1, *name2;
- int ret;
+ int ret;
if ((ret = compare_direntry_generic(entry1, entry2))) {
return ret;
}
- name1 = entry1->name;
- name2 = entry2->name;
-
- return compare_apply_inverted(BLI_strcasecmp_natural(name1, name2), sort_data);
+ return compare_apply_inverted(compare_tiebreaker(entry1, entry2), sort_data);
}
static int compare_date(void *user_data, const void *a1, const void *a2)
@@ -586,10 +631,9 @@ static int compare_date(void *user_data, const void *a1, const void *a2)
const FileListInternEntry *entry1 = a1;
const FileListInternEntry *entry2 = a2;
const struct FileSortData *sort_data = user_data;
- char *name1, *name2;
int64_t time1, time2;
- int ret;
+ int ret;
if ((ret = compare_direntry_generic(entry1, entry2))) {
return ret;
}
@@ -603,10 +647,7 @@ static int compare_date(void *user_data, const void *a1, const void *a2)
return compare_apply_inverted(-1, sort_data);
}
- name1 = entry1->name;
- name2 = entry2->name;
-
- return compare_apply_inverted(BLI_strcasecmp_natural(name1, name2), sort_data);
+ return compare_apply_inverted(compare_tiebreaker(entry1, entry2), sort_data);
}
static int compare_size(void *user_data, const void *a1, const void *a2)
@@ -614,7 +655,6 @@ static int compare_size(void *user_data, const void *a1, const void *a2)
const FileListInternEntry *entry1 = a1;
const FileListInternEntry *entry2 = a2;
const struct FileSortData *sort_data = user_data;
- char *name1, *name2;
uint64_t size1, size2;
int ret;
@@ -631,10 +671,7 @@ static int compare_size(void *user_data, const void *a1, const void *a2)
return compare_apply_inverted(-1, sort_data);
}
- name1 = entry1->name;
- name2 = entry2->name;
-
- return compare_apply_inverted(BLI_strcasecmp_natural(name1, name2), sort_data);
+ return compare_apply_inverted(compare_tiebreaker(entry1, entry2), sort_data);
}
static int compare_extension(void *user_data, const void *a1, const void *a2)
@@ -642,7 +679,6 @@ static int compare_extension(void *user_data, const void *a1, const void *a2)
const FileListInternEntry *entry1 = a1;
const FileListInternEntry *entry2 = a2;
const struct FileSortData *sort_data = user_data;
- char *name1, *name2;
int ret;
if ((ret = compare_direntry_generic(entry1, entry2))) {
@@ -690,10 +726,7 @@ static int compare_extension(void *user_data, const void *a1, const void *a2)
}
}
- name1 = entry1->name;
- name2 = entry2->name;
-
- return compare_apply_inverted(BLI_strcasecmp_natural(name1, name2), sort_data);
+ return compare_apply_inverted(compare_tiebreaker(entry1, entry2), sort_data);
}
void filelist_sort(struct FileList *filelist)
@@ -1128,10 +1161,14 @@ void filelist_setfilter_options(FileList *filelist,
}
}
-/**
- * \param catalog_id: The catalog that should be filtered by if \a catalog_visibility is
- * #FILE_SHOW_ASSETS_FROM_CATALOG. May be NULL otherwise.
- */
+void filelist_setindexer(FileList *filelist, const FileIndexerType *indexer)
+{
+ BLI_assert(filelist);
+ BLI_assert(indexer);
+
+ filelist->indexer = indexer;
+}
+
void filelist_set_asset_catalog_filter_options(
FileList *filelist,
eFileSel_Params_AssetCatalogVisibility catalog_visibility,
@@ -1171,9 +1208,6 @@ static bool filelist_compare_asset_libraries(const AssetLibraryReference *librar
return true;
}
-/**
- * \param asset_library_ref: May be NULL to unset the library.
- */
void filelist_setlibrary(FileList *filelist, const AssetLibraryReference *asset_library_ref)
{
/* Unset if needed. */
@@ -1351,7 +1385,7 @@ static int filelist_geticon_ex(const FileDirEntry *file,
}
if (typeflag & FILE_TYPE_BLENDER) {
- return ICON_FILE_BLEND;
+ return (is_main || file->preview_icon_id) ? ICON_FILE_BLEND : ICON_BLENDER;
}
if (typeflag & FILE_TYPE_BLENDER_BACKUP) {
return ICON_FILE_BACKUP;
@@ -1577,74 +1611,55 @@ static void filelist_cache_preview_runf(TaskPool *__restrict pool, void *taskdat
FileListEntryPreview *preview = preview_taskdata->preview;
ThumbSource source = 0;
- bool done = false;
// printf("%s: Start (%d)...\n", __func__, threadid);
- if (preview->in_memory_preview) {
- if (BKE_previewimg_is_finished(preview->in_memory_preview, ICON_SIZE_PREVIEW)) {
- ImBuf *imbuf = BKE_previewimg_to_imbuf(preview->in_memory_preview, ICON_SIZE_PREVIEW);
- if (imbuf) {
- preview->icon_id = BKE_icon_imbuf_create(imbuf);
- }
- done = true;
- }
- }
- else {
- // printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img);
- BLI_assert(preview->flags &
- (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT | FILE_TYPE_BLENDER |
- FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB));
+ // printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img);
+ BLI_assert(preview->flags &
+ (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT | FILE_TYPE_BLENDER |
+ FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB));
- if (preview->flags & FILE_TYPE_IMAGE) {
- source = THB_SOURCE_IMAGE;
- }
- else if (preview->flags &
- (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB)) {
- source = THB_SOURCE_BLEND;
- }
- else if (preview->flags & FILE_TYPE_MOVIE) {
- source = THB_SOURCE_MOVIE;
- }
- else if (preview->flags & FILE_TYPE_FTFONT) {
- source = THB_SOURCE_FONT;
- }
-
- IMB_thumb_path_lock(preview->path);
- /* Always generate biggest preview size for now, it's simpler and avoids having to re-generate
- * in case user switch to a bigger preview size. */
- ImBuf *imbuf = IMB_thumb_manage(preview->path, THB_LARGE, source);
- IMB_thumb_path_unlock(preview->path);
- if (imbuf) {
- preview->icon_id = BKE_icon_imbuf_create(imbuf);
- }
-
- done = true;
+ if (preview->flags & FILE_TYPE_IMAGE) {
+ source = THB_SOURCE_IMAGE;
+ }
+ else if (preview->flags &
+ (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB)) {
+ source = THB_SOURCE_BLEND;
+ }
+ else if (preview->flags & FILE_TYPE_MOVIE) {
+ source = THB_SOURCE_MOVIE;
+ }
+ else if (preview->flags & FILE_TYPE_FTFONT) {
+ source = THB_SOURCE_FONT;
}
- if (done) {
- /* That way task freeing function won't free th preview, since it does not own it anymore. */
- atomic_cas_ptr((void **)&preview_taskdata->preview, preview, NULL);
- BLI_thread_queue_push(cache->previews_done, preview);
- atomic_fetch_and_sub_z(&cache->previews_todo_count, 1);
+ IMB_thumb_path_lock(preview->path);
+ /* Always generate biggest preview size for now, it's simpler and avoids having to re-generate
+ * in case user switch to a bigger preview size. */
+ ImBuf *imbuf = IMB_thumb_manage(preview->path, THB_LARGE, source);
+ IMB_thumb_path_unlock(preview->path);
+ if (imbuf) {
+ preview->icon_id = BKE_icon_imbuf_create(imbuf);
}
+ /* Move ownership to the done queue. */
+ preview_taskdata->preview = NULL;
+
+ BLI_thread_queue_push(cache->previews_done, preview);
+ atomic_fetch_and_sub_z(&cache->previews_todo_count, 1);
+
// printf("%s: End (%d)...\n", __func__, threadid);
}
static void filelist_cache_preview_freef(TaskPool *__restrict UNUSED(pool), void *taskdata)
{
FileListEntryPreviewTaskData *preview_taskdata = taskdata;
- FileListEntryPreview *preview = preview_taskdata->preview;
- /* preview_taskdata->preview is atomically set to NULL once preview has been processed and sent
- * to previews_done queue. */
- if (preview != NULL) {
- if (preview->icon_id) {
- BKE_icon_delete(preview->icon_id);
- }
- MEM_freeN(preview);
+ /* In case the preview wasn't moved to the "done" queue yet. */
+ if (preview_taskdata->preview) {
+ MEM_freeN(preview_taskdata->preview);
}
+
MEM_freeN(preview_taskdata);
}
@@ -1719,34 +1734,51 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry
return;
}
- FileListEntryPreview *preview = MEM_mallocN(sizeof(*preview), __func__);
FileListInternEntry *intern_entry = filelist->filelist_intern.filtered[index];
-
- if (entry->redirection_path) {
- BLI_strncpy(preview->path, entry->redirection_path, FILE_MAXDIR);
- }
- else {
- BLI_join_dirfile(
- preview->path, sizeof(preview->path), filelist->filelist.root, entry->relpath);
+ PreviewImage *preview_in_memory = intern_entry->local_data.preview_image;
+ if (preview_in_memory && !BKE_previewimg_is_finished(preview_in_memory, ICON_SIZE_PREVIEW)) {
+ /* Nothing to set yet. Wait for next call. */
+ return;
}
+ filelist_cache_preview_ensure_running(cache);
+ entry->flags |= FILE_ENTRY_PREVIEW_LOADING;
+
+ FileListEntryPreview *preview = MEM_mallocN(sizeof(*preview), __func__);
preview->index = index;
preview->flags = entry->typeflag;
- preview->in_memory_preview = intern_entry->local_data.preview_image;
preview->icon_id = 0;
- // printf("%s: %d - %s\n", __func__, preview->index, preview->path);
- filelist_cache_preview_ensure_running(cache);
+ if (preview_in_memory) {
+ /* TODO(mano-wii): No need to use the thread API here. */
+ BLI_assert(BKE_previewimg_is_finished(preview_in_memory, ICON_SIZE_PREVIEW));
+ preview->path[0] = '\0';
+ ImBuf *imbuf = BKE_previewimg_to_imbuf(preview_in_memory, ICON_SIZE_PREVIEW);
+ if (imbuf) {
+ preview->icon_id = BKE_icon_imbuf_create(imbuf);
+ }
+ BLI_thread_queue_push(cache->previews_done, preview);
+ atomic_fetch_and_sub_z(&cache->previews_todo_count, 1);
+ }
+ else {
+ if (entry->redirection_path) {
+ BLI_strncpy(preview->path, entry->redirection_path, FILE_MAXDIR);
+ }
+ else {
+ BLI_join_dirfile(
+ preview->path, sizeof(preview->path), filelist->filelist.root, entry->relpath);
+ }
+ // printf("%s: %d - %s\n", __func__, preview->index, preview->path);
- FileListEntryPreviewTaskData *preview_taskdata = MEM_mallocN(sizeof(*preview_taskdata),
- __func__);
- preview_taskdata->preview = preview;
- entry->flags |= FILE_ENTRY_PREVIEW_LOADING;
- BLI_task_pool_push(cache->previews_pool,
- filelist_cache_preview_runf,
- preview_taskdata,
- true,
- filelist_cache_preview_freef);
+ FileListEntryPreviewTaskData *preview_taskdata = MEM_mallocN(sizeof(*preview_taskdata),
+ __func__);
+ preview_taskdata->preview = preview;
+ BLI_task_pool_push(cache->previews_pool,
+ filelist_cache_preview_runf,
+ preview_taskdata,
+ true,
+ filelist_cache_preview_freef);
+ }
}
static void filelist_cache_init(FileListEntryCache *cache, size_t cache_size)
@@ -1844,6 +1876,8 @@ FileList *filelist_new(short type)
p->filelist.nbr_entries = FILEDIR_NBR_ENTRIES_UNSET;
filelist_settype(p, type);
+ p->indexer = &file_indexer_noop;
+
return p;
}
@@ -1963,10 +1997,6 @@ void filelist_clear(FileList *filelist)
filelist_clear_ex(filelist, true, true, true);
}
-/**
- * A "smarter" version of #filelist_clear() that calls partial clearing based on the filelist
- * force-reset flags.
- */
void filelist_clear_from_reset_tag(FileList *filelist)
{
/* Do a full clear if needed. */
@@ -2073,9 +2103,6 @@ bool filelist_is_dir(struct FileList *filelist, const char *path)
return filelist->check_dir_fn(filelist, (char *)path, false);
}
-/**
- * May modify in place given r_dir, which is expected to be FILE_MAX_LIBEXTRA length.
- */
void filelist_setdir(struct FileList *filelist, char *r_dir)
{
const bool allow_invalid = filelist->asset_library_ref != NULL;
@@ -2133,12 +2160,6 @@ bool filelist_needs_reset_on_main_changes(const FileList *filelist)
return (filelist->tags & FILELIST_TAGS_USES_MAIN_DATA) != 0;
}
-/**
- * Limited version of full update done by space_file's file_refresh(),
- * to be used by operators and such.
- * Ensures given filelist is ready to be used (i.e. it is filtered and sorted),
- * unless it is tagged for a full refresh.
- */
int filelist_files_ensure(FileList *filelist)
{
if (!filelist_needs_force_reset(filelist) || !filelist_needs_reading(filelist)) {
@@ -2251,10 +2272,6 @@ FileDirEntry *filelist_file(struct FileList *filelist, int index)
return filelist_file_ex(filelist, index, true);
}
-/**
- * Find a file from a file name, or more precisely, its file-list relative path, inside the
- * filtered items. \return The index of the found file or -1.
- */
int filelist_file_find_path(struct FileList *filelist, const char *filename)
{
if (filelist->filelist.nbr_entries_filtered == FILEDIR_NBR_ENTRIES_UNSET) {
@@ -2275,10 +2292,6 @@ int filelist_file_find_path(struct FileList *filelist, const char *filename)
return -1;
}
-/**
- * Find a file representing \a id.
- * \return The index of the found file or -1.
- */
int filelist_file_find_id(const FileList *filelist, const ID *id)
{
if (filelist->filelist.nbr_entries_filtered == FILEDIR_NBR_ENTRIES_UNSET) {
@@ -2295,9 +2308,6 @@ int filelist_file_find_id(const FileList *filelist, const ID *id)
return -1;
}
-/**
- * Get the ID a file represents (if any). For #FILE_MAIN, #FILE_MAIN_ASSET.
- */
ID *filelist_file_get_id(const FileDirEntry *file)
{
return file->id;
@@ -2393,7 +2403,6 @@ static void filelist_file_cache_block_release(struct FileList *filelist,
}
}
-/* Load in cache all entries "around" given index (as much as block cache may hold). */
bool filelist_file_cache_block(struct FileList *filelist, const int index)
{
FileListEntryCache *cache = &filelist->filelist_cache;
@@ -2661,7 +2670,6 @@ bool filelist_cache_previews_update(FileList *filelist)
// printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img);
if (entry) {
- entry->flags &= ~FILE_ENTRY_PREVIEW_LOADING;
if (preview->icon_id) {
/* The FILE_ENTRY_PREVIEW_LOADING flag should have prevented any other asynchronous
* process from trying to generate the same preview icon. */
@@ -2678,6 +2686,7 @@ bool filelist_cache_previews_update(FileList *filelist)
* preview will be retried quite often anyway. */
entry->flags |= FILE_ENTRY_INVALID_PREVIEW;
}
+ entry->flags &= ~FILE_ENTRY_PREVIEW_LOADING;
}
else {
BKE_icon_delete(preview->icon_id);
@@ -2736,8 +2745,6 @@ static bool file_is_blend_backup(const char *str)
return retval;
}
-/* TODO: Maybe we should move this to BLI?
- * On the other hand, it's using defines from space-file area, so not sure... */
int ED_path_extension_type(const char *path)
{
if (BLO_has_bfile_extension(path)) {
@@ -2965,9 +2972,6 @@ bool filelist_entry_is_selected(FileList *filelist, const int index)
return selection_state != 0;
}
-/**
- * Set selection of the '..' parent entry, but only if it's actually visible.
- */
void filelist_entry_parent_select_set(FileList *filelist,
FileSelType select,
uint flag,
@@ -2978,7 +2982,6 @@ void filelist_entry_parent_select_set(FileList *filelist,
}
}
-/* WARNING! dir must be FILE_MAX_LIBEXTRA long! */
bool filelist_islibrary(struct FileList *filelist, char *dir, char **r_group)
{
return BLO_library_path_explode(filelist->filelist.root, dir, r_group, NULL);
@@ -3134,6 +3137,29 @@ static FileListInternEntry *filelist_readjob_list_lib_group_create(const int idc
return entry;
}
+static void filelist_readjob_list_lib_add_datablock(ListBase *entries,
+ const BLODataBlockInfo *datablock_info,
+ const bool prefix_relpath_with_group_name,
+ const int idcode,
+ const char *group_name)
+{
+ FileListInternEntry *entry = MEM_callocN(sizeof(*entry), __func__);
+ if (prefix_relpath_with_group_name) {
+ entry->relpath = BLI_sprintfN("%s/%s", group_name, datablock_info->name);
+ }
+ else {
+ entry->relpath = BLI_strdup(datablock_info->name);
+ }
+ entry->typeflag |= FILE_TYPE_BLENDERLIB;
+ if (datablock_info && datablock_info->asset_data) {
+ entry->typeflag |= FILE_TYPE_ASSET;
+ /* Moves ownership! */
+ entry->imported_asset_data = datablock_info->asset_data;
+ }
+ entry->blentype = idcode;
+ BLI_addtail(entries, entry);
+}
+
static void filelist_readjob_list_lib_add_datablocks(ListBase *entries,
LinkNode *datablock_infos,
const bool prefix_relpath_with_group_name,
@@ -3141,29 +3167,71 @@ static void filelist_readjob_list_lib_add_datablocks(ListBase *entries,
const char *group_name)
{
for (LinkNode *ln = datablock_infos; ln; ln = ln->next) {
- struct BLODataBlockInfo *info = ln->link;
- FileListInternEntry *entry = MEM_callocN(sizeof(*entry), __func__);
- if (prefix_relpath_with_group_name) {
- entry->relpath = BLI_sprintfN("%s/%s", group_name, info->name);
- }
- else {
- entry->relpath = BLI_strdup(info->name);
- }
- entry->typeflag |= FILE_TYPE_BLENDERLIB;
- if (info && info->asset_data) {
- entry->typeflag |= FILE_TYPE_ASSET;
- /* Moves ownership! */
- entry->imported_asset_data = info->asset_data;
- }
- entry->blentype = idcode;
+ struct BLODataBlockInfo *datablock_info = ln->link;
+ filelist_readjob_list_lib_add_datablock(
+ entries, datablock_info, prefix_relpath_with_group_name, idcode, group_name);
+ }
+}
+
+static void filelist_readjob_list_lib_add_from_indexer_entries(
+ ListBase *entries,
+ const FileIndexerEntries *indexer_entries,
+ const bool prefix_relpath_with_group_name)
+{
+ for (const LinkNode *ln = indexer_entries->entries; ln; ln = ln->next) {
+ const FileIndexerEntry *indexer_entry = (const FileIndexerEntry *)ln->link;
+ const char *group_name = BKE_idtype_idcode_to_name(indexer_entry->idcode);
+ filelist_readjob_list_lib_add_datablock(entries,
+ &indexer_entry->datablock_info,
+ prefix_relpath_with_group_name,
+ indexer_entry->idcode,
+ group_name);
+ }
+}
+
+static FileListInternEntry *filelist_readjob_list_lib_navigate_to_parent_entry_create(void)
+{
+ FileListInternEntry *entry = MEM_callocN(sizeof(*entry), __func__);
+ entry->relpath = BLI_strdup(FILENAME_PARENT);
+ entry->typeflag |= (FILE_TYPE_BLENDERLIB | FILE_TYPE_DIR);
+ return entry;
+}
+
+/**
+ * Structure to keep the file indexer and its user data together.
+ */
+typedef struct FileIndexer {
+ const FileIndexerType *callbacks;
+
+ /**
+ * User data. Contains the result of `callbacks.init_user_data`.
+ */
+ void *user_data;
+} FileIndexer;
+
+static int filelist_readjob_list_lib_populate_from_index(ListBase *entries,
+ const ListLibOptions options,
+ const int read_from_index,
+ const FileIndexerEntries *indexer_entries)
+{
+ int navigate_to_parent_len = 0;
+ if (options & LIST_LIB_ADD_PARENT) {
+ FileListInternEntry *entry = filelist_readjob_list_lib_navigate_to_parent_entry_create();
BLI_addtail(entries, entry);
+ navigate_to_parent_len = 1;
}
+
+ filelist_readjob_list_lib_add_from_indexer_entries(entries, indexer_entries, true);
+ return read_from_index + navigate_to_parent_len;
}
static int filelist_readjob_list_lib(const char *root,
ListBase *entries,
- const ListLibOptions options)
+ const ListLibOptions options,
+ FileIndexer *indexer_runtime)
{
+ BLI_assert(indexer_runtime);
+
char dir[FILE_MAX_LIBEXTRA], *group;
struct BlendHandle *libfiledata = NULL;
@@ -3171,13 +3239,37 @@ static int filelist_readjob_list_lib(const char *root,
/* Check if the given root is actually a library. All folders are passed to
* `filelist_readjob_list_lib` and based on the number of found entries `filelist_readjob_do`
* will do a dir listing only when this function does not return any entries. */
- /* TODO: We should consider introducing its own function to detect if it is a lib and
+ /* TODO(jbakker): We should consider introducing its own function to detect if it is a lib and
* call it directly from `filelist_readjob_do` to increase readability. */
const bool is_lib = BLO_library_path_explode(root, dir, &group, NULL);
if (!is_lib) {
return 0;
}
+ const bool group_came_from_path = group != NULL;
+
+ /* Try read from indexer_runtime. */
+ /* Indexing returns all entries in a blend file. We should ignore the index when listing a group
+ * inside a blend file, so the `entries` isn't filled with undesired entries.
+ * This happens when linking or appending data-blocks, where you can navigate into a group (ie
+ * Materials/Objects) where you only want to work with partial indexes.
+ *
+ * Adding support for partial reading/updating indexes would increase the complexity.
+ */
+ const bool use_indexer = !group_came_from_path;
+ FileIndexerEntries indexer_entries = {NULL};
+ if (use_indexer) {
+ int read_from_index = 0;
+ eFileIndexerResult indexer_result = indexer_runtime->callbacks->read_index(
+ dir, &indexer_entries, &read_from_index, indexer_runtime->user_data);
+ if (indexer_result == FILE_INDEXER_ENTRIES_LOADED) {
+ int entries_read = filelist_readjob_list_lib_populate_from_index(
+ entries, options, read_from_index, &indexer_entries);
+ ED_file_indexer_entries_clear(&indexer_entries);
+ return entries_read;
+ }
+ }
+
/* Open the library file. */
BlendFileReadReport bf_reports = {.reports = NULL};
libfiledata = BLO_blendhandle_from_file(dir, &bf_reports);
@@ -3186,18 +3278,18 @@ static int filelist_readjob_list_lib(const char *root,
}
/* Add current parent when requested. */
- int parent_len = 0;
+ /* Is the navigate to previous level added to the list of entries. When added the return value
+ * should be increased to match the actual number of entries added. It is introduced to keep
+ * the code clean and readable and not counting in a single variable. */
+ int navigate_to_parent_len = 0;
if (options & LIST_LIB_ADD_PARENT) {
- FileListInternEntry *entry = MEM_callocN(sizeof(*entry), __func__);
- entry->relpath = BLI_strdup(FILENAME_PARENT);
- entry->typeflag |= (FILE_TYPE_BLENDERLIB | FILE_TYPE_DIR);
+ FileListInternEntry *entry = filelist_readjob_list_lib_navigate_to_parent_entry_create();
BLI_addtail(entries, entry);
- parent_len = 1;
+ navigate_to_parent_len = 1;
}
int group_len = 0;
int datablock_len = 0;
- const bool group_came_from_path = group != NULL;
if (group_came_from_path) {
const int idcode = groupname_to_code(group);
LinkNode *datablock_infos = BLO_blendhandle_get_datablock_info(
@@ -3222,6 +3314,10 @@ static int filelist_readjob_list_lib(const char *root,
libfiledata, idcode, options & LIST_LIB_ASSETS_ONLY, &group_datablock_len);
filelist_readjob_list_lib_add_datablocks(
entries, group_datablock_infos, true, idcode, group_name);
+ if (use_indexer) {
+ ED_file_indexer_entries_extend_from_datablock_infos(
+ &indexer_entries, group_datablock_infos, idcode);
+ }
BLI_linklist_freeN(group_datablock_infos);
datablock_len += group_datablock_len;
}
@@ -3232,8 +3328,14 @@ static int filelist_readjob_list_lib(const char *root,
BLO_blendhandle_close(libfiledata);
+ /* Update the index. */
+ if (use_indexer) {
+ indexer_runtime->callbacks->update_index(dir, &indexer_entries, indexer_runtime->user_data);
+ ED_file_indexer_entries_clear(&indexer_entries);
+ }
+
/* Return the number of items added to entries. */
- int added_entries_len = group_len + datablock_len + parent_len;
+ int added_entries_len = group_len + datablock_len + navigate_to_parent_len;
return added_entries_len;
}
@@ -3425,11 +3527,11 @@ typedef struct FileListReadJob {
* The job system calls #filelist_readjob_update which moves any read file from #tmp_filelist
* into #filelist in a thread-safe way.
*
- * #tmp_filelist also keeps an `AssetLibrary *` so that it can be loaded in the same thread, and
- * moved to #filelist once all categories are loaded.
+ * #tmp_filelist also keeps an `AssetLibrary *` so that it can be loaded in the same thread,
+ * and moved to #filelist once all categories are loaded.
*
- * NOTE: #tmp_filelist is freed in #filelist_readjob_free, so any copied pointers need to be set
- * to NULL to avoid double-freeing them. */
+ * NOTE: #tmp_filelist is freed in #filelist_readjob_free, so any copied pointers need to be
+ * set to NULL to avoid double-freeing them. */
struct FileList *tmp_filelist;
} FileListReadJob;
@@ -3466,8 +3568,8 @@ static bool filelist_readjob_should_recurse_into_entry(const int max_recursion,
/* No more levels of recursion left. */
return false;
}
- /* Show entries when recursion is set to `Blend file` even when `current_recursion_level` exceeds
- * `max_recursion`. */
+ /* Show entries when recursion is set to `Blend file` even when `current_recursion_level`
+ * exceeds `max_recursion`. */
if (!is_lib && (current_recursion_level >= max_recursion) &&
((entry->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) == 0)) {
return false;
@@ -3515,6 +3617,12 @@ static void filelist_readjob_recursive_dir_add_items(const bool do_lib,
BLI_path_normalize_dir(job_params->main_name, dir);
td_dir->dir = BLI_strdup(dir);
+ /* Init the file indexer. */
+ FileIndexer indexer_runtime = {.callbacks = filelist->indexer};
+ if (indexer_runtime.callbacks->init_user_data) {
+ indexer_runtime.user_data = indexer_runtime.callbacks->init_user_data(dir, sizeof(dir));
+ }
+
while (!BLI_stack_is_empty(todo_dirs) && !(*stop)) {
FileListInternEntry *entry;
int nbr_entries = 0;
@@ -3557,7 +3665,8 @@ static void filelist_readjob_recursive_dir_add_items(const bool do_lib,
if (filelist->asset_library_ref) {
list_lib_options |= LIST_LIB_ASSETS_ONLY;
}
- nbr_entries = filelist_readjob_list_lib(subdir, &entries, list_lib_options);
+ nbr_entries = filelist_readjob_list_lib(
+ subdir, &entries, list_lib_options, &indexer_runtime);
if (nbr_entries > 0) {
is_lib = true;
}
@@ -3599,6 +3708,15 @@ static void filelist_readjob_recursive_dir_add_items(const bool do_lib,
MEM_freeN(subdir);
}
+ /* Finalize and free indexer. */
+ if (indexer_runtime.callbacks->filelist_finished && BLI_stack_is_empty(todo_dirs)) {
+ indexer_runtime.callbacks->filelist_finished(indexer_runtime.user_data);
+ }
+ if (indexer_runtime.callbacks->free_user_data && indexer_runtime.user_data) {
+ indexer_runtime.callbacks->free_user_data(indexer_runtime.user_data);
+ indexer_runtime.user_data = NULL;
+ }
+
/* If we were interrupted by stop, stack may not be empty and we need to free
* pending dir paths. */
while (!BLI_stack_is_empty(todo_dirs)) {
@@ -3741,8 +3859,8 @@ static void filelist_readjob_main_assets_add_items(FileListReadJob *job_params,
*/
static bool filelist_contains_main(const FileList *filelist, const Main *bmain)
{
- const char *main_path = BKE_main_blendfile_path(bmain);
- return main_path[0] && BLI_path_contains(filelist->filelist.root, main_path);
+ const char *blendfile_path = BKE_main_blendfile_path(bmain);
+ return blendfile_path[0] && BLI_path_contains(filelist->filelist.root, blendfile_path);
}
static void filelist_readjob_asset_library(FileListReadJob *job_params,
@@ -3949,7 +4067,13 @@ void filelist_readjob_start(FileList *filelist, const int space_notifier, const
/* Init even for single threaded execution. Called functions use it. */
BLI_mutex_init(&flrj->lock);
- if (filelist->tags & FILELIST_TAGS_NO_THREADS) {
+ /* The file list type may not support threading so execute immediately. Same when only rereading
+ * #Main data (which we do quite often on changes to #Main, since it's the easiest and safest way
+ * to ensure the displayed data is up to date), because some operations executing right after
+ * main data changed may need access to the ID files (see T93691). */
+ const bool no_threads = (filelist->tags & FILELIST_TAGS_NO_THREADS) || flrj->only_main_data;
+
+ if (no_threads) {
short dummy_stop = false;
short dummy_do_update = false;
float dummy_progress = 0.0f;
diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h
index 0048a349dca..0119a9b4f52 100644
--- a/source/blender/editors/space_file/filelist.h
+++ b/source/blender/editors/space_file/filelist.h
@@ -29,6 +29,7 @@ extern "C" {
struct AssetLibraryReference;
struct BlendHandle;
+struct FileIndexerType;
struct FileList;
struct FileSelection;
struct bUUID;
@@ -50,6 +51,7 @@ typedef enum FileCheckType {
CHECK_ALL = 3,
} FileCheckType;
+/* not listbase itself */
void folderlist_free(struct ListBase *folderlist);
void folderlist_popdir(struct ListBase *folderlist, char *dir);
void folderlist_pushdir(struct ListBase *folderlist, const char *dir);
@@ -72,12 +74,25 @@ void filelist_setfilter_options(struct FileList *filelist,
const bool filter_assets_only,
const char *filter_glob,
const char *filter_search);
+/**
+ * Set the indexer to be used by the filelist.
+ *
+ * The given indexer allocation should be handled by the caller or defined statically.
+ */
+void filelist_setindexer(struct FileList *filelist, const struct FileIndexerType *indexer);
+/**
+ * \param catalog_id: The catalog that should be filtered by if \a catalog_visibility is
+ * #FILE_SHOW_ASSETS_FROM_CATALOG. May be NULL otherwise.
+ */
void filelist_set_asset_catalog_filter_options(
struct FileList *filelist,
eFileSel_Params_AssetCatalogVisibility catalog_visibility,
const struct bUUID *catalog_id);
void filelist_tag_needs_filtering(struct FileList *filelist);
void filelist_filter(struct FileList *filelist);
+/**
+ * \param asset_library_ref: May be NULL to unset the library.
+ */
void filelist_setlibrary(struct FileList *filelist,
const struct AssetLibraryReference *asset_library_ref);
@@ -96,24 +111,51 @@ void filelist_clear_ex(struct FileList *filelist,
const bool do_asset_library,
const bool do_cache,
const bool do_selection);
+/**
+ * A "smarter" version of #filelist_clear() that calls partial clearing based on the filelist
+ * force-reset flags.
+ */
void filelist_clear_from_reset_tag(struct FileList *filelist);
void filelist_free(struct FileList *filelist);
const char *filelist_dir(struct FileList *filelist);
bool filelist_is_dir(struct FileList *filelist, const char *path);
+/**
+ * May modify in place given r_dir, which is expected to be FILE_MAX_LIBEXTRA length.
+ */
void filelist_setdir(struct FileList *filelist, char *r_dir);
+/**
+ * Limited version of full update done by space_file's file_refresh(),
+ * to be used by operators and such.
+ * Ensures given filelist is ready to be used (i.e. it is filtered and sorted),
+ * unless it is tagged for a full refresh.
+ */
int filelist_files_ensure(struct FileList *filelist);
int filelist_needs_reading(struct FileList *filelist);
FileDirEntry *filelist_file(struct FileList *filelist, int index);
FileDirEntry *filelist_file_ex(struct FileList *filelist, int index, bool use_request);
+/**
+ * Find a file from a file name, or more precisely, its file-list relative path, inside the
+ * filtered items. \return The index of the found file or -1.
+ */
int filelist_file_find_path(struct FileList *filelist, const char *file);
+/**
+ * Find a file representing \a id.
+ * \return The index of the found file or -1.
+ */
int filelist_file_find_id(const struct FileList *filelist, const struct ID *id);
+/**
+ * Get the ID a file represents (if any). For #FILE_MAIN, #FILE_MAIN_ASSET.
+ */
struct ID *filelist_file_get_id(const struct FileDirEntry *file);
bool filelist_uid_is_set(const FileUID uid);
void filelist_uid_unset(FileUID *r_uid);
void filelist_file_cache_slidingwindow_set(struct FileList *filelist, size_t window_size);
+/**
+ * Load in cache all entries "around" given index (as much as block cache may hold).
+ */
bool filelist_file_cache_block(struct FileList *filelist, const int index);
bool filelist_needs_force_reset(struct FileList *filelist);
@@ -145,6 +187,9 @@ unsigned int filelist_entry_select_index_get(struct FileList *filelist,
const int index,
FileCheckType check);
bool filelist_entry_is_selected(struct FileList *filelist, const int index);
+/**
+ * Set selection of the '..' parent entry, but only if it's actually visible.
+ */
void filelist_entry_parent_select_set(struct FileList *filelist,
FileSelType select,
unsigned int flag,
@@ -155,6 +200,9 @@ void filelist_setrecursion(struct FileList *filelist, const int recursion_level)
struct AssetLibrary *filelist_asset_library(struct FileList *filelist);
struct BlendHandle *filelist_lib(struct FileList *filelist);
+/**
+ * \param dir: Must be #FILE_MAX_LIBEXTRA long!
+ */
bool filelist_islibrary(struct FileList *filelist, char *dir, char **r_group);
void filelist_freelib(struct FileList *filelist);
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index 11757975a62..e3ac5840da3 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -358,9 +358,6 @@ static FileSelectParams *fileselect_ensure_updated_file_params(SpaceFile *sfile)
return params;
}
-/**
- * If needed, create and return the file select parameters for the active browse mode.
- */
FileSelectParams *ED_fileselect_ensure_active_params(SpaceFile *sfile)
{
switch ((eFileBrowse_Mode)sfile->browse_mode) {
@@ -380,9 +377,6 @@ FileSelectParams *ED_fileselect_ensure_active_params(SpaceFile *sfile)
return NULL;
}
-/**
- * Get the file select parameters for the active browse mode.
- */
FileSelectParams *ED_fileselect_get_active_params(const SpaceFile *sfile)
{
if (!sfile) {
@@ -411,6 +405,15 @@ FileAssetSelectParams *ED_fileselect_get_asset_params(const SpaceFile *sfile)
return (sfile->browse_mode == FILE_BROWSE_MODE_ASSETS) ? sfile->asset_params : NULL;
}
+bool ED_fileselect_is_local_asset_library(const SpaceFile *sfile)
+{
+ const FileAssetSelectParams *asset_params = ED_fileselect_get_asset_params(sfile);
+ if (asset_params == NULL) {
+ return false;
+ }
+ return asset_params->asset_library_ref.type == ASSET_LIBRARY_LOCAL;
+}
+
static void fileselect_refresh_asset_params(FileAssetSelectParams *asset_params)
{
AssetLibraryReference *library = &asset_params->asset_library_ref;
@@ -638,13 +641,6 @@ void ED_fileselect_set_params_from_userdef(SpaceFile *sfile)
}
}
-/**
- * Update the user-preference data for the file space. In fact, this also contains some
- * non-FileSelectParams data, but we can safely ignore this.
- *
- * \param temp_win_size: If the browser was opened in a temporary window,
- * pass its size here so we can store that in the preferences. Otherwise NULL.
- */
void ED_fileselect_params_to_userdef(SpaceFile *sfile,
const int temp_win_size[2],
const bool is_maximized)
@@ -682,9 +678,6 @@ void ED_fileselect_params_to_userdef(SpaceFile *sfile,
}
}
-/**
- * Sets FileSelectParams->file (name of selected file)
- */
void fileselect_file_set(SpaceFile *sfile, const int index)
{
const struct FileDirEntry *file = filelist_file(sfile->files, index);
@@ -805,10 +798,6 @@ int ED_fileselect_layout_offset(FileLayout *layout, int x, int y)
return active_file;
}
-/**
- * Get the currently visible bounds of the layout in screen space. Matches View2D.mask minus the
- * top column-header row.
- */
void ED_fileselect_layout_maskrect(const FileLayout *layout, const View2D *v2d, rcti *r_rect)
{
*r_rect = v2d->mask;
@@ -848,9 +837,6 @@ void ED_fileselect_layout_tilepos(FileLayout *layout, int tile, int *x, int *y)
}
}
-/**
- * Check if the region coordinate defined by \a x and \a y are inside the column header.
- */
bool file_attribute_column_header_is_inside(const View2D *v2d,
const FileLayout *layout,
int x,
@@ -877,9 +863,6 @@ bool file_attribute_column_type_enabled(const FileSelectParams *params,
}
}
-/**
- * Find the column type at region coordinate given by \a x (y doesn't matter for this).
- */
FileAttributeColumnType file_attribute_column_type_find_isect(const View2D *v2d,
const FileSelectParams *params,
FileLayout *layout,
@@ -1096,10 +1079,6 @@ FileLayout *ED_fileselect_get_layout(struct SpaceFile *sfile, ARegion *region)
return sfile->layout;
}
-/**
- * Support updating the directory even when this isn't the active space
- * needed so RNA properties update function isn't context sensitive, see T70255.
- */
void ED_file_change_dir_ex(bContext *C, ScrArea *area)
{
/* May happen when manipulating non-active spaces. */
@@ -1295,12 +1274,6 @@ void file_params_smoothscroll_timer_clear(wmWindowManager *wm, wmWindow *win, Sp
sfile->smoothscroll_timer = NULL;
}
-/**
- * Set the renaming-state to #FILE_PARAMS_RENAME_POSTSCROLL_PENDING and trigger the smooth-scroll
- * timer. To be used right after a file was renamed.
- * Note that the caller is responsible for setting the correct rename-file info
- * (#FileSelectParams.renamefile or #FileSelectParams.rename_id).
- */
void file_params_invoke_rename_postscroll(wmWindowManager *wm, wmWindow *win, SpaceFile *sfile)
{
FileSelectParams *params = ED_fileselect_get_active_params(sfile);
@@ -1314,9 +1287,6 @@ void file_params_invoke_rename_postscroll(wmWindowManager *wm, wmWindow *win, Sp
sfile->scroll_offset = 0;
}
-/**
- * To be executed whenever renaming ends (successfully or not).
- */
void file_params_rename_end(wmWindowManager *wm,
wmWindow *win,
SpaceFile *sfile,
@@ -1348,10 +1318,6 @@ static int file_params_find_renamed(const FileSelectParams *params, struct FileL
filelist_file_find_path(filelist, params->renamefile);
}
-/**
- * Helper used by both main update code, and smooth-scroll timer,
- * to try to enable rename editing from #FileSelectParams.renamefile name.
- */
void file_params_renamefile_activate(SpaceFile *sfile, FileSelectParams *params)
{
BLI_assert(params->rename_flag != 0);
@@ -1363,7 +1329,7 @@ void file_params_renamefile_activate(SpaceFile *sfile, FileSelectParams *params)
BLI_assert(params->renamefile[0] != '\0' || params->rename_id != NULL);
- const int idx = file_params_find_renamed(params, sfile->files);
+ int idx = file_params_find_renamed(params, sfile->files);
if (idx >= 0) {
FileDirEntry *file = filelist_file(sfile->files, idx);
BLI_assert(file != NULL);
@@ -1376,7 +1342,11 @@ void file_params_renamefile_activate(SpaceFile *sfile, FileSelectParams *params)
params->rename_flag = FILE_PARAMS_RENAME_ACTIVE;
}
else if ((params->rename_flag & FILE_PARAMS_RENAME_POSTSCROLL_PENDING) != 0) {
+ /* file_select_deselect_all() will resort and re-filter, so `idx` will probably have changed.
+ * Need to get the correct #FileDirEntry again. */
file_select_deselect_all(sfile, FILE_SEL_SELECTED);
+ idx = file_params_find_renamed(params, sfile->files);
+ file = filelist_file(sfile->files, idx);
filelist_entry_select_set(
sfile->files, file, FILE_SEL_ADD, FILE_SEL_SELECTED | FILE_SEL_HIGHLIGHTED, CHECK_ALL);
params->active_file = idx;
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index b115c63a569..bbf3c6f768c 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -27,6 +27,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
+#include "BLI_linklist.h"
#include "BLI_utildefines.h"
#include "BKE_appdir.h"
@@ -44,6 +45,7 @@
#include "WM_types.h"
#include "ED_asset.h"
+#include "ED_asset_indexer.h"
#include "ED_fileselect.h"
#include "ED_screen.h"
#include "ED_space_api.h"
@@ -59,6 +61,10 @@
#include "filelist.h"
#include "fsmenu.h"
+/* Enable asset indexing. Currently disabled as ID properties aren't indexed yet and is needed for
+ * object snapping. See {D12990}. */
+//#define SPACE_FILE_ENABLE_ASSET_INDEXING
+
static ARegion *file_ui_region_ensure(ScrArea *area, ARegion *region_prev)
{
ARegion *region;
@@ -353,6 +359,12 @@ static void file_refresh(const bContext *C, ScrArea *area)
sfile->files, asset_params->asset_catalog_visibility, &asset_params->catalog_id);
}
+#ifdef SPACE_FILE_ENABLE_ASSET_INDEXING
+ if (ED_fileselect_is_asset_browser(sfile)) {
+ filelist_setindexer(sfile->files, &file_indexer_asset);
+ }
+#endif
+
/* Update the active indices of bookmarks & co. */
sfile->systemnr = fsmenu_get_active_indices(fsmenu, FS_CATEGORY_SYSTEM, params->dir);
sfile->system_bookmarknr = fsmenu_get_active_indices(
@@ -688,7 +700,6 @@ static void file_operatortypes(void)
WM_operatortype_append(FILE_OT_previous);
WM_operatortype_append(FILE_OT_next);
WM_operatortype_append(FILE_OT_refresh);
- WM_operatortype_append(FILE_OT_asset_library_refresh);
WM_operatortype_append(FILE_OT_bookmark_add);
WM_operatortype_append(FILE_OT_bookmark_delete);
WM_operatortype_append(FILE_OT_bookmark_cleanup);
@@ -992,7 +1003,6 @@ static void file_id_remap(ScrArea *area, SpaceLink *sl, ID *UNUSED(old_id), ID *
file_reset_filelist_showing_main_data(area, sfile);
}
-/* only called once, from space/spacetypes.c */
void ED_spacetype_file(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype file");
diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c
index af88bbced9c..ed5993c77a7 100644
--- a/source/blender/editors/space_graph/graph_draw.c
+++ b/source/blender/editors/space_graph/graph_draw.c
@@ -1060,21 +1060,21 @@ static void draw_fcurve(bAnimContext *ac, SpaceGraph *sipo, ARegion *region, bAn
const uint shdr_pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
-
float viewport_size[4];
GPU_viewport_size_get_f(viewport_size);
- immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
-
- immUniform1i("colors_len", 0); /* Simple dashes. */
if (BKE_fcurve_is_protected(fcu)) {
- /* protected curves (non editable) are drawn with dotted lines */
+ /* Protected curves (non editable) are drawn with dotted lines. */
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+ immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
+ immUniform1i("colors_len", 0); /* Simple dashes. */
immUniform1f("dash_width", 4.0f);
immUniform1f("dash_factor", 0.5f);
}
else {
- immUniform1f("dash_factor", 2.0f); /* solid line */
+ immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
+ immUniform2fv("viewportSize", &viewport_size[2]);
+ immUniform1f("lineWidth", GPU_line_width_get());
}
if (((fcu->grp) && (fcu->grp->flag & AGRP_MUTED)) || (fcu->flag & FCURVE_MUTED)) {
@@ -1314,9 +1314,6 @@ static void graph_draw_driver_debug(bAnimContext *ac, ID *id, FCurve *fcu)
/* Public Curve-Drawing API ---------------- */
-/* Draw the 'ghost' F-Curves (i.e. snapshots of the curve)
- * NOTE: unit mapping has already been applied to the values, so do not try and apply again
- */
void graph_draw_ghost_curves(bAnimContext *ac, SpaceGraph *sipo, ARegion *region)
{
FCurve *fcu;
@@ -1364,9 +1361,6 @@ void graph_draw_ghost_curves(bAnimContext *ac, SpaceGraph *sipo, ARegion *region
GPU_blend(GPU_BLEND_NONE);
}
-/* This is called twice from space_graph.c -> graph_main_region_draw()
- * Unselected then selected F-Curves are drawn so that they do not occlude each other.
- */
void graph_draw_curves(bAnimContext *ac, SpaceGraph *sipo, ARegion *region, short sel)
{
ListBase anim_data = {NULL, NULL};
@@ -1408,7 +1402,6 @@ void graph_draw_curves(bAnimContext *ac, SpaceGraph *sipo, ARegion *region, shor
/** \name Channel List
* \{ */
-/* left hand part */
void graph_draw_channel_names(bContext *C, bAnimContext *ac, ARegion *region)
{
ListBase anim_data = {NULL, NULL};
diff --git a/source/blender/editors/space_graph/graph_intern.h b/source/blender/editors/space_graph/graph_intern.h
index 7add2f7cbb8..4db1eb5214e 100644
--- a/source/blender/editors/space_graph/graph_intern.h
+++ b/source/blender/editors/space_graph/graph_intern.h
@@ -34,12 +34,23 @@ struct bContext;
/* ***************************************** */
/* graph_draw.c */
+/**
+ * Left hand part.
+ */
void graph_draw_channel_names(struct bContext *C, struct bAnimContext *ac, struct ARegion *region);
+/**
+ * This is called twice from space_graph.c -> graph_main_region_draw()
+ * Unselected then selected F-Curves are drawn so that they do not occlude each other.
+ */
void graph_draw_curves(struct bAnimContext *ac,
struct SpaceGraph *sipo,
struct ARegion *region,
short sel);
+/**
+ * Draw the 'ghost' F-Curves (i.e. snapshots of the curve)
+ * \note unit mapping has already been applied to the values, so do not try and apply again.
+ */
void graph_draw_ghost_curves(struct bAnimContext *ac,
struct SpaceGraph *sipo,
struct ARegion *region);
@@ -47,6 +58,17 @@ void graph_draw_ghost_curves(struct bAnimContext *ac,
/* ***************************************** */
/* graph_select.c */
+/**
+ * Deselects keyframes in the Graph Editor
+ * - This is called by the deselect all operator, as well as other ones!
+ *
+ * - test: check if select or deselect all
+ * - sel: how to select keyframes
+ * 0 = deselect
+ * 1 = select
+ * 2 = invert
+ * - do_channels: whether to affect selection status of channels
+ */
void deselect_graph_keys(struct bAnimContext *ac, bool test, short sel, bool do_channels);
void GRAPH_OT_select_all(struct wmOperatorType *ot);
@@ -78,6 +100,10 @@ enum eGraphKeys_ColumnSelect_Mode {
/* ***************************************** */
/* graph_edit.c */
+/**
+ * Get the min/max keyframes.
+ * \note it should return total bound-box, filter for selection only can be argument.
+ */
void get_graph_keyframe_extents(struct bAnimContext *ac,
float *xmin,
float *xmax,
@@ -166,12 +192,36 @@ void graph_buttons_register(struct ARegionType *art);
/* ***************************************** */
/* graph_utils.c */
+/**
+ * Find 'active' F-Curve.
+ * It must be editable, since that's the purpose of these buttons (subject to change).
+ * We return the 'wrapper' since it contains valuable context info (about hierarchy),
+ * which will need to be freed when the caller is done with it.
+ *
+ * \note curve-visible flag isn't included,
+ * otherwise selecting a curve via list to edit is too cumbersome.
+ */
struct bAnimListElem *get_active_fcurve_channel(struct bAnimContext *ac);
+/**
+ * Check if there are any visible keyframes (for selection tools).
+ */
bool graphop_visible_keyframes_poll(struct bContext *C);
+/**
+ * Check if there are any visible + editable keyframes (for editing tools).
+ */
bool graphop_editable_keyframes_poll(struct bContext *C);
+/**
+ * Has active F-Curve that's editable.
+ */
bool graphop_active_fcurve_poll(struct bContext *C);
+/**
+ * Has active F-Curve in the context that's editable.
+ */
bool graphop_active_editable_fcurve_ctx_poll(struct bContext *C);
+/**
+ * Has selected F-Curve that's editable.
+ */
bool graphop_selected_fcurve_poll(struct bContext *C);
/* ***************************************** */
diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c
index 03bfd1092c6..29eb5b43e6c 100644
--- a/source/blender/editors/space_graph/graph_select.c
+++ b/source/blender/editors/space_graph/graph_select.c
@@ -346,17 +346,6 @@ static tNearestVertInfo *find_nearest_fcurve_vert(bAnimContext *ac, const int mv
* 3) (de)select all - no testing is done; only for use internal tools as normal function...
* \{ */
-/**
- * Deselects keyframes in the Graph Editor
- * - This is called by the deselect all operator, as well as other ones!
- *
- * - test: check if select or deselect all
- * - sel: how to select keyframes
- * 0 = deselect
- * 1 = select
- * 2 = invert
- * - do_channels: whether to affect selection status of channels
- */
void deselect_graph_keys(bAnimContext *ac, bool test, short sel, bool do_channels)
{
ListBase anim_data = {NULL, NULL};
diff --git a/source/blender/editors/space_graph/graph_slider_ops.c b/source/blender/editors/space_graph/graph_slider_ops.c
index 4e62ab2df2d..0bb5e8b8d9c 100644
--- a/source/blender/editors/space_graph/graph_slider_ops.c
+++ b/source/blender/editors/space_graph/graph_slider_ops.c
@@ -75,13 +75,16 @@ typedef struct tGraphSliderOp {
ARegion *region;
/** A 0-1 value for determining how much we should decimate. */
- PropertyRNA *percentage_prop;
+ PropertyRNA *factor_prop;
/** The original bezt curve data (used for restoring fcurves). */
ListBase bezt_arr_list;
struct tSlider *slider;
+ /* Each operator has a specific update function. */
+ void (*modal_update)(struct bContext *, struct wmOperator *);
+
NumInput num;
} tGraphSliderOp;
@@ -177,37 +180,10 @@ static void reset_bezts(tGraphSliderOp *gso)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Decimate Keyframes Operator
+/** \name Common Modal Functions
* \{ */
-typedef enum tDecimModes {
- DECIM_RATIO = 1,
- DECIM_ERROR,
-} tDecimModes;
-
-static void decimate_graph_keys(bAnimContext *ac, float remove_ratio, float error_sq_max)
-{
- ListBase anim_data = {NULL, NULL};
- bAnimListElem *ale;
-
- /* Filter data. */
- ANIM_animdata_filter(ac, &anim_data, OPERATOR_DATA_FILTER, ac->data, ac->datatype);
-
- /* Loop through filtered data and clean curves. */
- for (ale = anim_data.first; ale; ale = ale->next) {
- if (!decimate_fcurve(ale, remove_ratio, error_sq_max)) {
- /* The selection contains unsupported keyframe types! */
- WM_report(RPT_WARNING, "Decimate: Skipping non linear/bezier keyframes!");
- }
-
- ale->update |= ANIM_UPDATE_DEFAULT;
- }
-
- ANIM_animdata_update(ac, &anim_data);
- ANIM_animdata_freelist(&anim_data);
-}
-
-static void decimate_exit(bContext *C, wmOperator *op)
+static void graph_slider_exit(bContext *C, wmOperator *op)
{
tGraphSliderOp *gso = op->customdata;
wmWindow *win = CTX_wm_window(C);
@@ -235,36 +211,84 @@ static void decimate_exit(bContext *C, wmOperator *op)
WM_cursor_modal_restore(win);
ED_area_status_text(area, NULL);
- /* Cleanup. */
+ /* cleanup */
op->customdata = NULL;
}
-/* Draw a percentage indicator in workspace footer. */
-static void decimate_draw_status(bContext *C, tGraphSliderOp *gso)
+static int graph_slider_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
- char status_str[UI_MAX_DRAW_STR];
- char mode_str[32];
- char slider_string[UI_MAX_DRAW_STR];
+ tGraphSliderOp *gso = op->customdata;
- ED_slider_status_string_get(gso->slider, slider_string, UI_MAX_DRAW_STR);
+ const bool has_numinput = hasNumInput(&gso->num);
- strcpy(mode_str, TIP_("Decimate Keyframes"));
+ ED_slider_modal(gso->slider, event);
- if (hasNumInput(&gso->num)) {
- char str_ofs[NUM_STR_REP_LEN];
+ switch (event->type) {
+ /* Confirm */
+ case LEFTMOUSE:
+ case EVT_RETKEY:
+ case EVT_PADENTER: {
+ if (event->val == KM_PRESS) {
+ graph_slider_exit(C, op);
- outputNumInput(&gso->num, str_ofs, &gso->scene->unit);
+ return OPERATOR_FINISHED;
+ }
+ break;
+ }
- BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_ofs);
- }
- else {
- BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, slider_string);
+ /* Cancel */
+ case EVT_ESCKEY:
+ case RIGHTMOUSE: {
+ if (event->val == KM_PRESS) {
+ reset_bezts(gso);
+
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+
+ graph_slider_exit(C, op);
+
+ return OPERATOR_CANCELLED;
+ }
+ break;
+ }
+
+ /* When the mouse is moved, the percentage and the keyframes update. */
+ case MOUSEMOVE: {
+ if (has_numinput == false) {
+ /* Do the update as specified by the operator. */
+ gso->modal_update(C, op);
+ }
+ break;
+ }
+ default: {
+ if ((event->val == KM_PRESS) && handleNumInput(C, &gso->num, event)) {
+ float value;
+ float percentage = RNA_property_float_get(op->ptr, gso->factor_prop);
+
+ /* Grab percentage from numeric input, and store this new value for redo
+ * NOTE: users see ints, while internally we use a 0-1 float.
+ */
+ value = percentage * 100.0f;
+ applyNumInput(&gso->num, &value);
+
+ percentage = value / 100.0f;
+ ED_slider_factor_set(gso->slider, percentage);
+ RNA_property_float_set(op->ptr, gso->factor_prop, percentage);
+
+ gso->modal_update(C, op);
+ break;
+ }
+
+ /* Unhandled event - maybe it was some view manipulation? */
+ /* Allow to pass through. */
+ return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH;
+ }
}
- ED_workspace_status_text(C, status_str);
+ return OPERATOR_RUNNING_MODAL;
}
-static int graphkeys_decimate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+/* Allocate tGraphSliderOp and assign to op->customdata. */
+static int graph_slider_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
tGraphSliderOp *gso;
@@ -275,12 +299,10 @@ static int graphkeys_decimate_invoke(bContext *C, wmOperator *op, const wmEvent
/* Get editor data. */
if (ANIM_animdata_get_context(C, &gso->ac) == 0) {
- decimate_exit(C, op);
+ graph_slider_exit(C, op);
return OPERATOR_CANCELLED;
}
- gso->percentage_prop = RNA_struct_find_property(op->ptr, "remove_ratio");
-
gso->scene = CTX_data_scene(C);
gso->area = CTX_wm_area(C);
gso->region = CTX_wm_region(C);
@@ -289,14 +311,11 @@ static int graphkeys_decimate_invoke(bContext *C, wmOperator *op, const wmEvent
gso->slider = ED_slider_create(C);
ED_slider_init(gso->slider, event);
- ED_slider_allow_overshoot_set(gso->slider, false);
-
- decimate_draw_status(C, gso);
if (gso->bezt_arr_list.first == NULL) {
WM_report(RPT_WARNING,
- "Fcurve Decimate: Can't decimate baked channels. Unbake them and try again.");
- decimate_exit(C, op);
+ "Fcurve Slider: Can't work on baked channels. Unbake them and try again.");
+ graph_slider_exit(C, op);
return OPERATOR_CANCELLED;
}
@@ -304,102 +323,101 @@ static int graphkeys_decimate_invoke(bContext *C, wmOperator *op, const wmEvent
return OPERATOR_RUNNING_MODAL;
}
-static void graphkeys_decimate_modal_update(bContext *C, wmOperator *op)
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Decimate Keyframes Operator
+ * \{ */
+
+typedef enum tDecimModes {
+ DECIM_RATIO = 1,
+ DECIM_ERROR,
+} tDecimModes;
+
+static void decimate_graph_keys(bAnimContext *ac, float factor, float error_sq_max)
{
- /* Perform decimate updates - in response to some user action
- * (e.g. pressing a key or moving the mouse). */
- tGraphSliderOp *gso = op->customdata;
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
- decimate_draw_status(C, gso);
+ /* Filter data. */
+ ANIM_animdata_filter(ac, &anim_data, OPERATOR_DATA_FILTER, ac->data, ac->datatype);
- /* Reset keyframe data (so we get back to the original state). */
- reset_bezts(gso);
+ /* Loop through filtered data and clean curves. */
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ if (!decimate_fcurve(ale, factor, error_sq_max)) {
+ /* The selection contains unsupported keyframe types! */
+ WM_report(RPT_WARNING, "Decimate: Skipping non linear/bezier keyframes!");
+ }
- /* Apply... */
- float remove_ratio = ED_slider_factor_get(gso->slider);
- RNA_property_float_set(op->ptr, gso->percentage_prop, remove_ratio);
- /* We don't want to limit the decimation to a certain error margin. */
- const float error_sq_max = FLT_MAX;
- decimate_graph_keys(&gso->ac, remove_ratio, error_sq_max);
- WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ ale->update |= ANIM_UPDATE_DEFAULT;
+ }
+
+ ANIM_animdata_update(ac, &anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
-static int graphkeys_decimate_modal(bContext *C, wmOperator *op, const wmEvent *event)
+/* Draw a percentage indicator in workspace footer. */
+static void decimate_draw_status(bContext *C, tGraphSliderOp *gso)
{
- /* This assumes that we are in "DECIM_RATIO" mode. This is because the error margin is very hard
- * and finicky to control with this modal mouse grab method. Therefore, it is expected that the
- * error margin mode is not adjusted by the modal operator but instead tweaked via the redo
- * panel. */
- tGraphSliderOp *gso = op->customdata;
-
- const bool has_numinput = hasNumInput(&gso->num);
+ char status_str[UI_MAX_DRAW_STR];
+ char mode_str[32];
+ char slider_string[UI_MAX_DRAW_STR];
- ED_slider_modal(gso->slider, event);
+ ED_slider_status_string_get(gso->slider, slider_string, UI_MAX_DRAW_STR);
- switch (event->type) {
- case LEFTMOUSE: /* Confirm */
- case EVT_RETKEY:
- case EVT_PADENTER: {
- if (event->val == KM_PRESS) {
- decimate_exit(C, op);
+ strcpy(mode_str, TIP_("Decimate Keyframes"));
- return OPERATOR_FINISHED;
- }
- break;
- }
+ if (hasNumInput(&gso->num)) {
+ char str_ofs[NUM_STR_REP_LEN];
- case EVT_ESCKEY: /* Cancel */
- case RIGHTMOUSE: {
- if (event->val == KM_PRESS) {
- reset_bezts(gso);
+ outputNumInput(&gso->num, str_ofs, &gso->scene->unit);
- WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_ofs);
+ }
+ else {
+ BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, slider_string);
+ }
- decimate_exit(C, op);
+ ED_workspace_status_text(C, status_str);
+}
- return OPERATOR_CANCELLED;
- }
- break;
- }
+static void decimate_modal_update(bContext *C, wmOperator *op)
+{
+ /* Perform decimate updates - in response to some user action
+ * (e.g. pressing a key or moving the mouse). */
+ tGraphSliderOp *gso = op->customdata;
- /* Percentage Change... */
- case MOUSEMOVE: /* Calculate new position. */
- {
- if (has_numinput == false) {
- /* Update pose to reflect the new values. */
- graphkeys_decimate_modal_update(C, op);
- }
- break;
- }
- default: {
- if ((event->val == KM_PRESS) && handleNumInput(C, &gso->num, event)) {
- float value;
- float percentage = RNA_property_float_get(op->ptr, gso->percentage_prop);
+ decimate_draw_status(C, gso);
- /* Grab percentage from numeric input, and store this new value for redo
- * NOTE: users see ints, while internally we use a 0-1 float.
- */
- value = percentage * 100.0f;
- applyNumInput(&gso->num, &value);
+ /* Reset keyframe data (so we get back to the original state). */
+ reset_bezts(gso);
- percentage = value / 100.0f;
- RNA_property_float_set(op->ptr, gso->percentage_prop, percentage);
+ /* Apply... */
+ float factor = ED_slider_factor_get(gso->slider);
+ RNA_property_float_set(op->ptr, gso->factor_prop, factor);
+ /* We don't want to limit the decimation to a certain error margin. */
+ const float error_sq_max = FLT_MAX;
+ decimate_graph_keys(&gso->ac, factor, error_sq_max);
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+}
- /* Update decimate output to reflect the new values. */
- graphkeys_decimate_modal_update(C, op);
- break;
- }
+static int decimate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ const int invoke_result = graph_slider_invoke(C, op, event);
- /* Unhandled event - maybe it was some view manipulation? */
- /* Allow to pass through. */
- return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH;
- }
+ if (invoke_result == OPERATOR_CANCELLED) {
+ return OPERATOR_CANCELLED;
}
- return OPERATOR_RUNNING_MODAL;
+ tGraphSliderOp *gso = op->customdata;
+ gso->factor_prop = RNA_struct_find_property(op->ptr, "factor");
+ gso->modal_update = decimate_modal_update;
+ ED_slider_allow_overshoot_set(gso->slider, false);
+
+ return invoke_result;
}
-static int graphkeys_decimate_exec(bContext *C, wmOperator *op)
+static int decimate_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
@@ -410,13 +428,13 @@ static int graphkeys_decimate_exec(bContext *C, wmOperator *op)
tDecimModes mode = RNA_enum_get(op->ptr, "mode");
/* We want to be able to work on all available keyframes. */
- float remove_ratio = 1.0f;
+ float factor = 1.0f;
/* We don't want to limit the decimation to a certain error margin. */
float error_sq_max = FLT_MAX;
switch (mode) {
case DECIM_RATIO:
- remove_ratio = RNA_float_get(op->ptr, "remove_ratio");
+ factor = RNA_float_get(op->ptr, "factor");
break;
case DECIM_ERROR:
error_sq_max = RNA_float_get(op->ptr, "remove_error_margin");
@@ -426,12 +444,12 @@ static int graphkeys_decimate_exec(bContext *C, wmOperator *op)
break;
}
- if (remove_ratio == 0.0f || error_sq_max == 0.0f) {
+ if (factor == 0.0f || error_sq_max == 0.0f) {
/* Nothing to remove. */
return OPERATOR_FINISHED;
}
- decimate_graph_keys(&ac, remove_ratio, error_sq_max);
+ decimate_graph_keys(&ac, factor, error_sq_max);
/* Set notifier that keyframes have changed. */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
@@ -439,16 +457,16 @@ static int graphkeys_decimate_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static bool graphkeys_decimate_poll_property(const bContext *UNUSED(C),
- wmOperator *op,
- const PropertyRNA *prop)
+static bool decimate_poll_property(const bContext *UNUSED(C),
+ wmOperator *op,
+ const PropertyRNA *prop)
{
const char *prop_id = RNA_property_identifier(prop);
if (STRPREFIX(prop_id, "remove")) {
int mode = RNA_enum_get(op->ptr, "mode");
- if (STREQ(prop_id, "remove_ratio") && mode != DECIM_RATIO) {
+ if (STREQ(prop_id, "factor") && mode != DECIM_RATIO) {
return false;
}
if (STREQ(prop_id, "remove_error_margin") && mode != DECIM_ERROR) {
@@ -459,9 +477,7 @@ static bool graphkeys_decimate_poll_property(const bContext *UNUSED(C),
return true;
}
-static char *graphkeys_decimate_desc(bContext *UNUSED(C),
- wmOperatorType *UNUSED(op),
- PointerRNA *ptr)
+static char *decimate_desc(bContext *UNUSED(C), wmOperatorType *UNUSED(op), PointerRNA *ptr)
{
if (RNA_enum_get(ptr, "mode") == DECIM_ERROR) {
@@ -497,11 +513,11 @@ void GRAPH_OT_decimate(wmOperatorType *ot)
"Decimate F-Curves by removing keyframes that influence the curve shape the least";
/* API callbacks */
- ot->poll_property = graphkeys_decimate_poll_property;
- ot->get_description = graphkeys_decimate_desc;
- ot->invoke = graphkeys_decimate_invoke;
- ot->modal = graphkeys_decimate_modal;
- ot->exec = graphkeys_decimate_exec;
+ ot->poll_property = decimate_poll_property;
+ ot->get_description = decimate_desc;
+ ot->invoke = decimate_invoke;
+ ot->modal = graph_slider_modal;
+ ot->exec = decimate_exec;
ot->poll = graphop_editable_keyframes_poll;
/* Flags */
@@ -516,7 +532,7 @@ void GRAPH_OT_decimate(wmOperatorType *ot)
"Which mode to use for decimation");
RNA_def_float_factor(ot->srna,
- "remove_ratio",
+ "factor",
1.0f / 3.0f,
0.0f,
1.0f,
diff --git a/source/blender/editors/space_graph/graph_utils.c b/source/blender/editors/space_graph/graph_utils.c
index 89e7fefd9ac..d78af4c4bcf 100644
--- a/source/blender/editors/space_graph/graph_utils.c
+++ b/source/blender/editors/space_graph/graph_utils.c
@@ -50,9 +50,6 @@
/** \name Set Up Drivers Editor
* \{ */
-/* Set up UI configuration for Drivers Editor */
-/* NOTE: Currently called from window-manager
- * (new drivers editor window) and RNA (mode switching) */
void ED_drivers_editor_init(bContext *C, ScrArea *area)
{
SpaceGraph *sipo = (SpaceGraph *)area->spacedata.first;
@@ -96,15 +93,6 @@ void ED_drivers_editor_init(bContext *C, ScrArea *area)
/** \name Active F-Curve
* \{ */
-/**
- * Find 'active' F-Curve.
- * It must be editable, since that's the purpose of these buttons (subject to change).
- * We return the 'wrapper' since it contains valuable context info (about hierarchy),
- * which will need to be freed when the caller is done with it.
- *
- * \note curve-visible flag isn't included,
- * otherwise selecting a curve via list to edit is too cumbersome.
- */
bAnimListElem *get_active_fcurve_channel(bAnimContext *ac)
{
ListBase anim_data = {NULL, NULL};
@@ -134,7 +122,6 @@ bAnimListElem *get_active_fcurve_channel(bAnimContext *ac)
/** \name Operator Polling Callbacks
* \{ */
-/* Check if there are any visible keyframes (for selection tools) */
bool graphop_visible_keyframes_poll(bContext *C)
{
bAnimContext ac;
@@ -187,7 +174,6 @@ bool graphop_visible_keyframes_poll(bContext *C)
return found;
}
-/* Check if there are any visible + editable keyframes (for editing tools) */
bool graphop_editable_keyframes_poll(bContext *C)
{
bAnimContext ac;
@@ -242,7 +228,6 @@ bool graphop_editable_keyframes_poll(bContext *C)
return found;
}
-/* has active F-Curve that's editable */
bool graphop_active_fcurve_poll(bContext *C)
{
bAnimContext ac;
@@ -286,7 +271,6 @@ bool graphop_active_fcurve_poll(bContext *C)
return has_fcurve;
}
-/* has active F-Curve in the context that's editable */
bool graphop_active_editable_fcurve_ctx_poll(bContext *C)
{
PointerRNA ptr = CTX_data_pointer_get_type(C, "active_editable_fcurve", &RNA_FCurve);
@@ -294,7 +278,6 @@ bool graphop_active_editable_fcurve_ctx_poll(bContext *C)
return ptr.data != NULL;
}
-/* has selected F-Curve that's editable */
bool graphop_selected_fcurve_poll(bContext *C)
{
bAnimContext ac;
diff --git a/source/blender/editors/space_graph/graph_view.c b/source/blender/editors/space_graph/graph_view.c
index a12c6053877..a2f31a01a70 100644
--- a/source/blender/editors/space_graph/graph_view.c
+++ b/source/blender/editors/space_graph/graph_view.c
@@ -56,8 +56,6 @@
/** \name Calculate Range
* \{ */
-/* Get the min/max keyframes. */
-/* NOTE: it should return total boundbox, filter for selection only can be argument... */
void get_graph_keyframe_extents(bAnimContext *ac,
float *xmin,
float *xmax,
diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c
index 0e2c9b85bc6..40c95d4f382 100644
--- a/source/blender/editors/space_graph/space_graph.c
+++ b/source/blender/editors/space_graph/space_graph.c
@@ -829,7 +829,6 @@ static void graph_space_subtype_item_extend(bContext *UNUSED(C),
RNA_enum_items_add(item, totitem, rna_enum_space_graph_mode_items);
}
-/* only called once, from space/spacetypes.c */
void ED_spacetype_ipo(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype ipo");
diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c
index 6a50f6d42e8..4b8388a0002 100644
--- a/source/blender/editors/space_image/image_buttons.c
+++ b/source/blender/editors/space_image/image_buttons.c
@@ -63,7 +63,6 @@
#define B_NOP -1
#define MAX_IMAGE_INFO_LEN 128
-/* gets active viewer user */
struct ImageUser *ntree_get_active_iuser(bNodeTree *ntree)
{
bNode *node;
diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c
index d76b1842c94..ade5993cdb9 100644
--- a/source/blender/editors/space_image/image_draw.c
+++ b/source/blender/editors/space_image/image_draw.c
@@ -135,7 +135,6 @@ static void draw_render_info(
}
}
-/* used by node view too */
void ED_image_draw_info(Scene *scene,
ARegion *region,
bool color_manage,
@@ -614,11 +613,6 @@ void ED_space_image_grid_steps(SpaceImage *sima,
}
}
-/**
- * Calculate the increment snapping value for UV/image editor based on the zoom factor
- * The code in here (except the offset part) is used in `grid_frag.glsl` (see `grid_res`) for
- * drawing the grid overlay for the UV/Image editor.
- */
float ED_space_image_increment_snap_value(const int grid_dimesnions,
const float grid_steps[SI_GRID_STEPS_LEN],
const float zoom_factor)
diff --git a/source/blender/editors/space_image/image_edit.c b/source/blender/editors/space_image/image_edit.c
index 05124f49a20..470cff20718 100644
--- a/source/blender/editors/space_image/image_edit.c
+++ b/source/blender/editors/space_image/image_edit.c
@@ -177,7 +177,6 @@ void ED_space_image_release_buffer(SpaceImage *sima, ImBuf *ibuf, void *lock)
}
}
-/* Get the SpaceImage flag that is valid for the given ibuf. */
int ED_space_image_get_display_channel_mask(ImBuf *ibuf)
{
int result = (SI_USE_ALPHA | SI_SHOW_ALPHA | SI_SHOW_ZBUF | SI_SHOW_R | SI_SHOW_G | SI_SHOW_B);
@@ -318,7 +317,6 @@ void ED_image_get_uv_aspect(Image *ima, ImageUser *iuser, float *r_aspx, float *
}
}
-/* takes event->mval */
void ED_image_mouse_pos(SpaceImage *sima, const ARegion *region, const int mval[2], float co[2])
{
int sx, sy, width, height;
@@ -377,10 +375,6 @@ void ED_image_point_pos__reverse(SpaceImage *sima,
r_co[1] = (co[1] * height * zoomy) + (float)sy;
}
-/**
- * This is more a user-level functionality, for going to `next/prev` used slot,
- * Stepping onto the last unused slot too.
- */
bool ED_image_slot_cycle(struct Image *image, int direction)
{
const int cur = image->render_slot;
@@ -482,7 +476,6 @@ bool ED_space_image_show_uvedit(const SpaceImage *sima, Object *obedit)
return false;
}
-/* matches clip function */
bool ED_space_image_check_show_maskedit(SpaceImage *sima, Object *obedit)
{
/* check editmode - this is reserved for UV editing */
diff --git a/source/blender/editors/space_image/image_intern.h b/source/blender/editors/space_image/image_intern.h
index 6af0f3a416b..63c537467f7 100644
--- a/source/blender/editors/space_image/image_intern.h
+++ b/source/blender/editors/space_image/image_intern.h
@@ -36,11 +36,13 @@ struct wmOperatorType;
extern const char *image_context_dir[]; /* doc access */
/* image_draw.c */
+
void draw_image_main_helpers(const struct bContext *C, struct ARegion *region);
void draw_image_cache(const struct bContext *C, struct ARegion *region);
void draw_image_sample_line(struct SpaceImage *sima);
/* image_ops.c */
+
bool space_image_main_region_poll(struct bContext *C);
bool space_image_view_center_cursor_poll(struct bContext *C);
@@ -59,7 +61,13 @@ void IMAGE_OT_view_ndof(struct wmOperatorType *ot);
#endif
void IMAGE_OT_new(struct wmOperatorType *ot);
+/**
+ * Called by other space types too.
+ */
void IMAGE_OT_open(struct wmOperatorType *ot);
+/**
+ * Called by other space types too.
+ */
void IMAGE_OT_match_movie_length(struct wmOperatorType *ot);
void IMAGE_OT_replace(struct wmOperatorType *ot);
void IMAGE_OT_reload(struct wmOperatorType *ot);
@@ -94,5 +102,9 @@ void IMAGE_OT_tile_remove(struct wmOperatorType *ot);
void IMAGE_OT_tile_fill(struct wmOperatorType *ot);
/* image_panels.c */
+
+/**
+ * Gets active viewer user.
+ */
struct ImageUser *ntree_get_active_iuser(struct bNodeTree *ntree);
void image_buttons_register(struct ARegionType *art);
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index 478e484924a..f9160774c41 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -728,10 +728,10 @@ void IMAGE_OT_view_zoom(wmOperatorType *ot)
WM_operator_properties_use_cursor_init(ot);
}
-#ifdef WITH_INPUT_NDOF
-
/** \} */
+#ifdef WITH_INPUT_NDOF
+
/* -------------------------------------------------------------------- */
/** \name NDOF Operator
* \{ */
@@ -1499,7 +1499,6 @@ static void image_open_draw(bContext *UNUSED(C), wmOperator *op)
}
}
-/* called by other space types too */
void IMAGE_OT_open(wmOperatorType *ot)
{
/* identifiers */
@@ -1574,7 +1573,6 @@ static int image_match_len_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
-/* called by other space types too */
void IMAGE_OT_match_movie_length(wmOperatorType *ot)
{
/* identifiers */
@@ -3190,8 +3188,10 @@ void IMAGE_OT_unpack(wmOperatorType *ot)
/** \name Sample Image Operator
* \{ */
-/* Returns mouse position in image space. */
-bool ED_space_image_get_position(SpaceImage *sima, struct ARegion *ar, int mval[2], float fpos[2])
+bool ED_space_image_get_position(SpaceImage *sima,
+ struct ARegion *region,
+ int mval[2],
+ float fpos[2])
{
void *lock;
ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock, 0);
@@ -3201,13 +3201,12 @@ bool ED_space_image_get_position(SpaceImage *sima, struct ARegion *ar, int mval[
return false;
}
- UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &fpos[0], &fpos[1]);
+ UI_view2d_region_to_view(&region->v2d, mval[0], mval[1], &fpos[0], &fpos[1]);
ED_space_image_release_buffer(sima, ibuf, lock);
return true;
}
-/* Returns color in linear space, matching ED_space_node_color_sample(). */
bool ED_space_image_color_sample(
SpaceImage *sima, ARegion *region, int mval[2], float r_col[3], bool *r_is_data)
{
@@ -4137,3 +4136,5 @@ void IMAGE_OT_tile_fill(wmOperatorType *ot)
def_fill_tile(ot->srna);
}
+
+/** \} */
diff --git a/source/blender/editors/space_image/image_sequence.c b/source/blender/editors/space_image/image_sequence.c
index c4f111264a3..87bff913ff2 100644
--- a/source/blender/editors/space_image/image_sequence.c
+++ b/source/blender/editors/space_image/image_sequence.c
@@ -217,7 +217,6 @@ static void image_detect_frame_range(ImageFrameRange *range, const bool detect_u
}
}
-/* Used for both images and volume file loading. */
ListBase ED_image_filesel_detect_sequences(Main *bmain, wmOperator *op, const bool detect_udim)
{
ListBase ranges;
diff --git a/source/blender/editors/space_image/image_undo.c b/source/blender/editors/space_image/image_undo.c
index 3fbcc8348c8..e81f3b6a490 100644
--- a/source/blender/editors/space_image/image_undo.c
+++ b/source/blender/editors/space_image/image_undo.c
@@ -989,7 +989,6 @@ static void image_undosys_foreach_ID_ref(UndoStep *us_p,
}
}
-/* Export for ED_undo_sys. */
void ED_image_undosys_type(UndoType *ut)
{
ut->name = "Image";
@@ -1040,7 +1039,6 @@ ListBase *ED_image_paint_tile_list_get(void)
return &us->paint_tiles;
}
-/* Restore painting image to previous state. Used for anchored and drag-dot style brushes. */
void ED_image_undo_restore(UndoStep *us)
{
ListBase *paint_tiles = &((ImageUndoStep *)us)->paint_tiles;
@@ -1059,10 +1057,6 @@ static ImageUndoStep *image_undo_push_begin(const char *name, int paint_mode)
return us;
}
-/**
- * The caller is responsible for running #ED_image_undo_push_end,
- * failure to do so causes an invalid state for the undo system.
- */
void ED_image_undo_push_begin(const char *name, int paint_mode)
{
image_undo_push_begin(name, paint_mode);
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index 516ffcd1e75..dad494e6984 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -1042,7 +1042,6 @@ static void image_space_subtype_item_extend(bContext *UNUSED(C),
/**************************** spacetype *****************************/
-/* only called once, from space/spacetypes.c */
void ED_spacetype_image(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype image");
diff --git a/source/blender/editors/space_info/info_ops.c b/source/blender/editors/space_info/info_ops.c
index 8e37e5fe9a8..2a797fd1a78 100644
--- a/source/blender/editors/space_info/info_ops.c
+++ b/source/blender/editors/space_info/info_ops.c
@@ -408,13 +408,14 @@ void FILE_OT_unpack_item(wmOperatorType *ot)
static int make_paths_relative_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
+ const char *blendfile_path = BKE_main_blendfile_path(bmain);
- if (!G.relbase_valid) {
+ if (blendfile_path[0] == '\0') {
BKE_report(op->reports, RPT_WARNING, "Cannot set relative paths with an unsaved blend file");
return OPERATOR_CANCELLED;
}
- BKE_bpath_relative_convert(bmain, BKE_main_blendfile_path(bmain), op->reports);
+ BKE_bpath_relative_convert(bmain, blendfile_path, op->reports);
/* redraw everything so any changed paths register */
WM_main_add_notifier(NC_WINDOW, NULL);
@@ -445,13 +446,14 @@ void FILE_OT_make_paths_relative(wmOperatorType *ot)
static int make_paths_absolute_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
+ const char *blendfile_path = BKE_main_blendfile_path(bmain);
- if (!G.relbase_valid) {
+ if (blendfile_path[0] == '\0') {
BKE_report(op->reports, RPT_WARNING, "Cannot set absolute paths with an unsaved blend file");
return OPERATOR_CANCELLED;
}
- BKE_bpath_absolute_convert(bmain, BKE_main_blendfile_path(bmain), op->reports);
+ BKE_bpath_absolute_convert(bmain, blendfile_path, op->reports);
/* redraw everything so any changed paths register */
WM_main_add_notifier(NC_WINDOW, NULL);
diff --git a/source/blender/editors/space_info/info_report.c b/source/blender/editors/space_info/info_report.c
index 1062b76b1df..ce17450549e 100644
--- a/source/blender/editors/space_info/info_report.c
+++ b/source/blender/editors/space_info/info_report.c
@@ -299,6 +299,7 @@ static int box_select_exec(bContext *C, wmOperator *op)
}
/* ****** Box Select ****** */
+
void INFO_OT_select_box(wmOperatorType *ot)
{
/* identifiers */
diff --git a/source/blender/editors/space_info/info_stats.cc b/source/blender/editors/space_info/info_stats.cc
index 19c98fb4d17..bcf26743030 100644
--- a/source/blender/editors/space_info/info_stats.cc
+++ b/source/blender/editors/space_info/info_stats.cc
@@ -721,11 +721,6 @@ static void stats_row(int col1,
BLF_draw_default(col2, *y, 0.0f, values, sizeof(values));
}
-/**
- * \param v3d_local: Pass this argument to calculate view-port local statistics.
- * Note that this must only be used for local-view, otherwise report specific statistics
- * will be written into the global scene statistics giving incorrect results.
- */
void ED_info_draw_stats(
Main *bmain, Scene *scene, ViewLayer *view_layer, View3D *v3d_local, int x, int *y, int height)
{
diff --git a/source/blender/editors/space_info/space_info.c b/source/blender/editors/space_info/space_info.c
index e56bb44b1e6..1d28aace7f2 100644
--- a/source/blender/editors/space_info/space_info.c
+++ b/source/blender/editors/space_info/space_info.c
@@ -264,7 +264,6 @@ static void info_header_region_message_subscribe(const wmRegionMessageSubscribeP
WM_msg_subscribe_rna_anon_prop(mbus, ViewLayer, name, &msg_sub_value_region_tag_redraw);
}
-/* only called once, from space/spacetypes.c */
void ED_spacetype_info(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype info");
diff --git a/source/blender/editors/space_info/textview.c b/source/blender/editors/space_info/textview.c
index e656155fb13..cc14abd8bb3 100644
--- a/source/blender/editors/space_info/textview.c
+++ b/source/blender/editors/space_info/textview.c
@@ -303,13 +303,6 @@ static bool textview_draw_string(TextViewDrawState *tds,
return true;
}
-/**
- * \param r_mval_pick_item: The resulting item clicked on using \a mval_init.
- * Set from the void pointer which holds the current iterator.
- * Its type depends on the data being iterated over.
- * \param r_mval_pick_offset: The offset in bytes of the \a mval_init.
- * Use for selection.
- */
int textview_draw(TextViewContext *tvc,
const bool do_draw,
const int mval_init[2],
diff --git a/source/blender/editors/space_info/textview.h b/source/blender/editors/space_info/textview.h
index 7520dbce191..96f537b4b97 100644
--- a/source/blender/editors/space_info/textview.h
+++ b/source/blender/editors/space_info/textview.h
@@ -73,6 +73,13 @@ typedef struct TextViewContext {
} TextViewContext;
+/**
+ * \param r_mval_pick_item: The resulting item clicked on using \a mval_init.
+ * Set from the void pointer which holds the current iterator.
+ * Its type depends on the data being iterated over.
+ * \param r_mval_pick_offset: The offset in bytes of the \a mval_init.
+ * Use for selection.
+ */
int textview_draw(struct TextViewContext *tvc,
const bool do_draw,
const int mval_init[2],
diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c
index 1b87a8c6b9d..47af7a66f6f 100644
--- a/source/blender/editors/space_nla/nla_channels.c
+++ b/source/blender/editors/space_nla/nla_channels.c
@@ -629,7 +629,6 @@ void NLA_OT_action_unlink(wmOperatorType *ot)
/* ******************** Add Tracks Operator ***************************** */
/* Add NLA Tracks to the same AnimData block as a selected track, or above the selected tracks */
-/* helper - add NLA Tracks alongside existing ones */
bool nlaedit_add_tracks_existing(bAnimContext *ac, bool above_sel)
{
ListBase anim_data = {NULL, NULL};
@@ -678,7 +677,6 @@ bool nlaedit_add_tracks_existing(bAnimContext *ac, bool above_sel)
return added;
}
-/* helper - add NLA Tracks to empty (and selected) AnimData blocks */
bool nlaedit_add_tracks_empty(bAnimContext *ac)
{
ListBase anim_data = {NULL, NULL};
diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c
index bf2d20cf4c9..12f0011b499 100644
--- a/source/blender/editors/space_nla/nla_draw.c
+++ b/source/blender/editors/space_nla/nla_draw.c
@@ -65,9 +65,6 @@
/* Action-Line ---------------------- */
-/* get colors for drawing Action-Line
- * NOTE: color returned includes fine-tuned alpha!
- */
void nla_action_get_color(AnimData *adt, bAction *act, float color[4])
{
if (adt && (adt->flag & ADT_NLA_EDIT_ON)) {
@@ -111,11 +108,11 @@ static void nla_action_draw_keyframes(
/* draw a darkened region behind the strips
* - get and reset the background color, this time without the alpha to stand out better
- * (amplified alpha is used instead)
+ * (amplified alpha is used instead, but clamped to avoid 100% opacity)
*/
float color[4];
nla_action_get_color(adt, act, color);
- color[3] *= 2.5f;
+ color[3] = min_ff(0.7f, color[3] * 2.5f);
GPUVertFormat *format = immVertexFormat();
uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
@@ -786,6 +783,11 @@ void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *region)
case ANIMTYPE_NLAACTION: {
AnimData *adt = ale->adt;
+ /* Draw the manually set intended playback frame range highlight. */
+ if (ale->data) {
+ ANIM_draw_action_framerange(adt, ale->data, v2d, ymin, ymax);
+ }
+
uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c
index 62f8906d136..1376dade659 100644
--- a/source/blender/editors/space_nla/nla_edit.c
+++ b/source/blender/editors/space_nla/nla_edit.c
@@ -71,7 +71,6 @@
/** \name Public Utilities
* \{ */
-/* Perform validation for blending/extend settings */
void ED_nla_postop_refresh(bAnimContext *ac)
{
ListBase anim_data = {NULL, NULL};
@@ -205,7 +204,6 @@ void NLA_OT_tweakmode_enter(wmOperatorType *ot)
/** \name Disable Tweak-Mode Operator
* \{ */
-/* NLA Editor internal API function for exiting tweak-mode. */
bool nlaedit_disable_tweakmode(bAnimContext *ac, bool do_solo)
{
ListBase anim_data = {NULL, NULL};
@@ -2193,8 +2191,19 @@ static int nlaedit_apply_scale_exec(bContext *C, wmOperator *UNUSED(op))
* and recalculate the extents of the action now that it has been scaled
* but leave everything else alone
*/
+ const float start = nlastrip_get_frame(strip, strip->actstart, NLATIME_CONVERT_MAP);
+ const float end = nlastrip_get_frame(strip, strip->actend, NLATIME_CONVERT_MAP);
+
+ if (strip->act->flag & ACT_FRAME_RANGE) {
+ strip->act->frame_start = nlastrip_get_frame(
+ strip, strip->act->frame_start, NLATIME_CONVERT_MAP);
+ strip->act->frame_end = nlastrip_get_frame(
+ strip, strip->act->frame_end, NLATIME_CONVERT_MAP);
+ }
+
strip->scale = 1.0f;
- calc_action_range(strip->act, &strip->actstart, &strip->actend, 0);
+ strip->actstart = start;
+ strip->actend = end;
ale->update |= ANIM_UPDATE_DEPS;
}
diff --git a/source/blender/editors/space_nla/nla_intern.h b/source/blender/editors/space_nla/nla_intern.h
index 9a9ea161f56..dd322dd2ad1 100644
--- a/source/blender/editors/space_nla/nla_intern.h
+++ b/source/blender/editors/space_nla/nla_intern.h
@@ -75,6 +75,9 @@ enum eNlaEdit_Snap_Mode {
/* --- */
+/**
+ * NLA Editor internal API function for exiting tweak-mode.
+ */
bool nlaedit_disable_tweakmode(bAnimContext *ac, bool do_solo);
void NLA_OT_tweakmode_enter(wmOperatorType *ot);
@@ -121,7 +124,13 @@ void NLA_OT_fmodifier_paste(wmOperatorType *ot);
/* **************************************** */
/* nla_channels.c */
+/**
+ * Helper - add NLA Tracks alongside existing ones.
+ */
bool nlaedit_add_tracks_existing(bAnimContext *ac, bool above_sel);
+/**
+ * helper - add NLA Tracks to empty (and selected) AnimData blocks.
+ */
bool nlaedit_add_tracks_empty(bAnimContext *ac);
/* --- */
@@ -139,9 +148,18 @@ void NLA_OT_selected_objects_add(wmOperatorType *ot);
/* **************************************** */
/* nla_ops.c */
+/**
+ * Tweak-mode is NOT enabled.
+ */
bool nlaop_poll_tweakmode_off(bContext *C);
+/**
+ * Tweak-mode IS enabled.
+ */
bool nlaop_poll_tweakmode_on(bContext *C);
+/**
+ * Is tweak-mode enabled - for use in NLA operator code.
+ */
bool nlaedit_is_tweakmode_on(bAnimContext *ac);
/* --- */
diff --git a/source/blender/editors/space_nla/nla_ops.c b/source/blender/editors/space_nla/nla_ops.c
index 28f194877fa..33449bed798 100644
--- a/source/blender/editors/space_nla/nla_ops.c
+++ b/source/blender/editors/space_nla/nla_ops.c
@@ -39,7 +39,6 @@
/* ************************** poll callbacks for operators **********************************/
-/* Tweak-mode is NOT enabled. */
bool nlaop_poll_tweakmode_off(bContext *C)
{
Scene *scene;
@@ -62,7 +61,6 @@ bool nlaop_poll_tweakmode_off(bContext *C)
return 1;
}
-/* Tweak-mode IS enabled. */
bool nlaop_poll_tweakmode_on(bContext *C)
{
Scene *scene;
@@ -85,7 +83,6 @@ bool nlaop_poll_tweakmode_on(bContext *C)
return 1;
}
-/* is tweak-mode enabled - for use in NLA operator code */
bool nlaedit_is_tweakmode_on(bAnimContext *ac)
{
if (ac && ac->scene) {
diff --git a/source/blender/editors/space_nla/space_nla.c b/source/blender/editors/space_nla/space_nla.c
index 8b44c26f07c..0771153c5f5 100644
--- a/source/blender/editors/space_nla/space_nla.c
+++ b/source/blender/editors/space_nla/space_nla.c
@@ -591,7 +591,6 @@ static void nla_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID
}
}
-/* only called once, from space/spacetypes.c */
void ED_spacetype_nla(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype nla");
diff --git a/source/blender/editors/space_node/CMakeLists.txt b/source/blender/editors/space_node/CMakeLists.txt
index e88d61fe880..94b67e43651 100644
--- a/source/blender/editors/space_node/CMakeLists.txt
+++ b/source/blender/editors/space_node/CMakeLists.txt
@@ -39,6 +39,7 @@ set(INC
set(SRC
drawnode.cc
+ link_drag_search.cc
node_add.cc
node_context_path.cc
node_draw.cc
diff --git a/source/blender/editors/space_node/drawnode.cc b/source/blender/editors/space_node/drawnode.cc
index cf79893a8cb..bbfd886ce56 100644
--- a/source/blender/editors/space_node/drawnode.cc
+++ b/source/blender/editors/space_node/drawnode.cc
@@ -22,8 +22,6 @@
* \brief lower level node drawing for nodes (boarders, headers etc), also node layout.
*/
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
#include "BLI_system.h"
#include "BLI_threads.h"
@@ -31,7 +29,6 @@
#include "DNA_object_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
-#include "DNA_text_types.h"
#include "DNA_userdef_types.h"
#include "BKE_context.h"
@@ -79,6 +76,8 @@
#include "NOD_texture.h"
#include "node_intern.hh" /* own include */
+using blender::float2;
+
/* 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
@@ -236,6 +235,7 @@ static void node_shader_buts_clamp(uiLayout *layout, bContext *UNUSED(C), Pointe
static void node_shader_buts_map_range(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
+ uiItemR(layout, ptr, "data_type", DEFAULT_FLAGS, "", ICON_NONE);
uiItemR(layout, ptr, "interpolation_type", DEFAULT_FLAGS, "", ICON_NONE);
if (!ELEM(RNA_enum_get(ptr, "interpolation_type"),
NODE_MAP_RANGE_SMOOTHSTEP,
@@ -250,22 +250,50 @@ static void node_buts_math(uiLayout *layout, bContext *UNUSED(C), PointerRNA *pt
uiItemR(layout, ptr, "use_clamp", DEFAULT_FLAGS, nullptr, ICON_NONE);
}
-static int node_resize_area_default(bNode *node, int x, int y)
+NodeResizeDirection node_get_resize_direction(const bNode *node, const int x, const int y)
{
+ if (node->type == NODE_FRAME) {
+ const float size = 10.0f;
+ NodeFrame *data = (NodeFrame *)node->storage;
+
+ /* shrinking frame size is determined by child nodes */
+ if (!(data->flag & NODE_FRAME_RESIZEABLE)) {
+ return NODE_RESIZE_NONE;
+ }
+
+ NodeResizeDirection dir = NODE_RESIZE_NONE;
+
+ const rctf &totr = node->totr;
+ if (x >= totr.xmax - size && x < totr.xmax && y >= totr.ymin && y < totr.ymax) {
+ dir |= NODE_RESIZE_RIGHT;
+ }
+ if (x >= totr.xmin && x < totr.xmin + size && y >= totr.ymin && y < totr.ymax) {
+ dir |= NODE_RESIZE_LEFT;
+ }
+ if (x >= totr.xmin && x < totr.xmax && y >= totr.ymax - size && y < totr.ymax) {
+ dir |= NODE_RESIZE_TOP;
+ }
+ if (x >= totr.xmin && x < totr.xmax && y >= totr.ymin && y < totr.ymin + size) {
+ dir |= NODE_RESIZE_BOTTOM;
+ }
+
+ return dir;
+ }
+
if (node->flag & NODE_HIDDEN) {
- rctf totr = node->totr;
/* right part of node */
+ rctf totr = node->totr;
totr.xmin = node->totr.xmax - 1.0f * U.widget_unit;
if (BLI_rctf_isect_pt(&totr, x, y)) {
return NODE_RESIZE_RIGHT;
}
- return 0;
+ return NODE_RESIZE_NONE;
}
const float size = NODE_RESIZE_MARGIN;
- rctf totr = node->totr;
- int dir = 0;
+ const rctf &totr = node->totr;
+ NodeResizeDirection dir = NODE_RESIZE_NONE;
if (x >= totr.xmax - size && x < totr.xmax && y >= totr.ymin && y < totr.ymax) {
dir |= NODE_RESIZE_RIGHT;
@@ -284,225 +312,6 @@ static void node_draw_buttons_group(uiLayout *layout, bContext *C, PointerRNA *p
layout, C, ptr, "node_tree", nullptr, nullptr, nullptr, UI_TEMPLATE_ID_FILTER_ALL, nullptr);
}
-/* XXX Does a bounding box update by iterating over all children.
- * Not ideal to do this in every draw call, but doing as transform callback doesn't work,
- * since the child node totr rects are not updated properly at that point.
- */
-static void node_draw_frame_prepare(const bContext *UNUSED(C), bNodeTree *ntree, bNode *node)
-{
- const float margin = 1.5f * U.widget_unit;
- NodeFrame *data = (NodeFrame *)node->storage;
-
- /* init rect from current frame size */
- rctf rect;
- node_to_view(node, node->offsetx, node->offsety, &rect.xmin, &rect.ymax);
- node_to_view(
- node, node->offsetx + node->width, node->offsety - node->height, &rect.xmax, &rect.ymin);
-
- /* frame can be resized manually only if shrinking is disabled or no children are attached */
- data->flag |= NODE_FRAME_RESIZEABLE;
- /* for shrinking bbox, initialize the rect from first child node */
- bool bbinit = (data->flag & NODE_FRAME_SHRINK);
- /* fit bounding box to all children */
- LISTBASE_FOREACH (bNode *, tnode, &ntree->nodes) {
- if (tnode->parent != node) {
- continue;
- }
-
- /* add margin to node rect */
- rctf noderect = tnode->totr;
- noderect.xmin -= margin;
- noderect.xmax += margin;
- noderect.ymin -= margin;
- noderect.ymax += margin;
-
- /* first child initializes frame */
- if (bbinit) {
- bbinit = false;
- rect = noderect;
- data->flag &= ~NODE_FRAME_RESIZEABLE;
- }
- else {
- BLI_rctf_union(&rect, &noderect);
- }
- }
-
- /* now adjust the frame size from view-space bounding box */
- node_from_view(node, rect.xmin, rect.ymax, &node->offsetx, &node->offsety);
- float xmax, ymax;
- node_from_view(node, rect.xmax, rect.ymin, &xmax, &ymax);
- node->width = xmax - node->offsetx;
- node->height = -ymax + node->offsety;
-
- node->totr = rect;
-}
-
-static void node_draw_frame_label(bNodeTree *ntree, bNode *node, const float aspect)
-{
- /* XXX font id is crap design */
- const int fontid = UI_style_get()->widgetlabel.uifont_id;
- NodeFrame *data = (NodeFrame *)node->storage;
- const float font_size = data->label_size / aspect;
-
- char label[MAX_NAME];
- nodeLabel(ntree, node, label, sizeof(label));
-
- BLF_enable(fontid, BLF_ASPECT);
- BLF_aspect(fontid, aspect, aspect, 1.0f);
- /* clamp otherwise it can suck up a LOT of memory */
- BLF_size(fontid, MIN2(24.0f, font_size), U.dpi);
-
- /* title color */
- int color_id = node_get_colorid(node);
- uchar color[3];
- UI_GetThemeColorBlendShade3ubv(TH_TEXT, color_id, 0.4f, 10, color);
- BLF_color3ubv(fontid, color);
-
- const float margin = (float)(NODE_DY / 4);
- const float width = BLF_width(fontid, label, sizeof(label));
- const float ascender = BLF_ascender(fontid);
- const int label_height = ((margin / aspect) + (ascender * aspect));
-
- /* 'x' doesn't need aspect correction */
- rctf *rct = &node->totr;
- /* XXX a bit hacky, should use separate align values for x and y */
- float x = BLI_rctf_cent_x(rct) - (0.5f * width);
- float y = rct->ymax - label_height;
-
- /* label */
- const bool has_label = node->label[0] != '\0';
- if (has_label) {
- BLF_position(fontid, x, y, 0);
- BLF_draw(fontid, label, BLF_DRAW_STR_DUMMY_MAX);
- }
-
- /* draw text body */
- if (node->id) {
- Text *text = (Text *)node->id;
- const int line_height_max = BLF_height_max(fontid);
- const float line_spacing = (line_height_max * aspect);
- const float line_width = (BLI_rctf_size_x(rct) - margin) / aspect;
-
- /* 'x' doesn't need aspect correction */
- x = rct->xmin + margin;
- y = rct->ymax - label_height - (has_label ? line_spacing : 0);
-
- /* early exit */
- int y_min = y + ((margin * 2) - (y - rct->ymin));
-
- BLF_enable(fontid, BLF_CLIPPING | BLF_WORD_WRAP);
- BLF_clipping(fontid,
- rct->xmin,
- /* round to avoid clipping half-way through a line */
- y - (floorf(((y - rct->ymin) - (margin * 2)) / line_spacing) * line_spacing),
- rct->xmin + line_width,
- rct->ymax);
-
- BLF_wordwrap(fontid, line_width);
-
- LISTBASE_FOREACH (TextLine *, line, &text->lines) {
- struct ResultBLF info;
- if (line->line[0]) {
- BLF_position(fontid, x, y, 0);
- BLF_draw_ex(fontid, line->line, line->len, &info);
- y -= line_spacing * info.lines;
- }
- else {
- y -= line_spacing;
- }
- if (y < y_min) {
- break;
- }
- }
-
- BLF_disable(fontid, BLF_CLIPPING | BLF_WORD_WRAP);
- }
-
- BLF_disable(fontid, BLF_ASPECT);
-}
-
-static void node_draw_frame(const bContext *C,
- ARegion *region,
- SpaceNode *snode,
- bNodeTree *ntree,
- bNode *node,
- bNodeInstanceKey UNUSED(key))
-{
-
- /* skip if out of view */
- if (BLI_rctf_isect(&node->totr, &region->v2d.cur, nullptr) == false) {
- UI_block_end(C, node->block);
- node->block = nullptr;
- return;
- }
-
- float color[4];
- UI_GetThemeColor4fv(TH_NODE_FRAME, color);
- const float alpha = color[3];
-
- /* shadow */
- node_draw_shadow(snode, node, BASIS_RAD, alpha);
-
- /* body */
- if (node->flag & NODE_CUSTOM_COLOR) {
- rgba_float_args_set(color, node->color[0], node->color[1], node->color[2], alpha);
- }
- else {
- UI_GetThemeColor4fv(TH_NODE_FRAME, color);
- }
-
- const rctf *rct = &node->totr;
- UI_draw_roundbox_corner_set(UI_CNR_ALL);
- UI_draw_roundbox_4fv(rct, true, BASIS_RAD, color);
-
- /* outline active and selected emphasis */
- if (node->flag & SELECT) {
- if (node->flag & NODE_ACTIVE) {
- UI_GetThemeColorShadeAlpha4fv(TH_ACTIVE, 0, -40, color);
- }
- else {
- UI_GetThemeColorShadeAlpha4fv(TH_SELECT, 0, -40, color);
- }
-
- UI_draw_roundbox_aa(rct, false, BASIS_RAD, color);
- }
-
- /* label and text */
- node_draw_frame_label(ntree, node, snode->runtime->aspect);
-
- UI_block_end(C, node->block);
- UI_block_draw(C, node->block);
- node->block = nullptr;
-}
-
-static int node_resize_area_frame(bNode *node, int x, int y)
-{
- const float size = 10.0f;
- NodeFrame *data = (NodeFrame *)node->storage;
- rctf totr = node->totr;
- int dir = 0;
-
- /* shrinking frame size is determined by child nodes */
- if (!(data->flag & NODE_FRAME_RESIZEABLE)) {
- return 0;
- }
-
- if (x >= totr.xmax - size && x < totr.xmax && y >= totr.ymin && y < totr.ymax) {
- dir |= NODE_RESIZE_RIGHT;
- }
- if (x >= totr.xmin && x < totr.xmin + size && y >= totr.ymin && y < totr.ymax) {
- dir |= NODE_RESIZE_LEFT;
- }
- if (x >= totr.xmin && x < totr.xmax && y >= totr.ymax - size && y < totr.ymax) {
- dir |= NODE_RESIZE_TOP;
- }
- if (x >= totr.xmin && x < totr.xmax && y >= totr.ymin && y < totr.ymin + size) {
- dir |= NODE_RESIZE_BOTTOM;
- }
-
- return dir;
-}
-
static void node_buts_frame_ex(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "label_size", DEFAULT_FLAGS, IFACE_("Label Size"), ICON_NONE);
@@ -510,124 +319,6 @@ static void node_buts_frame_ex(uiLayout *layout, bContext *UNUSED(C), PointerRNA
uiItemR(layout, ptr, "text", DEFAULT_FLAGS, nullptr, ICON_NONE);
}
-#define NODE_REROUTE_SIZE 8.0f
-
-static void node_draw_reroute_prepare(const bContext *UNUSED(C),
- bNodeTree *UNUSED(ntree),
- bNode *node)
-{
- /* get "global" coords */
- float locx, locy;
- node_to_view(node, 0.0f, 0.0f, &locx, &locy);
-
- /* reroute node has exactly one input and one output, both in the same place */
- bNodeSocket *nsock = (bNodeSocket *)node->outputs.first;
- nsock->locx = locx;
- nsock->locy = locy;
-
- nsock = (bNodeSocket *)node->inputs.first;
- nsock->locx = locx;
- nsock->locy = locy;
-
- const float size = NODE_REROUTE_SIZE;
- node->width = size * 2;
- node->totr.xmin = locx - size;
- node->totr.xmax = locx + size;
- node->totr.ymax = locy + size;
- node->totr.ymin = locy - size;
-}
-
-static void node_draw_reroute(const bContext *C,
- ARegion *region,
- SpaceNode *UNUSED(snode),
- bNodeTree *ntree,
- bNode *node,
- bNodeInstanceKey UNUSED(key))
-{
- char showname[128]; /* 128 used below */
- rctf *rct = &node->totr;
-
- /* skip if out of view */
- if (node->totr.xmax < region->v2d.cur.xmin || node->totr.xmin > region->v2d.cur.xmax ||
- node->totr.ymax < region->v2d.cur.ymin || node->totr.ymin > region->v2d.cur.ymax) {
- UI_block_end(C, node->block);
- node->block = nullptr;
- return;
- }
-
- /* XXX only kept for debugging
- * selection state is indicated by socket outline below!
- */
-#if 0
- float size = NODE_REROUTE_SIZE;
-
- /* body */
- float debug_color[4];
- UI_draw_roundbox_corner_set(UI_CNR_ALL);
- UI_GetThemeColor4fv(TH_NODE, debug_color);
- UI_draw_roundbox_aa(true, rct->xmin, rct->ymin, rct->xmax, rct->ymax, size, debug_color);
-
- /* outline active and selected emphasis */
- if (node->flag & SELECT) {
- GPU_blend(GPU_BLEND_ALPHA);
- GPU_line_smooth(true);
- /* Using different shades of #TH_TEXT_HI for the emphasis, like triangle. */
- if (node->flag & NODE_ACTIVE) {
- UI_GetThemeColorShadeAlpha4fv(TH_TEXT_HI, 0, -40, debug_color);
- }
- else {
- UI_GetThemeColorShadeAlpha4fv(TH_TEXT_HI, -20, -120, debug_color);
- }
- UI_draw_roundbox_4fv(false, rct->xmin, rct->ymin, rct->xmax, rct->ymax, size, debug_color);
-
- GPU_line_smooth(false);
- GPU_blend(GPU_BLEND_NONE);
- }
-#endif
-
- if (node->label[0] != '\0') {
- /* draw title (node label) */
- BLI_strncpy(showname, node->label, sizeof(showname));
- uiDefBut(node->block,
- UI_BTYPE_LABEL,
- 0,
- showname,
- (int)(rct->xmin - NODE_DYS),
- (int)(rct->ymax),
- (short)512,
- (short)NODE_DY,
- nullptr,
- 0,
- 0,
- 0,
- 0,
- nullptr);
- }
-
- /* only draw input socket. as they all are placed on the same position.
- * highlight also if node itself is selected, since we don't display the node body separately!
- */
- node_draw_sockets(&region->v2d, C, ntree, node, false, node->flag & SELECT);
-
- UI_block_end(C, node->block);
- UI_block_draw(C, node->block);
- node->block = nullptr;
-}
-
-/* Special tweak area for reroute node.
- * Since this node is quite small, we use a larger tweak area for grabbing than for selection.
- */
-static int node_tweak_area_reroute(bNode *node, int x, int y)
-{
- /* square of tweak radius */
- const float tweak_radius_sq = square_f(24.0f);
-
- bNodeSocket *sock = (bNodeSocket *)node->inputs.first;
- float dx = sock->locx - x;
- float dy = sock->locy - y;
- return (dx * dx + dy * dy <= tweak_radius_sq);
-}
-
static void node_common_set_butfunc(bNodeType *ntype)
{
switch (ntype->type) {
@@ -635,15 +326,7 @@ static void node_common_set_butfunc(bNodeType *ntype)
ntype->draw_buttons = node_draw_buttons_group;
break;
case NODE_FRAME:
- ntype->draw_nodetype = node_draw_frame;
- ntype->draw_nodetype_prepare = node_draw_frame_prepare;
ntype->draw_buttons_ex = node_buts_frame_ex;
- ntype->resize_area_func = node_resize_area_frame;
- break;
- case NODE_REROUTE:
- ntype->draw_nodetype = node_draw_reroute;
- ntype->draw_nodetype_prepare = node_draw_reroute_prepare;
- ntype->tweak_area_func = node_tweak_area_reroute;
break;
}
}
@@ -1412,763 +1095,6 @@ static void node_composit_buts_image_ex(uiLayout *layout, bContext *C, PointerRN
uiTemplateImage(layout, C, ptr, "image", &iuserptr, false, true);
}
-static void node_composit_buts_viewlayers(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- bNode *node = (bNode *)ptr->data;
- uiLayout *col, *row;
-
- uiTemplateID(layout,
- C,
- ptr,
- "scene",
- nullptr,
- nullptr,
- nullptr,
- UI_TEMPLATE_ID_FILTER_ALL,
- false,
- nullptr);
-
- if (!node->id) {
- return;
- }
-
- col = uiLayoutColumn(layout, false);
- row = uiLayoutRow(col, true);
- uiItemR(row, ptr, "layer", DEFAULT_FLAGS, "", ICON_NONE);
-
- PropertyRNA *prop = RNA_struct_find_property(ptr, "layer");
- const char *layer_name;
- if (!(RNA_property_enum_identifier(
- C, ptr, prop, RNA_property_enum_get(ptr, prop), &layer_name))) {
- return;
- }
-
- PointerRNA scn_ptr;
- char scene_name[MAX_ID_NAME - 2];
- scn_ptr = RNA_pointer_get(ptr, "scene");
- RNA_string_get(&scn_ptr, "name", scene_name);
-
- PointerRNA op_ptr;
- uiItemFullO(
- row, "RENDER_OT_render", "", ICON_RENDER_STILL, nullptr, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
- RNA_string_set(&op_ptr, "layer", layer_name);
- RNA_string_set(&op_ptr, "scene", scene_name);
-}
-
-static void node_composit_buts_blur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col, *row;
-
- col = uiLayoutColumn(layout, false);
- const int filter = RNA_enum_get(ptr, "filter_type");
- const int reference = RNA_boolean_get(ptr, "use_variable_size");
-
- uiItemR(col, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE);
- if (filter != R_FILTER_FAST_GAUSS) {
- uiItemR(col, ptr, "use_variable_size", DEFAULT_FLAGS, nullptr, ICON_NONE);
- if (!reference) {
- uiItemR(col, ptr, "use_bokeh", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
- uiItemR(col, ptr, "use_gamma_correction", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
-
- uiItemR(col, ptr, "use_relative", DEFAULT_FLAGS, nullptr, 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", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(layout, true);
- 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", DEFAULT_FLAGS, IFACE_("X"), ICON_NONE);
- uiItemR(col, ptr, "size_y", DEFAULT_FLAGS, IFACE_("Y"), ICON_NONE);
- }
- uiItemR(col, ptr, "use_extended_bounds", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_dblur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- uiItemR(layout, ptr, "iterations", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "use_wrap", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(layout, true);
- uiItemL(col, IFACE_("Center:"), 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", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "angle", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- uiItemS(layout);
-
- uiItemR(layout, ptr, "spin", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "zoom", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_bilateralblur(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "iterations", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "sigma_color", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "sigma_space", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_defocus(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- uiLayout *sub, *col;
-
- col = uiLayoutColumn(layout, false);
- uiItemL(col, IFACE_("Bokeh Type:"), ICON_NONE);
- uiItemR(col, ptr, "bokeh", DEFAULT_FLAGS, "", ICON_NONE);
- uiItemR(col, ptr, "angle", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- uiItemR(layout, ptr, "use_gamma_correction", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(layout, false);
- uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_zbuffer") == true);
- uiItemR(col, ptr, "f_stop", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- uiItemR(layout, ptr, "blur_max", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "threshold", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "use_preview", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- uiTemplateID(layout,
- C,
- ptr,
- "scene",
- nullptr,
- nullptr,
- nullptr,
- UI_TEMPLATE_ID_FILTER_ALL,
- false,
- nullptr);
-
- col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "use_zbuffer", DEFAULT_FLAGS, nullptr, ICON_NONE);
- sub = uiLayoutColumn(col, false);
- uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_zbuffer") == false);
- uiItemR(sub, ptr, "z_scale", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_antialiasing(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, false);
-
- uiItemR(col, ptr, "threshold", 0, nullptr, ICON_NONE);
- uiItemR(col, ptr, "contrast_limit", 0, nullptr, ICON_NONE);
- uiItemR(col, ptr, "corner_rounding", 0, nullptr, ICON_NONE);
-}
-
-/* glare node */
-static void node_composit_buts_glare(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- 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", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- if (RNA_enum_get(ptr, "glare_type") != 0) {
- uiItemR(
- layout, ptr, "color_modulation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- }
- }
-
- uiItemR(layout, ptr, "mix", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "threshold", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- if (RNA_enum_get(ptr, "glare_type") == 2) {
- uiItemR(layout, ptr, "streaks", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "angle_offset", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
- if (RNA_enum_get(ptr, "glare_type") == 0 || RNA_enum_get(ptr, "glare_type") == 2) {
- uiItemR(layout, ptr, "fade", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-
- if (RNA_enum_get(ptr, "glare_type") == 0) {
- uiItemR(layout, ptr, "use_rotate_45", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
- }
- if (RNA_enum_get(ptr, "glare_type") == 1) {
- uiItemR(layout, ptr, "size", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
-}
-
-static void node_composit_buts_tonemap(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "tonemap_type", DEFAULT_FLAGS, "", ICON_NONE);
- if (RNA_enum_get(ptr, "tonemap_type") == 0) {
- uiItemR(col, ptr, "key", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "offset", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "gamma", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
- else {
- uiItemR(col, ptr, "intensity", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "adaptation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "correction", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- }
-}
-
-static void node_composit_buts_lensdist(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "use_projector", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(col, false);
- uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_projector") == false);
- uiItemR(col, ptr, "use_jitter", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "use_fit", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_vecblur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "samples", DEFAULT_FLAGS, nullptr, 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", DEFAULT_FLAGS, IFACE_("Min"), ICON_NONE);
- uiItemR(col, ptr, "speed_max", DEFAULT_FLAGS, IFACE_("Max"), ICON_NONE);
-
- uiItemR(layout, ptr, "use_curved", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_filter(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- 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", 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", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "relative", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(layout, true);
- if (RNA_boolean_get(ptr, "relative")) {
- 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", 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);
- }
-}
-
-static void node_composit_buts_splitviewer(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *row, *col;
-
- col = uiLayoutColumn(layout, false);
- row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "axis", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
- uiItemR(col, ptr, "factor", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_double_edge_mask(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, false);
-
- uiItemL(col, IFACE_("Inner Edge:"), ICON_NONE);
- uiItemR(col, ptr, "inner_mode", DEFAULT_FLAGS, "", ICON_NONE);
- uiItemL(col, IFACE_("Buffer Edge:"), 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)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "use_clamp", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_map_value(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *sub, *col;
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "offset", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "size", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "use_min", DEFAULT_FLAGS, nullptr, ICON_NONE);
- sub = uiLayoutColumn(col, false);
- uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_min"));
- uiItemR(sub, ptr, "min", DEFAULT_FLAGS, "", ICON_NONE);
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "use_max", DEFAULT_FLAGS, nullptr, ICON_NONE);
- sub = uiLayoutColumn(col, false);
- uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_max"));
- uiItemR(sub, ptr, "max", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_composit_buts_alphaover(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "use_premultiply", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "premul", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_zcombine(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "use_alpha", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "use_antialias_z", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_dilateerode(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "mode", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "distance", DEFAULT_FLAGS, nullptr, ICON_NONE);
- switch (RNA_enum_get(ptr, "mode")) {
- case CMP_NODE_DILATEERODE_DISTANCE_THRESH:
- uiItemR(layout, ptr, "edge", DEFAULT_FLAGS, nullptr, ICON_NONE);
- break;
- case CMP_NODE_DILATEERODE_DISTANCE_FEATHER:
- uiItemR(layout, ptr, "falloff", DEFAULT_FLAGS, nullptr, ICON_NONE);
- break;
- }
-}
-
-static void node_composit_buts_inpaint(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "distance", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_despeckle(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "threshold", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "threshold_neighbor", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_diff_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "tolerance", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "falloff", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_distance_matte(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
-{
- uiLayout *col, *row;
-
- col = uiLayoutColumn(layout, true);
-
- uiItemL(layout, IFACE_("Color Space:"), ICON_NONE);
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
-
- uiItemR(col, ptr, "tolerance", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "falloff", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_color_spill(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *row, *col;
-
- uiItemL(layout, IFACE_("Despill Channel:"), ICON_NONE);
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "limit_method", DEFAULT_FLAGS, nullptr, 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", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
- }
-
- uiItemR(col, ptr, "ratio", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "use_unspill", DEFAULT_FLAGS, nullptr, ICON_NONE);
- if (RNA_boolean_get(ptr, "use_unspill") == true) {
- uiItemR(col, ptr, "unspill_red", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "unspill_green", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "unspill_blue", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- }
-}
-
-static void node_composit_buts_chroma_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "tolerance", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "threshold", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(layout, true);
- /* Removed for now. */
- // uiItemR(col, ptr, "lift", UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- /* Removed for now. */
- // uiItemR(col, ptr, "shadow_adjust", UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_color_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "color_hue", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "color_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "color_value", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_channel_matte(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
-{
- uiLayout *col, *row;
-
- uiItemL(layout, IFACE_("Color Space:"), ICON_NONE);
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "color_space", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(layout, false);
- uiItemL(col, IFACE_("Key Channel:"), ICON_NONE);
- row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "matte_channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(layout, false);
-
- uiItemR(col, ptr, "limit_method", DEFAULT_FLAGS, nullptr, 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", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
- }
-
- uiItemR(col, ptr, "limit_max", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "limit_min", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_luma_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "limit_max", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "limit_min", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_map_uv(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "alpha", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_id_mask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "index", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "use_antialiasing", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_file_output(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- PointerRNA imfptr = RNA_pointer_get(ptr, "format");
- const bool multilayer = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_MULTILAYER;
-
- if (multilayer) {
- uiItemL(layout, IFACE_("Path:"), ICON_NONE);
- }
- else {
- uiItemL(layout, IFACE_("Base Path:"), 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)
-{
- Scene *scene = CTX_data_scene(C);
- PointerRNA imfptr = RNA_pointer_get(ptr, "format");
- PointerRNA active_input_ptr, op_ptr;
- uiLayout *row, *col;
- const bool multilayer = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_MULTILAYER;
- const bool is_exr = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_OPENEXR;
- const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
-
- node_composit_buts_file_output(layout, C, ptr);
- uiTemplateImageSettings(layout, &imfptr, false);
-
- /* disable stereo output for multilayer, too much work for something that no one will use */
- /* if someone asks for that we can implement it */
- if (is_multiview) {
- uiTemplateImageFormatViews(layout, &imfptr, nullptr);
- }
-
- uiItemS(layout);
-
- uiItemO(layout, IFACE_("Add Input"), ICON_ADD, "NODE_OT_output_file_add_socket");
-
- row = uiLayoutRow(layout, false);
- col = uiLayoutColumn(row, true);
-
- const int active_index = RNA_int_get(ptr, "active_input_index");
- /* using different collection properties if multilayer format is enabled */
- if (multilayer) {
- uiTemplateList(col,
- C,
- "UI_UL_list",
- "file_output_node",
- ptr,
- "layer_slots",
- ptr,
- "active_input_index",
- nullptr,
- 0,
- 0,
- 0,
- 0,
- UI_TEMPLATE_LIST_FLAG_NONE);
- RNA_property_collection_lookup_int(
- ptr, RNA_struct_find_property(ptr, "layer_slots"), active_index, &active_input_ptr);
- }
- else {
- uiTemplateList(col,
- C,
- "UI_UL_list",
- "file_output_node",
- ptr,
- "file_slots",
- ptr,
- "active_input_index",
- nullptr,
- 0,
- 0,
- 0,
- 0,
- UI_TEMPLATE_LIST_FLAG_NONE);
- RNA_property_collection_lookup_int(
- ptr, RNA_struct_find_property(ptr, "file_slots"), active_index, &active_input_ptr);
- }
- /* XXX collection lookup does not return the ID part of the pointer,
- * setting this manually here */
- active_input_ptr.owner_id = ptr->owner_id;
-
- col = uiLayoutColumn(row, true);
- wmOperatorType *ot = WM_operatortype_find("NODE_OT_output_file_move_active_socket", false);
- uiItemFullO_ptr(col, ot, "", ICON_TRIA_UP, nullptr, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
- RNA_enum_set(&op_ptr, "direction", 1);
- uiItemFullO_ptr(col, ot, "", ICON_TRIA_DOWN, nullptr, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
- RNA_enum_set(&op_ptr, "direction", 2);
-
- if (active_input_ptr.data) {
- if (multilayer) {
- col = uiLayoutColumn(layout, true);
-
- uiItemL(col, IFACE_("Layer:"), ICON_NONE);
- row = uiLayoutRow(col, false);
- uiItemR(row, &active_input_ptr, "name", DEFAULT_FLAGS, "", ICON_NONE);
- uiItemFullO(row,
- "NODE_OT_output_file_remove_active_socket",
- "",
- ICON_X,
- nullptr,
- WM_OP_EXEC_DEFAULT,
- UI_ITEM_R_ICON_ONLY,
- nullptr);
- }
- else {
- col = uiLayoutColumn(layout, true);
-
- uiItemL(col, IFACE_("File Subpath:"), ICON_NONE);
- row = uiLayoutRow(col, false);
- uiItemR(row, &active_input_ptr, "path", DEFAULT_FLAGS, "", ICON_NONE);
- uiItemFullO(row,
- "NODE_OT_output_file_remove_active_socket",
- "",
- ICON_X,
- nullptr,
- WM_OP_EXEC_DEFAULT,
- UI_ITEM_R_ICON_ONLY,
- nullptr);
-
- /* format details for individual files */
- imfptr = RNA_pointer_get(&active_input_ptr, "format");
-
- col = uiLayoutColumn(layout, true);
- uiItemL(col, IFACE_("Format:"), ICON_NONE);
- uiItemR(col, &active_input_ptr, "use_node_format", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- const bool is_socket_exr = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_OPENEXR;
- const bool use_node_format = RNA_boolean_get(&active_input_ptr, "use_node_format");
-
- if ((!is_exr && use_node_format) || (!is_socket_exr && !use_node_format)) {
- uiItemR(col, &active_input_ptr, "save_as_render", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
-
- col = uiLayoutColumn(layout, false);
- uiLayoutSetActive(col, use_node_format == false);
- uiTemplateImageSettings(col, &imfptr, false);
-
- if (is_multiview) {
- uiTemplateImageFormatViews(layout, &imfptr, nullptr);
- }
- }
- }
-}
-
-static void node_composit_buts_scale(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "space", DEFAULT_FLAGS, "", ICON_NONE);
-
- if (RNA_enum_get(ptr, "space") == CMP_SCALE_RENDERPERCENT) {
- uiLayout *row;
- uiItemR(layout, ptr, "frame_method", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
- row = uiLayoutRow(layout, true);
- 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", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_composit_buts_invert(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "invert_rgb", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "invert_alpha", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_premulkey(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- 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", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_composit_buts_colorbalance(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *split, *col, *row;
-
- uiItemR(layout, ptr, "correction_method", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- if (RNA_enum_get(ptr, "correction_method") == 0) {
-
- split = uiLayoutSplit(layout, 0.0f, false);
- col = uiLayoutColumn(split, false);
- uiTemplateColorPicker(col, ptr, "lift", true, true, false, true);
- row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "lift", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(split, false);
- uiTemplateColorPicker(col, ptr, "gamma", true, true, true, true);
- row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "gamma", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(split, false);
- uiTemplateColorPicker(col, ptr, "gain", true, true, true, true);
- row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "gain", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
- else {
-
- split = uiLayoutSplit(layout, 0.0f, false);
- col = uiLayoutColumn(split, false);
- uiTemplateColorPicker(col, ptr, "offset", true, true, false, true);
- row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "offset", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "offset_basis", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(split, false);
- uiTemplateColorPicker(col, ptr, "power", true, true, false, true);
- row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "power", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(split, false);
- uiTemplateColorPicker(col, ptr, "slope", true, true, false, true);
- row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "slope", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
-}
-static void node_composit_buts_colorbalance_ex(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "correction_method", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- if (RNA_enum_get(ptr, "correction_method") == 0) {
-
- uiTemplateColorPicker(layout, ptr, "lift", true, true, false, true);
- uiItemR(layout, ptr, "lift", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- uiTemplateColorPicker(layout, ptr, "gamma", true, true, true, true);
- uiItemR(layout, ptr, "gamma", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- uiTemplateColorPicker(layout, ptr, "gain", true, true, true, true);
- uiItemR(layout, ptr, "gain", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
- else {
- uiTemplateColorPicker(layout, ptr, "offset", true, true, false, true);
- uiItemR(layout, ptr, "offset", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- uiTemplateColorPicker(layout, ptr, "power", true, true, false, true);
- uiItemR(layout, ptr, "power", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- uiTemplateColorPicker(layout, ptr, "slope", true, true, false, true);
- uiItemR(layout, ptr, "slope", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
-}
-
static void node_composit_buts_huecorrect(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
bNode *node = (bNode *)ptr->data;
@@ -2190,260 +1116,6 @@ static void node_composit_buts_ycc(uiLayout *layout, bContext *UNUSED(C), Pointe
uiItemR(layout, ptr, "mode", DEFAULT_FLAGS, "", ICON_NONE);
}
-static void node_composit_buts_movieclip(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- uiTemplateID(layout,
- C,
- ptr,
- "clip",
- nullptr,
- "CLIP_OT_open",
- nullptr,
- UI_TEMPLATE_ID_FILTER_ALL,
- false,
- nullptr);
-}
-
-static void node_composit_buts_movieclip_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- bNode *node = (bNode *)ptr->data;
- PointerRNA clipptr;
-
- uiTemplateID(layout,
- C,
- ptr,
- "clip",
- nullptr,
- "CLIP_OT_open",
- nullptr,
- UI_TEMPLATE_ID_FILTER_ALL,
- false,
- nullptr);
-
- if (!node->id) {
- return;
- }
-
- clipptr = RNA_pointer_get(ptr, "clip");
-
- uiTemplateColorspaceSettings(layout, &clipptr, "colorspace_settings");
-}
-
-static void node_composit_buts_stabilize2d(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- bNode *node = (bNode *)ptr->data;
-
- uiTemplateID(layout,
- C,
- ptr,
- "clip",
- nullptr,
- "CLIP_OT_open",
- nullptr,
- UI_TEMPLATE_ID_FILTER_ALL,
- false,
- nullptr);
-
- if (!node->id) {
- return;
- }
-
- uiItemR(layout, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE);
- uiItemR(layout, ptr, "invert", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_translate(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "use_relative", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "wrap_axis", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_transform(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_composit_buts_moviedistortion(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- bNode *node = (bNode *)ptr->data;
-
- uiTemplateID(layout,
- C,
- ptr,
- "clip",
- nullptr,
- "CLIP_OT_open",
- nullptr,
- UI_TEMPLATE_ID_FILTER_ALL,
- false,
- nullptr);
-
- if (!node->id) {
- return;
- }
-
- uiItemR(layout, ptr, "distortion_type", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_composit_buts_colorcorrection(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
-{
- uiLayout *row;
-
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "red", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(row, ptr, "green", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(row, ptr, "blue", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- row = uiLayoutRow(layout, false);
- uiItemL(row, "", ICON_NONE);
- uiItemL(row, IFACE_("Saturation"), ICON_NONE);
- uiItemL(row, IFACE_("Contrast"), ICON_NONE);
- uiItemL(row, IFACE_("Gamma"), ICON_NONE);
- uiItemL(row, IFACE_("Gain"), ICON_NONE);
- uiItemL(row, IFACE_("Lift"), ICON_NONE);
-
- row = uiLayoutRow(layout, false);
- uiItemL(row, IFACE_("Master"), 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", 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", 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", 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", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "midtones_end", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_colorcorrection_ex(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
-{
- uiLayout *row;
-
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "red", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(row, ptr, "green", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(row, ptr, "blue", DEFAULT_FLAGS, nullptr, ICON_NONE);
- row = layout;
- uiItemL(row, IFACE_("Saturation"), ICON_NONE);
- uiItemR(row, ptr, "master_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "highlights_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "midtones_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "shadows_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-
- uiItemL(row, IFACE_("Contrast"), ICON_NONE);
- uiItemR(row, ptr, "master_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "highlights_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "midtones_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "shadows_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-
- uiItemL(row, IFACE_("Gamma"), ICON_NONE);
- uiItemR(row, ptr, "master_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "highlights_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "midtones_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "shadows_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-
- uiItemL(row, IFACE_("Gain"), ICON_NONE);
- uiItemR(row, ptr, "master_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "highlights_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "midtones_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "shadows_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-
- uiItemL(row, IFACE_("Lift"), ICON_NONE);
- uiItemR(row, ptr, "master_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "highlights_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "midtones_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "shadows_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "midtones_start", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(row, ptr, "midtones_end", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_set_alpha(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "mode", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_switch(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "check", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_switch_view_ex(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *UNUSED(ptr))
-{
- uiItemFullO(layout,
- "NODE_OT_switch_view_update",
- "Update Views",
- ICON_FILE_REFRESH,
- nullptr,
- WM_OP_INVOKE_DEFAULT,
- 0,
- nullptr);
-}
-
-static void node_composit_buts_boxmask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *row;
-
- row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "x", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(row, ptr, "y", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "width", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "height", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-
- uiItemR(layout, ptr, "rotation", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "mask_type", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_bokehimage(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "flaps", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "angle", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "rounding", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "catadioptric", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "shift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_bokehblur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "use_variable_size", DEFAULT_FLAGS, nullptr, ICON_NONE);
- // uiItemR(layout, ptr, "f_stop", DEFAULT_FLAGS, nullptr, ICON_NONE); /* UNUSED */
- uiItemR(layout, ptr, "blur_max", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "use_extended_bounds", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
static void node_composit_backdrop_viewer(
SpaceNode *snode, ImBuf *backdrop, bNode *node, int x, int y)
{
@@ -2563,227 +1235,6 @@ static void node_composit_backdrop_ellipsemask(
immUnbindProgram();
}
-static void node_composit_buts_ellipsemask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *row;
- row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "x", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(row, ptr, "y", DEFAULT_FLAGS, nullptr, ICON_NONE);
- row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "width", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "height", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-
- uiItemR(layout, ptr, "rotation", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "mask_type", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_composite(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "use_alpha", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_viewer(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "use_alpha", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_viewer_ex(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- uiItemR(layout, ptr, "use_alpha", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "tile_order", DEFAULT_FLAGS, nullptr, ICON_NONE);
- if (RNA_enum_get(ptr, "tile_order") == 0) {
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "center_x", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "center_y", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
-}
-
-static void node_composit_buts_mask(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- bNode *node = (bNode *)ptr->data;
-
- uiTemplateID(layout,
- C,
- ptr,
- "mask",
- nullptr,
- nullptr,
- nullptr,
- UI_TEMPLATE_ID_FILTER_ALL,
- false,
- nullptr);
- uiItemR(layout, ptr, "use_feather", DEFAULT_FLAGS, nullptr, 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", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "size_y", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
-
- uiItemR(layout, ptr, "use_motion_blur", DEFAULT_FLAGS, nullptr, ICON_NONE);
- if (node->custom1 & CMP_NODEFLAG_MASK_MOTION_BLUR) {
- uiItemR(layout, ptr, "motion_blur_samples", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "motion_blur_shutter", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
-}
-
-static void node_composit_buts_keyingscreen(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- bNode *node = (bNode *)ptr->data;
-
- uiTemplateID(layout,
- C,
- ptr,
- "clip",
- nullptr,
- nullptr,
- nullptr,
- UI_TEMPLATE_ID_FILTER_ALL,
- false,
- nullptr);
-
- if (node->id) {
- MovieClip *clip = (MovieClip *)node->id;
- uiLayout *col;
- PointerRNA tracking_ptr;
-
- RNA_pointer_create(&clip->id, &RNA_MovieTracking, &clip->tracking, &tracking_ptr);
-
- col = uiLayoutColumn(layout, true);
- uiItemPointerR(col, ptr, "tracking_object", &tracking_ptr, "objects", "", ICON_OBJECT_DATA);
- }
-}
-
-static void node_composit_buts_keying(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- /* bNode *node = (bNode*)ptr->data; */ /* UNUSED */
-
- uiItemR(layout, ptr, "blur_pre", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "screen_balance", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "despill_factor", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "despill_balance", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "edge_kernel_radius", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "edge_kernel_tolerance", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "clip_black", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "clip_white", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "dilate_distance", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "feather_falloff", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "feather_distance", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "blur_post", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_trackpos(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- bNode *node = (bNode *)ptr->data;
-
- uiTemplateID(layout,
- C,
- ptr,
- "clip",
- nullptr,
- "CLIP_OT_open",
- nullptr,
- UI_TEMPLATE_ID_FILTER_ALL,
- false,
- nullptr);
-
- if (node->id) {
- MovieClip *clip = (MovieClip *)node->id;
- MovieTracking *tracking = &clip->tracking;
- MovieTrackingObject *object;
- uiLayout *col;
- PointerRNA tracking_ptr;
- NodeTrackPosData *data = (NodeTrackPosData *)node->storage;
-
- RNA_pointer_create(&clip->id, &RNA_MovieTracking, tracking, &tracking_ptr);
-
- col = uiLayoutColumn(layout, false);
- uiItemPointerR(col, ptr, "tracking_object", &tracking_ptr, "objects", "", ICON_OBJECT_DATA);
-
- object = BKE_tracking_object_get_named(tracking, data->tracking_object);
- if (object) {
- PointerRNA object_ptr;
-
- RNA_pointer_create(&clip->id, &RNA_MovieTrackingObject, object, &object_ptr);
-
- uiItemPointerR(col, ptr, "track_name", &object_ptr, "tracks", "", ICON_ANIM_DATA);
- }
- else {
- uiItemR(layout, ptr, "track_name", DEFAULT_FLAGS, "", ICON_ANIM_DATA);
- }
-
- uiItemR(layout, ptr, "position", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- if (ELEM(node->custom1, CMP_TRACKPOS_RELATIVE_FRAME, CMP_TRACKPOS_ABSOLUTE_FRAME)) {
- uiItemR(layout, ptr, "frame_relative", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
- }
-}
-
-static void node_composit_buts_planetrackdeform(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- bNode *node = (bNode *)ptr->data;
- NodePlaneTrackDeformData *data = (NodePlaneTrackDeformData *)node->storage;
-
- uiTemplateID(layout,
- C,
- ptr,
- "clip",
- nullptr,
- "CLIP_OT_open",
- nullptr,
- UI_TEMPLATE_ID_FILTER_ALL,
- false,
- nullptr);
-
- if (node->id) {
- MovieClip *clip = (MovieClip *)node->id;
- MovieTracking *tracking = &clip->tracking;
- MovieTrackingObject *object;
- uiLayout *col;
- PointerRNA tracking_ptr;
-
- RNA_pointer_create(&clip->id, &RNA_MovieTracking, tracking, &tracking_ptr);
-
- col = uiLayoutColumn(layout, false);
- uiItemPointerR(col, ptr, "tracking_object", &tracking_ptr, "objects", "", ICON_OBJECT_DATA);
-
- object = BKE_tracking_object_get_named(tracking, data->tracking_object);
- if (object) {
- PointerRNA object_ptr;
-
- RNA_pointer_create(&clip->id, &RNA_MovieTrackingObject, object, &object_ptr);
-
- uiItemPointerR(
- col, ptr, "plane_track_name", &object_ptr, "plane_tracks", "", ICON_ANIM_DATA);
- }
- else {
- uiItemR(layout, ptr, "plane_track_name", 0, "", ICON_ANIM_DATA);
- }
- }
-
- uiItemR(layout, ptr, "use_motion_blur", DEFAULT_FLAGS, nullptr, ICON_NONE);
- if (data->flag & CMP_NODEFLAG_PLANETRACKDEFORM_MOTION_BLUR) {
- uiItemR(layout, ptr, "motion_blur_samples", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "motion_blur_shutter", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
-}
-
-static void node_composit_buts_cornerpin(uiLayout *UNUSED(layout),
- bContext *UNUSED(C),
- PointerRNA *UNUSED(ptr))
-{
-}
-
-static void node_composit_buts_sunbeams(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "source", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, "", ICON_NONE);
- uiItemR(layout, ptr, "ray_length", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-}
-
static void node_composit_buts_cryptomatte_legacy(uiLayout *layout,
bContext *UNUSED(C),
PointerRNA *ptr)
@@ -2859,31 +1310,6 @@ static void node_composit_buts_cryptomatte(uiLayout *layout, bContext *C, Pointe
uiTemplateCryptoPicker(row, ptr, "remove", ICON_REMOVE);
}
-static void node_composit_buts_brightcontrast(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "use_premultiply", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_denoise(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
-#ifndef WITH_OPENIMAGEDENOISE
- uiItemL(layout, IFACE_("Disabled, built without OpenImageDenoise"), ICON_ERROR);
-#else
- /* Always supported through Accelerate framework BNNS on macOS. */
-# ifndef __APPLE__
- if (!BLI_cpu_support_sse41()) {
- uiItemL(layout, IFACE_("Disabled, CPU with SSE4.1 is required"), ICON_ERROR);
- }
-# endif
-#endif
-
- uiItemL(layout, IFACE_("Prefilter:"), ICON_NONE);
- uiItemR(layout, ptr, "prefilter", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "use_hdr", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
/* only once called */
static void node_composit_set_butfunc(bNodeType *ntype)
{
@@ -2892,15 +1318,6 @@ static void node_composit_set_butfunc(bNodeType *ntype)
ntype->draw_buttons = node_composit_buts_image;
ntype->draw_buttons_ex = node_composit_buts_image_ex;
break;
- case CMP_NODE_R_LAYERS:
- ntype->draw_buttons = node_composit_buts_viewlayers;
- break;
- case CMP_NODE_NORMAL:
- ntype->draw_buttons = node_buts_normal;
- break;
- case CMP_NODE_CURVE_VEC:
- ntype->draw_buttons = node_buts_curvevec;
- break;
case CMP_NODE_CURVE_RGB:
ntype->draw_buttons = node_buts_curvecol;
break;
@@ -2910,213 +1327,34 @@ static void node_composit_set_butfunc(bNodeType *ntype)
case CMP_NODE_RGB:
ntype->draw_buttons = node_buts_rgb;
break;
- case CMP_NODE_FLIP:
- ntype->draw_buttons = node_composit_buts_flip;
- break;
- case CMP_NODE_SPLITVIEWER:
- ntype->draw_buttons = node_composit_buts_splitviewer;
- break;
case CMP_NODE_MIX_RGB:
ntype->draw_buttons = node_buts_mix_rgb;
break;
case CMP_NODE_VALTORGB:
ntype->draw_buttons = node_buts_colorramp;
break;
- case CMP_NODE_CROP:
- ntype->draw_buttons = node_composit_buts_crop;
- break;
- case CMP_NODE_BLUR:
- ntype->draw_buttons = node_composit_buts_blur;
- break;
- case CMP_NODE_DBLUR:
- ntype->draw_buttons = node_composit_buts_dblur;
- break;
- case CMP_NODE_BILATERALBLUR:
- ntype->draw_buttons = node_composit_buts_bilateralblur;
- break;
- case CMP_NODE_DEFOCUS:
- ntype->draw_buttons = node_composit_buts_defocus;
- break;
- case CMP_NODE_ANTIALIASING:
- ntype->draw_buttons = node_composit_buts_antialiasing;
- break;
- case CMP_NODE_GLARE:
- ntype->draw_buttons = node_composit_buts_glare;
- break;
- case CMP_NODE_TONEMAP:
- ntype->draw_buttons = node_composit_buts_tonemap;
- break;
- case CMP_NODE_LENSDIST:
- ntype->draw_buttons = node_composit_buts_lensdist;
- break;
- case CMP_NODE_VECBLUR:
- ntype->draw_buttons = node_composit_buts_vecblur;
- break;
- case CMP_NODE_FILTER:
- ntype->draw_buttons = node_composit_buts_filter;
- break;
- case CMP_NODE_MAP_VALUE:
- ntype->draw_buttons = node_composit_buts_map_value;
- break;
- case CMP_NODE_MAP_RANGE:
- ntype->draw_buttons = node_composit_buts_map_range;
- break;
case CMP_NODE_TIME:
ntype->draw_buttons = node_buts_time;
break;
- case CMP_NODE_ALPHAOVER:
- ntype->draw_buttons = node_composit_buts_alphaover;
- break;
case CMP_NODE_TEXTURE:
ntype->draw_buttons = node_buts_texture;
break;
- case CMP_NODE_DILATEERODE:
- ntype->draw_buttons = node_composit_buts_dilateerode;
- break;
- case CMP_NODE_INPAINT:
- ntype->draw_buttons = node_composit_buts_inpaint;
- break;
- case CMP_NODE_DESPECKLE:
- ntype->draw_buttons = node_composit_buts_despeckle;
- break;
- case CMP_NODE_OUTPUT_FILE:
- ntype->draw_buttons = node_composit_buts_file_output;
- ntype->draw_buttons_ex = node_composit_buts_file_output_ex;
- break;
- case CMP_NODE_DIFF_MATTE:
- ntype->draw_buttons = node_composit_buts_diff_matte;
- break;
- case CMP_NODE_DIST_MATTE:
- ntype->draw_buttons = node_composit_buts_distance_matte;
- break;
- case CMP_NODE_COLOR_SPILL:
- ntype->draw_buttons = node_composit_buts_color_spill;
- break;
- case CMP_NODE_CHROMA_MATTE:
- ntype->draw_buttons = node_composit_buts_chroma_matte;
- break;
- case CMP_NODE_COLOR_MATTE:
- ntype->draw_buttons = node_composit_buts_color_matte;
- break;
- case CMP_NODE_SCALE:
- ntype->draw_buttons = node_composit_buts_scale;
- break;
- case CMP_NODE_ROTATE:
- ntype->draw_buttons = node_composit_buts_rotate;
- break;
- case CMP_NODE_CHANNEL_MATTE:
- ntype->draw_buttons = node_composit_buts_channel_matte;
- break;
- case CMP_NODE_LUMA_MATTE:
- ntype->draw_buttons = node_composit_buts_luma_matte;
- break;
- case CMP_NODE_MAP_UV:
- ntype->draw_buttons = node_composit_buts_map_uv;
- break;
- case CMP_NODE_ID_MASK:
- ntype->draw_buttons = node_composit_buts_id_mask;
- break;
- case CMP_NODE_DOUBLEEDGEMASK:
- ntype->draw_buttons = node_composit_buts_double_edge_mask;
- break;
case CMP_NODE_MATH:
ntype->draw_buttons = node_buts_math;
break;
- case CMP_NODE_INVERT:
- ntype->draw_buttons = node_composit_buts_invert;
- break;
- case CMP_NODE_PREMULKEY:
- ntype->draw_buttons = node_composit_buts_premulkey;
- break;
- case CMP_NODE_VIEW_LEVELS:
- ntype->draw_buttons = node_composit_buts_view_levels;
- break;
- case CMP_NODE_COLORBALANCE:
- ntype->draw_buttons = node_composit_buts_colorbalance;
- ntype->draw_buttons_ex = node_composit_buts_colorbalance_ex;
- break;
case CMP_NODE_HUECORRECT:
ntype->draw_buttons = node_composit_buts_huecorrect;
break;
- case CMP_NODE_ZCOMBINE:
- ntype->draw_buttons = node_composit_buts_zcombine;
- break;
case CMP_NODE_COMBYCCA:
case CMP_NODE_SEPYCCA:
ntype->draw_buttons = node_composit_buts_ycc;
break;
- case CMP_NODE_MOVIECLIP:
- ntype->draw_buttons = node_composit_buts_movieclip;
- ntype->draw_buttons_ex = node_composit_buts_movieclip_ex;
- break;
- case CMP_NODE_STABILIZE2D:
- ntype->draw_buttons = node_composit_buts_stabilize2d;
- break;
- case CMP_NODE_TRANSFORM:
- ntype->draw_buttons = node_composit_buts_transform;
- break;
- case CMP_NODE_TRANSLATE:
- ntype->draw_buttons = node_composit_buts_translate;
- break;
- case CMP_NODE_MOVIEDISTORTION:
- ntype->draw_buttons = node_composit_buts_moviedistortion;
- break;
- case CMP_NODE_COLORCORRECTION:
- ntype->draw_buttons = node_composit_buts_colorcorrection;
- ntype->draw_buttons_ex = node_composit_buts_colorcorrection_ex;
- break;
- case CMP_NODE_SETALPHA:
- ntype->draw_buttons = node_composit_buts_set_alpha;
- break;
- case CMP_NODE_SWITCH:
- ntype->draw_buttons = node_composit_buts_switch;
- break;
- case CMP_NODE_SWITCH_VIEW:
- ntype->draw_buttons_ex = node_composit_buts_switch_view_ex;
- break;
case CMP_NODE_MASK_BOX:
- ntype->draw_buttons = node_composit_buts_boxmask;
ntype->draw_backdrop = node_composit_backdrop_boxmask;
break;
case CMP_NODE_MASK_ELLIPSE:
- ntype->draw_buttons = node_composit_buts_ellipsemask;
ntype->draw_backdrop = node_composit_backdrop_ellipsemask;
break;
- case CMP_NODE_BOKEHIMAGE:
- ntype->draw_buttons = node_composit_buts_bokehimage;
- break;
- case CMP_NODE_BOKEHBLUR:
- ntype->draw_buttons = node_composit_buts_bokehblur;
- break;
- case CMP_NODE_VIEWER:
- ntype->draw_buttons = node_composit_buts_viewer;
- ntype->draw_buttons_ex = node_composit_buts_viewer_ex;
- ntype->draw_backdrop = node_composit_backdrop_viewer;
- break;
- case CMP_NODE_COMPOSITE:
- ntype->draw_buttons = node_composit_buts_composite;
- break;
- case CMP_NODE_MASK:
- ntype->draw_buttons = node_composit_buts_mask;
- break;
- case CMP_NODE_KEYINGSCREEN:
- ntype->draw_buttons = node_composit_buts_keyingscreen;
- break;
- case CMP_NODE_KEYING:
- ntype->draw_buttons = node_composit_buts_keying;
- break;
- case CMP_NODE_TRACKPOS:
- ntype->draw_buttons = node_composit_buts_trackpos;
- break;
- case CMP_NODE_PLANETRACKDEFORM:
- ntype->draw_buttons = node_composit_buts_planetrackdeform;
- break;
- case CMP_NODE_CORNERPIN:
- ntype->draw_buttons = node_composit_buts_cornerpin;
- break;
- case CMP_NODE_SUNBEAMS:
- ntype->draw_buttons = node_composit_buts_sunbeams;
- break;
case CMP_NODE_CRYPTOMATTE:
ntype->draw_buttons = node_composit_buts_cryptomatte;
break;
@@ -3124,11 +1362,8 @@ static void node_composit_set_butfunc(bNodeType *ntype)
ntype->draw_buttons = node_composit_buts_cryptomatte_legacy;
ntype->draw_buttons_ex = node_composit_buts_cryptomatte_legacy_ex;
break;
- case CMP_NODE_BRIGHTCONTRAST:
- ntype->draw_buttons = node_composit_buts_brightcontrast;
- break;
- case CMP_NODE_DENOISE:
- ntype->draw_buttons = node_composit_buts_denoise;
+ case CMP_NODE_VIEWER:
+ ntype->draw_backdrop = node_composit_backdrop_viewer;
break;
}
}
@@ -3391,20 +1626,14 @@ static void node_socket_undefined_interface_draw_color(bContext *UNUSED(C),
/** \} */
-void ED_node_init_butfuncs(void)
+void ED_node_init_butfuncs()
{
/* Fallback types for undefined tree, nodes, sockets
* Defined in blenkernel, but not registered in type hashes.
*/
- /* default ui functions */
- NodeTypeUndefined.draw_nodetype = node_draw_default;
- NodeTypeUndefined.draw_nodetype_prepare = node_update_default;
- NodeTypeUndefined.select_area_func = node_select_area_default;
- NodeTypeUndefined.tweak_area_func = node_tweak_area_default;
NodeTypeUndefined.draw_buttons = nullptr;
NodeTypeUndefined.draw_buttons_ex = nullptr;
- NodeTypeUndefined.resize_area_func = node_resize_area_default;
NodeSocketTypeUndefined.draw = node_socket_undefined_draw;
NodeSocketTypeUndefined.draw_color = node_socket_undefined_draw_color;
@@ -3413,13 +1642,6 @@ void ED_node_init_butfuncs(void)
/* node type ui functions */
NODE_TYPES_BEGIN (ntype) {
- /* default ui functions */
- ntype->draw_nodetype = node_draw_default;
- ntype->draw_nodetype_prepare = node_update_default;
- ntype->select_area_func = node_select_area_default;
- ntype->tweak_area_func = node_tweak_area_default;
- ntype->resize_area_func = node_resize_area_default;
-
node_common_set_butfunc(ntype);
node_composit_set_butfunc(ntype);
@@ -3438,19 +1660,12 @@ void ED_node_init_butfuncs(void)
ntreeType_Geometry->ui_icon = ICON_NODETREE;
}
-void ED_init_custom_node_type(bNodeType *ntype)
+void ED_init_custom_node_type(bNodeType *UNUSED(ntype))
{
- /* default ui functions */
- ntype->draw_nodetype = node_draw_default;
- ntype->draw_nodetype_prepare = node_update_default;
- ntype->resize_area_func = node_resize_area_default;
- ntype->select_area_func = node_select_area_default;
- ntype->tweak_area_func = node_tweak_area_default;
}
void ED_init_custom_node_socket_type(bNodeSocketType *stype)
{
- /* default ui functions */
stype->draw = node_socket_button_label;
}
@@ -3611,7 +1826,7 @@ static void std_node_socket_draw(
if (socket_needs_attribute_search(*node, *sock)) {
const bNodeTree *node_tree = (const bNodeTree *)node_ptr->owner_id;
- node_geometry_add_attribute_search_button(C, node_tree, node, ptr, row);
+ node_geometry_add_attribute_search_button(*C, *node_tree, *node, *ptr, *row);
}
else {
uiItemR(row, ptr, "default_value", DEFAULT_FLAGS, "", 0);
@@ -3760,23 +1975,23 @@ void ED_init_node_socket_type_virtual(bNodeSocketType *stype)
/* ************** Generic drawing ************** */
-void draw_nodespace_back_pix(const bContext *C,
- ARegion *region,
- SpaceNode *snode,
+void draw_nodespace_back_pix(const bContext &C,
+ ARegion &region,
+ SpaceNode &snode,
bNodeInstanceKey parent_key)
{
- Main *bmain = CTX_data_main(C);
- bNodeInstanceKey active_viewer_key = (snode->nodetree ? snode->nodetree->active_viewer_key :
- NODE_INSTANCE_KEY_NONE);
+ Main *bmain = CTX_data_main(&C);
+ bNodeInstanceKey active_viewer_key = (snode.nodetree ? snode.nodetree->active_viewer_key :
+ NODE_INSTANCE_KEY_NONE);
GPU_matrix_push_projection();
GPU_matrix_push();
- wmOrtho2_region_pixelspace(region);
+ wmOrtho2_region_pixelspace(&region);
GPU_matrix_identity_set();
- ED_region_draw_cb_draw(C, region, REGION_DRAW_BACKDROP);
+ ED_region_draw_cb_draw(&C, &region, REGION_DRAW_BACKDROP);
GPU_matrix_pop_projection();
GPU_matrix_pop();
- if (!(snode->flag & SNODE_BACKDRAW) || !ED_node_is_compositor(snode)) {
+ if (!(snode.flag & SNODE_BACKDRAW) || !ED_node_is_compositor(&snode)) {
return;
}
@@ -3791,7 +2006,7 @@ void draw_nodespace_back_pix(const bContext *C,
GPUFrameBuffer *old_fb = GPU_framebuffer_active_get();
GPU_framebuffer_restore();
BLI_thread_lock(LOCK_DRAW_IMAGE);
- DRW_draw_view(C);
+ DRW_draw_view(&C);
BLI_thread_unlock(LOCK_DRAW_IMAGE);
GPU_framebuffer_bind_no_srgb(old_fb);
/* Draw manager changes the depth state. Set it back to NONE. Without this the node preview
@@ -3803,31 +2018,31 @@ void draw_nodespace_back_pix(const bContext *C,
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, nullptr, &lock);
if (ibuf) {
/* somehow the offset has to be calculated inverse */
- wmOrtho2_region_pixelspace(region);
- const float x = (region->winx - snode->zoom * ibuf->x) / 2 + snode->xof;
- const float y = (region->winy - snode->zoom * ibuf->y) / 2 + snode->yof;
+ wmOrtho2_region_pixelspace(&region);
+ const float x = (region.winx - snode.zoom * ibuf->x) / 2 + snode.xof;
+ const float y = (region.winy - snode.zoom * ibuf->y) / 2 + snode.yof;
/** \note draw selected info on backdrop */
- if (snode->edittree) {
- bNode *node = (bNode *)snode->edittree->nodes.first;
- rctf *viewer_border = &snode->nodetree->viewer_border;
+ if (snode.edittree) {
+ bNode *node = (bNode *)snode.edittree->nodes.first;
+ rctf *viewer_border = &snode.nodetree->viewer_border;
while (node) {
if (node->flag & NODE_SELECT) {
if (node->typeinfo->draw_backdrop) {
- node->typeinfo->draw_backdrop(snode, ibuf, node, x, y);
+ node->typeinfo->draw_backdrop(&snode, ibuf, node, x, y);
}
}
node = node->next;
}
- if ((snode->nodetree->flag & NTREE_VIEWER_BORDER) &&
+ if ((snode.nodetree->flag & NTREE_VIEWER_BORDER) &&
viewer_border->xmin < viewer_border->xmax && viewer_border->ymin < viewer_border->ymax) {
rcti pixel_border;
BLI_rcti_init(&pixel_border,
- x + snode->zoom * viewer_border->xmin * ibuf->x,
- x + snode->zoom * viewer_border->xmax * ibuf->x,
- y + snode->zoom * viewer_border->ymin * ibuf->y,
- y + snode->zoom * viewer_border->ymax * ibuf->y);
+ x + snode.zoom * viewer_border->xmin * ibuf->x,
+ x + snode.zoom * viewer_border->xmax * ibuf->x,
+ y + snode.zoom * viewer_border->ymin * ibuf->y,
+ y + snode.zoom * viewer_border->ymax * ibuf->y);
uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
@@ -3846,10 +2061,9 @@ void draw_nodespace_back_pix(const bContext *C,
GPU_matrix_pop();
}
-/* return quadratic beziers points for a given nodelink and clip if v2d is not nullptr. */
bool node_link_bezier_handles(const View2D *v2d,
const SpaceNode *snode,
- const bNodeLink *link,
+ const bNodeLink &link,
float vec[4][2])
{
float cursor[2] = {0.0f, 0.0f};
@@ -3863,17 +2077,17 @@ bool node_link_bezier_handles(const View2D *v2d,
/* in v0 and v3 we put begin/end points */
int toreroute, fromreroute;
- if (link->fromsock) {
- vec[0][0] = link->fromsock->locx;
- vec[0][1] = link->fromsock->locy;
- if (link->fromsock->flag & SOCK_MULTI_INPUT) {
- node_link_calculate_multi_input_position(link->fromsock->locx,
- link->fromsock->locy,
- link->fromsock->total_inputs - 1,
- link->fromsock->total_inputs,
- vec[0]);
- }
- fromreroute = (link->fromnode && link->fromnode->type == NODE_REROUTE);
+ if (link.fromsock) {
+ vec[0][0] = link.fromsock->locx;
+ vec[0][1] = link.fromsock->locy;
+ if (link.fromsock->flag & SOCK_MULTI_INPUT) {
+ const float2 position = node_link_calculate_multi_input_position(
+ {link.fromsock->locx, link.fromsock->locy},
+ link.fromsock->total_inputs - 1,
+ link.fromsock->total_inputs);
+ copy_v2_v2(vec[0], position);
+ }
+ fromreroute = (link.fromnode && link.fromnode->type == NODE_REROUTE);
}
else {
if (snode == nullptr) {
@@ -3882,17 +2096,17 @@ bool node_link_bezier_handles(const View2D *v2d,
copy_v2_v2(vec[0], cursor);
fromreroute = 0;
}
- if (link->tosock) {
- vec[3][0] = link->tosock->locx;
- vec[3][1] = link->tosock->locy;
- if (!(link->tonode->flag & NODE_HIDDEN) && link->tosock->flag & SOCK_MULTI_INPUT) {
- node_link_calculate_multi_input_position(link->tosock->locx,
- link->tosock->locy,
- link->multi_input_socket_index,
- link->tosock->total_inputs,
- vec[3]);
+ if (link.tosock) {
+ vec[3][0] = link.tosock->locx;
+ vec[3][1] = link.tosock->locy;
+ if (!(link.tonode->flag & NODE_HIDDEN) && link.tosock->flag & SOCK_MULTI_INPUT) {
+ const float2 position = node_link_calculate_multi_input_position(
+ {link.tosock->locx, link.tosock->locy},
+ link.multi_input_socket_index,
+ link.tosock->total_inputs);
+ copy_v2_v2(vec[3], position);
}
- toreroute = (link->tonode && link->tonode->type == NODE_REROUTE);
+ toreroute = (link.tonode && link.tonode->type == NODE_REROUTE);
}
else {
if (snode == nullptr) {
@@ -3955,10 +2169,9 @@ bool node_link_bezier_handles(const View2D *v2d,
return true;
}
-/* if v2d not nullptr, it clips and returns 0 if not visible */
bool node_link_bezier_points(const View2D *v2d,
const SpaceNode *snode,
- const bNodeLink *link,
+ const bNodeLink &link,
float coord_array[][2],
const int resol)
{
@@ -4186,7 +2399,7 @@ static char nodelink_get_color_id(int th_col)
return 0;
}
-static void nodelink_batch_draw(const SpaceNode *snode)
+static void nodelink_batch_draw(const SpaceNode &snode)
{
if (g_batch_link.count == 0) {
return;
@@ -4206,7 +2419,7 @@ static void nodelink_batch_draw(const SpaceNode *snode)
GPU_batch_program_set_builtin(g_batch_link.batch, GPU_SHADER_2D_NODELINK_INST);
GPU_batch_uniform_4fv_array(g_batch_link.batch, "colors", 6, colors);
- GPU_batch_uniform_1f(g_batch_link.batch, "expandSize", snode->runtime->aspect * LINK_WIDTH);
+ GPU_batch_uniform_1f(g_batch_link.batch, "expandSize", snode.runtime->aspect * LINK_WIDTH);
GPU_batch_uniform_1f(g_batch_link.batch, "arrowSize", ARROW_SIZE);
GPU_batch_draw(g_batch_link.batch);
@@ -4215,22 +2428,22 @@ static void nodelink_batch_draw(const SpaceNode *snode)
GPU_blend(GPU_BLEND_NONE);
}
-void nodelink_batch_start(SpaceNode *UNUSED(snode))
+void nodelink_batch_start(SpaceNode &UNUSED(snode))
{
g_batch_link.enabled = true;
}
-void nodelink_batch_end(SpaceNode *snode)
+void nodelink_batch_end(SpaceNode &snode)
{
nodelink_batch_draw(snode);
g_batch_link.enabled = false;
}
-static void nodelink_batch_add_link(const SpaceNode *snode,
- const float p0[2],
- const float p1[2],
- const float p2[2],
- const float p3[2],
+static void nodelink_batch_add_link(const SpaceNode &snode,
+ const float2 &p0,
+ const float2 &p1,
+ const float2 &p2,
+ const float2 &p3,
int th_col1,
int th_col2,
int th_col3,
@@ -4272,14 +2485,13 @@ static void nodelink_batch_add_link(const SpaceNode *snode,
}
}
-/* don't do shadows if th_col3 is -1. */
-void node_draw_link_bezier(const bContext *C,
- const View2D *v2d,
- const SpaceNode *snode,
- const bNodeLink *link,
- int th_col1,
- int th_col2,
- int th_col3)
+void node_draw_link_bezier(const bContext &C,
+ const View2D &v2d,
+ const SpaceNode &snode,
+ const bNodeLink &link,
+ const int th_col1,
+ const int th_col2,
+ const int th_col3)
{
const float dim_factor = node_link_dim_factor(v2d, link);
float thickness = 1.5f;
@@ -4288,8 +2500,8 @@ void node_draw_link_bezier(const bContext *C,
bTheme *btheme = UI_GetTheme();
const float dash_alpha = btheme->space_node.dash_alpha;
- if (snode->edittree->type == NTREE_GEOMETRY) {
- if (link->fromsock && link->fromsock->display_shape == SOCK_DISPLAY_SHAPE_DIAMOND) {
+ if (snode.edittree->type == NTREE_GEOMETRY) {
+ if (link.fromsock && link.fromsock->display_shape == SOCK_DISPLAY_SHAPE_DIAMOND) {
/* Make field links a bit thinner. */
thickness = 1.0f;
/* Draw field as dashes. */
@@ -4298,11 +2510,11 @@ void node_draw_link_bezier(const bContext *C,
}
float vec[4][2];
- const bool highlighted = link->flag & NODE_LINK_TEMP_HIGHLIGHT;
- if (node_link_bezier_handles(v2d, snode, link, vec)) {
- int drawarrow = ((link->tonode && (link->tonode->type == NODE_REROUTE)) &&
- (link->fromnode && (link->fromnode->type == NODE_REROUTE)));
- int drawmuted = (link->flag & NODE_LINK_MUTED);
+ const bool highlighted = link.flag & NODE_LINK_TEMP_HIGHLIGHT;
+ if (node_link_bezier_handles(&v2d, &snode, link, vec)) {
+ int drawarrow = ((link.tonode && (link.tonode->type == NODE_REROUTE)) &&
+ (link.fromnode && (link.fromnode->type == NODE_REROUTE)));
+ int drawmuted = (link.flag & NODE_LINK_MUTED);
if (g_batch_link.batch == nullptr) {
nodelink_batch_init();
}
@@ -4312,23 +2524,23 @@ void node_draw_link_bezier(const bContext *C,
UI_GetThemeColor4fv(th_col3, colors[0]);
}
- if (snode->overlay.flag & SN_OVERLAY_SHOW_OVERLAYS &&
- snode->overlay.flag & SN_OVERLAY_SHOW_WIRE_COLORS) {
+ if (snode.overlay.flag & SN_OVERLAY_SHOW_OVERLAYS &&
+ snode.overlay.flag & SN_OVERLAY_SHOW_WIRE_COLORS) {
PointerRNA from_node_ptr, to_node_ptr;
- RNA_pointer_create((ID *)snode->edittree, &RNA_Node, link->fromnode, &from_node_ptr);
- RNA_pointer_create((ID *)snode->edittree, &RNA_Node, link->tonode, &to_node_ptr);
- if (link->fromsock) {
- node_socket_color_get(C, snode->edittree, &from_node_ptr, link->fromsock, colors[1]);
+ RNA_pointer_create((ID *)snode.edittree, &RNA_Node, link.fromnode, &from_node_ptr);
+ RNA_pointer_create((ID *)snode.edittree, &RNA_Node, link.tonode, &to_node_ptr);
+ if (link.fromsock) {
+ node_socket_color_get(C, *snode.edittree, from_node_ptr, *link.fromsock, colors[1]);
}
else {
- node_socket_color_get(C, snode->edittree, &to_node_ptr, link->tosock, colors[1]);
+ node_socket_color_get(C, *snode.edittree, to_node_ptr, *link.tosock, colors[1]);
}
- if (link->tosock) {
- node_socket_color_get(C, snode->edittree, &to_node_ptr, link->tosock, colors[2]);
+ if (link.tosock) {
+ node_socket_color_get(C, *snode.edittree, to_node_ptr, *link.tosock, colors[2]);
}
else {
- node_socket_color_get(C, snode->edittree, &from_node_ptr, link->fromsock, colors[2]);
+ node_socket_color_get(C, *snode.edittree, from_node_ptr, *link.fromsock, colors[2]);
}
}
else {
@@ -4337,8 +2549,8 @@ void node_draw_link_bezier(const bContext *C,
}
/* Highlight links connected to selected nodes. */
- const bool is_fromnode_selected = link->fromnode && link->fromnode->flag & SELECT;
- const bool is_tonode_selected = link->tonode && link->tonode->flag & SELECT;
+ const bool is_fromnode_selected = link.fromnode && link.fromnode->flag & SELECT;
+ const bool is_tonode_selected = link.tonode && link.tonode->flag & SELECT;
if (is_fromnode_selected || is_tonode_selected) {
float color_selected[4];
UI_GetThemeColor4fv(TH_EDGE_SELECT, color_selected);
@@ -4385,7 +2597,7 @@ void node_draw_link_bezier(const bContext *C,
GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_NODELINK);
GPU_batch_uniform_2fv_array(batch, "bezierPts", 4, vec);
GPU_batch_uniform_4fv_array(batch, "colors", 3, colors);
- GPU_batch_uniform_1f(batch, "expandSize", snode->runtime->aspect * LINK_WIDTH);
+ GPU_batch_uniform_1f(batch, "expandSize", snode.runtime->aspect * LINK_WIDTH);
GPU_batch_uniform_1f(batch, "arrowSize", ARROW_SIZE);
GPU_batch_uniform_1i(batch, "doArrow", drawarrow);
GPU_batch_uniform_1i(batch, "doMuted", drawmuted);
@@ -4398,37 +2610,36 @@ void node_draw_link_bezier(const bContext *C,
}
}
-/* NOTE: this is used for fake links in groups too. */
-void node_draw_link(const bContext *C,
- const View2D *v2d,
- const SpaceNode *snode,
- const bNodeLink *link)
+void node_draw_link(const bContext &C,
+ const View2D &v2d,
+ const SpaceNode &snode,
+ const bNodeLink &link)
{
int th_col1 = TH_WIRE_INNER, th_col2 = TH_WIRE_INNER, th_col3 = TH_WIRE;
- if (link->fromsock == nullptr && link->tosock == nullptr) {
+ if (link.fromsock == nullptr && link.tosock == nullptr) {
return;
}
/* new connection */
- if (!link->fromsock || !link->tosock) {
+ if (!link.fromsock || !link.tosock) {
th_col1 = th_col2 = TH_ACTIVE;
}
else {
/* going to give issues once... */
- if (link->tosock->flag & SOCK_UNAVAIL) {
+ if (link.tosock->flag & SOCK_UNAVAIL) {
return;
}
- if (link->fromsock->flag & SOCK_UNAVAIL) {
+ if (link.fromsock->flag & SOCK_UNAVAIL) {
return;
}
- if (link->flag & NODE_LINK_VALID) {
+ if (link.flag & NODE_LINK_VALID) {
/* special indicated link, on drop-node */
- if (link->flag & NODE_LINKFLAG_HILITE) {
+ if (link.flag & NODE_LINKFLAG_HILITE) {
th_col1 = th_col2 = TH_ACTIVE;
}
- else if (link->flag & NODE_LINK_MUTED) {
+ else if (link.flag & NODE_LINK_MUTED) {
th_col1 = th_col2 = TH_REDALERT;
}
}
@@ -4439,9 +2650,9 @@ void node_draw_link(const bContext *C,
}
}
/* Links from field to non-field sockets are not allowed. */
- if (snode->edittree->type == NTREE_GEOMETRY && !(link->flag & NODE_LINK_DRAGGED)) {
- if ((link->fromsock && link->fromsock->display_shape == SOCK_DISPLAY_SHAPE_DIAMOND) &&
- (link->tosock && link->tosock->display_shape == SOCK_DISPLAY_SHAPE_CIRCLE)) {
+ if (snode.edittree->type == NTREE_GEOMETRY && !(link.flag & NODE_LINK_DRAGGED)) {
+ if ((link.fromsock && link.fromsock->display_shape == SOCK_DISPLAY_SHAPE_DIAMOND) &&
+ (link.tosock && link.tosock->display_shape == SOCK_DISPLAY_SHAPE_CIRCLE)) {
th_col1 = th_col2 = th_col3 = TH_REDALERT;
}
}
diff --git a/source/blender/editors/space_node/link_drag_search.cc b/source/blender/editors/space_node/link_drag_search.cc
new file mode 100644
index 00000000000..e1ba36e81c0
--- /dev/null
+++ b/source/blender/editors/space_node/link_drag_search.cc
@@ -0,0 +1,291 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "BLI_listbase.h"
+#include "BLI_string_search.h"
+
+#include "DNA_space_types.h"
+
+#include "BKE_context.h"
+
+#include "NOD_socket_search_link.hh"
+
+#include "BLT_translation.h"
+
+#include "RNA_access.h"
+
+#include "WM_api.h"
+
+#include "node_intern.hh"
+
+using blender::nodes::SocketLinkOperation;
+
+namespace blender::ed::space_node {
+
+struct LinkDragSearchStorage {
+ bNode &from_node;
+ bNodeSocket &from_socket;
+ float2 cursor;
+ Vector<SocketLinkOperation> search_link_ops;
+ char search[256];
+
+ eNodeSocketInOut in_out() const
+ {
+ return static_cast<eNodeSocketInOut>(from_socket.in_out);
+ }
+};
+
+static void add_reroute_node_fn(nodes::LinkSearchOpParams &params)
+{
+ bNode &reroute = params.add_node("NodeReroute");
+ if (params.socket.in_out == SOCK_IN) {
+ nodeAddLink(&params.node_tree,
+ &reroute,
+ static_cast<bNodeSocket *>(reroute.outputs.first),
+ &params.node,
+ &params.socket);
+ }
+ else {
+ nodeAddLink(&params.node_tree,
+ &params.node,
+ &params.socket,
+ &reroute,
+ static_cast<bNodeSocket *>(reroute.inputs.first));
+ }
+}
+
+static void add_group_input_node_fn(nodes::LinkSearchOpParams &params)
+{
+ /* Add a group input based on the connected socket, and add a new group input node. */
+ bNodeSocket *interface_socket = ntreeAddSocketInterfaceFromSocket(
+ &params.node_tree, &params.node, &params.socket);
+ const int group_input_index = BLI_findindex(&params.node_tree.inputs, interface_socket);
+
+ bNode &group_input = params.add_node("NodeGroupInput");
+
+ /* This is necessary to create the new sockets in the other input nodes. */
+ ntreeUpdateTree(CTX_data_main(&params.C), &params.node_tree);
+
+ /* Hide the new input in all other group input nodes, to avoid making them taller. */
+ LISTBASE_FOREACH (bNode *, node, &params.node_tree.nodes) {
+ if (node->type == NODE_GROUP_INPUT) {
+ bNodeSocket *new_group_input_socket = (bNodeSocket *)BLI_findlink(&node->outputs,
+ group_input_index);
+ new_group_input_socket->flag |= SOCK_HIDDEN;
+ }
+ }
+
+ /* Hide all existing inputs in the new group input node, to only display the new one. */
+ LISTBASE_FOREACH (bNodeSocket *, socket, &group_input.outputs) {
+ socket->flag |= SOCK_HIDDEN;
+ }
+
+ bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&group_input.outputs, group_input_index);
+ if (socket == nullptr) {
+ /* Adding sockets can fail in some cases. There's no good reason not to be safe here. */
+ return;
+ }
+ /* Unhide the socket for the new input in the new node and make a connection to it. */
+ socket->flag &= ~SOCK_HIDDEN;
+ nodeAddLink(&params.node_tree, &group_input, socket, &params.node, &params.socket);
+}
+
+/**
+ * Call the callback to gather compatible socket connections for all node types, and the operations
+ * that will actually make the connections. Also add some custom operations like connecting a group
+ * output node.
+ */
+static void gather_socket_link_operations(bNodeTree &node_tree,
+ const bNodeSocket &socket,
+ Vector<SocketLinkOperation> &search_link_ops)
+{
+ NODE_TYPES_BEGIN (node_type) {
+ if (StringRef(node_type->idname).find("Legacy") != StringRef::not_found) {
+ continue;
+ }
+ const char *disabled_hint;
+ if (!(node_type->poll && node_type->poll(node_type, &node_tree, &disabled_hint))) {
+ continue;
+ }
+
+ if (node_type->gather_link_search_ops) {
+ nodes::GatherLinkSearchOpParams params{*node_type, node_tree, socket, search_link_ops};
+ node_type->gather_link_search_ops(params);
+ }
+ }
+ NODE_TYPES_END;
+
+ search_link_ops.append({IFACE_("Reroute"), add_reroute_node_fn});
+
+ const bool is_node_group = !(node_tree.id.flag & LIB_EMBEDDED_DATA);
+
+ if (is_node_group && socket.in_out == SOCK_IN) {
+ search_link_ops.append({IFACE_("Group Input"), add_group_input_node_fn});
+ }
+}
+
+static void link_drag_search_update_fn(const bContext *UNUSED(C),
+ void *arg,
+ const char *str,
+ uiSearchItems *items,
+ const bool is_first)
+{
+ LinkDragSearchStorage &storage = *static_cast<LinkDragSearchStorage *>(arg);
+
+ StringSearch *search = BLI_string_search_new();
+
+ for (SocketLinkOperation &op : storage.search_link_ops) {
+ BLI_string_search_add(search, op.name.c_str(), &op, op.weight);
+ }
+
+ /* Don't filter when the menu is first opened, but still run the search
+ * so the items are in the same order they will appear in while searching. */
+ const char *string = is_first ? "" : str;
+ SocketLinkOperation **filtered_items;
+ const int filtered_amount = BLI_string_search_query(search, string, (void ***)&filtered_items);
+
+ for (const int i : IndexRange(filtered_amount)) {
+ SocketLinkOperation &item = *filtered_items[i];
+ if (!UI_search_item_add(items, item.name.c_str(), &item, ICON_NONE, 0, 0)) {
+ break;
+ }
+ }
+
+ MEM_freeN(filtered_items);
+ BLI_string_search_free(search);
+}
+
+static void link_drag_search_exec_fn(bContext *C, void *arg1, void *arg2)
+{
+ Main &bmain = *CTX_data_main(C);
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ LinkDragSearchStorage &storage = *static_cast<LinkDragSearchStorage *>(arg1);
+ SocketLinkOperation *item = static_cast<SocketLinkOperation *>(arg2);
+ if (item == nullptr) {
+ return;
+ }
+
+ node_deselect_all(snode);
+
+ Vector<bNode *> new_nodes;
+ nodes::LinkSearchOpParams params{
+ *C, *snode.edittree, storage.from_node, storage.from_socket, new_nodes};
+ item->fn(params);
+ if (new_nodes.is_empty()) {
+ return;
+ }
+
+ /* For now, assume that only one node is created by the callback. */
+ BLI_assert(new_nodes.size() == 1);
+ bNode *new_node = new_nodes.first();
+
+ new_node->locx = storage.cursor.x / UI_DPI_FAC;
+ new_node->locy = storage.cursor.y / UI_DPI_FAC + 20 * UI_DPI_FAC;
+ if (storage.in_out() == SOCK_IN) {
+ new_node->locx -= new_node->width;
+ }
+
+ nodeSetSelected(new_node, true);
+ nodeSetActive(snode.edittree, new_node);
+
+ /* Ideally it would be possible to tag the node tree in some way so it updates only after the
+ * translate operation is finished, but normally moving nodes around doesn't cause updates. */
+ ntreeUpdateTree(&bmain, snode.edittree);
+ snode_notify(*C, snode);
+ snode_dag_update(*C, snode);
+
+ /* Start translation operator with the new node. */
+ wmOperatorType *ot = WM_operatortype_find("TRANSFORM_OT_translate", true);
+ BLI_assert(ot);
+ PointerRNA ptr;
+ WM_operator_properties_create_ptr(&ptr, ot);
+ RNA_boolean_set(&ptr, "view2d_edge_pan", true);
+ WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr);
+ WM_operator_properties_free(&ptr);
+}
+
+static void link_drag_search_free_fn(void *arg)
+{
+ LinkDragSearchStorage *storage = static_cast<LinkDragSearchStorage *>(arg);
+ delete storage;
+}
+
+static uiBlock *create_search_popup_block(bContext *C, ARegion *region, void *arg_op)
+{
+ LinkDragSearchStorage &storage = *(LinkDragSearchStorage *)arg_op;
+
+ bNodeTree *node_tree = CTX_wm_space_node(C)->nodetree;
+ gather_socket_link_operations(*node_tree, storage.from_socket, storage.search_link_ops);
+
+ uiBlock *block = UI_block_begin(C, region, "_popup", UI_EMBOSS);
+ UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_SEARCH_MENU);
+ UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP);
+
+ uiBut *but = uiDefSearchBut(block,
+ storage.search,
+ 0,
+ ICON_VIEWZOOM,
+ sizeof(storage.search),
+ storage.in_out() == SOCK_OUT ? 10 : 10 - UI_searchbox_size_x(),
+ 10,
+ UI_searchbox_size_x(),
+ UI_UNIT_Y,
+ 0,
+ 0,
+ "");
+ UI_but_func_search_set_sep_string(but, UI_MENU_ARROW_SEP);
+ UI_but_func_search_set(but,
+ nullptr,
+ link_drag_search_update_fn,
+ &storage,
+ false,
+ link_drag_search_free_fn,
+ link_drag_search_exec_fn,
+ nullptr);
+ UI_but_flag_enable(but, UI_BUT_ACTIVATE_ON_INIT);
+
+ /* Fake button to hold space for the search items. */
+ uiDefBut(block,
+ UI_BTYPE_LABEL,
+ 0,
+ "",
+ storage.in_out() == SOCK_OUT ? 10 : 10 - UI_searchbox_size_x(),
+ 10 - UI_searchbox_size_y(),
+ UI_searchbox_size_x(),
+ UI_searchbox_size_y(),
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ nullptr);
+
+ const int offset[2] = {0, -UI_UNIT_Y};
+ UI_block_bounds_set_popup(block, 0.3f * U.widget_unit, offset);
+ return block;
+}
+
+void invoke_node_link_drag_add_menu(bContext &C,
+ bNode &node,
+ bNodeSocket &socket,
+ const float2 &cursor)
+{
+ LinkDragSearchStorage *storage = new LinkDragSearchStorage{node, socket, cursor};
+ /* Use the "_ex" variant with `can_refresh` false to avoid a double free when closing Blender. */
+ UI_popup_block_invoke_ex(&C, create_search_popup_block, storage, nullptr, false);
+}
+
+} // namespace blender::ed::space_node \ No newline at end of file
diff --git a/source/blender/editors/space_node/node_add.cc b/source/blender/editors/space_node/node_add.cc
index 2e3579caaa1..c6a5e8e68c0 100644
--- a/source/blender/editors/space_node/node_add.cc
+++ b/source/blender/editors/space_node/node_add.cc
@@ -28,7 +28,6 @@
#include "DNA_texture_types.h"
#include "BLI_listbase.h"
-#include "BLI_math.h"
#include "BLT_translation.h"
@@ -62,24 +61,19 @@
/** \name Utilities
* \{ */
-/**
- * XXX Does some additional initialization on top of #nodeAddNode
- * Can be used with both custom and static nodes,
- * if `idname == nullptr` the static int type will be used instead.
- */
-bNode *node_add_node(const bContext *C, const char *idname, int type, float locx, float locy)
+bNode *node_add_node(const bContext &C, const char *idname, int type, float locx, float locy)
{
- SpaceNode *snode = CTX_wm_space_node(C);
- Main *bmain = CTX_data_main(C);
+ SpaceNode &snode = *CTX_wm_space_node(&C);
+ Main &bmain = *CTX_data_main(&C);
bNode *node = nullptr;
node_deselect_all(snode);
if (idname) {
- node = nodeAddNode(C, snode->edittree, idname);
+ node = nodeAddNode(&C, snode.edittree, idname);
}
else {
- node = nodeAddStaticNode(C, snode->edittree, type);
+ node = nodeAddStaticNode(&C, snode.edittree, type);
}
BLI_assert(node && node->typeinfo);
@@ -89,13 +83,13 @@ bNode *node_add_node(const bContext *C, const char *idname, int type, float locx
nodeSetSelected(node, true);
- ntreeUpdateTree(bmain, snode->edittree);
- ED_node_set_active(bmain, snode, snode->edittree, node, nullptr);
+ ntreeUpdateTree(&bmain, snode.edittree);
+ ED_node_set_active(&bmain, &snode, snode.edittree, node, nullptr);
snode_update(snode, node);
- if (snode->nodetree->type == NTREE_TEXTURE) {
- ntreeTexCheckCyclics(snode->edittree);
+ if (snode.nodetree->type == NTREE_TEXTURE) {
+ ntreeTexCheckCyclics(snode.edittree);
}
return node;
@@ -107,7 +101,7 @@ bNode *node_add_node(const bContext *C, const char *idname, int type, float locx
/** \name Add Reroute Operator
* \{ */
-static bool add_reroute_intersect_check(bNodeLink *link,
+static bool add_reroute_intersect_check(const bNodeLink &link,
float mcoords[][2],
int tot,
float result[2])
@@ -224,9 +218,9 @@ static bNodeSocketLink *add_reroute_do_socket_section(bContext *C,
static int add_reroute_exec(bContext *C, wmOperator *op)
{
- SpaceNode *snode = CTX_wm_space_node(C);
- ARegion *region = CTX_wm_region(C);
- bNodeTree *ntree = snode->edittree;
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ ARegion &region = *CTX_wm_region(C);
+ bNodeTree &ntree = *snode.edittree;
float mcoords[256][2];
int i = 0;
@@ -236,7 +230,7 @@ static int add_reroute_exec(bContext *C, wmOperator *op)
RNA_float_get_array(&itemptr, "loc", loc);
UI_view2d_region_to_view(
- &region->v2d, (short)loc[0], (short)loc[1], &mcoords[i][0], &mcoords[i][1]);
+ &region.v2d, (short)loc[0], (short)loc[1], &mcoords[i][0], &mcoords[i][1]);
i++;
if (i >= 256) {
break;
@@ -246,7 +240,6 @@ static int add_reroute_exec(bContext *C, wmOperator *op)
if (i > 1) {
ListBase output_links, input_links;
- bNodeLink *link;
bNodeSocketLink *socklink;
float insert_point[2];
@@ -259,11 +252,11 @@ static int add_reroute_exec(bContext *C, wmOperator *op)
BLI_listbase_clear(&output_links);
BLI_listbase_clear(&input_links);
- for (link = (bNodeLink *)ntree->links.first; link; link = link->next) {
- if (node_link_is_hidden_or_dimmed(&region->v2d, link)) {
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
+ if (node_link_is_hidden_or_dimmed(region.v2d, *link)) {
continue;
}
- if (add_reroute_intersect_check(link, mcoords, i, insert_point)) {
+ if (add_reroute_intersect_check(*link, mcoords, i, insert_point)) {
add_reroute_insert_socket_link(&output_links, link->fromsock, link, insert_point);
add_reroute_insert_socket_link(&input_links, link->tosock, link, insert_point);
@@ -288,9 +281,9 @@ static int add_reroute_exec(bContext *C, wmOperator *op)
BLI_freelistN(&input_links);
/* always last */
- ntreeUpdateTree(CTX_data_main(C), ntree);
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ ntreeUpdateTree(CTX_data_main(C), &ntree);
+ snode_notify(*C, snode);
+ snode_dag_update(*C, snode);
return OPERATOR_FINISHED;
}
@@ -377,7 +370,7 @@ static int node_add_group_exec(bContext *C, wmOperator *op)
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
- bNode *group_node = node_add_node(C,
+ bNode *group_node = node_add_node(*C,
node_group_idname(C),
(node_group->type == NTREE_CUSTOM) ? NODE_CUSTOM_GROUP :
NODE_GROUP,
@@ -395,8 +388,8 @@ static int node_add_group_exec(bContext *C, wmOperator *op)
ntreeUpdateTree(bmain, node_group);
ntreeUpdateTree(bmain, ntree);
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ snode_notify(*C, *snode);
+ snode_dag_update(*C, *snode);
return OPERATOR_FINISHED;
}
@@ -469,7 +462,7 @@ static int node_add_object_exec(bContext *C, wmOperator *op)
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
bNode *object_node = node_add_node(
- C, nullptr, GEO_NODE_OBJECT_INFO, snode->runtime->cursor[0], snode->runtime->cursor[1]);
+ *C, nullptr, GEO_NODE_OBJECT_INFO, snode->runtime->cursor[0], snode->runtime->cursor[1]);
if (!object_node) {
BKE_report(op->reports, RPT_WARNING, "Could not add node object");
return OPERATOR_CANCELLED;
@@ -488,8 +481,8 @@ static int node_add_object_exec(bContext *C, wmOperator *op)
nodeSetActive(ntree, object_node);
ntreeUpdateTree(bmain, ntree);
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ snode_notify(*C, *snode);
+ snode_dag_update(*C, *snode);
ED_node_tag_update_nodetree(bmain, ntree, object_node);
DEG_relations_tag_update(bmain);
@@ -580,7 +573,7 @@ static int node_add_texture_exec(bContext *C, wmOperator *op)
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
- bNode *texture_node = node_add_node(C,
+ bNode *texture_node = node_add_node(*C,
nullptr,
GEO_NODE_LEGACY_ATTRIBUTE_SAMPLE_TEXTURE,
snode->runtime->cursor[0],
@@ -596,8 +589,8 @@ static int node_add_texture_exec(bContext *C, wmOperator *op)
nodeSetActive(ntree, texture_node);
ntreeUpdateTree(bmain, ntree);
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ snode_notify(*C, *snode);
+ snode_dag_update(*C, *snode);
DEG_relations_tag_update(bmain);
ED_node_tag_update_nodetree(bmain, ntree, texture_node);
@@ -680,8 +673,8 @@ static Collection *node_add_collection_get_and_poll_collection_node_tree(Main *b
static int node_add_collection_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
- SpaceNode *snode = CTX_wm_space_node(C);
- bNodeTree *ntree = snode->edittree;
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ bNodeTree *ntree = snode.edittree;
Collection *collection;
if (!(collection = node_add_collection_get_and_poll_collection_node_tree(bmain, op))) {
@@ -691,7 +684,7 @@ static int node_add_collection_exec(bContext *C, wmOperator *op)
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
bNode *collection_node = node_add_node(
- C, nullptr, GEO_NODE_COLLECTION_INFO, snode->runtime->cursor[0], snode->runtime->cursor[1]);
+ *C, nullptr, GEO_NODE_COLLECTION_INFO, snode.runtime->cursor[0], snode.runtime->cursor[1]);
if (!collection_node) {
BKE_report(op->reports, RPT_WARNING, "Could not add node collection");
return OPERATOR_CANCELLED;
@@ -710,8 +703,8 @@ static int node_add_collection_exec(bContext *C, wmOperator *op)
nodeSetActive(ntree, collection_node);
ntreeUpdateTree(bmain, ntree);
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ snode_notify(*C, snode);
+ snode_dag_update(*C, snode);
DEG_relations_tag_update(bmain);
ED_node_tag_update_nodetree(bmain, ntree, collection_node);
@@ -788,7 +781,7 @@ static bool node_add_file_poll(bContext *C)
static int node_add_file_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
- SpaceNode *snode = CTX_wm_space_node(C);
+ SpaceNode &snode = *CTX_wm_space_node(C);
bNode *node;
Image *ima;
int type = 0;
@@ -798,7 +791,7 @@ static int node_add_file_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- switch (snode->nodetree->type) {
+ switch (snode.nodetree->type) {
case NTREE_SHADER:
type = SH_NODE_TEX_IMAGE;
break;
@@ -817,7 +810,7 @@ static int node_add_file_exec(bContext *C, wmOperator *op)
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
- node = node_add_node(C, nullptr, type, snode->runtime->cursor[0], snode->runtime->cursor[1]);
+ node = node_add_node(*C, nullptr, type, snode.runtime->cursor[0], snode.runtime->cursor[1]);
if (!node) {
BKE_report(op->reports, RPT_WARNING, "Could not add an image node");
@@ -841,8 +834,8 @@ static int node_add_file_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
}
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ snode_notify(*C, snode);
+ snode_dag_update(*C, snode);
DEG_relations_tag_update(bmain);
return OPERATOR_FINISHED;
@@ -923,7 +916,7 @@ static bool node_add_mask_poll(bContext *C)
static int node_add_mask_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
- SpaceNode *snode = CTX_wm_space_node(C);
+ SpaceNode &snode = *CTX_wm_space_node(C);
bNode *node;
ID *mask = node_add_mask_get_and_poll_mask(bmain, op);
@@ -934,7 +927,7 @@ static int node_add_mask_exec(bContext *C, wmOperator *op)
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
node = node_add_node(
- C, nullptr, CMP_NODE_MASK, snode->runtime->cursor[0], snode->runtime->cursor[1]);
+ *C, nullptr, CMP_NODE_MASK, snode.runtime->cursor[0], snode.runtime->cursor[1]);
if (!node) {
BKE_report(op->reports, RPT_WARNING, "Could not add a mask node");
@@ -944,8 +937,8 @@ static int node_add_mask_exec(bContext *C, wmOperator *op)
node->id = mask;
id_us_plus(mask);
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ snode_notify(*C, snode);
+ snode_dag_update(*C, snode);
DEG_relations_tag_update(bmain);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc
index bf3a9ba0c52..d68f16f6197 100644
--- a/source/blender/editors/space_node/node_draw.cc
+++ b/source/blender/editors/space_node/node_draw.cc
@@ -22,21 +22,22 @@
* \brief higher level node drawing for the node editor.
*/
+#include <iomanip>
+
#include "MEM_guardedalloc.h"
#include "DNA_light_types.h"
#include "DNA_linestyle_types.h"
#include "DNA_material_types.h"
-#include "DNA_modifier_types.h"
#include "DNA_node_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
+#include "DNA_text_types.h"
#include "DNA_texture_types.h"
#include "DNA_world_types.h"
-#include "BLI_blenlib.h"
+#include "BLI_array.hh"
#include "BLI_map.hh"
-#include "BLI_math.h"
#include "BLI_set.hh"
#include "BLI_span.hh"
#include "BLI_string_ref.hh"
@@ -87,10 +88,8 @@
#include "node_intern.hh" /* own include */
-#ifdef WITH_COMPOSITOR
-# include "COM_compositor.h"
-#endif
-
+using blender::Array;
+using blender::float2;
using blender::Map;
using blender::Set;
using blender::Span;
@@ -109,7 +108,7 @@ extern void ui_draw_dropshadow(
const rctf *rct, float radius, float aspect, float alpha, int select);
}
-float ED_node_grid_size(void)
+float ED_node_grid_size()
{
return U.widget_unit;
}
@@ -118,7 +117,7 @@ void ED_node_tree_update(const bContext *C)
{
SpaceNode *snode = CTX_wm_space_node(C);
if (snode) {
- snode_set_context(C);
+ snode_set_context(*C);
id_us_ensure_real(&snode->nodetree->id);
}
@@ -185,7 +184,7 @@ void ED_node_tag_update_nodetree(Main *bmain, bNodeTree *ntree, bNode *node)
bool do_tag_update = true;
if (node != nullptr) {
- if (!node_connected_to_output(bmain, ntree, node)) {
+ if (!node_connected_to_output(*bmain, *ntree, *node)) {
do_tag_update = false;
}
}
@@ -262,10 +261,6 @@ static bool compare_nodes(const bNode *a, const bNode *b)
return false;
}
-/**
- * Sort nodes by selection: unselected nodes first, then selected,
- * then the active node at the very end. Relative order is kept intact.
- */
void ED_node_sort(bNodeTree *ntree)
{
/* Merge sort is the algorithm of choice here. */
@@ -321,67 +316,68 @@ void ED_node_sort(bNodeTree *ntree)
}
}
-static void node_uiblocks_init(const bContext *C, bNodeTree *ntree)
+static Array<uiBlock *> node_uiblocks_init(const bContext &C, Span<bNode *> nodes)
{
+ Array<uiBlock *> blocks(nodes.size());
/* Add node uiBlocks in drawing order - prevents events going to overlapping nodes. */
-
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- /* ui block */
- char uiblockstr[32];
- BLI_snprintf(uiblockstr, sizeof(uiblockstr), "node buttons %p", (void *)node);
- node->block = UI_block_begin(C, CTX_wm_region(C), uiblockstr, UI_EMBOSS);
-
+ for (const int i : nodes.index_range()) {
+ const std::string block_name = "node_" + std::string(nodes[i]->name);
+ blocks[i] = UI_block_begin(&C, CTX_wm_region(&C), block_name.c_str(), UI_EMBOSS);
/* this cancels events for background nodes */
- UI_block_flag_enable(node->block, UI_BLOCK_CLIP_EVENTS);
+ UI_block_flag_enable(blocks[i], UI_BLOCK_CLIP_EVENTS);
}
+
+ return blocks;
}
-void node_to_view(const bNode *node, float x, float y, float *rx, float *ry)
+float2 node_to_view(const bNode &node, const float2 &co)
{
- nodeToView(node, x, y, rx, ry);
- *rx *= UI_DPI_FAC;
- *ry *= UI_DPI_FAC;
+ float2 result;
+ nodeToView(&node, co.x, co.y, &result.x, &result.y);
+ return result * UI_DPI_FAC;
}
-void node_to_updated_rect(const bNode *node, rctf *r_rect)
+void node_to_updated_rect(const bNode &node, rctf &r_rect)
{
- node_to_view(node, node->offsetx, node->offsety, &r_rect->xmin, &r_rect->ymax);
- node_to_view(node,
- node->offsetx + node->width,
- node->offsety - node->height,
- &r_rect->xmax,
- &r_rect->ymin);
+ const float2 xmin_ymax = node_to_view(node, {node.offsetx, node.offsety});
+ r_rect.xmin = xmin_ymax.x;
+ r_rect.ymax = xmin_ymax.y;
+ const float2 xmax_ymin = node_to_view(node,
+ {node.offsetx + node.width, node.offsety - node.height});
+ r_rect.xmax = xmax_ymin.x;
+ r_rect.ymin = xmax_ymin.y;
}
-void node_from_view(const bNode *node, float x, float y, float *rx, float *ry)
+float2 node_from_view(const bNode &node, const float2 &co)
{
- x /= UI_DPI_FAC;
- y /= UI_DPI_FAC;
- nodeFromView(node, x, y, rx, ry);
+ const float x = co.x / UI_DPI_FAC;
+ const float y = co.y / UI_DPI_FAC;
+ float2 result;
+ nodeFromView(&node, x, y, &result.x, &result.y);
+ return result;
}
/**
* Based on settings and sockets in node, set drawing rect info.
*/
-static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node)
+static void node_update_basis(const bContext &C, bNodeTree &ntree, bNode &node, uiBlock &block)
{
PointerRNA nodeptr;
- RNA_pointer_create(&ntree->id, &RNA_Node, node, &nodeptr);
+ RNA_pointer_create(&ntree.id, &RNA_Node, &node, &nodeptr);
/* Get "global" coordinates. */
- float locx, locy;
- node_to_view(node, 0.0f, 0.0f, &locx, &locy);
+ float2 loc = node_to_view(node, float2(0));
/* Round the node origin because text contents are always pixel-aligned. */
- locx = round(locx);
- locy = round(locy);
+ loc.x = round(loc.x);
+ loc.y = round(loc.y);
- int dy = locy;
+ int dy = loc.y;
/* Header. */
dy -= NODE_DY;
- /* Little bit of space in top. */
- if (node->outputs.first) {
+ /* Add a little bit of padding above the top socket. */
+ if (node.outputs.first || node.inputs.first) {
dy -= NODE_DYS / 2;
}
@@ -389,25 +385,25 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node)
bool add_output_space = false;
int buty;
- LISTBASE_FOREACH (bNodeSocket *, nsock, &node->outputs) {
+ LISTBASE_FOREACH (bNodeSocket *, nsock, &node.outputs) {
if (nodeSocketIsHidden(nsock)) {
continue;
}
PointerRNA sockptr;
- RNA_pointer_create(&ntree->id, &RNA_NodeSocket, nsock, &sockptr);
+ RNA_pointer_create(&ntree.id, &RNA_NodeSocket, nsock, &sockptr);
- uiLayout *layout = UI_block_layout(node->block,
+ uiLayout *layout = UI_block_layout(&block,
UI_LAYOUT_VERTICAL,
UI_LAYOUT_PANEL,
- locx + NODE_DYS,
+ loc.x + NODE_DYS,
dy,
NODE_WIDTH(node) - NODE_DY,
NODE_DY,
0,
UI_style_get_dpi());
- if (node->flag & NODE_MUTED) {
+ if (node.flag & NODE_MUTED) {
uiLayoutSetActive(layout, false);
}
@@ -419,16 +415,16 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node)
uiLayout *row = uiLayoutRow(layout, true);
uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_RIGHT);
const char *socket_label = nodeSocketLabel(nsock);
- nsock->typeinfo->draw((bContext *)C, row, &sockptr, &nodeptr, IFACE_(socket_label));
+ nsock->typeinfo->draw((bContext *)&C, row, &sockptr, &nodeptr, IFACE_(socket_label));
- UI_block_align_end(node->block);
- UI_block_layout_resolve(node->block, nullptr, &buty);
+ UI_block_align_end(&block);
+ UI_block_layout_resolve(&block, nullptr, &buty);
/* Ensure minimum socket height in case layout is empty. */
buty = min_ii(buty, dy - NODE_DY);
/* Round the socket location to stop it from jiggling. */
- nsock->locx = round(locx + NODE_WIDTH(node));
+ nsock->locx = round(loc.x + NODE_WIDTH(node));
nsock->locy = round(0.5f * (dy + buty));
dy = buty;
@@ -443,86 +439,80 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node)
dy -= NODE_DY / 4;
}
- node->prvr.xmin = locx + NODE_DYS;
- node->prvr.xmax = locx + NODE_WIDTH(node) - NODE_DYS;
+ node.prvr.xmin = loc.x + NODE_DYS;
+ node.prvr.xmax = loc.x + NODE_WIDTH(node) - NODE_DYS;
/* preview rect? */
- if (node->flag & NODE_PREVIEW) {
+ if (node.flag & NODE_PREVIEW) {
float aspect = 1.0f;
- if (node->preview_xsize && node->preview_ysize) {
- aspect = (float)node->preview_ysize / (float)node->preview_xsize;
+ if (node.preview_xsize && node.preview_ysize) {
+ aspect = (float)node.preview_ysize / (float)node.preview_xsize;
}
dy -= NODE_DYS / 2;
- node->prvr.ymax = dy;
+ node.prvr.ymax = dy;
if (aspect <= 1.0f) {
- node->prvr.ymin = dy - aspect * (NODE_WIDTH(node) - NODE_DY);
+ node.prvr.ymin = dy - aspect * (NODE_WIDTH(node) - NODE_DY);
}
else {
/* Width correction of image. XXX huh? (ton) */
float dx = (NODE_WIDTH(node) - NODE_DYS) - (NODE_WIDTH(node) - NODE_DYS) / aspect;
- node->prvr.ymin = dy - (NODE_WIDTH(node) - NODE_DY);
+ node.prvr.ymin = dy - (NODE_WIDTH(node) - NODE_DY);
- node->prvr.xmin += 0.5f * dx;
- node->prvr.xmax -= 0.5f * dx;
+ node.prvr.xmin += 0.5f * dx;
+ node.prvr.xmax -= 0.5f * dx;
}
- dy = node->prvr.ymin - NODE_DYS / 2;
+ dy = node.prvr.ymin - NODE_DYS / 2;
/* Make sure that maximums are bigger or equal to minimums. */
- if (node->prvr.xmax < node->prvr.xmin) {
- SWAP(float, node->prvr.xmax, node->prvr.xmin);
+ if (node.prvr.xmax < node.prvr.xmin) {
+ SWAP(float, node.prvr.xmax, node.prvr.xmin);
}
- if (node->prvr.ymax < node->prvr.ymin) {
- SWAP(float, node->prvr.ymax, node->prvr.ymin);
+ if (node.prvr.ymax < node.prvr.ymin) {
+ SWAP(float, node.prvr.ymax, node.prvr.ymin);
}
}
/* Buttons rect? */
- if (node->typeinfo->draw_buttons && (node->flag & NODE_OPTIONS)) {
+ if (node.typeinfo->draw_buttons && (node.flag & NODE_OPTIONS)) {
dy -= NODE_DYS / 2;
- /* Set this for `uifunc()` that don't use layout engine yet. */
- node->butr.xmin = 0;
- node->butr.xmax = NODE_WIDTH(node) - 2 * NODE_DYS;
- node->butr.ymin = 0;
- node->butr.ymax = 0;
-
- uiLayout *layout = UI_block_layout(node->block,
+ uiLayout *layout = UI_block_layout(&block,
UI_LAYOUT_VERTICAL,
UI_LAYOUT_PANEL,
- locx + NODE_DYS,
+ loc.x + NODE_DYS,
dy,
- node->butr.xmax,
+ NODE_WIDTH(node) - NODE_DY,
0,
0,
UI_style_get_dpi());
- if (node->flag & NODE_MUTED) {
+ if (node.flag & NODE_MUTED) {
uiLayoutSetActive(layout, false);
}
uiLayoutSetContextPointer(layout, "node", &nodeptr);
- node->typeinfo->draw_buttons(layout, (bContext *)C, &nodeptr);
+ node.typeinfo->draw_buttons(layout, (bContext *)&C, &nodeptr);
- UI_block_align_end(node->block);
- UI_block_layout_resolve(node->block, nullptr, &buty);
+ UI_block_align_end(&block);
+ UI_block_layout_resolve(&block, nullptr, &buty);
dy = buty - NODE_DYS / 2;
}
/* Input sockets. */
- LISTBASE_FOREACH (bNodeSocket *, nsock, &node->inputs) {
+ LISTBASE_FOREACH (bNodeSocket *, nsock, &node.inputs) {
if (nodeSocketIsHidden(nsock)) {
continue;
}
PointerRNA sockptr;
- RNA_pointer_create(&ntree->id, &RNA_NodeSocket, nsock, &sockptr);
+ RNA_pointer_create(&ntree.id, &RNA_NodeSocket, nsock, &sockptr);
/* Add the half the height of a multi-input socket to cursor Y
* to account for the increased height of the taller sockets. */
@@ -534,17 +524,17 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node)
}
dy -= multi_input_socket_offset * 0.5f;
- uiLayout *layout = UI_block_layout(node->block,
+ uiLayout *layout = UI_block_layout(&block,
UI_LAYOUT_VERTICAL,
UI_LAYOUT_PANEL,
- locx + NODE_DYS,
+ loc.x + NODE_DYS,
dy,
NODE_WIDTH(node) - NODE_DY,
NODE_DY,
0,
UI_style_get_dpi());
- if (node->flag & NODE_MUTED) {
+ if (node.flag & NODE_MUTED) {
uiLayoutSetActive(layout, false);
}
@@ -555,15 +545,15 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node)
uiLayout *row = uiLayoutRow(layout, true);
const char *socket_label = nodeSocketLabel(nsock);
- nsock->typeinfo->draw((bContext *)C, row, &sockptr, &nodeptr, IFACE_(socket_label));
+ nsock->typeinfo->draw((bContext *)&C, row, &sockptr, &nodeptr, IFACE_(socket_label));
- UI_block_align_end(node->block);
- UI_block_layout_resolve(node->block, nullptr, &buty);
+ UI_block_align_end(&block);
+ UI_block_layout_resolve(&block, nullptr, &buty);
/* Ensure minimum socket height in case layout is empty. */
buty = min_ii(buty, dy - NODE_DY);
- nsock->locx = locx;
+ nsock->locx = loc.x;
/* Round the socket vertical position to stop it from jiggling. */
nsock->locy = round(0.5f * (dy + buty));
@@ -574,45 +564,44 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node)
}
/* Little bit of space in end. */
- if (node->inputs.first || (node->flag & (NODE_OPTIONS | NODE_PREVIEW)) == 0) {
+ if (node.inputs.first || (node.flag & (NODE_OPTIONS | NODE_PREVIEW)) == 0) {
dy -= NODE_DYS / 2;
}
- node->totr.xmin = locx;
- node->totr.xmax = locx + NODE_WIDTH(node);
- node->totr.ymax = locy;
- node->totr.ymin = min_ff(dy, locy - 2 * NODE_DY);
+ node.totr.xmin = loc.x;
+ node.totr.xmax = loc.x + NODE_WIDTH(node);
+ node.totr.ymax = loc.y;
+ node.totr.ymin = min_ff(dy, loc.y - 2 * NODE_DY);
/* Set the block bounds to clip mouse events from underlying nodes.
* Add a margin for sockets on each side. */
- UI_block_bounds_set_explicit(node->block,
- node->totr.xmin - NODE_SOCKSIZE,
- node->totr.ymin,
- node->totr.xmax + NODE_SOCKSIZE,
- node->totr.ymax);
+ UI_block_bounds_set_explicit(&block,
+ node.totr.xmin - NODE_SOCKSIZE,
+ node.totr.ymin,
+ node.totr.xmax + NODE_SOCKSIZE,
+ node.totr.ymax);
}
/**
* Based on settings in node, sets drawing rect info.
*/
-static void node_update_hidden(bNode *node)
+static void node_update_hidden(bNode &node, uiBlock &block)
{
int totin = 0, totout = 0;
- /* Get "global" coords. */
- float locx, locy;
- node_to_view(node, 0.0f, 0.0f, &locx, &locy);
+ /* Get "global" coordinates. */
+ float2 loc = node_to_view(node, float2(0));
/* Round the node origin because text contents are always pixel-aligned. */
- locx = round(locx);
- locy = round(locy);
+ loc.x = round(loc.x);
+ loc.y = round(loc.y);
/* Calculate minimal radius. */
- LISTBASE_FOREACH (bNodeSocket *, nsock, &node->inputs) {
+ LISTBASE_FOREACH (bNodeSocket *, nsock, &node.inputs) {
if (!nodeSocketIsHidden(nsock)) {
totin++;
}
}
- LISTBASE_FOREACH (bNodeSocket *, nsock, &node->outputs) {
+ LISTBASE_FOREACH (bNodeSocket *, nsock, &node.outputs) {
if (!nodeSocketIsHidden(nsock)) {
totout++;
}
@@ -624,20 +613,20 @@ static void node_update_hidden(bNode *node)
hiddenrad += 5.0f * (float)(tot - 4);
}
- node->totr.xmin = locx;
- node->totr.xmax = locx + max_ff(NODE_WIDTH(node), 2 * hiddenrad);
- node->totr.ymax = locy + (hiddenrad - 0.5f * NODE_DY);
- node->totr.ymin = node->totr.ymax - 2 * hiddenrad;
+ node.totr.xmin = loc.x;
+ node.totr.xmax = loc.x + max_ff(NODE_WIDTH(node), 2 * hiddenrad);
+ node.totr.ymax = loc.y + (hiddenrad - 0.5f * NODE_DY);
+ node.totr.ymin = node.totr.ymax - 2 * hiddenrad;
/* Output sockets. */
float rad = (float)M_PI / (1.0f + (float)totout);
float drad = rad;
- LISTBASE_FOREACH (bNodeSocket *, nsock, &node->outputs) {
+ LISTBASE_FOREACH (bNodeSocket *, nsock, &node.outputs) {
if (!nodeSocketIsHidden(nsock)) {
/* Round the socket location to stop it from jiggling. */
- nsock->locx = round(node->totr.xmax - hiddenrad + sinf(rad) * hiddenrad);
- nsock->locy = round(node->totr.ymin + hiddenrad + cosf(rad) * hiddenrad);
+ nsock->locx = round(node.totr.xmax - hiddenrad + sinf(rad) * hiddenrad);
+ nsock->locy = round(node.totr.ymin + hiddenrad + cosf(rad) * hiddenrad);
rad += drad;
}
}
@@ -645,51 +634,31 @@ static void node_update_hidden(bNode *node)
/* Input sockets. */
rad = drad = -(float)M_PI / (1.0f + (float)totin);
- LISTBASE_FOREACH (bNodeSocket *, nsock, &node->inputs) {
+ LISTBASE_FOREACH (bNodeSocket *, nsock, &node.inputs) {
if (!nodeSocketIsHidden(nsock)) {
/* Round the socket location to stop it from jiggling. */
- nsock->locx = round(node->totr.xmin + hiddenrad + sinf(rad) * hiddenrad);
- nsock->locy = round(node->totr.ymin + hiddenrad + cosf(rad) * hiddenrad);
+ nsock->locx = round(node.totr.xmin + hiddenrad + sinf(rad) * hiddenrad);
+ nsock->locy = round(node.totr.ymin + hiddenrad + cosf(rad) * hiddenrad);
rad += drad;
}
}
/* Set the block bounds to clip mouse events from underlying nodes.
* Add a margin for sockets on each side. */
- UI_block_bounds_set_explicit(node->block,
- node->totr.xmin - NODE_SOCKSIZE,
- node->totr.ymin,
- node->totr.xmax + NODE_SOCKSIZE,
- node->totr.ymax);
+ UI_block_bounds_set_explicit(&block,
+ node.totr.xmin - NODE_SOCKSIZE,
+ node.totr.ymin,
+ node.totr.xmax + NODE_SOCKSIZE,
+ node.totr.ymax);
}
-void node_update_default(const bContext *C, bNodeTree *ntree, bNode *node)
+static int node_get_colorid(const bNode &node)
{
- if (node->flag & NODE_HIDDEN) {
- node_update_hidden(node);
- }
- else {
- node_update_basis(C, ntree, node);
- }
-}
-
-int node_select_area_default(bNode *node, int x, int y)
-{
- return BLI_rctf_isect_pt(&node->totr, x, y);
-}
-
-int node_tweak_area_default(bNode *node, int x, int y)
-{
- return BLI_rctf_isect_pt(&node->totr, x, y);
-}
-
-int node_get_colorid(bNode *node)
-{
- switch (node->typeinfo->nclass) {
+ switch (node.typeinfo->nclass) {
case NODE_CLASS_INPUT:
return TH_NODE_INPUT;
case NODE_CLASS_OUTPUT:
- return (node->flag & NODE_DO_OUTPUT) ? TH_NODE_OUTPUT : TH_NODE;
+ return (node.flag & NODE_DO_OUTPUT) ? TH_NODE_OUTPUT : TH_NODE;
case NODE_CLASS_CONVERTER:
return TH_NODE_CONVERTER;
case NODE_CLASS_OP_COLOR:
@@ -725,21 +694,21 @@ int node_get_colorid(bNode *node)
}
}
-static void node_draw_mute_line(const bContext *C,
- const View2D *v2d,
- const SpaceNode *snode,
- const bNode *node)
+static void node_draw_mute_line(const bContext &C,
+ const View2D &v2d,
+ const SpaceNode &snode,
+ const bNode &node)
{
GPU_blend(GPU_BLEND_ALPHA);
- LISTBASE_FOREACH (const bNodeLink *, link, &node->internal_links) {
- node_draw_link_bezier(C, v2d, snode, link, TH_WIRE_INNER, TH_WIRE_INNER, TH_WIRE);
+ LISTBASE_FOREACH (const bNodeLink *, link, &node.internal_links) {
+ node_draw_link_bezier(C, v2d, snode, *link, TH_WIRE_INNER, TH_WIRE_INNER, TH_WIRE);
}
GPU_blend(GPU_BLEND_NONE);
}
-static void node_socket_draw(const bNodeSocket *sock,
+static void node_socket_draw(const bNodeSocket &sock,
const float color[4],
const float color_outline[4],
float size,
@@ -754,7 +723,7 @@ static void node_socket_draw(const bNodeSocket *sock,
int flags;
/* Set shape flags. */
- switch (sock->display_shape) {
+ switch (sock.display_shape) {
case SOCK_DISPLAY_SHAPE_DIAMOND:
case SOCK_DISPLAY_SHAPE_DIAMOND_DOT:
flags = GPU_KEYFRAME_SHAPE_DIAMOND;
@@ -770,7 +739,7 @@ static void node_socket_draw(const bNodeSocket *sock,
break;
}
- if (ELEM(sock->display_shape,
+ if (ELEM(sock.display_shape,
SOCK_DISPLAY_SHAPE_DIAMOND_DOT,
SOCK_DISPLAY_SHAPE_SQUARE_DOT,
SOCK_DISPLAY_SHAPE_CIRCLE_DOT)) {
@@ -825,16 +794,17 @@ static void node_socket_outline_color_get(const bool selected,
}
}
-/* Usual convention here would be node_socket_get_color(), but that's already used (for setting a
- * color property socket). */
-void node_socket_color_get(
- const bContext *C, bNodeTree *ntree, PointerRNA *node_ptr, bNodeSocket *sock, float r_color[4])
+void node_socket_color_get(const bContext &C,
+ const bNodeTree &ntree,
+ PointerRNA &node_ptr,
+ const bNodeSocket &sock,
+ float r_color[4])
{
PointerRNA ptr;
- BLI_assert(RNA_struct_is_a(node_ptr->type, &RNA_Node));
- RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr);
+ BLI_assert(RNA_struct_is_a(node_ptr.type, &RNA_Node));
+ RNA_pointer_create((ID *)&ntree, &RNA_NodeSocket, &const_cast<bNodeSocket &>(sock), &ptr);
- sock->typeinfo->draw_color((bContext *)C, &ptr, node_ptr, r_color);
+ sock.typeinfo->draw_color((bContext *)&C, &ptr, &node_ptr, r_color);
}
struct SocketTooltipData {
@@ -843,29 +813,43 @@ struct SocketTooltipData {
bNodeSocket *socket;
};
-static void create_inspection_string_for_generic_value(const geo_log::GenericValueLog &value_log,
- std::stringstream &ss)
+static void create_inspection_string_for_generic_value(const GPointer value, std::stringstream &ss)
{
auto id_to_inspection_string = [&](ID *id, short idcode) {
ss << (id ? id->name + 2 : TIP_("None")) << " (" << BKE_idtype_idcode_to_name(idcode) << ")";
};
- const GPointer value = value_log.value();
const CPPType &type = *value.type();
+ const void *buffer = value.get();
if (type.is<Object *>()) {
- id_to_inspection_string((ID *)*value.get<Object *>(), ID_OB);
+ id_to_inspection_string((ID *)buffer, ID_OB);
}
else if (type.is<Material *>()) {
- id_to_inspection_string((ID *)*value.get<Material *>(), ID_MA);
+ id_to_inspection_string((ID *)buffer, ID_MA);
}
else if (type.is<Tex *>()) {
- id_to_inspection_string((ID *)*value.get<Tex *>(), ID_TE);
+ id_to_inspection_string((ID *)buffer, ID_TE);
}
else if (type.is<Image *>()) {
- id_to_inspection_string((ID *)*value.get<Image *>(), ID_IM);
+ id_to_inspection_string((ID *)buffer, ID_IM);
}
else if (type.is<Collection *>()) {
- id_to_inspection_string((ID *)*value.get<Collection *>(), ID_GR);
+ id_to_inspection_string((ID *)buffer, ID_GR);
+ }
+ else if (type.is<int>()) {
+ ss << *(int *)buffer << TIP_(" (Integer)");
+ }
+ else if (type.is<float>()) {
+ ss << *(float *)buffer << TIP_(" (Float)");
+ }
+ else if (type.is<blender::float3>()) {
+ ss << *(blender::float3 *)buffer << TIP_(" (Vector)");
+ }
+ else if (type.is<bool>()) {
+ ss << ((*(bool *)buffer) ? TIP_("True") : TIP_("False")) << TIP_(" (Boolean)");
+ }
+ else if (type.is<std::string>()) {
+ ss << *(std::string *)buffer << TIP_(" (String)");
}
}
@@ -880,21 +864,7 @@ static void create_inspection_string_for_gfield(const geo_log::GFieldValueLog &v
if (field) {
BUFFER_FOR_CPP_TYPE_VALUE(type, buffer);
blender::fn::evaluate_constant_field(field, buffer);
- if (type.is<int>()) {
- ss << *(int *)buffer << TIP_(" (Integer)");
- }
- else if (type.is<float>()) {
- ss << *(float *)buffer << TIP_(" (Float)");
- }
- else if (type.is<blender::float3>()) {
- ss << *(blender::float3 *)buffer << TIP_(" (Vector)");
- }
- else if (type.is<bool>()) {
- ss << ((*(bool *)buffer) ? TIP_("True") : TIP_("False")) << TIP_(" (Boolean)");
- }
- else if (type.is<std::string>()) {
- ss << *(std::string *)buffer << TIP_(" (String)");
- }
+ create_inspection_string_for_generic_value({type, buffer}, ss);
type.destruct(buffer);
}
else {
@@ -1005,7 +975,6 @@ static void create_inspection_string_for_geometry(const geo_log::GeometryValueLo
}
static std::optional<std::string> create_socket_inspection_string(bContext *C,
- bNodeTree &UNUSED(ntree),
bNode &node,
bNodeSocket &socket)
{
@@ -1023,7 +992,7 @@ static std::optional<std::string> create_socket_inspection_string(bContext *C,
std::stringstream ss;
if (const geo_log::GenericValueLog *generic_value_log =
dynamic_cast<const geo_log::GenericValueLog *>(value_log)) {
- create_inspection_string_for_generic_value(*generic_value_log, ss);
+ create_inspection_string_for_generic_value(generic_value_log->value(), ss);
}
if (const geo_log::GFieldValueLog *gfield_value_log =
dynamic_cast<const geo_log::GFieldValueLog *>(value_log)) {
@@ -1037,54 +1006,52 @@ static std::optional<std::string> create_socket_inspection_string(bContext *C,
return ss.str();
}
-static void node_socket_draw_nested(const bContext *C,
- bNodeTree *ntree,
- PointerRNA *node_ptr,
- bNodeSocket *sock,
- uint pos_id,
- uint col_id,
- uint shape_id,
- uint size_id,
- uint outline_col_id,
- float size,
- bool selected)
+static void node_socket_draw_nested(const bContext &C,
+ bNodeTree &ntree,
+ PointerRNA &node_ptr,
+ uiBlock &block,
+ bNodeSocket &sock,
+ const uint pos_id,
+ const uint col_id,
+ const uint shape_id,
+ const uint size_id,
+ const uint outline_col_id,
+ const float size,
+ const bool selected)
{
float color[4];
float outline_color[4];
node_socket_color_get(C, ntree, node_ptr, sock, color);
- node_socket_outline_color_get(selected, sock->type, outline_color);
+ node_socket_outline_color_get(selected, sock.type, outline_color);
node_socket_draw(sock,
color,
outline_color,
size,
- sock->locx,
- sock->locy,
+ sock.locx,
+ sock.locy,
pos_id,
col_id,
shape_id,
size_id,
outline_col_id);
- if (ntree->type != NTREE_GEOMETRY) {
+ if (ntree.type != NTREE_GEOMETRY) {
/* Only geometry nodes has socket value tooltips currently. */
return;
}
- bNode *node = (bNode *)node_ptr->data;
- uiBlock *block = node->block;
-
/* Ideally sockets themselves should be buttons, but they aren't currently. So add an invisible
* button on top of them for the tooltip. */
- const eUIEmbossType old_emboss = UI_block_emboss_get(block);
- UI_block_emboss_set(block, UI_EMBOSS_NONE);
- uiBut *but = uiDefIconBut(block,
+ const eUIEmbossType old_emboss = UI_block_emboss_get(&block);
+ UI_block_emboss_set(&block, UI_EMBOSS_NONE);
+ uiBut *but = uiDefIconBut(&block,
UI_BTYPE_BUT,
0,
ICON_NONE,
- sock->locx - size / 2,
- sock->locy - size / 2,
+ sock.locx - size / 2,
+ sock.locy - size / 2,
size,
size,
nullptr,
@@ -1095,16 +1062,16 @@ static void node_socket_draw_nested(const bContext *C,
nullptr);
SocketTooltipData *data = (SocketTooltipData *)MEM_mallocN(sizeof(SocketTooltipData), __func__);
- data->ntree = ntree;
- data->node = (bNode *)node_ptr->data;
- data->socket = sock;
+ data->ntree = &ntree;
+ data->node = (bNode *)node_ptr.data;
+ data->socket = &sock;
UI_but_func_tooltip_set(
but,
[](bContext *C, void *argN, const char *UNUSED(tip)) {
SocketTooltipData *data = (SocketTooltipData *)argN;
std::optional<std::string> socket_inspection_str = create_socket_inspection_string(
- C, *data->ntree, *data->node, *data->socket);
+ C, *data->node, *data->socket);
std::stringstream output;
if (data->socket->declaration != nullptr) {
@@ -1126,14 +1093,9 @@ static void node_socket_draw_nested(const bContext *C,
MEM_freeN);
/* Disable the button so that clicks on it are ignored the the link operator still works. */
UI_but_flag_enable(but, UI_BUT_DISABLED);
- UI_block_emboss_set(block, old_emboss);
+ UI_block_emboss_set(&block, old_emboss);
}
-/**
- * Draw a single node socket at default size.
- * \note this is only called from external code, internally #node_socket_draw_nested() is used for
- * optimized drawing of multiple/all sockets of a node.
- */
void ED_node_socket_draw(bNodeSocket *sock, const rcti *rect, const float color[4], float scale)
{
const float size = 2.25f * NODE_SOCKSIZE * scale;
@@ -1162,7 +1124,7 @@ void ED_node_socket_draw(bNodeSocket *sock, const rcti *rect, const float color[
/* Single point. */
immBegin(GPU_PRIM_POINTS, 1);
- node_socket_draw(sock,
+ node_socket_draw(*sock,
color,
outline_color,
BLI_rcti_size_y(&draw_rect),
@@ -1260,34 +1222,38 @@ static void node_toggle_button_cb(struct bContext *C, void *node_argv, void *op_
const char *opname = (const char *)op_argv;
/* Select & activate only the button's node. */
- node_select_single(C, node);
+ node_select_single(*C, *node);
WM_operator_name_call(C, opname, WM_OP_INVOKE_DEFAULT, nullptr);
}
-void node_draw_shadow(const SpaceNode *snode, const bNode *node, float radius, float alpha)
+static void node_draw_shadow(const SpaceNode &snode,
+ const bNode &node,
+ const float radius,
+ const float alpha)
{
- const rctf *rct = &node->totr;
+ const rctf &rct = node.totr;
UI_draw_roundbox_corner_set(UI_CNR_ALL);
- ui_draw_dropshadow(rct, radius, snode->runtime->aspect, alpha, node->flag & SELECT);
+ ui_draw_dropshadow(&rct, radius, snode.runtime->aspect, alpha, node.flag & SELECT);
}
-void node_draw_sockets(const View2D *v2d,
- const bContext *C,
- bNodeTree *ntree,
- bNode *node,
- bool draw_outputs,
- bool select_all)
+static void node_draw_sockets(const View2D &v2d,
+ const bContext &C,
+ bNodeTree &ntree,
+ bNode &node,
+ uiBlock &block,
+ const bool draw_outputs,
+ const bool select_all)
{
- const uint total_input_len = BLI_listbase_count(&node->inputs);
- const uint total_output_len = BLI_listbase_count(&node->outputs);
+ const uint total_input_len = BLI_listbase_count(&node.inputs);
+ const uint total_output_len = BLI_listbase_count(&node.outputs);
if (total_input_len + total_output_len == 0) {
return;
}
PointerRNA node_ptr;
- RNA_pointer_create((ID *)ntree, &RNA_Node, node, &node_ptr);
+ RNA_pointer_create((ID *)&ntree, &RNA_Node, &node, &node_ptr);
bool selected = false;
@@ -1307,7 +1273,7 @@ void node_draw_sockets(const View2D *v2d,
/* Set handle size. */
float scale;
- UI_view2d_scale_get(v2d, &scale, nullptr);
+ UI_view2d_scale_get(&v2d, &scale, nullptr);
scale *= 2.25f * NODE_SOCKSIZE;
if (!select_all) {
@@ -1316,7 +1282,7 @@ void node_draw_sockets(const View2D *v2d,
/* Socket inputs. */
short selected_input_len = 0;
- LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node.inputs) {
if (nodeSocketIsHidden(sock)) {
continue;
}
@@ -1331,8 +1297,9 @@ void node_draw_sockets(const View2D *v2d,
node_socket_draw_nested(C,
ntree,
- &node_ptr,
- sock,
+ node_ptr,
+ block,
+ *sock,
pos_id,
col_id,
shape_id,
@@ -1345,7 +1312,7 @@ void node_draw_sockets(const View2D *v2d,
/* Socket outputs. */
short selected_output_len = 0;
if (draw_outputs) {
- LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node.outputs) {
if (nodeSocketIsHidden(sock)) {
continue;
}
@@ -1356,8 +1323,9 @@ void node_draw_sockets(const View2D *v2d,
node_socket_draw_nested(C,
ntree,
- &node_ptr,
- sock,
+ node_ptr,
+ block,
+ *sock,
pos_id,
col_id,
shape_id,
@@ -1382,15 +1350,16 @@ void node_draw_sockets(const View2D *v2d,
if (selected_input_len) {
/* Socket inputs. */
- LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node.inputs) {
if (nodeSocketIsHidden(sock)) {
continue;
}
if (select_all || (sock->flag & SELECT)) {
node_socket_draw_nested(C,
ntree,
- &node_ptr,
- sock,
+ node_ptr,
+ block,
+ *sock,
pos_id,
col_id,
shape_id,
@@ -1407,15 +1376,16 @@ void node_draw_sockets(const View2D *v2d,
if (selected_output_len) {
/* Socket outputs. */
- LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node.outputs) {
if (nodeSocketIsHidden(sock)) {
continue;
}
if (select_all || (sock->flag & SELECT)) {
node_socket_draw_nested(C,
ntree,
- &node_ptr,
- sock,
+ node_ptr,
+ block,
+ *sock,
pos_id,
col_id,
shape_id,
@@ -1440,7 +1410,7 @@ void node_draw_sockets(const View2D *v2d,
/* Draw multi-input sockets after the others because they are drawn with `UI_draw_roundbox`
* rather than with `GL_POINT`. */
- LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node.inputs) {
if (nodeSocketIsHidden(socket)) {
continue;
}
@@ -1448,13 +1418,13 @@ void node_draw_sockets(const View2D *v2d,
continue;
}
- const bool is_node_hidden = (node->flag & NODE_HIDDEN);
+ const bool is_node_hidden = (node.flag & NODE_HIDDEN);
const float width = NODE_SOCKSIZE;
- float height = is_node_hidden ? width : node_socket_calculate_height(socket) - width;
+ float height = is_node_hidden ? width : node_socket_calculate_height(*socket) - width;
float color[4];
float outline_color[4];
- node_socket_color_get(C, ntree, &node_ptr, socket, color);
+ node_socket_color_get(C, ntree, node_ptr, *socket, color);
node_socket_outline_color_get(selected, socket->type, outline_color);
node_socket_draw_multi_input(color, outline_color, width, height, socket->locx, socket->locy);
@@ -1536,9 +1506,9 @@ static char *node_errors_tooltip_fn(bContext *UNUSED(C), void *argN, const char
#define NODE_HEADER_ICON_SIZE (0.8f * U.widget_unit)
static void node_add_error_message_button(
- const bContext *C, bNodeTree &UNUSED(ntree), bNode &node, const rctf &rect, float &icon_offset)
+ const bContext &C, bNode &node, uiBlock &block, const rctf &rect, float &icon_offset)
{
- SpaceNode *snode = CTX_wm_space_node(C);
+ SpaceNode *snode = CTX_wm_space_node(&C);
const geo_log::NodeLog *node_log = geo_log::ModifierLog::find_node_by_node_editor_context(*snode,
node);
if (node_log == nullptr) {
@@ -1558,8 +1528,8 @@ static void node_add_error_message_button(
const geo_log::NodeWarningType display_type = node_error_highest_priority(warnings);
icon_offset -= NODE_HEADER_ICON_SIZE;
- UI_block_emboss_set(node.block, UI_EMBOSS_NONE);
- uiBut *but = uiDefIconBut(node.block,
+ UI_block_emboss_set(&block, UI_EMBOSS_NONE);
+ uiBut *but = uiDefIconBut(&block,
UI_BTYPE_BUT,
0,
node_error_type_to_icon(display_type),
@@ -1574,47 +1544,288 @@ static void node_add_error_message_button(
0,
nullptr);
UI_but_func_tooltip_set(but, node_errors_tooltip_fn, tooltip_data, MEM_freeN);
- UI_block_emboss_set(node.block, UI_EMBOSS);
+ UI_block_emboss_set(&block, UI_EMBOSS);
+}
+
+static void get_exec_time_other_nodes(const bNode &node,
+ const SpaceNode &snode,
+ std::chrono::microseconds &exec_time,
+ int &node_count)
+{
+ if (node.type == NODE_GROUP) {
+ const geo_log::TreeLog *root_tree_log = geo_log::ModifierLog::find_tree_by_node_editor_context(
+ snode);
+ if (root_tree_log == nullptr) {
+ return;
+ }
+ const geo_log::TreeLog *tree_log = root_tree_log->lookup_child_log(node.name);
+ if (tree_log == nullptr) {
+ return;
+ }
+ tree_log->foreach_node_log([&](const geo_log::NodeLog &node_log) {
+ exec_time += node_log.execution_time();
+ node_count++;
+ });
+ }
+ else {
+ const geo_log::NodeLog *node_log = geo_log::ModifierLog::find_node_by_node_editor_context(
+ snode, node);
+ if (node_log) {
+ exec_time += node_log->execution_time();
+ node_count++;
+ }
+ }
+}
+
+static std::chrono::microseconds node_get_execution_time(const bNodeTree &ntree,
+ const bNode &node,
+ const SpaceNode &snode,
+ int &node_count)
+{
+ std::chrono::microseconds exec_time = std::chrono::microseconds::zero();
+ if (node.type == NODE_GROUP_OUTPUT) {
+ const geo_log::TreeLog *tree_log = geo_log::ModifierLog::find_tree_by_node_editor_context(
+ snode);
+
+ if (tree_log == nullptr) {
+ return exec_time;
+ }
+ tree_log->foreach_node_log([&](const geo_log::NodeLog &node_log) {
+ exec_time += node_log.execution_time();
+ node_count++;
+ });
+ }
+ else if (node.type == NODE_FRAME) {
+ /* Could be cached in the future if this recursive code turns out to be slow. */
+ LISTBASE_FOREACH (bNode *, tnode, &ntree.nodes) {
+ if (tnode->parent != &node) {
+ continue;
+ }
+
+ if (tnode->type == NODE_FRAME) {
+ exec_time += node_get_execution_time(ntree, *tnode, snode, node_count);
+ }
+ else {
+ get_exec_time_other_nodes(*tnode, snode, exec_time, node_count);
+ }
+ }
+ }
+ else {
+ get_exec_time_other_nodes(node, snode, exec_time, node_count);
+ }
+ return exec_time;
+}
+
+static std::string node_get_execution_time_label(const SpaceNode &snode, const bNode &node)
+{
+ int node_count = 0;
+ std::chrono::microseconds exec_time = node_get_execution_time(
+ *snode.nodetree, node, snode, node_count);
+
+ if (node_count == 0) {
+ return std::string("");
+ }
+
+ uint64_t exec_time_us = exec_time.count();
+
+ /* Don't show time if execution time is 0 microseconds. */
+ if (exec_time_us == 0) {
+ return std::string("-");
+ }
+ if (exec_time_us < 100) {
+ return std::string("< 0.1 ms");
+ }
+
+ int precision = 0;
+ /* Show decimal if value is below 1ms */
+ if (exec_time_us < 1000) {
+ precision = 2;
+ }
+ else if (exec_time_us < 10000) {
+ precision = 1;
+ }
+
+ std::stringstream stream;
+ stream << std::fixed << std::setprecision(precision) << (exec_time_us / 1000.0f);
+ return stream.str() + " ms";
+}
+
+struct NodeExtraInfoRow {
+ std::string text;
+ const char *tooltip;
+ int icon;
+};
+
+static Vector<NodeExtraInfoRow> node_get_extra_info(const SpaceNode &snode, const bNode &node)
+{
+ Vector<NodeExtraInfoRow> rows;
+ if (!(snode.overlay.flag & SN_OVERLAY_SHOW_OVERLAYS)) {
+ return rows;
+ }
+
+ if (snode.overlay.flag & SN_OVERLAY_SHOW_TIMINGS && snode.edittree->type == NTREE_GEOMETRY &&
+ (ELEM(node.typeinfo->nclass, NODE_CLASS_GEOMETRY, NODE_CLASS_GROUP, NODE_CLASS_ATTRIBUTE) ||
+ ELEM(node.type, NODE_FRAME, NODE_GROUP_OUTPUT))) {
+ NodeExtraInfoRow row;
+ row.text = node_get_execution_time_label(snode, node);
+ if (!row.text.empty()) {
+ row.tooltip = TIP_(
+ "The execution time from the node tree's latest evaluation. For frame and group nodes, "
+ "the time for all sub-nodes");
+ row.icon = ICON_PREVIEW_RANGE;
+ rows.append(std::move(row));
+ }
+ }
+ const geo_log::NodeLog *node_log = geo_log::ModifierLog::find_node_by_node_editor_context(snode,
+ node);
+ if (node_log != nullptr) {
+ for (const std::string &message : node_log->debug_messages()) {
+ NodeExtraInfoRow row;
+ row.text = message;
+ row.icon = ICON_INFO;
+ rows.append(std::move(row));
+ }
+ }
+ return rows;
+}
+
+static void node_draw_extra_info_row(const bNode &node,
+ uiBlock &block,
+ const rctf &rect,
+ const int row,
+ const NodeExtraInfoRow &extra_info_row)
+{
+ uiBut *but_timing = uiDefBut(&block,
+ UI_BTYPE_LABEL,
+ 0,
+ extra_info_row.text.c_str(),
+ (int)(rect.xmin + 4.0f * U.dpi_fac + NODE_MARGIN_X + 0.4f),
+ (int)(rect.ymin + row * (20.0f * U.dpi_fac)),
+ (short)(rect.xmax - rect.xmin),
+ (short)NODE_DY,
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ "");
+ UI_block_emboss_set(&block, UI_EMBOSS_NONE);
+ uiBut *but_icon = uiDefIconBut(&block,
+ UI_BTYPE_BUT,
+ 0,
+ extra_info_row.icon,
+ (int)(rect.xmin + 6.0f * U.dpi_fac),
+ (int)(rect.ymin + row * (20.0f * U.dpi_fac)),
+ NODE_HEADER_ICON_SIZE * 0.8f,
+ UI_UNIT_Y,
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ extra_info_row.tooltip);
+ UI_block_emboss_set(&block, UI_EMBOSS);
+ if (node.flag & NODE_MUTED) {
+ UI_but_flag_enable(but_timing, UI_BUT_INACTIVE);
+ UI_but_flag_enable(but_icon, UI_BUT_INACTIVE);
+ }
+}
+
+static void node_draw_extra_info_panel(const SpaceNode &snode, const bNode &node, uiBlock &block)
+{
+ Vector<NodeExtraInfoRow> extra_info_rows = node_get_extra_info(snode, node);
+
+ if (extra_info_rows.size() == 0) {
+ return;
+ }
+
+ const rctf &rct = node.totr;
+ float color[4];
+ rctf extra_info_rect;
+
+ if (node.type == NODE_FRAME) {
+ extra_info_rect.xmin = rct.xmin;
+ extra_info_rect.xmax = rct.xmin + 95.0f * U.dpi_fac;
+ extra_info_rect.ymin = rct.ymin + 2.0f * U.dpi_fac;
+ extra_info_rect.ymax = rct.ymin + 2.0f * U.dpi_fac;
+ }
+ else {
+ extra_info_rect.xmin = rct.xmin + 3.0f * U.dpi_fac;
+ extra_info_rect.xmax = rct.xmin + 95.0f * U.dpi_fac;
+ extra_info_rect.ymin = rct.ymax;
+ extra_info_rect.ymax = rct.ymax + extra_info_rows.size() * (20.0f * U.dpi_fac);
+
+ if (node.flag & NODE_MUTED) {
+ UI_GetThemeColorBlend4f(TH_BACK, TH_NODE, 0.2f, color);
+ }
+ else {
+ UI_GetThemeColorBlend4f(TH_BACK, TH_NODE, 0.75f, color);
+ }
+ color[3] -= 0.35f;
+ UI_draw_roundbox_corner_set(
+ UI_CNR_ALL & ~UI_CNR_BOTTOM_LEFT &
+ ((rct.xmax) > extra_info_rect.xmax ? ~UI_CNR_BOTTOM_RIGHT : UI_CNR_ALL));
+ UI_draw_roundbox_4fv(&extra_info_rect, true, BASIS_RAD, color);
+
+ /* Draw outline. */
+ const float outline_width = 1.0f;
+ extra_info_rect.xmin = rct.xmin + 3.0f * U.dpi_fac - outline_width;
+ extra_info_rect.xmax = rct.xmin + 95.0f * U.dpi_fac + outline_width;
+ extra_info_rect.ymin = rct.ymax - outline_width;
+ extra_info_rect.ymax = rct.ymax + outline_width + extra_info_rows.size() * (20.0f * U.dpi_fac);
+
+ UI_GetThemeColorBlendShade4fv(TH_BACK, TH_NODE, 0.4f, -20, color);
+ UI_draw_roundbox_corner_set(
+ UI_CNR_ALL & ~UI_CNR_BOTTOM_LEFT &
+ ((rct.xmax) > extra_info_rect.xmax ? ~UI_CNR_BOTTOM_RIGHT : UI_CNR_ALL));
+ UI_draw_roundbox_4fv(&extra_info_rect, false, BASIS_RAD, color);
+ }
+
+ for (int row : extra_info_rows.index_range()) {
+ node_draw_extra_info_row(node, block, extra_info_rect, row, extra_info_rows[row]);
+ }
}
-static void node_draw_basis(const bContext *C,
- const View2D *v2d,
- const SpaceNode *snode,
- bNodeTree *ntree,
- bNode *node,
+static void node_draw_basis(const bContext &C,
+ const View2D &v2d,
+ const SpaceNode &snode,
+ bNodeTree &ntree,
+ bNode &node,
+ uiBlock &block,
bNodeInstanceKey key)
{
const float iconbutw = NODE_HEADER_ICON_SIZE;
/* Skip if out of view. */
- if (BLI_rctf_isect(&node->totr, &v2d->cur, nullptr) == false) {
- UI_block_end(C, node->block);
- node->block = nullptr;
+ if (BLI_rctf_isect(&node.totr, &v2d.cur, nullptr) == false) {
+ UI_block_end(&C, &block);
return;
}
/* Shadow. */
node_draw_shadow(snode, node, BASIS_RAD, 1.0f);
- rctf *rct = &node->totr;
+ const rctf &rct = node.totr;
float color[4];
int color_id = node_get_colorid(node);
GPU_line_width(1.0f);
+ node_draw_extra_info_panel(snode, node, block);
+
/* Header. */
{
const rctf rect = {
- rct->xmin,
- rct->xmax,
- rct->ymax - NODE_DY,
- rct->ymax,
+ rct.xmin,
+ rct.xmax,
+ rct.ymax - NODE_DY,
+ rct.ymax,
};
float color_header[4];
/* Muted nodes get a mix of the background with the node color. */
- if (node->flag & NODE_MUTED) {
+ if (node.flag & NODE_MUTED) {
UI_GetThemeColorBlend4f(TH_BACK, color_id, 0.1f, color_header);
}
else {
@@ -1626,18 +1837,18 @@ static void node_draw_basis(const bContext *C,
}
/* Show/hide icons. */
- float iconofs = rct->xmax - 0.35f * U.widget_unit;
+ float iconofs = rct.xmax - 0.35f * U.widget_unit;
/* Preview. */
- if (node->typeinfo->flag & NODE_PREVIEW) {
+ if (node.typeinfo->flag & NODE_PREVIEW) {
iconofs -= iconbutw;
- UI_block_emboss_set(node->block, UI_EMBOSS_NONE);
- uiBut *but = uiDefIconBut(node->block,
+ UI_block_emboss_set(&block, UI_EMBOSS_NONE);
+ uiBut *but = uiDefIconBut(&block,
UI_BTYPE_BUT_TOGGLE,
0,
ICON_MATERIAL,
iconofs,
- rct->ymax - NODE_DY,
+ rct.ymax - NODE_DY,
iconbutw,
UI_UNIT_Y,
nullptr,
@@ -1646,24 +1857,24 @@ static void node_draw_basis(const bContext *C,
0,
0,
"");
- UI_but_func_set(but, node_toggle_button_cb, node, (void *)"NODE_OT_preview_toggle");
+ UI_but_func_set(but, node_toggle_button_cb, &node, (void *)"NODE_OT_preview_toggle");
/* XXX this does not work when node is activated and the operator called right afterwards,
* since active ID is not updated yet (needs to process the notifier).
* This can only work as visual indicator! */
- // if (!(node->flag & (NODE_ACTIVE_ID|NODE_DO_OUTPUT)))
+ // if (!(node.flag & (NODE_ACTIVE_ID|NODE_DO_OUTPUT)))
// UI_but_flag_enable(but, UI_BUT_DISABLED);
- UI_block_emboss_set(node->block, UI_EMBOSS);
+ UI_block_emboss_set(&block, UI_EMBOSS);
}
/* Group edit. */
- if (node->type == NODE_GROUP) {
+ if (node.type == NODE_GROUP) {
iconofs -= iconbutw;
- UI_block_emboss_set(node->block, UI_EMBOSS_NONE);
- uiBut *but = uiDefIconBut(node->block,
+ UI_block_emboss_set(&block, UI_EMBOSS_NONE);
+ uiBut *but = uiDefIconBut(&block,
UI_BTYPE_BUT_TOGGLE,
0,
ICON_NODETREE,
iconofs,
- rct->ymax - NODE_DY,
+ rct.ymax - NODE_DY,
iconbutw,
UI_UNIT_Y,
nullptr,
@@ -1672,18 +1883,18 @@ static void node_draw_basis(const bContext *C,
0,
0,
"");
- UI_but_func_set(but, node_toggle_button_cb, node, (void *)"NODE_OT_group_edit");
- UI_block_emboss_set(node->block, UI_EMBOSS);
+ UI_but_func_set(but, node_toggle_button_cb, &node, (void *)"NODE_OT_group_edit");
+ UI_block_emboss_set(&block, UI_EMBOSS);
}
- if (node->type == NODE_CUSTOM && node->typeinfo->ui_icon != ICON_NONE) {
+ if (node.type == NODE_CUSTOM && node.typeinfo->ui_icon != ICON_NONE) {
iconofs -= iconbutw;
- UI_block_emboss_set(node->block, UI_EMBOSS_NONE);
- uiDefIconBut(node->block,
+ UI_block_emboss_set(&block, UI_EMBOSS_NONE);
+ uiDefIconBut(&block,
UI_BTYPE_BUT,
0,
- node->typeinfo->ui_icon,
+ node.typeinfo->ui_icon,
iconofs,
- rct->ymax - NODE_DY,
+ rct.ymax - NODE_DY,
iconbutw,
UI_UNIT_Y,
nullptr,
@@ -1692,13 +1903,13 @@ static void node_draw_basis(const bContext *C,
0,
0,
"");
- UI_block_emboss_set(node->block, UI_EMBOSS);
+ UI_block_emboss_set(&block, UI_EMBOSS);
}
- node_add_error_message_button(C, *ntree, *node, *rct, iconofs);
+ node_add_error_message_button(C, node, block, rct, iconofs);
/* Title. */
- if (node->flag & SELECT) {
+ if (node.flag & SELECT) {
UI_GetThemeColor4fv(TH_SELECT, color);
}
else {
@@ -1708,14 +1919,14 @@ static void node_draw_basis(const bContext *C,
/* Collapse/expand icon. */
{
const int but_size = U.widget_unit * 0.8f;
- UI_block_emboss_set(node->block, UI_EMBOSS_NONE);
+ UI_block_emboss_set(&block, UI_EMBOSS_NONE);
- uiBut *but = uiDefIconBut(node->block,
+ uiBut *but = uiDefIconBut(&block,
UI_BTYPE_BUT_TOGGLE,
0,
ICON_DOWNARROW_HLT,
- rct->xmin + (NODE_MARGIN_X / 3),
- rct->ymax - NODE_DY / 2.2f - but_size / 2,
+ rct.xmin + (NODE_MARGIN_X / 3),
+ rct.ymax - NODE_DY / 2.2f - but_size / 2,
but_size,
but_size,
nullptr,
@@ -1725,20 +1936,20 @@ static void node_draw_basis(const bContext *C,
0.0f,
"");
- UI_but_func_set(but, node_toggle_button_cb, node, (void *)"NODE_OT_hide_toggle");
- UI_block_emboss_set(node->block, UI_EMBOSS);
+ UI_but_func_set(but, node_toggle_button_cb, &node, (void *)"NODE_OT_hide_toggle");
+ UI_block_emboss_set(&block, UI_EMBOSS);
}
char showname[128];
- nodeLabel(ntree, node, showname, sizeof(showname));
+ nodeLabel(&ntree, &node, showname, sizeof(showname));
- uiBut *but = uiDefBut(node->block,
+ uiBut *but = uiDefBut(&block,
UI_BTYPE_LABEL,
0,
showname,
- (int)(rct->xmin + NODE_MARGIN_X + 0.4f),
- (int)(rct->ymax - NODE_DY),
- (short)(iconofs - rct->xmin - (18.0f * U.dpi_fac)),
+ (int)(rct.xmin + NODE_MARGIN_X + 0.4f),
+ (int)(rct.ymax - NODE_DY),
+ (short)(iconofs - rct.xmin - (18.0f * U.dpi_fac)),
(short)NODE_DY,
nullptr,
0,
@@ -1746,12 +1957,12 @@ static void node_draw_basis(const bContext *C,
0,
0,
"");
- if (node->flag & NODE_MUTED) {
+ if (node.flag & NODE_MUTED) {
UI_but_flag_enable(but, UI_BUT_INACTIVE);
}
/* Wire across the node when muted/disabled. */
- if (node->flag & NODE_MUTED) {
+ if (node.flag & NODE_MUTED) {
node_draw_mute_line(C, v2d, snode, node);
}
@@ -1759,35 +1970,35 @@ static void node_draw_basis(const bContext *C,
const float outline_width = 1.0f;
{
/* Use warning color to indicate undefined types. */
- if (nodeTypeUndefined(node)) {
+ if (nodeTypeUndefined(&node)) {
UI_GetThemeColorBlend4f(TH_REDALERT, TH_NODE, 0.4f, color);
}
/* Muted nodes get a mix of the background with the node color. */
- else if (node->flag & NODE_MUTED) {
+ else if (node.flag & NODE_MUTED) {
UI_GetThemeColorBlend4f(TH_BACK, TH_NODE, 0.2f, color);
}
- else if (node->flag & NODE_CUSTOM_COLOR) {
- rgba_float_args_set(color, node->color[0], node->color[1], node->color[2], 1.0f);
+ else if (node.flag & NODE_CUSTOM_COLOR) {
+ rgba_float_args_set(color, node.color[0], node.color[1], node.color[2], 1.0f);
}
else {
UI_GetThemeColor4fv(TH_NODE, color);
}
/* Draw selected nodes fully opaque. */
- if (node->flag & SELECT) {
+ if (node.flag & SELECT) {
color[3] = 1.0f;
}
/* Draw muted nodes slightly transparent so the wires inside are visible. */
- if (node->flag & NODE_MUTED) {
+ if (node.flag & NODE_MUTED) {
color[3] -= 0.2f;
}
const rctf rect = {
- rct->xmin,
- rct->xmax,
- rct->ymin,
- rct->ymax - (NODE_DY + outline_width),
+ rct.xmin,
+ rct.xmax,
+ rct.ymin,
+ rct.ymax - (NODE_DY + outline_width),
};
UI_draw_roundbox_corner_set(UI_CNR_BOTTOM_LEFT | UI_CNR_BOTTOM_RIGHT);
@@ -1798,7 +2009,7 @@ static void node_draw_basis(const bContext *C,
{
float color_underline[4];
- if (node->flag & NODE_MUTED) {
+ if (node.flag & NODE_MUTED) {
UI_GetThemeColor4fv(TH_WIRE, color_underline);
}
else {
@@ -1806,10 +2017,10 @@ static void node_draw_basis(const bContext *C,
}
const rctf rect = {
- rct->xmin,
- rct->xmax,
- rct->ymax - (NODE_DY + outline_width),
- rct->ymax - NODE_DY,
+ rct.xmin,
+ rct.xmax,
+ rct.ymax - (NODE_DY + outline_width),
+ rct.ymax - NODE_DY,
};
UI_draw_roundbox_corner_set(UI_CNR_NONE);
@@ -1819,19 +2030,19 @@ static void node_draw_basis(const bContext *C,
/* Outline. */
{
const rctf rect = {
- rct->xmin - outline_width,
- rct->xmax + outline_width,
- rct->ymin - outline_width,
- rct->ymax + outline_width,
+ rct.xmin - outline_width,
+ rct.xmax + outline_width,
+ rct.ymin - outline_width,
+ rct.ymax + outline_width,
};
/* Color the outline according to active, selected, or undefined status. */
float color_outline[4];
- if (node->flag & SELECT) {
- UI_GetThemeColor4fv((node->flag & NODE_ACTIVE) ? TH_ACTIVE : TH_SELECT, color_outline);
+ if (node.flag & SELECT) {
+ UI_GetThemeColor4fv((node.flag & NODE_ACTIVE) ? TH_ACTIVE : TH_SELECT, color_outline);
}
- else if (nodeTypeUndefined(node)) {
+ else if (nodeTypeUndefined(&node)) {
UI_GetThemeColor4fv(TH_REDALERT, color_outline);
}
else {
@@ -1843,42 +2054,42 @@ static void node_draw_basis(const bContext *C,
}
float scale;
- UI_view2d_scale_get(v2d, &scale, nullptr);
+ UI_view2d_scale_get(&v2d, &scale, nullptr);
/* Skip slow socket drawing if zoom is small. */
if (scale > 0.2f) {
- node_draw_sockets(v2d, C, ntree, node, true, false);
+ node_draw_sockets(v2d, C, ntree, node, block, true, false);
}
/* Preview. */
- bNodeInstanceHash *previews = (bNodeInstanceHash *)CTX_data_pointer_get(C, "node_previews").data;
- if (node->flag & NODE_PREVIEW && previews) {
+ bNodeInstanceHash *previews =
+ (bNodeInstanceHash *)CTX_data_pointer_get(&C, "node_previews").data;
+ if (node.flag & NODE_PREVIEW && previews) {
bNodePreview *preview = (bNodePreview *)BKE_node_instance_hash_lookup(previews, key);
if (preview && (preview->xsize && preview->ysize)) {
- if (preview->rect && !BLI_rctf_is_empty(&node->prvr)) {
- node_draw_preview(preview, &node->prvr);
+ if (preview->rect && !BLI_rctf_is_empty(&node.prvr)) {
+ node_draw_preview(preview, &node.prvr);
}
}
}
- UI_block_end(C, node->block);
- UI_block_draw(C, node->block);
- node->block = nullptr;
+ UI_block_end(&C, &block);
+ UI_block_draw(&C, &block);
}
-static void node_draw_hidden(const bContext *C,
- const View2D *v2d,
- const SpaceNode *snode,
- bNodeTree *ntree,
- bNode *node,
- bNodeInstanceKey UNUSED(key))
+static void node_draw_hidden(const bContext &C,
+ const View2D &v2d,
+ const SpaceNode &snode,
+ bNodeTree &ntree,
+ bNode &node,
+ uiBlock &block)
{
- rctf *rct = &node->totr;
- float centy = BLI_rctf_cent_y(rct);
- float hiddenrad = BLI_rctf_size_y(rct) / 2.0f;
+ const rctf &rct = node.totr;
+ float centy = BLI_rctf_cent_y(&rct);
+ float hiddenrad = BLI_rctf_size_y(&rct) / 2.0f;
float scale;
- UI_view2d_scale_get(v2d, &scale, nullptr);
+ UI_view2d_scale_get(&v2d, &scale, nullptr);
const int color_id = node_get_colorid(node);
@@ -1886,43 +2097,43 @@ static void node_draw_hidden(const bContext *C,
node_draw_shadow(snode, node, hiddenrad, 1.0f);
/* Wire across the node when muted/disabled. */
- if (node->flag & NODE_MUTED) {
+ if (node.flag & NODE_MUTED) {
node_draw_mute_line(C, v2d, snode, node);
}
/* Body. */
float color[4];
{
- if (nodeTypeUndefined(node)) {
+ if (nodeTypeUndefined(&node)) {
/* Use warning color to indicate undefined types. */
UI_GetThemeColorBlend4f(TH_REDALERT, TH_NODE, 0.4f, color);
}
- else if (node->flag & NODE_MUTED) {
+ else if (node.flag & NODE_MUTED) {
/* Muted nodes get a mix of the background with the node color. */
UI_GetThemeColorBlendShade4fv(TH_BACK, color_id, 0.1f, 0, color);
}
- else if (node->flag & NODE_CUSTOM_COLOR) {
- rgba_float_args_set(color, node->color[0], node->color[1], node->color[2], 1.0f);
+ else if (node.flag & NODE_CUSTOM_COLOR) {
+ rgba_float_args_set(color, node.color[0], node.color[1], node.color[2], 1.0f);
}
else {
UI_GetThemeColorBlend4f(TH_NODE, color_id, 0.4f, color);
}
/* Draw selected nodes fully opaque. */
- if (node->flag & SELECT) {
+ if (node.flag & SELECT) {
color[3] = 1.0f;
}
/* Draw muted nodes slightly transparent so the wires inside are visible. */
- if (node->flag & NODE_MUTED) {
+ if (node.flag & NODE_MUTED) {
color[3] -= 0.2f;
}
- UI_draw_roundbox_4fv(rct, true, hiddenrad, color);
+ UI_draw_roundbox_4fv(&rct, true, hiddenrad, color);
}
/* Title. */
- if (node->flag & SELECT) {
+ if (node.flag & SELECT) {
UI_GetThemeColor4fv(TH_SELECT, color);
}
else {
@@ -1932,13 +2143,13 @@ static void node_draw_hidden(const bContext *C,
/* Collapse/expand icon. */
{
const int but_size = U.widget_unit * 1.0f;
- UI_block_emboss_set(node->block, UI_EMBOSS_NONE);
+ UI_block_emboss_set(&block, UI_EMBOSS_NONE);
- uiBut *but = uiDefIconBut(node->block,
+ uiBut *but = uiDefIconBut(&block,
UI_BTYPE_BUT_TOGGLE,
0,
ICON_RIGHTARROW,
- rct->xmin + (NODE_MARGIN_X / 3),
+ rct.xmin + (NODE_MARGIN_X / 3),
centy - but_size / 2,
but_size,
but_size,
@@ -1949,20 +2160,20 @@ static void node_draw_hidden(const bContext *C,
0.0f,
"");
- UI_but_func_set(but, node_toggle_button_cb, node, (void *)"NODE_OT_hide_toggle");
- UI_block_emboss_set(node->block, UI_EMBOSS);
+ UI_but_func_set(but, node_toggle_button_cb, &node, (void *)"NODE_OT_hide_toggle");
+ UI_block_emboss_set(&block, UI_EMBOSS);
}
char showname[128];
- nodeLabel(ntree, node, showname, sizeof(showname));
+ nodeLabel(&ntree, &node, showname, sizeof(showname));
- uiBut *but = uiDefBut(node->block,
+ uiBut *but = uiDefBut(&block,
UI_BTYPE_LABEL,
0,
showname,
- round_fl_to_int(rct->xmin + NODE_MARGIN_X),
+ round_fl_to_int(rct.xmin + NODE_MARGIN_X),
round_fl_to_int(centy - NODE_DY * 0.5f),
- (short)(BLI_rctf_size_x(rct) - ((18.0f + 12.0f) * U.dpi_fac)),
+ (short)(BLI_rctf_size_x(&rct) - ((18.0f + 12.0f) * U.dpi_fac)),
(short)NODE_DY,
nullptr,
0,
@@ -1975,19 +2186,19 @@ static void node_draw_hidden(const bContext *C,
{
const float outline_width = 1.0f;
const rctf rect = {
- rct->xmin - outline_width,
- rct->xmax + outline_width,
- rct->ymin - outline_width,
- rct->ymax + outline_width,
+ rct.xmin - outline_width,
+ rct.xmax + outline_width,
+ rct.ymin - outline_width,
+ rct.ymax + outline_width,
};
/* Color the outline according to active, selected, or undefined status. */
float color_outline[4];
- if (node->flag & SELECT) {
- UI_GetThemeColor4fv((node->flag & NODE_ACTIVE) ? TH_ACTIVE : TH_SELECT, color_outline);
+ if (node.flag & SELECT) {
+ UI_GetThemeColor4fv((node.flag & NODE_ACTIVE) ? TH_ACTIVE : TH_SELECT, color_outline);
}
- else if (nodeTypeUndefined(node)) {
+ else if (nodeTypeUndefined(&node)) {
UI_GetThemeColor4fv(TH_REDALERT, color_outline);
}
else {
@@ -1998,7 +2209,7 @@ static void node_draw_hidden(const bContext *C,
UI_draw_roundbox_4fv(&rect, false, hiddenrad, color_outline);
}
- if (node->flag & NODE_MUTED) {
+ if (node.flag & NODE_MUTED) {
UI_but_flag_enable(but, UI_BUT_INACTIVE);
}
@@ -2009,39 +2220,38 @@ static void node_draw_hidden(const bContext *C,
immUniformThemeColorShadeAlpha(TH_TEXT, -40, -180);
float dx = 0.5f * U.widget_unit;
- const float dx2 = 0.15f * U.widget_unit * snode->runtime->aspect;
+ const float dx2 = 0.15f * U.widget_unit * snode.runtime->aspect;
const float dy = 0.2f * U.widget_unit;
immBegin(GPU_PRIM_LINES, 4);
- immVertex2f(pos, rct->xmax - dx, centy - dy);
- immVertex2f(pos, rct->xmax - dx, centy + dy);
+ immVertex2f(pos, rct.xmax - dx, centy - dy);
+ immVertex2f(pos, rct.xmax - dx, centy + dy);
- immVertex2f(pos, rct->xmax - dx - dx2, centy - dy);
- immVertex2f(pos, rct->xmax - dx - dx2, centy + dy);
+ immVertex2f(pos, rct.xmax - dx - dx2, centy - dy);
+ immVertex2f(pos, rct.xmax - dx - dx2, centy + dy);
immEnd();
immUniformThemeColorShadeAlpha(TH_TEXT, 0, -180);
- dx -= snode->runtime->aspect;
+ dx -= snode.runtime->aspect;
immBegin(GPU_PRIM_LINES, 4);
- immVertex2f(pos, rct->xmax - dx, centy - dy);
- immVertex2f(pos, rct->xmax - dx, centy + dy);
+ immVertex2f(pos, rct.xmax - dx, centy - dy);
+ immVertex2f(pos, rct.xmax - dx, centy + dy);
- immVertex2f(pos, rct->xmax - dx - dx2, centy - dy);
- immVertex2f(pos, rct->xmax - dx - dx2, centy + dy);
+ immVertex2f(pos, rct.xmax - dx - dx2, centy - dy);
+ immVertex2f(pos, rct.xmax - dx - dx2, centy + dy);
immEnd();
immUnbindProgram();
GPU_blend(GPU_BLEND_NONE);
- node_draw_sockets(v2d, C, ntree, node, true, false);
+ node_draw_sockets(v2d, C, ntree, node, block, true, false);
- UI_block_end(C, node->block);
- UI_block_draw(C, node->block);
- node->block = nullptr;
+ UI_block_end(&C, &block);
+ UI_block_draw(&C, &block);
}
-int node_get_resize_cursor(int directions)
+int node_get_resize_cursor(NodeResizeDirection directions)
{
if (directions == 0) {
return WM_CURSOR_DEFAULT;
@@ -2055,77 +2265,58 @@ int node_get_resize_cursor(int directions)
return WM_CURSOR_EDIT;
}
-void node_set_cursor(wmWindow *win, SpaceNode *snode, float cursor[2])
+void node_set_cursor(wmWindow &win, SpaceNode &snode, const float2 &cursor)
{
- bNodeTree *ntree = snode->edittree;
+ const bNodeTree *ntree = snode.edittree;
+ if (ntree == nullptr) {
+ WM_cursor_set(&win, WM_CURSOR_DEFAULT);
+ return;
+ }
+
bNode *node;
bNodeSocket *sock;
int wmcursor = WM_CURSOR_DEFAULT;
- if (ntree) {
- if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_IN | SOCK_OUT)) {
- /* Pass. */
- }
- else {
- /* Check nodes front to back. */
- for (node = (bNode *)ntree->nodes.last; node; node = node->prev) {
- if (BLI_rctf_isect_pt(&node->totr, cursor[0], cursor[1])) {
- break; /* First hit on node stops. */
- }
- }
- if (node) {
- int dir = node->typeinfo->resize_area_func(node, cursor[0], cursor[1]);
- wmcursor = node_get_resize_cursor(dir);
- }
- }
+ if (node_find_indicated_socket(
+ snode, &node, &sock, cursor, (eNodeSocketInOut)(SOCK_IN | SOCK_OUT))) {
+ WM_cursor_set(&win, WM_CURSOR_DEFAULT);
+ return;
}
- WM_cursor_set(win, wmcursor);
-}
-
-void node_draw_default(const bContext *C,
- ARegion *region,
- SpaceNode *snode,
- bNodeTree *ntree,
- bNode *node,
- bNodeInstanceKey key)
-{
- const View2D *v2d = &region->v2d;
- if (node->flag & NODE_HIDDEN) {
- node_draw_hidden(C, v2d, snode, ntree, node, key);
+ /* Check nodes front to back. */
+ for (node = (bNode *)ntree->nodes.last; node; node = node->prev) {
+ if (BLI_rctf_isect_pt(&node->totr, cursor[0], cursor[1])) {
+ break; /* First hit on node stops. */
+ }
}
- else {
- node_draw_basis(C, v2d, snode, ntree, node, key);
+ if (node) {
+ NodeResizeDirection dir = node_get_resize_direction(node, cursor[0], cursor[1]);
+ wmcursor = node_get_resize_cursor(dir);
}
-}
-static void node_update(const bContext *C, bNodeTree *ntree, bNode *node)
-{
- if (node->typeinfo->draw_nodetype_prepare) {
- node->typeinfo->draw_nodetype_prepare(C, ntree, node);
- }
+ WM_cursor_set(&win, wmcursor);
}
-static void count_multi_input_socket_links(bNodeTree *ntree, SpaceNode *snode)
+static void count_multi_input_socket_links(bNodeTree &ntree, SpaceNode &snode)
{
Map<bNodeSocket *, int> counts;
- LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
if (link->tosock->flag & SOCK_MULTI_INPUT) {
int &count = counts.lookup_or_add(link->tosock, 0);
count++;
}
}
/* Count temporary links going into this socket. */
- LISTBASE_FOREACH (bNodeLinkDrag *, nldrag, &snode->runtime->linkdrag) {
- LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) {
- bNodeLink *link = (bNodeLink *)linkdata->data;
+ if (snode.runtime->linkdrag) {
+ for (const bNodeLink *link : snode.runtime->linkdrag->links) {
if (link->tosock && (link->tosock->flag & SOCK_MULTI_INPUT)) {
int &count = counts.lookup_or_add(link->tosock, 0);
count++;
}
}
}
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+
+ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
if (socket->flag & SOCK_MULTI_INPUT) {
socket->total_inputs = counts.lookup_default(socket, 0);
@@ -2134,86 +2325,367 @@ static void count_multi_input_socket_links(bNodeTree *ntree, SpaceNode *snode)
}
}
-void node_update_nodetree(const bContext *C, bNodeTree *ntree)
+/* XXX Does a bounding box update by iterating over all children.
+ * Not ideal to do this in every draw call, but doing as transform callback doesn't work,
+ * since the child node totr rects are not updated properly at that point. */
+static void frame_node_prepare_for_draw(bNode &node, Span<bNode *> nodes)
+{
+ const float margin = 1.5f * U.widget_unit;
+ NodeFrame *data = (NodeFrame *)node.storage;
+
+ /* init rect from current frame size */
+ rctf rect;
+ node_to_updated_rect(node, rect);
+
+ /* frame can be resized manually only if shrinking is disabled or no children are attached */
+ data->flag |= NODE_FRAME_RESIZEABLE;
+ /* for shrinking bbox, initialize the rect from first child node */
+ bool bbinit = (data->flag & NODE_FRAME_SHRINK);
+ /* fit bounding box to all children */
+ for (const bNode *tnode : nodes) {
+ if (tnode->parent != &node) {
+ continue;
+ }
+
+ /* add margin to node rect */
+ rctf noderect = tnode->totr;
+ noderect.xmin -= margin;
+ noderect.xmax += margin;
+ noderect.ymin -= margin;
+ noderect.ymax += margin;
+
+ /* first child initializes frame */
+ if (bbinit) {
+ bbinit = false;
+ rect = noderect;
+ data->flag &= ~NODE_FRAME_RESIZEABLE;
+ }
+ else {
+ BLI_rctf_union(&rect, &noderect);
+ }
+ }
+
+ /* now adjust the frame size from view-space bounding box */
+ const float2 offset = node_from_view(node, {rect.xmin, rect.ymax});
+ node.offsetx = offset.x;
+ node.offsety = offset.y;
+ const float2 max = node_from_view(node, {rect.xmax, rect.ymin});
+ node.width = max.x - node.offsetx;
+ node.height = -max.y + node.offsety;
+
+ node.totr = rect;
+}
+
+static void reroute_node_prepare_for_draw(bNode &node)
+{
+ /* get "global" coords */
+ const float2 loc = node_to_view(node, float2(0));
+
+ /* reroute node has exactly one input and one output, both in the same place */
+ bNodeSocket *nsock = (bNodeSocket *)node.outputs.first;
+ nsock->locx = loc.x;
+ nsock->locy = loc.y;
+
+ nsock = (bNodeSocket *)node.inputs.first;
+ nsock->locx = loc.x;
+ nsock->locy = loc.y;
+
+ const float size = 8.0f;
+ node.width = size * 2;
+ node.totr.xmin = loc.x - size;
+ node.totr.xmax = loc.x + size;
+ node.totr.ymax = loc.y + size;
+ node.totr.ymin = loc.y - size;
+}
+
+static void node_update_nodetree(const bContext &C,
+ bNodeTree &ntree,
+ Span<bNode *> nodes,
+ Span<uiBlock *> blocks)
{
/* Make sure socket "used" tags are correct, for displaying value buttons. */
- SpaceNode *snode = CTX_wm_space_node(C);
- ntreeTagUsedSockets(ntree);
+ SpaceNode *snode = CTX_wm_space_node(&C);
+ ntreeTagUsedSockets(&ntree);
- count_multi_input_socket_links(ntree, snode);
+ count_multi_input_socket_links(ntree, *snode);
/* Update nodes front to back, so children sizes get updated before parents. */
- LISTBASE_FOREACH_BACKWARD (bNode *, node, &ntree->nodes) {
- node_update(C, ntree, node);
+ for (const int i : nodes.index_range()) {
+ bNode &node = *nodes[i];
+ uiBlock &block = *blocks[i];
+ if (node.type == NODE_FRAME) {
+ frame_node_prepare_for_draw(node, nodes);
+ }
+ else if (node.type == NODE_REROUTE) {
+ reroute_node_prepare_for_draw(node);
+ }
+ else {
+ if (node.flag & NODE_HIDDEN) {
+ node_update_hidden(node, block);
+ }
+ else {
+ node_update_basis(C, ntree, node, block);
+ }
+ }
}
}
-static void node_draw(const bContext *C,
- ARegion *region,
- SpaceNode *snode,
- bNodeTree *ntree,
- bNode *node,
- bNodeInstanceKey key)
+static void frame_node_draw_label(const bNodeTree &ntree,
+ const bNode &node,
+ const SpaceNode &snode)
{
- if (node->typeinfo->draw_nodetype) {
- node->typeinfo->draw_nodetype(C, region, snode, ntree, node, key);
+ const float aspect = snode.runtime->aspect;
+ /* XXX font id is crap design */
+ const int fontid = UI_style_get()->widgetlabel.uifont_id;
+ const NodeFrame *data = (const NodeFrame *)node.storage;
+ const float font_size = data->label_size / aspect;
+
+ char label[MAX_NAME];
+ nodeLabel(&ntree, &node, label, sizeof(label));
+
+ BLF_enable(fontid, BLF_ASPECT);
+ BLF_aspect(fontid, aspect, aspect, 1.0f);
+ /* clamp otherwise it can suck up a LOT of memory */
+ BLF_size(fontid, MIN2(24.0f, font_size), U.dpi);
+
+ /* title color */
+ int color_id = node_get_colorid(node);
+ uchar color[3];
+ UI_GetThemeColorBlendShade3ubv(TH_TEXT, color_id, 0.4f, 10, color);
+ BLF_color3ubv(fontid, color);
+
+ const float margin = (float)(NODE_DY / 4);
+ const float width = BLF_width(fontid, label, sizeof(label));
+ const float ascender = BLF_ascender(fontid);
+ const int label_height = ((margin / aspect) + (ascender * aspect));
+
+ /* 'x' doesn't need aspect correction */
+ const rctf &rct = node.totr;
+ /* XXX a bit hacky, should use separate align values for x and y */
+ float x = BLI_rctf_cent_x(&rct) - (0.5f * width);
+ float y = rct.ymax - label_height;
+
+ /* label */
+ const bool has_label = node.label[0] != '\0';
+ if (has_label) {
+ BLF_position(fontid, x, y, 0);
+ BLF_draw(fontid, label, BLF_DRAW_STR_DUMMY_MAX);
+ }
+
+ /* draw text body */
+ if (node.id) {
+ const Text *text = (const Text *)node.id;
+ const int line_height_max = BLF_height_max(fontid);
+ const float line_spacing = (line_height_max * aspect);
+ const float line_width = (BLI_rctf_size_x(&rct) - margin) / aspect;
+
+ /* 'x' doesn't need aspect correction */
+ x = rct.xmin + margin;
+ y = rct.ymax - label_height - (has_label ? line_spacing : 0);
+
+ /* early exit */
+ int y_min = y + ((margin * 2) - (y - rct.ymin));
+
+ BLF_enable(fontid, BLF_CLIPPING | BLF_WORD_WRAP);
+ BLF_clipping(fontid,
+ rct.xmin,
+ /* round to avoid clipping half-way through a line */
+ y - (floorf(((y - rct.ymin) - (margin * 2)) / line_spacing) * line_spacing),
+ rct.xmin + line_width,
+ rct.ymax);
+
+ BLF_wordwrap(fontid, line_width);
+
+ LISTBASE_FOREACH (const TextLine *, line, &text->lines) {
+ struct ResultBLF info;
+ if (line->line[0]) {
+ BLF_position(fontid, x, y, 0);
+ BLF_draw_ex(fontid, line->line, line->len, &info);
+ y -= line_spacing * info.lines;
+ }
+ else {
+ y -= line_spacing;
+ }
+ if (y < y_min) {
+ break;
+ }
+ }
+
+ BLF_disable(fontid, BLF_CLIPPING | BLF_WORD_WRAP);
}
+
+ BLF_disable(fontid, BLF_ASPECT);
}
-#define USE_DRAW_TOT_UPDATE
+static void frame_node_draw(const bContext &C,
+ const ARegion &region,
+ const SpaceNode &snode,
+ bNodeTree &ntree,
+ bNode &node,
+ uiBlock &block)
+{
+ /* skip if out of view */
+ if (BLI_rctf_isect(&node.totr, &region.v2d.cur, nullptr) == false) {
+ UI_block_end(&C, &block);
+ return;
+ }
+
+ float color[4];
+ UI_GetThemeColor4fv(TH_NODE_FRAME, color);
+ const float alpha = color[3];
-void node_draw_nodetree(const bContext *C,
- ARegion *region,
- SpaceNode *snode,
- bNodeTree *ntree,
- bNodeInstanceKey parent_key)
+ /* shadow */
+ node_draw_shadow(snode, node, BASIS_RAD, alpha);
+
+ /* body */
+ if (node.flag & NODE_CUSTOM_COLOR) {
+ rgba_float_args_set(color, node.color[0], node.color[1], node.color[2], alpha);
+ }
+ else {
+ UI_GetThemeColor4fv(TH_NODE_FRAME, color);
+ }
+
+ const rctf &rct = node.totr;
+ UI_draw_roundbox_corner_set(UI_CNR_ALL);
+ UI_draw_roundbox_4fv(&rct, true, BASIS_RAD, color);
+
+ /* outline active and selected emphasis */
+ if (node.flag & SELECT) {
+ if (node.flag & NODE_ACTIVE) {
+ UI_GetThemeColorShadeAlpha4fv(TH_ACTIVE, 0, -40, color);
+ }
+ else {
+ UI_GetThemeColorShadeAlpha4fv(TH_SELECT, 0, -40, color);
+ }
+
+ UI_draw_roundbox_aa(&rct, false, BASIS_RAD, color);
+ }
+
+ /* label and text */
+ frame_node_draw_label(ntree, node, snode);
+
+ node_draw_extra_info_panel(snode, node, block);
+
+ UI_block_end(&C, &block);
+ UI_block_draw(&C, &block);
+}
+
+static void reroute_node_draw(
+ const bContext &C, ARegion &region, bNodeTree &ntree, bNode &node, uiBlock &block)
{
- if (ntree == nullptr) {
- return; /* Groups. */
+ char showname[128]; /* 128 used below */
+ const rctf &rct = node.totr;
+
+ /* skip if out of view */
+ if (rct.xmax < region.v2d.cur.xmin || rct.xmin > region.v2d.cur.xmax ||
+ rct.ymax < region.v2d.cur.ymin || node.totr.ymin > region.v2d.cur.ymax) {
+ UI_block_end(&C, &block);
+ return;
}
-#ifdef USE_DRAW_TOT_UPDATE
- if (ntree->nodes.first) {
- BLI_rctf_init_minmax(&region->v2d.tot);
+ if (node.label[0] != '\0') {
+ /* draw title (node label) */
+ BLI_strncpy(showname, node.label, sizeof(showname));
+ uiDefBut(&block,
+ UI_BTYPE_LABEL,
+ 0,
+ showname,
+ (int)(rct.xmin - NODE_DYS),
+ (int)(rct.ymax),
+ (short)512,
+ (short)NODE_DY,
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ nullptr);
+ }
+
+ /* only draw input socket. as they all are placed on the same position.
+ * highlight also if node itself is selected, since we don't display the node body separately!
+ */
+ node_draw_sockets(region.v2d, C, ntree, node, block, false, node.flag & SELECT);
+
+ UI_block_end(&C, &block);
+ UI_block_draw(&C, &block);
+}
+
+static void node_draw(const bContext &C,
+ ARegion &region,
+ const SpaceNode &snode,
+ bNodeTree &ntree,
+ bNode &node,
+ uiBlock &block,
+ bNodeInstanceKey key)
+{
+ if (node.type == NODE_FRAME) {
+ frame_node_draw(C, region, snode, ntree, node, block);
+ }
+ else if (node.type == NODE_REROUTE) {
+ reroute_node_draw(C, region, ntree, node, block);
+ }
+ else {
+ const View2D &v2d = region.v2d;
+ if (node.flag & NODE_HIDDEN) {
+ node_draw_hidden(C, v2d, snode, ntree, node, block);
+ }
+ else {
+ node_draw_basis(C, v2d, snode, ntree, node, block, key);
+ }
}
+}
+
+#define USE_DRAW_TOT_UPDATE
+
+static void node_draw_nodetree(const bContext &C,
+ ARegion &region,
+ SpaceNode &snode,
+ bNodeTree &ntree,
+ Span<bNode *> nodes,
+ Span<uiBlock *> blocks,
+ bNodeInstanceKey parent_key)
+{
+#ifdef USE_DRAW_TOT_UPDATE
+ BLI_rctf_init_minmax(&region.v2d.tot);
#endif
/* Draw background nodes, last nodes in front. */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ for (const int i : nodes.index_range()) {
#ifdef USE_DRAW_TOT_UPDATE
/* Unrelated to background nodes, update the v2d->tot,
* can be anywhere before we draw the scroll bars. */
- BLI_rctf_union(&region->v2d.tot, &node->totr);
+ BLI_rctf_union(&region.v2d.tot, &nodes[i]->totr);
#endif
- if (!(node->flag & NODE_BACKGROUND)) {
+ if (!(nodes[i]->flag & NODE_BACKGROUND)) {
continue;
}
- bNodeInstanceKey key = BKE_node_instance_key(parent_key, ntree, node);
- node_draw(C, region, snode, ntree, node, key);
+ bNodeInstanceKey key = BKE_node_instance_key(parent_key, &ntree, nodes[i]);
+ node_draw(C, region, snode, ntree, *nodes[i], *blocks[i], key);
}
/* Node lines. */
GPU_blend(GPU_BLEND_ALPHA);
nodelink_batch_start(snode);
- LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
if (!nodeLinkIsHidden(link)) {
- node_draw_link(C, &region->v2d, snode, link);
+ node_draw_link(C, region.v2d, snode, *link);
}
}
nodelink_batch_end(snode);
GPU_blend(GPU_BLEND_NONE);
/* Draw foreground nodes, last nodes in front. */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->flag & NODE_BACKGROUND) {
+ for (const int i : nodes.index_range()) {
+ if (nodes[i]->flag & NODE_BACKGROUND) {
continue;
}
- bNodeInstanceKey key = BKE_node_instance_key(parent_key, ntree, node);
- node_draw(C, region, snode, ntree, node, key);
+ bNodeInstanceKey key = BKE_node_instance_key(parent_key, &ntree, nodes[i]);
+ node_draw(C, region, snode, ntree, *nodes[i], *blocks[i], key);
}
}
@@ -2247,36 +2719,38 @@ static void draw_tree_path(const bContext &C, ARegion &region)
GPU_matrix_pop_projection();
}
-static void snode_setup_v2d(SpaceNode *snode, ARegion *region, const float center[2])
+static void snode_setup_v2d(SpaceNode &snode, ARegion &region, const float2 &center)
{
- View2D *v2d = &region->v2d;
+ View2D &v2d = region.v2d;
/* Shift view to node tree center. */
- UI_view2d_center_set(v2d, center[0], center[1]);
- UI_view2d_view_ortho(v2d);
+ UI_view2d_center_set(&v2d, center[0], center[1]);
+ UI_view2d_view_ortho(&v2d);
/* Aspect + font, set each time. */
- snode->runtime->aspect = BLI_rctf_size_x(&v2d->cur) / (float)region->winx;
+ snode.runtime->aspect = BLI_rctf_size_x(&v2d.cur) / (float)region.winx;
// XXX snode->curfont = uiSetCurFont_ext(snode->aspect);
}
-static void draw_nodetree(const bContext *C,
- ARegion *region,
- bNodeTree *ntree,
+static void draw_nodetree(const bContext &C,
+ ARegion &region,
+ bNodeTree &ntree,
bNodeInstanceKey parent_key)
{
- SpaceNode *snode = CTX_wm_space_node(C);
+ SpaceNode *snode = CTX_wm_space_node(&C);
+
+ Vector<bNode *> nodes = ntree.nodes;
- node_uiblocks_init(C, ntree);
+ Array<uiBlock *> blocks = node_uiblocks_init(C, nodes);
- node_update_nodetree(C, ntree);
- node_draw_nodetree(C, region, snode, ntree, parent_key);
+ node_update_nodetree(C, ntree, nodes, blocks);
+ node_draw_nodetree(C, region, *snode, ntree, nodes, blocks, parent_key);
}
/**
* Make the background slightly brighter to indicate that users are inside a node-group.
*/
-static void draw_background_color(const SpaceNode *snode)
+static void draw_background_color(const SpaceNode &snode)
{
const int max_tree_length = 3;
const float bright_factor = 0.25f;
@@ -2284,7 +2758,7 @@ static void draw_background_color(const SpaceNode *snode)
/* We ignore the first element of the path since it is the top-most tree and it doesn't need to
* be brighter. We also set a cap to how many levels we want to set apart, to avoid the
* background from getting too bright. */
- const int clamped_tree_path_length = BLI_listbase_count_at_most(&snode->treepath,
+ const int clamped_tree_path_length = BLI_listbase_count_at_most(&snode.treepath,
max_tree_length);
const int depth = max_ii(0, clamped_tree_path_length - 1);
@@ -2294,34 +2768,34 @@ static void draw_background_color(const SpaceNode *snode)
GPU_clear_color(color[0], color[1], color[2], 1.0);
}
-void node_draw_space(const bContext *C, ARegion *region)
+void node_draw_space(const bContext &C, ARegion &region)
{
- wmWindow *win = CTX_wm_window(C);
- SpaceNode *snode = CTX_wm_space_node(C);
- View2D *v2d = &region->v2d;
+ wmWindow *win = CTX_wm_window(&C);
+ SpaceNode &snode = *CTX_wm_space_node(&C);
+ View2D &v2d = region.v2d;
/* Setup off-screen buffers. */
- GPUViewport *viewport = WM_draw_region_get_viewport(region);
+ GPUViewport *viewport = WM_draw_region_get_viewport(&region);
GPUFrameBuffer *framebuffer_overlay = GPU_viewport_framebuffer_overlay_get(viewport);
GPU_framebuffer_bind_no_srgb(framebuffer_overlay);
- UI_view2d_view_ortho(v2d);
+ UI_view2d_view_ortho(&v2d);
draw_background_color(snode);
GPU_depth_test(GPU_DEPTH_NONE);
GPU_scissor_test(true);
/* XXX `snode->runtime->cursor` set in coordinate-space for placing new nodes,
* used for drawing noodles too. */
- UI_view2d_region_to_view(&region->v2d,
- win->eventstate->xy[0] - region->winrct.xmin,
- win->eventstate->xy[1] - region->winrct.ymin,
- &snode->runtime->cursor[0],
- &snode->runtime->cursor[1]);
- snode->runtime->cursor[0] /= UI_DPI_FAC;
- snode->runtime->cursor[1] /= UI_DPI_FAC;
+ UI_view2d_region_to_view(&region.v2d,
+ win->eventstate->xy[0] - region.winrct.xmin,
+ win->eventstate->xy[1] - region.winrct.ymin,
+ &snode.runtime->cursor[0],
+ &snode.runtime->cursor[1]);
+ snode.runtime->cursor[0] /= UI_DPI_FAC;
+ snode.runtime->cursor[1] /= UI_DPI_FAC;
- ED_region_draw_cb_draw(C, region, REGION_DRAW_PRE_VIEW);
+ ED_region_draw_cb_draw(&C, &region, REGION_DRAW_PRE_VIEW);
/* Only set once. */
GPU_blend(GPU_BLEND_ALPHA);
@@ -2330,15 +2804,15 @@ void node_draw_space(const bContext *C, ARegion *region)
snode_set_context(C);
const int grid_levels = UI_GetThemeValueType(TH_NODE_GRID_LEVELS, SPACE_NODE);
- UI_view2d_dot_grid_draw(v2d, TH_GRID, NODE_GRID_STEP_SIZE, grid_levels);
+ UI_view2d_dot_grid_draw(&v2d, TH_GRID, NODE_GRID_STEP_SIZE, grid_levels);
/* Draw parent node trees. */
- if (snode->treepath.last) {
- bNodeTreePath *path = (bNodeTreePath *)snode->treepath.last;
+ if (snode.treepath.last) {
+ bNodeTreePath *path = (bNodeTreePath *)snode.treepath.last;
/* Update tree path name (drawn in the bottom left). */
- ID *name_id = (path->nodetree && path->nodetree != snode->nodetree) ? &path->nodetree->id :
- snode->id;
+ ID *name_id = (path->nodetree && path->nodetree != snode.nodetree) ? &path->nodetree->id :
+ snode.id;
if (name_id && UNLIKELY(!STREQ(path->display_name, name_id->name + 2))) {
BLI_strncpy(path->display_name, name_id->name + 2, sizeof(path->display_name));
@@ -2346,12 +2820,12 @@ void node_draw_space(const bContext *C, ARegion *region)
/* Current View2D center, will be set temporarily for parent node trees. */
float center[2];
- UI_view2d_center_get(v2d, &center[0], &center[1]);
+ UI_view2d_center_get(&v2d, &center[0], &center[1]);
/* Store new view center in path and current edit tree. */
copy_v2_v2(path->view_center, center);
- if (snode->edittree) {
- copy_v2_v2(snode->edittree->view_center, center);
+ if (snode.edittree) {
+ copy_v2_v2(snode.edittree->view_center, center);
}
/* Top-level edit tree. */
@@ -2369,31 +2843,31 @@ void node_draw_space(const bContext *C, ARegion *region)
GPU_matrix_push();
GPU_matrix_identity_set();
- wmOrtho2_pixelspace(region->winx, region->winy);
+ wmOrtho2_pixelspace(region.winx, region.winy);
- WM_gizmomap_draw(region->gizmo_map, C, WM_GIZMOMAP_DRAWSTEP_2D);
+ WM_gizmomap_draw(region.gizmo_map, &C, WM_GIZMOMAP_DRAWSTEP_2D);
GPU_matrix_pop();
GPU_matrix_projection_set(original_proj);
}
- draw_nodetree(C, region, ntree, path->parent_key);
+ draw_nodetree(C, region, *ntree, path->parent_key);
}
/* Temporary links. */
GPU_blend(GPU_BLEND_ALPHA);
GPU_line_smooth(true);
- LISTBASE_FOREACH (bNodeLinkDrag *, nldrag, &snode->runtime->linkdrag) {
- LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) {
- node_draw_link(C, v2d, snode, (bNodeLink *)linkdata->data);
+ if (snode.runtime->linkdrag) {
+ for (const bNodeLink *link : snode.runtime->linkdrag->links) {
+ node_draw_link(C, v2d, snode, *link);
}
}
GPU_line_smooth(false);
GPU_blend(GPU_BLEND_NONE);
- if (snode->overlay.flag & SN_OVERLAY_SHOW_OVERLAYS && snode->flag & SNODE_SHOW_GPENCIL) {
+ if (snode.overlay.flag & SN_OVERLAY_SHOW_OVERLAYS && snode.flag & SNODE_SHOW_GPENCIL) {
/* Draw grease-pencil annotations. */
- ED_annotation_draw_view2d(C, true);
+ ED_annotation_draw_view2d(&C, true);
}
}
else {
@@ -2402,23 +2876,23 @@ void node_draw_space(const bContext *C, ARegion *region)
draw_nodespace_back_pix(C, region, snode, NODE_INSTANCE_KEY_NONE);
}
- ED_region_draw_cb_draw(C, region, REGION_DRAW_POST_VIEW);
+ ED_region_draw_cb_draw(&C, &region, REGION_DRAW_POST_VIEW);
/* Reset view matrix. */
- UI_view2d_view_restore(C);
+ UI_view2d_view_restore(&C);
- if (snode->treepath.last) {
- if (snode->overlay.flag & SN_OVERLAY_SHOW_OVERLAYS && snode->flag & SNODE_SHOW_GPENCIL) {
+ if (snode.overlay.flag & SN_OVERLAY_SHOW_OVERLAYS) {
+ if (snode.flag & SNODE_SHOW_GPENCIL && snode.treepath.last) {
/* Draw grease-pencil (screen strokes, and also paint-buffer). */
- ED_annotation_draw_view2d(C, false);
+ ED_annotation_draw_view2d(&C, false);
}
- }
- /* Draw context path. */
- if (snode->edittree) {
- draw_tree_path(*C, *region);
+ /* Draw context path. */
+ if (snode.overlay.flag & SN_OVERLAY_SHOW_PATH && snode.edittree) {
+ draw_tree_path(C, region);
+ }
}
/* Scrollers. */
- UI_view2d_scrollers_draw(v2d, nullptr);
+ UI_view2d_scrollers_draw(&v2d, nullptr);
}
diff --git a/source/blender/editors/space_node/node_edit.cc b/source/blender/editors/space_node/node_edit.cc
index 30c9f7ea56b..fb90e2bfe50 100644
--- a/source/blender/editors/space_node/node_edit.cc
+++ b/source/blender/editors/space_node/node_edit.cc
@@ -31,9 +31,6 @@
#include "DNA_text_types.h"
#include "DNA_world_types.h"
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
-
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_image.h"
@@ -80,6 +77,8 @@
#define USE_ESC_COMPO
+using blender::float2;
+
/* ***************** composite job manager ********************** */
enum {
@@ -103,24 +102,23 @@ struct CompoJob {
float *progress;
};
-float node_socket_calculate_height(const bNodeSocket *socket)
+float node_socket_calculate_height(const bNodeSocket &socket)
{
float sock_height = NODE_SOCKSIZE * 2.0f;
- if (socket->flag & SOCK_MULTI_INPUT) {
- sock_height += max_ii(NODE_MULTI_INPUT_LINK_GAP * 0.5f * socket->total_inputs, NODE_SOCKSIZE);
+ if (socket.flag & SOCK_MULTI_INPUT) {
+ sock_height += max_ii(NODE_MULTI_INPUT_LINK_GAP * 0.5f * socket.total_inputs, NODE_SOCKSIZE);
}
return sock_height;
}
-void node_link_calculate_multi_input_position(const float socket_x,
- const float socket_y,
- const int index,
- const int total_inputs,
- float r[2])
+float2 node_link_calculate_multi_input_position(const float2 &socket_position,
+ const int index,
+ const int total_inputs)
{
- float offset = (total_inputs * NODE_MULTI_INPUT_LINK_GAP - NODE_MULTI_INPUT_LINK_GAP) * 0.5;
- r[0] = socket_x - NODE_SOCKSIZE * 0.5f;
- r[1] = socket_y - offset + (index * NODE_MULTI_INPUT_LINK_GAP);
+ const float offset = (total_inputs * NODE_MULTI_INPUT_LINK_GAP - NODE_MULTI_INPUT_LINK_GAP) *
+ 0.5f;
+ return {socket_position.x - NODE_SOCKSIZE * 0.5f,
+ socket_position.y - offset + index * NODE_MULTI_INPUT_LINK_GAP};
}
static void compo_tag_output_nodes(bNodeTree *nodetree, int recalc_flags)
@@ -320,13 +318,6 @@ static void compo_startjob(void *cjv,
ntree->progress = nullptr;
}
-/**
- * \param scene_owner: is the owner of the job,
- * we don't use it for anything else currently so could also be a void pointer,
- * but for now keep it an 'Scene' for consistency.
- *
- * \note only call from spaces `refresh` callbacks, not direct! - use with care.
- */
void ED_node_composite_job(const bContext *C, struct bNodeTree *nodetree, Scene *scene_owner)
{
Main *bmain = CTX_data_main(C);
@@ -370,7 +361,6 @@ void ED_node_composite_job(const bContext *C, struct bNodeTree *nodetree, Scene
/* ***************************************** */
-/* operator poll callback */
bool composite_node_active(bContext *C)
{
if (ED_operator_node_active(C)) {
@@ -382,7 +372,6 @@ bool composite_node_active(bContext *C)
return false;
}
-/* operator poll callback */
bool composite_node_editable(bContext *C)
{
if (ED_operator_node_editable(C)) {
@@ -394,31 +383,31 @@ bool composite_node_editable(bContext *C)
return false;
}
-void snode_dag_update(bContext *C, SpaceNode *snode)
+void snode_dag_update(bContext &C, SpaceNode &snode)
{
- Main *bmain = CTX_data_main(C);
+ Main *bmain = CTX_data_main(&C);
/* for groups, update all ID's using this */
- if ((snode->edittree->id.flag & LIB_EMBEDDED_DATA) == 0) {
+ if ((snode.edittree->id.flag & LIB_EMBEDDED_DATA) == 0) {
FOREACH_NODETREE_BEGIN (bmain, tntree, id) {
- if (ntreeHasTree(tntree, snode->edittree)) {
+ if (ntreeHasTree(tntree, snode.edittree)) {
DEG_id_tag_update(id, 0);
}
}
FOREACH_NODETREE_END;
}
- DEG_id_tag_update(snode->id, 0);
- DEG_id_tag_update(&snode->nodetree->id, 0);
+ DEG_id_tag_update(snode.id, 0);
+ DEG_id_tag_update(&snode.nodetree->id, 0);
}
-void snode_notify(bContext *C, SpaceNode *snode)
+void snode_notify(bContext &C, SpaceNode &snode)
{
- ID *id = snode->id;
+ ID *id = snode.id;
- WM_event_add_notifier(C, NC_NODE | NA_EDITED, nullptr);
+ WM_event_add_notifier(&C, NC_NODE | NA_EDITED, nullptr);
- if (ED_node_is_shader(snode)) {
+ if (ED_node_is_shader(&snode)) {
if (GS(id->name) == ID_MA) {
WM_main_add_notifier(NC_MATERIAL | ND_SHADING, id);
}
@@ -429,13 +418,13 @@ void snode_notify(bContext *C, SpaceNode *snode)
WM_main_add_notifier(NC_WORLD | ND_WORLD, id);
}
}
- else if (ED_node_is_compositor(snode)) {
- WM_event_add_notifier(C, NC_SCENE | ND_NODES, id);
+ else if (ED_node_is_compositor(&snode)) {
+ WM_event_add_notifier(&C, NC_SCENE | ND_NODES, id);
}
- else if (ED_node_is_texture(snode)) {
- WM_event_add_notifier(C, NC_TEXTURE | ND_NODES, id);
+ else if (ED_node_is_texture(&snode)) {
+ WM_event_add_notifier(&C, NC_TEXTURE | ND_NODES, id);
}
- else if (ED_node_is_geometry(snode)) {
+ else if (ED_node_is_geometry(&snode)) {
WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, id);
}
}
@@ -470,8 +459,6 @@ bool ED_node_is_geometry(struct SpaceNode *snode)
return STREQ(snode->tree_idname, ntreeType_Geometry->idname);
}
-/* assumes nothing being done in ntree yet, sets the default in/out node */
-/* called from shading buttons or header */
void ED_node_shader_default(const bContext *C, ID *id)
{
Main *bmain = CTX_data_main(C);
@@ -538,8 +525,6 @@ void ED_node_shader_default(const bContext *C, ID *id)
}
}
-/* assumes nothing being done in ntree yet, sets the default in/out node */
-/* called from shading buttons or header */
void ED_node_composit_default(const bContext *C, struct Scene *sce)
{
/* but lets check it anyway */
@@ -573,8 +558,6 @@ void ED_node_composit_default(const bContext *C, struct Scene *sce)
ntreeUpdateTree(CTX_data_main(C), sce->nodetree);
}
-/* assumes nothing being done in ntree yet, sets the default in/out node */
-/* called from shading buttons or header */
void ED_node_texture_default(const bContext *C, Tex *tex)
{
/* but lets check it anyway */
@@ -603,16 +586,18 @@ void ED_node_texture_default(const bContext *C, Tex *tex)
ntreeUpdateTree(CTX_data_main(C), tex->nodetree);
}
-/* Here we set the active tree(s), even called for each redraw now, so keep it fast :) */
-void snode_set_context(const bContext *C)
+/**
+ * Here we set the active tree(s), even called for each redraw now, so keep it fast :)
+ */
+void snode_set_context(const bContext &C)
{
- SpaceNode *snode = CTX_wm_space_node(C);
+ SpaceNode *snode = CTX_wm_space_node(&C);
bNodeTreeType *treetype = ntreeTypeFind(snode->tree_idname);
bNodeTree *ntree = snode->nodetree;
ID *id = snode->id, *from = snode->from;
/* check the tree type */
- if (!treetype || (treetype->poll && !treetype->poll(C, treetype))) {
+ if (!treetype || (treetype->poll && !treetype->poll(&C, treetype))) {
/* invalid tree type, skip
* NOTE: not resetting the node path here, invalid #bNodeTreeType
* may still be registered at a later point. */
@@ -633,7 +618,7 @@ void snode_set_context(const bContext *C)
id = nullptr;
from = nullptr;
- treetype->get_from_context(C, treetype, &ntree, &id, &from);
+ treetype->get_from_context(&C, treetype, &ntree, &id, &from);
}
}
@@ -643,7 +628,7 @@ void snode_set_context(const bContext *C)
}
}
-void snode_update(SpaceNode *snode, bNode *node)
+void snode_update(SpaceNode &snode, bNode *node)
{
/* XXX this only updates nodes in the current node space tree path.
* The function supposedly should update any potential group node linking to changed tree,
@@ -651,7 +636,7 @@ void snode_update(SpaceNode *snode, bNode *node)
*/
/* update all edited group nodes */
- bNodeTreePath *path = (bNodeTreePath *)snode->treepath.last;
+ bNodeTreePath *path = (bNodeTreePath *)snode.treepath.last;
if (path) {
bNodeTree *ngroup = path->nodetree;
for (path = path->prev; path; path = path->prev) {
@@ -661,7 +646,7 @@ void snode_update(SpaceNode *snode, bNode *node)
}
if (node) {
- nodeUpdate(snode->edittree, node);
+ nodeUpdate(snode.edittree, node);
}
}
@@ -918,10 +903,10 @@ static void edit_node_properties_get(
/* ************************** Node generic ************** */
/* is rct in visible part of node? */
-static bNode *visible_node(SpaceNode *snode, const rctf *rct)
+static bNode *visible_node(SpaceNode &snode, const rctf &rct)
{
- LISTBASE_FOREACH_BACKWARD (bNode *, node, &snode->edittree->nodes) {
- if (BLI_rctf_isect(&node->totr, rct, nullptr)) {
+ LISTBASE_FOREACH_BACKWARD (bNode *, node, &snode.edittree->nodes) {
+ if (BLI_rctf_isect(&node->totr, &rct, nullptr)) {
return node;
}
}
@@ -938,13 +923,15 @@ struct NodeSizeWidget {
int directions;
};
-static void node_resize_init(
- bContext *C, wmOperator *op, const wmEvent *UNUSED(event), bNode *node, int dir)
+static void node_resize_init(bContext *C,
+ wmOperator *op,
+ const wmEvent *UNUSED(event),
+ const bNode *node,
+ NodeResizeDirection dir)
{
SpaceNode *snode = CTX_wm_space_node(C);
- NodeSizeWidget *nsw = (NodeSizeWidget *)MEM_callocN(sizeof(NodeSizeWidget),
- "size widget op data");
+ NodeSizeWidget *nsw = (NodeSizeWidget *)MEM_callocN(sizeof(NodeSizeWidget), __func__);
op->customdata = nsw;
nsw->mxstart = snode->runtime->cursor[0] * UI_DPI_FAC;
@@ -1089,21 +1076,22 @@ static int node_resize_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
SpaceNode *snode = CTX_wm_space_node(C);
ARegion *region = CTX_wm_region(C);
- bNode *node = nodeGetActive(snode->edittree);
- int dir;
+ const bNode *node = nodeGetActive(snode->edittree);
- if (node) {
- float cursor[2];
+ if (node == nullptr) {
+ return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
+ }
- /* convert mouse coordinates to v2d space */
- UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &cursor[0], &cursor[1]);
- dir = node->typeinfo->resize_area_func(node, cursor[0], cursor[1]);
- if (dir != 0) {
- node_resize_init(C, op, event, node, dir);
- return OPERATOR_RUNNING_MODAL;
- }
+ /* convert mouse coordinates to v2d space */
+ float cursor[2];
+ UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &cursor[0], &cursor[1]);
+ const NodeResizeDirection dir = node_get_resize_direction(node, cursor[0], cursor[1]);
+ if (dir == NODE_RESIZE_NONE) {
+ return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
}
- return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
+
+ node_resize_init(C, op, event, node, dir);
+ return OPERATOR_RUNNING_MODAL;
}
static void node_resize_cancel(bContext *C, wmOperator *op)
@@ -1171,7 +1159,7 @@ void node_set_hidden_sockets(SpaceNode *snode, bNode *node, int set)
}
/* checks snode->mouse position, and returns found node/socket */
-static bool cursor_isect_multi_input_socket(const float cursor[2], const bNodeSocket *socket)
+static bool cursor_isect_multi_input_socket(const float cursor[2], const bNodeSocket &socket)
{
const float node_socket_height = node_socket_calculate_height(socket);
rctf multi_socket_rect;
@@ -1181,19 +1169,21 @@ static bool cursor_isect_multi_input_socket(const float cursor[2], const bNodeSo
* sometimes want to drag the link to the other side, if you may
* accidentally pick the wrong link otherwise. */
BLI_rctf_init(&multi_socket_rect,
- socket->locx - NODE_SOCKSIZE * 4.0f,
- socket->locx + NODE_SOCKSIZE * 2.0f,
- socket->locy - node_socket_height,
- socket->locy + node_socket_height);
+ socket.locx - NODE_SOCKSIZE * 4.0f,
+ socket.locx + NODE_SOCKSIZE * 2.0f,
+ socket.locy - node_socket_height,
+ socket.locy + node_socket_height);
if (BLI_rctf_isect_pt(&multi_socket_rect, cursor[0], cursor[1])) {
return true;
}
return false;
}
-/* type is SOCK_IN and/or SOCK_OUT */
-bool node_find_indicated_socket(
- SpaceNode *snode, bNode **nodep, bNodeSocket **sockp, const float cursor[2], int in_out)
+bool node_find_indicated_socket(SpaceNode &snode,
+ bNode **nodep,
+ bNodeSocket **sockp,
+ const float2 &cursor,
+ const eNodeSocketInOut in_out)
{
rctf rect;
@@ -1201,7 +1191,7 @@ bool node_find_indicated_socket(
*sockp = nullptr;
/* check if we click in a socket */
- LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) {
+ LISTBASE_FOREACH (bNode *, node, &snode.edittree->nodes) {
BLI_rctf_init_pt_radius(&rect, cursor, NODE_SOCKSIZE + 4);
if (!(node->flag & NODE_HIDDEN)) {
@@ -1220,8 +1210,8 @@ bool node_find_indicated_socket(
LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
if (!nodeSocketIsHidden(sock)) {
if (sock->flag & SOCK_MULTI_INPUT && !(node->flag & NODE_HIDDEN)) {
- if (cursor_isect_multi_input_socket(cursor, sock)) {
- if (node == visible_node(snode, &rect)) {
+ if (cursor_isect_multi_input_socket(cursor, *sock)) {
+ if (node == visible_node(snode, rect)) {
*nodep = node;
*sockp = sock;
return true;
@@ -1229,7 +1219,7 @@ bool node_find_indicated_socket(
}
}
else if (BLI_rctf_isect_pt(&rect, sock->locx, sock->locy)) {
- if (node == visible_node(snode, &rect)) {
+ if (node == visible_node(snode, rect)) {
*nodep = node;
*sockp = sock;
return true;
@@ -1242,7 +1232,7 @@ bool node_find_indicated_socket(
LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
if (!nodeSocketIsHidden(sock)) {
if (BLI_rctf_isect_pt(&rect, sock->locx, sock->locy)) {
- if (node == visible_node(snode, &rect)) {
+ if (node == visible_node(snode, rect)) {
*nodep = node;
*sockp = sock;
return true;
@@ -1258,28 +1248,28 @@ bool node_find_indicated_socket(
/* ****************** Link Dimming *********************** */
-float node_link_dim_factor(const View2D *v2d, const bNodeLink *link)
+float node_link_dim_factor(const View2D &v2d, const bNodeLink &link)
{
- if (link->fromsock == nullptr || link->tosock == nullptr) {
+ if (link.fromsock == nullptr || link.tosock == nullptr) {
return 1.0f;
}
const float min_endpoint_distance = std::min(
- std::max(BLI_rctf_length_x(&v2d->cur, link->fromsock->locx),
- BLI_rctf_length_y(&v2d->cur, link->fromsock->locy)),
- std::max(BLI_rctf_length_x(&v2d->cur, link->tosock->locx),
- BLI_rctf_length_y(&v2d->cur, link->tosock->locy)));
+ std::max(BLI_rctf_length_x(&v2d.cur, link.fromsock->locx),
+ BLI_rctf_length_y(&v2d.cur, link.fromsock->locy)),
+ std::max(BLI_rctf_length_x(&v2d.cur, link.tosock->locx),
+ BLI_rctf_length_y(&v2d.cur, link.tosock->locy)));
if (min_endpoint_distance == 0.0f) {
return 1.0f;
}
- const float viewport_width = BLI_rctf_size_x(&v2d->cur);
+ const float viewport_width = BLI_rctf_size_x(&v2d.cur);
return std::clamp(1.0f - min_endpoint_distance / viewport_width * 10.0f, 0.05f, 1.0f);
}
-bool node_link_is_hidden_or_dimmed(const View2D *v2d, const bNodeLink *link)
+bool node_link_is_hidden_or_dimmed(const View2D &v2d, const bNodeLink &link)
{
- return nodeLinkIsHidden(link) || node_link_dim_factor(v2d, link) < 0.5f;
+ return nodeLinkIsHidden(&link) || node_link_dim_factor(v2d, link) < 0.5f;
}
/* ****************** Duplicate *********************** */
@@ -1389,7 +1379,7 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
node->flag &= ~(NODE_ACTIVE | NODE_ACTIVE_TEXTURE);
nodeSetSelected(newnode, true);
- do_tag_update |= (do_tag_update || node_connected_to_output(bmain, ntree, newnode));
+ do_tag_update |= (do_tag_update || node_connected_to_output(*bmain, *ntree, *newnode));
}
/* make sure we don't copy new nodes again! */
@@ -1400,9 +1390,9 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
ntreeUpdateTree(CTX_data_main(C), snode->edittree);
- snode_notify(C, snode);
+ snode_notify(*C, *snode);
if (do_tag_update) {
- snode_dag_update(C, snode);
+ snode_dag_update(*C, *snode);
}
return OPERATOR_FINISHED;
@@ -1495,8 +1485,8 @@ static int node_read_viewlayers_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ snode_notify(*C, *snode);
+ snode_dag_update(*C, *snode);
return OPERATOR_FINISHED;
}
@@ -1663,7 +1653,7 @@ static int node_preview_toggle_exec(bContext *C, wmOperator *UNUSED(op))
node_flag_toggle_exec(snode, NODE_PREVIEW);
- snode_notify(C, snode);
+ snode_notify(*C, *snode);
return OPERATOR_FINISHED;
}
@@ -1777,14 +1767,15 @@ static int node_mute_exec(bContext *C, wmOperator *UNUSED(op))
LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) {
if ((node->flag & SELECT) && !node->typeinfo->no_muting) {
node->flag ^= NODE_MUTED;
- snode_update(snode, node);
- do_tag_update |= (do_tag_update || node_connected_to_output(bmain, snode->edittree, node));
+ snode_update(*snode, node);
+ do_tag_update |= (do_tag_update ||
+ node_connected_to_output(*bmain, *snode->edittree, *node));
}
}
- snode_notify(C, snode);
+ snode_notify(*C, *snode);
if (do_tag_update) {
- snode_dag_update(C, snode);
+ snode_dag_update(*C, *snode);
}
return OPERATOR_FINISHED;
@@ -1817,16 +1808,17 @@ static int node_delete_exec(bContext *C, wmOperator *UNUSED(op))
LISTBASE_FOREACH_MUTABLE (bNode *, node, &snode->edittree->nodes) {
if (node->flag & SELECT) {
- do_tag_update |= (do_tag_update || node_connected_to_output(bmain, snode->edittree, node));
+ do_tag_update |= (do_tag_update ||
+ node_connected_to_output(*bmain, *snode->edittree, *node));
nodeRemoveNode(bmain, snode->edittree, node, true);
}
}
ntreeUpdateTree(CTX_data_main(C), snode->edittree);
- snode_notify(C, snode);
+ snode_notify(*C, *snode);
if (do_tag_update) {
- snode_dag_update(C, snode);
+ snode_dag_update(*C, *snode);
}
return OPERATOR_FINISHED;
@@ -1873,8 +1865,8 @@ static int node_switch_view_exec(bContext *C, wmOperator *UNUSED(op))
ntreeUpdateTree(CTX_data_main(C), snode->edittree);
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ snode_notify(*C, *snode);
+ snode_dag_update(*C, *snode);
return OPERATOR_FINISHED;
}
@@ -1911,8 +1903,8 @@ static int node_delete_reconnect_exec(bContext *C, wmOperator *UNUSED(op))
ntreeUpdateTree(CTX_data_main(C), snode->edittree);
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ snode_notify(*C, *snode);
+ snode_dag_update(*C, *snode);
return OPERATOR_FINISHED;
}
@@ -1959,7 +1951,7 @@ static int node_output_file_add_socket_exec(bContext *C, wmOperator *op)
RNA_string_get(op->ptr, "file_path", file_path);
ntreeCompositOutputFileAddSocket(ntree, node, file_path, &scene->r.im_format);
- snode_notify(C, snode);
+ snode_notify(*C, *snode);
return OPERATOR_FINISHED;
}
@@ -2008,7 +2000,7 @@ static int node_output_file_remove_active_socket_exec(bContext *C, wmOperator *U
return OPERATOR_CANCELLED;
}
- snode_notify(C, snode);
+ snode_notify(*C, *snode);
return OPERATOR_FINISHED;
}
@@ -2075,7 +2067,7 @@ static int node_output_file_move_active_socket_exec(bContext *C, wmOperator *op)
nimf->active_input++;
}
- snode_notify(C, snode);
+ snode_notify(*C, *snode);
return OPERATOR_FINISHED;
}
@@ -2285,7 +2277,7 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op)
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
/* deselect old nodes */
- node_deselect_all(snode);
+ node_deselect_all(*snode);
/* calculate "barycenter" for placing on mouse cursor */
float center[2] = {0.0f, 0.0f};
@@ -2323,8 +2315,8 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op)
Main *bmain = CTX_data_main(C);
ntreeUpdateTree(bmain, snode->edittree);
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ snode_notify(*C, *snode);
+ snode_dag_update(*C, *snode);
/* Pasting nodes can create arbitrary new relations, because nodes can reference IDs. */
DEG_relations_tag_update(bmain);
@@ -2394,8 +2386,8 @@ static int ntree_socket_add_exec(bContext *C, wmOperator *op)
ntreeUpdateTree(CTX_data_main(C), ntree);
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ snode_notify(*C, *snode);
+ snode_dag_update(*C, *snode);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
@@ -2444,8 +2436,8 @@ static int ntree_socket_remove_exec(bContext *C, wmOperator *op)
ntreeUpdateTree(CTX_data_main(C), ntree);
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ snode_notify(*C, *snode);
+ snode_dag_update(*C, *snode);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
@@ -2507,8 +2499,8 @@ static int ntree_socket_change_type_exec(bContext *C, wmOperator *op)
ntreeUpdateTree(main, ntree);
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ snode_notify(*C, *snode);
+ snode_dag_update(*C, *snode);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
@@ -2622,8 +2614,8 @@ static int ntree_socket_move_exec(bContext *C, wmOperator *op)
ntree->update |= NTREE_UPDATE_GROUP;
ntreeUpdateTree(CTX_data_main(C), ntree);
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ snode_notify(*C, *snode);
+ snode_dag_update(*C, *snode);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
@@ -2854,7 +2846,7 @@ static int viewer_border_exec(bContext *C, wmOperator *op)
btree->flag |= NTREE_VIEWER_BORDER;
}
- snode_notify(C, snode);
+ snode_notify(*C, *snode);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
}
else {
@@ -2894,7 +2886,7 @@ static int clear_viewer_border_exec(bContext *C, wmOperator *UNUSED(op))
bNodeTree *btree = snode->nodetree;
btree->flag &= ~NTREE_VIEWER_BORDER;
- snode_notify(C, snode);
+ snode_notify(*C, *snode);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
return OPERATOR_FINISHED;
@@ -2939,7 +2931,7 @@ static int node_cryptomatte_add_socket_exec(bContext *C, wmOperator *UNUSED(op))
ntreeCompositCryptomatteAddSocket(ntree, node);
- snode_notify(C, snode);
+ snode_notify(*C, *snode);
return OPERATOR_FINISHED;
}
@@ -2985,7 +2977,7 @@ static int node_cryptomatte_remove_socket_exec(bContext *C, wmOperator *UNUSED(o
return OPERATOR_CANCELLED;
}
- snode_notify(C, snode);
+ snode_notify(*C, *snode);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_node/node_geometry_attribute_search.cc b/source/blender/editors/space_node/node_geometry_attribute_search.cc
index 79ba9b8d2d9..4890c3e39cf 100644
--- a/source/blender/editors/space_node/node_geometry_attribute_search.cc
+++ b/source/blender/editors/space_node/node_geometry_attribute_search.cc
@@ -100,13 +100,13 @@ static void attribute_search_exec_fn(bContext *C, void *data_v, void *item_v)
ED_undo_push(C, "Assign Attribute Name");
}
-void node_geometry_add_attribute_search_button(const bContext *UNUSED(C),
- const bNodeTree *node_tree,
- const bNode *node,
- PointerRNA *socket_ptr,
- uiLayout *layout)
+void node_geometry_add_attribute_search_button(const bContext &UNUSED(C),
+ const bNodeTree &node_tree,
+ const bNode &node,
+ PointerRNA &socket_ptr,
+ uiLayout &layout)
{
- uiBlock *block = uiLayoutGetBlock(layout);
+ uiBlock *block = uiLayoutGetBlock(&layout);
uiBut *but = uiDefIconTextButR(block,
UI_BTYPE_SEARCH_MENU,
0,
@@ -116,7 +116,7 @@ void node_geometry_add_attribute_search_button(const bContext *UNUSED(C),
0,
10 * UI_UNIT_X, /* Dummy value, replaced by layout system. */
UI_UNIT_Y,
- socket_ptr,
+ &socket_ptr,
"default_value",
0,
0.0f,
@@ -126,7 +126,7 @@ void node_geometry_add_attribute_search_button(const bContext *UNUSED(C),
"");
AttributeSearchData *data = OBJECT_GUARDED_NEW(
- AttributeSearchData, {node_tree, node, (bNodeSocket *)socket_ptr->data});
+ AttributeSearchData, {&node_tree, &node, (bNodeSocket *)socket_ptr.data});
UI_but_func_search_set_results_are_suggestions(but, true);
UI_but_func_search_set_sep_string(but, UI_MENU_ARROW_SEP);
diff --git a/source/blender/editors/space_node/node_group.cc b/source/blender/editors/space_node/node_group.cc
index d9fbbc81a8f..704ffe1e478 100644
--- a/source/blender/editors/space_node/node_group.cc
+++ b/source/blender/editors/space_node/node_group.cc
@@ -28,9 +28,9 @@
#include "DNA_anim_types.h"
#include "DNA_node_types.h"
+#include "BLI_float2.hh"
#include "BLI_linklist.h"
#include "BLI_listbase.h"
-#include "BLI_math.h"
#include "BLI_string.h"
#include "BLT_translation.h"
@@ -60,6 +60,8 @@
#include "NOD_socket.h"
#include "node_intern.hh" /* own include */
+using blender::float2;
+
/* -------------------------------------------------------------------- */
/** \name Local Utilities
* \{ */
@@ -417,8 +419,8 @@ static int node_group_ungroup_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ snode_notify(*C, *snode);
+ snode_dag_update(*C, *snode);
return OPERATOR_FINISHED;
}
@@ -444,24 +446,26 @@ void NODE_OT_group_ungroup(wmOperatorType *ot)
/** \name Separate Operator
* \{ */
-/* returns 1 if its OK */
-static int node_group_separate_selected(
- Main *bmain, bNodeTree *ntree, bNodeTree *ngroup, float offx, float offy, int make_copy)
+/**
+ * \return True if successful.
+ */
+static bool node_group_separate_selected(
+ Main &bmain, bNodeTree &ntree, bNodeTree &ngroup, const float2 &offset, const bool make_copy)
{
/* deselect all nodes in the target tree */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
nodeSetSelected(node, false);
}
/* clear new pointers, set in BKE_node_copy_ex(). */
- LISTBASE_FOREACH (bNode *, node, &ngroup->nodes) {
+ LISTBASE_FOREACH (bNode *, node, &ngroup.nodes) {
node->new_node = nullptr;
}
ListBase anim_basepaths = {nullptr, nullptr};
/* add selected nodes into the ntree */
- LISTBASE_FOREACH_MUTABLE (bNode *, node, &ngroup->nodes) {
+ LISTBASE_FOREACH_MUTABLE (bNode *, node, &ngroup.nodes) {
if (!(node->flag & NODE_SELECT)) {
continue;
}
@@ -475,7 +479,7 @@ static int node_group_separate_selected(
bNode *newnode;
if (make_copy) {
/* make a copy */
- newnode = BKE_node_copy_store_new_pointers(ngroup, node, LIB_ID_COPY_DEFAULT);
+ newnode = BKE_node_copy_store_new_pointers(&ngroup, node, LIB_ID_COPY_DEFAULT);
}
else {
/* use the existing node */
@@ -485,11 +489,11 @@ static int node_group_separate_selected(
/* keep track of this node's RNA "base" path (the part of the path identifying the node)
* if the old nodetree has animation data which potentially covers this node
*/
- if (ngroup->adt) {
+ if (ngroup.adt) {
PointerRNA ptr;
char *path;
- RNA_pointer_create(&ngroup->id, &RNA_Node, newnode, &ptr);
+ RNA_pointer_create(&ngroup.id, &RNA_Node, newnode, &ptr);
path = RNA_path_from_ID_to_struct(&ptr);
if (path) {
@@ -503,27 +507,27 @@ static int node_group_separate_selected(
}
/* migrate node */
- BLI_remlink(&ngroup->nodes, newnode);
- BLI_addtail(&ntree->nodes, newnode);
+ BLI_remlink(&ngroup.nodes, newnode);
+ BLI_addtail(&ntree.nodes, newnode);
/* ensure unique node name in the node tree */
- nodeUniqueName(ntree, newnode);
+ nodeUniqueName(&ntree, newnode);
if (!newnode->parent) {
- newnode->locx += offx;
- newnode->locy += offy;
+ newnode->locx += offset.x;
+ newnode->locy += offset.y;
}
}
/* add internal links to the ntree */
- LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ngroup->links) {
+ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ngroup.links) {
const bool fromselect = (link->fromnode && (link->fromnode->flag & NODE_SELECT));
const bool toselect = (link->tonode && (link->tonode->flag & NODE_SELECT));
if (make_copy) {
/* make a copy of internal links */
if (fromselect && toselect) {
- nodeAddLink(ntree,
+ nodeAddLink(&ntree,
link->fromnode->new_node,
link->fromsock->new_sock,
link->tonode->new_node,
@@ -533,20 +537,20 @@ static int node_group_separate_selected(
else {
/* move valid links over, delete broken links */
if (fromselect && toselect) {
- BLI_remlink(&ngroup->links, link);
- BLI_addtail(&ntree->links, link);
+ BLI_remlink(&ngroup.links, link);
+ BLI_addtail(&ntree.links, link);
}
else if (fromselect || toselect) {
- nodeRemLink(ngroup, link);
+ nodeRemLink(&ngroup, link);
}
}
}
/* and copy across the animation,
* note that the animation data's action can be nullptr here */
- if (ngroup->adt) {
+ if (ngroup.adt) {
/* now perform the moving */
- BKE_animdata_transfer_by_basepath(bmain, &ngroup->id, &ntree->id, &anim_basepaths);
+ BKE_animdata_transfer_by_basepath(&bmain, &ngroup.id, &ntree.id, &anim_basepaths);
/* paths + their wrappers need to be freed */
LISTBASE_FOREACH_MUTABLE (AnimationBasePathChange *, basepath_change, &anim_basepaths) {
@@ -554,12 +558,12 @@ static int node_group_separate_selected(
}
}
- ntree->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS;
+ ntree.update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS;
if (!make_copy) {
- ngroup->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS;
+ ngroup.update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS;
}
- return 1;
+ return true;
}
enum eNodeGroupSeparateType {
@@ -590,18 +594,17 @@ static int node_group_separate_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
/* get node tree offset */
- float offx, offy;
- space_node_group_offset(snode, &offx, &offy);
+ const float2 offset = space_node_group_offset(*snode);
switch (type) {
case NODE_GS_COPY:
- if (!node_group_separate_selected(bmain, nparent, ngroup, offx, offy, true)) {
+ if (!node_group_separate_selected(*bmain, *nparent, *ngroup, offset, true)) {
BKE_report(op->reports, RPT_WARNING, "Cannot separate nodes");
return OPERATOR_CANCELLED;
}
break;
case NODE_GS_MOVE:
- if (!node_group_separate_selected(bmain, nparent, ngroup, offx, offy, false)) {
+ if (!node_group_separate_selected(*bmain, *nparent, *ngroup, offset, false)) {
BKE_report(op->reports, RPT_WARNING, "Cannot separate nodes");
return OPERATOR_CANCELLED;
}
@@ -613,8 +616,8 @@ static int node_group_separate_exec(bContext *C, wmOperator *op)
ntreeUpdateTree(CTX_data_main(C), snode->nodetree);
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ snode_notify(*C, *snode);
+ snode_dag_update(*C, *snode);
return OPERATOR_FINISHED;
}
@@ -660,16 +663,16 @@ void NODE_OT_group_separate(wmOperatorType *ot)
/** \name Make Group Operator
* \{ */
-static bool node_group_make_use_node(bNode *node, bNode *gnode)
+static bool node_group_make_use_node(bNode &node, bNode *gnode)
{
- return (node != gnode && !ELEM(node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT) &&
- (node->flag & NODE_SELECT));
+ return (&node != gnode && !ELEM(node.type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT) &&
+ (node.flag & NODE_SELECT));
}
-static bool node_group_make_test_selected(bNodeTree *ntree,
+static bool node_group_make_test_selected(bNodeTree &ntree,
bNode *gnode,
const char *ntree_idname,
- struct ReportList *reports)
+ struct ReportList &reports)
{
int ok = true;
@@ -677,20 +680,20 @@ static bool node_group_make_test_selected(bNodeTree *ntree,
bNodeTree *ngroup = ntreeAddTree(nullptr, "Pseudo Node Group", ntree_idname);
/* check poll functions for selected nodes */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node_group_make_use_node(node, gnode)) {
+ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
+ if (node_group_make_use_node(*node, gnode)) {
const char *disabled_hint = nullptr;
if (node->typeinfo->poll_instance &&
!node->typeinfo->poll_instance(node, ngroup, &disabled_hint)) {
if (disabled_hint) {
- BKE_reportf(reports,
+ BKE_reportf(&reports,
RPT_WARNING,
"Can not add node '%s' in a group:\n %s",
node->name,
disabled_hint);
}
else {
- BKE_reportf(reports, RPT_WARNING, "Can not add node '%s' in a group", node->name);
+ BKE_reportf(&reports, RPT_WARNING, "Can not add node '%s' in a group", node->name);
}
ok = false;
break;
@@ -709,15 +712,15 @@ static bool node_group_make_test_selected(bNodeTree *ntree,
/* check if all connections are OK, no unselected node has both
* inputs and outputs to a selection */
- LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
- if (node_group_make_use_node(link->fromnode, gnode)) {
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
+ if (node_group_make_use_node(*link->fromnode, gnode)) {
link->tonode->done |= 1;
}
- if (node_group_make_use_node(link->tonode, gnode)) {
+ if (node_group_make_use_node(*link->tonode, gnode)) {
link->fromnode->done |= 2;
}
}
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
if (!(node->flag & NODE_SELECT) && node != gnode && node->done == 3) {
return false;
}
@@ -726,13 +729,13 @@ static bool node_group_make_test_selected(bNodeTree *ntree,
}
static int node_get_selected_minmax(
- bNodeTree *ntree, bNode *gnode, float *min, float *max, bool use_size)
+ bNodeTree &ntree, bNode *gnode, float2 &min, float2 &max, bool use_size)
{
int totselect = 0;
INIT_MINMAX2(min, max);
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node_group_make_use_node(node, gnode)) {
+ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
+ if (node_group_make_use_node(*node, gnode)) {
float loc[2];
nodeToView(node, node->offsetx, node->offsety, &loc[0], &loc[1]);
minmax_v2v2_v2(min, max, loc);
@@ -753,9 +756,9 @@ static int node_get_selected_minmax(
return totselect;
}
-static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree, bNode *gnode)
+static void node_group_make_insert_selected(const bContext &C, bNodeTree &ntree, bNode *gnode)
{
- Main *bmain = CTX_data_main(C);
+ Main *bmain = CTX_data_main(&C);
bNodeTree *ngroup = (bNodeTree *)gnode->id;
bool expose_visible = false;
@@ -768,12 +771,12 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
nodeSetSelected(node, false);
}
- float center[2], min[2], max[2];
+ float2 center, min, max;
const int totselect = node_get_selected_minmax(ntree, gnode, min, max, false);
add_v2_v2v2(center, min, max);
mul_v2_fl(center, 0.5f);
- float real_min[2], real_max[2];
+ float2 real_min, real_max;
node_get_selected_minmax(ntree, gnode, real_min, real_max, true);
/* auto-add interface for "solo" nodes */
@@ -784,16 +787,16 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
ListBase anim_basepaths = {nullptr, nullptr};
/* move nodes over */
- LISTBASE_FOREACH_MUTABLE (bNode *, node, &ntree->nodes) {
- if (node_group_make_use_node(node, gnode)) {
+ LISTBASE_FOREACH_MUTABLE (bNode *, node, &ntree.nodes) {
+ if (node_group_make_use_node(*node, gnode)) {
/* keep track of this node's RNA "base" path (the part of the pat identifying the node)
* if the old nodetree has animation data which potentially covers this node
*/
- if (ntree->adt) {
+ if (ntree.adt) {
PointerRNA ptr;
char *path;
- RNA_pointer_create(&ntree->id, &RNA_Node, node, &ptr);
+ RNA_pointer_create(&ntree.id, &RNA_Node, node, &ptr);
path = RNA_path_from_ID_to_struct(&ptr);
if (path) {
@@ -807,7 +810,7 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
}
/* change node-collection membership */
- BLI_remlink(&ntree->nodes, node);
+ BLI_remlink(&ntree.nodes, node);
BLI_addtail(&ngroup->nodes, node);
/* ensure unique node name in the ngroup */
@@ -816,8 +819,8 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
}
/* move animation data over */
- if (ntree->adt) {
- BKE_animdata_transfer_by_basepath(bmain, &ntree->id, &ngroup->id, &anim_basepaths);
+ if (ntree.adt) {
+ BKE_animdata_transfer_by_basepath(bmain, &ntree.id, &ngroup->id, &anim_basepaths);
/* paths + their wrappers need to be freed */
LISTBASE_FOREACH_MUTABLE (AnimationBasePathChange *, basepath_change, &anim_basepaths) {
@@ -829,36 +832,36 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
ntreeFreeCache(ngroup);
/* create input node */
- bNode *input_node = nodeAddStaticNode(C, ngroup, NODE_GROUP_INPUT);
+ bNode *input_node = nodeAddStaticNode(&C, ngroup, NODE_GROUP_INPUT);
input_node->locx = real_min[0] - center[0] - offsetx;
input_node->locy = -offsety;
/* create output node */
- bNode *output_node = nodeAddStaticNode(C, ngroup, NODE_GROUP_OUTPUT);
+ bNode *output_node = nodeAddStaticNode(&C, ngroup, NODE_GROUP_OUTPUT);
output_node->locx = real_max[0] - center[0] + offsetx * 0.25f;
output_node->locy = -offsety;
/* relink external sockets */
- LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) {
- int fromselect = node_group_make_use_node(link->fromnode, gnode);
- int toselect = node_group_make_use_node(link->tonode, gnode);
+ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree.links) {
+ int fromselect = node_group_make_use_node(*link->fromnode, gnode);
+ int toselect = node_group_make_use_node(*link->tonode, gnode);
if ((fromselect && link->tonode == gnode) || (toselect && link->fromnode == gnode)) {
/* remove all links to/from the gnode.
* this can remove link information, but there's no general way to preserve it.
*/
- nodeRemLink(ntree, link);
+ nodeRemLink(&ntree, link);
}
else if (toselect && !fromselect) {
bNodeSocket *link_sock;
bNode *link_node;
- node_socket_skip_reroutes(&ntree->links, link->tonode, link->tosock, &link_node, &link_sock);
+ node_socket_skip_reroutes(&ntree.links, link->tonode, link->tosock, &link_node, &link_sock);
bNodeSocket *iosock = ntreeAddSocketInterfaceFromSocket(ngroup, link_node, link_sock);
/* update the group node and interface node sockets,
* so the new interface socket can be linked.
*/
- node_group_update(ntree, gnode);
+ node_group_update(&ntree, gnode);
node_group_input_update(ngroup, input_node);
/* create new internal link */
@@ -887,13 +890,13 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
bNodeSocket *link_sock;
bNode *link_node;
node_socket_skip_reroutes(
- &ntree->links, link->fromnode, link->fromsock, &link_node, &link_sock);
+ &ntree.links, link->fromnode, link->fromsock, &link_node, &link_sock);
bNodeSocket *iosock = ntreeAddSocketInterfaceFromSocket(ngroup, link_node, link_sock);
/* update the group node and interface node sockets,
* so the new interface socket can be linked.
*/
- node_group_update(ntree, gnode);
+ node_group_update(&ntree, gnode);
node_group_output_update(ngroup, output_node);
/* create new internal link */
@@ -908,19 +911,19 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
}
/* move internal links */
- LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) {
- int fromselect = node_group_make_use_node(link->fromnode, gnode);
- int toselect = node_group_make_use_node(link->tonode, gnode);
+ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree.links) {
+ int fromselect = node_group_make_use_node(*link->fromnode, gnode);
+ int toselect = node_group_make_use_node(*link->tonode, gnode);
if (fromselect && toselect) {
- BLI_remlink(&ntree->links, link);
+ BLI_remlink(&ntree.links, link);
BLI_addtail(&ngroup->links, link);
}
}
/* move nodes in the group to the center */
LISTBASE_FOREACH (bNode *, node, &ngroup->nodes) {
- if (node_group_make_use_node(node, gnode) && !node->parent) {
+ if (node_group_make_use_node(*node, gnode) && !node->parent) {
node->locx -= center[0];
node->locy -= center[1];
}
@@ -929,7 +932,7 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
/* Expose all unlinked sockets too but only the visible ones. */
if (expose_visible) {
LISTBASE_FOREACH (bNode *, node, &ngroup->nodes) {
- if (node_group_make_use_node(node, gnode)) {
+ if (node_group_make_use_node(*node, gnode)) {
LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
bool skip = false;
LISTBASE_FOREACH (bNodeLink *, link, &ngroup->links) {
@@ -984,17 +987,17 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
/* update of the group tree */
ngroup->update |= NTREE_UPDATE | NTREE_UPDATE_LINKS;
/* update of the tree containing the group instance node */
- ntree->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS;
+ ntree.update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS;
}
-static bNode *node_group_make_from_selected(const bContext *C,
- bNodeTree *ntree,
+static bNode *node_group_make_from_selected(const bContext &C,
+ bNodeTree &ntree,
const char *ntype,
const char *ntreetype)
{
- Main *bmain = CTX_data_main(C);
+ Main *bmain = CTX_data_main(&C);
- float min[2], max[2];
+ float2 min, max;
const int totselect = node_get_selected_minmax(ntree, nullptr, min, max, false);
/* don't make empty group */
if (totselect == 0) {
@@ -1005,7 +1008,7 @@ static bNode *node_group_make_from_selected(const bContext *C,
bNodeTree *ngroup = ntreeAddTree(bmain, "NodeGroup", ntreetype);
/* make group node */
- bNode *gnode = nodeAddNode(C, ntree, ntype);
+ bNode *gnode = nodeAddNode(&C, &ntree, ntype);
gnode->id = (ID *)ngroup;
gnode->locx = 0.5f * (min[0] + max[0]);
@@ -1014,44 +1017,44 @@ static bNode *node_group_make_from_selected(const bContext *C,
node_group_make_insert_selected(C, ntree, gnode);
/* update of the tree containing the group instance node */
- ntree->update |= NTREE_UPDATE_NODES;
+ ntree.update |= NTREE_UPDATE_NODES;
return gnode;
}
static int node_group_make_exec(bContext *C, wmOperator *op)
{
- SpaceNode *snode = CTX_wm_space_node(C);
- bNodeTree *ntree = snode->edittree;
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ bNodeTree &ntree = *snode.edittree;
const char *ntree_idname = group_ntree_idname(C);
const char *node_idname = node_group_idname(C);
Main *bmain = CTX_data_main(C);
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
- if (!node_group_make_test_selected(ntree, nullptr, ntree_idname, op->reports)) {
+ if (!node_group_make_test_selected(ntree, nullptr, ntree_idname, *op->reports)) {
return OPERATOR_CANCELLED;
}
- bNode *gnode = node_group_make_from_selected(C, ntree, node_idname, ntree_idname);
+ bNode *gnode = node_group_make_from_selected(*C, ntree, node_idname, ntree_idname);
if (gnode) {
bNodeTree *ngroup = (bNodeTree *)gnode->id;
- nodeSetActive(ntree, gnode);
+ nodeSetActive(&ntree, gnode);
if (ngroup) {
- ED_node_tree_push(snode, ngroup, gnode);
+ ED_node_tree_push(&snode, ngroup, gnode);
LISTBASE_FOREACH (bNode *, node, &ngroup->nodes) {
- sort_multi_input_socket_links(snode, node, nullptr, nullptr);
+ sort_multi_input_socket_links(snode, *node, nullptr, nullptr);
}
ntreeUpdateTree(bmain, ngroup);
}
}
- ntreeUpdateTree(bmain, ntree);
+ ntreeUpdateTree(bmain, &ntree);
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ snode_notify(*C, snode);
+ snode_dag_update(*C, snode);
/* We broke relations in node tree, need to rebuild them in the graphs. */
DEG_relations_tag_update(bmain);
@@ -1096,11 +1099,11 @@ static int node_group_insert_exec(bContext *C, wmOperator *op)
}
bNodeTree *ngroup = (bNodeTree *)gnode->id;
- if (!node_group_make_test_selected(ntree, gnode, ngroup->idname, op->reports)) {
+ if (!node_group_make_test_selected(*ntree, gnode, ngroup->idname, *op->reports)) {
return OPERATOR_CANCELLED;
}
- node_group_make_insert_selected(C, ntree, gnode);
+ node_group_make_insert_selected(*C, *ntree, gnode);
nodeSetActive(ntree, gnode);
ED_node_tree_push(snode, ngroup, gnode);
@@ -1108,8 +1111,8 @@ static int node_group_insert_exec(bContext *C, wmOperator *op)
ntreeUpdateTree(bmain, ntree);
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ snode_notify(*C, *snode);
+ snode_dag_update(*C, *snode);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_node/node_intern.hh b/source/blender/editors/space_node/node_intern.hh
index 436df70429b..2e55bb0cb28 100644
--- a/source/blender/editors/space_node/node_intern.hh
+++ b/source/blender/editors/space_node/node_intern.hh
@@ -23,16 +23,14 @@
#pragma once
-#include "BKE_node.h"
-#include "UI_interface.h"
-#include "UI_view2d.h"
-
+#include "BLI_float2.hh"
#include "BLI_vector.hh"
-#include "UI_interface.hh"
-#include <stddef.h> /* for size_t */
+#include "BKE_node.h"
-/* internal exports only */
+#include "UI_interface.h"
+#include "UI_interface.hh"
+#include "UI_view2d.h"
struct ARegion;
struct ARegionType;
@@ -45,26 +43,39 @@ struct bNodeLink;
struct bNodeSocket;
struct wmGizmoGroupType;
struct wmKeyConfig;
+namespace blender {
+struct float2;
+}
struct wmWindow;
-/* temp data to pass on to modal */
+/** Temporary data used in node link drag modal operator. */
struct bNodeLinkDrag {
- struct bNodeLinkDrag *next, *prev;
-
- /* List of links dragged by the operator.
- * NOTE: This is a list of LinkData structs on top of the actual bNodeLinks.
- * This way the links can be added to the node tree while being stored in this list.
- */
- ListBase links;
+ /** Links dragged by the operator. */
+ blender::Vector<bNodeLink *> links;
bool from_multi_input_socket;
- int in_out;
+ eNodeSocketInOut in_out;
+
+ /** Draw handler for the "+" icon when dragging a link in empty space. */
+ void *draw_handle;
/** Temporarily stores the last picked link from multi-input socket operator. */
- struct bNodeLink *last_picked_multi_input_socket_link;
+ bNodeLink *last_picked_multi_input_socket_link;
+
+ /**
+ * Temporarily stores the last hovered socket for multi-input socket operator.
+ * Store it to recalculate sorting after it is no longer hovered.
+ */
+ bNode *last_node_hovered_while_dragging_a_link;
+
+ /* The cursor position, used for drawing a + icon when dragging a node link. */
+ std::array<int, 2> cursor;
- /** Temporarily stores the last hovered socket for multi-input socket operator.
- * Store it to recalculate sorting after it is no longer hovered. */
- struct bNode *last_node_hovered_while_dragging_a_link;
+ /** The node the drag started at. */
+ bNode *start_node;
+ /** The socket the drag started at. */
+ bNodeSocket *start_socket;
+ /** The number of links connected to the #start_socket when the drag started. */
+ int start_link_count;
/* Data for edge panning */
View2DEdgePanData pan_data;
@@ -74,83 +85,68 @@ struct SpaceNode_Runtime {
float aspect;
/** Mouse position for drawing socket-less links and adding nodes. */
- float cursor[2];
+ blender::float2 cursor;
/** For auto compositing. */
bool recalc;
/** Temporary data for modal linking operator. */
- struct ListBase linkdrag;
+ std::unique_ptr<bNodeLinkDrag> linkdrag;
/* XXX hack for translate_attach op-macros to pass data from transform op to insert_offset op */
/** Temporary data for node insert offset (in UI called Auto-offset). */
struct NodeInsertOfsData *iofsd;
};
-/* space_node.c */
-
-/* transform between View2Ds in the tree path */
-void space_node_group_offset(SpaceNode *snode, float *x, float *y);
-
-/* node_draw.cc */
-float node_socket_calculate_height(const bNodeSocket *socket);
-void node_link_calculate_multi_input_position(const float socket_x,
- const float socket_y,
- const int index,
- const int total_inputs,
- float r[2]);
-
-int node_get_colorid(bNode *node);
-int node_get_resize_cursor(int directions);
-void node_draw_shadow(const SpaceNode *snode, const bNode *node, float radius, float alpha);
-void node_draw_default(const bContext *C,
- ARegion *region,
- SpaceNode *snode,
- bNodeTree *ntree,
- bNode *node,
- bNodeInstanceKey key);
-void node_draw_sockets(const View2D *v2d,
- const bContext *C,
- bNodeTree *ntree,
- bNode *node,
- bool draw_outputs,
- bool select_all);
-void node_update_default(const bContext *C, bNodeTree *ntree, bNode *node);
-int node_select_area_default(bNode *node, int x, int y);
-int node_tweak_area_default(bNode *node, int x, int y);
-void node_socket_color_get(const bContext *C,
- bNodeTree *ntree,
- PointerRNA *node_ptr,
- bNodeSocket *sock,
+enum NodeResizeDirection {
+ NODE_RESIZE_NONE = 0,
+ NODE_RESIZE_TOP = (1 << 0),
+ NODE_RESIZE_BOTTOM = (1 << 1),
+ NODE_RESIZE_RIGHT = (1 << 2),
+ NODE_RESIZE_LEFT = (1 << 3),
+};
+ENUM_OPERATORS(NodeResizeDirection, NODE_RESIZE_LEFT);
+
+/**
+ * Transform between View2Ds in the tree path.
+ */
+blender::float2 space_node_group_offset(const SpaceNode &snode);
+
+float node_socket_calculate_height(const bNodeSocket &socket);
+blender::float2 node_link_calculate_multi_input_position(const blender::float2 &socket_position,
+ int index,
+ int total_inputs);
+
+int node_get_resize_cursor(NodeResizeDirection directions);
+NodeResizeDirection node_get_resize_direction(const bNode *node, const int x, const int y);
+/**
+ * Usual convention here would be #node_socket_get_color(),
+ * but that's already used (for setting a color property socket).
+ */
+void node_socket_color_get(const bContext &C,
+ const bNodeTree &ntree,
+ PointerRNA &node_ptr,
+ const bNodeSocket &sock,
float r_color[4]);
-void node_update_nodetree(const bContext *C, bNodeTree *ntree);
-void node_draw_nodetree(const bContext *C,
- ARegion *region,
- SpaceNode *snode,
- bNodeTree *ntree,
- bNodeInstanceKey parent_key);
-void node_draw_space(const bContext *C, ARegion *region);
-
-void node_set_cursor(wmWindow *win, SpaceNode *snode, float cursor[2]);
+void node_draw_space(const bContext &C, ARegion &region);
+
+void node_set_cursor(wmWindow &win, SpaceNode &snode, const blender::float2 &cursor);
/* DPI scaled coords */
-void node_to_view(const bNode *node, float x, float y, float *rx, float *ry);
-void node_to_updated_rect(const bNode *node, rctf *r_rect);
-void node_from_view(const bNode *node, float x, float y, float *rx, float *ry);
+blender::float2 node_to_view(const bNode &node, const blender::float2 &co);
+void node_to_updated_rect(const bNode &node, rctf &r_rect);
+blender::float2 node_from_view(const bNode &node, const blender::float2 &co);
-/* node_toolbar.c */
void node_toolbar_register(ARegionType *art);
-/* node_ops.c */
void node_operatortypes(void);
void node_keymap(wmKeyConfig *keyconf);
-/* node_select.c */
-void node_deselect_all(SpaceNode *snode);
-void node_socket_select(bNode *node, bNodeSocket *sock);
-void node_socket_deselect(bNode *node, bNodeSocket *sock, const bool deselect_node);
-void node_deselect_all_input_sockets(SpaceNode *snode, const bool deselect_nodes);
-void node_deselect_all_output_sockets(SpaceNode *snode, const bool deselect_nodes);
-void node_select_single(bContext *C, bNode *node);
+void node_deselect_all(SpaceNode &snode);
+void node_socket_select(bNode *node, bNodeSocket &sock);
+void node_socket_deselect(bNode *node, bNodeSocket &sock, const bool deselect_node);
+void node_deselect_all_input_sockets(SpaceNode &snode, const bool deselect_nodes);
+void node_deselect_all_output_sockets(SpaceNode &snode, const bool deselect_nodes);
+void node_select_single(bContext &C, bNode &node);
void NODE_OT_select(wmOperatorType *ot);
void NODE_OT_select_all(wmOperatorType *ot);
@@ -163,9 +159,8 @@ void NODE_OT_select_grouped(wmOperatorType *ot);
void NODE_OT_select_same_type_step(wmOperatorType *ot);
void NODE_OT_find_node(wmOperatorType *ot);
-/* node_view.c */
-int space_node_view_flag(
- bContext *C, SpaceNode *snode, ARegion *region, const int node_flag, const int smooth_viewtx);
+bool space_node_view_flag(
+ bContext &C, SpaceNode &snode, ARegion &region, int node_flag, int smooth_viewtx);
void NODE_OT_view_all(wmOperatorType *ot);
void NODE_OT_view_selected(wmOperatorType *ot);
@@ -176,37 +171,50 @@ void NODE_OT_backimage_zoom(wmOperatorType *ot);
void NODE_OT_backimage_fit(wmOperatorType *ot);
void NODE_OT_backimage_sample(wmOperatorType *ot);
-/* drawnode.c */
-void nodelink_batch_start(SpaceNode *snode);
-void nodelink_batch_end(SpaceNode *snode);
-
-void node_draw_link(const bContext *C,
- const View2D *v2d,
- const SpaceNode *snode,
- const bNodeLink *link);
-void node_draw_link_bezier(const bContext *C,
- const View2D *v2d,
- const SpaceNode *snode,
- const bNodeLink *link,
+void nodelink_batch_start(SpaceNode &snode);
+void nodelink_batch_end(SpaceNode &snode);
+
+/**
+ * \note this is used for fake links in groups too.
+ */
+void node_draw_link(const bContext &C,
+ const View2D &v2d,
+ const SpaceNode &snode,
+ const bNodeLink &link);
+/**
+ * Don't do shadows if th_col3 is -1.
+ */
+void node_draw_link_bezier(const bContext &C,
+ const View2D &v2d,
+ const SpaceNode &snode,
+ const bNodeLink &link,
int th_col1,
int th_col2,
int th_col3);
+/** If v2d not nullptr, it clips and returns 0 if not visible. */
bool node_link_bezier_points(const View2D *v2d,
const SpaceNode *snode,
- const bNodeLink *link,
+ const bNodeLink &link,
float coord_array[][2],
const int resol);
+/**
+ * Return quadratic beziers points for a given nodelink and clip if v2d is not nullptr.
+ */
bool node_link_bezier_handles(const View2D *v2d,
const SpaceNode *snode,
- const bNodeLink *link,
+ const bNodeLink &ink,
float vec[4][2]);
-void draw_nodespace_back_pix(const bContext *C,
- ARegion *region,
- SpaceNode *snode,
+void draw_nodespace_back_pix(const bContext &C,
+ ARegion &region,
+ SpaceNode &snode,
bNodeInstanceKey parent_key);
-/* node_add.c */
-bNode *node_add_node(const bContext *C, const char *idname, int type, float locx, float locy);
+/**
+ * XXX Does some additional initialization on top of #nodeAddNode
+ * Can be used with both custom and static nodes,
+ * if `idname == nullptr` the static int type will be used instead.
+ */
+bNode *node_add_node(const bContext &C, const char *idname, int type, float locx, float locy);
void NODE_OT_add_reroute(wmOperatorType *ot);
void NODE_OT_add_group(wmOperatorType *ot);
void NODE_OT_add_object(wmOperatorType *ot);
@@ -216,7 +224,6 @@ void NODE_OT_add_file(wmOperatorType *ot);
void NODE_OT_add_mask(wmOperatorType *ot);
void NODE_OT_new_node_tree(wmOperatorType *ot);
-/* node_group.c */
const char *node_group_idname(bContext *C);
void NODE_OT_group_make(wmOperatorType *ot);
void NODE_OT_group_insert(wmOperatorType *ot);
@@ -224,12 +231,11 @@ void NODE_OT_group_ungroup(wmOperatorType *ot);
void NODE_OT_group_separate(wmOperatorType *ot);
void NODE_OT_group_edit(wmOperatorType *ot);
-/* node_relationships.c */
-void sort_multi_input_socket_links(SpaceNode *snode,
- bNode *node,
+void sort_multi_input_socket_links(SpaceNode &snode,
+ bNode &node,
bNodeLink *drag_link,
- float cursor[2]);
-bool node_connected_to_output(Main *bmain, bNodeTree *ntree, bNode *node);
+ const blender::float2 *cursor);
+bool node_connected_to_output(Main &bmain, bNodeTree &ntree, bNode &node);
void NODE_OT_link(wmOperatorType *ot);
void NODE_OT_link_make(wmOperatorType *ot);
@@ -246,22 +252,27 @@ void NODE_OT_link_viewer(wmOperatorType *ot);
void NODE_OT_insert_offset(wmOperatorType *ot);
-/* node_edit.c */
-void snode_notify(bContext *C, SpaceNode *snode);
-void snode_dag_update(bContext *C, SpaceNode *snode);
-void snode_set_context(const bContext *C);
+void snode_notify(bContext &C, SpaceNode &snode);
+void snode_dag_update(bContext &C, SpaceNode &snode);
+void snode_set_context(const bContext &C);
-void snode_update(SpaceNode *snode, bNode *node);
+void snode_update(SpaceNode &snode, bNode *node);
+/** Operator poll callback. */
bool composite_node_active(bContext *C);
+/** Operator poll callback. */
bool composite_node_editable(bContext *C);
bool node_has_hidden_sockets(bNode *node);
void node_set_hidden_sockets(SpaceNode *snode, bNode *node, int set);
int node_render_changed_exec(bContext *, wmOperator *);
-bool node_find_indicated_socket(
- SpaceNode *snode, bNode **nodep, bNodeSocket **sockp, const float cursor[2], int in_out);
-float node_link_dim_factor(const View2D *v2d, const bNodeLink *link);
-bool node_link_is_hidden_or_dimmed(const View2D *v2d, const bNodeLink *link);
+/** Type is #SOCK_IN and/or #SOCK_OUT. */
+bool node_find_indicated_socket(SpaceNode &snode,
+ bNode **nodep,
+ bNodeSocket **sockp,
+ const blender::float2 &cursor,
+ eNodeSocketInOut in_out);
+float node_link_dim_factor(const View2D &v2d, const bNodeLink &link);
+bool node_link_is_hidden_or_dimmed(const View2D &v2d, const bNodeLink &link);
void NODE_OT_duplicate(wmOperatorType *ot);
void NODE_OT_delete(wmOperatorType *ot);
@@ -284,7 +295,9 @@ void NODE_OT_output_file_move_active_socket(wmOperatorType *ot);
void NODE_OT_switch_view_update(wmOperatorType *ot);
-/* NOTE: clipboard_cut is a simple macro of copy + delete. */
+/**
+ * \note clipboard_cut is a simple macro of copy + delete.
+ */
void NODE_OT_clipboard_copy(wmOperatorType *ot);
void NODE_OT_clipboard_paste(wmOperatorType *ot);
@@ -298,7 +311,6 @@ void NODE_OT_shader_script_update(wmOperatorType *ot);
void NODE_OT_viewer_border(wmOperatorType *ot);
void NODE_OT_clear_viewer_border(wmOperatorType *ot);
-/* node_widgets.c */
void NODE_GGT_backdrop_transform(wmGizmoGroupType *gzgt);
void NODE_GGT_backdrop_crop(wmGizmoGroupType *gzgt);
void NODE_GGT_backdrop_sun_beams(wmGizmoGroupType *gzgt);
@@ -307,25 +319,22 @@ void NODE_GGT_backdrop_corner_pin(wmGizmoGroupType *gzgt);
void NODE_OT_cryptomatte_layer_add(wmOperatorType *ot);
void NODE_OT_cryptomatte_layer_remove(wmOperatorType *ot);
-/* node_geometry_attribute_search.cc */
-void node_geometry_add_attribute_search_button(const bContext *C,
- const bNodeTree *node_tree,
- const bNode *node,
- PointerRNA *socket_ptr,
- uiLayout *layout);
+void node_geometry_add_attribute_search_button(const bContext &C,
+ const bNodeTree &node_tree,
+ const bNode &node,
+ PointerRNA &socket_ptr,
+ uiLayout &layout);
extern const char *node_context_dir[];
-/* XXXXXX */
-
/* Nodes draw without dpi - the view zoom is flexible. */
#define HIDDEN_RAD (0.75f * U.widget_unit)
#define BASIS_RAD (0.2f * U.widget_unit)
#define NODE_DYS (U.widget_unit / 2)
#define NODE_DY U.widget_unit
#define NODE_SOCKDY (0.1f * U.widget_unit)
-#define NODE_WIDTH(node) (node->width * UI_DPI_FAC)
-#define NODE_HEIGHT(node) (node->height * UI_DPI_FAC)
+#define NODE_WIDTH(node) (node.width * UI_DPI_FAC)
+#define NODE_HEIGHT(node) (node.height * UI_DPI_FAC)
#define NODE_MARGIN_X (1.2f * U.widget_unit)
#define NODE_SOCKSIZE (0.25f * U.widget_unit)
#define NODE_MULTI_INPUT_LINK_GAP (0.25f * U.widget_unit)
@@ -333,5 +342,12 @@ extern const char *node_context_dir[];
#define NODE_LINK_RESOL 12
namespace blender::ed::space_node {
+
Vector<ui::ContextPathItem> context_path_for_space_node(const bContext &C);
-}
+
+void invoke_node_link_drag_add_menu(bContext &C,
+ bNode &node,
+ bNodeSocket &socket,
+ const float2 &cursor);
+
+} // namespace blender::ed::space_node
diff --git a/source/blender/editors/space_node/node_ops.cc b/source/blender/editors/space_node/node_ops.cc
index 4c08f4d7b47..a6264f151e4 100644
--- a/source/blender/editors/space_node/node_ops.cc
+++ b/source/blender/editors/space_node/node_ops.cc
@@ -127,7 +127,7 @@ void node_operatortypes()
WM_operatortype_append(NODE_OT_cryptomatte_layer_remove);
}
-void ED_operatormacros_node(void)
+void ED_operatormacros_node()
{
wmOperatorType *ot;
wmOperatorTypeMacro *mot;
diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc
index ab20eaf131f..90b53258d5e 100644
--- a/source/blender/editors/space_node/node_relationships.cc
+++ b/source/blender/editors/space_node/node_relationships.cc
@@ -26,9 +26,7 @@
#include "DNA_anim_types.h"
#include "DNA_node_types.h"
-#include "BLI_blenlib.h"
#include "BLI_easing.h"
-#include "BLI_math.h"
#include "BKE_anim_data.h"
#include "BKE_context.h"
@@ -41,6 +39,7 @@
#include "ED_node.h" /* own include */
#include "ED_render.h"
#include "ED_screen.h"
+#include "ED_space_api.h"
#include "ED_spreadsheet.h"
#include "ED_util.h"
@@ -52,6 +51,9 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "GPU_state.h"
+
+#include "UI_interface_icons.h"
#include "UI_resources.h"
#include "UI_view2d.h"
@@ -59,37 +61,43 @@
#include "NOD_node_declaration.hh"
#include "NOD_node_tree_ref.hh"
+#include "NOD_socket_declarations.hh"
+#include "NOD_socket_declarations_geometry.hh"
#include "node_intern.hh" /* own include */
using namespace blender::nodes::node_tree_ref_types;
+using blender::float2;
+using blender::StringRef;
+using blender::StringRefNull;
+using blender::Vector;
/* -------------------------------------------------------------------- */
/** \name Relations Helpers
* \{ */
-static bool ntree_has_drivers(bNodeTree *ntree)
+static bool ntree_has_drivers(bNodeTree &ntree)
{
- const AnimData *adt = BKE_animdata_from_id(&ntree->id);
+ const AnimData *adt = BKE_animdata_from_id(&ntree.id);
if (adt == nullptr) {
return false;
}
return !BLI_listbase_is_empty(&adt->drivers);
}
-static bool ntree_check_nodes_connected_dfs(bNodeTree *ntree, bNode *from, bNode *to)
+static bool ntree_check_nodes_connected_dfs(bNodeTree &ntree, bNode &from, bNode &to)
{
- if (from->flag & NODE_TEST) {
+ if (from.flag & NODE_TEST) {
return false;
}
- from->flag |= NODE_TEST;
- LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
- if (link->fromnode == from) {
- if (link->tonode == to) {
+ from.flag |= NODE_TEST;
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
+ if (link->fromnode == &from) {
+ if (link->tonode == &to) {
return true;
}
- if (ntree_check_nodes_connected_dfs(ntree, link->tonode, to)) {
+ if (ntree_check_nodes_connected_dfs(ntree, *link->tonode, to)) {
return true;
}
}
@@ -97,26 +105,25 @@ static bool ntree_check_nodes_connected_dfs(bNodeTree *ntree, bNode *from, bNode
return false;
}
-static bool ntree_check_nodes_connected(bNodeTree *ntree, bNode *from, bNode *to)
+static bool ntree_check_nodes_connected(bNodeTree &ntree, bNode &from, bNode &to)
{
- if (from == to) {
+ if (&from == &to) {
return true;
}
- ntreeNodeFlagSet(ntree, NODE_TEST, false);
+ ntreeNodeFlagSet(&ntree, NODE_TEST, false);
return ntree_check_nodes_connected_dfs(ntree, from, to);
}
-static bool node_group_has_output_dfs(bNode *node)
+static bool node_group_has_output_dfs(bNode &node)
{
- bNodeTree *ntree = (bNodeTree *)node->id;
+ bNodeTree *ntree = (bNodeTree *)node.id;
if (ntree->id.tag & LIB_TAG_DOIT) {
return false;
}
ntree->id.tag |= LIB_TAG_DOIT;
- for (bNode *current_node = (bNode *)ntree->nodes.first; current_node != nullptr;
- current_node = current_node->next) {
+ LISTBASE_FOREACH (bNode *, current_node, &ntree->nodes) {
if (current_node->type == NODE_GROUP) {
- if (current_node->id && node_group_has_output_dfs(current_node)) {
+ if (current_node->id && node_group_has_output_dfs(*current_node)) {
return true;
}
}
@@ -127,18 +134,18 @@ static bool node_group_has_output_dfs(bNode *node)
return false;
}
-static bool node_group_has_output(Main *bmain, bNode *node)
+static bool node_group_has_output(Main &bmain, bNode &node)
{
- BLI_assert(ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP));
- bNodeTree *ntree = (bNodeTree *)node->id;
+ BLI_assert(ELEM(node.type, NODE_GROUP, NODE_CUSTOM_GROUP));
+ bNodeTree *ntree = (bNodeTree *)node.id;
if (ntree == nullptr) {
return false;
}
- BKE_main_id_tag_listbase(&bmain->nodetrees, LIB_TAG_DOIT, false);
+ BKE_main_id_tag_listbase(&bmain.nodetrees, LIB_TAG_DOIT, false);
return node_group_has_output_dfs(node);
}
-bool node_connected_to_output(Main *bmain, bNodeTree *ntree, bNode *node)
+bool node_connected_to_output(Main &bmain, bNodeTree &ntree, bNode &node)
{
/* Special case for drivers: if node tree has any drivers we assume it is
* always to be tagged for update when node changes. Otherwise we will be
@@ -148,7 +155,7 @@ bool node_connected_to_output(Main *bmain, bNodeTree *ntree, bNode *node)
if (ntree_has_drivers(ntree)) {
return true;
}
- LISTBASE_FOREACH (bNode *, current_node, &ntree->nodes) {
+ LISTBASE_FOREACH (bNode *, current_node, &ntree.nodes) {
/* Special case for group nodes -- if modified node connected to a group
* with active output inside we consider refresh is needed.
*
@@ -156,21 +163,21 @@ bool node_connected_to_output(Main *bmain, bNodeTree *ntree, bNode *node)
* is connected to and so eventually.
*/
if (ELEM(current_node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) {
- if (current_node->id != nullptr && ntree_has_drivers((bNodeTree *)current_node->id)) {
+ if (current_node->id != nullptr && ntree_has_drivers((bNodeTree &)current_node->id)) {
return true;
}
- if (ntree_check_nodes_connected(ntree, node, current_node) &&
- node_group_has_output(bmain, current_node)) {
+ if (ntree_check_nodes_connected(ntree, node, *current_node) &&
+ node_group_has_output(bmain, *current_node)) {
return true;
}
}
if (current_node->flag & NODE_DO_OUTPUT) {
- if (ntree_check_nodes_connected(ntree, node, current_node)) {
+ if (ntree_check_nodes_connected(ntree, node, *current_node)) {
return true;
}
}
if (current_node->type == GEO_NODE_VIEWER) {
- if (ntree_check_nodes_connected(ntree, node, current_node)) {
+ if (ntree_check_nodes_connected(ntree, node, *current_node)) {
return true;
}
}
@@ -207,49 +214,47 @@ static void clear_picking_highlight(ListBase *links)
}
}
-static LinkData *create_drag_link(Main *bmain, SpaceNode *snode, bNode *node, bNodeSocket *sock)
+static bNodeLink *create_drag_link(Main &bmain, SpaceNode &snode, bNode &node, bNodeSocket &sock)
{
- LinkData *linkdata = (LinkData *)MEM_callocN(sizeof(LinkData), "drag link op link data");
- bNodeLink *oplink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "drag link op link");
- linkdata->data = oplink;
- if (sock->in_out == SOCK_OUT) {
- oplink->fromnode = node;
- oplink->fromsock = sock;
+ bNodeLink *oplink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), __func__);
+ if (sock.in_out == SOCK_OUT) {
+ oplink->fromnode = &node;
+ oplink->fromsock = &sock;
}
else {
- oplink->tonode = node;
- oplink->tosock = sock;
+ oplink->tonode = &node;
+ oplink->tosock = &sock;
}
oplink->flag |= NODE_LINK_VALID;
oplink->flag &= ~NODE_LINK_TEST;
- if (node_connected_to_output(bmain, snode->edittree, node)) {
+ if (node_connected_to_output(bmain, *snode.edittree, node)) {
oplink->flag |= NODE_LINK_TEST;
}
oplink->flag |= NODE_LINK_DRAGGED;
- return linkdata;
+ return oplink;
}
-static void pick_link(const bContext *C,
- wmOperator *op,
- bNodeLinkDrag *nldrag,
- SpaceNode *snode,
+static void pick_link(const bContext &C,
+ wmOperator &op,
+ bNodeLinkDrag &nldrag,
+ SpaceNode &snode,
bNode *node,
- bNodeLink *link_to_pick)
+ bNodeLink &link_to_pick)
{
- clear_picking_highlight(&snode->edittree->links);
- RNA_boolean_set(op->ptr, "has_link_picked", true);
+ clear_picking_highlight(&snode.edittree->links);
+ RNA_boolean_set(op.ptr, "has_link_picked", true);
- Main *bmain = CTX_data_main(C);
- LinkData *linkdata = create_drag_link(
- bmain, snode, link_to_pick->fromnode, link_to_pick->fromsock);
+ Main *bmain = CTX_data_main(&C);
+ bNodeLink *link = create_drag_link(
+ *bmain, snode, *link_to_pick.fromnode, *link_to_pick.fromsock);
- BLI_addtail(&nldrag->links, linkdata);
- nodeRemLink(snode->edittree, link_to_pick);
+ nldrag.links.append(link);
+ nodeRemLink(snode.edittree, &link_to_pick);
- BLI_assert(nldrag->last_node_hovered_while_dragging_a_link != nullptr);
+ BLI_assert(nldrag.last_node_hovered_while_dragging_a_link != nullptr);
sort_multi_input_socket_links(
- snode, nldrag->last_node_hovered_while_dragging_a_link, nullptr, nullptr);
+ snode, *nldrag.last_node_hovered_while_dragging_a_link, nullptr, nullptr);
/* Send changed event to original link->tonode. */
if (node) {
@@ -257,20 +262,20 @@ static void pick_link(const bContext *C,
}
}
-static void pick_input_link_by_link_intersect(const bContext *C,
- wmOperator *op,
- bNodeLinkDrag *nldrag,
- const float *cursor)
+static void pick_input_link_by_link_intersect(const bContext &C,
+ wmOperator &op,
+ bNodeLinkDrag &nldrag,
+ const float2 &cursor)
{
- SpaceNode *snode = CTX_wm_space_node(C);
- const ARegion *region = CTX_wm_region(C);
+ SpaceNode *snode = CTX_wm_space_node(&C);
+ const ARegion *region = CTX_wm_region(&C);
const View2D *v2d = &region->v2d;
float drag_start[2];
- RNA_float_get_array(op->ptr, "drag_start", drag_start);
+ RNA_float_get_array(op.ptr, "drag_start", drag_start);
bNode *node;
bNodeSocket *socket;
- node_find_indicated_socket(snode, &node, &socket, drag_start, SOCK_IN);
+ node_find_indicated_socket(*snode, &node, &socket, drag_start, SOCK_IN);
/* Distance to test overlapping of cursor on link. */
const float cursor_link_touch_distance = 12.5f * UI_DPI_FAC;
@@ -283,7 +288,7 @@ static void pick_input_link_by_link_intersect(const bContext *C,
if (link->tosock == socket) {
/* Test if the cursor is near a link. */
float vec[4][2];
- node_link_bezier_handles(v2d, snode, link, vec);
+ node_link_bezier_handles(v2d, snode, *link, vec);
float data[NODE_LINK_RESOL * 2 + 2];
BKE_curve_forward_diff_bezier(
@@ -297,7 +302,7 @@ static void pick_input_link_by_link_intersect(const bContext *C,
float distance = dist_squared_to_line_segment_v2(cursor, l1, l2);
if (distance < cursor_link_touch_distance) {
link_to_pick = link;
- nldrag->last_picked_multi_input_socket_link = link_to_pick;
+ nldrag.last_picked_multi_input_socket_link = link_to_pick;
}
}
}
@@ -307,7 +312,7 @@ static void pick_input_link_by_link_intersect(const bContext *C,
* Not essential for the basic behavior, but can make interaction feel a bit better if
* the mouse moves to the right and loses the "selection." */
if (!link_to_pick) {
- bNodeLink *last_picked_link = nldrag->last_picked_multi_input_socket_link;
+ bNodeLink *last_picked_link = nldrag.last_picked_multi_input_socket_link;
if (last_picked_link) {
link_to_pick = last_picked_link;
}
@@ -316,27 +321,14 @@ static void pick_input_link_by_link_intersect(const bContext *C,
if (link_to_pick) {
/* Highlight is set here and cleared in the next iteration or if the operation finishes. */
link_to_pick->flag |= NODE_LINK_TEMP_HIGHLIGHT;
- ED_area_tag_redraw(CTX_wm_area(C));
+ ED_area_tag_redraw(CTX_wm_area(&C));
- if (!node_find_indicated_socket(snode, &node, &socket, cursor, SOCK_IN)) {
- pick_link(C, op, nldrag, snode, node, link_to_pick);
+ if (!node_find_indicated_socket(*snode, &node, &socket, cursor, SOCK_IN)) {
+ pick_link(C, op, nldrag, *snode, node, *link_to_pick);
}
}
}
-static int sort_nodes_locx(const void *a, const void *b)
-{
- const bNodeListItem *nli1 = (const bNodeListItem *)a;
- const bNodeListItem *nli2 = (const bNodeListItem *)b;
- const bNode *node1 = nli1->node;
- const bNode *node2 = nli2->node;
-
- if (node1->locx > node2->locx) {
- return 1;
- }
- return 0;
-}
-
static bool socket_is_available(bNodeTree *UNUSED(ntree), bNodeSocket *sock, const bool allow_used)
{
if (nodeSocketIsHidden(sock)) {
@@ -433,14 +425,14 @@ static bNodeSocket *best_socket_input(bNodeTree *ntree, bNode *node, int num, in
return nullptr;
}
-static bool snode_autoconnect_input(SpaceNode *snode,
+static bool snode_autoconnect_input(SpaceNode &snode,
bNode *node_fr,
bNodeSocket *sock_fr,
bNode *node_to,
bNodeSocket *sock_to,
int replace)
{
- bNodeTree *ntree = snode->edittree;
+ bNodeTree *ntree = snode.edittree;
/* then we can connect */
if (replace) {
@@ -452,105 +444,75 @@ static bool snode_autoconnect_input(SpaceNode *snode,
}
struct LinkAndPosition {
- struct bNodeLink *link;
- float multi_socket_position[2];
+ bNodeLink *link;
+ float2 multi_socket_position;
};
-static int compare_link_by_y_position(const void *a, const void *b)
-{
- const LinkAndPosition *link_and_position_a = *(const LinkAndPosition **)a;
- const LinkAndPosition *link_and_position_b = *(const LinkAndPosition **)b;
-
- BLI_assert(link_and_position_a->link->tosock == link_and_position_b->link->tosock);
- const float link_a_y = link_and_position_a->multi_socket_position[1];
- const float link_b_y = link_and_position_b->multi_socket_position[1];
- return link_a_y > link_b_y ? 1 : -1;
-}
-
-void sort_multi_input_socket_links(SpaceNode *snode,
- bNode *node,
+void sort_multi_input_socket_links(SpaceNode &snode,
+ bNode &node,
bNodeLink *drag_link,
- float cursor[2])
+ const float2 *cursor)
{
- LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node.inputs) {
if (!(socket->flag & SOCK_MULTI_INPUT)) {
continue;
}
- /* The total is calculated in #node_update_nodetree, which runs before this draw step. */
- int total_inputs = socket->total_inputs + 1;
- struct LinkAndPosition **input_links = (LinkAndPosition **)MEM_malloc_arrayN(
- total_inputs, sizeof(LinkAndPosition *), __func__);
+ Vector<LinkAndPosition, 8> links;
- int index = 0;
- LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) {
+ LISTBASE_FOREACH (bNodeLink *, link, &snode.edittree->links) {
if (link->tosock == socket) {
- struct LinkAndPosition *link_and_position = (LinkAndPosition *)MEM_callocN(
- sizeof(struct LinkAndPosition), __func__);
- link_and_position->link = link;
- node_link_calculate_multi_input_position(link->tosock->locx,
- link->tosock->locy,
- link->multi_input_socket_index,
- link->tosock->total_inputs,
- link_and_position->multi_socket_position);
- input_links[index] = link_and_position;
- index++;
+ links.append(
+ {link,
+ node_link_calculate_multi_input_position({link->tosock->locx, link->tosock->locy},
+ link->multi_input_socket_index,
+ link->tosock->total_inputs)});
}
}
if (drag_link) {
- LinkAndPosition *link_and_position = (LinkAndPosition *)MEM_callocN(sizeof(LinkAndPosition),
- __func__);
- link_and_position->link = drag_link;
- copy_v2_v2(link_and_position->multi_socket_position, cursor);
- input_links[index] = link_and_position;
- index++;
+ LinkAndPosition link_and_position{};
+ link_and_position.link = drag_link;
+ if (cursor) {
+ link_and_position.multi_socket_position = *cursor;
+ }
+ links.append(link_and_position);
}
- qsort(input_links, index, sizeof(bNodeLink *), compare_link_by_y_position);
+ std::sort(links.begin(), links.end(), [](const LinkAndPosition a, const LinkAndPosition b) {
+ return a.multi_socket_position.y < b.multi_socket_position.y;
+ });
- for (int i = 0; i < index; i++) {
- input_links[i]->link->multi_input_socket_index = i;
+ for (const int i : links.index_range()) {
+ links[i].link->multi_input_socket_index = i;
}
-
- for (int i = 0; i < index; i++) {
- if (input_links[i]) {
- MEM_freeN(input_links[i]);
- }
- }
- MEM_freeN(input_links);
}
}
-static void snode_autoconnect(Main *bmain,
- SpaceNode *snode,
+static void snode_autoconnect(Main &bmain,
+ SpaceNode &snode,
const bool allow_multiple,
const bool replace)
{
- bNodeTree *ntree = snode->edittree;
- ListBase *nodelist = (ListBase *)MEM_callocN(sizeof(ListBase), "items_list");
+ bNodeTree *ntree = snode.edittree;
+ Vector<bNode *> sorted_nodes;
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->flag & NODE_SELECT) {
- bNodeListItem *nli = (bNodeListItem *)MEM_mallocN(sizeof(bNodeListItem),
- "temporary node list item");
- nli->node = node;
- BLI_addtail(nodelist, nli);
+ sorted_nodes.append(node);
}
}
- /* sort nodes left to right */
- BLI_listbase_sort(nodelist, sort_nodes_locx);
+ /* Sort nodes left to right. */
+ std::sort(sorted_nodes.begin(), sorted_nodes.end(), [](const bNode *a, const bNode *b) {
+ return a->locx < b->locx;
+ });
int numlinks = 0;
- LISTBASE_FOREACH (bNodeListItem *, nli, nodelist) {
+ for (const int i : sorted_nodes.as_mutable_span().drop_back(1).index_range()) {
bool has_selected_inputs = false;
- if (nli->next == nullptr) {
- break;
- }
-
- bNode *node_fr = nli->node;
- bNode *node_to = nli->next->node;
+ bNode *node_fr = sorted_nodes[i];
+ bNode *node_to = sorted_nodes[i + 1];
/* corner case: input/output node aligned the wrong way around (T47729) */
if (BLI_listbase_is_empty(&node_to->inputs) || BLI_listbase_is_empty(&node_fr->outputs)) {
SWAP(bNode *, node_fr, node_to);
@@ -604,11 +566,8 @@ static void snode_autoconnect(Main *bmain,
}
if (numlinks > 0) {
- ntreeUpdateTree(bmain, ntree);
+ ntreeUpdateTree(&bmain, ntree);
}
-
- BLI_freelistN(nodelist);
- MEM_freeN(nodelist);
}
/** \} */
@@ -662,26 +621,26 @@ static CustomDataType socket_type_to_custom_data_type(const eNodeSocketDatatype
/**
* Find the socket to link to in a viewer node.
*/
-static bNodeSocket *node_link_viewer_get_socket(bNodeTree *ntree,
- bNode *viewer_node,
- bNodeSocket *src_socket)
+static bNodeSocket *node_link_viewer_get_socket(bNodeTree &ntree,
+ bNode &viewer_node,
+ bNodeSocket &src_socket)
{
- if (viewer_node->type != GEO_NODE_VIEWER) {
+ if (viewer_node.type != GEO_NODE_VIEWER) {
/* In viewer nodes in the compositor, only the first input should be linked to. */
- return (bNodeSocket *)viewer_node->inputs.first;
+ return (bNodeSocket *)viewer_node.inputs.first;
}
/* For the geometry nodes viewer, find the socket with the correct type. */
- LISTBASE_FOREACH (bNodeSocket *, viewer_socket, &viewer_node->inputs) {
- if (viewer_socket->type == src_socket->type) {
+ LISTBASE_FOREACH (bNodeSocket *, viewer_socket, &viewer_node.inputs) {
+ if (viewer_socket->type == src_socket.type) {
if (viewer_socket->type == SOCK_GEOMETRY) {
return viewer_socket;
}
- NodeGeometryViewer *storage = (NodeGeometryViewer *)viewer_node->storage;
+ NodeGeometryViewer *storage = (NodeGeometryViewer *)viewer_node.storage;
const CustomDataType data_type = socket_type_to_custom_data_type(
- (eNodeSocketDatatype)src_socket->type);
+ (eNodeSocketDatatype)src_socket.type);
BLI_assert(data_type != CD_AUTO_FROM_NAME);
storage->data_type = data_type;
- nodeUpdate(ntree, viewer_node);
+ nodeUpdate(&ntree, &viewer_node);
return viewer_socket;
}
}
@@ -814,31 +773,31 @@ static const OutputSocketRef *find_output_socket_to_be_viewed(const NodeRef *act
return nullptr;
}
-static int link_socket_to_viewer(const bContext *C,
+static int link_socket_to_viewer(const bContext &C,
bNode *viewer_bnode,
- bNode *bnode_to_view,
- bNodeSocket *bsocket_to_view)
+ bNode &bnode_to_view,
+ bNodeSocket &bsocket_to_view)
{
- SpaceNode *snode = CTX_wm_space_node(C);
- bNodeTree *btree = snode->edittree;
+ SpaceNode &snode = *CTX_wm_space_node(&C);
+ bNodeTree &btree = *snode.edittree;
if (viewer_bnode == nullptr) {
/* Create a new viewer node if none exists. */
- const int viewer_type = get_default_viewer_type(C);
+ const int viewer_type = get_default_viewer_type(&C);
viewer_bnode = node_add_node(
- C, nullptr, viewer_type, bsocket_to_view->locx + 100, bsocket_to_view->locy);
+ C, nullptr, viewer_type, bsocket_to_view.locx + 100, bsocket_to_view.locy);
if (viewer_bnode == nullptr) {
return OPERATOR_CANCELLED;
}
}
- bNodeSocket *viewer_bsocket = node_link_viewer_get_socket(btree, viewer_bnode, bsocket_to_view);
+ bNodeSocket *viewer_bsocket = node_link_viewer_get_socket(btree, *viewer_bnode, bsocket_to_view);
if (viewer_bsocket == nullptr) {
return OPERATOR_CANCELLED;
}
bNodeLink *link_to_change = nullptr;
- LISTBASE_FOREACH (bNodeLink *, link, &btree->links) {
+ LISTBASE_FOREACH (bNodeLink *, link, &btree.links) {
if (link->tosock == viewer_bsocket) {
link_to_change = link;
break;
@@ -846,38 +805,34 @@ static int link_socket_to_viewer(const bContext *C,
}
if (link_to_change == nullptr) {
- nodeAddLink(btree, bnode_to_view, bsocket_to_view, viewer_bnode, viewer_bsocket);
+ nodeAddLink(&btree, &bnode_to_view, &bsocket_to_view, viewer_bnode, viewer_bsocket);
}
else {
- link_to_change->fromnode = bnode_to_view;
- link_to_change->fromsock = bsocket_to_view;
- btree->update |= NTREE_UPDATE_LINKS;
+ link_to_change->fromnode = &bnode_to_view;
+ link_to_change->fromsock = &bsocket_to_view;
+ btree.update |= NTREE_UPDATE_LINKS;
}
- remove_links_to_unavailable_viewer_sockets(*btree, *viewer_bnode);
+ remove_links_to_unavailable_viewer_sockets(btree, *viewer_bnode);
- if (btree->type == NTREE_GEOMETRY) {
- ED_spreadsheet_context_paths_set_geometry_node(CTX_data_main(C), snode, viewer_bnode);
+ if (btree.type == NTREE_GEOMETRY) {
+ ED_spreadsheet_context_paths_set_geometry_node(CTX_data_main(&C), &snode, viewer_bnode);
}
- ntreeUpdateTree(CTX_data_main(C), btree);
+ ntreeUpdateTree(CTX_data_main(&C), &btree);
snode_update(snode, viewer_bnode);
- DEG_id_tag_update(&btree->id, 0);
+ DEG_id_tag_update(&btree.id, 0);
return OPERATOR_FINISHED;
}
-static int node_link_viewer(const bContext *C, bNode *bnode_to_view)
+static int node_link_viewer(const bContext &C, bNode &bnode_to_view)
{
- if (bnode_to_view == nullptr) {
- return OPERATOR_CANCELLED;
- }
-
- SpaceNode *snode = CTX_wm_space_node(C);
- bNodeTree *btree = snode->edittree;
+ SpaceNode &snode = *CTX_wm_space_node(&C);
+ bNodeTree *btree = snode.edittree;
const NodeTreeRef tree{btree};
- const NodeRef &node_to_view = *tree.find_node(*bnode_to_view);
+ const NodeRef &node_to_view = *tree.find_node(bnode_to_view);
const NodeRef *active_viewer_node = get_existing_viewer(tree);
const OutputSocketRef *socket_to_view = find_output_socket_to_be_viewed(active_viewer_node,
@@ -886,7 +841,7 @@ static int node_link_viewer(const bContext *C, bNode *bnode_to_view)
return OPERATOR_FINISHED;
}
- bNodeSocket *bsocket_to_view = socket_to_view->bsocket();
+ bNodeSocket &bsocket_to_view = *socket_to_view->bsocket();
bNode *viewer_bnode = active_viewer_node ? active_viewer_node->bnode() : nullptr;
return link_socket_to_viewer(C, viewer_bnode, bnode_to_view, bsocket_to_view);
}
@@ -895,8 +850,8 @@ static int node_link_viewer(const bContext *C, bNode *bnode_to_view)
static int node_active_link_viewer_exec(bContext *C, wmOperator *UNUSED(op))
{
- SpaceNode *snode = CTX_wm_space_node(C);
- bNode *node = nodeGetActive(snode->edittree);
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ bNode *node = nodeGetActive(snode.edittree);
if (!node) {
return OPERATOR_CANCELLED;
@@ -904,11 +859,11 @@ static int node_active_link_viewer_exec(bContext *C, wmOperator *UNUSED(op))
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
- if (blender::ed::nodes::viewer_linking::node_link_viewer(C, node) == OPERATOR_CANCELLED) {
+ if (blender::ed::nodes::viewer_linking::node_link_viewer(*C, *node) == OPERATOR_CANCELLED) {
return OPERATOR_CANCELLED;
}
- snode_notify(C, snode);
+ snode_notify(*C, snode);
return OPERATOR_FINISHED;
}
@@ -943,6 +898,83 @@ void NODE_OT_link_viewer(wmOperatorType *ot)
/** \name Add Link Operator
* \{ */
+/**
+ * Check if any of the dragged links are connected to a socket on the side that they are dragged
+ * from.
+ */
+static bool dragged_links_are_detached(const bNodeLinkDrag &nldrag)
+{
+ if (nldrag.in_out == SOCK_OUT) {
+ for (const bNodeLink *link : nldrag.links) {
+ if (link->tonode && link->tosock) {
+ return false;
+ }
+ }
+ }
+ else {
+ for (const bNodeLink *link : nldrag.links) {
+ if (link->fromnode && link->fromsock) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+static bool should_create_drag_link_search_menu(const bNodeTree &node_tree,
+ const bNodeLinkDrag &nldrag)
+{
+ /* Custom node trees aren't supported yet. */
+ if (node_tree.type == NTREE_CUSTOM) {
+ return false;
+ }
+ /* Only create the search menu when the drag has not already connected the links to a socket. */
+ if (!dragged_links_are_detached(nldrag)) {
+ return false;
+ }
+ /* Don't create the search menu if the drag is disconnecting a link from an input node. */
+ if (nldrag.start_socket->in_out == SOCK_IN && nldrag.start_link_count > 0) {
+ return false;
+ }
+ /* Don't allow a drag from the "new socket" of a group input node. Handling these
+ * properly in node callbacks increases the complexity too much for now. */
+ if (ELEM(nldrag.start_node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) {
+ if (nldrag.start_socket->type == SOCK_CUSTOM) {
+ return false;
+ }
+ }
+ return true;
+}
+
+static void draw_draglink_tooltip(const bContext *UNUSED(C), ARegion *UNUSED(region), void *arg)
+{
+ bNodeLinkDrag *nldrag = static_cast<bNodeLinkDrag *>(arg);
+
+ const uchar text_col[4] = {255, 255, 255, 255};
+ const int padding = 4 * UI_DPI_FAC;
+ const float x = nldrag->in_out == SOCK_IN ? nldrag->cursor[0] - 3.3f * padding :
+ nldrag->cursor[0];
+ const float y = nldrag->cursor[1] - 2.0f * UI_DPI_FAC;
+
+ UI_icon_draw_ex(x, y, ICON_ADD, U.inv_dpi_fac, 1.0f, 0.0f, text_col, false);
+}
+
+static void draw_draglink_tooltip_activate(const ARegion &region, bNodeLinkDrag &nldrag)
+{
+ if (nldrag.draw_handle == nullptr) {
+ nldrag.draw_handle = ED_region_draw_cb_activate(
+ region.type, draw_draglink_tooltip, &nldrag, REGION_DRAW_POST_PIXEL);
+ }
+}
+
+static void draw_draglink_tooltip_deactivate(const ARegion &region, bNodeLinkDrag &nldrag)
+{
+ if (nldrag.draw_handle) {
+ ED_region_draw_cb_exit(region.type, nldrag.draw_handle);
+ nldrag.draw_handle = nullptr;
+ }
+}
+
static void node_link_update_header(bContext *C, bNodeLinkDrag *UNUSED(nldrag))
{
char header[UI_MAX_DRAW_STR];
@@ -951,48 +983,49 @@ static void node_link_update_header(bContext *C, bNodeLinkDrag *UNUSED(nldrag))
ED_workspace_status_text(C, header);
}
-static int node_count_links(const bNodeTree *ntree, const bNodeSocket *socket)
+static int node_count_links(const bNodeTree &ntree, const bNodeSocket &socket)
{
int count = 0;
- LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
- if (ELEM(socket, link->fromsock, link->tosock)) {
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
+ if (ELEM(&socket, link->fromsock, link->tosock)) {
count++;
}
}
return count;
}
-static void node_remove_extra_links(SpaceNode *snode, bNodeLink *link)
+static void node_remove_extra_links(SpaceNode &snode, bNodeLink &link)
{
- bNodeTree *ntree = snode->edittree;
- bNodeSocket *from = link->fromsock, *to = link->tosock;
+ bNodeTree &ntree = *snode.edittree;
+ bNodeSocket &from = *link.fromsock;
+ bNodeSocket &to = *link.tosock;
int to_count = node_count_links(ntree, to);
int from_count = node_count_links(ntree, from);
- int to_link_limit = nodeSocketLinkLimit(to);
- int from_link_limit = nodeSocketLinkLimit(from);
+ int to_link_limit = nodeSocketLinkLimit(&to);
+ int from_link_limit = nodeSocketLinkLimit(&from);
- LISTBASE_FOREACH_MUTABLE (bNodeLink *, tlink, &ntree->links) {
- if (tlink == link) {
+ LISTBASE_FOREACH_MUTABLE (bNodeLink *, tlink, &ntree.links) {
+ if (tlink == &link) {
continue;
}
- if (tlink && tlink->fromsock == from) {
+ if (tlink && tlink->fromsock == &from) {
if (from_count > from_link_limit) {
- nodeRemLink(ntree, tlink);
+ nodeRemLink(&ntree, tlink);
tlink = nullptr;
from_count--;
}
}
- if (tlink && tlink->tosock == to) {
+ if (tlink && tlink->tosock == &to) {
if (to_count > to_link_limit) {
- nodeRemLink(ntree, tlink);
+ nodeRemLink(&ntree, tlink);
tlink = nullptr;
to_count--;
}
- else if (tlink->fromsock == from) {
+ else if (tlink->fromsock == &from) {
/* Also remove link if it comes from the same output. */
- nodeRemLink(ntree, tlink);
+ nodeRemLink(&ntree, tlink);
tlink = nullptr;
to_count--;
from_count--;
@@ -1001,21 +1034,18 @@ static void node_remove_extra_links(SpaceNode *snode, bNodeLink *link)
}
}
-static void node_link_exit(bContext *C, wmOperator *op, bool apply_links)
+static void node_link_exit(bContext &C, wmOperator &op, const bool apply_links)
{
- Main *bmain = CTX_data_main(C);
- SpaceNode *snode = CTX_wm_space_node(C);
- bNodeTree *ntree = snode->edittree;
- bNodeLinkDrag *nldrag = (bNodeLinkDrag *)op->customdata;
+ Main *bmain = CTX_data_main(&C);
+ ARegion &region = *CTX_wm_region(&C);
+ SpaceNode &snode = *CTX_wm_space_node(&C);
+ bNodeTree &ntree = *snode.edittree;
+ bNodeLinkDrag *nldrag = (bNodeLinkDrag *)op.customdata;
bool do_tag_update = false;
- /* View will be reset if no links connect. */
- bool reset_view = true;
/* avoid updates while applying links */
- ntree->is_updating = true;
- LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) {
- bNodeLink *link = (bNodeLink *)linkdata->data;
-
+ ntree.is_updating = true;
+ for (bNodeLink *link : nldrag->links) {
/* See note below, but basically TEST flag means that the link
* was connected to output (or to a node which affects the
* output).
@@ -1029,63 +1059,59 @@ static void node_link_exit(bContext *C, wmOperator *op, bool apply_links)
* let nodes perform special link insertion handling
*/
if (link->fromnode->typeinfo->insert_link) {
- link->fromnode->typeinfo->insert_link(ntree, link->fromnode, link);
+ link->fromnode->typeinfo->insert_link(&ntree, link->fromnode, link);
}
if (link->tonode->typeinfo->insert_link) {
- link->tonode->typeinfo->insert_link(ntree, link->tonode, link);
+ link->tonode->typeinfo->insert_link(&ntree, link->tonode, link);
}
/* add link to the node tree */
- BLI_addtail(&ntree->links, link);
+ BLI_addtail(&ntree.links, link);
- ntree->update |= NTREE_UPDATE_LINKS;
+ ntree.update |= NTREE_UPDATE_LINKS;
/* tag tonode for update */
link->tonode->update |= NODE_UPDATE;
/* we might need to remove a link */
- node_remove_extra_links(snode, link);
+ node_remove_extra_links(snode, *link);
if (link->tonode) {
- do_tag_update |= (do_tag_update || node_connected_to_output(bmain, ntree, link->tonode));
+ do_tag_update |= (do_tag_update || node_connected_to_output(*bmain, ntree, *link->tonode));
}
-
- reset_view = false;
}
else {
- nodeRemLink(ntree, link);
+ nodeRemLink(&ntree, link);
}
}
- ntree->is_updating = false;
+ ntree.is_updating = false;
- ntreeUpdateTree(bmain, ntree);
+ ntreeUpdateTree(bmain, &ntree);
snode_notify(C, snode);
if (do_tag_update) {
snode_dag_update(C, snode);
}
- if (reset_view) {
- UI_view2d_edge_pan_cancel(C, &nldrag->pan_data);
- }
+ /* Ensure draglink tooltip is disabled. */
+ draw_draglink_tooltip_deactivate(*CTX_wm_region(&C), *nldrag);
+
+ ED_workspace_status_text(&C, nullptr);
+ ED_region_tag_redraw(&region);
+ clear_picking_highlight(&snode.edittree->links);
- BLI_remlink(&snode->runtime->linkdrag, nldrag);
- /* links->data pointers are either held by the tree or freed already */
- BLI_freelistN(&nldrag->links);
- MEM_freeN(nldrag);
+ snode.runtime->linkdrag.reset();
}
-static void node_link_find_socket(bContext *C, wmOperator *op, float cursor[2])
+static void node_link_find_socket(bContext &C, wmOperator &op, const float2 &cursor)
{
- SpaceNode *snode = CTX_wm_space_node(C);
- bNodeLinkDrag *nldrag = (bNodeLinkDrag *)op->customdata;
+ SpaceNode &snode = *CTX_wm_space_node(&C);
+ bNodeLinkDrag *nldrag = (bNodeLinkDrag *)op.customdata;
if (nldrag->in_out == SOCK_OUT) {
bNode *tnode;
bNodeSocket *tsock = nullptr;
if (node_find_indicated_socket(snode, &tnode, &tsock, cursor, SOCK_IN)) {
- LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) {
- bNodeLink *link = (bNodeLink *)linkdata->data;
-
+ for (bNodeLink *link : nldrag->links) {
/* skip if socket is on the same node as the fromsock */
if (tnode && link->fromnode == tnode) {
continue;
@@ -1093,7 +1119,7 @@ static void node_link_find_socket(bContext *C, wmOperator *op, float cursor[2])
/* Skip if tsock is already linked with this output. */
bNodeLink *existing_link_connected_to_fromsock = nullptr;
- LISTBASE_FOREACH (bNodeLink *, existing_link, &snode->edittree->links) {
+ LISTBASE_FOREACH (bNodeLink *, existing_link, &snode.edittree->links) {
if (existing_link->fromsock == link->fromsock && existing_link->tosock == tsock) {
existing_link_connected_to_fromsock = existing_link;
break;
@@ -1110,16 +1136,15 @@ static void node_link_find_socket(bContext *C, wmOperator *op, float cursor[2])
continue;
}
if (link->tosock && link->tosock->flag & SOCK_MULTI_INPUT) {
- sort_multi_input_socket_links(snode, tnode, link, cursor);
+ sort_multi_input_socket_links(snode, *tnode, link, &cursor);
}
}
}
else {
- LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) {
- bNodeLink *link = (bNodeLink *)linkdata->data;
+ for (bNodeLink *link : nldrag->links) {
if (nldrag->last_node_hovered_while_dragging_a_link) {
sort_multi_input_socket_links(
- snode, nldrag->last_node_hovered_while_dragging_a_link, nullptr, cursor);
+ snode, *nldrag->last_node_hovered_while_dragging_a_link, nullptr, &cursor);
}
link->tonode = nullptr;
link->tosock = nullptr;
@@ -1130,9 +1155,7 @@ static void node_link_find_socket(bContext *C, wmOperator *op, float cursor[2])
bNode *tnode;
bNodeSocket *tsock = nullptr;
if (node_find_indicated_socket(snode, &tnode, &tsock, cursor, SOCK_OUT)) {
- LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) {
- bNodeLink *link = (bNodeLink *)linkdata->data;
-
+ for (bNodeLink *link : nldrag->links) {
/* skip if this is already the target socket */
if (link->fromsock == tsock) {
continue;
@@ -1148,9 +1171,7 @@ static void node_link_find_socket(bContext *C, wmOperator *op, float cursor[2])
}
}
else {
- LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) {
- bNodeLink *link = (bNodeLink *)linkdata->data;
-
+ for (bNodeLink *link : nldrag->links) {
link->fromnode = nullptr;
link->fromsock = nullptr;
}
@@ -1163,67 +1184,93 @@ static void node_link_find_socket(bContext *C, wmOperator *op, float cursor[2])
static int node_link_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
bNodeLinkDrag *nldrag = (bNodeLinkDrag *)op->customdata;
+ SpaceNode &snode = *CTX_wm_space_node(C);
ARegion *region = CTX_wm_region(C);
- float cursor[2];
UI_view2d_edge_pan_apply_event(C, &nldrag->pan_data, event);
- UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &cursor[0], &cursor[1]);
+ float2 cursor;
+ UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &cursor.x, &cursor.y);
+ nldrag->cursor[0] = event->mval[0];
+ nldrag->cursor[1] = event->mval[1];
switch (event->type) {
case MOUSEMOVE:
if (nldrag->from_multi_input_socket && !RNA_boolean_get(op->ptr, "has_link_picked")) {
- pick_input_link_by_link_intersect(C, op, nldrag, cursor);
+ pick_input_link_by_link_intersect(*C, *op, *nldrag, cursor);
}
else {
- node_link_find_socket(C, op, cursor);
+ node_link_find_socket(*C, *op, cursor);
node_link_update_header(C, nldrag);
ED_region_tag_redraw(region);
}
- break;
+ if (should_create_drag_link_search_menu(*snode.edittree, *nldrag)) {
+ draw_draglink_tooltip_activate(*region, *nldrag);
+ }
+ else {
+ draw_draglink_tooltip_deactivate(*region, *nldrag);
+ }
+ break;
case LEFTMOUSE:
+ if (event->val == KM_RELEASE) {
+ /* Add a search menu for compatible sockets if the drag released on empty space. */
+ if (should_create_drag_link_search_menu(*snode.edittree, *nldrag)) {
+ bNodeLink &link = *nldrag->links.first();
+ if (nldrag->in_out == SOCK_OUT) {
+ blender::ed::space_node::invoke_node_link_drag_add_menu(
+ *C, *link.fromnode, *link.fromsock, cursor);
+ }
+ else {
+ blender::ed::space_node::invoke_node_link_drag_add_menu(
+ *C, *link.tonode, *link.tosock, cursor);
+ }
+ }
+
+ /* Finish link. */
+ node_link_exit(*C, *op, true);
+ return OPERATOR_FINISHED;
+ }
+ break;
case RIGHTMOUSE:
case MIDDLEMOUSE: {
if (event->val == KM_RELEASE) {
- node_link_exit(C, op, true);
-
- ED_workspace_status_text(C, nullptr);
- ED_region_tag_redraw(region);
- SpaceNode *snode = CTX_wm_space_node(C);
- clear_picking_highlight(&snode->edittree->links);
+ node_link_exit(*C, *op, true);
return OPERATOR_FINISHED;
}
break;
}
+ case EVT_ESCKEY: {
+ node_link_exit(*C, *op, true);
+ return OPERATOR_FINISHED;
+ }
}
return OPERATOR_RUNNING_MODAL;
}
-/* return 1 when socket clicked */
-static bNodeLinkDrag *node_link_init(Main *bmain, SpaceNode *snode, float cursor[2], bool detach)
+static std::unique_ptr<bNodeLinkDrag> node_link_init(Main &bmain,
+ SpaceNode &snode,
+ float2 cursor,
+ const bool detach)
{
- bNodeLinkDrag *nldrag = nullptr;
-
/* output indicated? */
bNode *node;
bNodeSocket *sock;
if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_OUT)) {
- nldrag = (bNodeLinkDrag *)MEM_callocN(sizeof(bNodeLinkDrag), "drag link op customdata");
-
- const int num_links = nodeCountSocketLinks(snode->edittree, sock);
+ std::unique_ptr<bNodeLinkDrag> nldrag = std::make_unique<bNodeLinkDrag>();
+ nldrag->start_node = node;
+ nldrag->start_socket = sock;
+ nldrag->start_link_count = nodeCountSocketLinks(snode.edittree, sock);
int link_limit = nodeSocketLinkLimit(sock);
- if (num_links > 0 && (num_links >= link_limit || detach)) {
+ if (nldrag->start_link_count > 0 && (nldrag->start_link_count >= link_limit || detach)) {
/* dragged links are fixed on input side */
nldrag->in_out = SOCK_IN;
/* detach current links and store them in the operator data */
- LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &snode->edittree->links) {
+ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &snode.edittree->links) {
if (link->fromsock == sock) {
- LinkData *linkdata = (LinkData *)MEM_callocN(sizeof(LinkData), "drag link op link data");
bNodeLink *oplink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "drag link op link");
- linkdata->data = oplink;
*oplink = *link;
oplink->next = oplink->prev = nullptr;
oplink->flag |= NODE_LINK_VALID;
@@ -1236,12 +1283,12 @@ static bNodeLinkDrag *node_link_init(Main *bmain, SpaceNode *snode, float cursor
* using TEST flag.
*/
oplink->flag &= ~NODE_LINK_TEST;
- if (node_connected_to_output(bmain, snode->edittree, link->tonode)) {
+ if (node_connected_to_output(bmain, *snode.edittree, *link->tonode)) {
oplink->flag |= NODE_LINK_TEST;
}
- BLI_addtail(&nldrag->links, linkdata);
- nodeRemLink(snode->edittree, link);
+ nldrag->links.append(oplink);
+ nodeRemLink(snode.edittree, link);
}
}
}
@@ -1249,23 +1296,25 @@ static bNodeLinkDrag *node_link_init(Main *bmain, SpaceNode *snode, float cursor
/* dragged links are fixed on output side */
nldrag->in_out = SOCK_OUT;
/* create a new link */
- LinkData *linkdata = create_drag_link(bmain, snode, node, sock);
-
- BLI_addtail(&nldrag->links, linkdata);
+ nldrag->links.append(create_drag_link(bmain, snode, *node, *sock));
}
+ return nldrag;
}
+
/* or an input? */
- else if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_IN)) {
- nldrag = (bNodeLinkDrag *)MEM_callocN(sizeof(bNodeLinkDrag), "drag link op customdata");
+ if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_IN)) {
+ std::unique_ptr<bNodeLinkDrag> nldrag = std::make_unique<bNodeLinkDrag>();
nldrag->last_node_hovered_while_dragging_a_link = node;
+ nldrag->start_node = node;
+ nldrag->start_socket = sock;
- const int num_links = nodeCountSocketLinks(snode->edittree, sock);
- if (num_links > 0) {
+ nldrag->start_link_count = nodeCountSocketLinks(snode.edittree, sock);
+ if (nldrag->start_link_count > 0) {
/* dragged links are fixed on output side */
nldrag->in_out = SOCK_OUT;
/* detach current links and store them in the operator data */
bNodeLink *link_to_pick;
- LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &snode->edittree->links) {
+ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &snode.edittree->links) {
if (link->tosock == sock) {
if (sock->flag & SOCK_MULTI_INPUT) {
nldrag->from_multi_input_socket = true;
@@ -1275,20 +1324,18 @@ static bNodeLinkDrag *node_link_init(Main *bmain, SpaceNode *snode, float cursor
}
if (link_to_pick != nullptr && !nldrag->from_multi_input_socket) {
- LinkData *linkdata = (LinkData *)MEM_callocN(sizeof(LinkData), "drag link op link data");
bNodeLink *oplink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "drag link op link");
- linkdata->data = oplink;
*oplink = *link_to_pick;
oplink->next = oplink->prev = nullptr;
oplink->flag |= NODE_LINK_VALID;
oplink->flag |= NODE_LINK_DRAGGED;
oplink->flag &= ~NODE_LINK_TEST;
- if (node_connected_to_output(bmain, snode->edittree, link_to_pick->tonode)) {
+ if (node_connected_to_output(bmain, *snode.edittree, *link_to_pick->tonode)) {
oplink->flag |= NODE_LINK_TEST;
}
- BLI_addtail(&nldrag->links, linkdata);
- nodeRemLink(snode->edittree, link_to_pick);
+ nldrag->links.append(oplink);
+ nodeRemLink(snode.edittree, link_to_pick);
/* send changed event to original link->tonode */
if (node) {
@@ -1300,37 +1347,40 @@ static bNodeLinkDrag *node_link_init(Main *bmain, SpaceNode *snode, float cursor
/* dragged links are fixed on input side */
nldrag->in_out = SOCK_IN;
/* create a new link */
- LinkData *linkdata = create_drag_link(bmain, snode, node, sock);
-
- BLI_addtail(&nldrag->links, linkdata);
+ nldrag->links.append(create_drag_link(bmain, snode, *node, *sock));
}
+ return nldrag;
}
- return nldrag;
+ return {};
}
static int node_link_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- Main *bmain = CTX_data_main(C);
- SpaceNode *snode = CTX_wm_space_node(C);
- ARegion *region = CTX_wm_region(C);
+ Main &bmain = *CTX_data_main(C);
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ ARegion &region = *CTX_wm_region(C);
bool detach = RNA_boolean_get(op->ptr, "detach");
- float cursor[2];
- UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &cursor[0], &cursor[1]);
+ float2 cursor;
+ UI_view2d_region_to_view(&region.v2d, event->mval[0], event->mval[1], &cursor[0], &cursor[1]);
RNA_float_set_array(op->ptr, "drag_start", cursor);
RNA_boolean_set(op->ptr, "has_link_picked", false);
- ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
+ ED_preview_kill_jobs(CTX_wm_manager(C), &bmain);
- bNodeLinkDrag *nldrag = node_link_init(bmain, snode, cursor, detach);
+ std::unique_ptr<bNodeLinkDrag> nldrag = node_link_init(bmain, snode, cursor, detach);
if (nldrag) {
UI_view2d_edge_pan_operator_init(C, &nldrag->pan_data, op);
- op->customdata = nldrag;
- BLI_addtail(&snode->runtime->linkdrag, nldrag);
+ /* Add "+" icon when the link is dragged in empty space. */
+ if (should_create_drag_link_search_menu(*snode.edittree, *nldrag)) {
+ draw_draglink_tooltip_activate(*CTX_wm_region(C), *nldrag);
+ }
+ snode.runtime->linkdrag = std::move(nldrag);
+ op->customdata = snode.runtime->linkdrag.get();
/* add modal handler */
WM_event_add_modal_handler(C, op);
@@ -1345,12 +1395,10 @@ static void node_link_cancel(bContext *C, wmOperator *op)
SpaceNode *snode = CTX_wm_space_node(C);
bNodeLinkDrag *nldrag = (bNodeLinkDrag *)op->customdata;
- BLI_remlink(&snode->runtime->linkdrag, nldrag);
-
UI_view2d_edge_pan_cancel(C, &nldrag->pan_data);
- BLI_freelistN(&nldrag->links);
- MEM_freeN(nldrag);
+ snode->runtime->linkdrag.reset();
+
clear_picking_highlight(&snode->edittree->links);
}
@@ -1413,11 +1461,11 @@ void NODE_OT_link(wmOperatorType *ot)
/* makes a link between selected output and input sockets */
static int node_make_link_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
- SpaceNode *snode = CTX_wm_space_node(C);
+ Main &bmain = *CTX_data_main(C);
+ SpaceNode &snode = *CTX_wm_space_node(C);
const bool replace = RNA_boolean_get(op->ptr, "replace");
- ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
+ ED_preview_kill_jobs(CTX_wm_manager(C), &bmain);
snode_autoconnect(bmain, snode, true, replace);
@@ -1425,9 +1473,9 @@ static int node_make_link_exec(bContext *C, wmOperator *op)
node_deselect_all_input_sockets(snode, false);
node_deselect_all_output_sockets(snode, false);
- ntreeUpdateTree(CTX_data_main(C), snode->edittree);
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ ntreeUpdateTree(CTX_data_main(C), snode.edittree);
+ snode_notify(*C, snode);
+ snode_dag_update(*C, snode);
return OPERATOR_FINISHED;
}
@@ -1457,7 +1505,7 @@ void NODE_OT_link_make(wmOperatorType *ot)
/** \name Node Link Intersect
* \{ */
-static bool node_links_intersect(bNodeLink *link, const float mcoords[][2], int tot)
+static bool node_links_intersect(bNodeLink &link, const float mcoords[][2], int tot)
{
float coord_array[NODE_LINK_RESOL + 1][2];
@@ -1481,9 +1529,9 @@ static bool node_links_intersect(bNodeLink *link, const float mcoords[][2], int
static int cut_links_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
- SpaceNode *snode = CTX_wm_space_node(C);
- ARegion *region = CTX_wm_region(C);
+ Main &bmain = *CTX_data_main(C);
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ ARegion &region = *CTX_wm_region(C);
bool do_tag_update = false;
int i = 0;
@@ -1493,7 +1541,7 @@ static int cut_links_exec(bContext *C, wmOperator *op)
RNA_float_get_array(&itemptr, "loc", loc);
UI_view2d_region_to_view(
- &region->v2d, (int)loc[0], (int)loc[1], &mcoords[i][0], &mcoords[i][1]);
+ &region.v2d, (int)loc[0], (int)loc[1], &mcoords[i][0], &mcoords[i][1]);
i++;
if (i >= 256) {
break;
@@ -1504,36 +1552,36 @@ static int cut_links_exec(bContext *C, wmOperator *op)
if (i > 1) {
bool found = false;
- ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
+ ED_preview_kill_jobs(CTX_wm_manager(C), &bmain);
- LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &snode->edittree->links) {
- if (node_link_is_hidden_or_dimmed(&region->v2d, link)) {
+ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &snode.edittree->links) {
+ if (node_link_is_hidden_or_dimmed(region.v2d, *link)) {
continue;
}
- if (node_links_intersect(link, mcoords, i)) {
+ if (node_links_intersect(*link, mcoords, i)) {
if (found == false) {
/* TODO(sergey): Why did we kill jobs twice? */
- ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
+ ED_preview_kill_jobs(CTX_wm_manager(C), &bmain);
found = true;
}
do_tag_update |= (do_tag_update ||
- node_connected_to_output(bmain, snode->edittree, link->tonode));
+ node_connected_to_output(bmain, *snode.edittree, *link->tonode));
snode_update(snode, link->tonode);
bNode *to_node = link->tonode;
- nodeRemLink(snode->edittree, link);
- sort_multi_input_socket_links(snode, to_node, nullptr, nullptr);
+ nodeRemLink(snode.edittree, link);
+ sort_multi_input_socket_links(snode, *to_node, nullptr, nullptr);
}
}
if (found) {
- ntreeUpdateTree(CTX_data_main(C), snode->edittree);
- snode_notify(C, snode);
+ ntreeUpdateTree(CTX_data_main(C), snode.edittree);
+ snode_notify(*C, snode);
if (do_tag_update) {
- snode_dag_update(C, snode);
+ snode_dag_update(*C, snode);
}
return OPERATOR_FINISHED;
@@ -1578,9 +1626,9 @@ void NODE_OT_links_cut(wmOperatorType *ot)
static int mute_links_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
- SpaceNode *snode = CTX_wm_space_node(C);
- ARegion *region = CTX_wm_region(C);
+ Main &bmain = *CTX_data_main(C);
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ ARegion &region = *CTX_wm_region(C);
bool do_tag_update = false;
int i = 0;
@@ -1590,7 +1638,7 @@ static int mute_links_exec(bContext *C, wmOperator *op)
RNA_float_get_array(&itemptr, "loc", loc);
UI_view2d_region_to_view(
- &region->v2d, (int)loc[0], (int)loc[1], &mcoords[i][0], &mcoords[i][1]);
+ &region.v2d, (int)loc[0], (int)loc[1], &mcoords[i][0], &mcoords[i][1]);
i++;
if (i >= 256) {
break;
@@ -1599,16 +1647,16 @@ static int mute_links_exec(bContext *C, wmOperator *op)
RNA_END;
if (i > 1) {
- ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
+ ED_preview_kill_jobs(CTX_wm_manager(C), &bmain);
/* Count intersected links and clear test flag. */
int tot = 0;
- LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) {
- if (node_link_is_hidden_or_dimmed(&region->v2d, link)) {
+ LISTBASE_FOREACH (bNodeLink *, link, &snode.edittree->links) {
+ if (node_link_is_hidden_or_dimmed(region.v2d, *link)) {
continue;
}
link->flag &= ~NODE_LINK_TEST;
- if (node_links_intersect(link, mcoords, i)) {
+ if (node_links_intersect(*link, mcoords, i)) {
tot++;
}
}
@@ -1617,32 +1665,32 @@ static int mute_links_exec(bContext *C, wmOperator *op)
}
/* Mute links. */
- LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) {
- if (node_link_is_hidden_or_dimmed(&region->v2d, link) || (link->flag & NODE_LINK_TEST)) {
+ LISTBASE_FOREACH (bNodeLink *, link, &snode.edittree->links) {
+ if (node_link_is_hidden_or_dimmed(region.v2d, *link) || (link->flag & NODE_LINK_TEST)) {
continue;
}
- if (node_links_intersect(link, mcoords, i)) {
+ if (node_links_intersect(*link, mcoords, i)) {
do_tag_update |= (do_tag_update ||
- node_connected_to_output(bmain, snode->edittree, link->tonode));
+ node_connected_to_output(bmain, *snode.edittree, *link->tonode));
snode_update(snode, link->tonode);
- nodeMuteLinkToggle(snode->edittree, link);
+ nodeMuteLinkToggle(snode.edittree, link);
}
}
/* Clear remaining test flags. */
- LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) {
- if (node_link_is_hidden_or_dimmed(&region->v2d, link)) {
+ LISTBASE_FOREACH (bNodeLink *, link, &snode.edittree->links) {
+ if (node_link_is_hidden_or_dimmed(region.v2d, *link)) {
continue;
}
link->flag &= ~NODE_LINK_TEST;
}
- ntreeUpdateTree(CTX_data_main(C), snode->edittree);
- snode_notify(C, snode);
+ ntreeUpdateTree(CTX_data_main(C), snode.edittree);
+ snode_notify(*C, snode);
if (do_tag_update) {
- snode_dag_update(C, snode);
+ snode_dag_update(*C, snode);
}
return OPERATOR_FINISHED;
@@ -1684,21 +1732,21 @@ void NODE_OT_links_mute(wmOperatorType *ot)
static int detach_links_exec(bContext *C, wmOperator *UNUSED(op))
{
- SpaceNode *snode = CTX_wm_space_node(C);
- bNodeTree *ntree = snode->edittree;
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ bNodeTree &ntree = *snode.edittree;
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
if (node->flag & SELECT) {
- nodeInternalRelink(ntree, node);
+ nodeInternalRelink(&ntree, node);
}
}
- ntreeUpdateTree(CTX_data_main(C), ntree);
+ ntreeUpdateTree(CTX_data_main(C), &ntree);
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ snode_notify(*C, snode);
+ snode_dag_update(*C, snode);
return OPERATOR_FINISHED;
}
@@ -1805,12 +1853,12 @@ static void node_join_attach_recursive(bNode *node, bNode *frame)
static int node_join_exec(bContext *C, wmOperator *UNUSED(op))
{
- SpaceNode *snode = CTX_wm_space_node(C);
- bNodeTree *ntree = snode->edittree;
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ bNodeTree &ntree = *snode.edittree;
/* XXX save selection: node_add_node call below sets the new frame as single
* active+selected node */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
if (node->flag & NODE_SELECT) {
node->flag |= NODE_TEST;
}
@@ -1819,27 +1867,27 @@ static int node_join_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- bNode *frame = node_add_node(C, nullptr, NODE_FRAME, 0.0f, 0.0f);
+ bNode *frame = node_add_node(*C, nullptr, NODE_FRAME, 0.0f, 0.0f);
/* reset tags */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
node->done = 0;
}
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
if (!(node->done & NODE_JOIN_DONE)) {
node_join_attach_recursive(node, frame);
}
}
/* restore selection */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
if (node->flag & NODE_TEST) {
node->flag |= NODE_SELECT;
}
}
- ED_node_sort(ntree);
+ ED_node_sort(&ntree);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
return OPERATOR_FINISHED;
@@ -2073,7 +2121,7 @@ static bool ed_node_link_conditions(ScrArea *area,
/* test node for links */
LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) {
- if (node_link_is_hidden_or_dimmed(&region->v2d, link)) {
+ if (node_link_is_hidden_or_dimmed(region->v2d, *link)) {
continue;
}
@@ -2086,7 +2134,6 @@ static bool ed_node_link_conditions(ScrArea *area,
return true;
}
-/* test == 0, clear all intersect flags */
void ED_node_link_intersect_test(ScrArea *area, int test)
{
bNode *select;
@@ -2112,11 +2159,11 @@ void ED_node_link_intersect_test(ScrArea *area, int test)
LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) {
float coord_array[NODE_LINK_RESOL + 1][2];
- if (node_link_is_hidden_or_dimmed(&region->v2d, link)) {
+ if (node_link_is_hidden_or_dimmed(region->v2d, *link)) {
continue;
}
- if (node_link_bezier_points(nullptr, nullptr, link, coord_array, NODE_LINK_RESOL)) {
+ if (node_link_bezier_points(nullptr, nullptr, *link, coord_array, NODE_LINK_RESOL)) {
float dist = FLT_MAX;
/* loop over link coords to find shortest dist to
@@ -2158,18 +2205,19 @@ static int get_main_socket_priority(const bNodeSocket *socket)
{
switch ((eNodeSocketDatatype)socket->type) {
case __SOCK_MESH:
- case SOCK_CUSTOM:
return -1;
- case SOCK_BOOLEAN:
+ case SOCK_CUSTOM:
return 0;
- case SOCK_INT:
+ case SOCK_BOOLEAN:
return 1;
- case SOCK_FLOAT:
+ case SOCK_INT:
return 2;
- case SOCK_VECTOR:
+ case SOCK_FLOAT:
return 3;
- case SOCK_RGBA:
+ case SOCK_VECTOR:
return 4;
+ case SOCK_RGBA:
+ return 5;
case SOCK_STRING:
case SOCK_SHADER:
case SOCK_OBJECT:
@@ -2178,7 +2226,7 @@ static int get_main_socket_priority(const bNodeSocket *socket)
case SOCK_COLLECTION:
case SOCK_TEXTURE:
case SOCK_MATERIAL:
- return 5;
+ return 6;
}
return -1;
}
@@ -2251,19 +2299,19 @@ static bool node_parents_offset_flag_enable_cb(bNode *parent, void *UNUSED(userd
return true;
}
-static void node_offset_apply(bNode *node, const float offset_x)
+static void node_offset_apply(bNode &node, const float offset_x)
{
/* NODE_TEST is used to flag nodes that shouldn't be offset (again) */
- if ((node->flag & NODE_TEST) == 0) {
- node->anim_init_locx = node->locx;
- node->anim_ofsx = (offset_x / UI_DPI_FAC);
- node->flag |= NODE_TEST;
+ if ((node.flag & NODE_TEST) == 0) {
+ node.anim_init_locx = node.locx;
+ node.anim_ofsx = (offset_x / UI_DPI_FAC);
+ node.flag |= NODE_TEST;
}
}
static void node_parent_offset_apply(NodeInsertOfsData *data, bNode *parent, const float offset_x)
{
- node_offset_apply(parent, offset_x);
+ node_offset_apply(*parent, offset_x);
/* Flag all children as offset to prevent them from being offset
* separately (they've already moved with the parent). */
@@ -2290,10 +2338,10 @@ static bool node_link_insert_offset_frame_chain_cb(bNode *fromnode,
bNode *ofs_node = reversed ? fromnode : tonode;
if (ofs_node->parent && ofs_node->parent != data->insert_parent) {
- node_offset_apply(ofs_node->parent, data->offset_x);
+ node_offset_apply(*ofs_node->parent, data->offset_x);
}
else {
- node_offset_apply(ofs_node, data->offset_x);
+ node_offset_apply(*ofs_node, data->offset_x);
}
return true;
@@ -2332,7 +2380,7 @@ static bool node_link_insert_offset_chain_cb(bNode *fromnode,
node_link_insert_offset_frame_chains(data->ntree, ofs_node->parent, data, reversed);
}
else {
- node_offset_apply(ofs_node, data->offset_x);
+ node_offset_apply(*ofs_node, data->offset_x);
}
if (nodeIsChildOf(data->insert_parent, ofs_node) == false) {
@@ -2341,10 +2389,10 @@ static bool node_link_insert_offset_chain_cb(bNode *fromnode,
}
else if (ofs_node->parent) {
bNode *node = nodeFindRootParent(ofs_node);
- node_offset_apply(node, data->offset_x);
+ node_offset_apply(*node, data->offset_x);
}
else {
- node_offset_apply(ofs_node, data->offset_x);
+ node_offset_apply(*ofs_node, data->offset_x);
}
return true;
@@ -2356,9 +2404,9 @@ static void node_link_insert_offset_ntree(NodeInsertOfsData *iofsd,
const bool right_alignment)
{
bNodeTree *ntree = iofsd->ntree;
- bNode *insert = iofsd->insert;
+ bNode &insert = *iofsd->insert;
bNode *prev = iofsd->prev, *next = iofsd->next;
- bNode *init_parent = insert->parent; /* store old insert->parent for restoring later */
+ bNode *init_parent = insert.parent; /* store old insert.parent for restoring later */
const float min_margin = U.node_margin * UI_DPI_FAC;
const float width = NODE_WIDTH(insert);
@@ -2369,20 +2417,20 @@ static void node_link_insert_offset_ntree(NodeInsertOfsData *iofsd,
/* NODE_TEST will be used later, so disable for all nodes */
ntreeNodeFlagSet(ntree, NODE_TEST, false);
- /* `insert->totr` isn't updated yet,
+ /* `insert.totr` isn't updated yet,
* so `totr_insert` is used to get the correct world-space coords. */
rctf totr_insert;
- node_to_updated_rect(insert, &totr_insert);
+ node_to_updated_rect(insert, totr_insert);
/* frame attachment wasn't handled yet
* so we search the frame that the node will be attached to later */
- insert->parent = node_find_frame_to_attach(region, ntree, mouse_xy);
+ insert.parent = node_find_frame_to_attach(region, ntree, mouse_xy);
/* this makes sure nodes are also correctly offset when inserting a node on top of a frame
* without actually making it a part of the frame (because mouse isn't intersecting it)
* - logic here is similar to node_find_frame_to_attach */
- if (!insert->parent ||
- (prev->parent && (prev->parent == next->parent) && (prev->parent != insert->parent))) {
+ if (!insert.parent ||
+ (prev->parent && (prev->parent == next->parent) && (prev->parent != insert.parent))) {
bNode *frame;
rctf totr_frame;
@@ -2394,15 +2442,15 @@ static void node_link_insert_offset_ntree(NodeInsertOfsData *iofsd,
}
/* for some reason frame y coords aren't correct yet */
- node_to_updated_rect(frame, &totr_frame);
+ node_to_updated_rect(*frame, totr_frame);
if (BLI_rctf_isect_x(&totr_frame, totr_insert.xmin) &&
BLI_rctf_isect_x(&totr_frame, totr_insert.xmax)) {
if (BLI_rctf_isect_y(&totr_frame, totr_insert.ymin) ||
BLI_rctf_isect_y(&totr_frame, totr_insert.ymax)) {
- /* frame isn't insert->parent actually, but this is needed to make offsetting
+ /* frame isn't insert.parent actually, but this is needed to make offsetting
* nodes work correctly for above checked cases (it is restored later) */
- insert->parent = frame;
+ insert.parent = frame;
break;
}
}
@@ -2432,12 +2480,12 @@ static void node_link_insert_offset_ntree(NodeInsertOfsData *iofsd,
const float addval = (min_margin - dist) * (right_alignment ? 1.0f : -1.0f);
if (needs_alignment) {
bNode *offs_node = right_alignment ? next : prev;
- if (!offs_node->parent || offs_node->parent == insert->parent ||
- nodeIsChildOf(offs_node->parent, insert)) {
- node_offset_apply(offs_node, addval);
+ if (!offs_node->parent || offs_node->parent == insert.parent ||
+ nodeIsChildOf(offs_node->parent, &insert)) {
+ node_offset_apply(*offs_node, addval);
}
- else if (!insert->parent && offs_node->parent) {
- node_offset_apply(nodeFindRootParent(offs_node), addval);
+ else if (!insert.parent && offs_node->parent) {
+ node_offset_apply(*nodeFindRootParent(offs_node), addval);
}
margin = addval;
}
@@ -2449,11 +2497,11 @@ static void node_link_insert_offset_ntree(NodeInsertOfsData *iofsd,
}
if (needs_alignment) {
- iofsd->insert_parent = insert->parent;
+ iofsd->insert_parent = insert.parent;
iofsd->offset_x = margin;
/* flag all parents of insert as offset to prevent them from being offset */
- nodeParentsIter(insert, node_parents_offset_flag_enable_cb, nullptr);
+ nodeParentsIter(&insert, node_parents_offset_flag_enable_cb, nullptr);
/* iterate over entire chain and apply offsets */
nodeChainIter(ntree,
right_alignment ? next : prev,
@@ -2462,7 +2510,7 @@ static void node_link_insert_offset_ntree(NodeInsertOfsData *iofsd,
!right_alignment);
}
- insert->parent = init_parent;
+ insert.parent = init_parent;
}
/**
@@ -2567,7 +2615,6 @@ void NODE_OT_insert_offset(wmOperatorType *ot)
/** \name Note Link Insert
* \{ */
-/* assumes link with NODE_LINKFLAG_HILITE set */
void ED_node_link_insert(Main *bmain, ScrArea *area)
{
bNode *select;
@@ -2594,7 +2641,7 @@ void ED_node_link_insert(Main *bmain, ScrArea *area)
link->tonode = select;
link->tosock = best_input;
- node_remove_extra_links(snode, link);
+ node_remove_extra_links(*snode, *link);
link->flag &= ~NODE_LINKFLAG_HILITE;
bNodeLink *new_link = nodeAddLink(snode->edittree, select, best_output, node, sockto);
@@ -2617,7 +2664,7 @@ void ED_node_link_insert(Main *bmain, ScrArea *area)
}
ntreeUpdateTree(bmain, snode->edittree); /* needed for pointers */
- snode_update(snode, select);
+ snode_update(*snode, select);
ED_node_tag_update_id((ID *)snode->edittree);
ED_node_tag_update_id(snode->id);
}
diff --git a/source/blender/editors/space_node/node_select.cc b/source/blender/editors/space_node/node_select.cc
index 3c7b404547b..334ca1f76ee 100644
--- a/source/blender/editors/space_node/node_select.cc
+++ b/source/blender/editors/space_node/node_select.cc
@@ -29,7 +29,6 @@
#include "BLI_lasso_2d.h"
#include "BLI_listbase.h"
-#include "BLI_math.h"
#include "BLI_rect.h"
#include "BLI_string.h"
#include "BLI_string_search.h"
@@ -63,6 +62,8 @@
#include "node_intern.hh" /* own include */
+using blender::float2;
+
/**
* Function to detect if there is a visible view3d that uses workbench in texture mode.
* This function is for fixing T76970 for Blender 2.83. The actual fix should add a mechanism in
@@ -98,43 +99,43 @@ static bool has_workbench_in_texture_color(const wmWindowManager *wm,
/** \name Public Node Selection API
* \{ */
-static bNode *node_under_mouse_select(bNodeTree *ntree, int mx, int my)
+static bNode *node_under_mouse_select(bNodeTree &ntree, int mx, int my)
{
- bNode *node;
-
- for (node = (bNode *)ntree->nodes.last; node; node = node->prev) {
- if (node->typeinfo->select_area_func) {
- if (node->typeinfo->select_area_func(node, mx, my)) {
- return node;
- }
+ LISTBASE_FOREACH_BACKWARD (bNode *, node, &ntree.nodes) {
+ if (BLI_rctf_isect_pt(&node->totr, mx, my)) {
+ return node;
}
}
return nullptr;
}
-static bNode *node_under_mouse_tweak(bNodeTree *ntree, int mx, int my)
+static bNode *node_under_mouse_tweak(bNodeTree &ntree, const float2 &mouse)
{
- bNode *node;
-
- for (node = (bNode *)ntree->nodes.last; node; node = node->prev) {
- if (node->typeinfo->tweak_area_func) {
- if (node->typeinfo->tweak_area_func(node, mx, my)) {
+ LISTBASE_FOREACH_BACKWARD (bNode *, node, &ntree.nodes) {
+ if (node->type == NODE_REROUTE) {
+ bNodeSocket *socket = (bNodeSocket *)node->inputs.first;
+ const float2 location{socket->locx, socket->locy};
+ if (float2::distance(mouse, location) < 24.0f) {
return node;
}
}
+ if (BLI_rctf_isect_pt(&node->totr, mouse.x, mouse.y)) {
+ return node;
+ }
}
return nullptr;
}
-static bool is_position_over_node_or_socket(SpaceNode *snode, float mouse[2])
+static bool is_position_over_node_or_socket(SpaceNode &snode, const float2 &mouse)
{
- if (node_under_mouse_tweak(snode->edittree, mouse[0], mouse[1])) {
+ if (node_under_mouse_tweak(*snode.edittree, mouse)) {
return true;
}
bNode *node;
bNodeSocket *sock;
- if (node_find_indicated_socket(snode, &node, &sock, mouse, SOCK_IN | SOCK_OUT)) {
+ if (node_find_indicated_socket(
+ snode, &node, &sock, mouse, (eNodeSocketInOut)(SOCK_IN | SOCK_OUT))) {
return true;
}
@@ -145,9 +146,9 @@ static bool is_event_over_node_or_socket(bContext *C, const wmEvent *event)
{
SpaceNode *snode = CTX_wm_space_node(C);
ARegion *region = CTX_wm_region(C);
- float mouse[2];
- UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &mouse[0], &mouse[1]);
- return is_position_over_node_or_socket(snode, mouse);
+ float2 mouse;
+ UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &mouse.x, &mouse.y);
+ return is_position_over_node_or_socket(*snode, mouse);
}
static void node_toggle(bNode *node)
@@ -155,9 +156,9 @@ static void node_toggle(bNode *node)
nodeSetSelected(node, !(node->flag & SELECT));
}
-void node_socket_select(bNode *node, bNodeSocket *sock)
+void node_socket_select(bNode *node, bNodeSocket &sock)
{
- sock->flag |= SELECT;
+ sock.flag |= SELECT;
/* select node too */
if (node) {
@@ -165,22 +166,22 @@ void node_socket_select(bNode *node, bNodeSocket *sock)
}
}
-void node_socket_deselect(bNode *node, bNodeSocket *sock, const bool deselect_node)
+void node_socket_deselect(bNode *node, bNodeSocket &sock, const bool deselect_node)
{
- sock->flag &= ~SELECT;
+ sock.flag &= ~SELECT;
if (node && deselect_node) {
bool sel = false;
/* if no selected sockets remain, also deselect the node */
- for (sock = (bNodeSocket *)node->inputs.first; sock; sock = sock->next) {
- if (sock->flag & SELECT) {
+ LISTBASE_FOREACH (bNodeSocket *, input, &node->inputs) {
+ if (input->flag & SELECT) {
sel = true;
break;
}
}
- for (sock = (bNodeSocket *)node->outputs.first; sock; sock = sock->next) {
- if (sock->flag & SELECT) {
+ LISTBASE_FOREACH (bNodeSocket *, output, &node->outputs) {
+ if (output->flag & SELECT) {
sel = true;
break;
}
@@ -192,9 +193,9 @@ void node_socket_deselect(bNode *node, bNodeSocket *sock, const bool deselect_no
}
}
-static void node_socket_toggle(bNode *node, bNodeSocket *sock, int deselect_node)
+static void node_socket_toggle(bNode *node, bNodeSocket &sock, bool deselect_node)
{
- if (sock->flag & SELECT) {
+ if (sock.flag & SELECT) {
node_socket_deselect(node, sock, deselect_node);
}
else {
@@ -202,38 +203,32 @@ static void node_socket_toggle(bNode *node, bNodeSocket *sock, int deselect_node
}
}
-/* no undo here! */
-void node_deselect_all(SpaceNode *snode)
+void node_deselect_all(SpaceNode &snode)
{
- bNode *node;
-
- for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &snode.edittree->nodes) {
nodeSetSelected(node, false);
}
}
-void node_deselect_all_input_sockets(SpaceNode *snode, const bool deselect_nodes)
+void node_deselect_all_input_sockets(SpaceNode &snode, const bool deselect_nodes)
{
- bNode *node;
- bNodeSocket *sock;
-
/* XXX not calling node_socket_deselect here each time, because this does iteration
* over all node sockets internally to check if the node stays selected.
* We can do that more efficiently here.
*/
- for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) {
- int sel = 0;
+ LISTBASE_FOREACH (bNode *, node, &snode.edittree->nodes) {
+ bool sel = false;
- for (sock = (bNodeSocket *)node->inputs.first; sock; sock = sock->next) {
- sock->flag &= ~SELECT;
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
+ socket->flag &= ~SELECT;
}
/* if no selected sockets remain, also deselect the node */
if (deselect_nodes) {
- for (sock = (bNodeSocket *)node->outputs.first; sock; sock = sock->next) {
- if (sock->flag & SELECT) {
- sel = 1;
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) {
+ if (socket->flag & SELECT) {
+ sel = true;
break;
}
}
@@ -245,27 +240,24 @@ void node_deselect_all_input_sockets(SpaceNode *snode, const bool deselect_nodes
}
}
-void node_deselect_all_output_sockets(SpaceNode *snode, const bool deselect_nodes)
+void node_deselect_all_output_sockets(SpaceNode &snode, const bool deselect_nodes)
{
- bNode *node;
- bNodeSocket *sock;
-
/* XXX not calling node_socket_deselect here each time, because this does iteration
* over all node sockets internally to check if the node stays selected.
* We can do that more efficiently here.
*/
- for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &snode.edittree->nodes) {
bool sel = false;
- for (sock = (bNodeSocket *)node->outputs.first; sock; sock = sock->next) {
- sock->flag &= ~SELECT;
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) {
+ socket->flag &= ~SELECT;
}
/* if no selected sockets remain, also deselect the node */
if (deselect_nodes) {
- for (sock = (bNodeSocket *)node->inputs.first; sock; sock = sock->next) {
- if (sock->flag & SELECT) {
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
+ if (socket->flag & SELECT) {
sel = true;
break;
}
@@ -305,10 +297,9 @@ static bool node_select_grouped_type(SpaceNode *snode, bNode *node_act)
static bool node_select_grouped_color(SpaceNode *snode, bNode *node_act)
{
- bNode *node;
bool changed = false;
- for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) {
if ((node->flag & SELECT) == 0) {
if (compare_v3v3(node->color, node_act->color, 0.005f)) {
nodeSetSelected(node, true);
@@ -455,24 +446,24 @@ void NODE_OT_select_grouped(wmOperatorType *ot)
/** \name Select (Cursor Pick) Operator
* \{ */
-void node_select_single(bContext *C, bNode *node)
+void node_select_single(bContext &C, bNode &node)
{
- Main *bmain = CTX_data_main(C);
- SpaceNode *snode = CTX_wm_space_node(C);
- const Object *ob = CTX_data_active_object(C);
- const Scene *scene = CTX_data_scene(C);
- const wmWindowManager *wm = CTX_wm_manager(C);
+ Main *bmain = CTX_data_main(&C);
+ SpaceNode *snode = CTX_wm_space_node(&C);
+ const Object *ob = CTX_data_active_object(&C);
+ const Scene *scene = CTX_data_scene(&C);
+ const wmWindowManager *wm = CTX_wm_manager(&C);
bool active_texture_changed = false;
bNode *tnode;
for (tnode = (bNode *)snode->edittree->nodes.first; tnode; tnode = tnode->next) {
- if (tnode != node) {
+ if (tnode != &node) {
nodeSetSelected(tnode, false);
}
}
- nodeSetSelected(node, true);
+ nodeSetSelected(&node, true);
- ED_node_set_active(bmain, snode, snode->edittree, node, &active_texture_changed);
+ ED_node_set_active(bmain, snode, snode->edittree, &node, &active_texture_changed);
ED_node_set_active_viewer_key(snode);
ED_node_sort(snode->edittree);
@@ -480,7 +471,7 @@ void node_select_single(bContext *C, bNode *node)
DEG_id_tag_update(&snode->edittree->id, ID_RECALC_COPY_ON_WRITE);
}
- WM_event_add_notifier(C, NC_NODE | NA_SELECTED, nullptr);
+ WM_event_add_notifier(&C, NC_NODE | NA_SELECTED, nullptr);
}
static int node_mouse_select(bContext *C,
@@ -488,9 +479,9 @@ static int node_mouse_select(bContext *C,
const int mval[2],
bool wait_to_deselect_others)
{
- Main *bmain = CTX_data_main(C);
- SpaceNode *snode = CTX_wm_space_node(C);
- ARegion *region = CTX_wm_region(C);
+ Main &bmain = *CTX_data_main(C);
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ ARegion &region = *CTX_wm_region(C);
const Object *ob = CTX_data_active_object(C);
const Scene *scene = CTX_data_scene(C);
const wmWindowManager *wm = CTX_wm_manager(C);
@@ -511,20 +502,20 @@ static int node_mouse_select(bContext *C,
}
/* get mouse coordinates in view2d space */
- UI_view2d_region_to_view(&region->v2d, mval[0], mval[1], &cursor[0], &cursor[1]);
+ UI_view2d_region_to_view(&region.v2d, mval[0], mval[1], &cursor[0], &cursor[1]);
/* first do socket selection, these generally overlap with nodes. */
if (socket_select) {
if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_IN)) {
/* NOTE: SOCK_IN does not take into account the extend case...
* This feature is not really used anyway currently? */
- node_socket_toggle(node, sock, true);
+ node_socket_toggle(node, *sock, true);
ret_value = OPERATOR_FINISHED;
}
else if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_OUT)) {
if (sock->flag & SELECT) {
if (extend) {
- node_socket_deselect(node, sock, true);
+ node_socket_deselect(node, *sock, true);
}
else {
ret_value = OPERATOR_FINISHED;
@@ -538,20 +529,20 @@ static int node_mouse_select(bContext *C,
if (tsock == sock) {
continue;
}
- node_socket_deselect(node, tsock, true);
+ node_socket_deselect(node, *tsock, true);
}
}
if (!extend) {
- for (tnode = (bNode *)snode->edittree->nodes.first; tnode; tnode = tnode->next) {
+ for (tnode = (bNode *)snode.edittree->nodes.first; tnode; tnode = tnode->next) {
if (tnode == node) {
continue;
}
for (tsock = (bNodeSocket *)tnode->outputs.first; tsock; tsock = tsock->next) {
- node_socket_deselect(tnode, tsock, true);
+ node_socket_deselect(tnode, *tsock, true);
}
}
}
- node_socket_select(node, sock);
+ node_socket_select(node, *sock);
ret_value = OPERATOR_FINISHED;
}
}
@@ -559,7 +550,7 @@ static int node_mouse_select(bContext *C,
if (!sock) {
/* find the closest visible node */
- node = node_under_mouse_select(snode->edittree, (int)cursor[0], (int)cursor[1]);
+ node = node_under_mouse_select(*snode.edittree, (int)cursor[0], (int)cursor[1]);
if (extend) {
if (node != nullptr) {
@@ -580,7 +571,7 @@ static int node_mouse_select(bContext *C,
}
else {
/* Deselect in empty space. */
- for (tnode = (bNode *)snode->edittree->nodes.first; tnode; tnode = tnode->next) {
+ for (tnode = (bNode *)snode.edittree->nodes.first; tnode; tnode = tnode->next) {
nodeSetSelected(tnode, false);
}
ret_value = OPERATOR_FINISHED;
@@ -595,7 +586,7 @@ static int node_mouse_select(bContext *C,
else {
nodeSetSelected(node, true);
- for (tnode = (bNode *)snode->edittree->nodes.first; tnode; tnode = tnode->next) {
+ for (tnode = (bNode *)snode.edittree->nodes.first; tnode; tnode = tnode->next) {
if (tnode != node) {
nodeSetSelected(tnode, false);
}
@@ -612,16 +603,16 @@ static int node_mouse_select(bContext *C,
bool viewer_node_changed = false;
if (node != nullptr && ret_value != OPERATOR_RUNNING_MODAL) {
viewer_node_changed = (node->flag & NODE_DO_OUTPUT) == 0 && node->type == GEO_NODE_VIEWER;
- ED_node_set_active(bmain, snode, snode->edittree, node, &active_texture_changed);
+ ED_node_set_active(&bmain, &snode, snode.edittree, node, &active_texture_changed);
}
else if (node != nullptr && node->type == GEO_NODE_VIEWER) {
- ED_spreadsheet_context_paths_set_geometry_node(bmain, snode, node);
+ ED_spreadsheet_context_paths_set_geometry_node(&bmain, &snode, node);
}
- ED_node_set_active_viewer_key(snode);
- ED_node_sort(snode->edittree);
+ ED_node_set_active_viewer_key(&snode);
+ ED_node_sort(snode.edittree);
if ((active_texture_changed && has_workbench_in_texture_color(wm, scene, ob)) ||
viewer_node_changed) {
- DEG_id_tag_update(&snode->edittree->id, ID_RECALC_COPY_ON_WRITE);
+ DEG_id_tag_update(&snode.edittree->id, ID_RECALC_COPY_ON_WRITE);
}
WM_event_add_notifier(C, NC_NODE | NA_SELECTED, nullptr);
@@ -1149,13 +1140,13 @@ static int node_select_same_type_step_exec(bContext *C, wmOperator *op)
}
}
- node_select_single(C, active);
+ node_select_single(*C, *active);
/* is note outside view? */
if (active->totr.xmax < region->v2d.cur.xmin || active->totr.xmin > region->v2d.cur.xmax ||
active->totr.ymax < region->v2d.cur.ymin || active->totr.ymin > region->v2d.cur.ymax) {
const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
- space_node_view_flag(C, snode, region, NODE_SELECT, smooth_viewtx);
+ space_node_view_flag(*C, *snode, *region, NODE_SELECT, smooth_viewtx);
}
}
@@ -1213,7 +1204,7 @@ static void node_find_update_fn(const struct bContext *C,
LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) {
char name[256];
node_find_create_label(node, name, ARRAY_SIZE(name));
- BLI_string_search_add(search, name, node);
+ BLI_string_search_add(search, name, node, 0);
}
bNode **filtered_nodes;
@@ -1239,12 +1230,12 @@ static void node_find_exec_fn(struct bContext *C, void *UNUSED(arg1), void *arg2
if (active) {
ARegion *region = CTX_wm_region(C);
- node_select_single(C, active);
+ node_select_single(*C, *active);
/* is note outside view? */
if (active->totr.xmax < region->v2d.cur.xmin || active->totr.xmin > region->v2d.cur.xmax ||
active->totr.ymax < region->v2d.cur.ymin || active->totr.ymin > region->v2d.cur.ymax) {
- space_node_view_flag(C, snode, region, NODE_SELECT, U.smooth_viewtx);
+ space_node_view_flag(*C, *snode, *region, NODE_SELECT, U.smooth_viewtx);
}
}
}
diff --git a/source/blender/editors/space_node/node_templates.cc b/source/blender/editors/space_node/node_templates.cc
index b2a7c1753fb..386178596af 100644
--- a/source/blender/editors/space_node/node_templates.cc
+++ b/source/blender/editors/space_node/node_templates.cc
@@ -447,7 +447,9 @@ static void ui_node_link(bContext *C, void *arg_p, void *event_p)
ED_undo_push(C, "Node input modify");
}
-static void ui_node_sock_name(bNodeTree *ntree, bNodeSocket *sock, char name[UI_MAX_NAME_STR])
+static void ui_node_sock_name(const bNodeTree *ntree,
+ bNodeSocket *sock,
+ char name[UI_MAX_NAME_STR])
{
if (sock->link && sock->link->fromnode) {
bNode *node = sock->link->fromnode;
@@ -709,7 +711,7 @@ void uiTemplateNodeLink(
PointerRNA node_ptr;
RNA_pointer_create((ID *)ntree, &RNA_Node, node, &node_ptr);
- node_socket_color_get(C, ntree, &node_ptr, input, socket_col);
+ node_socket_color_get(*C, *ntree, node_ptr, *input, socket_col);
UI_block_layout_set_current(block, layout);
@@ -769,7 +771,6 @@ static void ui_node_draw_input(
PointerRNA inputptr, nodeptr;
uiBlock *block = uiLayoutGetBlock(layout);
uiLayout *row = nullptr;
- bNode *lnode;
bool dependency_loop;
if (input->flag & SOCK_UNAVAIL) {
@@ -778,7 +779,7 @@ static void ui_node_draw_input(
/* to avoid eternal loops on cyclic dependencies */
node->flag |= NODE_TEST;
- lnode = (input->link) ? input->link->fromnode : nullptr;
+ bNode *lnode = (input->link) ? input->link->fromnode : nullptr;
dependency_loop = (lnode && (lnode->flag & NODE_TEST));
if (dependency_loop) {
@@ -868,7 +869,7 @@ static void ui_node_draw_input(
if (node_tree->type == NTREE_GEOMETRY && snode != nullptr) {
/* Only add the attribute search in the node editor, in other places there is not
* enough context. */
- node_geometry_add_attribute_search_button(C, node_tree, node, &inputptr, row);
+ node_geometry_add_attribute_search_button(*C, *node_tree, *node, inputptr, *row);
}
else {
uiItemR(sub, &inputptr, "default_value", 0, "", ICON_NONE);
diff --git a/source/blender/editors/space_node/node_view.cc b/source/blender/editors/space_node/node_view.cc
index 36b84bec7eb..df629a983e3 100644
--- a/source/blender/editors/space_node/node_view.cc
+++ b/source/blender/editors/space_node/node_view.cc
@@ -24,7 +24,6 @@
#include "DNA_node_types.h"
#include "BLI_listbase.h"
-#include "BLI_math.h"
#include "BLI_rect.h"
#include "BLI_string_ref.hh"
#include "BLI_utildefines.h"
@@ -62,25 +61,21 @@ using blender::StringRef;
/** \name View All Operator
* \{ */
-int space_node_view_flag(
- bContext *C, SpaceNode *snode, ARegion *region, const int node_flag, const int smooth_viewtx)
+bool space_node_view_flag(
+ bContext &C, SpaceNode &snode, ARegion &region, const int node_flag, const int smooth_viewtx)
{
- bNode *node;
- rctf cur_new;
- float oldwidth, oldheight, width, height;
- float oldasp, asp;
- int tot = 0;
- bool has_frame = false;
+ const float oldwidth = BLI_rctf_size_x(&region.v2d.cur);
+ const float oldheight = BLI_rctf_size_y(&region.v2d.cur);
- oldwidth = BLI_rctf_size_x(&region->v2d.cur);
- oldheight = BLI_rctf_size_y(&region->v2d.cur);
-
- oldasp = oldwidth / oldheight;
+ const float old_aspect = oldwidth / oldheight;
+ rctf cur_new;
BLI_rctf_init_minmax(&cur_new);
- if (snode->edittree) {
- for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) {
+ int tot = 0;
+ bool has_frame = false;
+ if (snode.edittree) {
+ LISTBASE_FOREACH (const bNode *, node, &snode.edittree->nodes) {
if ((node->flag & node_flag) == node_flag) {
BLI_rctf_union(&cur_new, &node->totr);
tot++;
@@ -92,37 +87,39 @@ int space_node_view_flag(
}
}
- if (tot) {
- width = BLI_rctf_size_x(&cur_new);
- height = BLI_rctf_size_y(&cur_new);
- asp = width / height;
+ if (tot == 0) {
+ return false;
+ }
+
+ const float width = BLI_rctf_size_x(&cur_new);
+ const float height = BLI_rctf_size_y(&cur_new);
+ const float new_aspect = width / height;
- /* for single non-frame nodes, don't zoom in, just pan view,
- * but do allow zooming out, this allows for big nodes to be zoomed out */
- if ((tot == 1) && (has_frame == false) && ((oldwidth * oldheight) > (width * height))) {
- /* center, don't zoom */
- BLI_rctf_resize(&cur_new, oldwidth, oldheight);
+ /* for single non-frame nodes, don't zoom in, just pan view,
+ * but do allow zooming out, this allows for big nodes to be zoomed out */
+ if ((tot == 1) && (has_frame == false) && ((oldwidth * oldheight) > (width * height))) {
+ /* center, don't zoom */
+ BLI_rctf_resize(&cur_new, oldwidth, oldheight);
+ }
+ else {
+ if (old_aspect < new_aspect) {
+ const float height_new = width / old_aspect;
+ cur_new.ymin = cur_new.ymin - height_new / 2.0f;
+ cur_new.ymax = cur_new.ymax + height_new / 2.0f;
}
else {
- if (oldasp < asp) {
- const float height_new = width / oldasp;
- cur_new.ymin = cur_new.ymin - height_new / 2.0f;
- cur_new.ymax = cur_new.ymax + height_new / 2.0f;
- }
- else {
- const float width_new = height * oldasp;
- cur_new.xmin = cur_new.xmin - width_new / 2.0f;
- cur_new.xmax = cur_new.xmax + width_new / 2.0f;
- }
-
- /* add some padding */
- BLI_rctf_scale(&cur_new, 1.1f);
+ const float width_new = height * old_aspect;
+ cur_new.xmin = cur_new.xmin - width_new / 2.0f;
+ cur_new.xmax = cur_new.xmax + width_new / 2.0f;
}
- UI_view2d_smooth_view(C, region, &cur_new, smooth_viewtx);
+ /* add some padding */
+ BLI_rctf_scale(&cur_new, 1.1f);
}
- return (tot != 0);
+ UI_view2d_smooth_view(&C, &region, &cur_new, smooth_viewtx);
+
+ return true;
}
static int node_view_all_exec(bContext *C, wmOperator *op)
@@ -135,7 +132,7 @@ static int node_view_all_exec(bContext *C, wmOperator *op)
snode->xof = 0;
snode->yof = 0;
- if (space_node_view_flag(C, snode, region, 0, smooth_viewtx)) {
+ if (space_node_view_flag(*C, *snode, *region, 0, smooth_viewtx)) {
return OPERATOR_FINISHED;
}
return OPERATOR_CANCELLED;
@@ -168,7 +165,7 @@ static int node_view_selected_exec(bContext *C, wmOperator *op)
SpaceNode *snode = CTX_wm_space_node(C);
const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
- if (space_node_view_flag(C, snode, region, NODE_SELECT, smooth_viewtx)) {
+ if (space_node_view_flag(*C, *snode, *region, NODE_SELECT, smooth_viewtx)) {
return OPERATOR_FINISHED;
}
return OPERATOR_CANCELLED;
@@ -447,7 +444,6 @@ static void sample_draw(const bContext *C, ARegion *region, void *arg_info)
}
}
-/* Returns mouse position in image space. */
bool ED_space_node_get_position(
Main *bmain, SpaceNode *snode, struct ARegion *region, const int mval[2], float fpos[2])
{
@@ -475,9 +471,6 @@ bool ED_space_node_get_position(
return true;
}
-/* Returns color in linear space, matching ED_space_image_color_sample().
- * And here we've got recursion in the comments tips...
- */
bool ED_space_node_color_sample(
Main *bmain, SpaceNode *snode, ARegion *region, const int mval[2], float r_col[3])
{
@@ -738,7 +731,7 @@ static int space_node_view_geometry_nodes_legacy(bContext *C, SpaceNode *snode,
}
const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
- if (space_node_view_flag(C, snode, region, NODE_SELECT, smooth_viewtx)) {
+ if (space_node_view_flag(*C, *snode, *region, NODE_SELECT, smooth_viewtx)) {
return OPERATOR_FINISHED;
}
return OPERATOR_CANCELLED;
diff --git a/source/blender/editors/space_node/space_node.cc b/source/blender/editors/space_node/space_node.cc
index 784cf7d4dd8..4cc0bed1928 100644
--- a/source/blender/editors/space_node/space_node.cc
+++ b/source/blender/editors/space_node/space_node.cc
@@ -29,9 +29,6 @@
#include "MEM_guardedalloc.h"
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
-
#include "BKE_context.h"
#include "BKE_lib_id.h"
#include "BKE_node.h"
@@ -54,6 +51,8 @@
#include "node_intern.hh" /* own include */
+using blender::float2;
+
/* ******************** tree path ********************* */
void ED_node_tree_start(SpaceNode *snode, bNodeTree *ntree, ID *id, ID *from)
@@ -207,19 +206,14 @@ void ED_node_set_active_viewer_key(SpaceNode *snode)
}
}
-void space_node_group_offset(SpaceNode *snode, float *x, float *y)
+float2 space_node_group_offset(const SpaceNode &snode)
{
- bNodeTreePath *path = (bNodeTreePath *)snode->treepath.last;
+ const bNodeTreePath *path = (bNodeTreePath *)snode.treepath.last;
if (path && path->prev) {
- float dcenter[2];
- sub_v2_v2v2(dcenter, path->view_center, path->prev->view_center);
- *x = dcenter[0];
- *y = dcenter[1];
- }
- else {
- *x = *y = 0.0f;
+ return float2(path->view_center) - float2(path->prev->view_center);
}
+ return float2(0);
}
/* ******************** default callbacks for node space ***************** */
@@ -230,8 +224,8 @@ static SpaceLink *node_create(const ScrArea *UNUSED(area), const Scene *UNUSED(s
snode->spacetype = SPACE_NODE;
snode->flag = SNODE_SHOW_GPENCIL | SNODE_USE_ALPHA;
- snode->overlay.flag |= SN_OVERLAY_SHOW_OVERLAYS;
- snode->overlay.flag |= SN_OVERLAY_SHOW_WIRE_COLORS;
+ snode->overlay.flag = (SN_OVERLAY_SHOW_OVERLAYS | SN_OVERLAY_SHOW_WIRE_COLORS |
+ SN_OVERLAY_SHOW_PATH);
/* backdrop */
snode->zoom = 1.0f;
@@ -303,7 +297,10 @@ static void node_free(SpaceLink *sl)
MEM_freeN(path);
}
- MEM_SAFE_FREE(snode->runtime);
+ if (snode->runtime) {
+ snode->runtime->linkdrag.reset();
+ MEM_freeN(snode->runtime);
+ }
}
/* spacetype; init callback */
@@ -482,30 +479,10 @@ static void node_area_refresh(const struct bContext *C, ScrArea *area)
/* default now: refresh node is starting preview */
SpaceNode *snode = (SpaceNode *)area->spacedata.first;
- snode_set_context(C);
+ snode_set_context(*C);
if (snode->nodetree) {
- if (snode->nodetree->type == NTREE_SHADER) {
- if (GS(snode->id->name) == ID_MA) {
- Material *ma = (Material *)snode->id;
- if (ma->use_nodes) {
- ED_preview_shader_job(C, area, snode->id, nullptr, nullptr, 100, 100, PR_NODE_RENDER);
- }
- }
- else if (GS(snode->id->name) == ID_LA) {
- Light *la = (Light *)snode->id;
- if (la->use_nodes) {
- ED_preview_shader_job(C, area, snode->id, nullptr, nullptr, 100, 100, PR_NODE_RENDER);
- }
- }
- else if (GS(snode->id->name) == ID_WO) {
- World *wo = (World *)snode->id;
- if (wo->use_nodes) {
- ED_preview_shader_job(C, area, snode->id, nullptr, nullptr, 100, 100, PR_NODE_RENDER);
- }
- }
- }
- else if (snode->nodetree->type == NTREE_COMPOSIT) {
+ if (snode->nodetree->type == NTREE_COMPOSIT) {
Scene *scene = (Scene *)snode->id;
if (scene->use_nodes) {
/* recalc is set on 3d view changes for auto compo */
@@ -518,12 +495,6 @@ static void node_area_refresh(const struct bContext *C, ScrArea *area)
}
}
}
- else if (snode->nodetree->type == NTREE_TEXTURE) {
- Tex *tex = (Tex *)snode->id;
- if (tex->use_nodes) {
- ED_preview_shader_job(C, area, snode->id, nullptr, nullptr, 100, 100, PR_NODE_RENDER);
- }
- }
}
}
@@ -534,10 +505,7 @@ static SpaceLink *node_duplicate(SpaceLink *sl)
BLI_duplicatelist(&snoden->treepath, &snode->treepath);
- if (snode->runtime != nullptr) {
- snoden->runtime = (SpaceNode_Runtime *)MEM_dupallocN(snode->runtime);
- BLI_listbase_clear(&snoden->runtime->linkdrag);
- }
+ snoden->runtime = nullptr;
/* NOTE: no need to set node tree user counts,
* the editor only keeps at least 1 (id_us_ensure_real),
@@ -601,7 +569,7 @@ static void node_cursor(wmWindow *win, ScrArea *area, ARegion *region)
&snode->runtime->cursor[1]);
/* here snode->runtime->cursor is used to detect the node edge for sizing */
- node_set_cursor(win, snode, snode->runtime->cursor);
+ node_set_cursor(*win, *snode, snode->runtime->cursor);
/* XXX snode->runtime->cursor is in placing new nodes space */
snode->runtime->cursor[0] /= UI_DPI_FAC;
@@ -635,7 +603,7 @@ static void node_main_region_init(wmWindowManager *wm, ARegion *region)
static void node_main_region_draw(const bContext *C, ARegion *region)
{
- node_draw_space(C, region);
+ node_draw_space(*C, *region);
}
/* ************* dropboxes ************* */
@@ -758,7 +726,7 @@ static void node_header_region_init(wmWindowManager *UNUSED(wm), ARegion *region
static void node_header_region_draw(const bContext *C, ARegion *region)
{
/* find and set the context */
- snode_set_context(C);
+ snode_set_context(*C);
ED_region_header(C, region);
}
@@ -1001,8 +969,7 @@ static void node_space_subtype_item_extend(bContext *C, EnumPropertyItem **item,
}
}
-/* only called once, from space/spacetypes.c */
-void ED_spacetype_node(void)
+void ED_spacetype_node()
{
SpaceType *st = (SpaceType *)MEM_callocN(sizeof(SpaceType), "spacetype node");
ARegionType *art;
diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c
index ff0bd533671..946d7a0538d 100644
--- a/source/blender/editors/space_outliner/outliner_collections.c
+++ b/source/blender/editors/space_outliner/outliner_collections.c
@@ -134,11 +134,6 @@ TreeTraversalAction outliner_find_selected_objects(TreeElement *te, void *custom
return TRAVERSE_CONTINUE;
}
-/**
- * Populates the \param objects: ListBase with all the outliner selected objects
- * We store it as (Object *)LinkData->data
- * \param objects: expected to be empty
- */
void ED_outliner_selected_objects_get(const bContext *C, ListBase *objects)
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.c b/source/blender/editors/space_outliner/outliner_dragdrop.c
index ed52eeab98c..a4d5f2635d4 100644
--- a/source/blender/editors/space_outliner/outliner_dragdrop.c
+++ b/source/blender/editors/space_outliner/outliner_dragdrop.c
@@ -1515,7 +1515,6 @@ void OUTLINER_OT_item_drag_drop(wmOperatorType *ot)
/* *************************** Drop Boxes ************************** */
-/* region dropbox definition */
void outliner_dropboxes(void)
{
ListBase *lb = WM_dropboxmap_find("Outliner", SPACE_OUTLINER, RGN_TYPE_WINDOW);
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index 956c455c545..a586f268128 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -2368,6 +2368,9 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
case eGpencilModifierType_WeightAngle:
data.icon = ICON_MOD_VERTEX_WEIGHT;
break;
+ case eGpencilModifierType_Shrinkwrap:
+ data.icon = ICON_MOD_SHRINKWRAP;
+ break;
/* Default */
default:
@@ -2933,12 +2936,6 @@ static void outliner_draw_iconrow_doit(uiBlock *block,
(*offsx) += UI_UNIT_X;
}
-/**
- * Return the index to use based on the TreeElement ID and object type
- *
- * We use a continuum of indices until we get to the object data-blocks
- * and we then make room for the object types.
- */
int tree_element_id_type_to_index(TreeElement *te)
{
TreeStoreElem *tselem = TREESTORE(te);
diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c
index e449e4a609b..97e5c046452 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.c
@@ -78,8 +78,6 @@ static void outliner_show_active(SpaceOutliner *space_outliner,
TreeElement *te,
ID *id);
-/** \} */
-
/* -------------------------------------------------------------------- */
/** \name Highlight on Cursor Motion Operator
* \{ */
@@ -154,9 +152,6 @@ void OUTLINER_OT_highlight_update(wmOperatorType *ot)
/** \name Toggle Open/Closed Operator
* \{ */
-/**
- * Open or close a tree element, optionally toggling all children recursively.
- */
void outliner_item_openclose(SpaceOutliner *space_outliner,
TreeElement *te,
bool open,
@@ -708,6 +703,8 @@ void OUTLINER_OT_id_remap(wmOperatorType *ot)
prop = RNA_def_enum(ot->srna, "id_type", rna_enum_id_type_items, ID_OB, "ID Type", "");
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ID);
+ /* Changing ID type wont make sense, would return early with "Invalid old/new ID pair" anyways. */
+ RNA_def_property_flag(prop, PROP_HIDDEN);
prop = RNA_def_enum(ot->srna, "old_id", DummyRNA_NULL_items, 0, "Old ID", "Old ID to replace");
RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, outliner_id_itemf);
@@ -964,9 +961,6 @@ void OUTLINER_OT_lib_relocate(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* XXX This does not work with several items
- * (it is only called once in the end, due to the 'deferred'
- * file-browser invocation through event system...). */
void lib_relocate_fn(bContext *C,
ReportList *UNUSED(reports),
Scene *UNUSED(scene),
@@ -975,6 +969,10 @@ void lib_relocate_fn(bContext *C,
TreeStoreElem *tselem,
void *UNUSED(user_data))
{
+ /* XXX: This does not work with several items
+ * (it is only called once in the end, due to the 'deferred'
+ * file-browser invocation through event system...). */
+
wmOperatorType *ot = WM_operatortype_find("WM_OT_lib_relocate", false);
lib_relocate(C, te, tselem, ot, false);
@@ -1068,10 +1066,6 @@ int outliner_flag_is_any_test(ListBase *lb, short flag, const int curlevel)
return 0;
}
-/**
- * Set or unset \a flag for all outliner elements in \a lb and sub-trees.
- * \return if any flag was modified.
- */
bool outliner_flag_set(ListBase *lb, short flag, short set)
{
bool changed = false;
@@ -1225,7 +1219,6 @@ static void outliner_set_coordinates_element_recursive(SpaceOutliner *space_outl
}
}
-/* to retrieve coordinates with redrawing the entire tree */
void outliner_set_coordinates(ARegion *region, SpaceOutliner *space_outliner)
{
int starty = (int)(region->v2d.tot.ymax) - UI_UNIT_Y;
@@ -2234,8 +2227,6 @@ static bool ed_operator_outliner_id_orphans_active(bContext *C)
return true;
}
-/** \} */
-
static int outliner_orphans_purge_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
Main *bmain = CTX_data_main(C);
diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h
index 5336376b576..3439e4fa219 100644
--- a/source/blender/editors/space_outliner/outliner_intern.h
+++ b/source/blender/editors/space_outliner/outliner_intern.h
@@ -250,8 +250,17 @@ typedef enum TreeItemSelectAction {
void outliner_free_tree(ListBase *tree);
void outliner_cleanup_tree(struct SpaceOutliner *space_outliner);
+/**
+ * Free \a element and its sub-tree and remove its link in \a parent_subtree.
+ *
+ * \note Does not remove the #TreeStoreElem of \a element!
+ * \param parent_subtree: Sub-tree of the parent element, so the list containing \a element.
+ */
void outliner_free_tree_element(TreeElement *element, ListBase *parent_subtree);
+/**
+ * Main entry point for building the tree data-structure that the outliner represents.
+ */
void outliner_build_tree(struct Main *mainvar,
struct Scene *scene,
struct ViewLayer *view_layer,
@@ -260,6 +269,10 @@ void outliner_build_tree(struct Main *mainvar,
bool outliner_requires_rebuild_on_select_or_active_change(
const struct SpaceOutliner *space_outliner);
+/**
+ * Check if a display mode needs a full rebuild if the open/collapsed state changes.
+ * Element types in these modes don't actually add children if collapsed, so the rebuild is needed.
+ */
bool outliner_requires_rebuild_on_open_change(const struct SpaceOutliner *space_outliner);
typedef struct IDsSelectedData {
@@ -285,19 +298,34 @@ void outliner_collection_isolate_flag(struct Scene *scene,
const char *propname,
const bool value);
+/**
+ * Return the index to use based on the TreeElement ID and object type
+ *
+ * We use a continuum of indices until we get to the object data-blocks
+ * and we then make room for the object types.
+ */
int tree_element_id_type_to_index(TreeElement *te);
/* outliner_select.c -------------------------------------------- */
+/**
+ * Generic call for non-id data to make active in UI
+ */
void tree_element_type_active_set(struct bContext *C,
const TreeViewContext *tvc,
TreeElement *te,
TreeStoreElem *tselem,
const eOLSetState set,
bool recursive);
+/**
+ * Generic call for non-id data to check the active state in UI.
+ */
eOLDrawState tree_element_type_active_state_get(const struct bContext *C,
const struct TreeViewContext *tvc,
const TreeElement *te,
const TreeStoreElem *tselem);
+/**
+ * Generic call for ID data check or make/check active in UI.
+ */
void tree_element_activate(struct bContext *C,
const TreeViewContext *tvc,
TreeElement *te,
@@ -309,17 +337,32 @@ eOLDrawState tree_element_active_state_get(const TreeViewContext *tvc,
struct bPoseChannel *outliner_find_parent_bone(TreeElement *te, TreeElement **r_bone_te);
+/**
+ * Select the item using the set flags.
+ */
void outliner_item_select(struct bContext *C,
struct SpaceOutliner *space_outliner,
struct TreeElement *te,
const short select_flag);
+/**
+ * Find if x coordinate is over an icon or name.
+ */
bool outliner_item_is_co_over_name_icons(const TreeElement *te, float view_co_x);
bool outliner_item_is_co_over_icon(const TreeElement *te, float view_co_x);
+/**
+ * Find if x coordinate is over element name.
+ */
bool outliner_item_is_co_over_name(const TreeElement *te, float view_co_x);
+/**
+ * Find if x coordinate is over element disclosure toggle.
+ */
bool outliner_item_is_co_within_close_toggle(const TreeElement *te, float view_co_x);
bool outliner_is_co_within_mode_column(SpaceOutliner *space_outliner, const float view_mval[2]);
+/**
+ * Toggle the item's interaction mode if supported.
+ */
void outliner_item_mode_toggle(struct bContext *C,
TreeViewContext *tvc,
TreeElement *te,
@@ -334,6 +377,10 @@ typedef void (*outliner_operation_fn)(struct bContext *C,
TreeStoreElem *,
void *);
+/**
+ * \param recurse_selected: Set to false for operations which are already
+ * recursively operating on their children.
+ */
void outliner_do_object_operation_ex(struct bContext *C,
struct ReportList *reports,
struct Scene *scene,
@@ -350,6 +397,10 @@ void outliner_do_object_operation(struct bContext *C,
outliner_operation_fn operation_fn);
int outliner_flag_is_any_test(ListBase *lb, short flag, const int curlevel);
+/**
+ * Set or unset \a flag for all outliner elements in \a lb and sub-trees.
+ * \return if any flag was modified.
+ */
bool outliner_flag_set(ListBase *lb, short flag, short set);
bool outliner_flag_flip(ListBase *lb, short flag);
@@ -390,14 +441,24 @@ void id_remap_fn(struct bContext *C,
struct TreeStoreElem *tselem,
void *user_data);
+/**
+ * To retrieve coordinates with redrawing the entire tree.
+ */
void outliner_set_coordinates(struct ARegion *region, struct SpaceOutliner *space_outliner);
+/**
+ * Open or close a tree element, optionally toggling all children recursively.
+ */
void outliner_item_openclose(struct SpaceOutliner *space_outliner,
TreeElement *te,
bool open,
bool toggle_all);
/* outliner_dragdrop.c */
+
+/**
+ * Region drop-box definition.
+ */
void outliner_dropboxes(void);
void OUTLINER_OT_item_drag_drop(struct wmOperatorType *ot);
@@ -446,6 +507,8 @@ void merged_element_search_menu_invoke(struct bContext *C,
TreeElement *parent_te,
TreeElement *activate_te);
+/* Menu only! Calls other operators */
+
void OUTLINER_OT_operation(struct wmOperatorType *ot);
void OUTLINER_OT_scene_operation(struct wmOperatorType *ot);
void OUTLINER_OT_object_operation(struct wmOperatorType *ot);
@@ -510,19 +573,41 @@ void OUTLINER_OT_collection_color_tag_set(struct wmOperatorType *ot);
void outliner_viewcontext_init(const struct bContext *C, TreeViewContext *tvc);
+/**
+ * Try to find an item under y-coordinate \a view_co_y (view-space).
+ * \note Recursive
+ */
TreeElement *outliner_find_item_at_y(const SpaceOutliner *space_outliner,
const ListBase *tree,
float view_co_y);
+/**
+ * Collapsed items can show their children as click-able icons. This function tries to find
+ * such an icon that represents the child item at x-coordinate \a view_co_x (view-space).
+ *
+ * \return a hovered child item or \a parent_te (if no hovered child found).
+ */
TreeElement *outliner_find_item_at_x_in_row(const SpaceOutliner *space_outliner,
TreeElement *parent_te,
float view_co_x,
bool *r_is_merged_icon,
bool *r_is_over_icon);
+/**
+ * `tse` is not in the treestore, we use its contents to find a match.
+ */
TreeElement *outliner_find_tse(struct SpaceOutliner *space_outliner, const TreeStoreElem *tse);
+/**
+ * Find specific item from the trees-tore.
+ */
TreeElement *outliner_find_tree_element(ListBase *lb, const TreeStoreElem *store_elem);
+/**
+ * Find parent element of te.
+ */
TreeElement *outliner_find_parent_element(ListBase *lb,
TreeElement *parent_te,
const TreeElement *child_te);
+/**
+ * Find treestore that refers to given ID.
+ */
TreeElement *outliner_find_id(struct SpaceOutliner *space_outliner,
ListBase *lb,
const struct ID *id);
@@ -530,6 +615,14 @@ TreeElement *outliner_find_posechannel(ListBase *lb, const struct bPoseChannel *
TreeElement *outliner_find_editbone(ListBase *lb, const struct EditBone *ebone);
TreeElement *outliner_search_back_te(TreeElement *te, short idcode);
struct ID *outliner_search_back(TreeElement *te, short idcode);
+/**
+ * Iterate over all tree elements (pre-order traversal), executing \a func callback for
+ * each tree element matching the optional filters.
+ *
+ * \param filter_te_flag: If not 0, only TreeElements with this flag will be visited.
+ * \param filter_tselem_flag: Same as \a filter_te_flag, but for the TreeStoreElem.
+ * \param func: Custom callback to execute for each visited item.
+ */
bool outliner_tree_traverse(const SpaceOutliner *space_outliner,
ListBase *tree,
int filter_te_flag,
@@ -537,16 +630,33 @@ bool outliner_tree_traverse(const SpaceOutliner *space_outliner,
TreeTraversalFunc func,
void *customdata);
float outliner_restrict_columns_width(const struct SpaceOutliner *space_outliner);
+/**
+ * Find first tree element in tree with matching treestore flag.
+ */
TreeElement *outliner_find_element_with_flag(const ListBase *lb, short flag);
+/**
+ * Find if element is visible in the outliner tree.
+ */
bool outliner_is_element_visible(const TreeElement *te);
+/**
+ * Scroll view vertically while keeping within total bounds.
+ */
void outliner_scroll_view(struct SpaceOutliner *space_outliner,
struct ARegion *region,
int delta_y);
+/**
+ * The outliner should generally use #ED_region_tag_redraw_no_rebuild() to avoid unnecessary tree
+ * rebuilds. If elements are open or closed, we may still have to rebuild.
+ * Upon changing the open/closed state, call this to avoid rebuilds if possible.
+ */
void outliner_tag_redraw_avoid_rebuild_on_open_change(const struct SpaceOutliner *space_outliner,
struct ARegion *region);
/* outliner_sync.c ---------------------------------------------- */
+/**
+ * If outliner is dirty sync selection from view layer and sequencer.
+ */
void outliner_sync_selection(const struct bContext *C, struct SpaceOutliner *space_outliner);
/* outliner_context.c ------------------------------------------- */
diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c
index 5e409db0059..855975eb2dc 100644
--- a/source/blender/editors/space_outliner/outliner_select.c
+++ b/source/blender/editors/space_outliner/outliner_select.c
@@ -184,7 +184,6 @@ static void do_outliner_item_mode_toggle_generic(bContext *C, TreeViewContext *t
ED_undo_group_end(C);
}
-/* Toggle the item's interaction mode if supported */
void outliner_item_mode_toggle(bContext *C,
TreeViewContext *tvc,
TreeElement *te,
@@ -747,7 +746,6 @@ static void tree_element_text_activate(bContext *C, TreeElement *te)
/* ---------------------------------------------- */
-/* generic call for ID data check or make/check active in UI */
void tree_element_activate(bContext *C,
const TreeViewContext *tvc,
TreeElement *te,
@@ -778,9 +776,6 @@ void tree_element_activate(bContext *C,
}
}
-/**
- * Generic call for non-id data to make active in UI
- */
void tree_element_type_active_set(bContext *C,
const TreeViewContext *tvc,
TreeElement *te,
@@ -1086,9 +1081,6 @@ eOLDrawState tree_element_active_state_get(const TreeViewContext *tvc,
return OL_DRAWSEL_NONE;
}
-/**
- * Generic call for non-id data to check the active state in UI.
- */
eOLDrawState tree_element_type_active_state_get(const bContext *C,
const TreeViewContext *tvc,
const TreeElement *te,
@@ -1446,7 +1438,6 @@ static void do_outliner_item_activate_tree_element(bContext *C,
}
}
-/* Select the item using the set flags */
void outliner_item_select(bContext *C,
SpaceOutliner *space_outliner,
TreeElement *te,
diff --git a/source/blender/editors/space_outliner/outliner_sync.c b/source/blender/editors/space_outliner/outliner_sync.c
index d78767019b5..d95a0dde858 100644
--- a/source/blender/editors/space_outliner/outliner_sync.c
+++ b/source/blender/editors/space_outliner/outliner_sync.c
@@ -52,7 +52,6 @@
#include "outliner_intern.h"
-/* Functions for tagging outliner selection syncing is dirty from operators */
void ED_outliner_select_sync_from_object_tag(bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -89,7 +88,6 @@ bool ED_outliner_select_sync_is_dirty(const bContext *C)
return wm->outliner_sync_select_dirty & WM_OUTLINER_SYNC_SELECT_FROM_ALL;
}
-/* Copy sync select dirty flag from window manager to all outliners to be synced lazily on draw */
void ED_outliner_select_sync_flag_outliners(const bContext *C)
{
Main *bmain = CTX_data_main(C);
@@ -352,7 +350,6 @@ static void outliner_sync_selection_from_outliner(Scene *scene,
}
}
-/* Set clean outliner and mark other outliners for syncing */
void ED_outliner_select_sync_from_outliner(bContext *C, SpaceOutliner *space_outliner)
{
/* Don't sync if not checked or in certain outliner display modes */
@@ -547,7 +544,6 @@ static void get_sync_select_active_data(const bContext *C, SyncSelectActiveData
active_data->sequence = SEQ_select_active_get(scene);
}
-/* If outliner is dirty sync selection from view layer and sequencer. */
void outliner_sync_selection(const bContext *C, SpaceOutliner *space_outliner)
{
/* Set which types of data to sync from sync dirty flag and outliner display mode */
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index ae2b1870884..01f0feec771 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -1095,10 +1095,6 @@ static void singleuser_world_fn(bContext *C,
}
}
-/**
- * \param recurse_selected: Set to false for operations which are already
- * recursively operating on their children.
- */
void outliner_do_object_operation_ex(bContext *C,
ReportList *reports,
Scene *scene_act,
@@ -2984,7 +2980,6 @@ static int outliner_operation(bContext *C, wmOperator *op, const wmEvent *event)
return do_outliner_operation_event(C, op->reports, region, space_outliner, hovered_te);
}
-/* Menu only! Calls other operators */
void OUTLINER_OT_operation(wmOperatorType *ot)
{
ot->name = "Context Menu";
diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c
index 5427ae31ac3..3353726de18 100644
--- a/source/blender/editors/space_outliner/outliner_tree.c
+++ b/source/blender/editors/space_outliner/outliner_tree.c
@@ -203,12 +203,6 @@ void outliner_cleanup_tree(SpaceOutliner *space_outliner)
outliner_storage_cleanup(space_outliner);
}
-/**
- * Free \a element and its sub-tree and remove its link in \a parent_subtree.
- *
- * \note Does not remove the #TreeStoreElem of \a element!
- * \param parent_subtree: Sub-tree of the parent element, so the list containing \a element.
- */
void outliner_free_tree_element(TreeElement *element, ListBase *parent_subtree)
{
BLI_assert(BLI_findindex(parent_subtree, element) > -1);
@@ -235,10 +229,6 @@ bool outliner_requires_rebuild_on_select_or_active_change(const SpaceOutliner *s
return exclude_flags & (SO_FILTER_OB_STATE_SELECTED | SO_FILTER_OB_STATE_ACTIVE);
}
-/**
- * Check if a display mode needs a full rebuild if the open/collapsed state changes.
- * Element types in these modes don't actually add children if collapsed, so the rebuild is needed.
- */
bool outliner_requires_rebuild_on_open_change(const SpaceOutliner *space_outliner)
{
return ELEM(space_outliner->outlinevis, SO_DATA_API);
@@ -822,13 +812,6 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner,
}
}
-/**
- * TODO: this function needs to be split up! It's getting a bit too large...
- *
- * \note "ID" is not always a real ID.
- * \note If child items are only added to the tree if the item is open,
- * the `TSE_` type _must_ be added to #outliner_element_needs_rebuild_on_open_change().
- */
TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
ListBase *lb,
void *idv,
@@ -1176,7 +1159,6 @@ TreeElement *outliner_add_collection_recursive(SpaceOutliner *space_outliner,
/* Hierarchy --------------------------------------------- */
-/* make sure elements are correctly nested */
void outliner_make_object_parent_hierarchy(ListBase *lb)
{
/* build hierarchy */
@@ -1876,7 +1858,6 @@ static void outliner_clear_newid_from_main(Main *bmain)
/* ======================================================= */
/* Main Tree Building API */
-/* Main entry point for building the tree data-structure that the outliner represents. */
void outliner_build_tree(Main *mainvar,
Scene *scene,
ViewLayer *view_layer,
diff --git a/source/blender/editors/space_outliner/outliner_utils.c b/source/blender/editors/space_outliner/outliner_utils.c
index c62ca468747..d370d508198 100644
--- a/source/blender/editors/space_outliner/outliner_utils.c
+++ b/source/blender/editors/space_outliner/outliner_utils.c
@@ -71,10 +71,6 @@ void outliner_viewcontext_init(const bContext *C, TreeViewContext *tvc)
/** \} */
-/**
- * Try to find an item under y-coordinate \a view_co_y (view-space).
- * \note Recursive
- */
TreeElement *outliner_find_item_at_y(const SpaceOutliner *space_outliner,
const ListBase *tree,
float view_co_y)
@@ -142,12 +138,6 @@ static TreeElement *outliner_find_item_at_x_in_row_recursive(const TreeElement *
return (TreeElement *)parent_te;
}
-/**
- * Collapsed items can show their children as click-able icons. This function tries to find
- * such an icon that represents the child item at x-coordinate \a view_co_x (view-space).
- *
- * \return a hovered child item or \a parent_te (if no hovered child found).
- */
TreeElement *outliner_find_item_at_x_in_row(const SpaceOutliner *space_outliner,
TreeElement *parent_te,
float view_co_x,
@@ -167,7 +157,6 @@ TreeElement *outliner_find_item_at_x_in_row(const SpaceOutliner *space_outliner,
return te;
}
-/* Find specific item from the trees-tore. */
TreeElement *outliner_find_tree_element(ListBase *lb, const TreeStoreElem *store_elem)
{
LISTBASE_FOREACH (TreeElement *, te, lb) {
@@ -182,7 +171,6 @@ TreeElement *outliner_find_tree_element(ListBase *lb, const TreeStoreElem *store
return NULL;
}
-/* Find parent element of te */
TreeElement *outliner_find_parent_element(ListBase *lb,
TreeElement *parent_te,
const TreeElement *child_te)
@@ -200,7 +188,6 @@ TreeElement *outliner_find_parent_element(ListBase *lb,
return NULL;
}
-/* tse is not in the treestore, we use its contents to find a match */
TreeElement *outliner_find_tse(SpaceOutliner *space_outliner, const TreeStoreElem *tse)
{
TreeStoreElem *tselem;
@@ -219,7 +206,6 @@ TreeElement *outliner_find_tse(SpaceOutliner *space_outliner, const TreeStoreEle
return NULL;
}
-/* Find treestore that refers to given ID */
TreeElement *outliner_find_id(SpaceOutliner *space_outliner, ListBase *lb, const ID *id)
{
LISTBASE_FOREACH (TreeElement *, te, lb) {
@@ -302,14 +288,6 @@ ID *outliner_search_back(TreeElement *te, short idcode)
return NULL;
}
-/**
- * Iterate over all tree elements (pre-order traversal), executing \a func callback for
- * each tree element matching the optional filters.
- *
- * \param filter_te_flag: If not 0, only TreeElements with this flag will be visited.
- * \param filter_tselem_flag: Same as \a filter_te_flag, but for the TreeStoreElem.
- * \param func: Custom callback to execute for each visited item.
- */
bool outliner_tree_traverse(const SpaceOutliner *space_outliner,
ListBase *tree,
int filter_te_flag,
@@ -393,7 +371,6 @@ float outliner_restrict_columns_width(const SpaceOutliner *space_outliner)
return (num_columns * UI_UNIT_X + V2D_SCROLL_WIDTH);
}
-/* Find first tree element in tree with matching treestore flag */
TreeElement *outliner_find_element_with_flag(const ListBase *lb, short flag)
{
LISTBASE_FOREACH (TreeElement *, te, lb) {
@@ -408,7 +385,6 @@ TreeElement *outliner_find_element_with_flag(const ListBase *lb, short flag)
return NULL;
}
-/* Find if element is visible in the outliner tree */
bool outliner_is_element_visible(const TreeElement *te)
{
TreeStoreElem *tselem;
@@ -425,7 +401,6 @@ bool outliner_is_element_visible(const TreeElement *te)
return true;
}
-/* Find if x coordinate is over an icon or name */
bool outliner_item_is_co_over_name_icons(const TreeElement *te, float view_co_x)
{
/* Special case: count area left of Scene Collection as empty space */
@@ -441,19 +416,16 @@ bool outliner_item_is_co_over_icon(const TreeElement *te, float view_co_x)
return (view_co_x > (te->xs + UI_UNIT_X)) && (view_co_x < (te->xs + UI_UNIT_X * 2));
}
-/* Find if x coordinate is over element name. */
bool outliner_item_is_co_over_name(const TreeElement *te, float view_co_x)
{
return (view_co_x > (te->xs + UI_UNIT_X * 2)) && (view_co_x < te->xend);
}
-/* Find if x coordinate is over element disclosure toggle */
bool outliner_item_is_co_within_close_toggle(const TreeElement *te, float view_co_x)
{
return (view_co_x > te->xs) && (view_co_x < te->xs + UI_UNIT_X);
}
-/* Scroll view vertically while keeping within total bounds */
void outliner_scroll_view(SpaceOutliner *space_outliner, ARegion *region, int delta_y)
{
int tree_width, tree_height;
@@ -477,11 +449,6 @@ void outliner_scroll_view(SpaceOutliner *space_outliner, ARegion *region, int de
}
}
-/**
- * The outliner should generally use #ED_region_tag_redraw_no_rebuild() to avoid unnecessary tree
- * rebuilds. If elements are open or closed, we may still have to rebuild.
- * Upon changing the open/closed state, call this to avoid rebuilds if possible.
- */
void outliner_tag_redraw_avoid_rebuild_on_open_change(const SpaceOutliner *space_outliner,
ARegion *region)
{
@@ -494,7 +461,6 @@ void outliner_tag_redraw_avoid_rebuild_on_open_change(const SpaceOutliner *space
}
}
-/* Get base of object under cursor. Used for eyedropper tool */
Base *ED_outliner_give_base_under_cursor(bContext *C, const int mval[2])
{
ARegion *region = CTX_wm_region(C);
diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c
index 205f0117e6a..6c45d39e0d8 100644
--- a/source/blender/editors/space_outliner/space_outliner.c
+++ b/source/blender/editors/space_outliner/space_outliner.c
@@ -449,7 +449,6 @@ static void outliner_deactivate(struct ScrArea *area)
ED_region_tag_redraw_no_rebuild(BKE_area_find_region_type(area, RGN_TYPE_WINDOW));
}
-/* only called once, from space_api/spacetypes.c */
void ED_spacetype_outliner(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype time");
diff --git a/source/blender/editors/space_outliner/tree/tree_display.h b/source/blender/editors/space_outliner/tree/tree_display.h
index c0a751f2cd5..b6dc33ba7b7 100644
--- a/source/blender/editors/space_outliner/tree/tree_display.h
+++ b/source/blender/editors/space_outliner/tree/tree_display.h
@@ -49,12 +49,20 @@ ListBase outliner_tree_display_build_tree(TreeDisplay *tree_display, TreeSourceD
/* The following functions are needed to build the tree. They are calls back into C; the way
* elements are created should be refactored and ported to C++ with a new design/API too. */
+/**
+ * TODO: this function needs to be split up! It's getting a bit too large...
+ *
+ * \note "ID" is not always a real ID.
+ * \note If child items are only added to the tree if the item is open,
+ * the `TSE_` type _must_ be added to #outliner_element_needs_rebuild_on_open_change().
+ */
struct TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
ListBase *lb,
void *idv,
struct TreeElement *parent,
short type,
short index);
+/* make sure elements are correctly nested */
void outliner_make_object_parent_hierarchy(ListBase *lb);
bool outliner_animdata_test(const struct AnimData *adt);
TreeElement *outliner_add_collection_recursive(SpaceOutliner *space_outliner,
diff --git a/source/blender/editors/space_outliner/tree/tree_display.hh b/source/blender/editors/space_outliner/tree/tree_display.hh
index 8aaf396888f..54e64655b18 100644
--- a/source/blender/editors/space_outliner/tree/tree_display.hh
+++ b/source/blender/editors/space_outliner/tree/tree_display.hh
@@ -148,6 +148,9 @@ class TreeDisplaySequencer final : public AbstractTreeDisplay {
private:
TreeElement *add_sequencer_contents() const;
+ /**
+ * Helped function to put duplicate sequence in the same tree.
+ */
SequenceAddOp need_add_seq_dup(Sequence *seq) const;
void add_seq_dup(Sequence *seq, TreeElement *te, short index) const;
};
diff --git a/source/blender/editors/space_outliner/tree/tree_display_libraries.cc b/source/blender/editors/space_outliner/tree/tree_display_libraries.cc
index 371813cfb3f..836f0937cf4 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_libraries.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_libraries.cc
@@ -33,7 +33,6 @@
namespace blender::ed::outliner {
-/* Convenience/readability. */
template<typename T> using List = ListBaseWrapper<T>;
TreeDisplayLibraries::TreeDisplayLibraries(SpaceOutliner &space_outliner)
diff --git a/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc b/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc
index 69ccf014642..eeb3ca6893a 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc
@@ -31,7 +31,6 @@
namespace blender::ed::outliner {
-/* Convenience/readability. */
template<typename T> using List = ListBaseWrapper<T>;
TreeDisplayIDOrphans::TreeDisplayIDOrphans(SpaceOutliner &space_outliner)
diff --git a/source/blender/editors/space_outliner/tree/tree_display_override_library.cc b/source/blender/editors/space_outliner/tree/tree_display_override_library.cc
index 0e4636db69d..943e182277c 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_override_library.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_override_library.cc
@@ -34,6 +34,11 @@
namespace blender::ed::outliner {
/* Convenience/readability. */
+/* Convenience/readability. */
+/* Convenience/readability. */
+/* Convenience/readability. */
+/* Convenience/readability. */
+/* Convenience/readability. */
template<typename T> using List = ListBaseWrapper<T>;
TreeDisplayOverrideLibrary::TreeDisplayOverrideLibrary(SpaceOutliner &space_outliner)
diff --git a/source/blender/editors/space_outliner/tree/tree_display_scenes.cc b/source/blender/editors/space_outliner/tree/tree_display_scenes.cc
index 390f81cfcd1..29442aace37 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_scenes.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_scenes.cc
@@ -29,7 +29,6 @@
namespace blender::ed::outliner {
-/* Convenience/readability. */
template<typename T> using List = ListBaseWrapper<T>;
TreeDisplayScenes::TreeDisplayScenes(SpaceOutliner &space_outliner)
diff --git a/source/blender/editors/space_outliner/tree/tree_display_sequencer.cc b/source/blender/editors/space_outliner/tree/tree_display_sequencer.cc
index 02af6a13cb3..aa28b164584 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_sequencer.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_sequencer.cc
@@ -31,7 +31,6 @@
namespace blender::ed::outliner {
-/* Convenience/readability. */
template<typename T> using List = ListBaseWrapper<T>;
TreeDisplaySequencer::TreeDisplaySequencer(SpaceOutliner &space_outliner)
@@ -63,7 +62,6 @@ ListBase TreeDisplaySequencer::buildTree(const TreeSourceData &source_data)
return tree;
}
-/* Helped function to put duplicate sequence in the same tree. */
SequenceAddOp TreeDisplaySequencer::need_add_seq_dup(Sequence *seq) const
{
if ((!seq->strip) || (!seq->strip->stripdata)) {
diff --git a/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc b/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc
index c3d0aecd3cb..ebbc9baaa9f 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc
@@ -37,7 +37,6 @@
namespace blender::ed::outliner {
-/* Convenience/readability. */
template<typename T> using List = ListBaseWrapper<T>;
class ObjectsChildrenBuilder {
diff --git a/source/blender/editors/space_script/space_script.c b/source/blender/editors/space_script/space_script.c
index 11bee36e914..4c4cba2ac58 100644
--- a/source/blender/editors/space_script/space_script.c
+++ b/source/blender/editors/space_script/space_script.c
@@ -162,7 +162,6 @@ static void script_main_region_listener(const wmRegionListenerParams *UNUSED(par
#endif
}
-/* only called once, from space/spacetypes.c */
void ED_spacetype_script(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype script");
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index 2bbc346fb50..e814530d1e2 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -668,7 +668,6 @@ static void drawmeta_contents(Scene *scene,
GPU_blend(GPU_BLEND_NONE);
}
-/* Get handle width in 2d-View space. */
float sequence_handle_size_get_clamped(Sequence *seq, const float pixelx)
{
const float maxhandle = (pixelx * SEQ_HANDLE_SIZE) * U.pixelsize;
@@ -1517,13 +1516,6 @@ void ED_sequencer_special_preview_clear(void)
sequencer_special_update_set(NULL);
}
-/**
- * Rendering using opengl will change the current viewport/context.
- * This is why we need the \a region, to set back the render area.
- *
- * TODO: do not rely on such hack and just update the \a ibuf outside of
- * the UI drawing code.
- */
ImBuf *sequencer_ibuf_get(struct Main *bmain,
ARegion *region,
struct Depsgraph *depsgraph,
@@ -2097,6 +2089,10 @@ static int sequencer_draw_get_transform_preview_frame(Scene *scene)
static void seq_draw_image_origin_and_outline(const bContext *C, Sequence *seq, bool is_active_seq)
{
SpaceSeq *sseq = CTX_wm_space_seq(C);
+ const ARegion *region = CTX_wm_region(C);
+ if (region->regiontype == RGN_TYPE_PREVIEW && !sequencer_view_preview_only_poll(C)) {
+ return;
+ }
if ((seq->flag & SELECT) == 0) {
return;
}
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index 899c2f6b4f4..e9f37fa6838 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -127,7 +127,6 @@ bool ED_space_sequencer_maskedit_poll(bContext *C)
return false;
}
-/* Are we displaying the seq output (not channels or histogram). */
bool ED_space_sequencer_check_show_imbuf(SpaceSeq *sseq)
{
return (sseq->mainb == SEQ_DRAW_IMG_IMBUF) &&
@@ -152,12 +151,6 @@ static bool sequencer_fcurves_targets_color_strip(const FCurve *fcurve)
return true;
}
-/*
- * Check if there is animation shown during playback.
- *
- * - Colors of color strips are displayed on the strip itself.
- * - Backdrop is drawn.
- */
bool ED_space_sequencer_has_playback_animation(const struct SpaceSeq *sseq,
const struct Scene *scene)
{
@@ -187,7 +180,6 @@ bool ED_space_sequencer_has_playback_animation(const struct SpaceSeq *sseq,
/** \name Shared Poll Functions
* \{ */
-/* Operator functions. */
bool sequencer_edit_poll(bContext *C)
{
return (SEQ_editing_get(CTX_data_scene(C)) != NULL);
@@ -210,7 +202,7 @@ bool sequencer_strip_has_path_poll(bContext *C)
(SEQ_HAS_PATH(seq)));
}
-bool sequencer_view_preview_poll(bContext *C)
+bool sequencer_view_has_preview_poll(bContext *C)
{
SpaceSeq *sseq = CTX_wm_space_seq(C);
if (sseq == NULL) {
@@ -231,6 +223,26 @@ bool sequencer_view_preview_poll(bContext *C)
return true;
}
+bool sequencer_view_preview_only_poll(const bContext *C)
+{
+ SpaceSeq *sseq = CTX_wm_space_seq(C);
+ if (sseq == NULL) {
+ return false;
+ }
+ if (SEQ_editing_get(CTX_data_scene(C)) == NULL) {
+ return false;
+ }
+ if (!(ELEM(sseq->view, SEQ_VIEW_PREVIEW) && (sseq->mainb == SEQ_DRAW_IMG_IMBUF))) {
+ return false;
+ }
+ ARegion *region = CTX_wm_region(C);
+ if (!(region && region->regiontype == RGN_TYPE_PREVIEW)) {
+ return false;
+ }
+
+ return true;
+}
+
bool sequencer_view_strips_poll(bContext *C)
{
SpaceSeq *sseq = CTX_wm_space_seq(C);
@@ -1708,23 +1720,22 @@ static int sequencer_delete_exec(bContext *C, wmOperator *UNUSED(op))
Scene *scene = CTX_data_scene(C);
ListBase *seqbasep = SEQ_active_seqbase_get(SEQ_editing_get(scene));
+ if (sequencer_view_has_preview_poll(C) && !sequencer_view_preview_only_poll(C)) {
+ return OPERATOR_CANCELLED;
+ }
+
SEQ_prefetch_stop(scene);
- const bool is_preview = sequencer_view_preview_poll(C);
- if (is_preview) {
- SEQ_query_rendered_strips_to_tag(seqbasep, scene->r.cfra, 0);
- }
+ SeqCollection *selected_strips = selected_strips_from_context(C);
+ Sequence *seq;
- LISTBASE_FOREACH (Sequence *, seq, seqbasep) {
- if (is_preview && (seq->tmp_tag == false)) {
- continue;
- }
- if (seq->flag & SELECT) {
- SEQ_edit_flag_for_removal(scene, seqbasep, seq);
- }
+ SEQ_ITERATOR_FOREACH (seq, selected_strips) {
+ SEQ_edit_flag_for_removal(scene, seqbasep, seq);
}
SEQ_edit_remove_flagged_sequences(scene, seqbasep);
+ SEQ_collection_free(selected_strips);
+
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
@@ -3438,7 +3449,7 @@ void SEQUENCER_OT_cursor_set(wmOperatorType *ot)
/* api callbacks */
ot->exec = sequencer_set_2d_cursor_exec;
ot->invoke = sequencer_set_2d_cursor_invoke;
- ot->poll = sequencer_view_preview_poll;
+ ot->poll = sequencer_view_has_preview_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
diff --git a/source/blender/editors/space_sequencer/sequencer_intern.h b/source/blender/editors/space_sequencer/sequencer_intern.h
index 5982a0a8993..cb33c648b0a 100644
--- a/source/blender/editors/space_sequencer/sequencer_intern.h
+++ b/source/blender/editors/space_sequencer/sequencer_intern.h
@@ -34,6 +34,7 @@ struct Depsgraph;
struct Main;
struct Scene;
struct Sequence;
+struct SeqCollection;
struct SpaceSeq;
struct StripElem;
struct bContext;
@@ -60,11 +61,19 @@ void color3ubv_from_seq(const struct Scene *curscene,
uchar r_col[3]);
void sequencer_special_update_set(Sequence *seq);
+/* Get handle width in 2d-View space. */
float sequence_handle_size_get_clamped(struct Sequence *seq, const float pixelx);
/* UNUSED */
/* void seq_reset_imageofs(struct SpaceSeq *sseq); */
+/**
+ * Rendering using opengl will change the current viewport/context.
+ * This is why we need the \a region, to set back the render area.
+ *
+ * TODO: do not rely on such hack and just update the \a ibuf outside of
+ * the UI drawing code.
+ */
struct ImBuf *sequencer_ibuf_get(struct Main *bmain,
struct ARegion *region,
struct Depsgraph *depsgraph,
@@ -110,9 +119,29 @@ bool sequencer_edit_poll(struct bContext *C);
/* UNUSED */
/* bool sequencer_strip_poll(struct bContext *C); */
bool sequencer_strip_has_path_poll(struct bContext *C);
-bool sequencer_view_preview_poll(struct bContext *C);
+bool sequencer_view_has_preview_poll(struct bContext *C);
+bool sequencer_view_preview_only_poll(const struct bContext *C);
bool sequencer_view_strips_poll(struct bContext *C);
+/**
+ * Returns collection with all strips presented to user. If operation is done in preview,
+ * collection is limited to all presented strips that can produce image output.
+ *
+ * \param C: context
+ * \return collection of strips (`Sequence`)
+ */
+struct SeqCollection *all_strips_from_context(struct bContext *C);
+
+/**
+ * Returns collection with selected strips presented to user. If operation is done in preview,
+ * collection is limited to selected presented strips, that can produce image output at current
+ * frame.
+ *
+ * \param C: context
+ * \return collection of strips (`Sequence`)
+ */
+struct SeqCollection *selected_strips_from_context(struct bContext *C);
+
/* Externs. */
extern EnumPropertyItem sequencer_prop_effect_types[];
extern EnumPropertyItem prop_side_types[];
diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c
index 8a8a24f08ff..47696ab9256 100644
--- a/source/blender/editors/space_sequencer/sequencer_select.c
+++ b/source/blender/editors/space_sequencer/sequencer_select.c
@@ -64,6 +64,34 @@
/** \name Selection Utilities
* \{ */
+SeqCollection *all_strips_from_context(bContext *C)
+{
+ Scene *scene = CTX_data_scene(C);
+ ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene));
+
+ const bool is_preview = sequencer_view_has_preview_poll(C);
+ if (is_preview) {
+ return SEQ_query_rendered_strips(seqbase, scene->r.cfra, 0);
+ }
+
+ return SEQ_query_all_strips(seqbase);
+}
+
+SeqCollection *selected_strips_from_context(bContext *C)
+{
+ Scene *scene = CTX_data_scene(C);
+ ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene));
+
+ const bool is_preview = sequencer_view_has_preview_poll(C);
+ if (is_preview) {
+ SeqCollection *strips = SEQ_query_rendered_strips(seqbase, scene->r.cfra, 0);
+ SEQ_filter_selected_strips(strips);
+ return strips;
+ }
+
+ return SEQ_query_selected_strips(seqbase);
+}
+
static void select_surrounding_handles(Scene *scene, Sequence *test) /* XXX BRING BACK */
{
Sequence *neighbor;
@@ -411,22 +439,18 @@ static void sequencer_select_do_updates(bContext *C, Scene *scene)
static int sequencer_de_select_all_exec(bContext *C, wmOperator *op)
{
int action = RNA_enum_get(op->ptr, "action");
-
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene);
- Sequence *seq;
- const bool is_preview = sequencer_view_preview_poll(C);
- if (is_preview) {
- SEQ_query_rendered_strips_to_tag(ed->seqbasep, scene->r.cfra, 0);
+ if (sequencer_view_has_preview_poll(C) && !sequencer_view_preview_only_poll(C)) {
+ return OPERATOR_CANCELLED;
}
+ SeqCollection *strips = all_strips_from_context(C);
+ Sequence *seq;
+
if (action == SEL_TOGGLE) {
action = SEL_SELECT;
- for (seq = ed->seqbasep->first; seq; seq = seq->next) {
- if (is_preview && (seq->tmp_tag == false)) {
- continue;
- }
+ SEQ_ITERATOR_FOREACH (seq, strips) {
if (seq->flag & SEQ_ALLSEL) {
action = SEL_DESELECT;
break;
@@ -434,10 +458,7 @@ static int sequencer_de_select_all_exec(bContext *C, wmOperator *op)
}
}
- for (seq = ed->seqbasep->first; seq; seq = seq->next) {
- if (is_preview && (seq->tmp_tag == false)) {
- continue;
- }
+ SEQ_ITERATOR_FOREACH (seq, strips) {
switch (action) {
case SEL_SELECT:
seq->flag &= ~(SEQ_LEFTSEL + SEQ_RIGHTSEL);
@@ -458,8 +479,9 @@ static int sequencer_de_select_all_exec(bContext *C, wmOperator *op)
}
}
- ED_outliner_select_sync_from_sequence_tag(C);
+ SEQ_collection_free(strips);
+ ED_outliner_select_sync_from_sequence_tag(C);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
return OPERATOR_FINISHED;
@@ -491,18 +513,15 @@ void SEQUENCER_OT_select_all(struct wmOperatorType *ot)
static int sequencer_select_inverse_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene);
- Sequence *seq;
- const bool is_preview = sequencer_view_preview_poll(C);
- if (is_preview) {
- SEQ_query_rendered_strips_to_tag(ed->seqbasep, scene->r.cfra, 0);
+ if (sequencer_view_has_preview_poll(C) && !sequencer_view_preview_only_poll(C)) {
+ return OPERATOR_CANCELLED;
}
- for (seq = ed->seqbasep->first; seq; seq = seq->next) {
- if (is_preview && (seq->tmp_tag == false)) {
- continue;
- }
+ SeqCollection *strips = all_strips_from_context(C);
+ Sequence *seq;
+
+ SEQ_ITERATOR_FOREACH (seq, strips) {
if (seq->flag & SELECT) {
seq->flag &= ~SEQ_ALLSEL;
}
@@ -512,8 +531,9 @@ static int sequencer_select_inverse_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- ED_outliner_select_sync_from_sequence_tag(C);
+ SEQ_collection_free(strips);
+ ED_outliner_select_sync_from_sequence_tag(C);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
return OPERATOR_FINISHED;
@@ -866,6 +886,9 @@ static int sequencer_select_exec(bContext *C, wmOperator *op)
}
if (region->regiontype == RGN_TYPE_PREVIEW) {
+ if (!sequencer_view_preview_only_poll(C)) {
+ return OPERATOR_CANCELLED;
+ }
const SpaceSeq *sseq = CTX_wm_space_seq(C);
if (sseq->mainb != SEQ_DRAW_IMG_IMBUF) {
return OPERATOR_CANCELLED;
@@ -1612,6 +1635,9 @@ static int sequencer_box_select_exec(bContext *C, wmOperator *op)
ARegion *region = CTX_wm_region(C);
if (region->regiontype == RGN_TYPE_PREVIEW) {
+ if (!sequencer_view_preview_only_poll(C)) {
+ return OPERATOR_CANCELLED;
+ }
seq_box_select_seq_from_preview(C, &rectf, sel_op);
sequencer_select_do_updates(C, scene);
return OPERATOR_FINISHED;
@@ -1671,6 +1697,11 @@ static int sequencer_box_select_invoke(bContext *C, wmOperator *op, const wmEven
{
Scene *scene = CTX_data_scene(C);
View2D *v2d = &CTX_wm_region(C)->v2d;
+ ARegion *region = CTX_wm_region(C);
+
+ if (region->regiontype == RGN_TYPE_PREVIEW && !sequencer_view_preview_only_poll(C)) {
+ return OPERATOR_CANCELLED;
+ }
const bool tweak = RNA_boolean_get(op->ptr, "tweak");
@@ -1767,17 +1798,15 @@ static const EnumPropertyItem sequencer_prop_select_grouped_types[] = {
#define SEQ_CHANNEL_CHECK(_seq, _chan) (ELEM((_chan), 0, (_seq)->machine))
-static bool select_grouped_type(ListBase *seqbasep,
- const bool is_preview,
+static bool select_grouped_type(SeqCollection *strips,
+ ListBase *UNUSED(seqbase),
Sequence *actseq,
const int channel)
{
bool changed = false;
- LISTBASE_FOREACH (Sequence *, seq, seqbasep) {
- if (is_preview && (seq->tmp_tag == false)) {
- continue;
- }
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, strips) {
if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == actseq->type) {
seq->flag |= SELECT;
changed = true;
@@ -1787,18 +1816,16 @@ static bool select_grouped_type(ListBase *seqbasep,
return changed;
}
-static bool select_grouped_type_basic(ListBase *seqbase,
- const bool is_preview,
+static bool select_grouped_type_basic(SeqCollection *strips,
+ ListBase *UNUSED(seqbase),
Sequence *actseq,
const int channel)
{
bool changed = false;
const bool is_sound = SEQ_IS_SOUND(actseq);
- LISTBASE_FOREACH (Sequence *, seq, seqbase) {
- if (is_preview && (seq->tmp_tag == false)) {
- continue;
- }
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, strips) {
if (SEQ_CHANNEL_CHECK(seq, channel) && (is_sound ? SEQ_IS_SOUND(seq) : !SEQ_IS_SOUND(seq))) {
seq->flag |= SELECT;
changed = true;
@@ -1808,18 +1835,16 @@ static bool select_grouped_type_basic(ListBase *seqbase,
return changed;
}
-static bool select_grouped_type_effect(ListBase *seqbase,
- const bool is_preview,
+static bool select_grouped_type_effect(SeqCollection *strips,
+ ListBase *UNUSED(seqbase),
Sequence *actseq,
const int channel)
{
bool changed = false;
const bool is_effect = SEQ_IS_EFFECT(actseq);
- LISTBASE_FOREACH (Sequence *, seq, seqbase) {
- if (is_preview && (seq->tmp_tag == false)) {
- continue;
- }
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, strips) {
if (SEQ_CHANNEL_CHECK(seq, channel) &&
(is_effect ? SEQ_IS_EFFECT(seq) : !SEQ_IS_EFFECT(seq))) {
seq->flag |= SELECT;
@@ -1830,8 +1855,8 @@ static bool select_grouped_type_effect(ListBase *seqbase,
return changed;
}
-static bool select_grouped_data(ListBase *seqbase,
- const bool is_preview,
+static bool select_grouped_data(SeqCollection *strips,
+ ListBase *UNUSED(seqbase),
Sequence *actseq,
const int channel)
{
@@ -1842,11 +1867,10 @@ static bool select_grouped_data(ListBase *seqbase,
return changed;
}
+ Sequence *seq;
+
if (SEQ_HAS_PATH(actseq) && dir) {
- LISTBASE_FOREACH (Sequence *, seq, seqbase) {
- if (is_preview && (seq->tmp_tag == false)) {
- continue;
- }
+ SEQ_ITERATOR_FOREACH (seq, strips) {
if (SEQ_CHANNEL_CHECK(seq, channel) && SEQ_HAS_PATH(seq) && seq->strip &&
STREQ(seq->strip->dir, dir)) {
seq->flag |= SELECT;
@@ -1856,7 +1880,7 @@ static bool select_grouped_data(ListBase *seqbase,
}
else if (actseq->type == SEQ_TYPE_SCENE) {
Scene *sce = actseq->scene;
- LISTBASE_FOREACH (Sequence *, seq, seqbase) {
+ SEQ_ITERATOR_FOREACH (seq, strips) {
if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == SEQ_TYPE_SCENE && seq->scene == sce) {
seq->flag |= SELECT;
changed = true;
@@ -1865,7 +1889,7 @@ static bool select_grouped_data(ListBase *seqbase,
}
else if (actseq->type == SEQ_TYPE_MOVIECLIP) {
MovieClip *clip = actseq->clip;
- LISTBASE_FOREACH (Sequence *, seq, seqbase) {
+ SEQ_ITERATOR_FOREACH (seq, strips) {
if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == SEQ_TYPE_MOVIECLIP &&
seq->clip == clip) {
seq->flag |= SELECT;
@@ -1875,7 +1899,7 @@ static bool select_grouped_data(ListBase *seqbase,
}
else if (actseq->type == SEQ_TYPE_MASK) {
struct Mask *mask = actseq->mask;
- LISTBASE_FOREACH (Sequence *, seq, seqbase) {
+ SEQ_ITERATOR_FOREACH (seq, strips) {
if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == SEQ_TYPE_MASK && seq->mask == mask) {
seq->flag |= SELECT;
changed = true;
@@ -1886,8 +1910,8 @@ static bool select_grouped_data(ListBase *seqbase,
return changed;
}
-static bool select_grouped_effect(ListBase *seqbase,
- const bool is_preview,
+static bool select_grouped_effect(SeqCollection *strips,
+ ListBase *UNUSED(seqbase),
Sequence *actseq,
const int channel)
{
@@ -1898,20 +1922,15 @@ static bool select_grouped_effect(ListBase *seqbase,
effects[i] = false;
}
- LISTBASE_FOREACH (Sequence *, seq, seqbase) {
- if (is_preview && (seq->tmp_tag == false)) {
- continue;
- }
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, strips) {
if (SEQ_CHANNEL_CHECK(seq, channel) && (seq->type & SEQ_TYPE_EFFECT) &&
ELEM(actseq, seq->seq1, seq->seq2, seq->seq3)) {
effects[seq->type] = true;
}
}
- LISTBASE_FOREACH (Sequence *, seq, seqbase) {
- if (is_preview && (seq->tmp_tag == false)) {
- continue;
- }
+ SEQ_ITERATOR_FOREACH (seq, strips) {
if (SEQ_CHANNEL_CHECK(seq, channel) && effects[seq->type]) {
if (seq->seq1) {
seq->seq1->flag |= SELECT;
@@ -1929,14 +1948,14 @@ static bool select_grouped_effect(ListBase *seqbase,
return changed;
}
-static bool select_grouped_time_overlap(ListBase *seqbase, const bool is_preview, Sequence *actseq)
+static bool select_grouped_time_overlap(SeqCollection *strips,
+ ListBase *UNUSED(seqbase),
+ Sequence *actseq)
{
bool changed = false;
- LISTBASE_FOREACH (Sequence *, seq, seqbase) {
- if (is_preview && (seq->tmp_tag == false)) {
- continue;
- }
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, strips) {
if (seq->startdisp < actseq->enddisp && seq->enddisp > actseq->startdisp) {
seq->flag |= SELECT;
changed = true;
@@ -1965,31 +1984,26 @@ static void query_lower_channel_strips(Sequence *seq_reference,
/* Select all strips within time range and with lower channel of initial selection. Then select
* effect chains of these strips. */
-static bool select_grouped_effect_link(ListBase *seqbase,
- const bool is_preview,
+static bool select_grouped_effect_link(SeqCollection *strips,
+ ListBase *seqbase,
Sequence *UNUSED(actseq),
const int UNUSED(channel))
{
/* Get collection of strips. */
- SeqCollection *collection = SEQ_query_selected_strips(seqbase);
- const int selected_strip_count = BLI_gset_len(collection->set);
- SEQ_collection_expand(seqbase, collection, query_lower_channel_strips);
- SEQ_collection_expand(seqbase, collection, SEQ_query_strip_effect_chain);
+ SEQ_filter_selected_strips(strips);
+ const int selected_strip_count = SEQ_collection_len(strips);
+ SEQ_collection_expand(seqbase, strips, query_lower_channel_strips);
+ SEQ_collection_expand(seqbase, strips, SEQ_query_strip_effect_chain);
/* Check if other strips will be affected. */
- const bool changed = BLI_gset_len(collection->set) > selected_strip_count;
+ const bool changed = SEQ_collection_len(strips) > selected_strip_count;
/* Actual logic. */
Sequence *seq;
- SEQ_ITERATOR_FOREACH (seq, collection) {
- if (is_preview && (seq->tmp_tag == false)) {
- continue;
- }
+ SEQ_ITERATOR_FOREACH (seq, strips) {
seq->flag |= SELECT;
}
- SEQ_collection_free(collection);
-
return changed;
}
@@ -2003,15 +2017,14 @@ static int sequencer_select_grouped_exec(bContext *C, wmOperator *op)
ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene));
Sequence *actseq = SEQ_select_active_get(scene);
- const bool is_preview = sequencer_view_preview_poll(C);
- if (is_preview) {
- SEQ_query_rendered_strips_to_tag(seqbase, scene->r.cfra, 0);
- if (actseq && actseq->tmp_tag == false) {
- actseq = NULL;
- }
+ const bool is_preview = sequencer_view_has_preview_poll(C);
+ if (is_preview && !sequencer_view_preview_only_poll(C)) {
+ return OPERATOR_CANCELLED;
}
- if (actseq == NULL) {
+ SeqCollection *strips = all_strips_from_context(C);
+
+ if (actseq == NULL || (is_preview && !SEQ_collection_has_strip(actseq, strips))) {
BKE_report(op->reports, RPT_ERROR, "No active sequence!");
return OPERATOR_CANCELLED;
}
@@ -2031,31 +2044,33 @@ static int sequencer_select_grouped_exec(bContext *C, wmOperator *op)
switch (type) {
case SEQ_SELECT_GROUP_TYPE:
- changed |= select_grouped_type(seqbase, is_preview, actseq, channel);
+ changed |= select_grouped_type(strips, seqbase, actseq, channel);
break;
case SEQ_SELECT_GROUP_TYPE_BASIC:
- changed |= select_grouped_type_basic(seqbase, is_preview, actseq, channel);
+ changed |= select_grouped_type_basic(strips, seqbase, actseq, channel);
break;
case SEQ_SELECT_GROUP_TYPE_EFFECT:
- changed |= select_grouped_type_effect(seqbase, is_preview, actseq, channel);
+ changed |= select_grouped_type_effect(strips, seqbase, actseq, channel);
break;
case SEQ_SELECT_GROUP_DATA:
- changed |= select_grouped_data(seqbase, is_preview, actseq, channel);
+ changed |= select_grouped_data(strips, seqbase, actseq, channel);
break;
case SEQ_SELECT_GROUP_EFFECT:
- changed |= select_grouped_effect(seqbase, is_preview, actseq, channel);
+ changed |= select_grouped_effect(strips, seqbase, actseq, channel);
break;
case SEQ_SELECT_GROUP_EFFECT_LINK:
- changed |= select_grouped_effect_link(seqbase, is_preview, actseq, channel);
+ changed |= select_grouped_effect_link(strips, seqbase, actseq, channel);
break;
case SEQ_SELECT_GROUP_OVERLAP:
- changed |= select_grouped_time_overlap(seqbase, is_preview, actseq);
+ changed |= select_grouped_time_overlap(strips, seqbase, actseq);
break;
default:
BLI_assert(0);
break;
}
+ SEQ_collection_free(strips);
+
if (changed) {
ED_outliner_select_sync_from_sequence_tag(C);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
diff --git a/source/blender/editors/space_sequencer/sequencer_thumbnails.c b/source/blender/editors/space_sequencer/sequencer_thumbnails.c
index fe9cd44c5df..c6fecdb1fc6 100644
--- a/source/blender/editors/space_sequencer/sequencer_thumbnails.c
+++ b/source/blender/editors/space_sequencer/sequencer_thumbnails.c
@@ -452,7 +452,7 @@ void draw_seq_strip_thumbnail(View2D *v2d,
rcti crop;
/* If width of the strip too small ignore drawing thumbnails. */
- if ((y2 - y1) / pixely <= 40 * U.dpi_fac) {
+ if ((y2 - y1) / pixely <= 20 * U.dpi_fac) {
return;
}
diff --git a/source/blender/editors/space_sequencer/sequencer_view.c b/source/blender/editors/space_sequencer/sequencer_view.c
index 2d2e7de7135..360aa2253de 100644
--- a/source/blender/editors/space_sequencer/sequencer_view.c
+++ b/source/blender/editors/space_sequencer/sequencer_view.c
@@ -405,7 +405,7 @@ void SEQUENCER_OT_view_ghost_border(wmOperatorType *ot)
ot->invoke = WM_gesture_box_invoke;
ot->exec = view_ghost_border_exec;
ot->modal = WM_gesture_box_modal;
- ot->poll = sequencer_view_preview_poll;
+ ot->poll = sequencer_view_has_preview_poll;
ot->cancel = WM_gesture_box_cancel;
/* Flags. */
diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c
index 4b6c5e29d77..b93f421ff5c 100644
--- a/source/blender/editors/space_sequencer/space_sequencer.c
+++ b/source/blender/editors/space_sequencer/space_sequencer.c
@@ -28,6 +28,7 @@
#include "DNA_gpencil_types.h"
#include "DNA_mask_types.h"
#include "DNA_scene_types.h"
+#include "DNA_sound_types.h"
#include "MEM_guardedalloc.h"
@@ -400,7 +401,7 @@ static bool image_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
}
}
- return 0;
+ return WM_drag_is_ID_type(drag, ID_IM);
}
static bool movie_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
@@ -416,7 +417,8 @@ static bool movie_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
}
}
}
- return 0;
+
+ return WM_drag_is_ID_type(drag, ID_MC);
}
static bool sound_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
@@ -432,35 +434,61 @@ static bool sound_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
}
}
}
- return 0;
+
+ return WM_drag_is_ID_type(drag, ID_SO);
}
static void sequencer_drop_copy(wmDrag *drag, wmDropBox *drop)
{
- /* Copy drag path to properties. */
- if (RNA_struct_find_property(drop->ptr, "filepath")) {
- RNA_string_set(drop->ptr, "filepath", drag->path);
+ ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, 0);
+ /* ID dropped. */
+ if (id != NULL) {
+ const ID_Type id_type = GS(id->name);
+ if (id_type == ID_IM) {
+ Image *ima = (Image *)id;
+ PointerRNA itemptr;
+ char dir[FILE_MAX], file[FILE_MAX];
+ BLI_split_dirfile(ima->filepath, dir, file, sizeof(dir), sizeof(file));
+ RNA_string_set(drop->ptr, "directory", dir);
+ RNA_collection_clear(drop->ptr, "files");
+ RNA_collection_add(drop->ptr, "files", &itemptr);
+ RNA_string_set(&itemptr, "name", file);
+ }
+ else if (id_type == ID_MC) {
+ MovieClip *clip = (MovieClip *)id;
+ RNA_string_set(drop->ptr, "filepath", clip->filepath);
+ RNA_struct_property_unset(drop->ptr, "name");
+ }
+ else if (id_type == ID_SO) {
+ bSound *sound = (bSound *)id;
+ RNA_string_set(drop->ptr, "filepath", sound->filepath);
+ RNA_struct_property_unset(drop->ptr, "name");
+ }
}
+ /* Path dropped. */
+ else if (drag->path[0]) {
+ if (RNA_struct_find_property(drop->ptr, "filepath")) {
+ RNA_string_set(drop->ptr, "filepath", drag->path);
+ }
+ if (RNA_struct_find_property(drop->ptr, "directory")) {
+ PointerRNA itemptr;
+ char dir[FILE_MAX], file[FILE_MAX];
- if (RNA_struct_find_property(drop->ptr, "directory")) {
- PointerRNA itemptr;
- char dir[FILE_MAX], file[FILE_MAX];
-
- BLI_split_dirfile(drag->path, dir, file, sizeof(dir), sizeof(file));
+ BLI_split_dirfile(drag->path, dir, file, sizeof(dir), sizeof(file));
- RNA_string_set(drop->ptr, "directory", dir);
+ RNA_string_set(drop->ptr, "directory", dir);
- RNA_collection_clear(drop->ptr, "files");
- RNA_collection_add(drop->ptr, "files", &itemptr);
- RNA_string_set(&itemptr, "name", file);
+ RNA_collection_clear(drop->ptr, "files");
+ RNA_collection_add(drop->ptr, "files", &itemptr);
+ RNA_string_set(&itemptr, "name", file);
+ }
}
}
/* This region dropbox definition. */
-static void sequencer_dropboxes(void)
-{
- ListBase *lb = WM_dropboxmap_find("Sequencer", SPACE_SEQ, RGN_TYPE_WINDOW);
+static void sequencer_dropboxes_add_to_lb(ListBase *lb)
+{
WM_dropbox_add(
lb, "SEQUENCER_OT_image_strip_add", image_drop_poll, sequencer_drop_copy, NULL, NULL);
WM_dropbox_add(
@@ -469,6 +497,14 @@ static void sequencer_dropboxes(void)
lb, "SEQUENCER_OT_sound_strip_add", sound_drop_poll, sequencer_drop_copy, NULL, NULL);
}
+static void sequencer_dropboxes(void)
+{
+ ListBase *lb = WM_dropboxmap_find("Sequencer", SPACE_SEQ, RGN_TYPE_WINDOW);
+ sequencer_dropboxes_add_to_lb(lb);
+ lb = WM_dropboxmap_find("Sequencer", SPACE_SEQ, RGN_TYPE_PREVIEW);
+ sequencer_dropboxes_add_to_lb(lb);
+}
+
/* ************* end drop *********** */
/* DO NOT make this static, this hides the symbol and breaks API generation script. */
@@ -757,6 +793,9 @@ static void sequencer_preview_region_init(wmWindowManager *wm, ARegion *region)
/* Own keymap. */
keymap = WM_keymap_ensure(wm->defaultconf, "SequencerPreview", SPACE_SEQ, 0);
WM_event_add_keymap_handler_v2d_mask(&region->handlers, keymap);
+
+ ListBase *lb = WM_dropboxmap_find("Sequencer", SPACE_SEQ, RGN_TYPE_PREVIEW);
+ WM_event_add_dropbox_handler(&region->handlers, lb);
}
static void sequencer_preview_region_layout(const bContext *C, ARegion *region)
@@ -966,7 +1005,6 @@ static void sequencer_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_
/* ************************************* */
-/* Only called once, from space/spacetypes.c. */
void ED_spacetype_sequencer(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype sequencer");
diff --git a/source/blender/editors/space_spreadsheet/CMakeLists.txt b/source/blender/editors/space_spreadsheet/CMakeLists.txt
index 192b80881ee..f1db8dedf1a 100644
--- a/source/blender/editors/space_spreadsheet/CMakeLists.txt
+++ b/source/blender/editors/space_spreadsheet/CMakeLists.txt
@@ -41,22 +41,20 @@ set(SRC
spreadsheet_data_source.cc
spreadsheet_data_source_geometry.cc
spreadsheet_dataset_draw.cc
- spreadsheet_dataset_layout.cc
spreadsheet_draw.cc
spreadsheet_layout.cc
spreadsheet_ops.cc
+ spreadsheet_panels.cc
spreadsheet_row_filter.cc
spreadsheet_row_filter_ui.cc
spreadsheet_cache.hh
- spreadsheet_cell_value.hh
spreadsheet_column.hh
spreadsheet_column_values.hh
spreadsheet_context.hh
spreadsheet_data_source.hh
spreadsheet_data_source_geometry.hh
spreadsheet_dataset_draw.hh
- spreadsheet_dataset_layout.hh
spreadsheet_draw.hh
spreadsheet_intern.hh
spreadsheet_layout.hh
diff --git a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
index 50b67c55bd6..61cc70830af 100644
--- a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
+++ b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
@@ -41,6 +41,8 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "BLT_translation.h"
+
#include "BLF_api.h"
#include "spreadsheet_intern.hh"
@@ -321,6 +323,8 @@ static float get_default_column_width(const ColumnValues &values)
return 8.0f;
case SPREADSHEET_VALUE_TYPE_STRING:
return 5.0f;
+ case SPREADSHEET_VALUE_TYPE_UNKNOWN:
+ return 2.0f;
}
return float_width;
}
@@ -591,35 +595,10 @@ static void spreadsheet_dataset_region_listener(const wmRegionListenerParams *pa
spreadsheet_header_region_listener(params);
}
-static void spreadsheet_dataset_region_init(wmWindowManager *wm, ARegion *region)
-{
- region->v2d.scroll |= V2D_SCROLL_RIGHT;
- region->v2d.scroll &= ~(V2D_SCROLL_LEFT | V2D_SCROLL_TOP | V2D_SCROLL_BOTTOM);
- region->v2d.scroll |= V2D_SCROLL_HORIZONTAL_HIDE;
- region->v2d.scroll |= V2D_SCROLL_VERTICAL_HIDE;
-
- UI_view2d_region_reinit(&region->v2d, V2D_COMMONVIEW_LIST, region->winx, region->winy);
-
- wmKeyMap *keymap = WM_keymap_ensure(
- wm->defaultconf, "Spreadsheet Generic", SPACE_SPREADSHEET, 0);
- WM_event_add_keymap_handler(&region->handlers, keymap);
-}
-
static void spreadsheet_dataset_region_draw(const bContext *C, ARegion *region)
{
spreadsheet_update_context_path(C);
-
- View2D *v2d = &region->v2d;
- UI_view2d_view_ortho(v2d);
- UI_ThemeClearColor(TH_BACK);
-
- draw_dataset_in_region(C, region);
-
- /* reset view matrix */
- UI_view2d_view_restore(C);
-
- /* scrollers */
- UI_view2d_scrollers_draw(v2d, nullptr);
+ ED_region_panels(C, region);
}
static void spreadsheet_sidebar_init(wmWindowManager *wm, ARegion *region)
@@ -640,7 +619,7 @@ static void spreadsheet_right_region_listener(const wmRegionListenerParams *UNUS
{
}
-void ED_spacetype_spreadsheet(void)
+void ED_spacetype_spreadsheet()
{
SpaceType *st = (SpaceType *)MEM_callocN(sizeof(SpaceType), "spacetype spreadsheet");
ARegionType *art;
@@ -710,11 +689,12 @@ void ED_spacetype_spreadsheet(void)
/* regions: channels */
art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spreadsheet dataset region");
art->regionid = RGN_TYPE_CHANNELS;
- art->prefsizex = 200 + V2D_SCROLL_WIDTH;
+ art->prefsizex = 150 + V2D_SCROLL_WIDTH;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D;
- art->init = spreadsheet_dataset_region_init;
+ art->init = ED_region_panels_init;
art->draw = spreadsheet_dataset_region_draw;
art->listener = spreadsheet_dataset_region_listener;
+ blender::ed::spreadsheet::spreadsheet_data_set_region_panels_register(*art);
BLI_addhead(&st->regiontypes, art);
BKE_spacetype_register(st);
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh b/source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh
deleted file mode 100644
index c11b4a2b23d..00000000000
--- a/source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh
+++ /dev/null
@@ -1,64 +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.
- */
-
-#pragma once
-
-#include <optional>
-
-#include "BLI_color.hh"
-#include "BLI_float2.hh"
-#include "BLI_float3.hh"
-
-struct Collection;
-struct Object;
-
-namespace blender::ed::spreadsheet {
-
-struct ObjectCellValue {
- const Object *object;
-};
-
-struct CollectionCellValue {
- const Collection *collection;
-};
-
-struct GeometrySetCellValue {
- const GeometrySet *geometry_set;
-};
-
-/**
- * This is a type that can hold the value of a cell in a spreadsheet. This type allows us to
- * decouple the drawing of individual cells from the code that generates the data to be displayed.
- */
-class CellValue {
- public:
- /* The implementation just uses a bunch of `std::option` for now. Unfortunately, we cannot use
- * `std::variant` yet, due to missing compiler support. This type can really be optimized more,
- * but it does not really matter too much currently. */
-
- std::optional<int> value_int;
- std::optional<float> value_float;
- std::optional<bool> value_bool;
- std::optional<float2> value_float2;
- std::optional<float3> value_float3;
- std::optional<ColorGeometry4f> value_color;
- std::optional<ObjectCellValue> value_object;
- std::optional<CollectionCellValue> value_collection;
- std::optional<GeometrySetCellValue> value_geometry_set;
- std::optional<std::string> value_string;
-};
-
-} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_column.cc b/source/blender/editors/space_spreadsheet/spreadsheet_column.cc
index ee08c86b29f..7551593ef38 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_column.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_column.cc
@@ -18,14 +18,52 @@
#include "MEM_guardedalloc.h"
+#include "BLI_color.hh"
+#include "BLI_float2.hh"
+#include "BLI_float3.hh"
#include "BLI_hash.hh"
#include "BLI_string.h"
#include "BLI_string_ref.hh"
+#include "BKE_geometry_set.hh"
+
+#include "FN_cpp_type.hh"
+
#include "spreadsheet_column.hh"
+#include "spreadsheet_column_values.hh"
namespace blender::ed::spreadsheet {
+eSpreadsheetColumnValueType cpp_type_to_column_type(const fn::CPPType &type)
+{
+ if (type.is<bool>()) {
+ return SPREADSHEET_VALUE_TYPE_BOOL;
+ }
+ if (type.is<int>()) {
+ return SPREADSHEET_VALUE_TYPE_INT32;
+ }
+ if (type.is<float>()) {
+ return SPREADSHEET_VALUE_TYPE_FLOAT;
+ }
+ if (type.is<float2>()) {
+ return SPREADSHEET_VALUE_TYPE_FLOAT2;
+ }
+ if (type.is<float3>()) {
+ return SPREADSHEET_VALUE_TYPE_FLOAT3;
+ }
+ if (type.is<ColorGeometry4f>()) {
+ return SPREADSHEET_VALUE_TYPE_COLOR;
+ }
+ if (type.is<std::string>()) {
+ return SPREADSHEET_VALUE_TYPE_STRING;
+ }
+ if (type.is<InstanceReference>()) {
+ return SPREADSHEET_VALUE_TYPE_INSTANCES;
+ }
+
+ return SPREADSHEET_VALUE_TYPE_UNKNOWN;
+}
+
SpreadsheetColumnID *spreadsheet_column_id_new()
{
SpreadsheetColumnID *column_id = (SpreadsheetColumnID *)MEM_callocN(sizeof(SpreadsheetColumnID),
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh b/source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh
index 877651d6530..83e3217e5c8 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh
@@ -20,33 +20,36 @@
#include "BLI_string_ref.hh"
-#include "spreadsheet_cell_value.hh"
+#include "FN_generic_virtual_array.hh"
namespace blender::ed::spreadsheet {
+struct CellDrawParams;
+
+eSpreadsheetColumnValueType cpp_type_to_column_type(const fn::CPPType &type);
+
/**
* This represents a column in a spreadsheet. It has a name and provides a value for all the cells
* in the column.
*/
-class ColumnValues {
+class ColumnValues final {
protected:
- eSpreadsheetColumnValueType type_;
std::string name_;
- int size_;
+
+ fn::GVArray data_;
public:
- ColumnValues(const eSpreadsheetColumnValueType type, std::string name, const int size)
- : type_(type), name_(std::move(name)), size_(size)
+ ColumnValues(std::string name, fn::GVArray data) : name_(std::move(name)), data_(std::move(data))
{
+ /* The array should not be empty. */
+ BLI_assert(data_);
}
virtual ~ColumnValues() = default;
- virtual void get_value(int index, CellValue &r_cell_value) const = 0;
-
eSpreadsheetColumnValueType type() const
{
- return type_;
+ return cpp_type_to_column_type(data_.type());
}
StringRefNull name() const
@@ -56,45 +59,16 @@ class ColumnValues {
int size() const
{
- return size_;
+ return data_.size();
}
- /* The default width of newly created columns, in UI units. */
- float default_width = 0.0f;
-};
-
-/* Utility class for the function below. */
-template<typename GetValueF> class LambdaColumnValues : public ColumnValues {
- private:
- GetValueF get_value_;
-
- public:
- LambdaColumnValues(const eSpreadsheetColumnValueType type,
- std::string name,
- int size,
- GetValueF get_value)
- : ColumnValues(type, std::move(name), size), get_value_(std::move(get_value))
+ const fn::GVArray &data() const
{
+ return data_;
}
- void get_value(int index, CellValue &r_cell_value) const final
- {
- get_value_(index, r_cell_value);
- }
+ /* The default width of newly created columns, in UI units. */
+ float default_width = 0.0f;
};
-/* Utility function that simplifies creating a spreadsheet column from a lambda function. */
-template<typename GetValueF>
-std::unique_ptr<ColumnValues> column_values_from_function(const eSpreadsheetColumnValueType type,
- std::string name,
- const int size,
- GetValueF get_value,
- const float default_width = 0.0f)
-{
- std::unique_ptr<ColumnValues> column_values = std::make_unique<LambdaColumnValues<GetValueF>>(
- type, std::move(name), size, std::move(get_value));
- column_values->default_width = default_width;
- return column_values;
-}
-
} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
index fef84719bc4..337a6037c42 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
@@ -14,6 +14,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include "BLI_virtual_array.hh"
+
#include "BKE_context.h"
#include "BKE_editmesh.h"
#include "BKE_lib_id.h"
@@ -51,30 +53,6 @@ using blender::fn::GField;
namespace blender::ed::spreadsheet {
-static std::optional<eSpreadsheetColumnValueType> cpp_type_to_column_value_type(
- const fn::CPPType &type)
-{
- if (type.is<bool>()) {
- return SPREADSHEET_VALUE_TYPE_BOOL;
- }
- if (type.is<int>()) {
- return SPREADSHEET_VALUE_TYPE_INT32;
- }
- if (type.is<float>()) {
- return SPREADSHEET_VALUE_TYPE_FLOAT;
- }
- if (type.is<float2>()) {
- return SPREADSHEET_VALUE_TYPE_FLOAT2;
- }
- if (type.is<float3>()) {
- return SPREADSHEET_VALUE_TYPE_FLOAT3;
- }
- if (type.is<ColorGeometry4f>()) {
- return SPREADSHEET_VALUE_TYPE_COLOR;
- }
- return std::nullopt;
-}
-
void ExtraColumns::foreach_default_column_ids(
FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const
{
@@ -92,39 +70,7 @@ std::unique_ptr<ColumnValues> ExtraColumns::get_column_values(
if (values == nullptr) {
return {};
}
- eSpreadsheetColumnValueType column_type = *cpp_type_to_column_value_type(values->type());
- return column_values_from_function(column_type,
- column_id.name,
- values->size(),
- [column_type, values](int index, CellValue &r_cell_value) {
- const void *value = (*values)[index];
- switch (column_type) {
- case SPREADSHEET_VALUE_TYPE_BOOL:
- r_cell_value.value_bool = *(const bool *)value;
- break;
- case SPREADSHEET_VALUE_TYPE_INT32:
- r_cell_value.value_int = *(const int *)value;
- break;
- case SPREADSHEET_VALUE_TYPE_FLOAT:
- r_cell_value.value_float = *(const float *)value;
- break;
- case SPREADSHEET_VALUE_TYPE_FLOAT2:
- r_cell_value.value_float2 = *(const float2 *)value;
- break;
- case SPREADSHEET_VALUE_TYPE_FLOAT3:
- r_cell_value.value_float3 = *(const float3 *)value;
- break;
- case SPREADSHEET_VALUE_TYPE_COLOR:
- r_cell_value.value_color = *(
- const ColorGeometry4f *)value;
- break;
- case SPREADSHEET_VALUE_TYPE_STRING:
- r_cell_value.value_string = *(const std::string *)value;
- break;
- case SPREADSHEET_VALUE_TYPE_INSTANCES:
- break;
- }
- });
+ return std::make_unique<ColumnValues>(column_id.name, fn::GVArray::ForSpan(*values));
}
void GeometryDataSource::foreach_default_column_ids(
@@ -134,6 +80,10 @@ void GeometryDataSource::foreach_default_column_ids(
return;
}
+ if (component_->type() == GEO_COMPONENT_TYPE_INSTANCES) {
+ fn({(char *)"Name"}, false);
+ }
+
extra_columns_.foreach_default_column_ids(fn);
component_->attribute_foreach(
[&](const bke::AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
@@ -148,12 +98,18 @@ void GeometryDataSource::foreach_default_column_ids(
fn(column_id, false);
return true;
});
+
+ if (component_->type() == GEO_COMPONENT_TYPE_INSTANCES) {
+ fn({(char *)"Rotation"}, false);
+ fn({(char *)"Scale"}, false);
+ }
}
std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
const SpreadsheetColumnID &column_id) const
{
- if (component_->attribute_domain_size(domain_) == 0) {
+ const int domain_size = component_->attribute_domain_size(domain_);
+ if (domain_size == 0) {
return {};
}
@@ -164,6 +120,33 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
return extra_column_values;
}
+ if (component_->type() == GEO_COMPONENT_TYPE_INSTANCES) {
+ const InstancesComponent &instances = static_cast<const InstancesComponent &>(*component_);
+ if (STREQ(column_id.name, "Name")) {
+ Span<int> reference_handles = instances.instance_reference_handles();
+ Span<InstanceReference> references = instances.references();
+ return std::make_unique<ColumnValues>(
+ column_id.name,
+ VArray<InstanceReference>::ForFunc(domain_size,
+ [reference_handles, references](int64_t index) {
+ return references[reference_handles[index]];
+ }));
+ }
+ Span<float4x4> transforms = instances.instance_transforms();
+ if (STREQ(column_id.name, "Rotation")) {
+ return std::make_unique<ColumnValues>(
+ column_id.name, VArray<float3>::ForFunc(domain_size, [transforms](int64_t index) {
+ return transforms[index].to_euler();
+ }));
+ }
+ if (STREQ(column_id.name, "Scale")) {
+ return std::make_unique<ColumnValues>(
+ column_id.name, VArray<float3>::ForFunc(domain_size, [transforms](int64_t index) {
+ return transforms[index].scale();
+ }));
+ }
+ }
+
bke::ReadAttributeLookup attribute = component_->attribute_try_get_for_read(column_id.name);
if (!attribute) {
return {};
@@ -172,72 +155,8 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
if (attribute.domain != domain_) {
return {};
}
- int domain_size = varray.size();
- const CustomDataType type = bke::cpp_type_to_custom_data_type(varray.type());
- switch (type) {
- case CD_PROP_FLOAT:
- return column_values_from_function(SPREADSHEET_VALUE_TYPE_FLOAT,
- column_id.name,
- domain_size,
- [varray](int index, CellValue &r_cell_value) {
- float value;
- varray.get(index, &value);
- r_cell_value.value_float = value;
- });
- case CD_PROP_INT32:
- return column_values_from_function(
- SPREADSHEET_VALUE_TYPE_INT32,
- column_id.name,
- domain_size,
- [varray](int index, CellValue &r_cell_value) {
- int value;
- varray.get(index, &value);
- r_cell_value.value_int = value;
- },
- STREQ(column_id.name, "id") ? 5.5f : 0.0f);
- case CD_PROP_BOOL:
- return column_values_from_function(SPREADSHEET_VALUE_TYPE_BOOL,
- column_id.name,
- domain_size,
- [varray](int index, CellValue &r_cell_value) {
- bool value;
- varray.get(index, &value);
- r_cell_value.value_bool = value;
- });
- case CD_PROP_FLOAT2: {
- return column_values_from_function(SPREADSHEET_VALUE_TYPE_FLOAT2,
- column_id.name,
- domain_size,
- [varray](int index, CellValue &r_cell_value) {
- float2 value;
- varray.get(index, &value);
- r_cell_value.value_float2 = value;
- });
- }
- case CD_PROP_FLOAT3: {
- return column_values_from_function(SPREADSHEET_VALUE_TYPE_FLOAT3,
- column_id.name,
- domain_size,
- [varray](int index, CellValue &r_cell_value) {
- float3 value;
- varray.get(index, &value);
- r_cell_value.value_float3 = value;
- });
- }
- case CD_PROP_COLOR: {
- return column_values_from_function(SPREADSHEET_VALUE_TYPE_COLOR,
- column_id.name,
- domain_size,
- [varray](int index, CellValue &r_cell_value) {
- ColorGeometry4f value;
- varray.get(index, &value);
- r_cell_value.value_color = value;
- });
- }
- default:
- break;
- }
- return {};
+
+ return std::make_unique<ColumnValues>(column_id.name, std::move(varray));
}
int GeometryDataSource::tot_rows() const
@@ -245,90 +164,6 @@ int GeometryDataSource::tot_rows() const
return component_->attribute_domain_size(domain_);
}
-using IsVertexSelectedFn = FunctionRef<bool(int vertex_index)>;
-
-static void get_selected_vertex_indices(const Mesh &mesh,
- const IsVertexSelectedFn is_vertex_selected_fn,
- MutableSpan<bool> selection)
-{
- for (const int i : IndexRange(mesh.totvert)) {
- if (!selection[i]) {
- continue;
- }
- if (!is_vertex_selected_fn(i)) {
- selection[i] = false;
- }
- }
-}
-
-static void get_selected_corner_indices(const Mesh &mesh,
- const IsVertexSelectedFn is_vertex_selected_fn,
- MutableSpan<bool> selection)
-{
- for (const int i : IndexRange(mesh.totloop)) {
- const MLoop &loop = mesh.mloop[i];
- if (!selection[i]) {
- continue;
- }
- if (!is_vertex_selected_fn(loop.v)) {
- selection[i] = false;
- }
- }
-}
-
-static void get_selected_face_indices(const Mesh &mesh,
- const IsVertexSelectedFn is_vertex_selected_fn,
- MutableSpan<bool> selection)
-{
- for (const int poly_index : IndexRange(mesh.totpoly)) {
- if (!selection[poly_index]) {
- continue;
- }
- const MPoly &poly = mesh.mpoly[poly_index];
- for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
- const MLoop &loop = mesh.mloop[loop_index];
- if (!is_vertex_selected_fn(loop.v)) {
- selection[poly_index] = false;
- break;
- }
- }
- }
-}
-
-static void get_selected_edge_indices(const Mesh &mesh,
- const IsVertexSelectedFn is_vertex_selected_fn,
- MutableSpan<bool> selection)
-{
- for (const int i : IndexRange(mesh.totedge)) {
- if (!selection[i]) {
- continue;
- }
- const MEdge &edge = mesh.medge[i];
- if (!is_vertex_selected_fn(edge.v1) || !is_vertex_selected_fn(edge.v2)) {
- selection[i] = false;
- }
- }
-}
-
-static void get_selected_indices_on_domain(const Mesh &mesh,
- const AttributeDomain domain,
- const IsVertexSelectedFn is_vertex_selected_fn,
- MutableSpan<bool> selection)
-{
- switch (domain) {
- case ATTR_DOMAIN_POINT:
- return get_selected_vertex_indices(mesh, is_vertex_selected_fn, selection);
- case ATTR_DOMAIN_FACE:
- return get_selected_face_indices(mesh, is_vertex_selected_fn, selection);
- case ATTR_DOMAIN_CORNER:
- return get_selected_corner_indices(mesh, is_vertex_selected_fn, selection);
- case ATTR_DOMAIN_EDGE:
- return get_selected_edge_indices(mesh, is_vertex_selected_fn, selection);
- default:
- return;
- }
-}
-
/**
* Only data sets corresponding to mesh objects in edit mode currently support selection filtering.
*/
@@ -348,7 +183,18 @@ bool GeometryDataSource::has_selection_filter() const
return true;
}
-void GeometryDataSource::apply_selection_filter(MutableSpan<bool> rows_included) const
+static IndexMask index_mask_from_bool_array(const VArray<bool> &selection,
+ Vector<int64_t> &indices)
+{
+ for (const int i : selection.index_range()) {
+ if (selection[i]) {
+ indices.append(i);
+ }
+ }
+ return IndexMask(indices);
+}
+
+IndexMask GeometryDataSource::apply_selection_filter(Vector<int64_t> &indices) const
{
std::lock_guard lock{mutex_};
@@ -364,136 +210,38 @@ void GeometryDataSource::apply_selection_filter(MutableSpan<bool> rows_included)
int *orig_indices = (int *)CustomData_get_layer(&mesh_eval->vdata, CD_ORIGINDEX);
if (orig_indices != nullptr) {
/* Use CD_ORIGINDEX layer if it exists. */
- auto is_vertex_selected = [&](int vertex_index) -> bool {
- const int i_orig = orig_indices[vertex_index];
- if (i_orig < 0) {
- return false;
- }
- if (i_orig >= bm->totvert) {
- return false;
- }
- BMVert *vert = bm->vtable[i_orig];
- return BM_elem_flag_test(vert, BM_ELEM_SELECT);
- };
- get_selected_indices_on_domain(*mesh_eval, domain_, is_vertex_selected, rows_included);
- }
- else if (mesh_eval->totvert == bm->totvert) {
+ VArray<bool> selection = mesh_component->attribute_try_adapt_domain<bool>(
+ VArray<bool>::ForFunc(mesh_eval->totvert,
+ [bm, orig_indices](int vertex_index) -> bool {
+ const int i_orig = orig_indices[vertex_index];
+ if (i_orig < 0) {
+ return false;
+ }
+ if (i_orig >= bm->totvert) {
+ return false;
+ }
+ BMVert *vert = bm->vtable[i_orig];
+ return BM_elem_flag_test(vert, BM_ELEM_SELECT);
+ }),
+ ATTR_DOMAIN_POINT,
+ domain_);
+ return index_mask_from_bool_array(selection, indices);
+ }
+
+ if (mesh_eval->totvert == bm->totvert) {
/* Use a simple heuristic to match original vertices to evaluated ones. */
- auto is_vertex_selected = [&](int vertex_index) -> bool {
- BMVert *vert = bm->vtable[vertex_index];
- return BM_elem_flag_test(vert, BM_ELEM_SELECT);
- };
- get_selected_indices_on_domain(*mesh_eval, domain_, is_vertex_selected, rows_included);
- }
-}
-
-void InstancesDataSource::foreach_default_column_ids(
- FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const
-{
- if (component_->instances_amount() == 0) {
- return;
- }
-
- extra_columns_.foreach_default_column_ids(fn);
-
- SpreadsheetColumnID column_id;
- column_id.name = (char *)"Name";
- fn(column_id, false);
- for (const char *name : {"Position", "Rotation", "Scale", "id"}) {
- column_id.name = (char *)name;
- fn(column_id, false);
- }
-}
-
-std::unique_ptr<ColumnValues> InstancesDataSource::get_column_values(
- const SpreadsheetColumnID &column_id) const
-{
- if (component_->instances_amount() == 0) {
- return {};
- }
-
- std::unique_ptr<ColumnValues> extra_column_values = extra_columns_.get_column_values(column_id);
- if (extra_column_values) {
- return extra_column_values;
- }
-
- const int size = this->tot_rows();
- if (STREQ(column_id.name, "Name")) {
- Span<int> reference_handles = component_->instance_reference_handles();
- Span<InstanceReference> references = component_->references();
- std::unique_ptr<ColumnValues> values = column_values_from_function(
- SPREADSHEET_VALUE_TYPE_INSTANCES,
- "Name",
- size,
- [reference_handles, references](int index, CellValue &r_cell_value) {
- const InstanceReference &reference = references[reference_handles[index]];
- switch (reference.type()) {
- case InstanceReference::Type::Object: {
- Object &object = reference.object();
- r_cell_value.value_object = ObjectCellValue{&object};
- break;
- }
- case InstanceReference::Type::Collection: {
- Collection &collection = reference.collection();
- r_cell_value.value_collection = CollectionCellValue{&collection};
- break;
- }
- case InstanceReference::Type::GeometrySet: {
- const GeometrySet &geometry_set = reference.geometry_set();
- r_cell_value.value_geometry_set = GeometrySetCellValue{&geometry_set};
- break;
- }
- case InstanceReference::Type::None: {
- break;
- }
- }
- });
- return values;
- }
- Span<float4x4> transforms = component_->instance_transforms();
- if (STREQ(column_id.name, "Position")) {
- return column_values_from_function(
- SPREADSHEET_VALUE_TYPE_FLOAT3,
- column_id.name,
- size,
- [transforms](int index, CellValue &r_cell_value) {
- r_cell_value.value_float3 = transforms[index].translation();
- });
- }
- if (STREQ(column_id.name, "Rotation")) {
- return column_values_from_function(SPREADSHEET_VALUE_TYPE_FLOAT3,
- column_id.name,
- size,
- [transforms](int index, CellValue &r_cell_value) {
- r_cell_value.value_float3 = transforms[index].to_euler();
- });
- }
- if (STREQ(column_id.name, "Scale")) {
- return column_values_from_function(SPREADSHEET_VALUE_TYPE_FLOAT3,
- column_id.name,
- size,
- [transforms](int index, CellValue &r_cell_value) {
- r_cell_value.value_float3 = transforms[index].scale();
- });
- }
- Span<int> ids = component_->instance_ids();
- if (!ids.is_empty()) {
- if (STREQ(column_id.name, "id")) {
- /* Make the column a bit wider by default, since the IDs tend to be large numbers. */
- return column_values_from_function(
- SPREADSHEET_VALUE_TYPE_INT32,
- column_id.name,
- size,
- [ids](int index, CellValue &r_cell_value) { r_cell_value.value_int = ids[index]; },
- 5.5f);
- }
- }
- return {};
-}
-
-int InstancesDataSource::tot_rows() const
-{
- return component_->instances_amount();
+ VArray<bool> selection = mesh_component->attribute_try_adapt_domain<bool>(
+ VArray<bool>::ForFunc(mesh_eval->totvert,
+ [bm](int vertex_index) -> bool {
+ BMVert *vert = bm->vtable[vertex_index];
+ return BM_elem_flag_test(vert, BM_ELEM_SELECT);
+ }),
+ ATTR_DOMAIN_POINT,
+ domain_);
+ return index_mask_from_bool_array(selection, indices);
+ }
+
+ return IndexMask(mesh_eval->totvert);
}
void VolumeDataSource::foreach_default_column_ids(
@@ -520,50 +268,36 @@ std::unique_ptr<ColumnValues> VolumeDataSource::get_column_values(
#ifdef WITH_OPENVDB
const int size = this->tot_rows();
if (STREQ(column_id.name, "Grid Name")) {
- return column_values_from_function(
- SPREADSHEET_VALUE_TYPE_STRING,
- IFACE_("Grid Name"),
- size,
- [volume](int index, CellValue &r_cell_value) {
+ return std::make_unique<ColumnValues>(
+ IFACE_("Grid Name"), VArray<std::string>::ForFunc(size, [volume](int64_t index) {
const VolumeGrid *volume_grid = BKE_volume_grid_get_for_read(volume, index);
- r_cell_value.value_string = BKE_volume_grid_name(volume_grid);
- },
- 6.0f);
+ return BKE_volume_grid_name(volume_grid);
+ }));
}
if (STREQ(column_id.name, "Data Type")) {
- return column_values_from_function(
- SPREADSHEET_VALUE_TYPE_STRING,
- IFACE_("Type"),
- size,
- [volume](int index, CellValue &r_cell_value) {
+ return std::make_unique<ColumnValues>(
+ IFACE_("Data Type"), VArray<std::string>::ForFunc(size, [volume](int64_t index) {
const VolumeGrid *volume_grid = BKE_volume_grid_get_for_read(volume, index);
const VolumeGridType type = BKE_volume_grid_type(volume_grid);
const char *name = nullptr;
RNA_enum_name_from_value(rna_enum_volume_grid_data_type_items, type, &name);
- r_cell_value.value_string = IFACE_(name);
- },
- 5.0f);
+ return IFACE_(name);
+ }));
}
if (STREQ(column_id.name, "Class")) {
- return column_values_from_function(
- SPREADSHEET_VALUE_TYPE_STRING,
- IFACE_("Class"),
- size,
- [volume](int index, CellValue &r_cell_value) {
+ return std::make_unique<ColumnValues>(
+ IFACE_("Class"), VArray<std::string>::ForFunc(size, [volume](int64_t index) {
const VolumeGrid *volume_grid = BKE_volume_grid_get_for_read(volume, index);
openvdb::GridBase::ConstPtr grid = BKE_volume_grid_openvdb_for_read(volume, volume_grid);
openvdb::GridClass grid_class = grid->getGridClass();
if (grid_class == openvdb::GridClass::GRID_FOG_VOLUME) {
- r_cell_value.value_string = IFACE_("Fog Volume");
- }
- else if (grid_class == openvdb::GridClass::GRID_LEVEL_SET) {
- r_cell_value.value_string = IFACE_("Level Set");
+ return IFACE_("Fog Volume");
}
- else {
- r_cell_value.value_string = IFACE_("Unkown");
+ if (grid_class == openvdb::GridClass::GRID_LEVEL_SET) {
+ return IFACE_("Level Set");
}
- },
- 5.0f);
+ return IFACE_("Unknown");
+ }));
}
#else
UNUSED_VARS(column_id);
@@ -582,8 +316,7 @@ int VolumeDataSource::tot_rows() const
}
GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspreadsheet,
- Object *object_eval,
- const GeometryComponentType used_component_type)
+ Object *object_eval)
{
GeometrySet geometry_set;
if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_ORIGINAL) {
@@ -615,7 +348,7 @@ GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspread
}
}
else {
- if (used_component_type == GEO_COMPONENT_TYPE_MESH && object_eval->mode == OB_MODE_EDIT) {
+ if (object_eval->mode == OB_MODE_EDIT && object_eval->type == OB_MESH) {
Mesh *mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(object_eval, false);
if (mesh == nullptr) {
return geometry_set;
@@ -762,8 +495,7 @@ std::unique_ptr<DataSource> data_source_from_geometry(const bContext *C, Object
SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
const AttributeDomain domain = (AttributeDomain)sspreadsheet->attribute_domain;
const GeometryComponentType component_type = get_display_component_type(C, object_eval);
- GeometrySet geometry_set = spreadsheet_get_display_geometry_set(
- sspreadsheet, object_eval, component_type);
+ GeometrySet geometry_set = spreadsheet_get_display_geometry_set(sspreadsheet, object_eval);
if (!geometry_set.has(component_type)) {
return {};
@@ -773,9 +505,6 @@ std::unique_ptr<DataSource> data_source_from_geometry(const bContext *C, Object
ExtraColumns extra_columns;
add_fields_as_extra_columns(sspreadsheet, component, extra_columns);
- if (component_type == GEO_COMPONENT_TYPE_INSTANCES) {
- return std::make_unique<InstancesDataSource>(geometry_set, std::move(extra_columns));
- }
if (component_type == GEO_COMPONENT_TYPE_VOLUME) {
return std::make_unique<VolumeDataSource>(geometry_set);
}
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh
index a4114dd1f6a..b5105050d2b 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh
@@ -82,30 +82,12 @@ class GeometryDataSource : public DataSource {
return object_eval_;
}
+ /**
+ * Only data sets corresponding to mesh objects in edit mode currently support selection
+ * filtering.
+ */
bool has_selection_filter() const override;
- void apply_selection_filter(MutableSpan<bool> rows_included) const;
-
- void foreach_default_column_ids(
- FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const override;
-
- std::unique_ptr<ColumnValues> get_column_values(
- const SpreadsheetColumnID &column_id) const override;
-
- int tot_rows() const override;
-};
-
-class InstancesDataSource : public DataSource {
- const GeometrySet geometry_set_;
- const InstancesComponent *component_;
- ExtraColumns extra_columns_;
-
- public:
- InstancesDataSource(GeometrySet geometry_set, ExtraColumns extra_columns)
- : geometry_set_(std::move(geometry_set)),
- component_(geometry_set_.get_component_for_read<InstancesComponent>()),
- extra_columns_(std::move(extra_columns))
- {
- }
+ IndexMask apply_selection_filter(Vector<int64_t> &indices) const;
void foreach_default_column_ids(
FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const override;
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc
index acedcebe05c..2a81b56d129 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc
@@ -14,288 +14,226 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#include <array>
-
#include "DNA_space_types.h"
#include "DNA_windowmanager_types.h"
#include "BKE_context.h"
#include "BKE_volume.h"
-#include "BLF_api.h"
-
-#include "BLI_rect.h"
-
#include "RNA_access.h"
#include "UI_interface.h"
-#include "UI_view2d.h"
+#include "UI_interface.hh"
+#include "UI_tree_view.hh"
#include "WM_types.h"
+#include "BLT_translation.h"
+
#include "spreadsheet_dataset_draw.hh"
#include "spreadsheet_draw.hh"
#include "spreadsheet_intern.hh"
-static int is_component_row_selected(struct uiBut *but, const void *arg)
-{
- SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)arg;
-
- GeometryComponentType component = (GeometryComponentType)UI_but_datasetrow_component_get(but);
- AttributeDomain domain = (AttributeDomain)UI_but_datasetrow_domain_get(but);
+namespace blender::ed::spreadsheet {
- const bool is_component_selected = (GeometryComponentType)
- sspreadsheet->geometry_component_type == component;
- const bool is_domain_selected = (AttributeDomain)sspreadsheet->attribute_domain == domain;
- bool is_selected = is_component_selected && is_domain_selected;
+class GeometryDataSetTreeView;
- if (component == GEO_COMPONENT_TYPE_VOLUME) {
- is_selected = is_component_selected;
- }
+class GeometryDataSetTreeViewItem : public ui::AbstractTreeViewItem {
+ GeometryComponentType component_type_;
+ std::optional<AttributeDomain> domain_;
+ BIFIconID icon_;
- return is_selected;
-}
+ public:
+ GeometryDataSetTreeViewItem(GeometryComponentType component_type,
+ StringRef label,
+ BIFIconID icon);
+ GeometryDataSetTreeViewItem(GeometryComponentType component_type,
+ AttributeDomain domain,
+ StringRef label,
+ BIFIconID icon);
-namespace blender::ed::spreadsheet {
+ void on_activate() override;
-/* -------------------------------------------------------------------- */
-/* Draw Context */
+ void build_row(uiLayout &row) override;
-class DatasetDrawContext {
- std::array<int, 2> mval_;
+ protected:
+ std::optional<bool> should_be_active() const override;
+ bool supports_collapsing() const override;
- public:
- const SpaceSpreadsheet *sspreadsheet;
- Object *object_eval;
- /* Current geometry set, changes per component. */
- GeometrySet current_geometry_set;
+ private:
+ GeometryDataSetTreeView &get_tree() const;
+ std::optional<int> count() const;
+};
- DatasetDrawContext(const bContext *C);
+class GeometryDataSetTreeView : public ui::AbstractTreeView {
+ GeometrySet geometry_set_;
+ const bContext &C_;
+ SpaceSpreadsheet &sspreadsheet_;
+ bScreen &screen_;
- GeometrySet geometry_set_from_component(GeometryComponentType component);
- const std::array<int, 2> &cursor_mval() const;
-};
+ friend class GeometryDataSetTreeViewItem;
-DatasetDrawContext::DatasetDrawContext(const bContext *C)
- : sspreadsheet(CTX_wm_space_spreadsheet(C)),
- object_eval(spreadsheet_get_object_eval(sspreadsheet, CTX_data_depsgraph_pointer(C)))
-{
- const wmWindow *win = CTX_wm_window(C);
- const ARegion *region = CTX_wm_region(C);
- mval_ = {win->eventstate->xy[0] - region->winrct.xmin,
- win->eventstate->xy[1] - region->winrct.ymin};
-}
+ public:
+ GeometryDataSetTreeView(GeometrySet geometry_set, const bContext &C)
+ : geometry_set_(std::move(geometry_set)),
+ C_(C),
+ sspreadsheet_(*CTX_wm_space_spreadsheet(&C)),
+ screen_(*CTX_wm_screen(&C))
+ {
+ }
-GeometrySet DatasetDrawContext::geometry_set_from_component(GeometryComponentType component)
-{
- return spreadsheet_get_display_geometry_set(sspreadsheet, object_eval, component);
-}
+ void build_tree() override
+ {
+ GeometryDataSetTreeViewItem &mesh = this->add_tree_item<GeometryDataSetTreeViewItem>(
+ GEO_COMPONENT_TYPE_MESH, IFACE_("Mesh"), ICON_MESH_DATA);
+ mesh.add_tree_item<GeometryDataSetTreeViewItem>(
+ GEO_COMPONENT_TYPE_MESH, ATTR_DOMAIN_POINT, IFACE_("Vertex"), ICON_VERTEXSEL);
+ mesh.add_tree_item<GeometryDataSetTreeViewItem>(
+ GEO_COMPONENT_TYPE_MESH, ATTR_DOMAIN_EDGE, IFACE_("Edge"), ICON_EDGESEL);
+ mesh.add_tree_item<GeometryDataSetTreeViewItem>(
+ GEO_COMPONENT_TYPE_MESH, ATTR_DOMAIN_FACE, IFACE_("Face"), ICON_FACESEL);
+ mesh.add_tree_item<GeometryDataSetTreeViewItem>(
+ GEO_COMPONENT_TYPE_MESH, ATTR_DOMAIN_CORNER, IFACE_("Face Corner"), ICON_NODE_CORNER);
+
+ GeometryDataSetTreeViewItem &curve = this->add_tree_item<GeometryDataSetTreeViewItem>(
+ GEO_COMPONENT_TYPE_CURVE, IFACE_("Curve"), ICON_CURVE_DATA);
+ curve.add_tree_item<GeometryDataSetTreeViewItem>(GEO_COMPONENT_TYPE_CURVE,
+ ATTR_DOMAIN_POINT,
+ IFACE_("Control Point"),
+ ICON_CURVE_BEZCIRCLE);
+ curve.add_tree_item<GeometryDataSetTreeViewItem>(
+ GEO_COMPONENT_TYPE_CURVE, ATTR_DOMAIN_CURVE, IFACE_("Spline"), ICON_CURVE_PATH);
+
+ GeometryDataSetTreeViewItem &pointcloud = this->add_tree_item<GeometryDataSetTreeViewItem>(
+ GEO_COMPONENT_TYPE_POINT_CLOUD, IFACE_("Point Cloud"), ICON_POINTCLOUD_DATA);
+ pointcloud.add_tree_item<GeometryDataSetTreeViewItem>(
+ GEO_COMPONENT_TYPE_POINT_CLOUD, ATTR_DOMAIN_POINT, IFACE_("Point"), ICON_PARTICLE_POINT);
+
+ this->add_tree_item<GeometryDataSetTreeViewItem>(
+ GEO_COMPONENT_TYPE_VOLUME, IFACE_("Volume Grids"), ICON_VOLUME_DATA);
+
+ this->add_tree_item<GeometryDataSetTreeViewItem>(
+ GEO_COMPONENT_TYPE_INSTANCES, ATTR_DOMAIN_INSTANCE, IFACE_("Instances"), ICON_EMPTY_AXIS);
+ }
+};
-const std::array<int, 2> &DatasetDrawContext::cursor_mval() const
+GeometryDataSetTreeViewItem::GeometryDataSetTreeViewItem(GeometryComponentType component_type,
+ StringRef label,
+ BIFIconID icon)
+ : component_type_(component_type), domain_(std::nullopt), icon_(icon)
{
- return mval_;
+ label_ = label;
+ this->set_collapsed(false);
}
-
-/* -------------------------------------------------------------------- */
-/* Drawer */
-
-DatasetRegionDrawer::DatasetRegionDrawer(const ARegion *region,
- uiBlock &block,
- DatasetDrawContext &draw_context)
- : row_height(UI_UNIT_Y),
- xmin(region->v2d.cur.xmin),
- xmax(region->v2d.cur.xmax),
- block(block),
- v2d(region->v2d),
- draw_context(draw_context)
+GeometryDataSetTreeViewItem::GeometryDataSetTreeViewItem(GeometryComponentType component_type,
+ AttributeDomain domain,
+ StringRef label,
+ BIFIconID icon)
+ : component_type_(component_type), domain_(domain), icon_(icon)
{
+ label_ = label;
}
-void DatasetRegionDrawer::draw_hierarchy(const DatasetLayoutHierarchy &layout)
+void GeometryDataSetTreeViewItem::on_activate()
{
- for (const DatasetComponentLayoutInfo &component : layout.components) {
- draw_context.current_geometry_set = draw_context.geometry_set_from_component(component.type);
-
- draw_component_row(component);
-
- /* Iterate attribute domains, skip unset ones (storage has to be in a enum-based, fixed size
- * array so uses optionals to support skipping enum values that shouldn't be displayed for a
- * component). */
- for (const auto &optional_domain : component.attr_domains) {
- if (!optional_domain) {
- continue;
- }
-
- const DatasetAttrDomainLayoutInfo &domain_info = *optional_domain;
- draw_attribute_domain_row(component, domain_info);
- }
+ GeometryDataSetTreeView &tree_view = this->get_tree();
+ bContext &C = const_cast<bContext &>(tree_view.C_);
+ SpaceSpreadsheet &sspreadsheet = tree_view.sspreadsheet_;
+ tree_view.sspreadsheet_.geometry_component_type = component_type_;
+ if (domain_) {
+ tree_view.sspreadsheet_.attribute_domain = *domain_;
}
+ PointerRNA ptr;
+ RNA_pointer_create(&tree_view.screen_.id, &RNA_SpaceSpreadsheet, &sspreadsheet, &ptr);
+ RNA_property_update(&C, &ptr, RNA_struct_find_property(&ptr, "attribute_domain"));
+ RNA_property_update(&C, &ptr, RNA_struct_find_property(&ptr, "geometry_component_type"));
}
-static int element_count_from_volume(const GeometrySet &geometry_set)
+void GeometryDataSetTreeViewItem::build_row(uiLayout &row)
{
- if (const Volume *volume = geometry_set.get_volume_for_read()) {
- return BKE_volume_num_grids(volume);
+ uiItemL(&row, label_.c_str(), icon_);
+
+ if (const std::optional<int> count = this->count()) {
+ /* Using the tree row button instead of a separate right aligned button gives padding
+ * to the right side of the number, which it didn't have with the button. */
+ char element_count[7];
+ BLI_str_format_attribute_domain_size(element_count, *count);
+ UI_but_hint_drawstr_set((uiBut *)this->tree_row_button(), element_count);
}
- return 0;
}
-static int element_count_from_component_domain(const GeometrySet &geometry_set,
- GeometryComponentType component,
- AttributeDomain domain)
+std::optional<bool> GeometryDataSetTreeViewItem::should_be_active() const
{
- if (geometry_set.has_mesh() && component == GEO_COMPONENT_TYPE_MESH) {
- const MeshComponent *mesh_component = geometry_set.get_component_for_read<MeshComponent>();
- return mesh_component->attribute_domain_size(domain);
- }
-
- if (geometry_set.has_pointcloud() && component == GEO_COMPONENT_TYPE_POINT_CLOUD) {
- const PointCloudComponent *point_cloud_component =
- geometry_set.get_component_for_read<PointCloudComponent>();
- return point_cloud_component->attribute_domain_size(domain);
- }
+ GeometryDataSetTreeView &tree_view = this->get_tree();
+ SpaceSpreadsheet &sspreadsheet = tree_view.sspreadsheet_;
- if (geometry_set.has_volume() && component == GEO_COMPONENT_TYPE_VOLUME) {
- const VolumeComponent *volume_component =
- geometry_set.get_component_for_read<VolumeComponent>();
- return volume_component->attribute_domain_size(domain);
+ if (component_type_ == GEO_COMPONENT_TYPE_VOLUME) {
+ return sspreadsheet.geometry_component_type == component_type_;
}
- if (geometry_set.has_curve() && component == GEO_COMPONENT_TYPE_CURVE) {
- const CurveComponent *curve_component = geometry_set.get_component_for_read<CurveComponent>();
- return curve_component->attribute_domain_size(domain);
+ if (!domain_) {
+ return false;
}
- if (geometry_set.has_instances() && component == GEO_COMPONENT_TYPE_INSTANCES) {
- const InstancesComponent *instances_component =
- geometry_set.get_component_for_read<InstancesComponent>();
- return instances_component->attribute_domain_size(domain);
- }
-
- return 0;
+ return sspreadsheet.geometry_component_type == component_type_ &&
+ sspreadsheet.attribute_domain == *domain_;
}
-void DatasetRegionDrawer::draw_dataset_row(const int indentation,
- const GeometryComponentType component,
- const std::optional<AttributeDomain> domain,
- BIFIconID icon,
- const char *label,
- const bool is_active)
+bool GeometryDataSetTreeViewItem::supports_collapsing() const
{
+ return false;
+}
- const float row_height = UI_UNIT_Y;
- const float padding_x = UI_UNIT_X * 0.25f;
-
- const rctf rect = {float(xmin) + padding_x,
- float(xmax) - V2D_SCROLL_HANDLE_WIDTH,
- ymin_offset - row_height,
- ymin_offset};
-
- char element_count[7];
- if (component == GEO_COMPONENT_TYPE_VOLUME) {
- BLI_str_format_attribute_domain_size(
- element_count, element_count_from_volume(draw_context.current_geometry_set));
- }
- else {
- BLI_str_format_attribute_domain_size(
- element_count,
- domain ? element_count_from_component_domain(
- draw_context.current_geometry_set, component, *domain) :
- 0);
- }
+GeometryDataSetTreeView &GeometryDataSetTreeViewItem::get_tree() const
+{
+ return static_cast<GeometryDataSetTreeView &>(this->get_tree_view());
+}
- std::string label_and_element_count = label;
- label_and_element_count += UI_SEP_CHAR;
- label_and_element_count += element_count;
-
- uiBut *bt = uiDefIconTextButO(&block,
- UI_BTYPE_DATASETROW,
- "SPREADSHEET_OT_change_spreadsheet_data_source",
- WM_OP_INVOKE_DEFAULT,
- icon,
- label,
- rect.xmin,
- rect.ymin,
- BLI_rctf_size_x(&rect),
- BLI_rctf_size_y(&rect),
- nullptr);
-
- UI_but_datasetrow_indentation_set(bt, indentation);
-
- if (is_active) {
- UI_but_hint_drawstr_set(bt, element_count);
- UI_but_datasetrow_component_set(bt, component);
- if (domain) {
- UI_but_datasetrow_domain_set(bt, *domain);
- }
- UI_but_func_pushed_state_set(bt, &is_component_row_selected, draw_context.sspreadsheet);
+std::optional<int> GeometryDataSetTreeViewItem::count() const
+{
+ GeometryDataSetTreeView &tree_view = this->get_tree();
+ GeometrySet &geometry = tree_view.geometry_set_;
- PointerRNA *but_ptr = UI_but_operator_ptr_get((uiBut *)bt);
- RNA_int_set(but_ptr, "component_type", component);
- if (domain) {
- RNA_int_set(but_ptr, "attribute_domain_type", *domain);
+ /* Special case for volumes since there is no grid domain. */
+ if (component_type_ == GEO_COMPONENT_TYPE_VOLUME) {
+ if (const Volume *volume = geometry.get_volume_for_read()) {
+ return BKE_volume_num_grids(volume);
}
+ return 0;
}
- ymin_offset -= row_height;
-}
-
-void DatasetRegionDrawer::draw_component_row(const DatasetComponentLayoutInfo &component_info)
-{
- if (component_info.type == GEO_COMPONENT_TYPE_INSTANCES) {
- draw_dataset_row(0,
- component_info.type,
- ATTR_DOMAIN_INSTANCE,
- component_info.icon,
- component_info.label,
- true);
- }
- else if (component_info.type == GEO_COMPONENT_TYPE_VOLUME) {
- draw_dataset_row(
- 0, component_info.type, std::nullopt, component_info.icon, component_info.label, true);
+ if (!domain_) {
+ return std::nullopt;
}
- else {
- draw_dataset_row(
- 0, component_info.type, std::nullopt, component_info.icon, component_info.label, false);
+
+ if (const GeometryComponent *component = geometry.get_component_for_read(component_type_)) {
+ return component->attribute_domain_size(*domain_);
}
-}
-void DatasetRegionDrawer::draw_attribute_domain_row(
- const DatasetComponentLayoutInfo &component_info,
- const DatasetAttrDomainLayoutInfo &domain_info)
-{
- draw_dataset_row(
- 1, component_info.type, domain_info.type, domain_info.icon, domain_info.label, true);
+ return 0;
}
-/* -------------------------------------------------------------------- */
-/* Drawer */
-
-void draw_dataset_in_region(const bContext *C, ARegion *region)
+void spreadsheet_data_set_panel_draw(const bContext *C, Panel *panel)
{
- DatasetDrawContext draw_context{C};
- if (!draw_context.object_eval) {
- /* No object means nothing to display. Keep the region empty. */
+ const SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
+ Object *object = spreadsheet_get_object_eval(sspreadsheet, CTX_data_depsgraph_pointer(C));
+ if (!object) {
return;
}
+ uiLayout *layout = panel->layout;
- uiBlock *block = UI_block_begin(C, region, __func__, UI_EMBOSS);
-
- DatasetRegionDrawer drawer{region, *block, draw_context};
+ uiBlock *block = uiLayoutGetBlock(layout);
- /* Start with an offset to align buttons to spreadsheet rows. Use spreadsheet drawing info for
- * that. */
- drawer.ymin_offset = -SpreadsheetDrawer().top_row_height + drawer.row_height;
+ UI_block_layout_set_current(block, layout);
- const DatasetLayoutHierarchy hierarchy = dataset_layout_hierarchy();
- drawer.draw_hierarchy(hierarchy);
-#ifndef NDEBUG
- dataset_layout_hierarchy_sanity_check(hierarchy);
-#endif
+ ui::AbstractTreeView *tree_view = UI_block_add_view(
+ *block,
+ "Data Set Tree View",
+ std::make_unique<GeometryDataSetTreeView>(
+ spreadsheet_get_display_geometry_set(sspreadsheet, object), *C));
- UI_block_end(C, block);
- UI_view2d_totRect_set(&region->v2d, region->winx, abs(drawer.ymin_offset));
- UI_block_draw(C, block);
+ ui::TreeViewBuilder builder(*block);
+ builder.build_tree_view(*tree_view);
}
} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.hh b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.hh
index 19906d73e7f..4a604533f11 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.hh
@@ -16,49 +16,11 @@
#pragma once
-#include <array>
-
-#include "BKE_geometry_set.hh"
-#include "UI_interface.h"
-#include "spreadsheet_dataset_layout.hh"
-
-struct ARegion;
-struct View2D;
+struct Panel;
struct bContext;
-struct uiBlock;
namespace blender::ed::spreadsheet {
-class DatasetDrawContext;
-
-class DatasetRegionDrawer {
- public:
- const int row_height;
- float ymin_offset = 0;
-
- int xmin;
- int xmax;
- uiBlock &block;
- const View2D &v2d;
- DatasetDrawContext &draw_context;
-
- DatasetRegionDrawer(const ARegion *region, uiBlock &block, DatasetDrawContext &draw_context);
-
- void draw_hierarchy(const DatasetLayoutHierarchy &layout);
-
- void draw_attribute_domain_row(const DatasetComponentLayoutInfo &component,
- const DatasetAttrDomainLayoutInfo &domain_info);
- void draw_component_row(const DatasetComponentLayoutInfo &component_info);
-
- private:
- void draw_dataset_row(const int indentation,
- const GeometryComponentType component,
- const std::optional<AttributeDomain> domain,
- const BIFIconID icon,
- const char *label,
- const bool is_active);
-};
-
-void draw_dataset_in_region(const bContext *C, ARegion *region);
+void spreadsheet_data_set_panel_draw(const bContext *C, Panel *panel);
} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.cc b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.cc
deleted file mode 100644
index f15af2e4d32..00000000000
--- a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.cc
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#include <optional>
-
-#include "BLI_span.hh"
-
-#include "BLT_translation.h"
-
-#include "spreadsheet_dataset_layout.hh"
-
-namespace blender::ed::spreadsheet {
-
-#define ATTR_INFO(type, label, icon) \
- std::optional<DatasetAttrDomainLayoutInfo> \
- { \
- std::in_place, type, label, icon \
- }
-#define ATTR_INFO_NONE(type) \
- { \
- std::nullopt \
- }
-
-/**
- * Definition for the component->attribute-domain hierarchy.
- * Constructed at compile time.
- *
- * \warning Order of attribute-domains matters! It __must__ match the #AttributeDomain
- * definition and fill gaps with unset optionals (i.e. `std::nullopt`). Would be nice to use
- * array designators for this (which C++ doesn't support).
- */
-constexpr DatasetComponentLayoutInfo DATASET_layout_hierarchy[] = {
- {
- GEO_COMPONENT_TYPE_MESH,
- N_("Mesh"),
- ICON_MESH_DATA,
- {
- ATTR_INFO(ATTR_DOMAIN_POINT, N_("Vertex"), ICON_VERTEXSEL),
- ATTR_INFO(ATTR_DOMAIN_EDGE, N_("Edge"), ICON_EDGESEL),
- ATTR_INFO(ATTR_DOMAIN_FACE, N_("Face"), ICON_FACESEL),
- ATTR_INFO(ATTR_DOMAIN_CORNER, N_("Face Corner"), ICON_NODE_CORNER),
- },
- },
- {
- GEO_COMPONENT_TYPE_CURVE,
- N_("Curves"),
- ICON_CURVE_DATA,
- {
- ATTR_INFO(ATTR_DOMAIN_POINT, N_("Control Point"), ICON_CURVE_BEZCIRCLE),
- ATTR_INFO_NONE(ATTR_DOMAIN_EDGE),
- ATTR_INFO_NONE(ATTR_DOMAIN_CORNER),
- ATTR_INFO_NONE(ATTR_DOMAIN_FACE),
- ATTR_INFO(ATTR_DOMAIN_CURVE, N_("Spline"), ICON_CURVE_PATH),
- },
- },
- {
- GEO_COMPONENT_TYPE_POINT_CLOUD,
- N_("Point Cloud"),
- ICON_POINTCLOUD_DATA,
- {
- ATTR_INFO(ATTR_DOMAIN_POINT, N_("Point"), ICON_PARTICLE_POINT),
- },
- },
- {
- GEO_COMPONENT_TYPE_VOLUME,
- N_("Volume Grids"),
- ICON_VOLUME_DATA,
- {},
- },
- {
- GEO_COMPONENT_TYPE_INSTANCES,
- N_("Instances"),
- ICON_EMPTY_AXIS,
- {},
- },
-};
-
-#undef ATTR_INFO
-#undef ATTR_INFO_LABEL
-
-DatasetLayoutHierarchy dataset_layout_hierarchy()
-{
- return DatasetLayoutHierarchy{
- Span{DATASET_layout_hierarchy, ARRAY_SIZE(DATASET_layout_hierarchy)}};
-}
-
-#ifndef NDEBUG
-/**
- * Debug-only sanity check for correct attribute domain initialization (order/indices must
- * match AttributeDomain). This doesn't check for all possible missuses, but should catch the most
- * likely mistakes.
- */
-void dataset_layout_hierarchy_sanity_check(const DatasetLayoutHierarchy &hierarchy)
-{
- for (const DatasetComponentLayoutInfo &component : hierarchy.components) {
- for (uint i = 0; i < component.attr_domains.size(); i++) {
- if (component.attr_domains[i]) {
- BLI_assert(component.attr_domains[i]->type == static_cast<AttributeDomain>(i));
- }
- }
- }
-}
-#endif
-
-} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.hh b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.hh
deleted file mode 100644
index d463739a0fa..00000000000
--- a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.hh
+++ /dev/null
@@ -1,68 +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.
- */
-
-#pragma once
-
-#include <array>
-#include <optional>
-
-/* Enum definitions... */
-#include "BKE_attribute.h"
-#include "BKE_geometry_set.h"
-
-#include "BLI_span.hh"
-
-/* More enum definitions... */
-#include "UI_resources.h"
-
-#pragma once
-
-namespace blender::ed::spreadsheet {
-
-struct DatasetAttrDomainLayoutInfo {
- AttributeDomain type;
- const char *label;
- BIFIconID icon;
-
- constexpr DatasetAttrDomainLayoutInfo(AttributeDomain type, const char *label, BIFIconID icon)
- : type(type), label(label), icon(icon)
- {
- }
-};
-
-struct DatasetComponentLayoutInfo {
- GeometryComponentType type;
- const char *label;
- BIFIconID icon;
- /** Array of attribute-domains. Has to be fixed size based on #AttributeDomain enum, but not all
- * values need displaying for all parent components. Hence the optional use. */
- using AttrDomainArray = std::array<std::optional<DatasetAttrDomainLayoutInfo>, ATTR_DOMAIN_NUM>;
- const AttrDomainArray attr_domains;
-};
-
-struct DatasetLayoutHierarchy {
- /** The components for display (with layout info like icon and label). Each component stores
- * the attribute domains it wants to display (also with layout info like icon and label). */
- const Span<DatasetComponentLayoutInfo> components;
-};
-
-DatasetLayoutHierarchy dataset_layout_hierarchy();
-
-#ifndef NDEBUG
-void dataset_layout_hierarchy_sanity_check(const DatasetLayoutHierarchy &hierarchy);
-#endif
-
-} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_draw.cc b/source/blender/editors/space_spreadsheet/spreadsheet_draw.cc
index b911c80fa63..857aa20da92 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_draw.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_draw.cc
@@ -27,6 +27,8 @@
#include "spreadsheet_draw.hh"
+#define CELL_RIGHT_PADDING (2.0f * UI_DPI_FAC)
+
namespace blender::ed::spreadsheet {
SpreadsheetDrawer::SpreadsheetDrawer()
@@ -159,7 +161,7 @@ static void draw_left_column_content(const int scroll_offset_y,
params.xmin = 0;
params.ymin = region->winy - drawer.top_row_height - (row_index + 1) * drawer.row_height -
scroll_offset_y;
- params.width = drawer.left_column_width;
+ params.width = drawer.left_column_width - CELL_RIGHT_PADDING;
params.height = drawer.row_height;
drawer.draw_left_column_cell(row_index, params);
}
@@ -194,7 +196,7 @@ static void draw_top_row_content(const bContext *C,
params.block = first_row_block;
params.xmin = left_x;
params.ymin = region->winy - drawer.top_row_height;
- params.width = column_width;
+ params.width = column_width - CELL_RIGHT_PADDING;
params.height = drawer.top_row_height;
drawer.draw_top_row_cell(column_index, params);
@@ -242,7 +244,7 @@ static void draw_cell_contents(const bContext *C,
params.xmin = left_x;
params.ymin = region->winy - drawer.top_row_height - (row_index + 1) * drawer.row_height -
scroll_offset_y;
- params.width = column_width;
+ params.width = column_width - CELL_RIGHT_PADDING;
params.height = drawer.row_height;
drawer.draw_content_cell(row_index, column_index, params);
}
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh b/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh
index 8b050c2e69b..e62835d5792 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh
@@ -37,6 +37,7 @@ struct SpaceSpreadsheet_Runtime {
};
struct bContext;
+struct ARegionType;
void spreadsheet_operatortypes(void);
void spreadsheet_update_context_path(const bContext *C);
@@ -45,6 +46,8 @@ Object *spreadsheet_get_object_eval(const SpaceSpreadsheet *sspreadsheet,
namespace blender::ed::spreadsheet {
GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspreadsheet,
- Object *object_eval,
- const GeometryComponentType used_component_type);
-}
+ Object *object_eval);
+
+void spreadsheet_data_set_region_panels_register(ARegionType &region_type);
+
+} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc
index 202523c0e64..7cc2d8d0b48 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc
@@ -17,8 +17,16 @@
#include <iomanip>
#include <sstream>
+#include "BLI_float2.hh"
+#include "BLI_float3.hh"
+
+#include "BKE_geometry_set.hh"
+
+#include "spreadsheet_column_values.hh"
#include "spreadsheet_layout.hh"
+#include "DNA_collection_types.h"
+#include "DNA_object_types.h"
#include "DNA_userdef_types.h"
#include "UI_interface.h"
@@ -92,13 +100,14 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
{
const int real_index = spreadsheet_layout_.row_indices[row_index];
const ColumnValues &column = *spreadsheet_layout_.columns[column_index].values;
- CellValue cell_value;
- if (real_index < column.size()) {
- column.get_value(real_index, cell_value);
+ if (real_index > column.size()) {
+ return;
}
- if (cell_value.value_int.has_value()) {
- const int value = *cell_value.value_int;
+ const fn::GVArray &data = column.data();
+
+ if (data.type().is<int>()) {
+ const int value = data.get<int>(real_index);
const std::string value_str = std::to_string(value);
uiBut *but = uiDefIconTextBut(params.block,
UI_BTYPE_LABEL,
@@ -119,8 +128,8 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT);
UI_but_drawflag_enable(but, UI_BUT_TEXT_RIGHT);
}
- else if (cell_value.value_float.has_value()) {
- const float value = *cell_value.value_float;
+ else if (data.type().is<float>()) {
+ const float value = data.get<float>(real_index);
std::stringstream ss;
ss << std::fixed << std::setprecision(3) << value;
const std::string value_str = ss.str();
@@ -143,8 +152,8 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT);
UI_but_drawflag_enable(but, UI_BUT_TEXT_RIGHT);
}
- else if (cell_value.value_bool.has_value()) {
- const bool value = *cell_value.value_bool;
+ else if (data.type().is<bool>()) {
+ const bool value = data.get<bool>(real_index);
const int icon = value ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT;
uiBut *but = uiDefIconTextBut(params.block,
UI_BTYPE_LABEL,
@@ -163,87 +172,81 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
nullptr);
UI_but_drawflag_disable(but, UI_BUT_ICON_LEFT);
}
- else if (cell_value.value_float2.has_value()) {
- const float2 value = *cell_value.value_float2;
+ else if (data.type().is<float2>()) {
+ const float2 value = data.get<float2>(real_index);
this->draw_float_vector(params, Span(&value.x, 2));
}
- else if (cell_value.value_float3.has_value()) {
- const float3 value = *cell_value.value_float3;
+ else if (data.type().is<float3>()) {
+ const float3 value = data.get<float3>(real_index);
this->draw_float_vector(params, Span(&value.x, 3));
}
- else if (cell_value.value_color.has_value()) {
- const ColorGeometry4f value = *cell_value.value_color;
+ else if (data.type().is<ColorGeometry4f>()) {
+ const ColorGeometry4f value = data.get<ColorGeometry4f>(real_index);
this->draw_float_vector(params, Span(&value.r, 4));
}
- else if (cell_value.value_object.has_value()) {
- const ObjectCellValue value = *cell_value.value_object;
- uiDefIconTextBut(params.block,
- UI_BTYPE_LABEL,
- 0,
- ICON_OBJECT_DATA,
- reinterpret_cast<const ID *const>(value.object)->name + 2,
- params.xmin,
- params.ymin,
- params.width,
- params.height,
- nullptr,
- 0,
- 0,
- 0,
- 0,
- nullptr);
- }
- else if (cell_value.value_collection.has_value()) {
- const CollectionCellValue value = *cell_value.value_collection;
- uiDefIconTextBut(params.block,
- UI_BTYPE_LABEL,
- 0,
- ICON_OUTLINER_COLLECTION,
- reinterpret_cast<const ID *const>(value.collection)->name + 2,
- params.xmin,
- params.ymin,
- params.width,
- params.height,
- nullptr,
- 0,
- 0,
- 0,
- 0,
- nullptr);
- }
- else if (cell_value.value_geometry_set.has_value()) {
- uiDefIconTextBut(params.block,
- UI_BTYPE_LABEL,
- 0,
- ICON_MESH_DATA,
- "Geometry",
- params.xmin,
- params.ymin,
- params.width,
- params.height,
- nullptr,
- 0,
- 0,
- 0,
- 0,
- nullptr);
- }
- else if (cell_value.value_string.has_value()) {
- uiDefIconTextBut(params.block,
- UI_BTYPE_LABEL,
- 0,
- ICON_NONE,
- cell_value.value_string->c_str(),
- params.xmin,
- params.ymin,
- params.width,
- params.height,
- nullptr,
- 0,
- 0,
- 0,
- 0,
- nullptr);
+ else if (data.type().is<InstanceReference>()) {
+ const InstanceReference value = data.get<InstanceReference>(real_index);
+ switch (value.type()) {
+ case InstanceReference::Type::Object: {
+ const Object &object = value.object();
+ uiDefIconTextBut(params.block,
+ UI_BTYPE_LABEL,
+ 0,
+ ICON_OBJECT_DATA,
+ object.id.name + 2,
+ params.xmin,
+ params.ymin,
+ params.width,
+ params.height,
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ nullptr);
+ break;
+ }
+ case InstanceReference::Type::Collection: {
+ Collection &collection = value.collection();
+ uiDefIconTextBut(params.block,
+ UI_BTYPE_LABEL,
+ 0,
+ ICON_OUTLINER_COLLECTION,
+ collection.id.name + 2,
+ params.xmin,
+ params.ymin,
+ params.width,
+ params.height,
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ nullptr);
+ break;
+ }
+ case InstanceReference::Type::GeometrySet: {
+ uiDefIconTextBut(params.block,
+ UI_BTYPE_LABEL,
+ 0,
+ ICON_MESH_DATA,
+ "Geometry",
+ params.xmin,
+ params.ymin,
+ params.width,
+ params.height,
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ nullptr);
+ break;
+ }
+ case InstanceReference::Type::None: {
+ break;
+ }
+ }
}
}
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_layout.hh b/source/blender/editors/space_spreadsheet/spreadsheet_layout.hh
index 1768af6ae09..f996cd99dad 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_layout.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_layout.hh
@@ -32,7 +32,7 @@ struct ColumnLayout {
/* Layout information for the entire spreadsheet. */
struct SpreadsheetLayout {
Vector<ColumnLayout> columns;
- Span<int64_t> row_indices;
+ IndexMask row_indices;
int index_column_width = 100;
};
diff --git a/source/blender/functions/FN_multi_function_parallel.hh b/source/blender/editors/space_spreadsheet/spreadsheet_panels.cc
index 84c57efd434..854c3d4aba6 100644
--- a/source/blender/functions/FN_multi_function_parallel.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_panels.cc
@@ -14,26 +14,24 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#pragma once
+#include "BKE_screen.h"
-/** \file
- * \ingroup fn
- */
-
-#include "FN_multi_function.hh"
-
-namespace blender::fn {
+#include "BLT_translation.h"
-class ParallelMultiFunction : public MultiFunction {
- private:
- const MultiFunction &fn_;
- const int64_t grain_size_;
- bool threading_supported_;
+#include "spreadsheet_dataset_draw.hh"
+#include "spreadsheet_intern.hh"
- public:
- ParallelMultiFunction(const MultiFunction &fn, const int64_t grain_size);
+namespace blender::ed::spreadsheet {
- void call(IndexMask mask, MFParams params, MFContext context) const override;
-};
+void spreadsheet_data_set_region_panels_register(ARegionType &region_type)
+{
+ PanelType *panel_type = (PanelType *)MEM_callocN(sizeof(PanelType), __func__);
+ strcpy(panel_type->idname, "SPREADSHEET_PT_data_set");
+ strcpy(panel_type->label, N_("Data Set"));
+ strcpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
+ panel_type->flag = PANEL_TYPE_NO_HEADER;
+ panel_type->draw = spreadsheet_data_set_panel_draw;
+ BLI_addtail(&region_type.paneltypes, panel_type);
+}
-} // namespace blender::fn
+} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
index 1e46fef8d71..a6a0266fcc1 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
@@ -18,7 +18,6 @@
#include "BLI_listbase.h"
-#include "DNA_collection_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
@@ -38,238 +37,197 @@
namespace blender::ed::spreadsheet {
-template<typename OperationFn>
-static void apply_filter_operation(const ColumnValues &values,
+template<typename T, typename OperationFn>
+static void apply_filter_operation(const VArray<T> &data,
OperationFn check_fn,
- MutableSpan<bool> rows_included)
+ const IndexMask mask,
+ Vector<int64_t> &new_indices)
{
- for (const int i : rows_included.index_range()) {
- if (!rows_included[i]) {
- continue;
- }
- CellValue cell_value;
- values.get_value(i, cell_value);
- if (!check_fn(cell_value)) {
- rows_included[i] = false;
+ for (const int64_t i : mask) {
+ if (check_fn(data[i])) {
+ new_indices.append(i);
}
}
}
-static void apply_row_filter(const SpreadsheetLayout &spreadsheet_layout,
- const SpreadsheetRowFilter &row_filter,
- MutableSpan<bool> rows_included)
+static void apply_row_filter(const SpreadsheetRowFilter &row_filter,
+ const Map<StringRef, const ColumnValues *> &columns,
+ const IndexMask prev_mask,
+ Vector<int64_t> &new_indices)
{
- for (const ColumnLayout &column : spreadsheet_layout.columns) {
- const ColumnValues &values = *column.values;
- if (values.name() != row_filter.column_name) {
- continue;
+ const ColumnValues &column = *columns.lookup(row_filter.column_name);
+ const fn::GVArray &column_data = column.data();
+ if (column_data.type().is<float>()) {
+ const float value = row_filter.value_float;
+ switch (row_filter.operation) {
+ case SPREADSHEET_ROW_FILTER_EQUAL: {
+ const float threshold = row_filter.threshold;
+ apply_filter_operation(
+ column_data.typed<float>(),
+ [&](const float cell) { return std::abs(cell - value) < threshold; },
+ prev_mask,
+ new_indices);
+ break;
+ }
+ case SPREADSHEET_ROW_FILTER_GREATER: {
+ apply_filter_operation(
+ column_data.typed<float>(),
+ [&](const float cell) { return cell > value; },
+ prev_mask,
+ new_indices);
+ break;
+ }
+ case SPREADSHEET_ROW_FILTER_LESS: {
+ apply_filter_operation(
+ column_data.typed<float>(),
+ [&](const float cell) { return cell < value; },
+ prev_mask,
+ new_indices);
+ break;
+ }
}
-
- switch (values.type()) {
- case SPREADSHEET_VALUE_TYPE_INT32: {
- const int value = row_filter.value_int;
- switch (row_filter.operation) {
- case SPREADSHEET_ROW_FILTER_EQUAL: {
- apply_filter_operation(
- values,
- [value](const CellValue &cell_value) -> bool {
- return *cell_value.value_int == value;
- },
- rows_included);
- break;
- }
- case SPREADSHEET_ROW_FILTER_GREATER: {
- apply_filter_operation(
- values,
- [value](const CellValue &cell_value) -> bool {
- return *cell_value.value_int > value;
- },
- rows_included);
- break;
- }
- case SPREADSHEET_ROW_FILTER_LESS: {
- apply_filter_operation(
- values,
- [value](const CellValue &cell_value) -> bool {
- return *cell_value.value_int < value;
- },
- rows_included);
- break;
- }
- }
+ }
+ else if (column_data.type().is<int>()) {
+ const int value = row_filter.value_int;
+ switch (row_filter.operation) {
+ case SPREADSHEET_ROW_FILTER_EQUAL: {
+ apply_filter_operation(
+ column_data.typed<int>(),
+ [&](const int cell) { return cell == value; },
+ prev_mask,
+ new_indices);
break;
}
- case SPREADSHEET_VALUE_TYPE_FLOAT: {
- const float value = row_filter.value_float;
- switch (row_filter.operation) {
- case SPREADSHEET_ROW_FILTER_EQUAL: {
- const float threshold = row_filter.threshold;
- apply_filter_operation(
- values,
- [value, threshold](const CellValue &cell_value) -> bool {
- return std::abs(*cell_value.value_float - value) < threshold;
- },
- rows_included);
- break;
- }
- case SPREADSHEET_ROW_FILTER_GREATER: {
- apply_filter_operation(
- values,
- [value](const CellValue &cell_value) -> bool {
- return *cell_value.value_float > value;
- },
- rows_included);
- break;
- }
- case SPREADSHEET_ROW_FILTER_LESS: {
- apply_filter_operation(
- values,
- [value](const CellValue &cell_value) -> bool {
- return *cell_value.value_float < value;
- },
- rows_included);
- break;
- }
- }
+ case SPREADSHEET_ROW_FILTER_GREATER: {
+ apply_filter_operation(
+ column_data.typed<int>(),
+ [value](const int cell) { return cell > value; },
+ prev_mask,
+ new_indices);
break;
}
- case SPREADSHEET_VALUE_TYPE_FLOAT2: {
- const float2 value = row_filter.value_float2;
- switch (row_filter.operation) {
- case SPREADSHEET_ROW_FILTER_EQUAL: {
- const float threshold_squared = row_filter.threshold * row_filter.threshold;
- apply_filter_operation(
- values,
- [value, threshold_squared](const CellValue &cell_value) -> bool {
- return float2::distance_squared(*cell_value.value_float2, value) <
- threshold_squared;
- },
- rows_included);
- break;
- }
- case SPREADSHEET_ROW_FILTER_GREATER: {
- apply_filter_operation(
- values,
- [value](const CellValue &cell_value) -> bool {
- return cell_value.value_float2->x > value.x &&
- cell_value.value_float2->y > value.y;
- },
- rows_included);
- break;
- }
- case SPREADSHEET_ROW_FILTER_LESS: {
- apply_filter_operation(
- values,
- [value](const CellValue &cell_value) -> bool {
- return cell_value.value_float2->x < value.x &&
- cell_value.value_float2->y < value.y;
- },
- rows_included);
- break;
- }
- }
+ case SPREADSHEET_ROW_FILTER_LESS: {
+ apply_filter_operation(
+ column_data.typed<int>(),
+ [&](const int cell) { return cell < value; },
+ prev_mask,
+ new_indices);
break;
}
- case SPREADSHEET_VALUE_TYPE_FLOAT3: {
- const float3 value = row_filter.value_float3;
- switch (row_filter.operation) {
- case SPREADSHEET_ROW_FILTER_EQUAL: {
- const float threshold_squared = row_filter.threshold * row_filter.threshold;
- apply_filter_operation(
- values,
- [value, threshold_squared](const CellValue &cell_value) -> bool {
- return float3::distance_squared(*cell_value.value_float3, value) <
- threshold_squared;
- },
- rows_included);
- break;
- }
- case SPREADSHEET_ROW_FILTER_GREATER: {
- apply_filter_operation(
- values,
- [value](const CellValue &cell_value) -> bool {
- return cell_value.value_float3->x > value.x &&
- cell_value.value_float3->y > value.y &&
- cell_value.value_float3->z > value.z;
- },
- rows_included);
- break;
- }
- case SPREADSHEET_ROW_FILTER_LESS: {
- apply_filter_operation(
- values,
- [value](const CellValue &cell_value) -> bool {
- return cell_value.value_float3->x < value.x &&
- cell_value.value_float3->y < value.y &&
- cell_value.value_float3->z < value.z;
- },
- rows_included);
- break;
- }
- }
+ }
+ }
+ else if (column_data.type().is<float2>()) {
+ const float2 value = row_filter.value_float2;
+ switch (row_filter.operation) {
+ case SPREADSHEET_ROW_FILTER_EQUAL: {
+ const float threshold_sq = row_filter.threshold;
+ apply_filter_operation(
+ column_data.typed<float2>(),
+ [&](const float2 cell) {
+ return float2::distance_squared(cell, value) > threshold_sq;
+ },
+ prev_mask,
+ new_indices);
break;
}
- case SPREADSHEET_VALUE_TYPE_COLOR: {
- const ColorGeometry4f value = row_filter.value_color;
- switch (row_filter.operation) {
- case SPREADSHEET_ROW_FILTER_EQUAL: {
- const float threshold_squared = row_filter.threshold * row_filter.threshold;
- apply_filter_operation(
- values,
- [value, threshold_squared](const CellValue &cell_value) -> bool {
- return len_squared_v4v4(value, *cell_value.value_color) < threshold_squared;
- },
- rows_included);
- break;
- }
- }
+ case SPREADSHEET_ROW_FILTER_GREATER: {
+ apply_filter_operation(
+ column_data.typed<float2>(),
+ [&](const float2 cell) { return cell.x > value.x && cell.y > value.y; },
+ prev_mask,
+ new_indices);
break;
}
- case SPREADSHEET_VALUE_TYPE_BOOL: {
- const bool value = (row_filter.flag & SPREADSHEET_ROW_FILTER_BOOL_VALUE) != 0;
+ case SPREADSHEET_ROW_FILTER_LESS: {
apply_filter_operation(
- values,
- [value](const CellValue &cell_value) -> bool {
- return *cell_value.value_bool == value;
+ column_data.typed<float2>(),
+ [&](const float2 cell) { return cell.x < value.x && cell.y < value.y; },
+ prev_mask,
+ new_indices);
+ break;
+ }
+ }
+ }
+ else if (column_data.type().is<float3>()) {
+ const float3 value = row_filter.value_float3;
+ switch (row_filter.operation) {
+ case SPREADSHEET_ROW_FILTER_EQUAL: {
+ const float threshold_sq = row_filter.threshold;
+ apply_filter_operation(
+ column_data.typed<float3>(),
+ [&](const float3 cell) {
+ return float3::distance_squared(cell, value) > threshold_sq;
},
- rows_included);
+ prev_mask,
+ new_indices);
break;
}
- case SPREADSHEET_VALUE_TYPE_INSTANCES: {
- const StringRef value = row_filter.value_string;
+ case SPREADSHEET_ROW_FILTER_GREATER: {
apply_filter_operation(
- values,
- [value](const CellValue &cell_value) -> bool {
- const ID *id = nullptr;
- if (cell_value.value_object) {
- id = &cell_value.value_object->object->id;
- }
- else if (cell_value.value_collection) {
- id = &cell_value.value_collection->collection->id;
- }
- if (id == nullptr) {
- return false;
- }
-
- return value == id->name + 2;
+ column_data.typed<float3>(),
+ [&](const float3 cell) {
+ return cell.x > value.x && cell.y > value.y && cell.z > value.z;
},
- rows_included);
+ prev_mask,
+ new_indices);
break;
}
- default:
+ case SPREADSHEET_ROW_FILTER_LESS: {
+ apply_filter_operation(
+ column_data.typed<float3>(),
+ [&](const float3 cell) {
+ return cell.x < value.x && cell.y < value.y && cell.z < value.z;
+ },
+ prev_mask,
+ new_indices);
break;
+ }
}
-
- /* Only one column should have this name. */
- break;
}
-}
-
-static void index_vector_from_bools(Span<bool> selection, Vector<int64_t> &indices)
-{
- for (const int i : selection.index_range()) {
- if (selection[i]) {
- indices.append(i);
+ else if (column_data.type().is<ColorGeometry4f>()) {
+ const ColorGeometry4f value = row_filter.value_color;
+ switch (row_filter.operation) {
+ case SPREADSHEET_ROW_FILTER_EQUAL: {
+ const float threshold_sq = row_filter.threshold;
+ apply_filter_operation(
+ column_data.typed<ColorGeometry4f>(),
+ [&](const ColorGeometry4f cell) {
+ return len_squared_v4v4(cell, value) > threshold_sq;
+ },
+ prev_mask,
+ new_indices);
+ break;
+ }
+ }
+ }
+ else if (column_data.type().is<InstanceReference>()) {
+ const StringRef value = row_filter.value_string;
+ switch (row_filter.operation) {
+ case SPREADSHEET_ROW_FILTER_EQUAL: {
+ apply_filter_operation(
+ column_data.typed<InstanceReference>(),
+ [&](const InstanceReference cell) {
+ switch (cell.type()) {
+ case InstanceReference::Type::Object: {
+ return value == (reinterpret_cast<ID &>(cell.object()).name + 2);
+ }
+ case InstanceReference::Type::Collection: {
+ return value == (reinterpret_cast<ID &>(cell.collection()).name + 2);
+ }
+ case InstanceReference::Type::GeometrySet: {
+ return false;
+ }
+ case InstanceReference::Type::None: {
+ return false;
+ }
+ }
+ BLI_assert_unreachable();
+ return false;
+ },
+ prev_mask,
+ new_indices);
+ break;
+ }
}
}
}
@@ -297,10 +255,10 @@ static bool use_selection_filter(const SpaceSpreadsheet &sspreadsheet,
return true;
}
-Span<int64_t> spreadsheet_filter_rows(const SpaceSpreadsheet &sspreadsheet,
- const SpreadsheetLayout &spreadsheet_layout,
- const DataSource &data_source,
- ResourceScope &scope)
+IndexMask spreadsheet_filter_rows(const SpaceSpreadsheet &sspreadsheet,
+ const SpreadsheetLayout &spreadsheet_layout,
+ const DataSource &data_source,
+ ResourceScope &scope)
{
const int tot_rows = data_source.tot_rows();
@@ -309,29 +267,46 @@ Span<int64_t> spreadsheet_filter_rows(const SpaceSpreadsheet &sspreadsheet,
/* Avoid allocating an array if no row filtering is necessary. */
if (!(use_filters || use_selection)) {
- return IndexRange(tot_rows).as_span();
+ return IndexMask(tot_rows);
}
- Array<bool> rows_included(tot_rows, true);
+ IndexMask mask(tot_rows);
+
+ Vector<int64_t> mask_indices;
+ mask_indices.reserve(tot_rows);
+
+ if (use_selection) {
+ const GeometryDataSource *geometry_data_source = dynamic_cast<const GeometryDataSource *>(
+ &data_source);
+ mask = geometry_data_source->apply_selection_filter(mask_indices);
+ }
if (use_filters) {
+ Map<StringRef, const ColumnValues *> columns;
+ for (const ColumnLayout &column : spreadsheet_layout.columns) {
+ columns.add(column.values->name(), column.values);
+ }
+
LISTBASE_FOREACH (const SpreadsheetRowFilter *, row_filter, &sspreadsheet.row_filters) {
if (row_filter->flag & SPREADSHEET_ROW_FILTER_ENABLED) {
- apply_row_filter(spreadsheet_layout, *row_filter, rows_included);
+ if (!columns.contains(row_filter->column_name)) {
+ continue;
+ }
+ Vector<int64_t> new_indices;
+ new_indices.reserve(mask_indices.size());
+ apply_row_filter(*row_filter, columns, mask, new_indices);
+ std::swap(new_indices, mask_indices);
+ mask = IndexMask(mask_indices);
}
}
}
- if (use_selection) {
- const GeometryDataSource *geometry_data_source = dynamic_cast<const GeometryDataSource *>(
- &data_source);
- geometry_data_source->apply_selection_filter(rows_included);
+ if (mask_indices.is_empty()) {
+ BLI_assert(mask.is_empty() || mask.is_range());
+ return mask;
}
- Vector<int64_t> &indices = scope.construct<Vector<int64_t>>();
- index_vector_from_bools(rows_included, indices);
-
- return indices;
+ return IndexMask(scope.add_value(std::move(mask_indices)));
}
SpreadsheetRowFilter *spreadsheet_row_filter_new()
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.hh b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.hh
index 0a5783e318d..3788baaa993 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.hh
@@ -23,10 +23,10 @@
namespace blender::ed::spreadsheet {
-Span<int64_t> spreadsheet_filter_rows(const SpaceSpreadsheet &sspreadsheet,
- const SpreadsheetLayout &spreadsheet_layout,
- const DataSource &data_source,
- ResourceScope &scope);
+IndexMask spreadsheet_filter_rows(const SpaceSpreadsheet &sspreadsheet,
+ const SpreadsheetLayout &spreadsheet_layout,
+ const DataSource &data_source,
+ ResourceScope &scope);
SpreadsheetRowFilter *spreadsheet_row_filter_new();
SpreadsheetRowFilter *spreadsheet_row_filter_copy(const SpreadsheetRowFilter *src_row_filter);
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc
index a07abac4474..bcced7b5937 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc
@@ -114,6 +114,8 @@ static std::string value_string(const SpreadsheetRowFilter &row_filter,
}
case SPREADSHEET_VALUE_TYPE_STRING:
return row_filter.value_string;
+ case SPREADSHEET_VALUE_TYPE_UNKNOWN:
+ return "";
}
BLI_assert_unreachable();
return "";
@@ -238,6 +240,10 @@ static void spreadsheet_filter_panel_draw(const bContext *C, Panel *panel)
uiItemR(layout, filter_ptr, "threshold", 0, nullptr, ICON_NONE);
break;
case SPREADSHEET_VALUE_TYPE_STRING:
+ uiItemR(layout, filter_ptr, "value_string", 0, IFACE_("Value"), ICON_NONE);
+ break;
+ case SPREADSHEET_VALUE_TYPE_UNKNOWN:
+ uiItemL(layout, IFACE_("Unkown column type"), ICON_ERROR);
break;
}
}
diff --git a/source/blender/editors/space_statusbar/space_statusbar.c b/source/blender/editors/space_statusbar/space_statusbar.c
index bf2a5534e0b..91a85e4c4b0 100644
--- a/source/blender/editors/space_statusbar/space_statusbar.c
+++ b/source/blender/editors/space_statusbar/space_statusbar.c
@@ -144,7 +144,6 @@ static void statusbar_header_region_message_subscribe(const wmRegionMessageSubsc
WM_msg_subscribe_rna_anon_prop(mbus, ViewLayer, name, &msg_sub_value_region_tag_redraw);
}
-/* only called once, from space/spacetypes.c */
void ED_spacetype_statusbar(void)
{
SpaceType *st = MEM_callocN(sizeof(*st), "spacetype statusbar");
diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c
index f8dc61f18f2..f449ce50ae3 100644
--- a/source/blender/editors/space_text/space_text.c
+++ b/source/blender/editors/space_text/space_text.c
@@ -417,7 +417,6 @@ static void text_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, I
/********************* registration ********************/
-/* only called once, from space/spacetypes.c */
void ED_spacetype_text(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype text");
diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c
index f8d16e396d4..8fb55ed9b46 100644
--- a/source/blender/editors/space_text/text_draw.c
+++ b/source/blender/editors/space_text/text_draw.c
@@ -200,7 +200,6 @@ int wrap_width(const SpaceText *st, ARegion *region)
return max > 8 ? max : 8;
}
-/* Sets (offl, offc) for transforming (line, curs) to its wrapped position */
void wrap_offset(
const SpaceText *st, ARegion *region, TextLine *linein, int cursin, int *offl, int *offc)
{
@@ -305,7 +304,6 @@ void wrap_offset(
}
}
-/* cursin - mem, offc - view */
void wrap_offset_in_line(
const SpaceText *st, ARegion *region, TextLine *linein, int cursin, int *offl, int *offc)
{
@@ -1671,7 +1669,7 @@ void draw_text_main(SpaceText *st, ARegion *region)
if (st->showlinenrs && !wrap_skip) {
/* Draw line number. */
- UI_FontThemeColor(tdc.font_id, (tmp == text->curl) ? TH_HILITE : TH_LINENUMBERS);
+ UI_FontThemeColor(tdc.font_id, (tmp == text->sell) ? TH_HILITE : TH_LINENUMBERS);
BLI_snprintf(linenr,
sizeof(linenr),
"%*d",
@@ -1754,8 +1752,6 @@ bool ED_text_activate_in_screen(bContext *C, Text *text)
return false;
}
-/* Moves the view to the cursor location,
- * also used to make sure the view isn't outside the file */
void ED_text_scroll_to_cursor(SpaceText *st, ARegion *region, const bool center)
{
Text *text;
@@ -1823,7 +1819,6 @@ void ED_text_scroll_to_cursor(SpaceText *st, ARegion *region, const bool center)
st->runtime.scroll_ofs_px[1] = 0;
}
-/* takes an area instead of a region, use for listeners */
void text_scroll_to_cursor__area(SpaceText *st, ScrArea *area, const bool center)
{
ARegion *region;
@@ -1847,9 +1842,6 @@ void text_update_cursor_moved(bContext *C)
text_scroll_to_cursor__area(st, area, true);
}
-/**
- * Takes a cursor (row, character) and returns x,y pixel coords.
- */
bool ED_text_region_location_from_cursor(SpaceText *st,
ARegion *region,
const int cursor_co[2],
diff --git a/source/blender/editors/space_text/text_format.c b/source/blender/editors/space_text/text_format.c
index 66765206fa6..cf0a7c089b5 100644
--- a/source/blender/editors/space_text/text_format.c
+++ b/source/blender/editors/space_text/text_format.c
@@ -111,7 +111,6 @@ void flatten_string_free(FlattenString *fs)
}
}
-/* takes a string within fs->buf and returns its length */
int flatten_string_strlen(FlattenString *fs, const char *str)
{
const int len = (fs->pos - (int)(str - fs->buf)) - 1;
@@ -119,8 +118,6 @@ int flatten_string_strlen(FlattenString *fs, const char *str)
return len;
}
-/* Ensures the format string for the given line is long enough, reallocating
- * as needed. Allocation is done here, alone, to ensure consistency. */
int text_check_format_len(TextLine *line, uint len)
{
if (line->format) {
@@ -142,12 +139,6 @@ int text_check_format_len(TextLine *line, uint len)
return 1;
}
-/**
- * Fill the string with formatting constant,
- * advancing \a str_p and \a fmt_p
- *
- * \param len: length in bytes of \a fmt_p to fill.
- */
void text_format_fill(const char **str_p, char **fmt_p, const char type, const int len)
{
const char *str = *str_p;
@@ -170,10 +161,6 @@ void text_format_fill(const char **str_p, char **fmt_p, const char type, const i
*str_p = str;
*fmt_p = fmt;
}
-/**
- * ascii version of #text_format_fill,
- * use when we no the text being stepped over is ascii (as is the case for most keywords)
- */
void text_format_fill_ascii(const char **str_p, char **fmt_p, const char type, const int len)
{
const char *str = *str_p;
diff --git a/source/blender/editors/space_text/text_format.h b/source/blender/editors/space_text/text_format.h
index fe7b3328030..01c40b4ed22 100644
--- a/source/blender/editors/space_text/text_format.h
+++ b/source/blender/editors/space_text/text_format.h
@@ -33,7 +33,9 @@ typedef struct FlattenString {
int pos, len;
} FlattenString;
-/* format continuation flags (stored just after the NULL terminator) */
+/**
+ * Format continuation flags (stored just after the NULL terminator).
+ */
enum {
FMT_CONT_NOP = 0, /* no continuation */
FMT_CONT_QUOTESINGLE = (1 << 0), /* single quotes */
@@ -48,10 +50,27 @@ enum {
int flatten_string(const struct SpaceText *st, FlattenString *fs, const char *in);
void flatten_string_free(FlattenString *fs);
+/**
+ * Takes a string within `fs->buf` and returns its length.
+ */
int flatten_string_strlen(FlattenString *fs, const char *str);
+/**
+ * Ensures the format string for the given line is long enough, reallocating
+ * as needed. Allocation is done here, alone, to ensure consistency.
+ */
int text_check_format_len(TextLine *line, unsigned int len);
+/**
+ * Fill the string with formatting constant,
+ * advancing \a str_p and \a fmt_p
+ *
+ * \param len: length in bytes of \a fmt_p to fill.
+ */
void text_format_fill(const char **str_p, char **fmt_p, const char type, const int len);
+/**
+ * ASCII version of #text_format_fill,
+ * use when we no the text being stepped over is ascii (as is the case for most keywords)
+ */
void text_format_fill_ascii(const char **str_p, char **fmt_p, const char type, const int len);
/* *** Generalize Formatting *** */
diff --git a/source/blender/editors/space_text/text_intern.h b/source/blender/editors/space_text/text_intern.h
index 241e0133a8a..3cae4188932 100644
--- a/source/blender/editors/space_text/text_intern.h
+++ b/source/blender/editors/space_text/text_intern.h
@@ -39,6 +39,9 @@ void draw_text_main(struct SpaceText *st, struct ARegion *region);
void text_update_line_edited(struct TextLine *line);
void text_update_edited(struct Text *text);
void text_update_character_width(struct SpaceText *st);
+/**
+ * Takes an area instead of a region, use for listeners.
+ */
void text_scroll_to_cursor__area(struct SpaceText *st, struct ScrArea *area, const bool center);
void text_update_cursor_moved(struct bContext *C);
@@ -73,12 +76,18 @@ void text_update_cursor_moved(struct bContext *C);
#define TOOL_DOCUMENT 0x02
int wrap_width(const struct SpaceText *st, struct ARegion *region);
+/**
+ * Sets (offl, offc) for transforming (line, curs) to its wrapped position.
+ */
void wrap_offset(const struct SpaceText *st,
struct ARegion *region,
struct TextLine *linein,
int cursin,
int *offl,
int *offc);
+/**
+ * cursin - mem, offc - view.
+ */
void wrap_offset_in_line(const struct SpaceText *st,
struct ARegion *region,
struct TextLine *linein,
diff --git a/source/blender/editors/space_text/text_undo.c b/source/blender/editors/space_text/text_undo.c
index 80af7d8c9f6..3e40593d40e 100644
--- a/source/blender/editors/space_text/text_undo.c
+++ b/source/blender/editors/space_text/text_undo.c
@@ -252,8 +252,6 @@ static void text_undosys_foreach_ID_ref(UndoStep *us_p,
foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->text_ref));
}
-/* Export for ED_undo_sys. */
-
void ED_text_undosys_type(UndoType *ut)
{
ut->name = "Text";
@@ -276,7 +274,6 @@ void ED_text_undosys_type(UndoType *ut)
/** \name Utilities
* \{ */
-/* Use operator system to finish the undo step. */
UndoStep *ED_text_undo_push_init(bContext *C)
{
UndoStack *ustack = ED_undo_stack_get();
diff --git a/source/blender/editors/space_topbar/space_topbar.c b/source/blender/editors/space_topbar/space_topbar.c
index 419721cf89e..7f0f30624cb 100644
--- a/source/blender/editors/space_topbar/space_topbar.c
+++ b/source/blender/editors/space_topbar/space_topbar.c
@@ -35,6 +35,7 @@
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_screen.h"
+#include "BKE_undo_system.h"
#include "ED_screen.h"
#include "ED_space_api.h"
@@ -236,7 +237,59 @@ static void recent_files_menu_register(void)
WM_menutype_add(mt);
}
-/* only called once, from space/spacetypes.c */
+static void undo_history_draw_menu(const bContext *C, Menu *menu)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ if (wm->undo_stack == NULL) {
+ return;
+ }
+ int undo_step_count = 0;
+ for (UndoStep *us = wm->undo_stack->steps.first; us; us = us->next) {
+ if (us->skip) {
+ continue;
+ }
+ undo_step_count += 1;
+ }
+
+ uiLayout *split = uiLayoutSplit(menu->layout, 0.0f, false);
+ uiLayout *column = NULL;
+
+ const int col_size = 20 + (undo_step_count / 12);
+ int i = 0;
+
+ undo_step_count = 0;
+ for (UndoStep *us = wm->undo_stack->steps.first; us; us = us->next, i++) {
+ if (us->skip) {
+ continue;
+ }
+ if (!(undo_step_count % col_size)) {
+ column = uiLayoutColumn(split, false);
+ }
+ const bool is_active = (us == wm->undo_stack->step_active);
+ uiLayout *row = uiLayoutRow(column, false);
+ uiLayoutSetEnabled(row, !is_active);
+ uiItemIntO(row,
+ IFACE_(us->name),
+ is_active ? ICON_LAYER_ACTIVE : ICON_NONE,
+ "ED_OT_undo_history",
+ "item",
+ i);
+ undo_step_count += 1;
+ }
+}
+
+static void undo_history_menu_register(void)
+{
+ MenuType *mt;
+
+ mt = MEM_callocN(sizeof(MenuType), __func__);
+ strcpy(mt->idname, "TOPBAR_MT_undo_history");
+ strcpy(mt->label, N_("Undo History"));
+ strcpy(mt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
+ mt->draw = undo_history_draw_menu;
+ WM_menutype_add(mt);
+}
+
void ED_spacetype_topbar(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype topbar");
@@ -279,6 +332,7 @@ void ED_spacetype_topbar(void)
BLI_addhead(&st->regiontypes, art);
recent_files_menu_register();
+ undo_history_menu_register();
BKE_spacetype_register(st);
}
diff --git a/source/blender/editors/space_userpref/space_userpref.c b/source/blender/editors/space_userpref/space_userpref.c
index ceba8ca268d..1711188fca7 100644
--- a/source/blender/editors/space_userpref/space_userpref.c
+++ b/source/blender/editors/space_userpref/space_userpref.c
@@ -199,7 +199,6 @@ static void userpref_execute_region_listener(const wmRegionListenerParams *UNUSE
{
}
-/* only called once, from space/spacetypes.c */
void ED_spacetype_userpref(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype userpref");
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index e54ef3c931a..8822ea6af3b 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -91,7 +91,6 @@
/* ******************** manage regions ********************* */
-/* function to always find a regionview3d context inside 3D window */
RegionView3D *ED_view3d_context_rv3d(bContext *C)
{
RegionView3D *rv3d = CTX_wm_region_view3d(C);
@@ -108,8 +107,6 @@ RegionView3D *ED_view3d_context_rv3d(bContext *C)
return rv3d;
}
-/* ideally would return an rv3d but in some cases the region is needed too
- * so return that, the caller can then access the region->regiondata */
bool ED_view3d_context_user_region(bContext *C, View3D **r_v3d, ARegion **r_region)
{
ScrArea *area = CTX_wm_area(C);
@@ -140,10 +137,6 @@ bool ED_view3d_context_user_region(bContext *C, View3D **r_v3d, ARegion **r_regi
return false;
}
-/**
- * Similar to #ED_view3d_context_user_region() but does not use context. Always performs a lookup.
- * Also works if \a v3d is not the active space.
- */
bool ED_view3d_area_user_region(const ScrArea *area, const View3D *v3d, ARegion **r_region)
{
RegionView3D *rv3d = NULL;
@@ -182,17 +175,6 @@ bool ED_view3d_area_user_region(const ScrArea *area, const View3D *v3d, ARegion
return false;
}
-/* Most of the time this isn't needed since you could assume the view matrix was
- * set while drawing, however when functions like mesh_foreachScreenVert are
- * called by selection tools, we can't be sure this object was the last.
- *
- * for example, transparent objects are drawn after editmode and will cause
- * the rv3d mat's to change and break selection.
- *
- * 'ED_view3d_init_mats_rv3d' should be called before
- * view3d_project_short_clip and view3d_project_short_noclip in cases where
- * these functions are not used during draw_object
- */
void ED_view3d_init_mats_rv3d(const struct Object *ob, struct RegionView3D *rv3d)
{
/* local viewmat and persmat, to calculate projections */
@@ -214,7 +196,6 @@ void ED_view3d_init_mats_rv3d_gl(const struct Object *ob, struct RegionView3D *r
}
#ifdef DEBUG
-/* ensure we correctly initialize */
void ED_view3d_clear_mats_rv3d(struct RegionView3D *rv3d)
{
zero_m4(rv3d->viewmatob);
@@ -1294,6 +1275,7 @@ static void view3d_main_region_message_subscribe(const wmRegionMessageSubscribeP
&RNA_Object,
&RNA_UnitSettings, /* grid-floor */
+ &RNA_View3DCursor,
&RNA_View3DOverlay,
&RNA_View3DShading,
&RNA_World,
@@ -1878,7 +1860,6 @@ static void view3d_id_remap(ScrArea *area, SpaceLink *slink, ID *old_id, ID *new
}
}
-/* only called once, from space/spacetypes.c */
void ED_spacetype_view3d(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype view3d");
diff --git a/source/blender/editors/space_view3d/view3d_camera_control.c b/source/blender/editors/space_view3d/view3d_camera_control.c
index 8380c87b999..535a65c8f0c 100644
--- a/source/blender/editors/space_view3d/view3d_camera_control.c
+++ b/source/blender/editors/space_view3d/view3d_camera_control.c
@@ -102,9 +102,6 @@ BLI_INLINE Object *view3d_cameracontrol_object(const View3DCameraControl *vctrl)
return vctrl->root_parent ? vctrl->root_parent : vctrl->ctx_v3d->camera;
}
-/**
- * Returns the object which is being manipulated or NULL.
- */
Object *ED_view3d_cameracontrol_object_get(View3DCameraControl *vctrl)
{
RegionView3D *rv3d = vctrl->ctx_rv3d;
@@ -116,10 +113,6 @@ Object *ED_view3d_cameracontrol_object_get(View3DCameraControl *vctrl)
return NULL;
}
-/**
- * Creates a #View3DCameraControl handle and sets up
- * the view for first-person style navigation.
- */
struct View3DCameraControl *ED_view3d_cameracontrol_acquire(Depsgraph *depsgraph,
Scene *scene,
View3D *v3d,
@@ -243,9 +236,6 @@ static bool object_apply_mat4_with_protect(Object *ob,
return view_changed;
}
-/**
- * Updates cameras from the `rv3d` values, optionally auto-keyframing.
- */
void ED_view3d_cameracontrol_update(View3DCameraControl *vctrl,
/* args for keyframing */
const bool use_autokey,
@@ -317,12 +307,6 @@ void ED_view3d_cameracontrol_update(View3DCameraControl *vctrl,
}
}
-/**
- * Release view control.
- *
- * \param restore: Sets the view state to the values that were set
- * before #ED_view3d_control_acquire was called.
- */
void ED_view3d_cameracontrol_release(View3DCameraControl *vctrl, const bool restore)
{
View3D *v3d = vctrl->ctx_v3d;
diff --git a/source/blender/editors/space_view3d/view3d_cursor_snap.c b/source/blender/editors/space_view3d/view3d_cursor_snap.c
index ac80a70011a..f5abba2c674 100644
--- a/source/blender/editors/space_view3d/view3d_cursor_snap.c
+++ b/source/blender/editors/space_view3d/view3d_cursor_snap.c
@@ -94,7 +94,7 @@ typedef struct SnapCursorDataIntern {
} SnapCursorDataIntern;
static SnapCursorDataIntern g_data_intern = {
- .state_default = {.prevpoint = NULL,
+ .state_default = {.flag = V3D_SNAPCURSOR_SNAP_EDIT_GEOM_FINAL,
.snap_elem_force = SCE_SNAP_MODE_GEOM,
.plane_axis = 2,
.color_point = {255, 255, 255, 255},
@@ -104,6 +104,12 @@ static SnapCursorDataIntern g_data_intern = {
.draw_point = true}};
/**
+ * Dot products below this will be considered view aligned.
+ * In this case we can't usefully project the mouse cursor onto the plane.
+ */
+static const float eps_view_align = 1e-2f;
+
+/**
* Calculate a 3x3 orientation matrix from the surface under the cursor.
*/
static void v3d_cursor_poject_surface_normal(const float normal[3],
@@ -714,14 +720,19 @@ static void v3d_cursor_snap_update(V3DSnapCursorState *state,
float *co_depth = snap_elem ? co : scene->cursor.location;
snap_elem &= ~data_intern->snap_elem_hidden;
if (snap_elem == 0) {
- float plane[4];
- if (state->plane_depth != V3D_PLACE_DEPTH_CURSOR_VIEW) {
- const float *plane_normal = omat[state->plane_axis];
+ RegionView3D *rv3d = region->regiondata;
+ const float *plane_normal = omat[state->plane_axis];
+ bool do_plane_isect = (state->plane_depth != V3D_PLACE_DEPTH_CURSOR_VIEW) &&
+ (rv3d->is_persp ||
+ (fabsf(dot_v3v3(plane_normal, rv3d->viewinv[2])) > eps_view_align));
+
+ if (do_plane_isect) {
+ float plane[4];
plane_from_point_normal_v3(plane, co_depth, plane_normal);
+ do_plane_isect = ED_view3d_win_to_3d_on_plane(region, plane, mval_fl, rv3d->is_persp, co);
}
- if ((state->plane_depth == V3D_PLACE_DEPTH_CURSOR_VIEW) ||
- !ED_view3d_win_to_3d_on_plane(region, plane, mval_fl, true, co)) {
+ if (!do_plane_isect) {
ED_view3d_win_to_3d(v3d, region, co_depth, mval_fl, co);
}
@@ -919,6 +930,14 @@ static void v3d_cursor_snap_free(void)
void ED_view3d_cursor_snap_state_default_set(V3DSnapCursorState *state)
{
g_data_intern.state_default = *state;
+
+ /* These values are temporarily set by the tool.
+ * They are not convenient as default values.
+ * So reset to null. */
+ g_data_intern.state_default.gzgrp_type = NULL;
+ g_data_intern.state_default.prevpoint = NULL;
+ g_data_intern.state_default.draw_plane = false;
+ g_data_intern.state_default.draw_box = false;
}
V3DSnapCursorState *ED_view3d_cursor_snap_active(void)
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index 6f6fa8b7576..a7d170982ed 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -108,9 +108,6 @@
/** \name General Functions
* \{ */
-/**
- * \note keep this synced with #ED_view3d_mats_rv3d_backup/#ED_view3d_mats_rv3d_restore
- */
void ED_view3d_update_viewmat(Depsgraph *depsgraph,
const Scene *scene,
View3D *v3d,
@@ -355,9 +352,6 @@ static void view3d_xr_mirror_setup(const wmWindowManager *wm,
}
#endif /* WITH_XR_OPENXR */
-/**
- * Set the correct matrices
- */
void ED_view3d_draw_setup_view(const wmWindowManager *wm,
wmWindow *win,
Depsgraph *depsgraph,
@@ -848,7 +842,6 @@ static void drawrenderborder(ARegion *region, View3D *v3d)
/** \name Other Elements
* \{ */
-/** could move this elsewhere, but tied into #ED_view3d_grid_scale */
float ED_scene_grid_scale(const Scene *scene, const char **r_grid_unit)
{
/* apply units */
@@ -921,9 +914,6 @@ void ED_view3d_grid_steps(const Scene *scene,
}
}
-/* Simulates the grid scale that is actually viewed.
- * The actual code is seen in `object_grid_frag.glsl` (see `grid_res`).
- * Currently the simulation is only done when RV3D_VIEW_IS_AXIS. */
float ED_view3d_grid_view_scale(Scene *scene,
View3D *v3d,
ARegion *region,
@@ -1472,9 +1462,6 @@ static void draw_grid_unit_name(
}
}
-/**
- * Information drawn on top of the solid plates and composed data
- */
void view3d_draw_region_info(const bContext *C, ARegion *region)
{
RegionView3D *rv3d = region->regiondata;
@@ -1751,10 +1738,6 @@ void ED_view3d_draw_offscreen(Depsgraph *depsgraph,
G.f &= ~G_FLAG_RENDER_VIEWPORT;
}
-/**
- * Creates own fake 3d views (wrapping #ED_view3d_draw_offscreen). Similar too
- * #ED_view_draw_offscreen_imbuf_simple, but takes view/projection matrices as arguments.
- */
void ED_view3d_draw_offscreen_simple(Depsgraph *depsgraph,
Scene *scene,
View3DShading *shading_override,
@@ -1853,12 +1836,6 @@ void ED_view3d_draw_offscreen_simple(Depsgraph *depsgraph,
viewport);
}
-/**
- * Utility func for ED_view3d_draw_offscreen
- *
- * \param ofs: Optional off-screen buffer, can be NULL.
- * (avoids re-creating when doing multiple GL renders).
- */
ImBuf *ED_view3d_draw_offscreen_imbuf(Depsgraph *depsgraph,
Scene *scene,
eDrawType drawtype,
@@ -2008,14 +1985,6 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(Depsgraph *depsgraph,
return ibuf;
}
-/**
- * Creates own fake 3d views (wrapping #ED_view3d_draw_offscreen_imbuf)
- *
- * \param ofs: Optional off-screen buffer can be NULL.
- * (avoids re-creating when doing multiple GL renders).
- *
- * \note used by the sequencer
- */
ImBuf *ED_view3d_draw_offscreen_imbuf_simple(Depsgraph *depsgraph,
Scene *scene,
View3DShading *shading_override,
@@ -2046,6 +2015,15 @@ ImBuf *ED_view3d_draw_offscreen_imbuf_simple(Depsgraph *depsgraph,
}
memcpy(&v3d.shading, source_shading_settings, sizeof(View3DShading));
+ if (drawtype == OB_RENDER) {
+ /* Don't use external engines for preview. Fall back to solid instead of Eevee as rendering
+ * with Eevee is potentially slow due to compiling shaders and loading textures, and the
+ * depsgraph may not have been updated to have all the right geometry attributes. */
+ if (!(BKE_scene_uses_blender_eevee(scene) || BKE_scene_uses_blender_workbench(scene))) {
+ drawtype = OB_SOLID;
+ }
+ }
+
if (drawtype == OB_MATERIAL) {
v3d.shading.flag = V3D_SHADING_SCENE_WORLD | V3D_SHADING_SCENE_LIGHTS;
v3d.shading.render_pass = SCE_PASS_COMBINED;
@@ -2137,15 +2115,6 @@ static bool view3d_clipping_test(const float co[3], const float clip[6][4])
return true;
}
-/**
- * Return true when `co` is hidden by the 3D views clipping planes.
- *
- * \param local: When true use local (object-space) #ED_view3d_clipping_local must run first,
- * then all comparisons can be done in local-space.
- * \return True when `co` is outside all clipping planes.
- *
- * \note Callers should check #RV3D_CLIPPING_ENABLED first.
- */
bool ED_view3d_clipping_test(const RegionView3D *rv3d, const float co[3], const bool is_local)
{
return view3d_clipping_test(co, is_local ? rv3d->clip_local : rv3d->clip);
@@ -2231,10 +2200,6 @@ void ED_view3d_select_id_validate(ViewContext *vc)
validate_object_select_id(vc->depsgraph, vc->view_layer, vc->region, vc->v3d, vc->obact);
}
-/**
- * allow for small values [0.5 - 2.5],
- * and large values, FLT_MAX by clamping by the area size
- */
int ED_view3d_backbuf_sample_size_clamp(ARegion *region, const float dist)
{
return (int)min_ff(ceilf(dist), (float)max_ii(region->winx, region->winx));
@@ -2311,7 +2276,6 @@ static ViewDepths *view3d_depths_create(ARegion *region)
return d;
}
-/* Utility function to find the closest Z value, use for auto-depth. */
float view3d_depth_near(ViewDepths *d)
{
/* Convert to float for comparisons. */
@@ -2335,14 +2299,6 @@ float view3d_depth_near(ViewDepths *d)
return far == far_real ? FLT_MAX : far;
}
-/**
- * Redraw the viewport depth buffer.
- *
- * \param mode: V3D_DEPTH_NO_GPENCIL - Redraw viewport without Grease Pencil and Annotations.
- * V3D_DEPTH_GPENCIL_ONLY - Redraw viewport with Grease Pencil and Annotations only.
- * V3D_DEPTH_OBJECT_ONLY - Redraw viewport with active object only.
- * \param update_cache: If true, store the entire depth buffer in #rv3d->depths.
- */
void ED_view3d_depth_override(Depsgraph *depsgraph,
ARegion *region,
View3D *v3d,
@@ -2457,7 +2413,6 @@ void ED_view3d_datamask(const bContext *C,
}
}
-/* Goes over all modes and view3d settings. */
void ED_view3d_screen_datamask(const bContext *C,
const Scene *scene,
const bScreen *screen,
@@ -2527,10 +2482,6 @@ void ED_view3d_mats_rv3d_restore(struct RegionView3D *rv3d, struct RV3DMatrixSto
/** \name FPS Drawing
* \{ */
-/**
- * \note The info that this uses is updated in #ED_refresh_viewport_fps,
- * which currently gets called during #SCREEN_OT_animation_step.
- */
void ED_scene_draw_fps(const Scene *scene, int xoffset, int *yoffset)
{
ScreenFrameRateInfo *fpsi = scene->fps_info;
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index b85b424405e..830f7cbeff1 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -618,7 +618,6 @@ enum {
VIEWROT_MODAL_SWITCH_ROTATE = 6,
};
-/* Called in transform_ops.c, on each regeneration of key-maps. */
void viewrotate_modal_keymap(wmKeyConfig *keyconf)
{
static const EnumPropertyItem modal_items[] = {
@@ -1250,9 +1249,6 @@ static void view3d_ndof_orbit(const struct wmNDOFMotionData *ndof,
}
}
-/**
- * Called from both fly mode and walk mode,
- */
void view3d_ndof_fly(const wmNDOFMotionData *ndof,
View3D *v3d,
RegionView3D *rv3d,
@@ -1685,7 +1681,6 @@ void VIEW3D_OT_ndof_all(struct wmOperatorType *ot)
/* NOTE: these defines are saved in keymap files, do not change values but just add new ones */
-/* Called in transform_ops.c, on each regeneration of key-maps. */
void viewmove_modal_keymap(wmKeyConfig *keyconf)
{
static const EnumPropertyItem modal_items[] = {
@@ -1882,7 +1877,6 @@ void VIEW3D_OT_move(wmOperatorType *ot)
* \{ */
/* #viewdolly_modal_keymap has an exact copy of this, apply fixes to both. */
-/* Called in transform_ops.c, on each regeneration of key-maps. */
void viewzoom_modal_keymap(wmKeyConfig *keyconf)
{
static const EnumPropertyItem modal_items[] = {
@@ -2446,7 +2440,6 @@ void VIEW3D_OT_zoom(wmOperatorType *ot)
* \{ */
/* This is an exact copy of #viewzoom_modal_keymap. */
-/* Called in transform_ops.c, on each regeneration of key-maps. */
void viewdolly_modal_keymap(wmKeyConfig *keyconf)
{
static const EnumPropertyItem modal_items[] = {
@@ -3059,6 +3052,23 @@ static int viewselected_exec(bContext *C, wmOperator *op)
if ((gps->flag & GP_STROKE_SELECT) && (gps->flag & GP_STROKE_3DSPACE)) {
ok |= BKE_gpencil_stroke_minmax(gps, true, min, max);
}
+ if (gps->editcurve != NULL) {
+ for (int i = 0; i < gps->editcurve->tot_curve_points; i++) {
+ BezTriple *bezt = &gps->editcurve->curve_points[i].bezt;
+ if ((bezt->f1 & SELECT)) {
+ minmax_v3v3_v3(min, max, bezt->vec[0]);
+ ok = true;
+ }
+ if ((bezt->f2 & SELECT)) {
+ minmax_v3v3_v3(min, max, bezt->vec[1]);
+ ok = true;
+ }
+ if ((bezt->f3 & SELECT)) {
+ minmax_v3v3_v3(min, max, bezt->vec[2]);
+ ok = true;
+ }
+ }
+ }
}
CTX_DATA_END;
@@ -5010,7 +5020,6 @@ void VIEW3D_OT_clip_border(wmOperatorType *ot)
* \{ */
/* cursor position in vec, result in vec, mval in region coords */
-/* NOTE: cannot use `event->mval` here, called by #object_add(). */
void ED_view3d_cursor3d_position(bContext *C,
const int mval[2],
const bool use_depth,
diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h
index a21fc006b02..7388004125c 100644
--- a/source/blender/editors/space_view3d/view3d_intern.h
+++ b/source/blender/editors/space_view3d/view3d_intern.h
@@ -91,7 +91,13 @@ void VIEW3D_OT_zoom_border(struct wmOperatorType *ot);
void VIEW3D_OT_toggle_shading(struct wmOperatorType *ot);
void VIEW3D_OT_toggle_xray(struct wmOperatorType *ot);
+/**
+ * For home, center etc.
+ */
void view3d_boxview_copy(struct ScrArea *area, struct ARegion *region);
+/**
+ * Sync center/zoom view of region to others, for view transforms.
+ */
void view3d_boxview_sync(struct ScrArea *area, struct ARegion *region);
void view3d_orbit_apply_dyn_ofs(float r_ofs[3],
@@ -103,6 +109,9 @@ void view3d_orbit_apply_dyn_ofs(float r_ofs[3],
#ifdef WITH_INPUT_NDOF
struct wmNDOFMotionData;
+/**
+ * Called from both fly mode and walk mode,
+ */
void view3d_ndof_fly(const struct wmNDOFMotionData *ndof,
struct View3D *v3d,
struct RegionView3D *rv3d,
@@ -113,17 +122,24 @@ void view3d_ndof_fly(const struct wmNDOFMotionData *ndof,
#endif /* WITH_INPUT_NDOF */
/* view3d_navigate_fly.c */
+
void view3d_keymap(struct wmKeyConfig *keyconf);
void VIEW3D_OT_fly(struct wmOperatorType *ot);
/* view3d_navigate_walk.c */
+
void VIEW3D_OT_walk(struct wmOperatorType *ot);
/* view3d_draw.c */
+
void view3d_main_region_draw(const struct bContext *C, struct ARegion *region);
+/**
+ * Information drawn on top of the solid plates and composed data.
+ */
void view3d_draw_region_info(const struct bContext *C, struct ARegion *region);
/* view3d_draw_legacy.c */
+
void ED_view3d_draw_select_loop(struct Depsgraph *depsgraph,
ViewContext *vc,
Scene *scene,
@@ -139,6 +155,9 @@ void ED_view3d_draw_depth_loop(struct Depsgraph *depsgraph,
View3D *v3d);
void view3d_depths_rect_create(struct ARegion *region, struct rcti *rect, struct ViewDepths *r_d);
+/**
+ * Utility function to find the closest Z value, use for auto-depth.
+ */
float view3d_depth_near(struct ViewDepths *d);
/* view3d_select.c */
@@ -175,6 +194,9 @@ typedef struct V3D_SmoothParams {
const float *dyn_ofs;
} V3D_SmoothParams;
+/**
+ * The arguments are the desired situation.
+ */
void ED_view3d_smooth_view_ex(const struct Depsgraph *depsgraph,
struct wmWindowManager *wm,
struct wmWindow *win,
@@ -190,20 +212,41 @@ void ED_view3d_smooth_view(struct bContext *C,
const int smooth_viewtx,
const V3D_SmoothParams *sview);
+/**
+ * Apply the smooth-view immediately, use when we need to start a new view operation.
+ * (so we don't end up half-applying a view operation when pressing keys quickly).
+ */
void ED_view3d_smooth_view_force_finish(struct bContext *C,
struct View3D *v3d,
struct ARegion *region);
+/**
+ * \param rect: optional for picking (can be NULL).
+ */
void view3d_winmatrix_set(struct Depsgraph *depsgraph,
struct ARegion *region,
const View3D *v3d,
const rcti *rect);
+/**
+ * Sets #RegionView3D.viewmat
+ *
+ * \param depsgraph: Depsgraph.
+ * \param scene: Scene for camera and cursor location.
+ * \param v3d: View 3D space data.
+ * \param rv3d: 3D region which stores the final matrices.
+ * \param rect_scale: Optional 2D scale argument,
+ * Use when displaying a sub-region, eg: when #view3d_winmatrix_set takes a 'rect' argument.
+ *
+ * \note don't set windows active in here, is used by renderwin too.
+ */
void view3d_viewmatrix_set(struct Depsgraph *depsgraph,
const struct Scene *scene,
const View3D *v3d,
RegionView3D *rv3d,
const float rect_scale[2]);
+/* Called in transform_ops.c, on each regeneration of key-maps. */
+
void fly_modal_keymap(struct wmKeyConfig *keyconf);
void walk_modal_keymap(struct wmKeyConfig *keyconf);
void viewrotate_modal_keymap(struct wmKeyConfig *keyconf);
@@ -213,23 +256,46 @@ void viewdolly_modal_keymap(struct wmKeyConfig *keyconf);
void viewplace_modal_keymap(struct wmKeyConfig *keyconf);
/* view3d_buttons.c */
+
void VIEW3D_OT_object_mode_pie_or_toggle(struct wmOperatorType *ot);
void view3d_buttons_register(struct ARegionType *art);
/* view3d_camera_control.c */
+
+/**
+ * Creates a #View3DCameraControl handle and sets up
+ * the view for first-person style navigation.
+ */
struct View3DCameraControl *ED_view3d_cameracontrol_acquire(struct Depsgraph *depsgraph,
Scene *scene,
View3D *v3d,
RegionView3D *rv3d);
+/**
+ * Updates cameras from the `rv3d` values, optionally auto-keyframing.
+ */
void ED_view3d_cameracontrol_update(struct View3DCameraControl *vctrl,
const bool use_autokey,
struct bContext *C,
const bool do_rotate,
const bool do_translate);
+/**
+ * Release view control.
+ *
+ * \param restore: Sets the view state to the values that were set
+ * before #ED_view3d_control_acquire was called.
+ */
void ED_view3d_cameracontrol_release(struct View3DCameraControl *vctrl, const bool restore);
+/**
+ * Returns the object which is being manipulated or NULL.
+ */
struct Object *ED_view3d_cameracontrol_object_get(struct View3DCameraControl *vctrl);
/* view3d_snap.c */
+
+/**
+ * Calculates the bounding box corners (min and max) for \a obedit.
+ * The returned values are in global space.
+ */
bool ED_view3d_minmax_verts(struct Object *obedit, float min[3], float max[3]);
void VIEW3D_OT_snap_selected_to_grid(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_view3d/view3d_iterators.c b/source/blender/editors/space_view3d/view3d_iterators.c
index 20e00356152..16d9b9182cf 100644
--- a/source/blender/editors/space_view3d/view3d_iterators.c
+++ b/source/blender/editors/space_view3d/view3d_iterators.c
@@ -486,10 +486,6 @@ static void mesh_foreachScreenEdge_clip_bb_segment__mapFunc(void *userData,
data->func(data->userData, eed, screen_co_a, screen_co_b, index);
}
-/**
- * A version of #mesh_foreachScreenEdge that clips the segment when
- * there is a clipping bounding box.
- */
void mesh_foreachScreenEdge_clip_bb_segment(ViewContext *vc,
void (*func)(void *userData,
BMEdge *eed,
@@ -691,7 +687,6 @@ void nurbs_foreachScreenVert(ViewContext *vc,
/** \name Edit-Meta: For Each Screen Meta-Element
* \{ */
-/* ED_view3d_init_mats_rv3d must be called first */
void mball_foreachScreenElem(struct ViewContext *vc,
void (*func)(void *userData,
struct MetaElem *ml,
@@ -756,7 +751,6 @@ void lattice_foreachScreenVert(ViewContext *vc,
/** \name Edit-Armature: For Each Screen Bone
* \{ */
-/* ED_view3d_init_mats_rv3d must be called first */
void armature_foreachScreenBone(struct ViewContext *vc,
void (*func)(void *userData,
struct EditBone *ebone,
@@ -824,8 +818,6 @@ void armature_foreachScreenBone(struct ViewContext *vc,
/** \name Pose: For Each Screen Bone
* \{ */
-/* ED_view3d_init_mats_rv3d must be called first */
-/* almost _exact_ copy of #armature_foreachScreenBone */
void pose_foreachScreenBone(struct ViewContext *vc,
void (*func)(void *userData,
struct bPoseChannel *pchan,
@@ -834,6 +826,8 @@ void pose_foreachScreenBone(struct ViewContext *vc,
void *userData,
const eV3DProjTest clip_flag)
{
+ /* Almost _exact_ copy of #armature_foreachScreenBone */
+
const Object *ob_eval = DEG_get_evaluated_object(vc->depsgraph, vc->obact);
const bArmature *arm_eval = ob_eval->data;
bPose *pose = vc->obact->pose;
diff --git a/source/blender/editors/space_view3d/view3d_navigate_fly.c b/source/blender/editors/space_view3d/view3d_navigate_fly.c
index f48e436e014..2e9cb419e2e 100644
--- a/source/blender/editors/space_view3d/view3d_navigate_fly.c
+++ b/source/blender/editors/space_view3d/view3d_navigate_fly.c
@@ -101,7 +101,6 @@ typedef enum eFlyPanState {
FLY_AXISLOCK_STATE_ACTIVE = 2,
} eFlyPanState;
-/* Called in transform_ops.c, on each regeneration of key-maps. */
void fly_modal_keymap(wmKeyConfig *keyconf)
{
static const EnumPropertyItem modal_items[] = {
diff --git a/source/blender/editors/space_view3d/view3d_navigate_walk.c b/source/blender/editors/space_view3d/view3d_navigate_walk.c
index 83b8c04acb6..ed76b10c95a 100644
--- a/source/blender/editors/space_view3d/view3d_navigate_walk.c
+++ b/source/blender/editors/space_view3d/view3d_navigate_walk.c
@@ -142,7 +142,6 @@ typedef enum eWalkLockState {
WALK_AXISLOCK_STATE_DONE = 3,
} eWalkLockState;
-/* Called in transform_ops.c, on each regeneration of key-maps. */
void walk_modal_keymap(wmKeyConfig *keyconf)
{
static const EnumPropertyItem modal_items[] = {
diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c
index 88efc530484..8c2e0df0275 100644
--- a/source/blender/editors/space_view3d/view3d_project.c
+++ b/source/blender/editors/space_view3d/view3d_project.c
@@ -43,9 +43,6 @@
/* Non Clipping Projection Functions
* ********************************* */
-/**
- * \note use #ED_view3d_ob_project_mat_get to get the projection matrix
- */
void ED_view3d_project_float_v2_m4(const ARegion *region,
const float co[3],
float r_co[2],
@@ -68,9 +65,6 @@ void ED_view3d_project_float_v2_m4(const ARegion *region,
}
}
-/**
- * \note use #ED_view3d_ob_project_mat_get to get projecting mat
- */
void ED_view3d_project_float_v3_m4(const ARegion *region,
const float co[3],
float r_co[3],
@@ -231,7 +225,6 @@ eV3DProjStatus ED_view3d_project_float_ex(const ARegion *region,
return ret;
}
-/* --- short --- */
eV3DProjStatus ED_view3d_project_short_global(const ARegion *region,
const float co[3],
short r_co[2],
@@ -240,7 +233,6 @@ eV3DProjStatus ED_view3d_project_short_global(const ARegion *region,
RegionView3D *rv3d = region->regiondata;
return ED_view3d_project_short_ex(region, rv3d->persmat, false, co, r_co, flag);
}
-/* object space, use ED_view3d_init_mats_rv3d before calling */
eV3DProjStatus ED_view3d_project_short_object(const ARegion *region,
const float co[3],
short r_co[2],
@@ -251,7 +243,6 @@ eV3DProjStatus ED_view3d_project_short_object(const ARegion *region,
return ED_view3d_project_short_ex(region, rv3d->persmatob, true, co, r_co, flag);
}
-/* --- int --- */
eV3DProjStatus ED_view3d_project_int_global(const ARegion *region,
const float co[3],
int r_co[2],
@@ -260,7 +251,6 @@ eV3DProjStatus ED_view3d_project_int_global(const ARegion *region,
RegionView3D *rv3d = region->regiondata;
return ED_view3d_project_int_ex(region, rv3d->persmat, false, co, r_co, flag);
}
-/* object space, use ED_view3d_init_mats_rv3d before calling */
eV3DProjStatus ED_view3d_project_int_object(const ARegion *region,
const float co[3],
int r_co[2],
@@ -271,7 +261,6 @@ eV3DProjStatus ED_view3d_project_int_object(const ARegion *region,
return ED_view3d_project_int_ex(region, rv3d->persmatob, true, co, r_co, flag);
}
-/* --- float --- */
eV3DProjStatus ED_view3d_project_float_global(const ARegion *region,
const float co[3],
float r_co[2],
@@ -280,7 +269,6 @@ eV3DProjStatus ED_view3d_project_float_global(const ARegion *region,
RegionView3D *rv3d = region->regiondata;
return ED_view3d_project_float_ex(region, rv3d->persmat, false, co, r_co, flag);
}
-/* object space, use ED_view3d_init_mats_rv3d before calling */
eV3DProjStatus ED_view3d_project_float_object(const ARegion *region,
const float co[3],
float r_co[2],
@@ -304,9 +292,6 @@ float ED_view3d_pixel_size_no_ui_scale(const RegionView3D *rv3d, const float co[
return mul_project_m4_v3_zfac(rv3d->persmat, co) * rv3d->pixsize;
}
-/**
- * Calculate a depth value from \a co, use with #ED_view3d_win_to_delta
- */
float ED_view3d_calc_zfac(const RegionView3D *rv3d, const float co[3], bool *r_flip)
{
float zfac = mul_project_m4_v3_zfac(rv3d->persmat, co);
@@ -330,9 +315,6 @@ float ED_view3d_calc_zfac(const RegionView3D *rv3d, const float co[3], bool *r_f
return zfac;
}
-/**
- * Calculate a depth value from `co` (result should only be used for comparison).
- */
float ED_view3d_calc_depth_for_comparison(const RegionView3D *rv3d, const float co[3])
{
if (rv3d->is_persp) {
@@ -388,22 +370,6 @@ bool ED_view3d_clip_segment(const RegionView3D *rv3d, float ray_start[3], float
return true;
}
-/**
- * Calculate a 3d viewpoint and direction vector from 2d window coordinates.
- * This ray_start is located at the viewpoint, ray_normal is the direction towards mval.
- * ray_start is clipped by the view near limit so points in front of it are always in view.
- * In orthographic view the resulting ray_normal will match the view vector.
- * This version also returns the ray_co point of the ray on window plane, useful to fix precision
- * issues esp. with ortho view, where default ray_start is set rather far away.
- * \param region: The region (used for the window width and height).
- * \param v3d: The 3d viewport (used for near clipping value).
- * \param mval: The area relative 2d location (such as event->mval, converted into float[2]).
- * \param r_ray_co: The world-space point where the ray intersects the window plane.
- * \param r_ray_normal: The normalized world-space direction of towards mval.
- * \param r_ray_start: The world-space starting point of the ray.
- * \param do_clip_planes: Optionally clip the start of the ray by the view clipping planes.
- * \return success, false if the ray is totally clipped.
- */
bool ED_view3d_win_to_ray_clipped_ex(struct Depsgraph *depsgraph,
const ARegion *region,
const View3D *v3d,
@@ -426,19 +392,6 @@ bool ED_view3d_win_to_ray_clipped_ex(struct Depsgraph *depsgraph,
return true;
}
-/**
- * Calculate a 3d viewpoint and direction vector from 2d window coordinates.
- * This ray_start is located at the viewpoint, ray_normal is the direction towards mval.
- * ray_start is clipped by the view near limit so points in front of it are always in view.
- * In orthographic view the resulting ray_normal will match the view vector.
- * \param region: The region (used for the window width and height).
- * \param v3d: The 3d viewport (used for near clipping value).
- * \param mval: The area relative 2d location (such as event->mval, converted into float[2]).
- * \param r_ray_start: The world-space point where the ray intersects the window plane.
- * \param r_ray_normal: The normalized world-space direction of towards mval.
- * \param do_clip_planes: Optionally clip the start of the ray by the view clipping planes.
- * \return success, false if the ray is totally clipped.
- */
bool ED_view3d_win_to_ray_clipped(struct Depsgraph *depsgraph,
const ARegion *region,
const View3D *v3d,
@@ -451,17 +404,6 @@ bool ED_view3d_win_to_ray_clipped(struct Depsgraph *depsgraph,
depsgraph, region, v3d, mval, NULL, r_ray_normal, r_ray_start, do_clip_planes);
}
-/**
- * Calculate a 3d viewpoint and direction vector from 2d window coordinates.
- * This ray_start is located at the viewpoint, ray_normal is the direction towards mval.
- * \param region: The region (used for the window width and height).
- * \param mval: The area relative 2d location (such as event->mval, converted into float[2]).
- * \param r_ray_start: The world-space point where the ray intersects the window plane.
- * \param r_ray_normal: The normalized world-space direction of towards mval.
- *
- * \note Ignores view near/far clipping,
- * to take this into account use #ED_view3d_win_to_ray_clipped.
- */
void ED_view3d_win_to_ray(const ARegion *region,
const float mval[2],
float r_ray_start[3],
@@ -471,13 +413,6 @@ void ED_view3d_win_to_ray(const ARegion *region,
ED_view3d_win_to_vector(region, mval, r_ray_normal);
}
-/**
- * Calculate a normalized 3d direction vector from the viewpoint towards a global location.
- * In orthographic view the resulting vector will match the view vector.
- * \param rv3d: The region (used for the window width and height).
- * \param coord: The world-space location.
- * \param vec: The resulting normalized vector.
- */
void ED_view3d_global_to_vector(const RegionView3D *rv3d, const float coord[3], float vec[3])
{
if (rv3d->is_persp) {
@@ -536,13 +471,6 @@ bool view3d_get_view_aligned_coordinate(ARegion *region,
}
#endif
-/**
- * Calculate a 3d location from 2d window coordinates.
- * \param region: The region (used for the window width and height).
- * \param depth_pt: The reference location used to calculate the Z depth.
- * \param mval: The area relative location (such as event->mval converted to floats).
- * \param r_out: The resulting world-space location.
- */
void ED_view3d_win_to_3d(const View3D *v3d,
const ARegion *region,
const float depth_pt[3],
@@ -636,13 +564,6 @@ bool ED_view3d_win_to_3d_on_plane_int(const ARegion *region,
return ED_view3d_win_to_3d_on_plane(region, plane, mval_fl, do_clip, r_out);
}
-/**
- * A wrapper for #ED_view3d_win_to_3d_on_plane that projects onto \a plane_fallback
- * then maps this back to \a plane.
- *
- * This is intended to be used when \a plane is orthogonal to the views Z axis where
- * projecting the \a mval doesn't work well (or fail completely when exactly aligned).
- */
bool ED_view3d_win_to_3d_on_plane_with_fallback(const ARegion *region,
const float plane[4],
const float mval[2],
@@ -678,14 +599,6 @@ bool ED_view3d_win_to_3d_on_plane_with_fallback(const ARegion *region,
return true;
}
-/**
- * Calculate a 3d difference vector from 2d window offset.
- * note that #ED_view3d_calc_zfac() must be called first to determine
- * the depth used to calculate the delta.
- * \param region: The region (used for the window width and height).
- * \param mval: The area relative 2d difference (such as event->mval[0] - other_x).
- * \param out: The resulting world-space delta.
- */
void ED_view3d_win_to_delta(const ARegion *region,
const float mval[2],
float out[3],
@@ -702,16 +615,6 @@ void ED_view3d_win_to_delta(const ARegion *region,
out[2] = (rv3d->persinv[0][2] * dx + rv3d->persinv[1][2] * dy);
}
-/**
- * Calculate a 3d origin from 2d window coordinates.
- * \note Orthographic views have a less obvious origin,
- * Since far clip can be a very large value resulting in numeric precision issues,
- * the origin in this case is close to zero coordinate.
- *
- * \param region: The region (used for the window width and height).
- * \param mval: The area relative 2d location (such as event->mval converted to floats).
- * \param out: The resulting normalized world-space direction vector.
- */
void ED_view3d_win_to_origin(const ARegion *region, const float mval[2], float out[3])
{
RegionView3D *rv3d = region->regiondata;
@@ -733,19 +636,6 @@ void ED_view3d_win_to_origin(const ARegion *region, const float mval[2], float o
}
}
-/**
- * Calculate a 3d direction vector from 2d window coordinates.
- * This direction vector starts and the view in the direction of the 2d window coordinates.
- * In orthographic view all window coordinates yield the same vector.
- *
- * \note doesn't rely on ED_view3d_calc_zfac
- * for perspective view, get the vector direction to
- * the mouse cursor as a normalized vector.
- *
- * \param region: The region (used for the window width and height).
- * \param mval: The area relative 2d location (such as event->mval converted to floats).
- * \param out: The resulting normalized world-space direction vector.
- */
void ED_view3d_win_to_vector(const ARegion *region, const float mval[2], float out[3])
{
RegionView3D *rv3d = region->regiondata;
@@ -763,20 +653,6 @@ void ED_view3d_win_to_vector(const ARegion *region, const float mval[2], float o
normalize_v3(out);
}
-/**
- * Calculate a 3d segment from 2d window coordinates.
- * This ray_start is located at the viewpoint, ray_end is a far point.
- * ray_start and ray_end are clipped by the view near and far limits
- * so points along this line are always in view.
- * In orthographic view all resulting segments will be parallel.
- * \param region: The region (used for the window width and height).
- * \param v3d: The 3d viewport (used for near and far clipping range).
- * \param mval: The area relative 2d location (such as event->mval, converted into float[2]).
- * \param r_ray_start: The world-space starting point of the segment.
- * \param r_ray_end: The world-space end point of the segment.
- * \param do_clip_planes: Optionally clip the ray by the view clipping planes.
- * \return success, false if the segment is totally clipped.
- */
bool ED_view3d_win_to_segment_clipped(struct Depsgraph *depsgraph,
const ARegion *region,
View3D *v3d,
@@ -817,9 +693,6 @@ void ED_view3d_ob_project_mat_get_from_obmat(const RegionView3D *rv3d,
mul_m4_m4m4(r_pmat, rv3d->winmat, vmat);
}
-/**
- * Convert between region relative coordinates (x,y) and depth component z and
- * a point in world space. */
void ED_view3d_project_v3(const struct ARegion *region, const float world[3], float r_region_co[3])
{
/* Viewport is set up to make coordinates relative to the region, not window. */
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index 18820039c7f..cc8aac21a6e 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -119,9 +119,10 @@ float ED_view3d_select_dist_px(void)
return 75.0f * U.pixelsize;
}
-/* TODO: should return whether there is valid context to continue */
void ED_view3d_viewcontext_init(bContext *C, ViewContext *vc, Depsgraph *depsgraph)
{
+ /* TODO: should return whether there is valid context to continue. */
+
memset(vc, 0, sizeof(ViewContext));
vc->C = C;
vc->region = CTX_wm_region(C);
@@ -1279,40 +1280,6 @@ static bool do_lasso_select_paintface(ViewContext *vc,
return changed;
}
-#if 0
-static void do_lasso_select_node(int mcoords[][2], const int mcoords_len, const eSelectOp sel_op)
-{
- SpaceNode *snode = area->spacedata.first;
-
- bNode *node;
- rcti rect;
- int node_cent[2];
- float node_centf[2];
- bool changed = false;
-
- BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
-
- /* store selection in temp test flag */
- for (node = snode->edittree->nodes.first; node; node = node->next) {
- node_centf[0] = BLI_RCT_CENTER_X(&node->totr);
- node_centf[1] = BLI_RCT_CENTER_Y(&node->totr);
-
- 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(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);
- changed = true;
- }
- }
- if (changed) {
- BIF_undo_push("Lasso select nodes");
- }
-}
-#endif
-
static bool view3d_lasso_select(bContext *C,
ViewContext *vc,
const int mcoords[][2],
@@ -2229,7 +2196,6 @@ static Base *ed_view3d_give_base_under_cursor_ex(bContext *C,
return basact;
}
-/* mval comes from event->mval, only use within region handlers */
Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2])
{
return ed_view3d_give_base_under_cursor_ex(C, mval, NULL);
diff --git a/source/blender/editors/space_view3d/view3d_snap.c b/source/blender/editors/space_view3d/view3d_snap.c
index 583a9ad75c2..53bd181f544 100644
--- a/source/blender/editors/space_view3d/view3d_snap.c
+++ b/source/blender/editors/space_view3d/view3d_snap.c
@@ -1013,10 +1013,6 @@ void VIEW3D_OT_snap_cursor_to_center(wmOperatorType *ot)
/** \name Min/Max Object Vertices Utility
* \{ */
-/**
- * Calculates the bounding box corners (min and max) for \a obedit.
- * The returned values are in global space.
- */
bool ED_view3d_minmax_verts(Object *obedit, float r_min[3], float r_max[3])
{
TransVertStore tvs = {NULL};
diff --git a/source/blender/editors/space_view3d/view3d_utils.c b/source/blender/editors/space_view3d/view3d_utils.c
index d6a1cd930fc..8b75ce63cde 100644
--- a/source/blender/editors/space_view3d/view3d_utils.c
+++ b/source/blender/editors/space_view3d/view3d_utils.c
@@ -122,9 +122,6 @@ void ED_view3d_dist_range_get(const View3D *v3d, float r_dist_range[2])
r_dist_range[1] = v3d->clip_end * 10.0f;
}
-/**
- * \note copies logic of #ED_view3d_viewplane_get(), keep in sync.
- */
bool ED_view3d_clip_range_get(Depsgraph *depsgraph,
const View3D *v3d,
const RegionView3D *rv3d,
@@ -191,10 +188,6 @@ bool ED_view3d_viewplane_get(Depsgraph *depsgraph,
/** \name View State/Context Utilities
* \{ */
-/**
- * Use this call when executing an operator,
- * event system doesn't set for each event the OpenGL drawing context.
- */
void view3d_operator_needs_opengl(const bContext *C)
{
wmWindow *win = CTX_wm_window(C);
@@ -218,9 +211,6 @@ void view3d_region_operator_needs_opengl(wmWindow *UNUSED(win), ARegion *region)
}
}
-/**
- * Use instead of: `GPU_polygon_offset(rv3d->dist, ...)` see bug T37727.
- */
void ED_view3d_polygon_offset(const RegionView3D *rv3d, const float dist)
{
if (rv3d->rflag & RV3D_ZOFFSET_DISABLED) {
@@ -339,18 +329,6 @@ static void points_in_planes_minmax_fn(
minmax_v3v3_v3(user_data->min, user_data->max, co);
}
-/**
- * Clamp min/max by the viewport clipping.
- *
- * \note This is an approximation, with the limitation that the bounding box from the (mix, max)
- * calculation might not have any geometry inside the clipped region.
- * Performing a clipping test on each vertex would work well enough for most cases,
- * although it's not perfect either as edges/faces may intersect the clipping without having any
- * of their vertices inside it.
- * A more accurate result would be quite involved.
- *
- * \return True when the arguments were clamped.
- */
bool ED_view3d_clipping_clamp_minmax(const RegionView3D *rv3d, float min[3], float max[3])
{
/* 6 planes for the cube, 4..6 for the current view clipping planes. */
@@ -481,9 +459,6 @@ bool ED_view3d_offset_lock_check(const View3D *v3d, const RegionView3D *rv3d)
return (rv3d->persp != RV3D_CAMOB) && (v3d->ob_center_cursor || v3d->ob_center);
}
-/**
- * Use to store the last view, before entering camera view.
- */
void ED_view3d_lastview_store(RegionView3D *rv3d)
{
copy_qt_qt(rv3d->lviewquat, rv3d->viewquat);
@@ -503,13 +478,6 @@ void ED_view3d_lock_clear(View3D *v3d)
v3d->flag2 &= ~V3D_LOCK_CAMERA;
}
-/**
- * For viewport operators that exit camera perspective.
- *
- * \note This differs from simply setting `rv3d->persp = persp` because it
- * sets the `ofs` and `dist` values of the viewport so it matches the camera,
- * otherwise switching out of camera view may jump to a different part of the scene.
- */
void ED_view3d_persp_switch_from_camera(const Depsgraph *depsgraph,
View3D *v3d,
RegionView3D *rv3d,
@@ -528,12 +496,6 @@ void ED_view3d_persp_switch_from_camera(const Depsgraph *depsgraph,
rv3d->persp = persp;
}
}
-/**
- * Action to take when rotating the view,
- * handle auto-perspective and logic for switching out of views.
- *
- * shared with NDOF.
- */
bool ED_view3d_persp_ensure(const Depsgraph *depsgraph, View3D *v3d, ARegion *region)
{
RegionView3D *rv3d = region->regiondata;
@@ -569,19 +531,12 @@ bool ED_view3d_persp_ensure(const Depsgraph *depsgraph, View3D *v3d, ARegion *re
* Lock the camera to the 3D Viewport, allowing view manipulation to transform the camera.
* \{ */
-/**
- * \return true when the 3D Viewport is locked to its camera.
- */
bool ED_view3d_camera_lock_check(const View3D *v3d, const RegionView3D *rv3d)
{
return ((v3d->camera) && (!ID_IS_LINKED(v3d->camera)) && (v3d->flag2 & V3D_LOCK_CAMERA) &&
(rv3d->persp == RV3D_CAMOB));
}
-/**
- * Apply the camera object transformation to the 3D Viewport.
- * (needed so we can use regular 3D Viewport manipulation operators, that sync back to the camera).
- */
void ED_view3d_camera_lock_init_ex(const Depsgraph *depsgraph,
View3D *v3d,
RegionView3D *rv3d,
@@ -603,11 +558,6 @@ void ED_view3d_camera_lock_init(const Depsgraph *depsgraph, View3D *v3d, RegionV
ED_view3d_camera_lock_init_ex(depsgraph, v3d, rv3d, true);
}
-/**
- * Apply the 3D Viewport transformation back to the camera object.
- *
- * \return true if the camera is moved.
- */
bool ED_view3d_camera_lock_sync(const Depsgraph *depsgraph, View3D *v3d, RegionView3D *rv3d)
{
if (ED_view3d_camera_lock_check(v3d, rv3d)) {
@@ -701,12 +651,6 @@ bool ED_view3d_camera_autokey(const Scene *scene,
return false;
}
-/**
- * Call after modifying a locked view.
- *
- * \note Not every view edit currently auto-keys (num-pad for eg),
- * this is complicated because of smooth-view.
- */
bool ED_view3d_camera_lock_autokey(View3D *v3d,
RegionView3D *rv3d,
struct bContext *C,
@@ -885,7 +829,6 @@ static void view3d_boxview_sync_axis(RegionView3D *rv3d_dst, RegionView3D *rv3d_
}
}
-/* sync center/zoom view of region to others, for view transforms */
void view3d_boxview_sync(ScrArea *area, ARegion *region)
{
RegionView3D *rv3d = region->regiondata;
@@ -910,7 +853,6 @@ void view3d_boxview_sync(ScrArea *area, ARegion *region)
}
}
-/* for home, center etc */
void view3d_boxview_copy(ScrArea *area, ARegion *region)
{
RegionView3D *rv3d = region->regiondata;
@@ -935,7 +877,6 @@ void view3d_boxview_copy(ScrArea *area, ARegion *region)
}
}
-/* 'clip' is used to know if our clip setting has changed */
void ED_view3d_quadview_update(ScrArea *area, ARegion *region, bool do_clip)
{
ARegion *region_sync = NULL;
@@ -1023,14 +964,6 @@ static float view_autodist_depth_margin(ARegion *region, const int mval[2], int
return depth_close;
}
-/**
- * Get the world-space 3d location from a screen-space 2d point.
- * TODO: Implement #alphaoverride. We don't want to zoom into billboards.
- *
- * \param mval: Input screen-space pixel location.
- * \param mouse_worldloc: Output world-space location.
- * \param fallback_depth_pt: Use this points depth when no depth can be found.
- */
bool ED_view3d_autodist(Depsgraph *depsgraph,
ARegion *region,
View3D *v3d,
@@ -1069,7 +1002,6 @@ bool ED_view3d_autodist(Depsgraph *depsgraph,
return false;
}
-/* no 4x4 sampling, run #ED_view3d_depth_override first */
bool ED_view3d_autodist_simple(ARegion *region,
const int mval[2],
float mouse_worldloc[3],
@@ -1127,7 +1059,7 @@ bool ED_view3d_depth_read_cached_seg(
data.vd = vd;
data.margin = margin;
- data.depth = FLT_MAX;
+ data.depth = 1.0f;
copy_v2_v2_int(p1, mval_sta);
copy_v2_v2_int(p2, mval_end);
@@ -1136,7 +1068,7 @@ bool ED_view3d_depth_read_cached_seg(
*depth = data.depth;
- return (*depth != FLT_MAX);
+ return (*depth != 1.0f);
}
/** \} */
@@ -1157,31 +1089,6 @@ float ED_view3d_radius_to_dist_ortho(const float lens, const float radius)
return radius / (DEFAULT_SENSOR_WIDTH / lens);
}
-/**
- * Return a new RegionView3D.dist value to fit the \a radius.
- *
- * \note Depth isn't taken into account, this will fit a flat plane exactly,
- * but points towards the view (with a perspective projection),
- * may be within the radius but outside the view. eg:
- *
- * <pre>
- * +
- * pt --> + /^ radius
- * / |
- * / |
- * view + +
- * \ |
- * \ |
- * \|
- * +
- * </pre>
- *
- * \param region: Can be NULL if \a use_aspect is false.
- * \param persp: Allow the caller to tell what kind of perspective to use (ortho/view/camera)
- * \param use_aspect: Increase the distance to account for non 1:1 view aspect.
- * \param radius: The radius will be fitted exactly,
- * typically pre-scaled by a margin (#VIEW3D_MARGIN).
- */
float ED_view3d_radius_to_dist(const View3D *v3d,
const ARegion *region,
const struct Depsgraph *depsgraph,
@@ -1262,18 +1169,6 @@ float ED_view3d_radius_to_dist(const View3D *v3d,
/** \name View Distance Utilities
* \{ */
-/**
- * This function solves the problem of having to switch between camera and non-camera views.
- *
- * When viewing from the perspective of \a mat, and having the view center \a ofs,
- * this calculates a distance from \a ofs to the matrix \a mat.
- * Using \a fallback_dist when the distance would be too small.
- *
- * \param mat: A matrix use for the view-point (typically the camera objects matrix).
- * \param ofs: Orbit center (negated), matching #RegionView3D.ofs, which is typically passed in.
- * \param fallback_dist: The distance to use if the object is too near or in front of \a ofs.
- * \returns A newly calculated distance or the fallback.
- */
float ED_view3d_offset_distance(const float mat[4][4],
const float ofs[3],
const float fallback_dist)
@@ -1295,11 +1190,6 @@ float ED_view3d_offset_distance(const float mat[4][4],
return dist;
}
-/**
- * Set the dist without moving the view (compensate with #RegionView3D.ofs)
- *
- * \note take care that viewinv is up to date, #ED_view3d_update_viewmat first.
- */
void ED_view3d_distance_set(RegionView3D *rv3d, const float dist)
{
float viewinv[4];
@@ -1320,13 +1210,6 @@ void ED_view3d_distance_set(RegionView3D *rv3d, const float dist)
rv3d->dist = dist;
}
-/**
- * Change the distance & offset to match the depth of \a dist_co along the view axis.
- *
- * \param dist_co: A world-space location to use for the new depth.
- * \param dist_min: Resulting distances below this will be ignored.
- * \return Success if the distance was set.
- */
bool ED_view3d_distance_set_from_location(RegionView3D *rv3d,
const float dist_co[3],
const float dist_min)
@@ -1485,14 +1368,6 @@ bool ED_view3d_lock(RegionView3D *rv3d)
/** \name View Transform Utilities
* \{ */
-/**
- * Set the view transformation from a 4x4 matrix.
- *
- * \param mat: The view 4x4 transformation matrix to assign.
- * \param ofs: The view offset, normally from RegionView3D.ofs.
- * \param quat: The view rotation, quaternion normally from RegionView3D.viewquat.
- * \param dist: The view distance from ofs, normally from RegionView3D.dist.
- */
void ED_view3d_from_m4(const float mat[4][4], float ofs[3], float quat[4], const float *dist)
{
float nmat[3][3];
@@ -1519,14 +1394,6 @@ void ED_view3d_from_m4(const float mat[4][4], float ofs[3], float quat[4], const
}
}
-/**
- * Calculate the view transformation matrix from RegionView3D input.
- * The resulting matrix is equivalent to RegionView3D.viewinv
- * \param mat: The view 4x4 transformation matrix to calculate.
- * \param ofs: The view offset, normally from RegionView3D.ofs.
- * \param quat: The view rotation, quaternion normally from RegionView3D.viewquat.
- * \param dist: The view distance from ofs, normally from RegionView3D.dist.
- */
void ED_view3d_to_m4(float mat[4][4], const float ofs[3], const float quat[4], const float dist)
{
const float iviewquat[4] = {-quat[0], quat[1], quat[2], quat[3]};
@@ -1537,14 +1404,6 @@ void ED_view3d_to_m4(float mat[4][4], const float ofs[3], const float quat[4], c
sub_v3_v3v3(mat[3], dvec, ofs);
}
-/**
- * Set the RegionView3D members from an objects transformation and optionally lens.
- * \param ob: The object to set the view to.
- * \param ofs: The view offset to be set, normally from RegionView3D.ofs.
- * \param quat: The view rotation to be set, quaternion normally from RegionView3D.viewquat.
- * \param dist: The view distance from ofs to be set, normally from RegionView3D.dist.
- * \param lens: The view lens angle set for cameras and lights, normally from View3D.lens.
- */
void ED_view3d_from_object(const Object *ob, float ofs[3], float quat[4], float *dist, float *lens)
{
ED_view3d_from_m4(ob->obmat, ofs, quat, dist);
@@ -1558,15 +1417,6 @@ void ED_view3d_from_object(const Object *ob, float ofs[3], float quat[4], float
}
}
-/**
- * Set the object transformation from RegionView3D members.
- * \param depsgraph: The depsgraph to get the evaluated object parent
- * for the transformation calculation.
- * \param ob: The object which has the transformation assigned.
- * \param ofs: The view offset, normally from RegionView3D.ofs.
- * \param quat: The view rotation, quaternion normally from RegionView3D.viewquat.
- * \param dist: The view distance from ofs, normally from RegionView3D.dist.
- */
void ED_view3d_to_object(const Depsgraph *depsgraph,
Object *ob,
const float ofs[3],
@@ -1647,6 +1497,9 @@ bool ED_view3d_depth_read_cached(const ViewDepths *vd,
int margin,
float *r_depth)
{
+ BLI_assert(1.0 <= vd->depth_range[1]);
+ *r_depth = 1.0f;
+
if (!vd || !vd->depths) {
return false;
}
@@ -1676,15 +1529,11 @@ bool ED_view3d_depth_read_cached(const ViewDepths *vd,
depth = vd->depths[y * vd->w + x];
}
- BLI_assert(1.0 <= vd->depth_range[1]);
if (depth != 1.0f) {
*r_depth = depth;
return true;
}
- /* Grease-pencil and annotations also need the returned depth value to be high
- * so the caller can detect it's invalid. */
- *r_depth = FLT_MAX;
return false;
}
diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c
index 6f0ce6c9326..165f931394d 100644
--- a/source/blender/editors/space_view3d/view3d_view.c
+++ b/source/blender/editors/space_view3d/view3d_view.c
@@ -123,7 +123,6 @@ static void view3d_smooth_view_state_restore(const struct SmoothView3DState *sms
}
/* will start timer if appropriate */
-/* the arguments are the desired situation */
void ED_view3d_smooth_view_ex(
/* avoid passing in the context */
const Depsgraph *depsgraph,
@@ -407,10 +406,6 @@ static int view3d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), const w
return OPERATOR_FINISHED;
}
-/**
- * Apply the smooth-view immediately, use when we need to start a new view operation.
- * (so we don't end up half-applying a view operation when pressing keys quickly).
- */
void ED_view3d_smooth_view_force_finish(bContext *C, View3D *v3d, ARegion *region)
{
RegionView3D *rv3d = region->regiondata;
@@ -696,21 +691,18 @@ void VIEW3D_OT_object_as_camera(wmOperatorType *ot)
/** \name Window and View Matrix Calculation
* \{ */
-/**
- * \param rect: optional for picking (can be NULL).
- */
void view3d_winmatrix_set(Depsgraph *depsgraph,
ARegion *region,
const View3D *v3d,
const rcti *rect)
{
RegionView3D *rv3d = region->regiondata;
- rctf viewplane;
+ rctf full_viewplane;
float clipsta, clipend;
bool is_ortho;
is_ortho = ED_view3d_viewplane_get(
- depsgraph, v3d, rv3d, region->winx, region->winy, &viewplane, &clipsta, &clipend, NULL);
+ depsgraph, v3d, rv3d, region->winx, region->winy, &full_viewplane, &clipsta, &clipend, NULL);
rv3d->is_persp = !is_ortho;
#if 0
@@ -718,21 +710,29 @@ void view3d_winmatrix_set(Depsgraph *depsgraph,
__func__,
winx,
winy,
- viewplane.xmin,
- viewplane.ymin,
- viewplane.xmax,
- viewplane.ymax,
+ full_viewplane.xmin,
+ full_viewplane.ymin,
+ full_viewplane.xmax,
+ full_viewplane.ymax,
clipsta,
clipend);
#endif
- if (rect) { /* picking */
- rctf r;
- r.xmin = viewplane.xmin + (BLI_rctf_size_x(&viewplane) * (rect->xmin / (float)region->winx));
- r.ymin = viewplane.ymin + (BLI_rctf_size_y(&viewplane) * (rect->ymin / (float)region->winy));
- r.xmax = viewplane.xmin + (BLI_rctf_size_x(&viewplane) * (rect->xmax / (float)region->winx));
- r.ymax = viewplane.ymin + (BLI_rctf_size_y(&viewplane) * (rect->ymax / (float)region->winy));
- viewplane = r;
+ /* Note the code here was tweaked to avoid an apparent compiler bug in clang 13 (see T91680). */
+ rctf viewplane;
+ if (rect) {
+ /* Smaller viewplane subset for selection picking. */
+ viewplane.xmin = full_viewplane.xmin +
+ (BLI_rctf_size_x(&full_viewplane) * (rect->xmin / (float)region->winx));
+ viewplane.ymin = full_viewplane.ymin +
+ (BLI_rctf_size_y(&full_viewplane) * (rect->ymin / (float)region->winy));
+ viewplane.xmax = full_viewplane.xmin +
+ (BLI_rctf_size_x(&full_viewplane) * (rect->xmax / (float)region->winx));
+ viewplane.ymax = full_viewplane.ymin +
+ (BLI_rctf_size_y(&full_viewplane) * (rect->ymax / (float)region->winy));
+ }
+ else {
+ viewplane = full_viewplane;
}
if (is_ortho) {
@@ -761,18 +761,6 @@ static void obmat_to_viewmat(RegionView3D *rv3d, Object *ob)
mat4_normalized_to_quat(rv3d->viewquat, rv3d->viewmat);
}
-/**
- * Sets #RegionView3D.viewmat
- *
- * \param depsgraph: Depsgraph.
- * \param scene: Scene for camera and cursor location.
- * \param v3d: View 3D space data.
- * \param rv3d: 3D region which stores the final matrices.
- * \param rect_scale: Optional 2D scale argument,
- * Use when displaying a sub-region, eg: when #view3d_winmatrix_set takes a 'rect' argument.
- *
- * \note don't set windows active in here, is used by renderwin too.
- */
void view3d_viewmatrix_set(Depsgraph *depsgraph,
const Scene *scene,
const View3D *v3d,
@@ -862,11 +850,6 @@ void view3d_viewmatrix_set(Depsgraph *depsgraph,
/** \name OpenGL Select Utilities
* \{ */
-/**
- * Optionally cache data for multiple calls to #view3d_opengl_select
- *
- * just avoid GPU_select headers outside this file
- */
void view3d_opengl_select_cache_begin(void)
{
GPU_select_cache_begin();
@@ -943,13 +926,6 @@ static bool drw_select_filter_object_mode_lock_for_weight_paint(Object *ob, void
return ob_pose_list && (BLI_linklist_index(ob_pose_list, DEG_get_original_object(ob)) != -1);
}
-/**
- * \warning be sure to account for a negative return value
- * This is an error, "Too many objects in select buffer"
- * and no action should be taken (can crash blender) if this happens
- *
- * \note (vc->obedit == NULL) can be set to explicitly skip edit-object selection.
- */
int view3d_opengl_select_ex(ViewContext *vc,
uint *buffer,
uint bufsize,
@@ -1621,11 +1597,6 @@ static void view3d_local_collections_reset(Main *bmain, const uint local_view_bi
}
}
-/**
- * See if current uuid is valid, otherwise set a valid uuid to v3d,
- * Try to keep the same uuid previously used to allow users to
- * quickly toggle back and forth.
- */
bool ED_view3d_local_collections_set(Main *bmain, struct View3D *v3d)
{
if ((v3d->flag & V3D_LOCAL_COLLECTIONS) == 0) {
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index ae4c3f02c46..386fd85213e 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -668,7 +668,6 @@ static bool transform_modal_item_poll(const wmOperator *op, int value)
return true;
}
-/* Called in transform_ops.c, on each regeneration of key-maps. */
wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf)
{
static const EnumPropertyItem modal_items[] = {
@@ -1449,9 +1448,6 @@ static void drawTransformPixel(const struct bContext *C, ARegion *region, void *
}
}
-/**
- * \see #initTransform which reads values from the operator.
- */
void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
{
ToolSettings *ts = CTX_data_tool_settings(C);
@@ -1670,11 +1666,6 @@ static void initSnapSpatial(TransInfo *t, float r_snap[2])
}
}
-/**
- * \note caller needs to free 't' on a 0 return
- * \warning \a event might be NULL (when tweaking from redo panel)
- * \see #saveTransform which writes these values back.
- */
bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *event, int mode)
{
int options = 0;
@@ -1987,7 +1978,6 @@ int transformEnd(bContext *C, TransInfo *t)
return exit_code;
}
-/* TODO: move to: `transform_query.c`. */
bool checkUseAxisMatrix(TransInfo *t)
{
/* currently only checks for editmode */
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index d78cd13f8b8..3035d11d0e3 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -298,6 +298,10 @@ enum {
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Transform Types
+ * \{ */
+
typedef struct TransSnapPoint {
struct TransSnapPoint *next, *prev;
float co[3];
@@ -608,7 +612,7 @@ typedef struct TransInfo {
* mouse button then.) */
bool is_launch_event_tweak;
- bool is_orient_set;
+ bool is_orient_default_overwrite;
struct {
short type;
@@ -687,11 +691,19 @@ typedef struct TransInfo {
/** \name Public Transform API
* \{ */
+/**
+ * \note caller needs to free `t` on a 0 return
+ * \warning \a event might be NULL (when tweaking from redo panel)
+ * \see #saveTransform which writes these values back.
+ */
bool initTransform(struct bContext *C,
struct TransInfo *t,
struct wmOperator *op,
const struct wmEvent *event,
int mode);
+/**
+ * \see #initTransform which reads values from the operator.
+ */
void saveTransform(struct bContext *C, struct TransInfo *t, struct wmOperator *op);
int transformEvent(TransInfo *t, const struct wmEvent *event);
void transformApply(struct bContext *C, TransInfo *t);
@@ -708,6 +720,9 @@ void projectFloatView(TransInfo *t, const float vec[3], float adr[2]);
void applyAspectRatio(TransInfo *t, float vec[2]);
void removeAspectRatio(TransInfo *t, float vec[2]);
+/**
+ * Called in transform_ops.c, on each regeneration of key-maps.
+ */
struct wmKeyMap *transform_modal_keymap(struct wmKeyConfig *keyconf);
/** \} */
@@ -772,12 +787,28 @@ void setInputPostFct(MouseInput *mi, void (*post)(struct TransInfo *t, float val
/** \name Generics
* \{ */
+/**
+ * Setup internal data, mouse, vectors
+ *
+ * \note \a op and \a event can be NULL
+ *
+ * \see #saveTransform does the reverse.
+ */
void initTransInfo(struct bContext *C,
TransInfo *t,
struct wmOperator *op,
const struct wmEvent *event);
+/**
+ * Needed for mode switching.
+ */
void freeTransCustomDataForMode(TransInfo *t);
+/**
+ * Here I would suggest only #TransInfo related issues, like free data & reset vars. Not redraws.
+ */
void postTrans(struct bContext *C, TransInfo *t);
+/**
+ * Free data before switching to another mode.
+ */
void resetTransModal(TransInfo *t);
void resetTransRestrictions(TransInfo *t);
@@ -800,17 +831,25 @@ void calculateCenterMedian(TransInfo *t, float r_center[3]);
void calculateCenterCursor(TransInfo *t, float r_center[3]);
void calculateCenterCursor2D(TransInfo *t, float r_center[2]);
void calculateCenterCursorGraph2D(TransInfo *t, float r_center[2]);
+/**
+ * \param select_only: only get active center from data being transformed.
+ */
bool calculateCenterActive(TransInfo *t, bool select_only, float r_center[3]);
void calculatePropRatio(TransInfo *t);
+/**
+ * Rotate an element, low level code, ignore protected channels.
+ * (use for objects or pose-bones)
+ * Similar to #ElementRotation.
+ */
void transform_data_ext_rotate(TransData *td, float mat[3][3], bool use_drot);
struct Object *transform_object_deform_pose_armature_get(const TransInfo *t, struct Object *ob);
void freeCustomNormalArray(TransInfo *t, TransDataContainer *tc, TransCustomData *custom_data);
-/* TODO: `transform_query.c`. */
+/* TODO: move to: `transform_query.c`. */
bool checkUseAxisMatrix(TransInfo *t);
#define TRANSFORM_SNAP_MAX_PX 100.0f
diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c
index a24491119c6..ede4c3e458c 100644
--- a/source/blender/editors/transform/transform_constraints.c
+++ b/source/blender/editors/transform/transform_constraints.c
@@ -295,10 +295,6 @@ static void constraint_snap_plane_to_edge(const TransInfo *t, const float plane[
}
}
-/**
- * Snap to the nearest point between the snap point and the line that
- * intersects the face plane with the constraint plane.
- */
static void UNUSED_FUNCTION(constraint_snap_plane_to_face(const TransInfo *t,
const float plane[4],
float r_out[3]))
@@ -314,9 +310,6 @@ static void UNUSED_FUNCTION(constraint_snap_plane_to_face(const TransInfo *t,
}
}
-/**
- * Snap to the nearest point on the axis to the edge/line element.
- */
void transform_constraint_snap_axis_to_edge(const TransInfo *t,
const float axis[3],
float r_out[3])
@@ -331,9 +324,6 @@ void transform_constraint_snap_axis_to_edge(const TransInfo *t,
}
}
-/**
- * Snap to the intersection of the axis and the plane defined by the face.
- */
void transform_constraint_snap_axis_to_face(const TransInfo *t,
const float axis[3],
float r_out[3])
@@ -700,7 +690,6 @@ void setConstraint(TransInfo *t, int mode, const char text[])
t->redraw = TREDRAW_HARD;
}
-/* applies individual td->axismtx constraints */
void setAxisMatrixConstraint(TransInfo *t, int mode, const char text[])
{
BLI_strncpy(t->con.text + 1, text, sizeof(t->con.text) - 1);
@@ -728,12 +717,6 @@ void setLocalConstraint(TransInfo *t, int mode, const char text[])
}
}
-/**
- * Set the constraint according to the user defined orientation
- *
- * `ftext` is a format string passed to #BLI_snprintf. It will add the name of
- * the orientation where %s is (logically).
- */
void setUserConstraint(TransInfo *t, int mode, const char ftext[])
{
char text[256];
@@ -842,7 +825,6 @@ void drawConstraint(TransInfo *t)
}
}
-/* called from drawview.c, as an extra per-window draw option */
void drawPropCircle(const struct bContext *C, TransInfo *t)
{
if (t->flag & T_PROP_EDIT) {
@@ -1200,13 +1182,6 @@ bool isLockConstraint(const TransInfo *t)
return false;
}
-/**
- * Returns the dimension of the constraint space.
- *
- * For that reason, the flags always needs to be set to properly evaluate here,
- * even if they aren't actually used in the callback function.
- * (Which could happen for weird constraints not yet designed. Along a path for example.)
- */
int getConstraintSpaceDimension(const TransInfo *t)
{
int n = 0;
diff --git a/source/blender/editors/transform/transform_constraints.h b/source/blender/editors/transform/transform_constraints.h
index 3632b352476..12151f9df07 100644
--- a/source/blender/editors/transform/transform_constraints.h
+++ b/source/blender/editors/transform/transform_constraints.h
@@ -26,17 +26,35 @@
struct TransInfo;
void constraintNumInput(TransInfo *t, float vec[3]);
+/**
+ * Snap to the nearest point on the axis to the edge/line element.
+ */
void transform_constraint_snap_axis_to_edge(const TransInfo *t,
const float axis[3],
float r_out[3]);
+/**
+ * Snap to the intersection of the axis and the plane defined by the face.
+ */
void transform_constraint_snap_axis_to_face(const TransInfo *t,
const float axis[3],
float r_out[3]);
void setConstraint(TransInfo *t, int mode, const char text[]);
+/**
+ * Applies individual `td->axismtx` constraints.
+ */
void setAxisMatrixConstraint(TransInfo *t, int mode, const char text[]);
void setLocalConstraint(TransInfo *t, int mode, const char text[]);
+/**
+ * Set the constraint according to the user defined orientation
+ *
+ * `ftext` is a format string passed to #BLI_snprintf. It will add the name of
+ * the orientation where %s is (logically).
+ */
void setUserConstraint(TransInfo *t, int mode, const char text[]);
void drawConstraint(TransInfo *t);
+/**
+ * Called from drawview.c, as an extra per-window draw option.
+ */
void drawPropCircle(const struct bContext *C, TransInfo *t);
void startConstraint(TransInfo *t);
void stopConstraint(TransInfo *t);
@@ -47,4 +65,11 @@ void setNearestAxis(TransInfo *t);
int constraintModeToIndex(const TransInfo *t);
char constraintModeToChar(const TransInfo *t);
bool isLockConstraint(const TransInfo *t);
+/**
+ * Returns the dimension of the constraint space.
+ *
+ * For that reason, the flags always needs to be set to properly evaluate here,
+ * even if they aren't actually used in the callback function.
+ * (Which could happen for weird constraints not yet designed. Along a path for example.)
+ */
int getConstraintSpaceDimension(const TransInfo *t);
diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c
index ff20f569a71..8f3d13176a3 100644
--- a/source/blender/editors/transform/transform_convert.c
+++ b/source/blender/editors/transform/transform_convert.c
@@ -68,10 +68,6 @@ bool transform_mode_use_local_origins(const TransInfo *t)
return ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL);
}
-/**
- * Transforming around ourselves is no use, fallback to individual origins,
- * useful for curve/armatures.
- */
void transform_around_single_fallback_ex(TransInfo *t, int data_len_all)
{
if (data_len_all != 1) {
@@ -369,7 +365,6 @@ static bool pchan_autoik_adjust(bPoseChannel *pchan, short chainlen)
return changed;
}
-/* change the chain-length of auto-ik */
void transform_autoik_update(TransInfo *t, short mode)
{
Main *bmain = CTX_data_main(t->context);
@@ -482,7 +477,6 @@ void calc_distanceCurveVerts(TransData *head, TransData *tail, bool cyclic)
BLI_LINKSTACK_FREE(queue);
}
-/* Utility function for getting the handle data from bezier's */
TransDataCurveHandleFlags *initTransDataCurveHandles(TransData *td, struct BezTriple *bezt)
{
TransDataCurveHandleFlags *hdata;
@@ -611,9 +605,6 @@ void clipUVData(TransInfo *t)
/** \name Animation Editors (General)
* \{ */
-/**
- * Used for `TFM_TIME_EXTEND`.
- */
char transform_convert_frame_side_dir_get(TransInfo *t, float cframe)
{
char r_dir;
@@ -636,7 +627,6 @@ char transform_convert_frame_side_dir_get(TransInfo *t, float cframe)
return r_dir;
}
-/* This function tests if a point is on the "mouse" side of the cursor/frame-marking */
bool FrameOnMouseSide(char side, float frame, float cframe)
{
/* both sides, so it doesn't matter */
@@ -667,14 +657,6 @@ typedef struct tRetainedKeyframe {
size_t del_count; /* number of keyframes of this sort that have been deleted so far */
} tRetainedKeyframe;
-/**
- * Called during special_aftertrans_update to make sure selected keyframes replace
- * any other keyframes which may reside on that frame (that is not selected).
- *
- * \param sel_flag: The flag (bezt.f1/2/3) value to use to determine selection. Usually `SELECT`,
- * but may want to use a different one at times (if caller does not operate on
- * selection).
- */
void posttrans_fcurve_clean(FCurve *fcu, const int sel_flag, const bool use_handle)
{
/* NOTE: We assume that all keys are sorted */
@@ -798,12 +780,6 @@ void posttrans_fcurve_clean(FCurve *fcu, const int sel_flag, const bool use_hand
/** \name Transform Utilities
* \{ */
-/* Little helper function for ObjectToTransData used to give certain
- * constraints (ChildOf, FollowPath, and others that may be added)
- * inverse corrections for transform, so that they aren't in CrazySpace.
- * These particular constraints benefit from this, but others don't, hence
- * this semi-hack ;-) - Aligorith
- */
bool constraints_list_needinv(TransInfo *t, ListBase *list)
{
bConstraint *con;
@@ -894,14 +870,12 @@ bool constraints_list_needinv(TransInfo *t, ListBase *list)
/** \name Transform (After-Transform Update)
* \{ */
-/* inserting keys, pointcache, redraw events... */
-/**
- * \note Sequencer freeing has its own function now because of a conflict
- * with transform's order of freeing (campbell).
- * Order changed, the sequencer stuff should go back in here
- */
void special_aftertrans_update(bContext *C, TransInfo *t)
{
+ /* NOTE: Sequencer freeing has its own function now because of a conflict
+ * with transform's order of freeing (campbell).
+ * Order changed, the sequencer stuff should go back in here. */
+
/* early out when nothing happened */
if (t->data_len_all == 0 || t->mode == TFM_DUMMY) {
return;
@@ -1609,7 +1583,6 @@ void transform_convert_clip_mirror_modifier_apply(TransDataContainer *tc)
}
}
-/* for the realtime animation recording feature, handle overlapping data */
void animrecord_check_state(TransInfo *t, struct Object *ob)
{
Scene *scene = t->scene;
@@ -1708,7 +1681,6 @@ void transform_convert_flush_handle2D(TransData *td, TransData2D *td2d, const fl
}
}
-/* called for updating while transform acts, once per redraw */
void recalcData(TransInfo *t)
{
switch (t->data_type) {
diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h
index e4f2ab05bec..5ed8182857d 100644
--- a/source/blender/editors/transform/transform_convert.h
+++ b/source/blender/editors/transform/transform_convert.h
@@ -36,47 +36,101 @@ struct TransInfo;
struct bContext;
/* transform_convert.c */
+
+/**
+ * Change the chain-length of auto-IK.
+ */
void transform_autoik_update(TransInfo *t, short mode);
int special_transform_moving(TransInfo *t);
+/**
+ * Inserting keys, point-cache, redraw events.
+ */
void special_aftertrans_update(struct bContext *C, TransInfo *t);
void sort_trans_data_dist(TransInfo *t);
void createTransData(struct bContext *C, TransInfo *t);
bool clipUVTransform(TransInfo *t, float vec[2], const bool resize);
void clipUVData(TransInfo *t);
void transform_convert_flush_handle2D(TransData *td, TransData2D *td2d, const float y_fac);
+/**
+ * Called for updating while transform acts, once per redraw.
+ */
void recalcData(TransInfo *t);
/* transform_convert_mesh.c */
+
void transform_convert_mesh_customdatacorrect_init(TransInfo *t);
/* transform_convert_sequencer.c */
+
void transform_convert_sequencer_channel_clamp(TransInfo *t, float r_val[2]);
/********************* intern **********************/
/* transform_convert.c */
+
bool transform_mode_use_local_origins(const TransInfo *t);
+/**
+ * Transforming around ourselves is no use, fallback to individual origins,
+ * useful for curve/armatures.
+ */
void transform_around_single_fallback_ex(TransInfo *t, int data_len_all);
void transform_around_single_fallback(TransInfo *t);
+/**
+ * Called during special_aftertrans_update to make sure selected keyframes replace
+ * any other keyframes which may reside on that frame (that is not selected).
+ *
+ * \param sel_flag: The flag (bezt.f1/2/3) value to use to determine selection. Usually `SELECT`,
+ * but may want to use a different one at times (if caller does not operate on
+ * selection).
+ */
void posttrans_fcurve_clean(struct FCurve *fcu, const int sel_flag, const bool use_handle);
+/**
+ * Little helper function for ObjectToTransData used to give certain
+ * constraints (ChildOf, FollowPath, and others that may be added)
+ * inverse corrections for transform, so that they aren't in CrazySpace.
+ * These particular constraints benefit from this, but others don't, hence
+ * this semi-hack ;-) - Aligorith
+ */
bool constraints_list_needinv(TransInfo *t, ListBase *list);
void calc_distanceCurveVerts(TransData *head, TransData *tail, bool cyclic);
+/**
+ * Utility function for getting the handle data from bezier's.
+ */
struct TransDataCurveHandleFlags *initTransDataCurveHandles(TransData *td, struct BezTriple *bezt);
+/**
+ * Used for `TFM_TIME_EXTEND`.
+ */
char transform_convert_frame_side_dir_get(TransInfo *t, float cframe);
+/**
+ * This function tests if a point is on the "mouse" side of the cursor/frame-marking.
+ */
bool FrameOnMouseSide(char side, float frame, float cframe);
void transform_convert_clip_mirror_modifier_apply(TransDataContainer *tc);
+/**
+ * For the realtime animation recording feature, handle overlapping data.
+ */
void animrecord_check_state(TransInfo *t, struct Object *ob);
/* transform_convert_action.c */
+
void createTransActionData(bContext *C, TransInfo *t);
+/* helper for recalcData() - for Action Editor transforms */
void recalcData_actedit(TransInfo *t);
void special_aftertrans_update__actedit(bContext *C, TransInfo *t);
/* transform_convert_armature.c */
+
+/**
+ * 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]);
+/**
+ * When objects array is NULL, use 't->data_container' as is.
+ */
void createTransPose(TransInfo *t);
void createTransArmatureVerts(TransInfo *t);
void recalcData_edit_armature(TransInfo *t);
@@ -84,6 +138,7 @@ void recalcData_pose(TransInfo *t);
void special_aftertrans_update__pose(bContext *C, TransInfo *t);
/* transform_convert_cursor.c */
+
void createTransCursor_image(TransInfo *t);
void createTransCursor_sequencer(TransInfo *t);
void createTransCursor_view3d(TransInfo *t);
@@ -92,16 +147,28 @@ void recalcData_cursor_sequencer(TransInfo *t);
void recalcData_cursor_view3d(TransInfo *t);
/* transform_convert_curve.c */
+
void createTransCurveVerts(TransInfo *t);
void recalcData_curve(TransInfo *t);
/* transform_convert_graph.c */
+/**
+ * It is important to note that this doesn't always act on the selection (like it's usually done),
+ * it acts on a subset of it. E.g. the selection code may leave a hint that we just dragged on a
+ * left or right handle (SIPO_RUNTIME_FLAG_TWEAK_HANDLES_LEFT/RIGHT) and then we only transform the
+ * selected left or right handles accordingly.
+ * The points to be transformed are tagged with BEZT_FLAG_TEMP_TAG; some lower level curve
+ * functions may need to be made aware of this. It's ugly that these act based on selection state
+ * anyway.
+ */
void createTransGraphEditData(bContext *C, TransInfo *t);
+/* helper for recalcData() - for Graph Editor transforms */
void recalcData_graphedit(TransInfo *t);
void special_aftertrans_update__graph(bContext *C, TransInfo *t);
/* transform_convert_gpencil.c */
void createTransGPencil(bContext *C, TransInfo *t);
+/* force recalculation of triangles during transformation */
void recalcData_gpencil_strokes(TransInfo *t);
/* transform_convert_lattice.c */
@@ -146,6 +213,11 @@ void transform_convert_mesh_islands_calc(struct BMEditMesh *em,
const bool calc_island_axismtx,
struct TransIslandData *r_island_data);
void transform_convert_mesh_islanddata_free(struct TransIslandData *island_data);
+/**
+ * \param mtx: Measure distance in this space.
+ * \param dists: Store the closest connected distance to selected vertices.
+ * \param index: Optionally store the original index we're measuring the distance to (can be NULL).
+ */
void transform_convert_mesh_connectivity_distance(struct BMesh *bm,
const float mtx[3][3],
float *dists,
@@ -156,6 +228,10 @@ void transform_convert_mesh_mirrordata_calc(struct BMEditMesh *em,
const bool mirror_axis[3],
struct TransMirrorData *r_mirror_data);
void transform_convert_mesh_mirrordata_free(struct TransMirrorData *mirror_data);
+/**
+ * Detect CrazySpace [tm].
+ * Vertices with space affected by quats are marked with #BM_ELEM_TAG.
+ */
void transform_convert_mesh_crazyspace_detect(TransInfo *t,
struct TransDataContainer *tc,
struct BMEditMesh *em,
@@ -181,10 +257,12 @@ void recalcData_mesh_skin(TransInfo *t);
/* transform_convert_mesh_uv.c */
void createTransUVs(bContext *C, TransInfo *t);
+/* helper for recalcData() - for Image Editor transforms */
void recalcData_uv(TransInfo *t);
/* transform_convert_nla.c */
void createTransNlaData(bContext *C, TransInfo *t);
+/* helper for recalcData() - for NLA Editor transforms */
void recalcData_nla(TransInfo *t);
void special_aftertrans_update__nla(bContext *C, TransInfo *t);
@@ -195,11 +273,13 @@ void special_aftertrans_update__node(bContext *C, TransInfo *t);
/* transform_convert_object.c */
void createTransObject(bContext *C, TransInfo *t);
+/* helper for recalcData() - for object transforms, typically in the 3D view */
void recalcData_objects(TransInfo *t);
void special_aftertrans_update__object(bContext *C, TransInfo *t);
/* transform_convert_object_texspace.c */
void createTransTexspace(TransInfo *t);
+/* helper for recalcData() - for object transforms, typically in the 3D view */
void recalcData_texspace(TransInfo *t);
/* transform_convert_paintcurve.c */
@@ -217,6 +297,7 @@ void special_aftertrans_update__sculpt(bContext *C, TransInfo *t);
/* transform_convert_sequencer.c */
void createTransSeqData(TransInfo *t);
+/* helper for recalcData() - for sequencer transforms */
void recalcData_sequencer(TransInfo *t);
void special_aftertrans_update__sequencer(bContext *C, TransInfo *t);
@@ -226,5 +307,6 @@ void recalcData_sequencer_image(TransInfo *t);
/* transform_convert_tracking.c */
void createTransTrackingData(bContext *C, TransInfo *t);
+/* helper for recalcData() - for Movie Clip transforms */
void recalcData_tracking(TransInfo *t);
void special_aftertrans_update__movieclip(bContext *C, TransInfo *t);
diff --git a/source/blender/editors/transform/transform_convert_action.c b/source/blender/editors/transform/transform_convert_action.c
index 24d84bc2de8..69b4de48c56 100644
--- a/source/blender/editors/transform/transform_convert_action.c
+++ b/source/blender/editors/transform/transform_convert_action.c
@@ -580,7 +580,6 @@ static void flushTransIntFrameActionData(TransInfo *t)
}
}
-/* helper for recalcData() - for Action Editor transforms */
void recalcData_actedit(TransInfo *t)
{
ViewLayer *view_layer = t->view_layer;
diff --git a/source/blender/editors/transform/transform_convert_armature.c b/source/blender/editors/transform/transform_convert_armature.c
index 88790e9645c..63aada0f797 100644
--- a/source/blender/editors/transform/transform_convert_armature.c
+++ b/source/blender/editors/transform/transform_convert_armature.c
@@ -716,9 +716,6 @@ static void add_pose_transdata(TransInfo *t, bPoseChannel *pchan, Object *ob, Tr
td->con = pchan->constraints.first;
}
-/**
- * When objects array is NULL, use 't->data_container' as is.
- */
void createTransPose(TransInfo *t)
{
Main *bmain = CTX_data_main(t->context);
@@ -1502,10 +1499,6 @@ 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 transform_convert_pose_transflags_update(Object *ob,
const int mode,
const short around,
diff --git a/source/blender/editors/transform/transform_convert_gpencil.c b/source/blender/editors/transform/transform_convert_gpencil.c
index f7b78b10868..e52dcb17806 100644
--- a/source/blender/editors/transform/transform_convert_gpencil.c
+++ b/source/blender/editors/transform/transform_convert_gpencil.c
@@ -496,8 +496,8 @@ static void createTransGPencil_strokes(bContext *C,
if (BKE_gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
const int cfra = (gpl->flag & GP_LAYER_FRAMELOCK) ? gpl->actframe->framenum : cfra_scene;
bGPDframe *gpf = gpl->actframe;
- float diff_mat[4][4];
- float inverse_diff_mat[4][4];
+ float diff_mat[3][3];
+ float inverse_diff_mat[3][3];
bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
/* Init multiframe falloff options. */
@@ -509,9 +509,14 @@ static void createTransGPencil_strokes(bContext *C,
}
/* Calculate difference matrix. */
- BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat);
- /* Undo matrix. */
- invert_m4_m4(inverse_diff_mat, diff_mat);
+ {
+ float diff_mat_tmp[4][4];
+ BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat_tmp);
+ copy_m3_m4(diff_mat, diff_mat_tmp);
+ }
+
+ /* Use safe invert for cases where the input matrix has zero axes. */
+ invert_m3_m3_safe_ortho(inverse_diff_mat, diff_mat);
/* Make a new frame to work on if the layer's frame
* and the current scene frame don't match up.
@@ -651,9 +656,9 @@ static void createTransGPencil_strokes(bContext *C,
}
}
/* apply parent transformations */
- copy_m3_m4(td->smtx, inverse_diff_mat); /* final position */
- copy_m3_m4(td->mtx, diff_mat); /* display position */
- copy_m3_m4(td->axismtx, diff_mat); /* axis orientation */
+ copy_m3_m3(td->smtx, inverse_diff_mat); /* final position */
+ copy_m3_m3(td->mtx, diff_mat); /* display position */
+ copy_m3_m3(td->axismtx, diff_mat); /* axis orientation */
/* Triangulation must be calculated again,
* so save the stroke for recalc function */
@@ -748,7 +753,6 @@ void createTransGPencil(bContext *C, TransInfo *t)
}
}
-/* force recalculation of triangles during transformation */
void recalcData_gpencil_strokes(TransInfo *t)
{
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
diff --git a/source/blender/editors/transform/transform_convert_graph.c b/source/blender/editors/transform/transform_convert_graph.c
index d22277f9d91..40c226b8f7c 100644
--- a/source/blender/editors/transform/transform_convert_graph.c
+++ b/source/blender/editors/transform/transform_convert_graph.c
@@ -218,15 +218,6 @@ static void graph_key_shortest_dist(
}
}
-/**
- * It is important to note that this doesn't always act on the selection (like it's usually done),
- * it acts on a subset of it. E.g. the selection code may leave a hint that we just dragged on a
- * left or right handle (SIPO_RUNTIME_FLAG_TWEAK_HANDLES_LEFT/RIGHT) and then we only transform the
- * selected left or right handles accordingly.
- * The points to be transformed are tagged with BEZT_FLAG_TEMP_TAG; some lower level curve
- * functions may need to be made aware of this. It's ugly that these act based on selection state
- * anyway.
- */
void createTransGraphEditData(bContext *C, TransInfo *t)
{
SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first;
@@ -913,7 +904,6 @@ static void remake_graph_transdata(TransInfo *t, ListBase *anim_data)
}
}
-/* helper for recalcData() - for Graph Editor transforms */
void recalcData_graphedit(TransInfo *t)
{
SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first;
diff --git a/source/blender/editors/transform/transform_convert_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c
index 7377e47da3d..c3d95e1ad98 100644
--- a/source/blender/editors/transform/transform_convert_mesh.c
+++ b/source/blender/editors/transform/transform_convert_mesh.c
@@ -1000,11 +1000,6 @@ static bool bmesh_test_loose_edge(BMEdge *edge)
return true;
}
-/**
- * \param mtx: Measure distance in this space.
- * \param dists: Store the closest connected distance to selected vertices.
- * \param index: Optionally store the original index we're measuring the distance to (can be NULL).
- */
void transform_convert_mesh_connectivity_distance(struct BMesh *bm,
const float mtx[3][3],
float *dists,
@@ -1307,8 +1302,6 @@ void transform_convert_mesh_mirrordata_free(struct TransMirrorData *mirror_data)
/** \name Crazy Space
* \{ */
-/* Detect CrazySpace [tm].
- * Vertices with space affected by quats are marked with #BM_ELEM_TAG */
void transform_convert_mesh_crazyspace_detect(TransInfo *t,
struct TransDataContainer *tc,
struct BMEditMesh *em,
@@ -2099,6 +2092,7 @@ void recalcData_mesh(TransInfo *t)
tc_mesh_partial_update(t, tc, &partial_state);
}
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -2164,4 +2158,5 @@ void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t)
break;
}
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_convert_mesh_skin.c b/source/blender/editors/transform/transform_convert_mesh_skin.c
index 69b44998980..7c742f29c86 100644
--- a/source/blender/editors/transform/transform_convert_mesh_skin.c
+++ b/source/blender/editors/transform/transform_convert_mesh_skin.c
@@ -303,4 +303,5 @@ void recalcData_mesh_skin(TransInfo *t)
BKE_editmesh_looptri_and_normals_calc(em);
}
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_convert_mesh_uv.c b/source/blender/editors/transform/transform_convert_mesh_uv.c
index 61397b6ef4b..69f29389b31 100644
--- a/source/blender/editors/transform/transform_convert_mesh_uv.c
+++ b/source/blender/editors/transform/transform_convert_mesh_uv.c
@@ -464,7 +464,6 @@ static void flushTransUVs(TransInfo *t)
}
}
-/* helper for recalcData() - for Image Editor transforms */
void recalcData_uv(TransInfo *t)
{
SpaceImage *sima = t->area->spacedata.first;
diff --git a/source/blender/editors/transform/transform_convert_nla.c b/source/blender/editors/transform/transform_convert_nla.c
index acef8a666e3..d19698a4f61 100644
--- a/source/blender/editors/transform/transform_convert_nla.c
+++ b/source/blender/editors/transform/transform_convert_nla.c
@@ -266,7 +266,6 @@ void createTransNlaData(bContext *C, TransInfo *t)
ANIM_animdata_freelist(&anim_data);
}
-/* helper for recalcData() - for NLA Editor transforms */
void recalcData_nla(TransInfo *t)
{
SpaceNla *snla = (SpaceNla *)t->area->spacedata.first;
diff --git a/source/blender/editors/transform/transform_convert_object.c b/source/blender/editors/transform/transform_convert_object.c
index 4a8ebf3fc6e..52365e4e519 100644
--- a/source/blender/editors/transform/transform_convert_object.c
+++ b/source/blender/editors/transform/transform_convert_object.c
@@ -874,7 +874,6 @@ static bool motionpath_need_update_object(Scene *scene, Object *ob)
/** \name Recalc Data object
* \{ */
-/* helper for recalcData() - for object transforms, typically in the 3D view */
void recalcData_objects(TransInfo *t)
{
bool motionpath_update = false;
diff --git a/source/blender/editors/transform/transform_convert_object_texspace.c b/source/blender/editors/transform/transform_convert_object_texspace.c
index 371a5b48818..3e434da66ec 100644
--- a/source/blender/editors/transform/transform_convert_object_texspace.c
+++ b/source/blender/editors/transform/transform_convert_object_texspace.c
@@ -51,7 +51,7 @@ void createTransTexspace(TransInfo *t)
TransData *td;
Object *ob;
ID *id;
- short *texflag;
+ char *texflag;
ob = OBACT(view_layer);
@@ -102,7 +102,6 @@ void createTransTexspace(TransInfo *t)
/** \name Recalc Data object
* \{ */
-/* helper for recalcData() - for object transforms, typically in the 3D view */
void recalcData_texspace(TransInfo *t)
{
diff --git a/source/blender/editors/transform/transform_convert_sequencer.c b/source/blender/editors/transform/transform_convert_sequencer.c
index 70089164d8a..88c01321785 100644
--- a/source/blender/editors/transform/transform_convert_sequencer.c
+++ b/source/blender/editors/transform/transform_convert_sequencer.c
@@ -789,7 +789,6 @@ static void flushTransSeq(TransInfo *t)
SEQ_collection_free(transformed_strips);
}
-/* helper for recalcData() - for sequencer transforms */
void recalcData_sequencer(TransInfo *t)
{
TransData *td;
diff --git a/source/blender/editors/transform/transform_convert_sequencer_image.c b/source/blender/editors/transform/transform_convert_sequencer_image.c
index e8af1680a41..d5a59885014 100644
--- a/source/blender/editors/transform/transform_convert_sequencer_image.c
+++ b/source/blender/editors/transform/transform_convert_sequencer_image.c
@@ -118,16 +118,17 @@ static void freeSeqData(TransInfo *UNUSED(t),
void createTransSeqImageData(TransInfo *t)
{
Editing *ed = SEQ_editing_get(t->scene);
+ const SpaceSeq *sseq = t->area->spacedata.first;
+ const ARegion *region = t->region;
if (ed == NULL) {
return;
}
-
- {
- const SpaceSeq *sseq = t->area->spacedata.first;
- if (sseq->mainb != SEQ_DRAW_IMG_IMBUF) {
- return;
- }
+ if (sseq->mainb != SEQ_DRAW_IMG_IMBUF) {
+ return;
+ }
+ if (region->regiontype == RGN_TYPE_PREVIEW && sseq->view == SEQ_VIEW_SEQUENCE_PREVIEW) {
+ return;
}
ListBase *seqbase = SEQ_active_seqbase_get(ed);
diff --git a/source/blender/editors/transform/transform_convert_tracking.c b/source/blender/editors/transform/transform_convert_tracking.c
index 211dec3c4e8..dc37f2796bf 100644
--- a/source/blender/editors/transform/transform_convert_tracking.c
+++ b/source/blender/editors/transform/transform_convert_tracking.c
@@ -707,7 +707,6 @@ static void flushTransTracking(TransInfo *t)
}
}
-/* helper for recalcData() - for Movie Clip transforms */
void recalcData_tracking(TransInfo *t)
{
SpaceClip *sc = t->area->spacedata.first;
diff --git a/source/blender/editors/transform/transform_draw_cursors.c b/source/blender/editors/transform/transform_draw_cursors.c
index af1f3cb72a4..13127ae06bb 100644
--- a/source/blender/editors/transform/transform_draw_cursors.c
+++ b/source/blender/editors/transform/transform_draw_cursors.c
@@ -88,20 +88,12 @@ static void drawArrow(const uint pos_id, const enum eArrowDirection dir)
immEnd();
}
-/**
- * Poll callback for cursor drawing:
- * #WM_paint_cursor_activate
- */
bool transform_draw_cursor_poll(bContext *C)
{
ARegion *region = CTX_wm_region(C);
return (region && ELEM(region->regiontype, RGN_TYPE_WINDOW, RGN_TYPE_PREVIEW)) ? 1 : 0;
}
-/**
- * Cursor and help-line drawing, callback for:
- * #WM_paint_cursor_activate
- */
void transform_draw_cursor_draw(bContext *UNUSED(C), int x, int y, void *customdata)
{
TransInfo *t = (TransInfo *)customdata;
diff --git a/source/blender/editors/transform/transform_draw_cursors.h b/source/blender/editors/transform/transform_draw_cursors.h
index 0f626c9039b..b520cd1d4f8 100644
--- a/source/blender/editors/transform/transform_draw_cursors.h
+++ b/source/blender/editors/transform/transform_draw_cursors.h
@@ -24,5 +24,14 @@
#pragma once
/* Callbacks for #WM_paint_cursor_activate */
+
+/**
+ * Poll callback for cursor drawing:
+ * #WM_paint_cursor_activate
+ */
bool transform_draw_cursor_poll(struct bContext *C);
+/**
+ * Cursor and help-line drawing, callback for:
+ * #WM_paint_cursor_activate
+ */
void transform_draw_cursor_draw(struct bContext *C, int x, int y, void *customdata);
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index 4194fb2a0ad..43d894d60f2 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -125,9 +125,6 @@ void drawLine(TransInfo *t, const float center[3], const float dir[3], char axis
GPU_matrix_pop();
}
-/**
- * Free data before switching to another mode.
- */
void resetTransModal(TransInfo *t)
{
freeTransCustomDataForMode(t);
@@ -144,7 +141,7 @@ static void *t_view_get(TransInfo *t)
View3D *v3d = t->area->spacedata.first;
return (void *)v3d;
}
- else if (t->region) {
+ if (t->region) {
return (void *)&t->region->v2d;
}
return NULL;
@@ -158,41 +155,39 @@ static int t_around_get(TransInfo *t)
}
ScrArea *area = t->area;
- if (t->spacetype == SPACE_VIEW3D) {
- /* Bend always uses the cursor. */
- if (t->mode == TFM_BEND) {
- return V3D_AROUND_CURSOR;
- }
- else {
+ switch (t->spacetype) {
+ case SPACE_VIEW3D: {
+ if (t->mode == TFM_BEND) {
+ /* Bend always uses the cursor. */
+ return V3D_AROUND_CURSOR;
+ }
return t->settings->transform_pivot_point;
}
- }
- else if (t->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = area->spacedata.first;
- return sima->around;
- }
- else if (t->spacetype == SPACE_GRAPH) {
- SpaceGraph *sipo = area->spacedata.first;
- return sipo->around;
- }
- else if (t->spacetype == SPACE_CLIP) {
- SpaceClip *sclip = area->spacedata.first;
- return sclip->around;
- }
- else if (t->spacetype == SPACE_SEQ && t->region->regiontype == RGN_TYPE_PREVIEW) {
- return SEQ_tool_settings_pivot_point_get(t->scene);
+ case SPACE_IMAGE: {
+ SpaceImage *sima = area->spacedata.first;
+ return sima->around;
+ }
+ case SPACE_GRAPH: {
+ SpaceGraph *sipo = area->spacedata.first;
+ return sipo->around;
+ }
+ case SPACE_CLIP: {
+ SpaceClip *sclip = area->spacedata.first;
+ return sclip->around;
+ }
+ case SPACE_SEQ: {
+ if (t->region->regiontype == RGN_TYPE_PREVIEW) {
+ return SEQ_tool_settings_pivot_point_get(t->scene);
+ }
+ break;
+ }
+ default:
+ break;
}
return V3D_AROUND_CENTER_BOUNDS;
}
-/**
- * Setup internal data, mouse, vectors
- *
- * \note \a op and \a event can be NULL
- *
- * \see #saveTransform does the reverse.
- */
void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *event)
{
Scene *sce = CTX_data_scene(C);
@@ -219,7 +214,8 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->flag = 0;
- if (obact && ELEM(object_mode, OB_MODE_EDIT, OB_MODE_EDIT_GPENCIL)) {
+ if (obact && !(t->options & (CTX_CURSOR | CTX_TEXTURE_SPACE)) &&
+ ELEM(object_mode, OB_MODE_EDIT, OB_MODE_EDIT_GPENCIL)) {
t->obedit_type = obact->type;
}
else {
@@ -398,11 +394,11 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
RNA_property_is_set(op->ptr, prop)) {
float values[4] = {0}; /* in case value isn't length 4, avoid uninitialized memory. */
if (RNA_property_array_check(prop)) {
- RNA_float_get_array(op->ptr, "value", values);
+ RNA_property_float_get_array(op->ptr, prop, values);
t_values_set_is_array = true;
}
else {
- values[0] = RNA_float_get(op->ptr, "value");
+ values[0] = RNA_property_float_get(op->ptr, prop);
}
if (t->flag & T_MODAL) {
@@ -488,25 +484,31 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
}
+ orient_type_default = orient_type_scene;
+
if (orient_type_set != -1) {
- orient_type_default = orient_type_set;
- t->is_orient_set = true;
+ if (!(t->con.mode & CON_APPLY)) {
+ /* Only overwrite default if not constrained. */
+ orient_type_default = orient_type_set;
+ t->is_orient_default_overwrite = true;
+ }
}
else if (orient_type_matrix_set != -1) {
- orient_type_default = orient_type_set = orient_type_matrix_set;
- t->is_orient_set = true;
+ orient_type_set = orient_type_matrix_set;
+ if (!(t->con.mode & CON_APPLY)) {
+ /* Only overwrite default if not constrained. */
+ orient_type_default = orient_type_set;
+ t->is_orient_default_overwrite = true;
+ }
}
else if (t->con.mode & CON_APPLY) {
- orient_type_default = orient_type_set = orient_type_scene;
+ orient_type_set = orient_type_scene;
+ }
+ else if (orient_type_scene == V3D_ORIENT_GLOBAL) {
+ orient_type_set = V3D_ORIENT_LOCAL;
}
else {
- orient_type_default = orient_type_scene;
- if (orient_type_scene == V3D_ORIENT_GLOBAL) {
- orient_type_set = V3D_ORIENT_LOCAL;
- }
- else {
- orient_type_set = V3D_ORIENT_GLOBAL;
- }
+ orient_type_set = V3D_ORIENT_GLOBAL;
}
BLI_assert(!ELEM(-1, orient_type_default, orient_type_set));
@@ -708,9 +710,6 @@ static void freeTransCustomDataContainer(TransInfo *t,
}
}
-/**
- * Needed for mode switching.
- */
void freeTransCustomDataForMode(TransInfo *t)
{
freeTransCustomData(t, NULL, &t->custom.mode);
@@ -719,7 +718,6 @@ void freeTransCustomDataForMode(TransInfo *t)
}
}
-/* Here I would suggest only TransInfo related issues, like free data & reset vars. Not redraws */
void postTrans(bContext *C, TransInfo *t)
{
if (t->draw_handle_view) {
@@ -1057,9 +1055,6 @@ void calculateCenterBound(TransInfo *t, float r_center[3])
}
}
-/**
- * \param select_only: only get active center from data being transformed.
- */
bool calculateCenterActive(TransInfo *t, bool select_only, float r_center[3])
{
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_OK(t);
@@ -1313,11 +1308,6 @@ void calculatePropRatio(TransInfo *t)
}
}
-/**
- * Rotate an element, low level code, ignore protected channels.
- * (use for objects or pose-bones)
- * Similar to #ElementRotation.
- */
void transform_data_ext_rotate(TransData *td, float mat[3][3], bool use_drot)
{
float totmat[3][3];
diff --git a/source/blender/editors/transform/transform_gizmo_2d.c b/source/blender/editors/transform/transform_gizmo_2d.c
index 7a23a4a92ce..c3a0e4b1163 100644
--- a/source/blender/editors/transform/transform_gizmo_2d.c
+++ b/source/blender/editors/transform/transform_gizmo_2d.c
@@ -286,7 +286,14 @@ static bool gizmo2d_calc_bounds(const bContext *C, float *r_center, float *r_min
* In addition to this, the rotation of the bounding box can not currently be hooked up
* properly to read the result from the transform system (when transforming multiple strips).
*/
- mid_v2_v2v2(r_center, r_min, r_max);
+ const int pivot_point = scene->toolsettings->sequencer_tool_settings->pivot_point;
+ if (pivot_point == V3D_AROUND_CURSOR) {
+ SpaceSeq *sseq = area->spacedata.first;
+ SEQ_image_preview_unit_to_px(scene, sseq->cursor, r_center);
+ }
+ else {
+ mid_v2_v2v2(r_center, r_min, r_max);
+ }
zero_v2(r_min);
zero_v2(r_max);
return has_select;
@@ -353,39 +360,59 @@ static float gizmo2d_calc_rotation(const bContext *C)
return 0.0f;
}
-static bool gizmo2d_calc_center(const bContext *C, float r_center[2])
+static bool seq_get_strip_pivot_median(const Scene *scene, float r_pivot[2])
+{
+ zero_v2(r_pivot);
+
+ ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene));
+ SeqCollection *strips = SEQ_query_rendered_strips(seqbase, scene->r.cfra, 0);
+ SEQ_filter_selected_strips(strips);
+ bool has_select = SEQ_collection_len(strips) != 0;
+
+ if (has_select) {
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, strips) {
+ float origin[2];
+ SEQ_image_transform_origin_offset_pixelspace_get(scene, seq, origin);
+ add_v2_v2(r_pivot, origin);
+ }
+ mul_v2_fl(r_pivot, 1.0f / SEQ_collection_len(strips));
+ }
+
+ SEQ_collection_free(strips);
+ return has_select;
+}
+
+static bool gizmo2d_calc_transform_pivot(const bContext *C, float r_pivot[2])
{
ScrArea *area = CTX_wm_area(C);
Scene *scene = CTX_data_scene(C);
bool has_select = false;
- zero_v2(r_center);
+
if (area->spacetype == SPACE_IMAGE) {
SpaceImage *sima = area->spacedata.first;
ViewLayer *view_layer = CTX_data_view_layer(C);
- ED_uvedit_center_from_pivot_ex(sima, scene, view_layer, r_center, sima->around, &has_select);
+ ED_uvedit_center_from_pivot_ex(sima, scene, view_layer, r_pivot, sima->around, &has_select);
}
else if (area->spacetype == SPACE_SEQ) {
SpaceSeq *sseq = area->spacedata.first;
const int pivot_point = scene->toolsettings->sequencer_tool_settings->pivot_point;
- ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene));
- SeqCollection *strips = SEQ_query_rendered_strips(seqbase, scene->r.cfra, 0);
- SEQ_filter_selected_strips(strips);
- has_select = SEQ_collection_len(strips) != 0;
if (pivot_point == V3D_AROUND_CURSOR) {
- SEQ_image_preview_unit_to_px(scene, sseq->cursor, r_center);
+ SEQ_image_preview_unit_to_px(scene, sseq->cursor, r_pivot);
+
+ ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene));
+ SeqCollection *strips = SEQ_query_rendered_strips(seqbase, scene->r.cfra, 0);
+ SEQ_filter_selected_strips(strips);
+ has_select = SEQ_collection_len(strips) != 0;
+ SEQ_collection_free(strips);
}
- else if (has_select) {
- Sequence *seq;
- SEQ_ITERATOR_FOREACH (seq, strips) {
- float origin[2];
- SEQ_image_transform_origin_offset_pixelspace_get(scene, seq, origin);
- add_v2_v2(r_center, origin);
- }
- mul_v2_fl(r_center, 1.0f / SEQ_collection_len(strips));
+ else {
+ has_select = seq_get_strip_pivot_median(scene, r_pivot);
}
-
- SEQ_collection_free(strips);
+ }
+ else {
+ BLI_assert_msg(0, "Unhandled space type!");
}
return has_select;
}
@@ -409,7 +436,7 @@ static int gizmo2d_modal(bContext *C,
ARegion *region = CTX_wm_region(C);
float origin[3];
- gizmo2d_calc_center(C, origin);
+ gizmo2d_calc_transform_pivot(C, origin);
gizmo2d_origin_to_region(region, origin);
WM_gizmo_set_matrix_location(widget, origin);
@@ -541,7 +568,7 @@ static void gizmo2d_xform_refresh(const bContext *C, wmGizmoGroup *gzgroup)
GizmoGroup2D *ggd = gzgroup->customdata;
bool has_select;
if (ggd->no_cage) {
- has_select = gizmo2d_calc_center(C, ggd->origin);
+ has_select = gizmo2d_calc_transform_pivot(C, ggd->origin);
}
else {
has_select = gizmo2d_calc_bounds(C, ggd->origin, ggd->min, ggd->max);
@@ -597,7 +624,8 @@ static void gizmo2d_xform_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
ScrArea *area = CTX_wm_area(C);
if (area->spacetype == SPACE_SEQ) {
- gizmo2d_calc_center(C, origin);
+ Scene *scene = CTX_data_scene(C);
+ seq_get_strip_pivot_median(scene, origin);
float matrix_rotate[4][4];
unit_m4(matrix_rotate);
@@ -660,7 +688,8 @@ static void gizmo2d_xform_invoke_prepare(const bContext *C,
if (ggd->rotation != 0.0f && area->spacetype == SPACE_SEQ) {
float origin[3];
- gizmo2d_calc_center(C, origin);
+ Scene *scene = CTX_data_scene(C);
+ seq_get_strip_pivot_median(scene, origin);
/* We need to rotate the cardinal points so they align with the rotated bounding box. */
rotate_around_center_v2(n, origin, ggd->rotation);
@@ -781,7 +810,7 @@ static void gizmo2d_resize_refresh(const bContext *C, wmGizmoGroup *gzgroup)
{
GizmoGroup_Resize2D *ggd = gzgroup->customdata;
float origin[3];
- const bool has_select = gizmo2d_calc_center(C, origin);
+ const bool has_select = gizmo2d_calc_transform_pivot(C, origin);
if (has_select == false) {
for (int i = 0; i < ARRAY_SIZE(ggd->gizmo_xy); i++) {
@@ -941,7 +970,7 @@ static void gizmo2d_rotate_refresh(const bContext *C, wmGizmoGroup *gzgroup)
{
GizmoGroup_Rotate2D *ggd = gzgroup->customdata;
float origin[3];
- const bool has_select = gizmo2d_calc_center(C, origin);
+ const bool has_select = gizmo2d_calc_transform_pivot(C, origin);
if (has_select == false) {
ggd->gizmo->flag |= WM_GIZMO_HIDDEN;
diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c
index 6a2353d403f..9bd55d78039 100644
--- a/source/blender/editors/transform/transform_gizmo_3d.c
+++ b/source/blender/editors/transform/transform_gizmo_3d.c
@@ -623,8 +623,6 @@ bool gimbal_axis_object(Object *ob, float gmat[3][3])
return 1;
}
-/* centroid, boundbox, of selection */
-/* returns total items selected */
int ED_transform_calc_gizmo_stats(const bContext *C,
const struct TransformCalcParams *params,
struct TransformBounds *tbounds)
@@ -2005,7 +2003,6 @@ void VIEW3D_GGT_xform_gizmo(wmGizmoGroupType *gzgt)
"");
}
-/** Only poll, flag & gzmap_params differ. */
void VIEW3D_GGT_xform_gizmo_context(wmGizmoGroupType *gzgt)
{
gzgt->name = "3D View: Transform Gizmo Context";
diff --git a/source/blender/editors/transform/transform_mode.c b/source/blender/editors/transform/transform_mode.c
index 5e0abbc1a08..d2e7f9f83df 100644
--- a/source/blender/editors/transform/transform_mode.c
+++ b/source/blender/editors/transform/transform_mode.c
@@ -78,7 +78,6 @@ bool transdata_check_local_center(const TransInfo *t, short around)
(t->options & (CTX_MOVIECLIP | CTX_MASK | CTX_PAINT_CURVE | CTX_SEQUENCER_IMAGE))));
}
-/* Informs if the mode can be switched during modal. */
bool transform_mode_is_changeable(const int mode)
{
return ELEM(mode,
@@ -520,10 +519,12 @@ void constraintSizeLim(const TransInfo *t, TransData *td)
}
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Transform (Rotation Utils)
* \{ */
-/* Used by Transform Rotation and Transform Normal Rotation */
+
void headerRotation(TransInfo *t, char *str, const int str_size, float final)
{
size_t ofs = 0;
@@ -551,12 +552,6 @@ void headerRotation(TransInfo *t, char *str, const int str_size, float final)
}
}
-/**
- * Applies values of rotation to `td->loc` and `td->ext->quat`
- * based on a rotation matrix (mat) and a pivot (center).
- *
- * Protected axis and other transform settings are taken into account.
- */
void ElementRotation_ex(const TransInfo *t,
const TransDataContainer *tc,
TransData *td,
@@ -828,11 +823,13 @@ void ElementRotation(const TransInfo *t,
ElementRotation_ex(t, tc, td, mat, center);
}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name Transform (Resize Utils)
* \{ */
+
void headerResize(TransInfo *t, const float vec[3], char *str, const int str_size)
{
char tvec[NUM_STR_REP_LEN * 3];
@@ -1232,15 +1229,12 @@ void transform_mode_init(TransInfo *t, wmOperator *op, const int mode)
* BLI_assert(t->mode == mode); */
}
-/**
- * When in modal and not set, initializes a default orientation for the mode.
- */
void transform_mode_default_modal_orientation_set(TransInfo *t, int type)
{
/* Currently only these types are supported. */
BLI_assert(ELEM(type, V3D_ORIENT_GLOBAL, V3D_ORIENT_VIEW));
- if (t->is_orient_set) {
+ if (t->is_orient_default_overwrite) {
return;
}
@@ -1276,4 +1270,5 @@ void transform_mode_default_modal_orientation_set(TransInfo *t, int type)
transform_orientations_current_set(t, O_DEFAULT);
}
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode.h b/source/blender/editors/transform/transform_mode.h
index c561d1c8a4f..ec3d5b8d0fe 100644
--- a/source/blender/editors/transform/transform_mode.h
+++ b/source/blender/editors/transform/transform_mode.h
@@ -42,12 +42,24 @@ typedef struct TransDataGenericSlideVert {
/* transform_mode.c */
int transform_mode_really_used(struct bContext *C, int mode);
bool transdata_check_local_center(const TransInfo *t, short around);
+/**
+ * Informs if the mode can be switched during modal.
+ */
bool transform_mode_is_changeable(const int mode);
void protectedTransBits(short protectflag, float vec[3]);
void protectedSizeBits(short protectflag, float size[3]);
void constraintTransLim(const TransInfo *t, TransData *td);
void constraintSizeLim(const TransInfo *t, TransData *td);
+/**
+ * Used by Transform Rotation and Transform Normal Rotation.
+ */
void headerRotation(TransInfo *t, char *str, int str_size, float final);
+/**
+ * Applies values of rotation to `td->loc` and `td->ext->quat`
+ * based on a rotation matrix (mat) and a pivot (center).
+ *
+ * Protected axis and other transform settings are taken into account.
+ */
void ElementRotation_ex(const TransInfo *t,
const TransDataContainer *tc,
TransData *td,
@@ -64,6 +76,9 @@ void ElementResize(const TransInfo *t,
TransData *td,
const float mat[3][3]);
void transform_mode_init(TransInfo *t, struct wmOperator *op, const int mode);
+/**
+ * When in modal and not set, initializes a default orientation for the mode.
+ */
void transform_mode_default_modal_orientation_set(TransInfo *t, int type);
/* transform_mode_align.c */
diff --git a/source/blender/editors/transform/transform_mode_align.c b/source/blender/editors/transform/transform_mode_align.c
index 1a1d84699f4..f27a194dda0 100644
--- a/source/blender/editors/transform/transform_mode_align.c
+++ b/source/blender/editors/transform/transform_mode_align.c
@@ -89,4 +89,5 @@ void initAlign(TransInfo *t)
initMouseInputMode(t, &t->mouse, INPUT_NONE);
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_baketime.c b/source/blender/editors/transform/transform_mode_baketime.c
index 653944b56a7..46d6e5c5983 100644
--- a/source/blender/editors/transform/transform_mode_baketime.c
+++ b/source/blender/editors/transform/transform_mode_baketime.c
@@ -132,4 +132,5 @@ void initBakeTime(TransInfo *t)
t->num.unit_sys = t->scene->unit.system;
t->num.unit_type[0] = B_UNIT_NONE; /* Don't think this uses units? */
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_bbone_resize.c b/source/blender/editors/transform/transform_mode_bbone_resize.c
index 95e2d944b9b..ce2f3c15651 100644
--- a/source/blender/editors/transform/transform_mode_bbone_resize.c
+++ b/source/blender/editors/transform/transform_mode_bbone_resize.c
@@ -123,6 +123,7 @@ static void applyBoneSize(TransInfo *t, const int UNUSED(mval[2]))
float ratio = t->values[0];
copy_v3_fl(t->values_final, ratio);
+ add_v3_v3(t->values_final, t->values_modal_offset);
transform_snap_increment(t, t->values_final);
@@ -184,4 +185,5 @@ void initBoneSize(TransInfo *t)
t->num.unit_type[1] = B_UNIT_NONE;
t->num.unit_type[2] = B_UNIT_NONE;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_bend.c b/source/blender/editors/transform/transform_mode_bend.c
index 6d84c397fa6..a1bcd3aeb50 100644
--- a/source/blender/editors/transform/transform_mode_bend.c
+++ b/source/blender/editors/transform/transform_mode_bend.c
@@ -393,4 +393,5 @@ void initBend(TransInfo *t)
t->custom.mode.data = data;
t->custom.mode.use_free = true;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_boneenvelope.c b/source/blender/editors/transform/transform_mode_boneenvelope.c
index da7393ab42e..bb7bd81f7bd 100644
--- a/source/blender/editors/transform/transform_mode_boneenvelope.c
+++ b/source/blender/editors/transform/transform_mode_boneenvelope.c
@@ -51,7 +51,7 @@ static void applyBoneEnvelope(TransInfo *t, const int UNUSED(mval[2]))
int i;
char str[UI_MAX_DRAW_STR];
- ratio = t->values[0];
+ ratio = t->values[0] + t->values_modal_offset[0];
transform_snap_increment(t, &ratio);
diff --git a/source/blender/editors/transform/transform_mode_boneroll.c b/source/blender/editors/transform/transform_mode_boneroll.c
index cd04ca2b844..00629b13ede 100644
--- a/source/blender/editors/transform/transform_mode_boneroll.c
+++ b/source/blender/editors/transform/transform_mode_boneroll.c
@@ -52,7 +52,7 @@ static void applyBoneRoll(TransInfo *t, const int UNUSED(mval[2]))
float final;
- final = t->values[0];
+ final = t->values[0] + t->values_modal_offset[0];
transform_snap_increment(t, &final);
@@ -107,4 +107,5 @@ void initBoneRoll(TransInfo *t)
t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_curveshrinkfatten.c b/source/blender/editors/transform/transform_mode_curveshrinkfatten.c
index 9433502ef55..c4c33c881ed 100644
--- a/source/blender/editors/transform/transform_mode_curveshrinkfatten.c
+++ b/source/blender/editors/transform/transform_mode_curveshrinkfatten.c
@@ -51,7 +51,7 @@ static void applyCurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
int i;
char str[UI_MAX_DRAW_STR];
- ratio = t->values[0];
+ ratio = t->values[0] + t->values_modal_offset[0];
transform_snap_increment(t, &ratio);
@@ -115,4 +115,5 @@ void initCurveShrinkFatten(TransInfo *t)
t->flag |= T_NO_CONSTRAINT;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_edge_bevelweight.c b/source/blender/editors/transform/transform_mode_edge_bevelweight.c
index 5466ba3e91f..8aa7955bc2a 100644
--- a/source/blender/editors/transform/transform_mode_edge_bevelweight.c
+++ b/source/blender/editors/transform/transform_mode_edge_bevelweight.c
@@ -96,7 +96,7 @@ static void applyBevelWeight(TransInfo *t, const int UNUSED(mval[2]))
int i;
char str[UI_MAX_DRAW_STR];
- weight = t->values[0];
+ weight = t->values[0] + t->values_modal_offset[0];
CLAMP_MAX(weight, 1.0f);
@@ -174,4 +174,5 @@ void initBevelWeight(TransInfo *t)
t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_edge_crease.c b/source/blender/editors/transform/transform_mode_edge_crease.c
index 1d3b4dbb4f0..debc2a1be3e 100644
--- a/source/blender/editors/transform/transform_mode_edge_crease.c
+++ b/source/blender/editors/transform/transform_mode_edge_crease.c
@@ -97,7 +97,7 @@ static void applyCrease(TransInfo *t, const int UNUSED(mval[2]))
int i;
char str[UI_MAX_DRAW_STR];
- crease = t->values[0];
+ crease = t->values[0] + t->values_modal_offset[0];
CLAMP_MAX(crease, 1.0f);
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 1f57bacf78f..edba9809207 100644
--- a/source/blender/editors/transform/transform_mode_edge_rotate_normal.c
+++ b/source/blender/editors/transform/transform_mode_edge_rotate_normal.c
@@ -95,7 +95,7 @@ static void applyNormalRotation(TransInfo *t, const int UNUSED(mval[2]))
float axis[3];
float mat[3][3];
- float angle = t->values[0];
+ float angle = t->values[0] + t->values_modal_offset[0];
copy_v3_v3(axis, axis_final);
transform_snap_increment(t, &angle);
@@ -152,4 +152,5 @@ void initNormalRotation(TransInfo *t)
transform_mode_default_modal_orientation_set(t, V3D_ORIENT_VIEW);
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_edge_slide.c b/source/blender/editors/transform/transform_mode_edge_slide.c
index cfcb17b8da0..7a0f2743a98 100644
--- a/source/blender/editors/transform/transform_mode_edge_slide.c
+++ b/source/blender/editors/transform/transform_mode_edge_slide.c
@@ -1458,7 +1458,7 @@ static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
const bool is_constrained = !(is_clamp == false || hasNumInput(&t->num));
- final = t->values[0];
+ final = t->values[0] + t->values_modal_offset[0];
applySnapping(t, &final);
if (!validSnap(t)) {
@@ -1567,4 +1567,5 @@ void initEdgeSlide(TransInfo *t)
{
initEdgeSlide_ex(t, true, false, false, true);
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_gpopacity.c b/source/blender/editors/transform/transform_mode_gpopacity.c
index 748769491f1..5772c6b4717 100644
--- a/source/blender/editors/transform/transform_mode_gpopacity.c
+++ b/source/blender/editors/transform/transform_mode_gpopacity.c
@@ -53,7 +53,7 @@ static void applyGPOpacity(TransInfo *t, const int UNUSED(mval[2]))
int i;
char str[UI_MAX_DRAW_STR];
- ratio = t->values[0];
+ ratio = t->values[0] + t->values_modal_offset[0];
transform_snap_increment(t, &ratio);
@@ -125,4 +125,5 @@ void initGPOpacity(TransInfo *t)
t->flag |= T_NO_CONSTRAINT;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_gpshrinkfatten.c b/source/blender/editors/transform/transform_mode_gpshrinkfatten.c
index bc081edd597..f4a0c3c659c 100644
--- a/source/blender/editors/transform/transform_mode_gpshrinkfatten.c
+++ b/source/blender/editors/transform/transform_mode_gpshrinkfatten.c
@@ -53,7 +53,7 @@ static void applyGPShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
int i;
char str[UI_MAX_DRAW_STR];
- ratio = t->values[0];
+ ratio = t->values[0] + t->values_modal_offset[0];
transform_snap_increment(t, &ratio);
@@ -127,4 +127,5 @@ void initGPShrinkFatten(TransInfo *t)
t->flag |= T_NO_CONSTRAINT;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_maskshrinkfatten.c b/source/blender/editors/transform/transform_mode_maskshrinkfatten.c
index 327a639773c..a1a8bed59b3 100644
--- a/source/blender/editors/transform/transform_mode_maskshrinkfatten.c
+++ b/source/blender/editors/transform/transform_mode_maskshrinkfatten.c
@@ -52,7 +52,7 @@ static void applyMaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
bool initial_feather = false;
char str[UI_MAX_DRAW_STR];
- ratio = t->values[0];
+ ratio = t->values[0] + t->values_modal_offset[0];
transform_snap_increment(t, &ratio);
@@ -141,4 +141,5 @@ void initMaskShrinkFatten(TransInfo *t)
t->flag |= T_NO_CONSTRAINT;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_mirror.c b/source/blender/editors/transform/transform_mode_mirror.c
index 2ae32f3545a..ee584cb9833 100644
--- a/source/blender/editors/transform/transform_mode_mirror.c
+++ b/source/blender/editors/transform/transform_mode_mirror.c
@@ -238,4 +238,5 @@ void initMirror(TransInfo *t)
t->flag |= T_NULL_ONE;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_push_pull.c b/source/blender/editors/transform/transform_mode_push_pull.c
index 0527d1bc08e..8577a0a5e11 100644
--- a/source/blender/editors/transform/transform_mode_push_pull.c
+++ b/source/blender/editors/transform/transform_mode_push_pull.c
@@ -124,7 +124,7 @@ static void applyPushPull(TransInfo *t, const int UNUSED(mval[2]))
int i;
char str[UI_MAX_DRAW_STR];
- distance = t->values[0];
+ distance = t->values[0] + t->values_modal_offset[0];
transform_snap_increment(t, &distance);
@@ -199,4 +199,5 @@ void initPushPull(TransInfo *t)
t->num.unit_sys = t->scene->unit.system;
t->num.unit_type[0] = B_UNIT_LENGTH;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_resize.c b/source/blender/editors/transform/transform_mode_resize.c
index 28323460626..3d7f0aa6d67 100644
--- a/source/blender/editors/transform/transform_mode_resize.c
+++ b/source/blender/editors/transform/transform_mode_resize.c
@@ -267,4 +267,5 @@ void initResize(TransInfo *t, float mouse_dir_constraint[3])
transform_mode_default_modal_orientation_set(t, V3D_ORIENT_GLOBAL);
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_rotate.c b/source/blender/editors/transform/transform_mode_rotate.c
index bfbdaa389f4..e8ef71a6639 100644
--- a/source/blender/editors/transform/transform_mode_rotate.c
+++ b/source/blender/editors/transform/transform_mode_rotate.c
@@ -363,4 +363,5 @@ void initRotation(TransInfo *t)
transform_mode_default_modal_orientation_set(t, V3D_ORIENT_VIEW);
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_shear.c b/source/blender/editors/transform/transform_mode_shear.c
index 018725ec6dd..9369cb2e62b 100644
--- a/source/blender/editors/transform/transform_mode_shear.c
+++ b/source/blender/editors/transform/transform_mode_shear.c
@@ -199,7 +199,7 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2]))
char str[UI_MAX_DRAW_STR];
const bool is_local_center = transdata_check_local_center(t, t->around);
- value = t->values[0];
+ value = t->values[0] + t->values_modal_offset[0];
transform_snap_increment(t, &value);
@@ -289,4 +289,5 @@ void initShear(TransInfo *t)
transform_mode_default_modal_orientation_set(t, V3D_ORIENT_VIEW);
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_shrink_fatten.c b/source/blender/editors/transform/transform_mode_shrink_fatten.c
index b18e0aa0c7f..01dd1b701a5 100644
--- a/source/blender/editors/transform/transform_mode_shrink_fatten.c
+++ b/source/blender/editors/transform/transform_mode_shrink_fatten.c
@@ -110,7 +110,7 @@ static void applyShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
size_t ofs = 0;
UnitSettings *unit = &t->scene->unit;
- distance = t->values[0];
+ distance = t->values[0] + t->values_modal_offset[0];
transform_snap_increment(t, &distance);
@@ -216,4 +216,5 @@ void initShrinkFatten(TransInfo *t)
}
}
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_skin_resize.c b/source/blender/editors/transform/transform_mode_skin_resize.c
index 236c9024201..f5e502fed4f 100644
--- a/source/blender/editors/transform/transform_mode_skin_resize.c
+++ b/source/blender/editors/transform/transform_mode_skin_resize.c
@@ -107,6 +107,7 @@ static void applySkinResize(TransInfo *t, const int UNUSED(mval[2]))
}
else {
copy_v3_fl(t->values_final, t->values[0]);
+ add_v3_v3(t->values_final, t->values_modal_offset);
transform_snap_increment(t, t->values_final);
@@ -179,4 +180,5 @@ void initSkinResize(TransInfo *t)
t->num.unit_type[1] = B_UNIT_NONE;
t->num.unit_type[2] = B_UNIT_NONE;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_tilt.c b/source/blender/editors/transform/transform_mode_tilt.c
index b48f474e16e..6451a7d77d5 100644
--- a/source/blender/editors/transform/transform_mode_tilt.c
+++ b/source/blender/editors/transform/transform_mode_tilt.c
@@ -52,7 +52,7 @@ static void applyTilt(TransInfo *t, const int UNUSED(mval[2]))
float final;
- final = t->values[0];
+ final = t->values[0] + t->values_modal_offset[0];
transform_snap_increment(t, &final);
@@ -111,4 +111,5 @@ void initTilt(TransInfo *t)
t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_timescale.c b/source/blender/editors/transform/transform_mode_timescale.c
index 0a7ae54982e..c198f235cf8 100644
--- a/source/blender/editors/transform/transform_mode_timescale.c
+++ b/source/blender/editors/transform/transform_mode_timescale.c
@@ -151,4 +151,5 @@ void initTimeScale(TransInfo *t)
t->num.unit_sys = t->scene->unit.system;
t->num.unit_type[0] = B_UNIT_NONE;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_timeslide.c b/source/blender/editors/transform/transform_mode_timeslide.c
index 5cc53eb08ce..98abab0fd6b 100644
--- a/source/blender/editors/transform/transform_mode_timeslide.c
+++ b/source/blender/editors/transform/transform_mode_timeslide.c
@@ -232,4 +232,5 @@ void initTimeSlide(TransInfo *t)
/* No time unit supporting frames currently... */
t->num.unit_type[0] = B_UNIT_NONE;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_timetranslate.c b/source/blender/editors/transform/transform_mode_timetranslate.c
index 294040946bd..5f2a2e472c5 100644
--- a/source/blender/editors/transform/transform_mode_timetranslate.c
+++ b/source/blender/editors/transform/transform_mode_timetranslate.c
@@ -157,4 +157,5 @@ void initTimeTranslate(TransInfo *t)
/* No time unit supporting frames currently... */
t->num.unit_type[0] = B_UNIT_NONE;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_tosphere.c b/source/blender/editors/transform/transform_mode_tosphere.c
index bfc85b2fe44..2062f78c326 100644
--- a/source/blender/editors/transform/transform_mode_tosphere.c
+++ b/source/blender/editors/transform/transform_mode_tosphere.c
@@ -194,7 +194,7 @@ static void applyToSphere(TransInfo *t, const int UNUSED(mval[2]))
int i;
char str[UI_MAX_DRAW_STR];
- ratio = t->values[0];
+ ratio = t->values[0] + t->values_modal_offset[0];
transform_snap_increment(t, &ratio);
@@ -277,4 +277,5 @@ void initToSphere(TransInfo *t)
to_sphere_radius_update(t);
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_trackball.c b/source/blender/editors/transform/transform_mode_trackball.c
index aa8b0783d0a..ddffc4f8438 100644
--- a/source/blender/editors/transform/transform_mode_trackball.c
+++ b/source/blender/editors/transform/transform_mode_trackball.c
@@ -218,4 +218,5 @@ void initTrackball(TransInfo *t)
t->flag |= T_NO_CONSTRAINT;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c
index 233e32c0e48..19d0c6d39a3 100644
--- a/source/blender/editors/transform/transform_mode_translate.c
+++ b/source/blender/editors/transform/transform_mode_translate.c
@@ -579,4 +579,5 @@ void initTranslation(TransInfo *t)
t->custom.mode.data = custom_data;
t->custom.mode.use_free = true;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_vert_slide.c b/source/blender/editors/transform/transform_mode_vert_slide.c
index def5f911c6f..48a8fcf60eb 100644
--- a/source/blender/editors/transform/transform_mode_vert_slide.c
+++ b/source/blender/editors/transform/transform_mode_vert_slide.c
@@ -582,7 +582,7 @@ static void applyVertSlide(TransInfo *t, const int UNUSED(mval[2]))
const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
const bool is_constrained = !(is_clamp == false || hasNumInput(&t->num));
- final = t->values[0];
+ final = t->values[0] + t->values_modal_offset[0];
applySnapping(t, &final);
if (!validSnap(t)) {
@@ -687,4 +687,5 @@ void initVertSlide(TransInfo *t)
{
initVertSlide_ex(t, false, false, true);
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c
index 61bbe722d71..fa2485c33c2 100644
--- a/source/blender/editors/transform/transform_orientations.c
+++ b/source/blender/editors/transform/transform_orientations.c
@@ -315,11 +315,6 @@ bool createSpaceNormal(float mat[3][3], const float normal[3])
return true;
}
-/**
- * \note To recreate an orientation from the matrix:
- * - (plane == mat[1])
- * - (normal == mat[2])
- */
bool createSpaceNormalTangent(float mat[3][3], const float normal[3], const float tangent[3])
{
if (normalize_v3_v3(mat[2], normal) == 0.0f) {
@@ -503,15 +498,6 @@ void ED_transform_calc_orientation_from_type(const bContext *C, float r_mat[3][3
scene, view_layer, v3d, rv3d, ob, obedit, orient_index, pivot_point, r_mat);
}
-/**
- * \note The resulting matrix may not be orthogonal,
- * callers that depend on `r_mat` to be orthogonal should use #orthogonalize_m3.
- *
- * A non orthogonal matrix may be returned when:
- * - #V3D_ORIENT_GIMBAL the result won't be orthogonal unless the object has no rotation.
- * - #V3D_ORIENT_LOCAL may contain shear from non-uniform scale in parent/child relationships.
- * - #V3D_ORIENT_CUSTOM may have been created from #V3D_ORIENT_LOCAL.
- */
short ED_transform_calc_orientation_from_type_ex(const Scene *scene,
ViewLayer *view_layer,
const View3D *v3d,
@@ -602,9 +588,6 @@ short ED_transform_calc_orientation_from_type_ex(const Scene *scene,
return orientation_index;
}
-/* Sets the matrix of the specified space orientation.
- * If the matrix cannot be obtained, an orientation different from the one
- * informed is returned */
short transform_orientation_matrix_get(bContext *C,
TransInfo *t,
short orient_index,
diff --git a/source/blender/editors/transform/transform_orientations.h b/source/blender/editors/transform/transform_orientations.h
index 1da369c8307..6e0e3d9f8c7 100644
--- a/source/blender/editors/transform/transform_orientations.h
+++ b/source/blender/editors/transform/transform_orientations.h
@@ -25,6 +25,10 @@
struct TransInfo;
+/**
+ * Sets the matrix of the specified space orientation.
+ * If the matrix cannot be obtained, an orientation different from the one informed is returned.
+ */
short transform_orientation_matrix_get(struct bContext *C,
struct TransInfo *t,
short orient_index,
@@ -33,12 +37,19 @@ short transform_orientation_matrix_get(struct bContext *C,
const char *transform_orientations_spacename_get(struct TransInfo *t, const short orient_type);
void transform_orientations_current_set(struct TransInfo *t, const short orient_index);
-/* Those two fill in mat and return non-zero on success */
+/**
+ * Those two fill in mat and return non-zero on success.
+ */
bool transform_orientations_create_from_axis(float mat[3][3],
const float x[3],
const float y[3],
const float z[3]);
bool createSpaceNormal(float mat[3][3], const float normal[3]);
+/**
+ * \note To recreate an orientation from the matrix:
+ * - (plane == mat[1])
+ * - (normal == mat[2])
+ */
bool createSpaceNormalTangent(float mat[3][3], const float normal[3], const float tangent[3]);
struct TransformOrientation *addMatrixSpace(struct bContext *C,
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index 71f26ef0594..9cdec357afd 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -499,7 +499,9 @@ void applySnapping(TransInfo *t, float *vec)
/* Time base quirky code to go around find-nearest slowness. */
/* TODO: add exception for object mode, no need to slow it down then. */
if (current - t->tsnap.last >= 0.01) {
- t->tsnap.calcSnap(t, vec);
+ if (t->tsnap.calcSnap) {
+ t->tsnap.calcSnap(t, vec);
+ }
if (t->tsnap.targetSnap) {
t->tsnap.targetSnap(t);
}
@@ -708,33 +710,39 @@ void initSnapping(TransInfo *t, wmOperator *op)
resetSnapping(t);
/* if snap property exists */
- if (op && RNA_struct_find_property(op->ptr, "snap") &&
- RNA_struct_property_is_set(op->ptr, "snap")) {
- if (RNA_boolean_get(op->ptr, "snap")) {
+ PropertyRNA *prop;
+ if (op && (prop = RNA_struct_find_property(op->ptr, "snap")) &&
+ RNA_property_is_set(op->ptr, prop)) {
+ if (RNA_property_boolean_get(op->ptr, prop)) {
t->modifiers |= MOD_SNAP;
- if (RNA_struct_property_is_set(op->ptr, "snap_target")) {
- snap_target = RNA_enum_get(op->ptr, "snap_target");
+ if ((prop = RNA_struct_find_property(op->ptr, "snap_target")) &&
+ RNA_property_is_set(op->ptr, prop)) {
+ snap_target = RNA_property_enum_get(op->ptr, prop);
}
- if (RNA_struct_property_is_set(op->ptr, "snap_point")) {
- RNA_float_get_array(op->ptr, "snap_point", t->tsnap.snapPoint);
+ if ((prop = RNA_struct_find_property(op->ptr, "snap_point")) &&
+ RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_float_get_array(op->ptr, prop, t->tsnap.snapPoint);
t->tsnap.status |= SNAP_FORCED | POINT_INIT;
}
/* snap align only defined in specific cases */
- if (RNA_struct_find_property(op->ptr, "snap_align")) {
- t->tsnap.align = RNA_boolean_get(op->ptr, "snap_align");
+ if ((prop = RNA_struct_find_property(op->ptr, "snap_align")) &&
+ RNA_property_is_set(op->ptr, prop)) {
+ t->tsnap.align = RNA_property_boolean_get(op->ptr, prop);
RNA_float_get_array(op->ptr, "snap_normal", t->tsnap.snapNormal);
normalize_v3(t->tsnap.snapNormal);
}
- if (RNA_struct_find_property(op->ptr, "use_snap_project")) {
- t->tsnap.project = RNA_boolean_get(op->ptr, "use_snap_project");
+ if ((prop = RNA_struct_find_property(op->ptr, "use_snap_project")) &&
+ RNA_property_is_set(op->ptr, prop)) {
+ t->tsnap.project = RNA_property_boolean_get(op->ptr, prop);
}
- if (RNA_struct_find_property(op->ptr, "use_snap_self")) {
- t->tsnap.snap_self = RNA_boolean_get(op->ptr, "use_snap_self");
+ if ((prop = RNA_struct_find_property(op->ptr, "use_snap_self")) &&
+ RNA_property_is_set(op->ptr, prop)) {
+ t->tsnap.snap_self = RNA_property_boolean_get(op->ptr, prop);
}
}
}
@@ -777,8 +785,15 @@ static void setSnappingCallback(TransInfo *t)
if (t->spacetype == SPACE_VIEW3D) {
t->tsnap.calcSnap = snap_calc_view3d_fn;
}
- else if (t->spacetype == SPACE_IMAGE && t->obedit_type == OB_MESH) {
- t->tsnap.calcSnap = snap_calc_uv_fn;
+ else if (t->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = t->area->spacedata.first;
+ Object *obact = t->view_layer->basact ? t->view_layer->basact->object : NULL;
+
+ const bool is_uv_editor = sima->mode == SI_MODE_UV;
+ const bool has_edit_object = obact && BKE_object_is_in_editmode(obact);
+ if (is_uv_editor && has_edit_object) {
+ t->tsnap.calcSnap = snap_calc_uv_fn;
+ }
}
else if (t->spacetype == SPACE_NODE) {
t->tsnap.calcSnap = snap_calc_node_fn;
@@ -953,7 +968,7 @@ static void snap_calc_view3d_fn(TransInfo *t, float *UNUSED(vec))
static void snap_calc_uv_fn(TransInfo *t, float *UNUSED(vec))
{
- BLI_assert(t->spacetype == SPACE_IMAGE && t->obedit_type == OB_MESH);
+ BLI_assert(t->spacetype == SPACE_IMAGE);
if (t->tsnap.mode & SCE_SNAP_MODE_VERTEX) {
float co[2];
diff --git a/source/blender/editors/transform/transform_snap.h b/source/blender/editors/transform/transform_snap.h
index ed7f93304bc..bc89c7a8cda 100644
--- a/source/blender/editors/transform/transform_snap.h
+++ b/source/blender/editors/transform/transform_snap.h
@@ -76,18 +76,30 @@ void removeSnapPoint(TransInfo *t);
float transform_snap_distance_len_squared_fn(TransInfo *t, const float p1[3], const float p2[3]);
/* transform_snap_sequencer.c */
+
struct TransSeqSnapData *transform_snap_sequencer_data_alloc(const TransInfo *t);
void transform_snap_sequencer_data_free(struct TransSeqSnapData *data);
bool transform_snap_sequencer_calc(struct TransInfo *t);
void transform_snap_sequencer_apply_translate(TransInfo *t, float *vec);
/* transform_snap_animation.c */
+
+/**
+ * This function returns the snapping 'mode' for Animation Editors only.
+ * We cannot use the standard snapping due to NLA-strip scaling complexities.
+ *
+ * TODO: these modifier checks should be accessible from the key-map.
+ */
short getAnimEdit_SnapMode(TransInfo *t);
void snapFrameTransform(TransInfo *t,
const eAnimEdit_AutoSnap autosnap,
const float val_initial,
const float val_final,
float *r_val_final);
+/**
+ * This function is used by Animation Editor specific transform functions to do
+ * the Snap Keyframe to Nearest Frame/Marker
+ */
void transform_snap_anim_flush_data(TransInfo *t,
TransData *td,
const eAnimEdit_AutoSnap autosnap,
diff --git a/source/blender/editors/transform/transform_snap_animation.c b/source/blender/editors/transform/transform_snap_animation.c
index 8828f96247d..6ca16c171e2 100644
--- a/source/blender/editors/transform/transform_snap_animation.c
+++ b/source/blender/editors/transform/transform_snap_animation.c
@@ -38,12 +38,6 @@
/** \name Snapping in Anim Editors
* \{ */
-/**
- * This function returns the snapping 'mode' for Animation Editors only.
- * We cannot use the standard snapping due to NLA-strip scaling complexities.
- *
- * TODO: these modifier checks should be accessible from the key-map.
- */
short getAnimEdit_SnapMode(TransInfo *t)
{
short autosnap = SACTSNAP_OFF;
@@ -128,9 +122,6 @@ void snapFrameTransform(TransInfo *t,
}
}
-/* This function is used by Animation Editor specific transform functions to do
- * the Snap Keyframe to Nearest Frame/Marker
- */
void transform_snap_anim_flush_data(TransInfo *t,
TransData *td,
const eAnimEdit_AutoSnap autosnap,
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index 4b981e763f1..350d3a2676c 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -125,8 +125,6 @@ struct SnapObjectContext {
const ARegion *region;
const View3D *v3d;
- const struct SnapObjectParams *params;
-
float mval[2];
float pmat[4][4]; /* perspective matrix */
float win_size[2]; /* win x and y */
@@ -444,6 +442,7 @@ static SnapObjectData *snap_object_data_editmesh_get(SnapObjectContext *sctx,
* \{ */
typedef void (*IterSnapObjsCallback)(SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
Object *ob_eval,
float obmat[4][4],
bool is_object_active,
@@ -453,16 +452,17 @@ typedef void (*IterSnapObjsCallback)(SnapObjectContext *sctx,
* Walks through all objects in the scene to create the list of objects to snap.
*/
static void iter_snap_objects(SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
IterSnapObjsCallback sob_callback,
void *data)
{
ViewLayer *view_layer = DEG_get_input_view_layer(sctx->runtime.depsgraph);
- const eSnapSelect snap_select = sctx->runtime.params->snap_select;
+ const eSnapSelect snap_select = params->snap_select;
Base *base_act = view_layer->basact;
if (snap_select == SNAP_ONLY_ACTIVE) {
Object *obj_eval = DEG_get_evaluated_object(sctx->runtime.depsgraph, base_act->object);
- sob_callback(sctx, obj_eval, obj_eval->obmat, true, data);
+ sob_callback(sctx, params, obj_eval, obj_eval->obmat, true, data);
return;
}
@@ -500,12 +500,12 @@ static void iter_snap_objects(SnapObjectContext *sctx,
ListBase *lb = object_duplilist(sctx->runtime.depsgraph, sctx->scene, obj_eval);
for (DupliObject *dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) {
BLI_assert(DEG_is_evaluated_object(dupli_ob->ob));
- sob_callback(sctx, dupli_ob->ob, dupli_ob->mat, is_object_active, data);
+ sob_callback(sctx, params, dupli_ob->ob, dupli_ob->mat, is_object_active, data);
}
free_object_duplilist(lb);
}
- sob_callback(sctx, obj_eval, obj_eval->obmat, is_object_active, data);
+ sob_callback(sctx, params, obj_eval, obj_eval->obmat, is_object_active, data);
}
}
@@ -665,6 +665,7 @@ static void editmesh_looptri_raycast_backface_culling_cb(void *userdata,
}
static bool raycastMesh(SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
const float ray_start[3],
const float ray_dir[3],
Object *ob_eval,
@@ -773,7 +774,7 @@ static bool raycastMesh(SnapObjectContext *sctx,
ray_normal_local,
0.0f,
&hit,
- sctx->runtime.params->use_backface_culling ?
+ params->use_backface_culling ?
mesh_looptri_raycast_backface_culling_cb :
treedata->raycast_callback,
treedata) != -1) {
@@ -805,6 +806,7 @@ static bool raycastMesh(SnapObjectContext *sctx,
}
static bool raycastEditMesh(SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
const float ray_start[3],
const float ray_dir[3],
Object *ob_eval,
@@ -943,7 +945,7 @@ static bool raycastEditMesh(SnapObjectContext *sctx,
ray_normal_local,
0.0f,
&hit,
- sctx->runtime.params->use_backface_culling ?
+ params->use_backface_culling ?
editmesh_looptri_raycast_backface_culling_cb :
treedata->raycast_callback,
treedata) != -1) {
@@ -994,12 +996,14 @@ struct RaycastObjUserData {
};
/**
- * \param use_obedit: Uses the coordinates of BMesh (if any) to do the snapping;
- *
* \note Duplicate args here are documented at #snapObjectsRay
*/
-static void raycast_obj_fn(
- SnapObjectContext *sctx, Object *ob_eval, float obmat[4][4], bool is_object_active, void *data)
+static void raycast_obj_fn(SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
+ Object *ob_eval,
+ float obmat[4][4],
+ bool is_object_active,
+ void *data)
{
struct RaycastObjUserData *dt = data;
const uint ob_index = dt->ob_index++;
@@ -1018,13 +1022,14 @@ static void raycast_obj_fn(
switch (ob_eval->type) {
case OB_MESH: {
- const eSnapEditType edit_mode_type = sctx->runtime.params->edit_mode_type;
+ const eSnapEditType edit_mode_type = params->edit_mode_type;
bool use_hide = false;
Mesh *me_eval = mesh_for_snap(ob_eval, edit_mode_type, &use_hide);
if (me_eval == NULL) {
/* Operators only update the editmesh looptris of the original mesh. */
BMEditMesh *em_orig = BKE_editmesh_from_object(DEG_get_original_object(ob_eval));
retval = raycastEditMesh(sctx,
+ params,
dt->ray_start,
dt->ray_dir,
ob_eval,
@@ -1039,6 +1044,7 @@ static void raycast_obj_fn(
break;
}
retval = raycastMesh(sctx,
+ params,
dt->ray_start,
dt->ray_dir,
ob_eval,
@@ -1060,6 +1066,7 @@ static void raycast_obj_fn(
const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob_eval);
if (mesh_eval) {
retval = raycastMesh(sctx,
+ params,
dt->ray_start,
dt->ray_dir,
ob_eval,
@@ -1115,6 +1122,7 @@ static void raycast_obj_fn(
* \param r_hit_list: List of #SnapObjectHitDepth (caller must free).
*/
static bool raycastObjects(SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
const float ray_start[3],
const float ray_dir[3],
/* read/write args */
@@ -1129,7 +1137,6 @@ static bool raycastObjects(SnapObjectContext *sctx,
float r_obmat[4][4],
ListBase *r_hit_list)
{
- const struct SnapObjectParams *params = sctx->runtime.params;
const View3D *v3d = sctx->runtime.v3d;
if (params->use_occlusion_test && v3d && XRAY_FLAG_ENABLED(v3d)) {
/* General testing of occlusion geometry is disabled if the snap is not intended for the edit
@@ -1154,7 +1161,7 @@ static bool raycastObjects(SnapObjectContext *sctx,
.ret = false,
};
- iter_snap_objects(sctx, raycast_obj_fn, &data);
+ iter_snap_objects(sctx, params, raycast_obj_fn, &data);
return data.ret;
}
@@ -1531,6 +1538,7 @@ static void cb_snap_tri_verts(void *userdata,
* \{ */
static short snap_mesh_polygon(SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
Object *ob_eval,
const float obmat[4][4],
/* read/write args */
@@ -1564,10 +1572,8 @@ static short snap_mesh_polygon(SnapObjectContext *sctx,
BLI_assert(sod != NULL);
Nearest2dUserData nearest2d;
- nearest2d_data_init(sod,
- sctx->runtime.view_proj == VIEW_PROJ_PERSP,
- sctx->runtime.params->use_backface_culling,
- &nearest2d);
+ nearest2d_data_init(
+ sod, sctx->runtime.view_proj == VIEW_PROJ_PERSP, params->use_backface_culling, &nearest2d);
if (sod->type == SNAP_MESH) {
BVHTreeFromMesh *treedata = &sod->treedata_mesh;
@@ -1657,6 +1663,7 @@ static short snap_mesh_polygon(SnapObjectContext *sctx,
}
static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
Object *ob_eval,
const float obmat[4][4],
float original_dist_px,
@@ -1678,10 +1685,8 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
BLI_assert(sod != NULL);
Nearest2dUserData nearest2d;
- nearest2d_data_init(sod,
- sctx->runtime.view_proj == VIEW_PROJ_PERSP,
- sctx->runtime.params->use_backface_culling,
- &nearest2d);
+ nearest2d_data_init(
+ sod, sctx->runtime.view_proj == VIEW_PROJ_PERSP, params->use_backface_culling, &nearest2d);
int vindex[2];
nearest2d.get_edge_verts_index(*r_index, nearest2d.userdata, vindex);
@@ -1806,6 +1811,7 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
}
static short snapArmature(SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
Object *ob_eval,
const float obmat[4][4],
/* read/write args */
@@ -1849,7 +1855,7 @@ static short snapArmature(SnapObjectContext *sctx,
mul_v4_m4v4(clip_planes_local[i], tobmat, sctx->runtime.clip_plane[i]);
}
- const eSnapSelect snap_select = sctx->runtime.params->snap_select;
+ const eSnapSelect snap_select = params->snap_select;
bool is_persp = sctx->runtime.view_proj == VIEW_PROJ_PERSP;
bArmature *arm = ob_eval->data;
@@ -1963,6 +1969,7 @@ static short snapArmature(SnapObjectContext *sctx,
}
static short snapCurve(SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
Object *ob_eval,
const float obmat[4][4],
/* read/write args */
@@ -2022,7 +2029,7 @@ static short snapCurve(SnapObjectContext *sctx,
}
bool is_persp = sctx->runtime.view_proj == VIEW_PROJ_PERSP;
- bool skip_selected = sctx->runtime.params->snap_select == SNAP_NOT_SELECTED;
+ bool skip_selected = params->snap_select == SNAP_NOT_SELECTED;
for (Nurb *nu = (use_obedit ? cu->editnurb->nurbs.first : cu->nurb.first); nu; nu = nu->next) {
for (int u = 0; u < nu->pntsu; u++) {
@@ -2284,6 +2291,7 @@ static short snapCamera(const SnapObjectContext *sctx,
}
static short snapMesh(SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
Object *ob_eval,
Mesh *me_eval,
const float obmat[4][4],
@@ -2358,10 +2366,8 @@ static short snapMesh(SnapObjectContext *sctx,
}
Nearest2dUserData nearest2d;
- nearest2d_data_init(sod,
- sctx->runtime.view_proj == VIEW_PROJ_PERSP,
- sctx->runtime.params->use_backface_culling,
- &nearest2d);
+ nearest2d_data_init(
+ sod, sctx->runtime.view_proj == VIEW_PROJ_PERSP, params->use_backface_culling, &nearest2d);
BVHTreeNearest nearest = {
.index = -1,
@@ -2476,6 +2482,7 @@ static short snapMesh(SnapObjectContext *sctx,
}
static short snapEditMesh(SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
Object *ob_eval,
BMEditMesh *em,
const float obmat[4][4],
@@ -2579,10 +2586,8 @@ static short snapEditMesh(SnapObjectContext *sctx,
}
Nearest2dUserData nearest2d;
- nearest2d_data_init(sod,
- sctx->runtime.view_proj == VIEW_PROJ_PERSP,
- sctx->runtime.params->use_backface_culling,
- &nearest2d);
+ nearest2d_data_init(
+ sod, sctx->runtime.view_proj == VIEW_PROJ_PERSP, params->use_backface_culling, &nearest2d);
BVHTreeNearest nearest = {
.index = -1,
@@ -2670,11 +2675,10 @@ struct SnapObjUserData {
};
/**
- * \param use_obedit: Uses the coordinates of BMesh (if any) to do the snapping;
- *
* \note Duplicate args here are documented at #snapObjectsRay
*/
static void snap_obj_fn(SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
Object *ob_eval,
float obmat[4][4],
bool UNUSED(is_object_active),
@@ -2685,14 +2689,14 @@ static void snap_obj_fn(SnapObjectContext *sctx,
switch (ob_eval->type) {
case OB_MESH: {
- const eSnapEditType edit_mode_type = sctx->runtime.params->edit_mode_type;
+ const eSnapEditType edit_mode_type = params->edit_mode_type;
bool use_hide;
Mesh *me_eval = mesh_for_snap(ob_eval, edit_mode_type, &use_hide);
if (me_eval == NULL) {
/* Operators only update the editmesh looptris of the original mesh. */
BMEditMesh *em_orig = BKE_editmesh_from_object(DEG_get_original_object(ob_eval));
retval = snapEditMesh(
- sctx, ob_eval, em_orig, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
+ sctx, params, ob_eval, em_orig, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
break;
}
if (ob_eval->dt == OB_BOUNDBOX) {
@@ -2700,22 +2704,40 @@ static void snap_obj_fn(SnapObjectContext *sctx,
return;
}
- retval = snapMesh(
- sctx, ob_eval, me_eval, obmat, use_hide, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
+ retval = snapMesh(sctx,
+ params,
+ ob_eval,
+ me_eval,
+ obmat,
+ use_hide,
+ dt->dist_px,
+ dt->r_loc,
+ dt->r_no,
+ dt->r_index);
break;
}
case OB_ARMATURE:
- retval = snapArmature(sctx, ob_eval, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
+ retval = snapArmature(
+ sctx, params, ob_eval, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
break;
case OB_CURVE:
- retval = snapCurve(sctx, ob_eval, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
+ retval = snapCurve(
+ sctx, params, ob_eval, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
break; /* Use ATTR_FALLTHROUGH if we want to snap to the generated mesh. */
case OB_SURF:
case OB_FONT: {
Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob_eval);
if (mesh_eval) {
- retval |= snapMesh(
- sctx, ob_eval, mesh_eval, obmat, false, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
+ retval |= snapMesh(sctx,
+ params,
+ ob_eval,
+ mesh_eval,
+ obmat,
+ false,
+ dt->dist_px,
+ dt->r_loc,
+ dt->r_no,
+ dt->r_index);
}
break;
}
@@ -2765,6 +2787,7 @@ static void snap_obj_fn(SnapObjectContext *sctx,
* \param r_obmat: Object matrix (may not be #Object.obmat with dupli-instances).
*/
static short snapObjectsRay(SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
/* read/write args */
/* Parameters below cannot be const, because they are assigned to a
* non-const variable (readability-non-const-parameter). */
@@ -2786,7 +2809,7 @@ static short snapObjectsRay(SnapObjectContext *sctx,
.ret = 0,
};
- iter_snap_objects(sctx, snap_obj_fn, &data);
+ iter_snap_objects(sctx, params, snap_obj_fn, &data);
return data.ret;
}
@@ -2857,21 +2880,13 @@ bool ED_transform_snap_object_project_ray_ex(SnapObjectContext *sctx,
Object **r_ob,
float r_obmat[4][4])
{
- sctx->runtime.params = params;
sctx->runtime.depsgraph = depsgraph;
sctx->runtime.v3d = v3d;
return raycastObjects(
- sctx, ray_start, ray_normal, ray_depth, r_loc, r_no, r_index, r_ob, r_obmat, NULL);
+ sctx, params, ray_start, ray_normal, ray_depth, r_loc, r_no, r_index, r_ob, r_obmat, NULL);
}
-/**
- * Fill in a list of all hits.
- *
- * \param ray_depth: Only depths in this range are considered, -1.0 for maximum.
- * \param sort: Optionally sort the hits by depth.
- * \param r_hit_list: List of #SnapObjectHitDepth (caller must free).
- */
bool ED_transform_snap_object_project_ray_all(SnapObjectContext *sctx,
Depsgraph *depsgraph,
const View3D *v3d,
@@ -2882,7 +2897,6 @@ bool ED_transform_snap_object_project_ray_all(SnapObjectContext *sctx,
bool sort,
ListBase *r_hit_list)
{
- sctx->runtime.params = params;
sctx->runtime.depsgraph = depsgraph;
sctx->runtime.v3d = v3d;
@@ -2895,7 +2909,7 @@ bool ED_transform_snap_object_project_ray_all(SnapObjectContext *sctx,
#endif
bool retval = raycastObjects(
- sctx, ray_start, ray_normal, &ray_depth, NULL, NULL, NULL, NULL, NULL, r_hit_list);
+ sctx, params, ray_start, ray_normal, &ray_depth, NULL, NULL, NULL, NULL, NULL, r_hit_list);
/* meant to be readonly for 'all' hits, ensure it is */
#ifdef DEBUG
@@ -2982,7 +2996,6 @@ static short transform_snap_context_project_view3d_mixed_impl(
float r_obmat[4][4],
float r_face_nor[3])
{
- sctx->runtime.params = params;
sctx->runtime.depsgraph = depsgraph;
sctx->runtime.region = region;
sctx->runtime.v3d = v3d;
@@ -3015,8 +3028,17 @@ static short transform_snap_context_project_view3d_mixed_impl(
float dummy_ray_depth = BVH_RAYCAST_DIST_MAX;
- has_hit = raycastObjects(
- sctx, ray_start, ray_normal, &dummy_ray_depth, loc, no, &index, &ob_eval, obmat, NULL);
+ has_hit = raycastObjects(sctx,
+ params,
+ ray_start,
+ ray_normal,
+ &dummy_ray_depth,
+ loc,
+ no,
+ &index,
+ &ob_eval,
+ obmat,
+ NULL);
if (has_hit) {
if (r_face_nor) {
@@ -3086,7 +3108,7 @@ static short transform_snap_context_project_view3d_mixed_impl(
new_clipplane[3] += 0.01f;
/* Try to snap only to the polygon. */
- elem_test = snap_mesh_polygon(sctx, ob_eval, obmat, &dist_px_tmp, loc, no, &index);
+ elem_test = snap_mesh_polygon(sctx, params, ob_eval, obmat, &dist_px_tmp, loc, no, &index);
if (elem_test) {
elem = elem_test;
}
@@ -3100,7 +3122,7 @@ static short transform_snap_context_project_view3d_mixed_impl(
sctx->runtime.has_occlusion_plane = true;
}
- elem_test = snapObjectsRay(sctx, &dist_px_tmp, loc, no, &index, &ob_eval, obmat);
+ elem_test = snapObjectsRay(sctx, params, &dist_px_tmp, loc, no, &index, &ob_eval, obmat);
if (elem_test) {
elem = elem_test;
}
@@ -3110,7 +3132,7 @@ static short transform_snap_context_project_view3d_mixed_impl(
SCE_SNAP_MODE_EDGE_PERPENDICULAR))) {
sctx->runtime.snap_to_flag = snap_to_flag;
elem = snap_mesh_edge_verts_mixed(
- sctx, ob_eval, obmat, *dist_px, prev_co, &dist_px_tmp, loc, no, &index);
+ sctx, params, ob_eval, obmat, *dist_px, prev_co, &dist_px_tmp, loc, no, &index);
}
if (elem & snap_to_flag) {
@@ -3174,19 +3196,6 @@ short ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx,
r_face_nor);
}
-/**
- * Convenience function for performing snapping.
- *
- * Given a 2D region value, snap to vert/edge/face.
- *
- * \param sctx: Snap context.
- * \param mval: Screenspace coordinate.
- * \param prev_co: Coordinate for perpendicular point calculation (optional).
- * \param dist_px: Maximum distance to snap (in pixels).
- * \param r_loc: hit location.
- * \param r_no: hit normal (optional).
- * \return Snap success
- */
short ED_transform_snap_object_project_view3d(SnapObjectContext *sctx,
Depsgraph *depsgraph,
const ARegion *region,
@@ -3216,9 +3225,6 @@ short ED_transform_snap_object_project_view3d(SnapObjectContext *sctx,
NULL);
}
-/**
- * see: #ED_transform_snap_object_project_ray_all
- */
bool ED_transform_snap_object_project_all_view3d_ex(SnapObjectContext *sctx,
Depsgraph *depsgraph,
const ARegion *region,
diff --git a/source/blender/editors/undo/ed_undo.c b/source/blender/editors/undo/ed_undo.c
index fa722d0646a..c6fa5acfff5 100644
--- a/source/blender/editors/undo/ed_undo.c
+++ b/source/blender/editors/undo/ed_undo.c
@@ -64,6 +64,7 @@
#include "RNA_access.h"
#include "RNA_define.h"
+#include "RNA_enum_types.h"
#include "UI_interface.h"
#include "UI_resources.h"
@@ -77,9 +78,6 @@ static CLG_LogRef LOG = {"ed.undo"};
* Non-operator undo editor functions.
* \{ */
-/**
- * Run from the main event loop, basic checks that undo is left in a correct state.
- */
bool ED_undo_is_state_valid(bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -377,6 +375,9 @@ static int ed_undo_step_by_index(bContext *C, const int undo_index, ReportList *
wmWindowManager *wm = CTX_wm_manager(C);
const int active_step_index = BLI_findindex(&wm->undo_stack->steps, wm->undo_stack->step_active);
+ if (undo_index == active_step_index) {
+ return OPERATOR_CANCELLED;
+ }
const enum eUndoStepDir undo_dir = (undo_index < active_step_index) ? STEP_UNDO : STEP_REDO;
CLOG_INFO(&LOG,
@@ -438,7 +439,6 @@ void ED_undo_pop_op(bContext *C, wmOperator *op)
ed_undo_step_by_name(C, op->type->name, op->reports);
}
-/* name optionally, function used to check for operator redo panel */
bool ED_undo_is_valid(const bContext *C, const char *undoname)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -461,14 +461,6 @@ bool ED_undo_is_memfile_compatible(const bContext *C)
return true;
}
-/**
- * When a property of ID changes, return false.
- *
- * This is to avoid changes to a property making undo pushes
- * which are ignored by the undo-system.
- * For example, changing a brush property isn't stored by sculpt-mode undo steps.
- * This workaround is needed until the limitation is removed, see: T61948.
- */
bool ED_undo_is_legacy_compatible_for_property(struct bContext *C, ID *id)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -494,13 +486,6 @@ bool ED_undo_is_legacy_compatible_for_property(struct bContext *C, ID *id)
return true;
}
-/**
- * Ideally we won't access the stack directly,
- * this is needed for modes which handle undo themselves (bypassing #ED_undo_push).
- *
- * Using global isn't great, this just avoids doing inline,
- * causing 'BKE_global.h' & 'BKE_main.h' includes.
- */
UndoStack *ED_undo_stack_get(void)
{
wmWindowManager *wm = G_MAIN->wm.first;
@@ -513,17 +498,28 @@ UndoStack *ED_undo_stack_get(void)
/** \name Undo, Undo Push & Redo Operators
* \{ */
+/**
+ * Refresh to run after user activated undo/redo actions.
+ */
+static void ed_undo_refresh_for_op(bContext *C)
+{
+ /* The "last operator" should disappear, later we can tie this with undo stack nicer. */
+ WM_operator_stack_clear(CTX_wm_manager(C));
+
+ /* Keep button under the cursor active. */
+ WM_event_add_mousemove(CTX_wm_window(C));
+
+ ED_outliner_select_sync_from_all_tag(C);
+}
+
static int ed_undo_exec(bContext *C, wmOperator *op)
{
/* "last operator" should disappear, later we can tie this with undo stack nicer */
WM_operator_stack_clear(CTX_wm_manager(C));
int ret = ed_undo_step_direction(C, STEP_UNDO, op->reports);
if (ret & OPERATOR_FINISHED) {
- /* Keep button under the cursor active. */
- WM_event_add_mousemove(CTX_wm_window(C));
+ ed_undo_refresh_for_op(C);
}
-
- ED_outliner_select_sync_from_all_tag(C);
return ret;
}
@@ -548,11 +544,8 @@ static int ed_redo_exec(bContext *C, wmOperator *op)
{
int ret = ed_undo_step_direction(C, STEP_REDO, op->reports);
if (ret & OPERATOR_FINISHED) {
- /* Keep button under the cursor active. */
- WM_event_add_mousemove(CTX_wm_window(C));
+ ed_undo_refresh_for_op(C);
}
-
- ED_outliner_select_sync_from_all_tag(C);
return ret;
}
@@ -682,7 +675,6 @@ void ED_OT_undo_redo(wmOperatorType *ot)
/** \name Operator Repeat
* \{ */
-/* ui callbacks should call this rather than calling WM_operator_repeat() themselves */
int ED_undo_operator_repeat(bContext *C, wmOperator *op)
{
int ret = 0;
@@ -768,97 +760,36 @@ void ED_undo_operator_repeat_cb_evt(bContext *C, void *arg_op, int UNUSED(arg_un
/* -------------------------------------------------------------------- */
/** \name Undo History Operator
+ *
+ * See `TOPBAR_MT_undo_history` which is used to access this operator.
* \{ */
-/* create enum based on undo items */
-static const EnumPropertyItem *rna_undo_itemf(bContext *C, int *totitem)
-{
- EnumPropertyItem item_tmp = {0}, *item = NULL;
- int i = 0;
-
- wmWindowManager *wm = CTX_wm_manager(C);
- if (wm->undo_stack == NULL) {
- return NULL;
- }
-
- for (UndoStep *us = wm->undo_stack->steps.first; us; us = us->next, i++) {
- if (us->skip == false) {
- item_tmp.identifier = us->name;
- item_tmp.name = IFACE_(us->name);
- if (us == wm->undo_stack->step_active) {
- item_tmp.icon = ICON_LAYER_ACTIVE;
- }
- else {
- item_tmp.icon = ICON_NONE;
- }
- item_tmp.value = i;
- RNA_enum_item_add(&item, totitem, &item_tmp);
- }
- }
- RNA_enum_item_end(&item, totitem);
-
- return item;
-}
-
-static int undo_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+/* NOTE: also check #ed_undo_step() in top if you change notifiers. */
+static int undo_history_exec(bContext *C, wmOperator *op)
{
- int totitem = 0;
-
- {
- const EnumPropertyItem *item = rna_undo_itemf(C, &totitem);
-
- if (totitem > 0) {
- uiPopupMenu *pup = UI_popup_menu_begin(
- C, WM_operatortype_name(op->type, op->ptr), ICON_NONE);
- uiLayout *layout = UI_popup_menu_layout(pup);
- uiLayout *split = uiLayoutSplit(layout, 0.0f, false);
- uiLayout *column = NULL;
- const int col_size = 20 + totitem / 12;
- int i, c;
- bool add_col = true;
-
- for (c = 0, i = totitem; i--;) {
- if (add_col && !(c % col_size)) {
- column = uiLayoutColumn(split, false);
- add_col = false;
- }
- if (item[i].identifier) {
- uiItemIntO(column, item[i].name, item[i].icon, op->type->idname, "item", item[i].value);
- c++;
- add_col = true;
- }
- }
-
- MEM_freeN((void *)item);
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "item");
+ if (RNA_property_is_set(op->ptr, prop)) {
+ const int item = RNA_property_int_get(op->ptr, prop);
+ const int ret = ed_undo_step_by_index(C, item, op->reports);
+ if (ret & OPERATOR_FINISHED) {
+ ed_undo_refresh_for_op(C);
- UI_popup_menu_end(C, pup);
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
+ return OPERATOR_FINISHED;
}
}
return OPERATOR_CANCELLED;
}
-/* NOTE: also check #ed_undo_step() in top if you change notifiers. */
-static int undo_history_exec(bContext *C, wmOperator *op)
+static int undo_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
PropertyRNA *prop = RNA_struct_find_property(op->ptr, "item");
if (RNA_property_is_set(op->ptr, prop)) {
- int item = RNA_property_int_get(op->ptr, prop);
- WM_operator_stack_clear(CTX_wm_manager(C));
- ed_undo_step_by_index(C, item, op->reports);
- WM_event_add_notifier(C, NC_WINDOW, NULL);
- return OPERATOR_FINISHED;
+ return undo_history_exec(C, op);
}
- return OPERATOR_CANCELLED;
-}
-static bool undo_history_poll(bContext *C)
-{
- if (!ed_undo_is_init_and_screenactive_poll(C)) {
- return false;
- }
- UndoStack *undo_stack = CTX_wm_manager(C)->undo_stack;
- /* More than just original state entry. */
- return BLI_listbase_count_at_most(&undo_stack->steps, 2) > 1;
+ WM_menu_name_call(C, "TOPBAR_MT_undo_history", WM_OP_INVOKE_DEFAULT);
+ return OPERATOR_FINISHED;
}
void ED_OT_undo_history(wmOperatorType *ot)
@@ -871,7 +802,7 @@ void ED_OT_undo_history(wmOperatorType *ot)
/* api callbacks */
ot->invoke = undo_history_invoke;
ot->exec = undo_history_exec;
- ot->poll = undo_history_poll;
+ ot->poll = ed_undo_is_init_and_screenactive_poll;
RNA_def_int(ot->srna, "item", 0, 0, INT_MAX, "Item", "", 0, INT_MAX);
}
@@ -899,9 +830,6 @@ void ED_undo_object_set_active_or_warn(
}
}
-/**
- * Load all our objects from `object_array` into edit-mode, clear everything else.
- */
void ED_undo_object_editmode_restore_helper(struct bContext *C,
Object **object_array,
uint object_array_len,
diff --git a/source/blender/editors/undo/memfile_undo.c b/source/blender/editors/undo/memfile_undo.c
index 1bdc2b2251e..b6ad5603808 100644
--- a/source/blender/editors/undo/memfile_undo.c
+++ b/source/blender/editors/undo/memfile_undo.c
@@ -35,6 +35,7 @@
#include "BKE_blender_undo.h"
#include "BKE_context.h"
+#include "BKE_icons.h"
#include "BKE_lib_id.h"
#include "BKE_lib_query.h"
#include "BKE_main.h"
@@ -48,6 +49,7 @@
#include "WM_types.h"
#include "ED_object.h"
+#include "ED_render.h"
#include "ED_undo.h"
#include "ED_util.h"
@@ -142,6 +144,32 @@ static int memfile_undosys_step_id_reused_cb(LibraryIDLinkCallbackData *cb_data)
return IDWALK_RET_NOP;
}
+/**
+ * ID previews may be generated in a parallel job. So whatever operation generates the preview
+ * likely does the undo push before the preview is actually done and stored in the ID. Hence they
+ * get some extra treatment here:
+ * When undoing back to the moment the preview generation was triggered, this function schedules
+ * the preview for regeneration.
+ */
+static void memfile_undosys_unfinished_id_previews_restart(ID *id)
+{
+ PreviewImage *preview = BKE_previewimg_id_get(id);
+ if (!preview) {
+ return;
+ }
+
+ for (int i = 0; i < NUM_ICON_SIZES; i++) {
+ if (preview->flag[i] & PRV_USER_EDITED) {
+ /* Don't modify custom previews. */
+ continue;
+ }
+
+ if (!BKE_previewimg_is_finished(preview, i)) {
+ ED_preview_restart_queue_add(id, i);
+ }
+ }
+}
+
static void memfile_undosys_step_decode(struct bContext *C,
struct Main *bmain,
UndoStep *us_p,
@@ -188,6 +216,9 @@ static void memfile_undosys_step_decode(struct bContext *C,
}
ED_editors_exit(bmain, false);
+ /* Ensure there's no preview job running. Unfinished previews will be scheduled for regeneration
+ * via #memfile_undosys_unfinished_id_previews_restart(). */
+ ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
MemFileUndoStep *us = (MemFileUndoStep *)us_p;
BKE_memfile_undo_decode(us->data, undo_direction, use_old_bmain_data, C);
@@ -239,6 +270,9 @@ static void memfile_undosys_step_decode(struct bContext *C,
bmain, &scene->master_collection->id, scene->master_collection->id.recalc);
}
}
+
+ /* Restart preview generation if the undo state was generating previews. */
+ memfile_undosys_unfinished_id_previews_restart(id);
}
FOREACH_MAIN_ID_END;
@@ -263,6 +297,14 @@ static void memfile_undosys_step_decode(struct bContext *C,
}
FOREACH_MAIN_ID_END;
}
+ else {
+ ID *id = NULL;
+ FOREACH_MAIN_ID_BEGIN (bmain, id) {
+ /* Restart preview generation if the undo state was generating previews. */
+ memfile_undosys_unfinished_id_previews_restart(id);
+ }
+ FOREACH_MAIN_ID_END;
+ }
WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, CTX_data_scene(C));
}
@@ -283,7 +325,6 @@ static void memfile_undosys_step_free(UndoStep *us_p)
BKE_memfile_undo_free(us->data);
}
-/* Export for ED_undo_sys. */
void ED_memfile_undosys_type(UndoType *ut)
{
ut->name = "Global Undo";
@@ -322,21 +363,6 @@ struct MemFile *ED_undosys_stack_memfile_get_active(UndoStack *ustack)
return NULL;
}
-/**
- * If the last undo step is a memfile one, find the first #MemFileChunk matching given ID
- * (using its session UUID), and tag it as "changed in the future".
- *
- * Since non-memfile undo-steps cannot automatically set this flag in the previous step as done
- * with memfile ones, this has to be called manually by relevant undo code.
- *
- * \note Only current known case for this is undoing a switch from Object to Sculpt mode (see
- * T82388).
- *
- * \note Calling this ID by ID is not optimal, as it will loop over all #MemFile.chunks until it
- * finds the expected one. If this becomes an issue we'll have to add a mapping from session UUID
- * to first #MemFileChunk in #MemFile itself
- * (currently we only do that in #MemFileWriteData when writing a new step).
- */
void ED_undosys_stack_memfile_id_changed_tag(UndoStack *ustack, ID *id)
{
UndoStep *us = ustack->step_active;
diff --git a/source/blender/editors/undo/undo_intern.h b/source/blender/editors/undo/undo_intern.h
index 660f1a5b57d..d27bc1c8c0a 100644
--- a/source/blender/editors/undo/undo_intern.h
+++ b/source/blender/editors/undo/undo_intern.h
@@ -25,4 +25,6 @@
struct UndoType;
/* memfile_undo.c */
+
+/** Export for ED_undo_sys. */
void ED_memfile_undosys_type(struct UndoType *ut);
diff --git a/source/blender/editors/util/ed_draw.c b/source/blender/editors/util/ed_draw.c
index 721e32a3051..ccbde07f5b1 100644
--- a/source/blender/editors/util/ed_draw.c
+++ b/source/blender/editors/util/ed_draw.c
@@ -397,17 +397,11 @@ tSlider *ED_slider_create(struct bContext *C)
return slider;
}
-/**
- * For modal operations so the percentage doesn't pop on the first mouse movement.
- */
void ED_slider_init(struct tSlider *slider, const wmEvent *event)
{
copy_v2fl_v2i(slider->last_cursor, event->xy);
}
-/**
- * Calculate slider factor based on mouse position.
- */
bool ED_slider_modal(tSlider *slider, const wmEvent *event)
{
bool event_handled = true;
@@ -441,9 +435,6 @@ bool ED_slider_modal(tSlider *slider, const wmEvent *event)
return event_handled;
}
-/**
- * Return string based on the current state of the slider.
- */
void ED_slider_status_string_get(const struct tSlider *slider,
char *status_string,
const size_t size_of_status_string)
@@ -523,9 +514,6 @@ void ED_slider_allow_overshoot_set(struct tSlider *slider, const bool value)
/** \} */
-/**
- * Callback that draws a line between the mouse and a position given as the initial argument.
- */
void ED_region_draw_mouse_line_cb(const bContext *C, ARegion *region, void *arg_info)
{
wmWindow *win = CTX_wm_window(C);
@@ -776,9 +764,6 @@ static float metadata_box_height_get(ImBuf *ibuf, int fontid, const bool is_top)
return 0;
}
-/**
- * \note Keep in sync with #BKE_image_stamp_buf.
- */
void ED_region_image_metadata_draw(
int x, int y, ImBuf *ibuf, const rctf *frame, float zoomx, float zoomy)
{
diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c
index 348deec1166..882f140c063 100644
--- a/source/blender/editors/util/ed_util.c
+++ b/source/blender/editors/util/ed_util.c
@@ -195,7 +195,6 @@ void ED_editors_init(bContext *C)
wm->op_undo_depth--;
}
-/* frees all editmode stuff */
void ED_editors_exit(Main *bmain, bool do_undo_system)
{
if (!bmain) {
@@ -291,8 +290,6 @@ bool ED_editors_flush_edits_for_object(Main *bmain, Object *ob)
return ED_editors_flush_edits_for_object_ex(bmain, ob, false, false);
}
-/* flush any temp data from object editing to DNA before writing files,
- * rendering, copying, etc. */
bool ED_editors_flush_edits_ex(Main *bmain, bool for_render, bool check_needs_flush)
{
bool has_edited = false;
@@ -317,11 +314,6 @@ bool ED_editors_flush_edits(Main *bmain)
/* ***** XXX: functions are using old blender names, cleanup later ***** */
-/**
- * Now only used in 2D spaces, like time, f-curve, NLA, image, etc.
- *
- * \note Shift/Control are not configurable key-bindings.
- */
void apply_keyb_grid(
int shift, int ctrl, float *val, float fac1, float fac2, float fac3, int invert)
{
@@ -360,6 +352,7 @@ void unpack_menu(bContext *C,
uiLayout *layout;
char line[FILE_MAX + 100];
wmOperatorType *ot = WM_operatortype_find(opname, 1);
+ const char *blendfile_path = BKE_main_blendfile_path(bmain);
pup = UI_popup_menu_begin(C, IFACE_("Unpack File"), ICON_NONE);
layout = UI_popup_menu_layout(pup);
@@ -369,13 +362,13 @@ void unpack_menu(bContext *C,
RNA_enum_set(&props_ptr, "method", PF_REMOVE);
RNA_string_set(&props_ptr, "id", id_name);
- if (G.relbase_valid) {
+ if (blendfile_path[0] != '\0') {
char local_name[FILE_MAXDIR + FILE_MAX], fi[FILE_MAX];
BLI_split_file_part(abs_name, fi, sizeof(fi));
BLI_snprintf(local_name, sizeof(local_name), "//%s/%s", folder, fi);
if (!STREQ(abs_name, local_name)) {
- switch (BKE_packedfile_compare_to_file(BKE_main_blendfile_path(bmain), local_name, pf)) {
+ switch (BKE_packedfile_compare_to_file(blendfile_path, local_name, pf)) {
case PF_CMP_NOFILE:
BLI_snprintf(line, sizeof(line), TIP_("Create %s"), local_name);
uiItemFullO_ptr(layout, ot, line, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, 0, &props_ptr);
@@ -408,7 +401,7 @@ void unpack_menu(bContext *C,
}
}
- switch (BKE_packedfile_compare_to_file(BKE_main_blendfile_path(bmain), abs_name, pf)) {
+ switch (BKE_packedfile_compare_to_file(blendfile_path, abs_name, pf)) {
case PF_CMP_NOFILE:
BLI_snprintf(line, sizeof(line), TIP_("Create %s"), abs_name);
// uiItemEnumO_ptr(layout, ot, line, 0, "method", PF_WRITE_ORIGINAL);
@@ -441,11 +434,6 @@ void unpack_menu(bContext *C,
UI_popup_menu_end(C, pup);
}
-/**
- * Use to free ID references within runtime data (stored outside of DNA)
- *
- * \param new_id: may be NULL to unlink \a old_id.
- */
void ED_spacedata_id_remap(struct ScrArea *area, struct SpaceLink *sl, ID *old_id, ID *new_id)
{
SpaceType *st = BKE_spacetype_from_id(sl->spacetype);
diff --git a/source/blender/editors/util/ed_util_ops.cc b/source/blender/editors/util/ed_util_ops.cc
index 7d32d252718..a1b17d799bc 100644
--- a/source/blender/editors/util/ed_util_ops.cc
+++ b/source/blender/editors/util/ed_util_ops.cc
@@ -110,7 +110,7 @@ static void ED_OT_lib_id_load_custom_preview(wmOperatorType *ot)
ot->invoke = WM_operator_filesel;
/* flags */
- ot->flag = OPTYPE_INTERNAL;
+ ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
WM_operator_properties_filesel(ot,
FILE_TYPE_FOLDER | FILE_TYPE_IMAGE,
@@ -276,7 +276,7 @@ static void ED_OT_flush_edits(wmOperatorType *ot)
/** \} */
-void ED_operatortypes_edutils(void)
+void ED_operatortypes_edutils()
{
WM_operatortype_append(ED_OT_lib_id_load_custom_preview);
WM_operatortype_append(ED_OT_lib_id_generate_preview);
diff --git a/source/blender/editors/util/gizmo_utils.c b/source/blender/editors/util/gizmo_utils.c
index 08e7b3a9a0a..99df194f0eb 100644
--- a/source/blender/editors/util/gizmo_utils.c
+++ b/source/blender/editors/util/gizmo_utils.c
@@ -70,7 +70,6 @@ bool ED_gizmo_poll_or_unlink_delayed_from_tool_ex(const bContext *C,
return true;
}
-/** Can use this as poll function directly. */
bool ED_gizmo_poll_or_unlink_delayed_from_tool(const bContext *C, wmGizmoGroupType *gzgt)
{
return ED_gizmo_poll_or_unlink_delayed_from_tool_ex(C, gzgt, gzgt->idname);
diff --git a/source/blender/editors/util/numinput.c b/source/blender/editors/util/numinput.c
index d0f27770d9b..583e4060a9a 100644
--- a/source/blender/editors/util/numinput.c
+++ b/source/blender/editors/util/numinput.c
@@ -98,7 +98,6 @@ void initNumInput(NumInput *n)
n->str_cur = 0;
}
-/* str must be NUM_STR_REP_LEN * (idx_max + 1) length. */
void outputNumInput(NumInput *n, char *str, UnitSettings *unit_settings)
{
short j;
@@ -201,9 +200,6 @@ bool hasNumInput(const NumInput *n)
return false;
}
-/**
- * \warning \a vec must be set beforehand otherwise we risk uninitialized vars.
- */
bool applyNumInput(NumInput *n, float *vec)
{
short i, j;
diff --git a/source/blender/editors/util/select_utils.c b/source/blender/editors/util/select_utils.c
index 99412079adf..c7bb26db1bd 100644
--- a/source/blender/editors/util/select_utils.c
+++ b/source/blender/editors/util/select_utils.c
@@ -26,7 +26,6 @@
#include "ED_select_utils.h"
-/** 1: select, 0: deselect, -1: pass. */
int ED_select_op_action(const eSelectOp sel_op, const bool is_select, const bool is_inside)
{
switch (sel_op) {
@@ -44,12 +43,6 @@ int ED_select_op_action(const eSelectOp sel_op, const bool is_select, const bool
BLI_assert_msg(0, "invalid sel_op");
return -1;
}
-/**
- * Use when we've de-selected all items first (for modes that need it).
- *
- * \note In some cases changing selection needs to perform other checks,
- * so it's more straightforward to deselect all, then select.
- */
int ED_select_op_action_deselected(const eSelectOp sel_op,
const bool is_select,
const bool is_inside)
@@ -71,9 +64,6 @@ int ED_select_op_action_deselected(const eSelectOp sel_op,
return -1;
}
-/**
- * Utility to use for selection operations that run multiple times (circle select).
- */
eSelectOp ED_select_op_modal(const eSelectOp sel_op, const bool is_first)
{
if (sel_op == SEL_OP_SET) {
diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h
index 9bc8a165b1f..0a0dd9a133b 100644
--- a/source/blender/editors/uvedit/uvedit_intern.h
+++ b/source/blender/editors/uvedit/uvedit_intern.h
@@ -95,6 +95,15 @@ bool uv_find_nearest_edge_multi(struct Scene *scene,
const float penalty,
struct UvNearestHit *hit);
+/**
+ * \param only_in_face: when true, only hit faces which `co` is inside.
+ * This gives users a result they might expect, especially when zoomed in.
+ *
+ * \note Concave faces can cause odd behavior, although in practice this isn't often an issue.
+ * The center can be outside the face, in this case the distance to the center
+ * could cause the face to be considered too far away.
+ * If this becomes an issue we could track the distance to the faces closest edge.
+ */
bool uv_find_nearest_face_ex(struct Scene *scene,
struct Object *obedit,
const float co[2],
@@ -167,6 +176,10 @@ bool uvedit_select_is_any_selected(struct Scene *scene, struct Object *obedit);
bool uvedit_select_is_any_selected_multi(struct Scene *scene,
struct Object **objects,
const uint objects_len);
+/**
+ * \warning This returns first selected UV,
+ * not ideal in many cases since there could be multiple.
+ */
const float *uvedit_first_selected_uv_from_vertex(struct Scene *scene,
struct BMVert *eve,
const int cd_loop_uv_offset);
diff --git a/source/blender/editors/uvedit/uvedit_islands.c b/source/blender/editors/uvedit/uvedit_islands.c
index 6159758dbcd..63a7ab6ab2d 100644
--- a/source/blender/editors/uvedit/uvedit_islands.c
+++ b/source/blender/editors/uvedit/uvedit_islands.c
@@ -237,9 +237,6 @@ static void bm_face_array_uv_scale_y(BMFace **faces,
/** \name UDIM packing helper functions
* \{ */
-/**
- * Returns true if UV coordinates lie on a valid tile in UDIM grid or tiled image.
- */
bool uv_coords_isect_udim(const Image *image, const int udim_grid[2], const float coords[2])
{
const float coords_floor[2] = {floorf(coords[0]), floorf(coords[1])};
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index acdffd5ff98..342afa847b4 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -253,7 +253,6 @@ bool ED_uvedit_minmax(const Scene *scene, Object *obedit, float r_min[2], float
return ED_uvedit_minmax_multi(scene, &obedit, 1, r_min, r_max);
}
-/* Be careful when using this, it bypasses all synchronization options */
void ED_uvedit_select_all(BMesh *bm)
{
BMFace *efa;
diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c
index 83e8259f693..22467c7391f 100644
--- a/source/blender/editors/uvedit/uvedit_select.c
+++ b/source/blender/editors/uvedit/uvedit_select.c
@@ -166,10 +166,6 @@ BMLoop *ED_uvedit_active_edge_loop_get(BMesh *bm)
/** \name Visibility and Selection Utilities
* \{ */
-/**
- * Intentionally don't return #UV_SELECT_ISLAND as it's not an element type.
- * In this case return #UV_SELECT_VERTEX as a fallback.
- */
char ED_uvedit_select_mode_get(const Scene *scene)
{
const ToolSettings *ts = scene->toolsettings;
@@ -946,15 +942,6 @@ bool uv_find_nearest_edge_multi(Scene *scene,
return found;
}
-/**
- * \param only_in_face: when true, only hit faces which `co` is inside.
- * This gives users a result they might expect, especially when zoomed in.
- *
- * \note Concave faces can cause odd behavior, although in practice this isn't often an issue.
- * The center can be outside the face, in this case the distance to the center
- * could cause the face to be considered too far away.
- * If this becomes an issue we could track the distance to the faces closest edge.
- */
bool uv_find_nearest_face_ex(
Scene *scene, Object *obedit, const float co[2], UvNearestHit *hit, const bool only_in_face)
{
@@ -2082,10 +2069,6 @@ static void uv_select_linked_multi(Scene *scene,
}
}
-/**
- * \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,
BMVert *eve,
const int cd_loop_uv_offset)
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index db838bf353b..362e020f306 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -2826,6 +2826,8 @@ void UV_OT_cylinder_project(wmOperatorType *ot)
uv_map_clip_correct_properties(ot);
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Cube UV Project Operator
* \{ */
diff --git a/source/blender/freestyle/FRS_freestyle.h b/source/blender/freestyle/FRS_freestyle.h
index bc5e9d49bee..77e906c6ea5 100644
--- a/source/blender/freestyle/FRS_freestyle.h
+++ b/source/blender/freestyle/FRS_freestyle.h
@@ -59,6 +59,10 @@ void FRS_exit(void);
void FRS_copy_active_lineset(struct FreestyleConfig *config);
void FRS_paste_active_lineset(struct FreestyleConfig *config);
void FRS_delete_active_lineset(struct FreestyleConfig *config);
+/**
+ * Reinsert the active lineset at an offset \a direction from current position.
+ * \return if position of active lineset has changed.
+ */
bool FRS_move_active_lineset(struct FreestyleConfig *config, int direction);
/* Testing */
diff --git a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
index b31f4fd2303..ce80ed78594 100644
--- a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
+++ b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
@@ -769,10 +769,6 @@ void FRS_delete_active_lineset(FreestyleConfig *config)
}
}
-/**
- * Reinsert the active lineset at an offset \a direction from current position.
- * \return if position of active lineset has changed.
- */
bool FRS_move_active_lineset(FreestyleConfig *config, int direction)
{
FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(config);
diff --git a/source/blender/freestyle/intern/image/GaussianFilter.h b/source/blender/freestyle/intern/image/GaussianFilter.h
index 2cb3e7d7ac5..af537cf2d86 100644
--- a/source/blender/freestyle/intern/image/GaussianFilter.h
+++ b/source/blender/freestyle/intern/image/GaussianFilter.h
@@ -37,14 +37,16 @@ namespace Freestyle {
class GaussianFilter {
protected:
/* The mask is a symmetrical 2d array (with respect to the middle point).
- * Thus, M(i,j) = M(-i,j) = M(i,-j) = M(-i,-j).
- * For this reason, to represent a NxN array (N odd), we only store a ((N+1)/2)x((N+1)/2) array.
- */
+ * Thus: `M(i,j) = M(-i,j) = M(i,-j) = M(-i,-j)`.
+ * For this reason, to represent a NxN array (N odd),
+ * we only store a `((N+1)/2)x((N+1)/2)` array. */
+
+ /** The sigma value of the gaussian function. */
float _sigma;
float *_mask;
int _bound;
- // the real mask size (must be odd)(the size of the mask we store is
- // ((_maskSize+1)/2)*((_maskSize+1)/2))
+ /* the real mask size (must be odd)(the size of the mask we store is:
+ * `((_maskSize+1)/2)*((_maskSize+1)/2))`. */
int _maskSize;
int _storedMaskSize; // (_maskSize+1)/2)
@@ -65,8 +67,6 @@ class GaussianFilter {
* The abscissa of the pixel where we want to evaluate the gaussian blur.
* \param y:
* The ordinate of the pixel where we want to evaluate the gaussian blur.
- * \param sigma:
- * The sigma value of the gaussian function.
*/
template<class Map> float getSmoothedPixel(Map *map, int x, int y);
diff --git a/source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.h b/source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.h
index 52cd037a73a..b41beb356c4 100644
--- a/source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.h
+++ b/source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.h
@@ -119,7 +119,7 @@ class SmoothingShader : public StrokeShader {
* 0.2
* \param iAnisoPoint:
* 0
- * \param iAnisNormal:
+ * \param iAnisoNormal:
* 0
* \param iAnisoCurvature:
* 0
diff --git a/source/blender/freestyle/intern/system/PythonInterpreter.h b/source/blender/freestyle/intern/system/PythonInterpreter.h
index 50ebacbd6e8..90dbc259038 100644
--- a/source/blender/freestyle/intern/system/PythonInterpreter.h
+++ b/source/blender/freestyle/intern/system/PythonInterpreter.h
@@ -71,7 +71,7 @@ class PythonInterpreter : public Interpreter {
bool ok = BPY_run_filepath(_context, fn, reports);
#else
bool ok;
- Text *text = BKE_text_load(&_freestyle_bmain, fn, G_MAIN->name);
+ Text *text = BKE_text_load(&_freestyle_bmain, fn, G_MAIN->filepath);
if (text) {
ok = BPY_run_text(_context, text, reports, false);
BKE_id_delete(&_freestyle_bmain, text);
diff --git a/source/blender/freestyle/intern/winged_edge/Curvature.cpp b/source/blender/freestyle/intern/winged_edge/Curvature.cpp
index 411685bd921..ec07a124808 100644
--- a/source/blender/freestyle/intern/winged_edge/Curvature.cpp
+++ b/source/blender/freestyle/intern/winged_edge/Curvature.cpp
@@ -104,27 +104,6 @@ static real angle_from_cotan(WVertex *vo, WVertex *v1, WVertex *v2)
return (fabs(atan2(denom, udotv)));
}
-/** gts_vertex_mean_curvature_normal:
- * \param v: a #WVertex.
- * \param s: a #GtsSurface.
- * \param Kh: the Mean Curvature Normal at \a v.
- *
- * Computes the Discrete Mean Curvature Normal approximation at \a v.
- * The mean curvature at \a v is half the magnitude of the vector \a Kh.
- *
- * NOTE: the normal computed is not unit length, and may point either into or out of the surface,
- * depending on the curvature at \a v. It is the responsibility of the caller of the function to
- * use the mean curvature normal appropriately.
- *
- * This approximation is from the paper:
- * Discrete Differential-Geometry Operators for Triangulated 2-Manifolds
- * Mark Meyer, Mathieu Desbrun, Peter Schroder, Alan H. Barr
- * VisMath '02, Berlin (Germany)
- * http://www-grail.usc.edu/pubs.html
- *
- * Returns: %true if the operator could be evaluated, %false if the evaluation failed for some
- * reason (@v is boundary or is the endpoint of a non-manifold edge.)
- */
bool gts_vertex_mean_curvature_normal(WVertex *v, Vec3r &Kh)
{
real area = 0.0;
@@ -175,22 +154,6 @@ bool gts_vertex_mean_curvature_normal(WVertex *v, Vec3r &Kh)
return true;
}
-/** gts_vertex_gaussian_curvature:
- * \param v: a #WVertex.
- * \param s: a #GtsSurface.
- * \param Kg: the Discrete Gaussian Curvature approximation at \a v.
- *
- * Computes the Discrete Gaussian Curvature approximation at \a v.
- *
- * This approximation is from the paper:
- * Discrete Differential-Geometry Operators for Triangulated 2-Manifolds
- * Mark Meyer, Mathieu Desbrun, Peter Schroder, Alan H. Barr
- * VisMath '02, Berlin (Germany)
- * http://www-grail.usc.edu/pubs.html
- *
- * Returns: %true if the operator could be evaluated, %false if the evaluation failed for some
- * reason (@v is boundary or is the endpoint of a non-manifold edge.)
- */
bool gts_vertex_gaussian_curvature(WVertex *v, real *Kg)
{
real area = 0.0;
@@ -226,20 +189,6 @@ bool gts_vertex_gaussian_curvature(WVertex *v, real *Kg)
return true;
}
-/** gts_vertex_principal_curvatures:
- * @Kh: mean curvature.
- * @Kg: Gaussian curvature.
- * @K1: first principal curvature.
- * @K2: second principal curvature.
- *
- * Computes the principal curvatures at a point given the mean and Gaussian curvatures at that
- * point.
- *
- * The mean curvature can be computed as one-half the magnitude of the vector computed by
- * gts_vertex_mean_curvature_normal().
- *
- * The Gaussian curvature can be computed with gts_vertex_gaussian_curvature().
- */
void gts_vertex_principal_curvatures(real Kh, real Kg, real *K1, real *K2)
{
real temp = Kh * Kh - Kg;
@@ -279,21 +228,6 @@ static void eigenvector(real a, real b, real c, Vec3r e)
e[2] = 0.0;
}
-/** gts_vertex_principal_directions:
- * \param v: a #WVertex.
- * \param s: a #GtsSurface.
- * \param Kh: mean curvature normal (a #Vec3r).
- * \param Kg: Gaussian curvature (a real).
- * \param e1: first principal curvature direction (direction of largest curvature).
- * \param e2: second principal curvature direction.
- *
- * Computes the principal curvature directions at a point given \a Kh and \a Kg,
- * the mean curvature normal and Gaussian curvatures at that point, computed with
- * gts_vertex_mean_curvature_normal() and gts_vertex_gaussian_curvature(), respectively.
- *
- * Note that this computation is very approximate and tends to be unstable. Smoothing of the
- * surface or the principal directions may be necessary to achieve reasonable results.
- */
void gts_vertex_principal_directions(WVertex *v, Vec3r Kh, real Kg, Vec3r &e1, Vec3r &e2)
{
Vec3r N;
diff --git a/source/blender/freestyle/intern/winged_edge/Curvature.h b/source/blender/freestyle/intern/winged_edge/Curvature.h
index 0eefc57c3a2..acbe4e8daf6 100644
--- a/source/blender/freestyle/intern/winged_edge/Curvature.h
+++ b/source/blender/freestyle/intern/winged_edge/Curvature.h
@@ -122,12 +122,75 @@ class Face_Curvature_Info {
#endif
};
+/**
+ * \param v: a #WVertex.
+ * \param Kh: the Mean Curvature Normal at \a v.
+ *
+ * Computes the Discrete Mean Curvature Normal approximation at \a v.
+ * The mean curvature at \a v is half the magnitude of the vector \a Kh.
+ *
+ * \note the normal computed is not unit length, and may point either into or out of the surface,
+ * depending on the curvature at \a v. It is the responsibility of the caller of the function to
+ * use the mean curvature normal appropriately.
+ *
+ * This approximation is from the paper:
+ * Discrete Differential-Geometry Operators for Triangulated 2-Manifolds
+ * Mark Meyer, Mathieu Desbrun, Peter Schroder, Alan H. Barr
+ * VisMath '02, Berlin (Germany)
+ * http://www-grail.usc.edu/pubs.html
+ *
+ * Returns: %true if the operator could be evaluated, %false if the evaluation failed for some
+ * reason (`v` is boundary or is the endpoint of a non-manifold edge.)
+ */
bool gts_vertex_mean_curvature_normal(WVertex *v, Vec3r &Kh);
+/**
+ * \param v: a #WVertex.
+ * \param Kg: the Discrete Gaussian Curvature approximation at \a v.
+ *
+ * Computes the Discrete Gaussian Curvature approximation at \a v.
+ *
+ * This approximation is from the paper:
+ * Discrete Differential-Geometry Operators for Triangulated 2-Manifolds
+ * Mark Meyer, Mathieu Desbrun, Peter Schroder, Alan H. Barr
+ * VisMath '02, Berlin (Germany)
+ * http://www-grail.usc.edu/pubs.html
+ *
+ * Returns: %true if the operator could be evaluated, %false if the evaluation failed for some
+ * reason (`v` is boundary or is the endpoint of a non-manifold edge.)
+ */
bool gts_vertex_gaussian_curvature(WVertex *v, real *Kg);
+/**
+ * \param Kh: mean curvature.
+ * \param Kg: Gaussian curvature.
+ * \param K1: first principal curvature.
+ * \param K2: second principal curvature.
+ *
+ * Computes the principal curvatures at a point given the mean and Gaussian curvatures at that
+ * point.
+ *
+ * The mean curvature can be computed as one-half the magnitude of the vector computed by
+ * #gts_vertex_mean_curvature_normal().
+ *
+ * The Gaussian curvature can be computed with gts_vertex_gaussian_curvature().
+ */
void gts_vertex_principal_curvatures(real Kh, real Kg, real *K1, real *K2);
+/**
+ * \param v: a #WVertex.
+ * \param Kh: mean curvature normal (a #Vec3r).
+ * \param Kg: Gaussian curvature (a real).
+ * \param e1: first principal curvature direction (direction of largest curvature).
+ * \param e2: second principal curvature direction.
+ *
+ * Computes the principal curvature directions at a point given \a Kh and \a Kg,
+ * the mean curvature normal and Gaussian curvatures at that point, computed with
+ * #gts_vertex_mean_curvature_normal() and #gts_vertex_gaussian_curvature(), respectively.
+ *
+ * Note that this computation is very approximate and tends to be unstable. Smoothing of the
+ * surface or the principal directions may be necessary to achieve reasonable results.
+ */
void gts_vertex_principal_directions(WVertex *v, Vec3r Kh, real Kg, Vec3r &e1, Vec3r &e2);
namespace OGF {
diff --git a/source/blender/functions/CMakeLists.txt b/source/blender/functions/CMakeLists.txt
index 54670c0d1b3..9cfaf3eabea 100644
--- a/source/blender/functions/CMakeLists.txt
+++ b/source/blender/functions/CMakeLists.txt
@@ -34,10 +34,11 @@ set(SRC
intern/generic_virtual_vector_array.cc
intern/multi_function.cc
intern/multi_function_builder.cc
- intern/multi_function_parallel.cc
+ intern/multi_function_params.cc
intern/multi_function_procedure.cc
intern/multi_function_procedure_builder.cc
intern/multi_function_procedure_executor.cc
+ intern/multi_function_procedure_optimization.cc
FN_cpp_type.hh
FN_cpp_type_make.hh
@@ -54,12 +55,12 @@ set(SRC
FN_multi_function_builder.hh
FN_multi_function_context.hh
FN_multi_function_data_type.hh
- FN_multi_function_parallel.hh
FN_multi_function_param_type.hh
FN_multi_function_params.hh
FN_multi_function_procedure.hh
FN_multi_function_procedure_builder.hh
FN_multi_function_procedure_executor.hh
+ FN_multi_function_procedure_optimization.hh
FN_multi_function_signature.hh
)
diff --git a/source/blender/functions/FN_cpp_type.hh b/source/blender/functions/FN_cpp_type.hh
index 643b2fc1f28..7ddb5bf1f46 100644
--- a/source/blender/functions/FN_cpp_type.hh
+++ b/source/blender/functions/FN_cpp_type.hh
@@ -207,6 +207,18 @@ class CPPType : NonCopyable, NonMovable {
return is_trivially_destructible_;
}
+ /**
+ * When true, the value is like a normal C type, it can be copied around with #memcpy and does
+ * not have to be destructed.
+ *
+ * C++ equivalent:
+ * std::is_trivial_v<T>;
+ */
+ bool is_trivial() const
+ {
+ return is_trivial_;
+ }
+
bool is_default_constructible() const
{
return default_construct_ != nullptr;
diff --git a/source/blender/functions/FN_field.hh b/source/blender/functions/FN_field.hh
index fb488fdbfa9..a591aaed34a 100644
--- a/source/blender/functions/FN_field.hh
+++ b/source/blender/functions/FN_field.hh
@@ -49,16 +49,15 @@
#include "BLI_function_ref.hh"
#include "BLI_string_ref.hh"
#include "BLI_vector.hh"
+#include "BLI_vector_set.hh"
#include "FN_generic_virtual_array.hh"
#include "FN_multi_function_builder.hh"
-#include "FN_multi_function_procedure.hh"
-#include "FN_multi_function_procedure_builder.hh"
-#include "FN_multi_function_procedure_executor.hh"
namespace blender::fn {
class FieldInput;
+struct FieldInputs;
/**
* A node in a field-tree. It has at least one output that can be referenced by fields.
@@ -66,18 +65,18 @@ class FieldInput;
class FieldNode {
private:
bool is_input_;
+
+ protected:
/**
- * True when this node is a #FieldInput or (potentially indirectly) depends on one. This could
- * always be derived again later by traversing the field-tree, but keeping track of it while the
- * field is built is cheaper.
- *
- * If this is false, the field is constant. Note that even when this is true, the field may be
- * constant when all inputs are constant.
+ * Keeps track of the inputs that this node depends on. This avoids recomputing it every time the
+ * data is required. It is a shared pointer, because very often multiple nodes depend on the same
+ * inputs.
+ * Might contain null.
*/
- bool depends_on_input_;
+ std::shared_ptr<const FieldInputs> field_inputs_;
public:
- FieldNode(bool is_input, bool depends_on_input);
+ FieldNode(bool is_input);
virtual ~FieldNode() = default;
@@ -87,11 +86,7 @@ class FieldNode {
bool is_operation() const;
bool depends_on_input() const;
- /**
- * Invoke callback for every field input. It might be called multiple times for the same input.
- * The caller is responsible for deduplication if required.
- */
- virtual void foreach_field_input(FunctionRef<void(const FieldInput &)> foreach_fn) const = 0;
+ const std::shared_ptr<const FieldInputs> &field_inputs() const;
virtual uint64_t hash() const;
virtual bool is_equal_to(const FieldNode &other) const;
@@ -178,11 +173,19 @@ class GFieldRef : public GFieldBase<const FieldNode *> {
}
};
+namespace detail {
+/* Utility class to make #is_field_v work. */
+struct TypedFieldBase {
+};
+} // namespace detail
+
/**
* A typed version of #GField. It has the same memory layout as #GField.
*/
-template<typename T> class Field : public GField {
+template<typename T> class Field : public GField, detail::TypedFieldBase {
public:
+ using base_type = T;
+
Field() = default;
Field(GField field) : GField(std::move(field))
@@ -196,6 +199,11 @@ template<typename T> class Field : public GField {
}
};
+/** True when T is any Field<...> type. */
+template<typename T>
+static constexpr bool is_field_v = std::is_base_of_v<detail::TypedFieldBase, T> &&
+ !std::is_same_v<detail::TypedFieldBase, T>;
+
/**
* A #FieldNode that allows composing existing fields into new fields.
*/
@@ -218,7 +226,6 @@ class FieldOperation : public FieldNode {
const MultiFunction &multi_function() const;
const CPPType &output_cpp_type(int output_index) const override;
- void foreach_field_input(FunctionRef<void(const FieldInput &)> foreach_fn) const override;
};
class FieldContext;
@@ -258,7 +265,19 @@ class FieldInput : public FieldNode {
Category category() const;
const CPPType &output_cpp_type(int output_index) const override;
- void foreach_field_input(FunctionRef<void(const FieldInput &)> foreach_fn) const override;
+};
+
+/**
+ * Keeps track of the inputs of a field.
+ */
+struct FieldInputs {
+ /** All #FieldInput nodes that a field (possibly indirectly) depends on. */
+ VectorSet<const FieldInput *> nodes;
+ /**
+ * Same as above but the inputs are deduplicated. For example, when there are two separate index
+ * input nodes, only one will show up in this list.
+ */
+ VectorSet<std::reference_wrapper<const FieldInput>> deduplicated_nodes;
};
/**
@@ -294,6 +313,9 @@ class FieldEvaluator : NonMovable, NonCopyable {
Vector<OutputPointerInfo> output_pointer_infos_;
bool is_evaluated_ = false;
+ Field<bool> selection_field_;
+ IndexMask selection_mask_;
+
public:
/** Takes #mask by pointer because the mask has to live longer than the evaluator. */
FieldEvaluator(const FieldContext &context, const IndexMask *mask)
@@ -314,6 +336,18 @@ class FieldEvaluator : NonMovable, NonCopyable {
}
/**
+ * The selection field is evaluated first to determine which indices of the other fields should
+ * be evaluated. Calling this method multiple times will just replace the previously set
+ * selection field. Only the elements selected by both this selection and the selection provided
+ * in the constructor are calculated. If no selection field is set, it is assumed that all
+ * indices passed to the constructor are selected.
+ */
+ void set_selection(Field<bool> selection)
+ {
+ selection_field_ = std::move(selection);
+ }
+
+ /**
* \param field: Field to add to the evaluator.
* \param dst: Mutable virtual array that the evaluated result for this field is be written into.
*/
@@ -384,6 +418,8 @@ class FieldEvaluator : NonMovable, NonCopyable {
return this->get_evaluated(field_index).typed<T>();
}
+ IndexMask get_evaluated_selection_as_mask();
+
/**
* Retrieve the output of an evaluated boolean field and convert it to a mask, which can be used
* to avoid calculations for unnecessary elements later on. The evaluator will own the indices in
@@ -392,6 +428,24 @@ class FieldEvaluator : NonMovable, NonCopyable {
IndexMask get_evaluated_as_mask(const int field_index);
};
+/**
+ * Evaluate fields in the given context. If possible, multiple fields should be evaluated together,
+ * because that can be more efficient when they share common sub-fields.
+ *
+ * \param scope: The resource scope that owns data that makes up the output virtual arrays. Make
+ * sure the scope is not destructed when the output virtual arrays are still used.
+ * \param fields_to_evaluate: The fields that should be evaluated together.
+ * \param mask: Determines which indices are computed. The mask may be referenced by the returned
+ * virtual arrays. So the underlying indices (if applicable) should live longer then #scope.
+ * \param context: The context that the field is evaluated in. Used to retrieve data from each
+ * #FieldInput in the field network.
+ * \param dst_varrays: If provided, the computed data will be written into those virtual arrays
+ * instead of into newly created ones. That allows making the computed data live longer than
+ * #scope and is more efficient when the data will be written into those virtual arrays
+ * later anyway.
+ * \return The computed virtual arrays for each provided field. If #dst_varrays is passed, the
+ * provided virtual arrays are returned.
+ */
Vector<GVArray> evaluate_fields(ResourceScope &scope,
Span<GFieldRef> fields_to_evaluate,
IndexMask mask,
@@ -419,13 +473,24 @@ template<typename T> Field<T> make_constant_field(T value)
return Field<T>{GField{std::move(operation), 0}};
}
+GField make_constant_field(const CPPType &type, const void *value);
+
+/**
+ * If the field depends on some input, the same field is returned.
+ * Otherwise the field is evaluated and a new field is created that just computes this constant.
+ *
+ * Making the field constant has two benefits:
+ * - The field-tree becomes a single node, which is more efficient when the field is evaluated many
+ * times.
+ * - Memory of the input fields may be freed.
+ */
GField make_field_constant_if_possible(GField field);
class IndexFieldInput final : public FieldInput {
public:
IndexFieldInput();
- static GVArray get_index_varray(IndexMask mask, ResourceScope &scope);
+ static GVArray get_index_varray(IndexMask mask);
GVArray get_varray_for_context(const FieldContext &context,
IndexMask mask,
@@ -438,11 +503,56 @@ class IndexFieldInput final : public FieldInput {
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Value or Field Class
+ *
+ * Utility class that wraps a single value and a field, to simplify accessing both of the types.
+ * \{ */
+
+template<typename T> struct ValueOrField {
+ /** Value that is used when the field is empty. */
+ T value{};
+ Field<T> field;
+
+ ValueOrField() = default;
+
+ ValueOrField(T value) : value(std::move(value))
+ {
+ }
+
+ ValueOrField(Field<T> field) : field(std::move(field))
+ {
+ }
+
+ bool is_field() const
+ {
+ return (bool)this->field;
+ }
+
+ Field<T> as_field() const
+ {
+ if (this->field) {
+ return this->field;
+ }
+ return make_constant_field(this->value);
+ }
+
+ T as_value() const
+ {
+ if (this->field) {
+ /* This returns a default value when the field is not constant. */
+ return evaluate_constant_field(this->field);
+ }
+ return this->value;
+ }
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name #FieldNode Inline Methods
* \{ */
-inline FieldNode::FieldNode(bool is_input, bool depends_on_input)
- : is_input_(is_input), depends_on_input_(depends_on_input)
+inline FieldNode::FieldNode(bool is_input) : is_input_(is_input)
{
}
@@ -458,7 +568,12 @@ inline bool FieldNode::is_operation() const
inline bool FieldNode::depends_on_input() const
{
- return depends_on_input_;
+ return field_inputs_ && !field_inputs_->nodes.is_empty();
+}
+
+inline const std::shared_ptr<const FieldInputs> &FieldNode::field_inputs() const
+{
+ return field_inputs_;
}
inline uint64_t FieldNode::hash() const
diff --git a/source/blender/functions/FN_field_cpp_type.hh b/source/blender/functions/FN_field_cpp_type.hh
index 5e6f1b5a585..940faba6d70 100644
--- a/source/blender/functions/FN_field_cpp_type.hh
+++ b/source/blender/functions/FN_field_cpp_type.hh
@@ -30,19 +30,19 @@ template<typename T> struct FieldCPPTypeParam {
class FieldCPPType : public CPPType {
private:
- const CPPType &field_type_;
+ const CPPType &base_type_;
public:
template<typename T>
FieldCPPType(FieldCPPTypeParam<Field<T>> /* unused */, StringRef debug_name)
: CPPType(CPPTypeParam<Field<T>, CPPTypeFlags::None>(), debug_name),
- field_type_(CPPType::get<T>())
+ base_type_(CPPType::get<T>())
{
}
- const CPPType &field_type() const
+ const CPPType &base_type() const
{
- return field_type_;
+ return base_type_;
}
/* Ensure that #GField and #Field<T> have the same layout, to enable casting between the two. */
@@ -60,6 +60,84 @@ class FieldCPPType : public CPPType {
}
};
+class ValueOrFieldCPPType : public CPPType {
+ private:
+ const CPPType &base_type_;
+ void (*construct_from_value_)(void *dst, const void *value);
+ void (*construct_from_field_)(void *dst, GField field);
+ const void *(*get_value_ptr_)(const void *value_or_field);
+ const GField *(*get_field_ptr_)(const void *value_or_field);
+ bool (*is_field_)(const void *value_or_field);
+ GField (*as_field_)(const void *value_or_field);
+
+ public:
+ template<typename T>
+ ValueOrFieldCPPType(FieldCPPTypeParam<ValueOrField<T>> /* unused */, StringRef debug_name)
+ : CPPType(CPPTypeParam<ValueOrField<T>, CPPTypeFlags::None>(), debug_name),
+ base_type_(CPPType::get<T>())
+ {
+ construct_from_value_ = [](void *dst, const void *value_or_field) {
+ new (dst) ValueOrField<T>(*(const T *)value_or_field);
+ };
+ construct_from_field_ = [](void *dst, GField field) {
+ new (dst) ValueOrField<T>(Field<T>(std::move(field)));
+ };
+ get_value_ptr_ = [](const void *value_or_field) {
+ return (const void *)&((ValueOrField<T> *)value_or_field)->value;
+ };
+ get_field_ptr_ = [](const void *value_or_field) -> const GField * {
+ return &((ValueOrField<T> *)value_or_field)->field;
+ };
+ is_field_ = [](const void *value_or_field) {
+ return ((ValueOrField<T> *)value_or_field)->is_field();
+ };
+ as_field_ = [](const void *value_or_field) -> GField {
+ return ((ValueOrField<T> *)value_or_field)->as_field();
+ };
+ }
+
+ const CPPType &base_type() const
+ {
+ return base_type_;
+ }
+
+ void construct_from_value(void *dst, const void *value) const
+ {
+ construct_from_value_(dst, value);
+ }
+
+ void construct_from_field(void *dst, GField field) const
+ {
+ construct_from_field_(dst, field);
+ }
+
+ const void *get_value_ptr(const void *value_or_field) const
+ {
+ return get_value_ptr_(value_or_field);
+ }
+
+ void *get_value_ptr(void *value_or_field) const
+ {
+ /* Use `const_cast` to avoid duplicating the callback for the non-const case. */
+ return const_cast<void *>(get_value_ptr_(value_or_field));
+ }
+
+ const GField *get_field_ptr(const void *value_or_field) const
+ {
+ return get_field_ptr_(value_or_field);
+ }
+
+ bool is_field(const void *value_or_field) const
+ {
+ return is_field_(value_or_field);
+ }
+
+ GField as_field(const void *value_or_field) const
+ {
+ return as_field_(value_or_field);
+ }
+};
+
} // namespace blender::fn
#define MAKE_FIELD_CPP_TYPE(DEBUG_NAME, FIELD_TYPE) \
@@ -69,4 +147,13 @@ class FieldCPPType : public CPPType {
static blender::fn::FieldCPPType cpp_type{ \
blender::fn::FieldCPPTypeParam<blender::fn::Field<FIELD_TYPE>>(), STRINGIFY(DEBUG_NAME)}; \
return cpp_type; \
+ } \
+ template<> \
+ const blender::fn::CPPType & \
+ blender::fn::CPPType::get_impl<blender::fn::ValueOrField<FIELD_TYPE>>() \
+ { \
+ static blender::fn::ValueOrFieldCPPType cpp_type{ \
+ blender::fn::FieldCPPTypeParam<blender::fn::ValueOrField<FIELD_TYPE>>(), \
+ STRINGIFY(DEBUG_NAME##OrValue)}; \
+ return cpp_type; \
}
diff --git a/source/blender/functions/FN_generic_span.hh b/source/blender/functions/FN_generic_span.hh
index e2c49697ba9..6f0147b7fb3 100644
--- a/source/blender/functions/FN_generic_span.hh
+++ b/source/blender/functions/FN_generic_span.hh
@@ -93,6 +93,11 @@ class GSpan {
const int64_t new_size = std::max<int64_t>(0, std::min(size, size_ - start));
return GSpan(*type_, POINTER_OFFSET(data_, type_->size() * start), new_size);
}
+
+ GSpan slice(const IndexRange range) const
+ {
+ return this->slice(range.start(), range.size());
+ }
};
/**
@@ -169,6 +174,11 @@ class GMutableSpan {
const int64_t new_size = std::max<int64_t>(0, std::min(size, size_ - start));
return GMutableSpan(*type_, POINTER_OFFSET(data_, type_->size() * start), new_size);
}
+
+ GMutableSpan slice(IndexRange range) const
+ {
+ return this->slice(range.start(), range.size());
+ }
};
} // namespace blender::fn
diff --git a/source/blender/functions/FN_generic_virtual_array.hh b/source/blender/functions/FN_generic_virtual_array.hh
index b822f3a7c33..fc8612d6f87 100644
--- a/source/blender/functions/FN_generic_virtual_array.hh
+++ b/source/blender/functions/FN_generic_virtual_array.hh
@@ -148,14 +148,37 @@ class GVArrayCommon {
void materialize_to_uninitialized(void *dst) const;
void materialize_to_uninitialized(const IndexMask mask, void *dst) const;
+ /**
+ * Returns true when the virtual array is stored as a span internally.
+ */
bool is_span() const;
+ /**
+ * Returns the internally used span of the virtual array. This invokes undefined behavior is the
+ * virtual array is not stored as a span internally.
+ */
GSpan get_internal_span() const;
+ /**
+ * Returns true when the virtual array returns the same value for every index.
+ */
bool is_single() const;
+ /**
+ * Copies the value that is used for every element into `r_value`, which is expected to point to
+ * initialized memory. This invokes undefined behavior if the virtual array would not return the
+ * same value for every index.
+ */
void get_internal_single(void *r_value) const;
+ /**
+ * Same as `get_internal_single`, but `r_value` points to initialized memory.
+ */
void get_internal_single_to_uninitialized(void *r_value) const;
void get(const int64_t index, void *r_value) const;
+ /**
+ * Returns a copy of the value at the given index. Usually a typed virtual array should
+ * be used instead, but sometimes this is simpler when only a few indices are needed.
+ */
+ template<typename T> T get(const int64_t index) const;
void get_to_uninitialized(const int64_t index, void *r_value) const;
};
@@ -226,6 +249,9 @@ class GVMutableArray : public GVArrayCommon {
void set_by_relocate(const int64_t index, void *value);
void fill(const void *value);
+ /**
+ * Copy the values from the source buffer to all elements in the virtual array.
+ */
void set_all(const void *src);
GVMutableArrayImpl *get_implementation() const;
@@ -555,37 +581,19 @@ template<typename T> class VMutableArrayImpl_For_GVMutableArray : public VMutabl
/** \} */
/* -------------------------------------------------------------------- */
-/** \name #GVArrayImpl_For_GSpan and #GVMutableArrayImpl_For_GMutableSpan.
+/** \name #GVArrayImpl_For_GSpan.
* \{ */
-class GVArrayImpl_For_GSpan : public GVArrayImpl {
- protected:
- const void *data_ = nullptr;
- const int64_t element_size_;
-
- public:
- GVArrayImpl_For_GSpan(const GSpan span);
-
- protected:
- GVArrayImpl_For_GSpan(const CPPType &type, const int64_t size);
-
- void get(const int64_t index, void *r_value) const override;
- void get_to_uninitialized(const int64_t index, void *r_value) const override;
-
- bool is_span() const override;
- GSpan get_internal_span() const override;
-};
-
-class GVMutableArrayImpl_For_GMutableSpan : public GVMutableArrayImpl {
+class GVArrayImpl_For_GSpan : public GVMutableArrayImpl {
protected:
void *data_ = nullptr;
const int64_t element_size_;
public:
- GVMutableArrayImpl_For_GMutableSpan(const GMutableSpan span);
+ GVArrayImpl_For_GSpan(const GMutableSpan span);
protected:
- GVMutableArrayImpl_For_GMutableSpan(const CPPType &type, const int64_t size);
+ GVArrayImpl_For_GSpan(const CPPType &type, const int64_t size);
public:
void get(const int64_t index, void *r_value) const override;
@@ -688,6 +696,16 @@ inline void GVArrayCommon::get(const int64_t index, void *r_value) const
impl_->get(index, r_value);
}
+template<typename T> inline T GVArrayCommon::get(const int64_t index) const
+{
+ BLI_assert(index >= 0);
+ BLI_assert(index < this->size());
+ BLI_assert(this->type().is<T>());
+ T value{};
+ impl_->get(index, &value);
+ return value;
+}
+
/* Same as `get`, but `r_value` is expected to point to uninitialized memory. */
inline void GVArrayCommon::get_to_uninitialized(const int64_t index, void *r_value) const
{
diff --git a/source/blender/functions/FN_multi_function.hh b/source/blender/functions/FN_multi_function.hh
index c57f6cf574e..1e36d87668a 100644
--- a/source/blender/functions/FN_multi_function.hh
+++ b/source/blender/functions/FN_multi_function.hh
@@ -60,6 +60,13 @@ class MultiFunction {
{
}
+ /**
+ * The result is the same as using #call directly but this method has some additional features.
+ * - Automatic multi-threading when possible and appropriate.
+ * - Automatic index mask offsetting to avoid large temporary intermediate arrays that are mostly
+ * unused.
+ */
+ void call_auto(IndexMask mask, MFParams params, MFContext context) const;
virtual void call(IndexMask mask, MFParams params, MFContext context) const = 0;
virtual uint64_t hash() const
@@ -97,6 +104,8 @@ class MultiFunction {
return signature_ref_->function_name;
}
+ virtual std::string debug_name() const;
+
bool depends_on_context() const
{
return signature_ref_->depends_on_context;
@@ -108,6 +117,31 @@ class MultiFunction {
return *signature_ref_;
}
+ /**
+ * Information about how the multi-function behaves that help a caller to execute it efficiently.
+ */
+ struct ExecutionHints {
+ /**
+ * Suggested minimum workload under which multi-threading does not really help.
+ * This should be lowered when the multi-function is doing something computationally expensive.
+ */
+ int64_t min_grain_size = 10000;
+ /**
+ * Indicates that the multi-function will allocate an array large enough to hold all indices
+ * passed in as mask. This tells the caller that it would be preferable to pass in smaller
+ * indices. Also maybe the full mask should be split up into smaller segments to decrease peak
+ * memory usage.
+ */
+ bool allocates_array = false;
+ /**
+ * Tells the caller that every execution takes about the same time. This helps making a more
+ * educated guess about a good grain size.
+ */
+ bool uniform_execution_time = true;
+ };
+
+ ExecutionHints execution_hints() const;
+
protected:
/* Make the function use the given signature. This should be called once in the constructor of
* child classes. No copy of the signature is made, so the caller has to make sure that the
@@ -119,6 +153,8 @@ class MultiFunction {
BLI_assert(signature != nullptr);
signature_ref_ = signature;
}
+
+ virtual ExecutionHints get_execution_hints() const;
};
inline MFParamsBuilder::MFParamsBuilder(const MultiFunction &fn, int64_t mask_size)
diff --git a/source/blender/functions/FN_multi_function_builder.hh b/source/blender/functions/FN_multi_function_builder.hh
index 0ce05cbca30..eaf9e5ce70f 100644
--- a/source/blender/functions/FN_multi_function_builder.hh
+++ b/source/blender/functions/FN_multi_function_builder.hh
@@ -43,7 +43,7 @@ template<typename In1, typename Out1> class CustomMF_SI_SO : public MultiFunctio
MFSignature signature_;
public:
- CustomMF_SI_SO(StringRef name, FunctionT function) : function_(std::move(function))
+ CustomMF_SI_SO(const char *name, FunctionT function) : function_(std::move(function))
{
MFSignatureBuilder signature{name};
signature.single_input<In1>("In1");
@@ -53,7 +53,7 @@ template<typename In1, typename Out1> class CustomMF_SI_SO : public MultiFunctio
}
template<typename ElementFuncT>
- CustomMF_SI_SO(StringRef name, ElementFuncT element_fn)
+ CustomMF_SI_SO(const char *name, ElementFuncT element_fn)
: CustomMF_SI_SO(name, CustomMF_SI_SO::create_function(element_fn))
{
}
@@ -92,7 +92,7 @@ class CustomMF_SI_SI_SO : public MultiFunction {
MFSignature signature_;
public:
- CustomMF_SI_SI_SO(StringRef name, FunctionT function) : function_(std::move(function))
+ CustomMF_SI_SI_SO(const char *name, FunctionT function) : function_(std::move(function))
{
MFSignatureBuilder signature{name};
signature.single_input<In1>("In1");
@@ -103,7 +103,7 @@ class CustomMF_SI_SI_SO : public MultiFunction {
}
template<typename ElementFuncT>
- CustomMF_SI_SI_SO(StringRef name, ElementFuncT element_fn)
+ CustomMF_SI_SI_SO(const char *name, ElementFuncT element_fn)
: CustomMF_SI_SI_SO(name, CustomMF_SI_SI_SO::create_function(element_fn))
{
}
@@ -150,7 +150,7 @@ class CustomMF_SI_SI_SI_SO : public MultiFunction {
MFSignature signature_;
public:
- CustomMF_SI_SI_SI_SO(StringRef name, FunctionT function) : function_(std::move(function))
+ CustomMF_SI_SI_SI_SO(const char *name, FunctionT function) : function_(std::move(function))
{
MFSignatureBuilder signature{name};
signature.single_input<In1>("In1");
@@ -162,7 +162,7 @@ class CustomMF_SI_SI_SI_SO : public MultiFunction {
}
template<typename ElementFuncT>
- CustomMF_SI_SI_SI_SO(StringRef name, ElementFuncT element_fn)
+ CustomMF_SI_SI_SI_SO(const char *name, ElementFuncT element_fn)
: CustomMF_SI_SI_SI_SO(name, CustomMF_SI_SI_SI_SO::create_function(element_fn))
{
}
@@ -211,7 +211,7 @@ class CustomMF_SI_SI_SI_SI_SO : public MultiFunction {
MFSignature signature_;
public:
- CustomMF_SI_SI_SI_SI_SO(StringRef name, FunctionT function) : function_(std::move(function))
+ CustomMF_SI_SI_SI_SI_SO(const char *name, FunctionT function) : function_(std::move(function))
{
MFSignatureBuilder signature{name};
signature.single_input<In1>("In1");
@@ -224,7 +224,7 @@ class CustomMF_SI_SI_SI_SI_SO : public MultiFunction {
}
template<typename ElementFuncT>
- CustomMF_SI_SI_SI_SI_SO(StringRef name, ElementFuncT element_fn)
+ CustomMF_SI_SI_SI_SI_SO(const char *name, ElementFuncT element_fn)
: CustomMF_SI_SI_SI_SI_SO(name, CustomMF_SI_SI_SI_SI_SO::create_function(element_fn))
{
}
@@ -265,7 +265,7 @@ template<typename Mut1> class CustomMF_SM : public MultiFunction {
MFSignature signature_;
public:
- CustomMF_SM(StringRef name, FunctionT function) : function_(std::move(function))
+ CustomMF_SM(const char *name, FunctionT function) : function_(std::move(function))
{
MFSignatureBuilder signature{name};
signature.single_mutable<Mut1>("Mut1");
@@ -274,7 +274,7 @@ template<typename Mut1> class CustomMF_SM : public MultiFunction {
}
template<typename ElementFuncT>
- CustomMF_SM(StringRef name, ElementFuncT element_fn)
+ CustomMF_SM(const char *name, ElementFuncT element_fn)
: CustomMF_SM(name, CustomMF_SM::create_function(element_fn))
{
}
@@ -306,8 +306,8 @@ template<typename From, typename To> class CustomMF_Convert : public MultiFuncti
static MFSignature create_signature()
{
- std::string name = CPPType::get<From>().name() + " to " + CPPType::get<To>().name();
- MFSignatureBuilder signature{std::move(name)};
+ static std::string name = CPPType::get<From>().name() + " to " + CPPType::get<To>().name();
+ MFSignatureBuilder signature{name.c_str()};
signature.single_input<From>("Input");
signature.single_output<To>("Output");
return signature.build();
@@ -372,9 +372,7 @@ template<typename T> class CustomMF_Constant : public MultiFunction {
template<typename U> CustomMF_Constant(U &&value) : value_(std::forward<U>(value))
{
MFSignatureBuilder signature{"Constant"};
- std::stringstream ss;
- ss << value_;
- signature.single_output<T>(ss.str());
+ signature.single_output<T>("Value");
signature_ = signature.build();
this->set_signature(&signature_);
}
@@ -414,9 +412,7 @@ class CustomMF_DefaultOutput : public MultiFunction {
MFSignature signature_;
public:
- CustomMF_DefaultOutput(StringRef name,
- Span<MFDataType> input_types,
- Span<MFDataType> output_types);
+ CustomMF_DefaultOutput(Span<MFDataType> input_types, Span<MFDataType> output_types);
void call(IndexMask mask, MFParams params, MFContext context) const override;
};
@@ -425,7 +421,7 @@ class CustomMF_GenericCopy : public MultiFunction {
MFSignature signature_;
public:
- CustomMF_GenericCopy(StringRef name, MFDataType data_type);
+ CustomMF_GenericCopy(MFDataType data_type);
void call(IndexMask mask, MFParams params, MFContext context) const override;
};
diff --git a/source/blender/functions/FN_multi_function_params.hh b/source/blender/functions/FN_multi_function_params.hh
index 5c7e75230f3..f4ddc4f2881 100644
--- a/source/blender/functions/FN_multi_function_params.hh
+++ b/source/blender/functions/FN_multi_function_params.hh
@@ -25,6 +25,8 @@
* the function. `MFParams` is then used inside the called function to access the parameters.
*/
+#include <mutex>
+
#include "BLI_resource_scope.hh"
#include "FN_generic_pointer.hh"
@@ -45,6 +47,9 @@ class MFParamsBuilder {
Vector<const GVVectorArray *> virtual_vector_arrays_;
Vector<GVectorArray *> vector_arrays_;
+ std::mutex mutex_;
+ Vector<std::pair<int, GMutableSpan>> dummy_output_spans_;
+
friend class MFParams;
MFParamsBuilder(const MFSignature &signature, const IndexMask mask)
@@ -62,8 +67,8 @@ class MFParamsBuilder {
template<typename T> void add_readonly_single_input_value(T value, StringRef expected_name = "")
{
- T *value_ptr = &scope_.add_value<T>(std::move(value));
- this->add_readonly_single_input(value_ptr, expected_name);
+ this->add_readonly_single_input(VArray<T>::ForSingle(std::move(value), min_array_size_),
+ expected_name);
}
template<typename T> void add_readonly_single_input(const T *value, StringRef expected_name = "")
{
@@ -254,20 +259,12 @@ class MFParams {
this->assert_correct_param(param_index, name, MFParamType::SingleOutput);
int data_index = builder_->signature_->data_index(param_index);
GMutableSpan span = builder_->mutable_spans_[data_index];
- if (span.is_empty()) {
- /* The output is ignored by the caller, but the multi-function does not handle this case. So
- * create a temporary buffer that the multi-function can write to. */
- const CPPType &type = span.type();
- void *buffer = builder_->scope_.linear_allocator().allocate(
- builder_->min_array_size_ * type.size(), type.alignment());
- if (!type.is_trivially_destructible()) {
- /* Make sure the temporary elements will be destructed in the end. */
- builder_->scope_.add_destruct_call(
- [&type, buffer, mask = builder_->mask_]() { type.destruct_indices(buffer, mask); });
- }
- span = GMutableSpan{type, buffer, builder_->min_array_size_};
+ if (!span.is_empty()) {
+ return span;
}
- return span;
+ /* The output is ignored by the caller, but the multi-function does not handle this case. So
+ * create a temporary buffer that the multi-function can write to. */
+ return this->ensure_dummy_single_output(data_index);
}
/**
@@ -356,6 +353,8 @@ class MFParams {
}
#endif
}
+
+ GMutableSpan ensure_dummy_single_output(int data_index);
};
} // namespace blender::fn
diff --git a/source/blender/functions/FN_multi_function_procedure_executor.hh b/source/blender/functions/FN_multi_function_procedure_executor.hh
index 9c8b59739b8..409a031e7ed 100644
--- a/source/blender/functions/FN_multi_function_procedure_executor.hh
+++ b/source/blender/functions/FN_multi_function_procedure_executor.hh
@@ -31,9 +31,12 @@ class MFProcedureExecutor : public MultiFunction {
const MFProcedure &procedure_;
public:
- MFProcedureExecutor(std::string name, const MFProcedure &procedure);
+ MFProcedureExecutor(const MFProcedure &procedure);
void call(IndexMask mask, MFParams params, MFContext context) const override;
+
+ private:
+ ExecutionHints get_execution_hints() const override;
};
} // namespace blender::fn
diff --git a/source/blender/functions/FN_multi_function_procedure_optimization.hh b/source/blender/functions/FN_multi_function_procedure_optimization.hh
new file mode 100644
index 00000000000..e5ffc12b241
--- /dev/null
+++ b/source/blender/functions/FN_multi_function_procedure_optimization.hh
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/** \file
+ * \ingroup fn
+ *
+ * A #MFProcedure optimization pass takes an existing procedure and changes it in a way that
+ * improves its performance when executed.
+ *
+ * Oftentimes it would also be possible to implement a specific optimization directly during
+ * construction of the initial #MFProcedure. There is a trade-off between doing that or just
+ * building a "simple" procedure and then optimizing it uses separate optimization passes.
+ * - Doing optimizations directly during construction is typically faster than doing it as a
+ * separate pass. However, it would be much harder to turn the optimization off when it is not
+ * necessary, making the construction potentially slower in those cases.
+ * - Doing optimizations directly would also make code more complex, because it mixes the logic
+ * that generates the procedure from some other data with optimization decisions.
+ * - Having a separate pass allows us to use it in different places when necessary.
+ * - Having a separate pass allows us to enable and disable it easily to better understand its
+ * impact on performance.
+ */
+
+#include "FN_multi_function_procedure.hh"
+
+namespace blender::fn::procedure_optimization {
+
+/**
+ * When generating a procedure, destruct instructions (#MFDestructInstruction) have to be inserted
+ * for all variables that are not outputs. Often the simplest approach is to add these instructions
+ * at the very end. However, when the procedure is executed this is not optimal, because many more
+ * variables are initialized at the same time than necessary. This inhibits the reuse of memory
+ * buffers which decreases performance and increases memory use.
+ *
+ * This optimization pass moves destruct instructions up in the procedure. The goal is to destruct
+ * each variable right after its last use.
+ *
+ * For simplicity, and because this is the most common use case, this optimization currently only
+ * works on a single chain of instructions. Destruct instructions are not moved across branches.
+ *
+ * \param procedure The procedure that should be optimized.
+ * \param block_end_instr The instruction that points to the last instruction within a linear chain
+ * of instructions. The algorithm moves instructions backward starting at this instruction.
+ */
+void move_destructs_up(MFProcedure &procedure, MFInstruction &block_end_instr);
+
+} // namespace blender::fn::procedure_optimization
diff --git a/source/blender/functions/FN_multi_function_signature.hh b/source/blender/functions/FN_multi_function_signature.hh
index d05948cc645..3c991bc9c56 100644
--- a/source/blender/functions/FN_multi_function_signature.hh
+++ b/source/blender/functions/FN_multi_function_signature.hh
@@ -30,8 +30,15 @@
namespace blender::fn {
struct MFSignature {
- std::string function_name;
- Vector<std::string> param_names;
+ /**
+ * The name should be statically allocated so that it lives longer than this signature. This is
+ * used instead of an #std::string because of the overhead when many functions are created.
+ * If the name of the function has to be more dynamic for debugging purposes, override
+ * #MultiFunction::debug_name() instead. Then the dynamic name will only be computed when it is
+ * actually needed.
+ */
+ const char *function_name;
+ Vector<const char *> param_names;
Vector<MFParamType> param_types;
Vector<int> param_data_indices;
bool depends_on_context = false;
@@ -51,9 +58,9 @@ class MFSignatureBuilder {
int vector_array_count_ = 0;
public:
- MFSignatureBuilder(std::string function_name)
+ MFSignatureBuilder(const char *function_name)
{
- signature_.function_name = std::move(function_name);
+ signature_.function_name = function_name;
}
MFSignature build() const
@@ -63,23 +70,23 @@ class MFSignatureBuilder {
/* Input Parameter Types */
- template<typename T> void single_input(StringRef name)
+ template<typename T> void single_input(const char *name)
{
this->single_input(name, CPPType::get<T>());
}
- void single_input(StringRef name, const CPPType &type)
+ void single_input(const char *name, const CPPType &type)
{
this->input(name, MFDataType::ForSingle(type));
}
- template<typename T> void vector_input(StringRef name)
+ template<typename T> void vector_input(const char *name)
{
this->vector_input(name, CPPType::get<T>());
}
- void vector_input(StringRef name, const CPPType &base_type)
+ void vector_input(const char *name, const CPPType &base_type)
{
this->input(name, MFDataType::ForVector(base_type));
}
- void input(StringRef name, MFDataType data_type)
+ void input(const char *name, MFDataType data_type)
{
signature_.param_names.append(name);
signature_.param_types.append(MFParamType(MFParamType::Input, data_type));
@@ -96,23 +103,23 @@ class MFSignatureBuilder {
/* Output Parameter Types */
- template<typename T> void single_output(StringRef name)
+ template<typename T> void single_output(const char *name)
{
this->single_output(name, CPPType::get<T>());
}
- void single_output(StringRef name, const CPPType &type)
+ void single_output(const char *name, const CPPType &type)
{
this->output(name, MFDataType::ForSingle(type));
}
- template<typename T> void vector_output(StringRef name)
+ template<typename T> void vector_output(const char *name)
{
this->vector_output(name, CPPType::get<T>());
}
- void vector_output(StringRef name, const CPPType &base_type)
+ void vector_output(const char *name, const CPPType &base_type)
{
this->output(name, MFDataType::ForVector(base_type));
}
- void output(StringRef name, MFDataType data_type)
+ void output(const char *name, MFDataType data_type)
{
signature_.param_names.append(name);
signature_.param_types.append(MFParamType(MFParamType::Output, data_type));
@@ -129,23 +136,23 @@ class MFSignatureBuilder {
/* Mutable Parameter Types */
- template<typename T> void single_mutable(StringRef name)
+ template<typename T> void single_mutable(const char *name)
{
this->single_mutable(name, CPPType::get<T>());
}
- void single_mutable(StringRef name, const CPPType &type)
+ void single_mutable(const char *name, const CPPType &type)
{
this->mutable_(name, MFDataType::ForSingle(type));
}
- template<typename T> void vector_mutable(StringRef name)
+ template<typename T> void vector_mutable(const char *name)
{
this->vector_mutable(name, CPPType::get<T>());
}
- void vector_mutable(StringRef name, const CPPType &base_type)
+ void vector_mutable(const char *name, const CPPType &base_type)
{
this->mutable_(name, MFDataType::ForVector(base_type));
}
- void mutable_(StringRef name, MFDataType data_type)
+ void mutable_(const char *name, MFDataType data_type)
{
signature_.param_names.append(name);
signature_.param_types.append(MFParamType(MFParamType::Mutable, data_type));
@@ -160,7 +167,7 @@ class MFSignatureBuilder {
}
}
- void add(StringRef name, const MFParamType &param_type)
+ void add(const char *name, const MFParamType &param_type)
{
switch (param_type.interface_type()) {
case MFParamType::Input:
diff --git a/source/blender/functions/intern/field.cc b/source/blender/functions/intern/field.cc
index 68a8446e6ae..604e5c6d13f 100644
--- a/source/blender/functions/intern/field.cc
+++ b/source/blender/functions/intern/field.cc
@@ -21,7 +21,10 @@
#include "BLI_vector_set.hh"
#include "FN_field.hh"
-#include "FN_multi_function_parallel.hh"
+#include "FN_multi_function_procedure.hh"
+#include "FN_multi_function_procedure_builder.hh"
+#include "FN_multi_function_procedure_executor.hh"
+#include "FN_multi_function_procedure_optimization.hh"
namespace blender::fn {
@@ -237,8 +240,7 @@ static void build_multi_function_procedure_for_fields(MFProcedure &procedure,
if (!already_output_variables.add(variable)) {
/* One variable can be output at most once. To output the same value twice, we have to make
* a copy first. */
- const MultiFunction &copy_fn = scope.construct<CustomMF_GenericCopy>("copy",
- variable->data_type());
+ const MultiFunction &copy_fn = scope.construct<CustomMF_GenericCopy>(variable->data_type());
variable = builder.add_call<1>(copy_fn, {variable})[0];
}
builder.add_output_parameter(*variable);
@@ -253,30 +255,14 @@ static void build_multi_function_procedure_for_fields(MFProcedure &procedure,
builder.add_destruct(*variable);
}
- builder.add_return();
+ MFReturnInstruction &return_instr = builder.add_return();
+
+ procedure_optimization::move_destructs_up(procedure, return_instr);
// std::cout << procedure.to_dot() << "\n";
BLI_assert(procedure.validate());
}
-/**
- * Evaluate fields in the given context. If possible, multiple fields should be evaluated together,
- * because that can be more efficient when they share common sub-fields.
- *
- * \param scope: The resource scope that owns data that makes up the output virtual arrays. Make
- * sure the scope is not destructed when the output virtual arrays are still used.
- * \param fields_to_evaluate: The fields that should be evaluated together.
- * \param mask: Determines which indices are computed. The mask may be referenced by the returned
- * virtual arrays. So the underlying indices (if applicable) should live longer then #scope.
- * \param context: The context that the field is evaluated in. Used to retrieve data from each
- * #FieldInput in the field network.
- * \param dst_varrays: If provided, the computed data will be written into those virtual arrays
- * instead of into newly created ones. That allows making the computed data live longer than
- * #scope and is more efficient when the data will be written into those virtual arrays
- * later anyway.
- * \return The computed virtual arrays for each provided field. If #dst_varrays is passed, the
- * provided virtual arrays are returned.
- */
Vector<GVArray> evaluate_fields(ResourceScope &scope,
Span<GFieldRef> fields_to_evaluate,
IndexMask mask,
@@ -358,14 +344,9 @@ Vector<GVArray> evaluate_fields(ResourceScope &scope,
MFProcedure procedure;
build_multi_function_procedure_for_fields(
procedure, scope, field_tree_info, varying_fields_to_evaluate);
- MFProcedureExecutor procedure_executor{"Procedure", procedure};
- /* Add multi threading capabilities to the field evaluation. */
- const int grain_size = 10000;
- fn::ParallelMultiFunction parallel_procedure_executor{procedure_executor, grain_size};
- /* Utility variable to make easy to switch the executor. */
- const MultiFunction &executor_fn = parallel_procedure_executor;
-
- MFParamsBuilder mf_params{executor_fn, &mask};
+ MFProcedureExecutor procedure_executor{procedure};
+
+ MFParamsBuilder mf_params{procedure_executor, &mask};
MFContextBuilder mf_context;
/* Provide inputs to the procedure executor. */
@@ -406,7 +387,7 @@ Vector<GVArray> evaluate_fields(ResourceScope &scope,
mf_params.add_uninitialized_single_output(span);
}
- executor_fn.call(mask, mf_params, mf_context);
+ procedure_executor.call_auto(mask, mf_params, mf_context);
}
/* Evaluate constant fields if necessary. */
@@ -415,7 +396,7 @@ Vector<GVArray> evaluate_fields(ResourceScope &scope,
MFProcedure procedure;
build_multi_function_procedure_for_fields(
procedure, scope, field_tree_info, constant_fields_to_evaluate);
- MFProcedureExecutor procedure_executor{"Procedure", procedure};
+ MFProcedureExecutor procedure_executor{procedure};
MFParamsBuilder mf_params{procedure_executor, 1};
MFContextBuilder mf_context;
@@ -495,15 +476,6 @@ void evaluate_constant_field(const GField &field, void *r_value)
varrays[0].get_to_uninitialized(0, r_value);
}
-/**
- * If the field depends on some input, the same field is returned.
- * Otherwise the field is evaluated and a new field is created that just computes this constant.
- *
- * Making the field constant has two benefits:
- * - The field-tree becomes a single node, which is more efficient when the field is evaluated many
- * times.
- * - Memory of the input fields may be freed.
- */
GField make_field_constant_if_possible(GField field)
{
if (field.node().depends_on_input()) {
@@ -512,10 +484,16 @@ GField make_field_constant_if_possible(GField field)
const CPPType &type = field.cpp_type();
BUFFER_FOR_CPP_TYPE_VALUE(type, buffer);
evaluate_constant_field(field, buffer);
- auto constant_fn = std::make_unique<CustomMF_GenericConstant>(type, buffer, true);
+ GField new_field = make_constant_field(type, buffer);
type.destruct(buffer);
+ return new_field;
+}
+
+GField make_constant_field(const CPPType &type, const void *value)
+{
+ auto constant_fn = std::make_unique<CustomMF_GenericConstant>(type, value, true);
auto operation = std::make_shared<FieldOperation>(std::move(constant_fn));
- return GField{operation, 0};
+ return GField{std::move(operation), 0};
}
GVArray FieldContext::get_varray_for_input(const FieldInput &field_input,
@@ -532,7 +510,7 @@ IndexFieldInput::IndexFieldInput() : FieldInput(CPPType::get<int>(), "Index")
category_ = Category::Generated;
}
-GVArray IndexFieldInput::get_index_varray(IndexMask mask, ResourceScope &UNUSED(scope))
+GVArray IndexFieldInput::get_index_varray(IndexMask mask)
{
auto index_func = [](int i) { return i; };
return VArray<int>::ForFunc(mask.min_array_size(), index_func);
@@ -540,10 +518,10 @@ GVArray IndexFieldInput::get_index_varray(IndexMask mask, ResourceScope &UNUSED(
GVArray IndexFieldInput::get_varray_for_context(const fn::FieldContext &UNUSED(context),
IndexMask mask,
- ResourceScope &scope) const
+ ResourceScope &UNUSED(scope)) const
{
/* TODO: Investigate a similar method to IndexRange::as_span() */
- return get_index_varray(mask, scope);
+ return get_index_varray(mask);
}
uint64_t IndexFieldInput::hash() const
@@ -568,28 +546,65 @@ FieldOperation::FieldOperation(std::shared_ptr<const MultiFunction> function,
owned_function_ = std::move(function);
}
-static bool any_field_depends_on_input(Span<GField> fields)
+/**
+ * Returns the field inputs used by all the provided fields.
+ * This tries to reuse an existing #FieldInputs whenever possible to avoid copying it.
+ */
+static std::shared_ptr<const FieldInputs> combine_field_inputs(Span<GField> fields)
{
+ /* The #FieldInputs that we try to reuse if possible. */
+ const std::shared_ptr<const FieldInputs> *field_inputs_candidate = nullptr;
for (const GField &field : fields) {
- if (field.node().depends_on_input()) {
- return true;
+ const std::shared_ptr<const FieldInputs> &field_inputs = field.node().field_inputs();
+ /* Only try to reuse non-empty #FieldInputs. */
+ if (field_inputs && !field_inputs->nodes.is_empty()) {
+ if (field_inputs_candidate == nullptr) {
+ field_inputs_candidate = &field_inputs;
+ }
+ else if ((*field_inputs_candidate)->nodes.size() < field_inputs->nodes.size()) {
+ /* Always try to reuse the #FieldInputs that has the most nodes already. */
+ field_inputs_candidate = &field_inputs;
+ }
+ }
+ }
+ if (field_inputs_candidate == nullptr) {
+ /* None of the field depends on an input. */
+ return {};
+ }
+ /* Check if all inputs are in the candidate. */
+ Vector<const FieldInput *> inputs_not_in_candidate;
+ for (const GField &field : fields) {
+ const std::shared_ptr<const FieldInputs> &field_inputs = field.node().field_inputs();
+ if (!field_inputs) {
+ continue;
+ }
+ if (&field_inputs == field_inputs_candidate) {
+ continue;
}
+ for (const FieldInput *field_input : field_inputs->nodes) {
+ if (!(*field_inputs_candidate)->nodes.contains(field_input)) {
+ inputs_not_in_candidate.append(field_input);
+ }
+ }
+ }
+ if (inputs_not_in_candidate.is_empty()) {
+ /* The existing #FieldInputs can be reused, because no other field has additional inputs. */
+ return *field_inputs_candidate;
}
- return false;
+ /* Create new #FieldInputs that contains all of the inputs that the fields depend on. */
+ std::shared_ptr<FieldInputs> new_field_inputs = std::make_shared<FieldInputs>(
+ **field_inputs_candidate);
+ for (const FieldInput *field_input : inputs_not_in_candidate) {
+ new_field_inputs->nodes.add(field_input);
+ new_field_inputs->deduplicated_nodes.add(*field_input);
+ }
+ return new_field_inputs;
}
FieldOperation::FieldOperation(const MultiFunction &function, Vector<GField> inputs)
- : FieldNode(false, any_field_depends_on_input(inputs)),
- function_(&function),
- inputs_(std::move(inputs))
+ : FieldNode(false), function_(&function), inputs_(std::move(inputs))
{
-}
-
-void FieldOperation::foreach_field_input(FunctionRef<void(const FieldInput &)> foreach_fn) const
-{
- for (const GField &field : inputs_) {
- field.node().foreach_field_input(foreach_fn);
- }
+ field_inputs_ = combine_field_inputs(inputs_);
}
/* --------------------------------------------------------------------
@@ -597,20 +612,19 @@ void FieldOperation::foreach_field_input(FunctionRef<void(const FieldInput &)> f
*/
FieldInput::FieldInput(const CPPType &type, std::string debug_name)
- : FieldNode(true, true), type_(&type), debug_name_(std::move(debug_name))
-{
-}
-
-void FieldInput::foreach_field_input(FunctionRef<void(const FieldInput &)> foreach_fn) const
+ : FieldNode(true), type_(&type), debug_name_(std::move(debug_name))
{
- foreach_fn(*this);
+ std::shared_ptr<FieldInputs> field_inputs = std::make_shared<FieldInputs>();
+ field_inputs->nodes.add_new(this);
+ field_inputs->deduplicated_nodes.add_new(*this);
+ field_inputs_ = std::move(field_inputs);
}
/* --------------------------------------------------------------------
* FieldEvaluator.
*/
-static Vector<int64_t> indices_from_selection(const VArray<bool> &selection)
+static Vector<int64_t> indices_from_selection(IndexMask mask, const VArray<bool> &selection)
{
/* If the selection is just a single value, it's best to avoid calling this
* function when constructing an IndexMask and use an IndexRange instead. */
@@ -619,14 +633,14 @@ static Vector<int64_t> indices_from_selection(const VArray<bool> &selection)
Vector<int64_t> indices;
if (selection.is_span()) {
Span<bool> span = selection.get_internal_span();
- for (const int64_t i : span.index_range()) {
+ for (const int64_t i : mask) {
if (span[i]) {
indices.append(i);
}
}
}
else {
- for (const int i : selection.index_range()) {
+ for (const int i : mask) {
if (selection[i]) {
indices.append(i);
}
@@ -667,14 +681,36 @@ int FieldEvaluator::add(GField field)
return field_index;
}
+static IndexMask evaluate_selection(const Field<bool> &selection_field,
+ const FieldContext &context,
+ IndexMask full_mask,
+ ResourceScope &scope)
+{
+ if (selection_field) {
+ VArray<bool> selection =
+ evaluate_fields(scope, {selection_field}, full_mask, context)[0].typed<bool>();
+ if (selection.is_single()) {
+ if (selection.get_internal_single()) {
+ return full_mask;
+ }
+ return IndexRange(0);
+ }
+ return scope.add_value(indices_from_selection(full_mask, selection)).as_span();
+ }
+ return full_mask;
+}
+
void FieldEvaluator::evaluate()
{
BLI_assert_msg(!is_evaluated_, "Cannot evaluate fields twice.");
+
+ selection_mask_ = evaluate_selection(selection_field_, context_, mask_, scope_);
+
Array<GFieldRef> fields(fields_to_evaluate_.size());
for (const int i : fields_to_evaluate_.index_range()) {
fields[i] = fields_to_evaluate_[i];
}
- evaluated_varrays_ = evaluate_fields(scope_, fields, mask_, context_, dst_varrays_);
+ evaluated_varrays_ = evaluate_fields(scope_, fields, selection_mask_, context_, dst_varrays_);
BLI_assert(fields_to_evaluate_.size() == evaluated_varrays_.size());
for (const int i : fields_to_evaluate_.index_range()) {
OutputPointerInfo &info = output_pointer_infos_[i];
@@ -696,7 +732,13 @@ IndexMask FieldEvaluator::get_evaluated_as_mask(const int field_index)
return IndexRange(0);
}
- return scope_.add_value(indices_from_selection(varray)).as_span();
+ return scope_.add_value(indices_from_selection(mask_, varray)).as_span();
+}
+
+IndexMask FieldEvaluator::get_evaluated_selection_as_mask()
+{
+ BLI_assert(is_evaluated_);
+ return selection_mask_;
}
} // namespace blender::fn
diff --git a/source/blender/functions/intern/generic_virtual_array.cc b/source/blender/functions/intern/generic_virtual_array.cc
index 1fe1c2fc229..b4180a885e7 100644
--- a/source/blender/functions/intern/generic_virtual_array.cc
+++ b/source/blender/functions/intern/generic_virtual_array.cc
@@ -139,107 +139,56 @@ bool GVMutableArrayImpl::try_assign_VMutableArray(void *UNUSED(varray)) const
/** \name #GVArrayImpl_For_GSpan
* \{ */
-GVArrayImpl_For_GSpan::GVArrayImpl_For_GSpan(const GSpan span)
- : GVArrayImpl(span.type(), span.size()), data_(span.data()), element_size_(span.type().size())
-{
-}
-
-GVArrayImpl_For_GSpan::GVArrayImpl_For_GSpan(const CPPType &type, const int64_t size)
- : GVArrayImpl(type, size), element_size_(type.size())
-{
-}
-
-void GVArrayImpl_For_GSpan::get(const int64_t index, void *r_value) const
-{
- type_->copy_assign(POINTER_OFFSET(data_, element_size_ * index), r_value);
-}
-
-void GVArrayImpl_For_GSpan::get_to_uninitialized(const int64_t index, void *r_value) const
-{
- type_->copy_construct(POINTER_OFFSET(data_, element_size_ * index), r_value);
-}
-
-bool GVArrayImpl_For_GSpan::is_span() const
-{
- return true;
-}
-
-GSpan GVArrayImpl_For_GSpan::get_internal_span() const
-{
- return GSpan(*type_, data_, size_);
-}
-
-/** See #VArrayImpl_For_Span_final. */
-class GVArrayImpl_For_GSpan_final final : public GVArrayImpl_For_GSpan {
- public:
- using GVArrayImpl_For_GSpan::GVArrayImpl_For_GSpan;
-
- private:
- bool may_have_ownership() const override
- {
- return false;
- }
-};
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name #GVMutableArrayImpl_For_GMutableSpan
- * \{ */
-
-GVMutableArrayImpl_For_GMutableSpan::GVMutableArrayImpl_For_GMutableSpan(const GMutableSpan span)
+GVArrayImpl_For_GSpan::GVArrayImpl_For_GSpan(const GMutableSpan span)
: GVMutableArrayImpl(span.type(), span.size()),
data_(span.data()),
element_size_(span.type().size())
{
}
-GVMutableArrayImpl_For_GMutableSpan::GVMutableArrayImpl_For_GMutableSpan(const CPPType &type,
- const int64_t size)
+GVArrayImpl_For_GSpan::GVArrayImpl_For_GSpan(const CPPType &type, const int64_t size)
: GVMutableArrayImpl(type, size), element_size_(type.size())
{
}
-void GVMutableArrayImpl_For_GMutableSpan::get(const int64_t index, void *r_value) const
+void GVArrayImpl_For_GSpan::get(const int64_t index, void *r_value) const
{
type_->copy_assign(POINTER_OFFSET(data_, element_size_ * index), r_value);
}
-void GVMutableArrayImpl_For_GMutableSpan::get_to_uninitialized(const int64_t index,
- void *r_value) const
+void GVArrayImpl_For_GSpan::get_to_uninitialized(const int64_t index, void *r_value) const
{
type_->copy_construct(POINTER_OFFSET(data_, element_size_ * index), r_value);
}
-void GVMutableArrayImpl_For_GMutableSpan::set_by_copy(const int64_t index, const void *value)
+void GVArrayImpl_For_GSpan::set_by_copy(const int64_t index, const void *value)
{
type_->copy_assign(value, POINTER_OFFSET(data_, element_size_ * index));
}
-void GVMutableArrayImpl_For_GMutableSpan::set_by_move(const int64_t index, void *value)
+void GVArrayImpl_For_GSpan::set_by_move(const int64_t index, void *value)
{
type_->move_construct(value, POINTER_OFFSET(data_, element_size_ * index));
}
-void GVMutableArrayImpl_For_GMutableSpan::set_by_relocate(const int64_t index, void *value)
+void GVArrayImpl_For_GSpan::set_by_relocate(const int64_t index, void *value)
{
type_->relocate_assign(value, POINTER_OFFSET(data_, element_size_ * index));
}
-bool GVMutableArrayImpl_For_GMutableSpan::is_span() const
+bool GVArrayImpl_For_GSpan::is_span() const
{
return true;
}
-GSpan GVMutableArrayImpl_For_GMutableSpan::get_internal_span() const
+GSpan GVArrayImpl_For_GSpan::get_internal_span() const
{
return GSpan(*type_, data_, size_);
}
-class GVMutableArrayImpl_For_GMutableSpan_final final
- : public GVMutableArrayImpl_For_GMutableSpan {
+class GVArrayImpl_For_GSpan_final final : public GVArrayImpl_For_GSpan {
public:
- using GVMutableArrayImpl_For_GMutableSpan::GVMutableArrayImpl_For_GMutableSpan;
+ using GVArrayImpl_For_GSpan::GVArrayImpl_For_GSpan;
private:
bool may_have_ownership() const override
@@ -337,6 +286,57 @@ class GVArrayImpl_For_SingleValue : public GVArrayImpl_For_SingleValueRef,
/** \} */
/* -------------------------------------------------------------------- */
+/** \name #GVArrayImpl_For_SmallTrivialSingleValue
+ * \{ */
+
+/**
+ * Contains an inline buffer that can store a single value of a trivial type.
+ * This avoids the allocation that would be done by #GVArrayImpl_For_SingleValue.
+ */
+template<int BufferSize> class GVArrayImpl_For_SmallTrivialSingleValue : public GVArrayImpl {
+ private:
+ AlignedBuffer<BufferSize, 8> buffer_;
+
+ public:
+ GVArrayImpl_For_SmallTrivialSingleValue(const CPPType &type,
+ const int64_t size,
+ const void *value)
+ : GVArrayImpl(type, size)
+ {
+ BLI_assert(type.is_trivial());
+ BLI_assert(type.alignment() <= 8);
+ BLI_assert(type.size() <= BufferSize);
+ type.copy_construct(value, &buffer_);
+ }
+
+ private:
+ void get(const int64_t UNUSED(index), void *r_value) const override
+ {
+ this->copy_value_to(r_value);
+ }
+ void get_to_uninitialized(const int64_t UNUSED(index), void *r_value) const override
+ {
+ this->copy_value_to(r_value);
+ }
+
+ bool is_single() const override
+ {
+ return true;
+ }
+ void get_internal_single(void *r_value) const override
+ {
+ this->copy_value_to(r_value);
+ }
+
+ void copy_value_to(void *dst) const
+ {
+ memcpy(dst, &buffer_, type_->size());
+ }
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name #GVArray_GSpan
* \{ */
@@ -426,12 +426,14 @@ class GVArrayImpl_For_SlicedGVArray : public GVArrayImpl {
protected:
GVArray varray_;
int64_t offset_;
+ IndexRange slice_;
public:
GVArrayImpl_For_SlicedGVArray(GVArray varray, const IndexRange slice)
: GVArrayImpl(varray.type(), slice.size()),
varray_(std::move(varray)),
- offset_(slice.start())
+ offset_(slice.start()),
+ slice_(slice)
{
BLI_assert(slice.one_after_last() <= varray_.size());
}
@@ -445,6 +447,24 @@ class GVArrayImpl_For_SlicedGVArray : public GVArrayImpl {
{
varray_.get_to_uninitialized(index + offset_, r_value);
}
+
+ bool is_span() const override
+ {
+ return varray_.is_span();
+ }
+ GSpan get_internal_span() const override
+ {
+ return varray_.get_internal_span().slice(slice_);
+ }
+
+ bool is_single() const override
+ {
+ return varray_.is_single();
+ }
+ void get_internal_single(void *r_value) const override
+ {
+ varray_.get_internal_single(r_value);
+ }
};
/** \} */
@@ -527,49 +547,28 @@ void GVArrayCommon::move_from(GVArrayCommon &&other) noexcept
other.impl_ = nullptr;
}
-/* Returns true when the virtual array is stored as a span internally. */
bool GVArrayCommon::is_span() const
{
- if (this->is_empty()) {
- return true;
- }
return impl_->is_span();
}
-/* Returns the internally used span of the virtual array. This invokes undefined behavior is the
- * virtual array is not stored as a span internally. */
GSpan GVArrayCommon::get_internal_span() const
{
BLI_assert(this->is_span());
- if (this->is_empty()) {
- return GSpan(impl_->type());
- }
return impl_->get_internal_span();
}
-/* Returns true when the virtual array returns the same value for every index. */
bool GVArrayCommon::is_single() const
{
- if (impl_->size() == 1) {
- return true;
- }
return impl_->is_single();
}
-/* Copies the value that is used for every element into `r_value`, which is expected to point to
- * initialized memory. This invokes undefined behavior if the virtual array would not return the
- * same value for every index. */
void GVArrayCommon::get_internal_single(void *r_value) const
{
BLI_assert(this->is_single());
- if (impl_->size() == 1) {
- impl_->get(0, r_value);
- return;
- }
impl_->get_internal_single(r_value);
}
-/* Same as `get_internal_single`, but `r_value` points to initialized memory. */
void GVArrayCommon::get_internal_single_to_uninitialized(void *r_value) const
{
impl_->type().default_construct(r_value);
@@ -606,6 +605,9 @@ GVArray::GVArray(std::shared_ptr<const GVArrayImpl> impl) : GVArrayCommon(std::m
GVArray GVArray::ForSingle(const CPPType &type, const int64_t size, const void *value)
{
+ if (type.is_trivial() && type.size() <= 16 && type.alignment() <= 8) {
+ return GVArray::For<GVArrayImpl_For_SmallTrivialSingleValue<16>>(type, size, value);
+ }
return GVArray::For<GVArrayImpl_For_SingleValue>(type, size, value);
}
@@ -621,7 +623,10 @@ GVArray GVArray::ForSingleDefault(const CPPType &type, const int64_t size)
GVArray GVArray::ForSpan(GSpan span)
{
- return GVArray::For<GVArrayImpl_For_GSpan_final>(span);
+ /* Use const-cast because the underlying virtual array implementation is shared between const
+ * and non const data. */
+ GMutableSpan mutable_span{span.type(), const_cast<void *>(span.data()), span.size()};
+ return GVArray::For<GVArrayImpl_For_GSpan_final>(mutable_span);
}
class GVArrayImpl_For_GArray : public GVArrayImpl_For_GSpan {
@@ -630,7 +635,7 @@ class GVArrayImpl_For_GArray : public GVArrayImpl_For_GSpan {
public:
GVArrayImpl_For_GArray(GArray<> array)
- : GVArrayImpl_For_GSpan(array.as_span()), array_(std::move(array))
+ : GVArrayImpl_For_GSpan(array.as_mutable_span()), array_(std::move(array))
{
}
};
@@ -682,7 +687,7 @@ GVMutableArray::GVMutableArray(std::shared_ptr<GVMutableArrayImpl> impl)
GVMutableArray GVMutableArray::ForSpan(GMutableSpan span)
{
- return GVMutableArray::For<GVMutableArrayImpl_For_GMutableSpan_final>(span);
+ return GVMutableArray::For<GVArrayImpl_For_GSpan_final>(span);
}
GVMutableArray::operator GVArray() const &
@@ -716,7 +721,6 @@ GVMutableArrayImpl *GVMutableArray::get_implementation() const
return this->get_impl();
}
-/* Copy the values from the source buffer to all elements in the virtual array. */
void GVMutableArray::set_all(const void *src)
{
this->get_impl()->set_all(src);
diff --git a/source/blender/functions/intern/multi_function.cc b/source/blender/functions/intern/multi_function.cc
index 43eacdcd2a1..837ccc4f4fb 100644
--- a/source/blender/functions/intern/multi_function.cc
+++ b/source/blender/functions/intern/multi_function.cc
@@ -16,6 +16,138 @@
#include "FN_multi_function.hh"
+#include "BLI_task.hh"
+#include "BLI_threads.h"
+
namespace blender::fn {
+using ExecutionHints = MultiFunction::ExecutionHints;
+
+ExecutionHints MultiFunction::execution_hints() const
+{
+ return this->get_execution_hints();
+}
+
+ExecutionHints MultiFunction::get_execution_hints() const
+{
+ return ExecutionHints{};
+}
+
+static bool supports_threading_by_slicing_params(const MultiFunction &fn)
+{
+ for (const int i : fn.param_indices()) {
+ const MFParamType param_type = fn.param_type(i);
+ if (ELEM(param_type.interface_type(),
+ MFParamType::InterfaceType::Mutable,
+ MFParamType::InterfaceType::Output)) {
+ if (param_type.data_type().is_vector()) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+static int64_t compute_grain_size(const ExecutionHints &hints, const IndexMask mask)
+{
+ int64_t grain_size = hints.min_grain_size;
+ if (hints.uniform_execution_time) {
+ const int thread_count = BLI_system_thread_count();
+ /* Avoid using a small grain size even if it is not necessary. */
+ const int64_t thread_based_grain_size = mask.size() / thread_count / 4;
+ grain_size = std::max(grain_size, thread_based_grain_size);
+ }
+ if (hints.allocates_array) {
+ const int64_t max_grain_size = 10000;
+ /* Avoid allocating many large intermediate arrays. Better process data in smaller chunks to
+ * keep peak memory usage lower. */
+ grain_size = std::min(grain_size, max_grain_size);
+ }
+ return grain_size;
+}
+
+void MultiFunction::call_auto(IndexMask mask, MFParams params, MFContext context) const
+{
+ if (mask.is_empty()) {
+ return;
+ }
+ const ExecutionHints hints = this->execution_hints();
+ const int64_t grain_size = compute_grain_size(hints, mask);
+
+ if (mask.size() <= grain_size) {
+ this->call(mask, params, context);
+ return;
+ }
+
+ const bool supports_threading = supports_threading_by_slicing_params(*this);
+ if (!supports_threading) {
+ this->call(mask, params, context);
+ return;
+ }
+
+ threading::parallel_for(mask.index_range(), grain_size, [&](const IndexRange sub_range) {
+ const IndexMask sliced_mask = mask.slice(sub_range);
+ if (!hints.allocates_array) {
+ /* There is no benefit to changing indices in this case. */
+ this->call(sliced_mask, params, context);
+ return;
+ }
+ if (sliced_mask[0] < grain_size) {
+ /* The indices are low, no need to offset them. */
+ this->call(sliced_mask, params, context);
+ return;
+ }
+ const int64_t input_slice_start = sliced_mask[0];
+ const int64_t input_slice_size = sliced_mask.last() - input_slice_start + 1;
+ const IndexRange input_slice_range{input_slice_start, input_slice_size};
+
+ Vector<int64_t> offset_mask_indices;
+ const IndexMask offset_mask = mask.slice_and_offset(sub_range, offset_mask_indices);
+
+ MFParamsBuilder offset_params{*this, offset_mask.min_array_size()};
+
+ /* Slice all parameters so that for the actual function call. */
+ for (const int param_index : this->param_indices()) {
+ const MFParamType param_type = this->param_type(param_index);
+ switch (param_type.category()) {
+ case MFParamType::SingleInput: {
+ const GVArray &varray = params.readonly_single_input(param_index);
+ offset_params.add_readonly_single_input(varray.slice(input_slice_range));
+ break;
+ }
+ case MFParamType::SingleMutable: {
+ const GMutableSpan span = params.single_mutable(param_index);
+ const GMutableSpan sliced_span = span.slice(input_slice_range);
+ offset_params.add_single_mutable(sliced_span);
+ break;
+ }
+ case MFParamType::SingleOutput: {
+ const GMutableSpan span = params.uninitialized_single_output_if_required(param_index);
+ if (span.is_empty()) {
+ offset_params.add_ignored_single_output();
+ }
+ else {
+ const GMutableSpan sliced_span = span.slice(input_slice_range);
+ offset_params.add_uninitialized_single_output(sliced_span);
+ }
+ break;
+ }
+ case MFParamType::VectorInput:
+ case MFParamType::VectorMutable:
+ case MFParamType::VectorOutput: {
+ BLI_assert_unreachable();
+ break;
+ }
+ }
+ }
+
+ this->call(offset_mask, offset_params, context);
+ });
+}
+
+std::string MultiFunction::debug_name() const
+{
+ return signature_ref_->function_name;
+}
+
} // namespace blender::fn
diff --git a/source/blender/functions/intern/multi_function_builder.cc b/source/blender/functions/intern/multi_function_builder.cc
index f891f162820..24f9bbe0179 100644
--- a/source/blender/functions/intern/multi_function_builder.cc
+++ b/source/blender/functions/intern/multi_function_builder.cc
@@ -32,10 +32,8 @@ CustomMF_GenericConstant::CustomMF_GenericConstant(const CPPType &type,
}
value_ = value;
- MFSignatureBuilder signature{"Constant " + type.name()};
- std::stringstream ss;
- type.print_or_default(value, ss, type.name());
- signature.single_output(ss.str(), type);
+ MFSignatureBuilder signature{"Constant"};
+ signature.single_output("Value", type);
signature_ = signature.build();
this->set_signature(&signature_);
}
@@ -73,28 +71,11 @@ bool CustomMF_GenericConstant::equals(const MultiFunction &other) const
return type_.is_equal(value_, _other->value_);
}
-static std::string gspan_to_string(GSpan array)
-{
- const CPPType &type = array.type();
- std::stringstream ss;
- ss << "[";
- const int64_t max_amount = 5;
- for (int64_t i : IndexRange(std::min(max_amount, array.size()))) {
- type.print_or_default(array[i], ss, type.name());
- ss << ", ";
- }
- if (max_amount < array.size()) {
- ss << "...";
- }
- ss << "]";
- return ss.str();
-}
-
CustomMF_GenericConstantArray::CustomMF_GenericConstantArray(GSpan array) : array_(array)
{
const CPPType &type = array.type();
- MFSignatureBuilder signature{"Constant " + type.name() + " Vector"};
- signature.vector_output(gspan_to_string(array), type);
+ MFSignatureBuilder signature{"Constant Vector"};
+ signature.vector_output("Value", type);
signature_ = signature.build();
this->set_signature(&signature_);
}
@@ -109,12 +90,11 @@ void CustomMF_GenericConstantArray::call(IndexMask mask,
}
}
-CustomMF_DefaultOutput::CustomMF_DefaultOutput(StringRef name,
- Span<MFDataType> input_types,
+CustomMF_DefaultOutput::CustomMF_DefaultOutput(Span<MFDataType> input_types,
Span<MFDataType> output_types)
: output_amount_(output_types.size())
{
- MFSignatureBuilder signature{name};
+ MFSignatureBuilder signature{"Default Output"};
for (MFDataType data_type : input_types) {
signature.input("Input", data_type);
}
@@ -140,9 +120,9 @@ void CustomMF_DefaultOutput::call(IndexMask mask, MFParams params, MFContext UNU
}
}
-CustomMF_GenericCopy::CustomMF_GenericCopy(StringRef name, MFDataType data_type)
+CustomMF_GenericCopy::CustomMF_GenericCopy(MFDataType data_type)
{
- MFSignatureBuilder signature{name};
+ MFSignatureBuilder signature{"Copy"};
signature.input("Input", data_type);
signature.output("Output", data_type);
signature_ = signature.build();
diff --git a/source/blender/functions/intern/multi_function_parallel.cc b/source/blender/functions/intern/multi_function_parallel.cc
deleted file mode 100644
index eefe647644d..00000000000
--- a/source/blender/functions/intern/multi_function_parallel.cc
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#include "FN_multi_function_parallel.hh"
-
-#include "BLI_task.hh"
-
-namespace blender::fn {
-
-ParallelMultiFunction::ParallelMultiFunction(const MultiFunction &fn, const int64_t grain_size)
- : fn_(fn), grain_size_(grain_size)
-{
- this->set_signature(&fn.signature());
-
- threading_supported_ = true;
- for (const int param_index : fn.param_indices()) {
- const MFParamType param_type = fn.param_type(param_index);
- if (param_type.data_type().category() == MFDataType::Vector) {
- /* Vector parameters do not support threading yet. */
- threading_supported_ = false;
- break;
- }
- }
-}
-
-void ParallelMultiFunction::call(IndexMask full_mask, MFParams params, MFContext context) const
-{
- if (full_mask.size() <= grain_size_ || !threading_supported_) {
- fn_.call(full_mask, params, context);
- return;
- }
-
- threading::parallel_for(full_mask.index_range(), grain_size_, [&](const IndexRange mask_slice) {
- Vector<int64_t> sub_mask_indices;
- const IndexMask sub_mask = full_mask.slice_and_offset(mask_slice, sub_mask_indices);
- if (sub_mask.is_empty()) {
- return;
- }
- const int64_t input_slice_start = full_mask[mask_slice.first()];
- const int64_t input_slice_size = full_mask[mask_slice.last()] - input_slice_start + 1;
- const IndexRange input_slice_range{input_slice_start, input_slice_size};
-
- MFParamsBuilder sub_params{fn_, sub_mask.min_array_size()};
-
- /* All parameters are sliced so that the wrapped multi-function does not have to take care of
- * the index offset. */
- for (const int param_index : fn_.param_indices()) {
- const MFParamType param_type = fn_.param_type(param_index);
- switch (param_type.category()) {
- case MFParamType::SingleInput: {
- const GVArray &varray = params.readonly_single_input(param_index);
- sub_params.add_readonly_single_input(varray.slice(input_slice_range));
- break;
- }
- case MFParamType::SingleMutable: {
- const GMutableSpan span = params.single_mutable(param_index);
- const GMutableSpan sliced_span = span.slice(input_slice_start, input_slice_size);
- sub_params.add_single_mutable(sliced_span);
- break;
- }
- case MFParamType::SingleOutput: {
- const GMutableSpan span = params.uninitialized_single_output(param_index);
- const GMutableSpan sliced_span = span.slice(input_slice_start, input_slice_size);
- sub_params.add_uninitialized_single_output(sliced_span);
- break;
- }
- case MFParamType::VectorInput:
- case MFParamType::VectorMutable:
- case MFParamType::VectorOutput: {
- BLI_assert_unreachable();
- break;
- }
- }
- }
-
- fn_.call(sub_mask, sub_params, context);
- });
-}
-
-} // namespace blender::fn
diff --git a/source/blender/functions/intern/multi_function_params.cc b/source/blender/functions/intern/multi_function_params.cc
new file mode 100644
index 00000000000..376c5b2deb7
--- /dev/null
+++ b/source/blender/functions/intern/multi_function_params.cc
@@ -0,0 +1,44 @@
+/*
+ * 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 "FN_multi_function_params.hh"
+
+namespace blender::fn {
+
+GMutableSpan MFParams::ensure_dummy_single_output(int data_index)
+{
+ /* Lock because we are actually modifying #builder_ and it may be used by multiple threads. */
+ std::lock_guard lock{builder_->mutex_};
+
+ for (const std::pair<int, GMutableSpan> &items : builder_->dummy_output_spans_) {
+ if (items.first == data_index) {
+ return items.second;
+ }
+ }
+
+ const CPPType &type = builder_->mutable_spans_[data_index].type();
+ void *buffer = builder_->scope_.linear_allocator().allocate(
+ builder_->min_array_size_ * type.size(), type.alignment());
+ if (!type.is_trivially_destructible()) {
+ builder_->scope_.add_destruct_call(
+ [&type, buffer, mask = builder_->mask_]() { type.destruct_indices(buffer, mask); });
+ }
+ const GMutableSpan span{type, buffer, builder_->min_array_size_};
+ builder_->dummy_output_spans_.append({data_index, span});
+ return span;
+}
+
+} // namespace blender::fn
diff --git a/source/blender/functions/intern/multi_function_procedure.cc b/source/blender/functions/intern/multi_function_procedure.cc
index 986c5dff0c4..804beb7d66f 100644
--- a/source/blender/functions/intern/multi_function_procedure.cc
+++ b/source/blender/functions/intern/multi_function_procedure.cc
@@ -782,7 +782,7 @@ class MFProcedureDotExport {
void instruction_to_string(const MFCallInstruction &instruction, std::stringstream &ss)
{
const MultiFunction &fn = instruction.fn();
- this->instruction_name_format(fn.name() + ": ", ss);
+ this->instruction_name_format(fn.debug_name() + ": ", ss);
for (const int param_index : fn.param_indices()) {
const MFParamType param_type = fn.param_type(param_index);
const MFVariable *variable = instruction.params()[param_index];
diff --git a/source/blender/functions/intern/multi_function_procedure_executor.cc b/source/blender/functions/intern/multi_function_procedure_executor.cc
index 85d0cf4909f..47643ed22ee 100644
--- a/source/blender/functions/intern/multi_function_procedure_executor.cc
+++ b/source/blender/functions/intern/multi_function_procedure_executor.cc
@@ -20,13 +20,12 @@
namespace blender::fn {
-MFProcedureExecutor::MFProcedureExecutor(std::string name, const MFProcedure &procedure)
- : procedure_(procedure)
+MFProcedureExecutor::MFProcedureExecutor(const MFProcedure &procedure) : procedure_(procedure)
{
- MFSignatureBuilder signature(std::move(name));
+ MFSignatureBuilder signature("Procedure Executor");
for (const ConstMFParameter &param : procedure.params()) {
- signature.add(param.variable->name(), MFParamType(param.type, param.variable->data_type()));
+ signature.add("Parameter", MFParamType(param.type, param.variable->data_type()));
}
signature_ = signature.build();
@@ -140,32 +139,36 @@ class VariableState;
*/
class ValueAllocator : NonCopyable, NonMovable {
private:
- /* Allocate with 64 byte alignment for better reusability of buffers and improved cache
- * performance. */
+ /**
+ * Allocate with 64 byte alignment for better reusability of buffers and improved cache
+ * performance.
+ */
static constexpr inline int min_alignment = 64;
- /* Use stacks so that the most recently used buffers are reused first. This improves cache
- * efficiency. */
- std::array<Stack<VariableValue *>, tot_variable_value_types> values_free_lists_;
- /* The integer key is the size of one element (e.g. 4 for an integer buffer). All buffers are
- * aligned to #min_alignment bytes. */
+ /** All buffers in the free-lists below have been allocated with this allocator. */
+ LinearAllocator<> &linear_allocator_;
+
+ /**
+ * Use stacks so that the most recently used buffers are reused first. This improves cache
+ * efficiency.
+ */
+ std::array<Stack<VariableValue *>, tot_variable_value_types> variable_value_free_lists_;
+
+ /**
+ * The integer key is the size of one element (e.g. 4 for an integer buffer). All buffers are
+ * aligned to #min_alignment bytes.
+ */
Map<int, Stack<void *>> span_buffers_free_list_;
- public:
- ValueAllocator() = default;
+ /** Cache buffers for single values of different types. */
+ Map<const CPPType *, Stack<void *>> single_value_free_lists_;
- ~ValueAllocator()
+ /** The cached memory buffers can hold #VariableState values. */
+ Stack<void *> variable_state_free_list_;
+
+ public:
+ ValueAllocator(LinearAllocator<> &linear_allocator) : linear_allocator_(linear_allocator)
{
- for (Stack<VariableValue *> &stack : values_free_lists_) {
- while (!stack.is_empty()) {
- MEM_freeN(stack.pop());
- }
- }
- for (Stack<void *> &stack : span_buffers_free_list_.values()) {
- while (!stack.is_empty()) {
- MEM_freeN(stack.pop());
- }
- }
}
template<typename... Args> VariableState *obtain_variable_state(Args &&...args);
@@ -191,17 +194,17 @@ class ValueAllocator : NonCopyable, NonMovable {
{
void *buffer = nullptr;
- const int element_size = type.size();
- const int alignment = type.alignment();
+ const int64_t element_size = type.size();
+ const int64_t alignment = type.alignment();
if (alignment > min_alignment) {
/* In this rare case we fallback to not reusing existing buffers. */
- buffer = MEM_mallocN_aligned(element_size * size, alignment, __func__);
+ buffer = linear_allocator_.allocate(element_size * size, alignment);
}
else {
Stack<void *> *stack = span_buffers_free_list_.lookup_ptr(element_size);
if (stack == nullptr || stack->is_empty()) {
- buffer = MEM_mallocN_aligned(element_size * size, min_alignment, __func__);
+ buffer = linear_allocator_.allocate(element_size * size, min_alignment);
}
else {
/* Reuse existing buffer. */
@@ -225,7 +228,14 @@ class ValueAllocator : NonCopyable, NonMovable {
VariableValue_OneSingle *obtain_OneSingle(const CPPType &type)
{
- void *buffer = MEM_mallocN_aligned(type.size(), type.alignment(), __func__);
+ Stack<void *> &stack = single_value_free_lists_.lookup_or_add_default(&type);
+ void *buffer;
+ if (stack.is_empty()) {
+ buffer = linear_allocator_.allocate(type.size(), type.alignment());
+ }
+ else {
+ buffer = stack.pop();
+ }
return this->obtain<VariableValue_OneSingle>(buffer);
}
@@ -263,11 +273,11 @@ class ValueAllocator : NonCopyable, NonMovable {
}
case ValueType::OneSingle: {
auto *value_typed = static_cast<VariableValue_OneSingle *>(value);
+ const CPPType &type = data_type.single_type();
if (value_typed->is_initialized) {
- const CPPType &type = data_type.single_type();
type.destruct(value_typed->data);
}
- MEM_freeN(value_typed->data);
+ single_value_free_lists_.lookup_or_add_default(&type).push(value_typed->data);
break;
}
case ValueType::OneVector: {
@@ -277,7 +287,7 @@ class ValueAllocator : NonCopyable, NonMovable {
}
}
- Stack<VariableValue *> &stack = values_free_lists_[(int)value->type];
+ Stack<VariableValue *> &stack = variable_value_free_lists_[(int)value->type];
stack.push(value);
}
@@ -285,9 +295,9 @@ class ValueAllocator : NonCopyable, NonMovable {
template<typename T, typename... Args> T *obtain(Args &&...args)
{
static_assert(std::is_base_of_v<VariableValue, T>);
- Stack<VariableValue *> &stack = values_free_lists_[(int)T::static_type];
+ Stack<VariableValue *> &stack = variable_value_free_lists_[(int)T::static_type];
if (stack.is_empty()) {
- void *buffer = MEM_mallocN(sizeof(T), __func__);
+ void *buffer = linear_allocator_.allocate(sizeof(T), alignof(T));
return new (buffer) T(std::forward<Args>(args)...);
}
return new (stack.pop()) T(std::forward<Args>(args)...);
@@ -670,7 +680,12 @@ class VariableState : NonCopyable, NonMovable {
tot_initialized_ += mask.size();
}
- void destruct(IndexMask mask,
+ /**
+ * Destruct the masked elements in this variable.
+ * \return True when all elements of this variable are initialized and the variable state can be
+ * released.
+ */
+ bool destruct(IndexMask mask,
IndexMask full_mask,
const MFDataType &data_type,
ValueAllocator &value_allocator)
@@ -680,13 +695,12 @@ class VariableState : NonCopyable, NonMovable {
/* Sanity check to make sure that enough indices can be destructed. */
BLI_assert(new_tot_initialized >= 0);
+ bool do_destruct_self = false;
+
switch (value_->type) {
case ValueType::GVArray: {
if (mask.size() == full_mask.size()) {
- /* All elements are destructed. The elements are owned by the caller, so we don't
- * actually destruct them. */
- value_allocator.release_value(value_, data_type);
- value_ = value_allocator.obtain_OneSingle(data_type.single_type());
+ do_destruct_self = true;
}
else {
/* Not all elements are destructed. Since we can't work on the original array, we have to
@@ -702,18 +716,13 @@ class VariableState : NonCopyable, NonMovable {
const CPPType &type = data_type.single_type();
type.destruct_indices(this->value_as<VariableValue_Span>()->data, mask);
if (new_tot_initialized == 0) {
- /* Release span when all values are initialized. */
- value_allocator.release_value(value_, data_type);
- value_ = value_allocator.obtain_OneSingle(data_type.single_type());
+ do_destruct_self = true;
}
break;
}
case ValueType::GVVectorArray: {
if (mask.size() == full_mask.size()) {
- /* All elements are cleared. The elements are owned by the caller, so don't actually
- * destruct them. */
- value_allocator.release_value(value_, data_type);
- value_ = value_allocator.obtain_OneVector(data_type.vector_base_type());
+ do_destruct_self = true;
}
else {
/* Not all elements are cleared. Since we can't work on the original vector array, we
@@ -732,23 +741,24 @@ class VariableState : NonCopyable, NonMovable {
case ValueType::OneSingle: {
auto *value_typed = this->value_as<VariableValue_OneSingle>();
BLI_assert(value_typed->is_initialized);
+ UNUSED_VARS_NDEBUG(value_typed);
if (mask.size() == tot_initialized_) {
- const CPPType &type = data_type.single_type();
- type.destruct(value_typed->data);
- value_typed->is_initialized = false;
+ do_destruct_self = true;
}
break;
}
case ValueType::OneVector: {
auto *value_typed = this->value_as<VariableValue_OneVector>();
+ UNUSED_VARS(value_typed);
if (mask.size() == tot_initialized_) {
- value_typed->data.clear({0});
+ do_destruct_self = true;
}
break;
}
}
tot_initialized_ = new_tot_initialized;
+ return do_destruct_self;
}
void indices_split(IndexMask mask, IndicesSplitVectors &r_indices)
@@ -802,12 +812,17 @@ class VariableState : NonCopyable, NonMovable {
template<typename... Args> VariableState *ValueAllocator::obtain_variable_state(Args &&...args)
{
- return new VariableState(std::forward<Args>(args)...);
+ if (variable_state_free_list_.is_empty()) {
+ void *buffer = linear_allocator_.allocate(sizeof(VariableState), alignof(VariableState));
+ return new (buffer) VariableState(std::forward<Args>(args)...);
+ }
+ return new (variable_state_free_list_.pop()) VariableState(std::forward<Args>(args)...);
}
void ValueAllocator::release_variable_state(VariableState *state)
{
- delete state;
+ state->~VariableState();
+ variable_state_free_list_.push(state);
}
/** Keeps track of the states of all variables during evaluation. */
@@ -818,7 +833,8 @@ class VariableStates {
IndexMask full_mask_;
public:
- VariableStates(IndexMask full_mask) : full_mask_(full_mask)
+ VariableStates(LinearAllocator<> &linear_allocator, IndexMask full_mask)
+ : value_allocator_(linear_allocator), full_mask_(full_mask)
{
}
@@ -940,7 +956,10 @@ class VariableStates {
void destruct(const MFVariable &variable, const IndexMask &mask)
{
VariableState &variable_state = this->get_variable_state(variable);
- variable_state.destruct(mask, full_mask_, variable.data_type(), value_allocator_);
+ if (variable_state.destruct(mask, full_mask_, variable.data_type(), value_allocator_)) {
+ variable_state.destruct_self(value_allocator_, variable.data_type());
+ variable_states_.remove_contained(&variable);
+ }
}
VariableState &get_variable_state(const MFVariable &variable)
@@ -1046,7 +1065,7 @@ static void execute_call_instruction(const MFCallInstruction &instruction,
}
try {
- fn.call(mask, params, context);
+ fn.call_auto(mask, params, context);
}
catch (...) {
/* Multi-functions must not throw exceptions. */
@@ -1162,9 +1181,9 @@ void MFProcedureExecutor::call(IndexMask full_mask, MFParams params, MFContext c
{
BLI_assert(procedure_.validate());
- LinearAllocator<> allocator;
+ LinearAllocator<> linear_allocator;
- VariableStates variable_states{full_mask};
+ VariableStates variable_states{linear_allocator, full_mask};
variable_states.add_initial_variable_states(*this, procedure_, params);
InstructionScheduler scheduler;
@@ -1237,4 +1256,12 @@ void MFProcedureExecutor::call(IndexMask full_mask, MFParams params, MFContext c
}
}
+MultiFunction::ExecutionHints MFProcedureExecutor::get_execution_hints() const
+{
+ ExecutionHints hints;
+ hints.allocates_array = true;
+ hints.min_grain_size = 10000;
+ return hints;
+}
+
} // namespace blender::fn
diff --git a/source/blender/functions/intern/multi_function_procedure_optimization.cc b/source/blender/functions/intern/multi_function_procedure_optimization.cc
new file mode 100644
index 00000000000..f220c85e535
--- /dev/null
+++ b/source/blender/functions/intern/multi_function_procedure_optimization.cc
@@ -0,0 +1,90 @@
+/*
+ * 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 "FN_multi_function_procedure_optimization.hh"
+
+namespace blender::fn::procedure_optimization {
+
+void move_destructs_up(MFProcedure &procedure, MFInstruction &block_end_instr)
+{
+ /* A mapping from a variable to its destruct instruction. */
+ Map<MFVariable *, MFDestructInstruction *> destruct_instructions;
+ MFInstruction *current_instr = &block_end_instr;
+ while (true) {
+ MFInstructionType instr_type = current_instr->type();
+ switch (instr_type) {
+ case MFInstructionType::Destruct: {
+ MFDestructInstruction &destruct_instr = static_cast<MFDestructInstruction &>(
+ *current_instr);
+ MFVariable *variable = destruct_instr.variable();
+ if (variable == nullptr) {
+ continue;
+ }
+ /* Remember this destruct instruction so that it can be moved up later on when the last use
+ * of the variable is found. */
+ destruct_instructions.add(variable, &destruct_instr);
+ break;
+ }
+ case MFInstructionType::Call: {
+ MFCallInstruction &call_instr = static_cast<MFCallInstruction &>(*current_instr);
+ /* For each variable, place the corresponding remembered destruct instruction right after
+ * this call instruction. */
+ for (MFVariable *variable : call_instr.params()) {
+ if (variable == nullptr) {
+ continue;
+ }
+ MFDestructInstruction *destruct_instr = destruct_instructions.pop_default(variable,
+ nullptr);
+ if (destruct_instr == nullptr) {
+ continue;
+ }
+
+ /* Unlink destruct instruction from previous position. */
+ MFInstruction *after_destruct_instr = destruct_instr->next();
+ while (!destruct_instr->prev().is_empty()) {
+ /* Do a copy of the cursor here, because `destruct_instr->prev()` changes when
+ * #set_next is called below. */
+ const MFInstructionCursor cursor = destruct_instr->prev()[0];
+ cursor.set_next(procedure, after_destruct_instr);
+ }
+
+ /* Insert destruct instruction in new position. */
+ MFInstruction *next_instr = call_instr.next();
+ call_instr.set_next(destruct_instr);
+ destruct_instr->set_next(next_instr);
+ }
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+
+ const Span<MFInstructionCursor> prev_cursors = current_instr->prev();
+ if (prev_cursors.size() != 1) {
+ /* Stop when there is some branching before this instruction. */
+ break;
+ }
+ const MFInstructionCursor &prev_cursor = prev_cursors[0];
+ current_instr = prev_cursor.instruction();
+ if (current_instr == nullptr) {
+ /* Stop when there is no previous instruction. E.g. when this is the first instruction. */
+ break;
+ }
+ }
+}
+
+} // namespace blender::fn::procedure_optimization
diff --git a/source/blender/functions/tests/FN_field_test.cc b/source/blender/functions/tests/FN_field_test.cc
index 16a6c73183d..4614f9eee58 100644
--- a/source/blender/functions/tests/FN_field_test.cc
+++ b/source/blender/functions/tests/FN_field_test.cc
@@ -160,9 +160,9 @@ class TwoOutputFunction : public MultiFunction {
MFSignature signature_;
public:
- TwoOutputFunction(StringRef name)
+ TwoOutputFunction()
{
- MFSignatureBuilder signature{name};
+ MFSignatureBuilder signature{"Two Outputs"};
signature.single_input<int>("In1");
signature.single_input<int>("In2");
signature.single_output<int>("Add");
@@ -190,8 +190,8 @@ TEST(field, FunctionTwoOutputs)
GField index_field_1{std::make_shared<IndexFieldInput>()};
GField index_field_2{std::make_shared<IndexFieldInput>()};
- std::shared_ptr<FieldOperation> fn = std::make_shared<FieldOperation>(FieldOperation(
- std::make_unique<TwoOutputFunction>("SI_SI_SO_SO"), {index_field_1, index_field_2}));
+ std::shared_ptr<FieldOperation> fn = std::make_shared<FieldOperation>(
+ FieldOperation(std::make_unique<TwoOutputFunction>(), {index_field_1, index_field_2}));
GField result_field_1{fn, 0};
GField result_field_2{fn, 1};
@@ -221,8 +221,8 @@ TEST(field, TwoFunctionsTwoOutputs)
{
GField index_field{std::make_shared<IndexFieldInput>()};
- std::shared_ptr<FieldOperation> fn = std::make_shared<FieldOperation>(FieldOperation(
- std::make_unique<TwoOutputFunction>("SI_SI_SO_SO"), {index_field, index_field}));
+ std::shared_ptr<FieldOperation> fn = std::make_shared<FieldOperation>(
+ FieldOperation(std::make_unique<TwoOutputFunction>(), {index_field, index_field}));
Array<int64_t> mask_indices = {2, 4, 6, 8};
IndexMask mask = mask_indices.as_span();
diff --git a/source/blender/functions/tests/FN_multi_function_procedure_test.cc b/source/blender/functions/tests/FN_multi_function_procedure_test.cc
index a0919d7926e..e3de23550c5 100644
--- a/source/blender/functions/tests/FN_multi_function_procedure_test.cc
+++ b/source/blender/functions/tests/FN_multi_function_procedure_test.cc
@@ -32,7 +32,7 @@ TEST(multi_function_procedure, ConstantOutput)
EXPECT_TRUE(procedure.validate());
- MFProcedureExecutor executor{"My Procedure", procedure};
+ MFProcedureExecutor executor{procedure};
MFParamsBuilder params{executor, 2};
MFContextBuilder context;
@@ -73,7 +73,7 @@ TEST(multi_function_procedure, SimpleTest)
EXPECT_TRUE(procedure.validate());
- MFProcedureExecutor executor{"My Procedure", procedure};
+ MFProcedureExecutor executor{procedure};
MFParamsBuilder params{executor, 3};
MFContextBuilder context;
@@ -125,7 +125,7 @@ TEST(multi_function_procedure, BranchTest)
EXPECT_TRUE(procedure.validate());
- MFProcedureExecutor procedure_fn{"Condition Test", procedure};
+ MFProcedureExecutor procedure_fn{procedure};
MFParamsBuilder params(procedure_fn, 5);
Array<int> values_a = {1, 5, 3, 6, 2};
@@ -167,7 +167,7 @@ TEST(multi_function_procedure, EvaluateOne)
builder.add_return();
builder.add_output_parameter(*var2);
- MFProcedureExecutor procedure_fn{"Evaluate One", procedure};
+ MFProcedureExecutor procedure_fn{procedure};
MFParamsBuilder params{procedure_fn, 5};
Array<int> values_out = {1, 2, 3, 4, 5};
@@ -239,7 +239,7 @@ TEST(multi_function_procedure, SimpleLoop)
EXPECT_TRUE(procedure.validate());
- MFProcedureExecutor procedure_fn{"Simple Loop", procedure};
+ MFProcedureExecutor procedure_fn{procedure};
MFParamsBuilder params{procedure_fn, 5};
Array<int> counts = {4, 3, 7, 6, 4};
@@ -295,7 +295,7 @@ TEST(multi_function_procedure, Vectors)
EXPECT_TRUE(procedure.validate());
- MFProcedureExecutor procedure_fn{"Vectors", procedure};
+ MFProcedureExecutor procedure_fn{procedure};
MFParamsBuilder params{procedure_fn, 5};
Array<int> v1 = {5, 2, 3};
@@ -359,7 +359,7 @@ TEST(multi_function_procedure, BufferReuse)
EXPECT_TRUE(procedure.validate());
- MFProcedureExecutor procedure_fn{"Buffer Reuse", procedure};
+ MFProcedureExecutor procedure_fn{procedure};
Array<int> inputs = {4, 1, 6, 2, 3};
Array<int> results(5, -1);
diff --git a/source/blender/functions/tests/FN_multi_function_test.cc b/source/blender/functions/tests/FN_multi_function_test.cc
index d99993b35ac..20ca00cf598 100644
--- a/source/blender/functions/tests/FN_multi_function_test.cc
+++ b/source/blender/functions/tests/FN_multi_function_test.cc
@@ -264,7 +264,6 @@ TEST(multi_function, CustomMF_GenericConstant)
{
int value = 42;
CustomMF_GenericConstant fn{CPPType::get<int32_t>(), (const void *)&value, false};
- EXPECT_EQ(fn.param_name(0), "42");
Array<int> outputs(4, 0);
@@ -285,7 +284,6 @@ TEST(multi_function, CustomMF_GenericConstantArray)
{
std::array<int, 4> values = {3, 4, 5, 6};
CustomMF_GenericConstantArray fn{GSpan(Span(values))};
- EXPECT_EQ(fn.param_name(0), "[3, 4, 5, 6, ]");
GVectorArray vector_array{CPPType::get<int32_t>(), 4};
GVectorArray_TypedMutableRef<int> vector_array_ref{vector_array};
diff --git a/source/blender/geometry/CMakeLists.txt b/source/blender/geometry/CMakeLists.txt
index 03f736d4dde..de508ddc540 100644
--- a/source/blender/geometry/CMakeLists.txt
+++ b/source/blender/geometry/CMakeLists.txt
@@ -31,7 +31,10 @@ set(INC
set(SRC
intern/mesh_to_curve_convert.cc
+ intern/realize_instances.cc
+
GEO_mesh_to_curve.hh
+ GEO_realize_instances.hh
)
set(LIB
diff --git a/source/blender/geometry/GEO_mesh_to_curve.hh b/source/blender/geometry/GEO_mesh_to_curve.hh
index 66459ab79a9..fac40cc40d5 100644
--- a/source/blender/geometry/GEO_mesh_to_curve.hh
+++ b/source/blender/geometry/GEO_mesh_to_curve.hh
@@ -29,6 +29,11 @@ class MeshComponent;
namespace blender::geometry {
+/**
+ * Convert the mesh into one or many poly splines. Since splines cannot have branches,
+ * intersections of more than three edges will become breaks in splines. Attributes that
+ * are not built-in on meshes and not curves are transferred to the result curve.
+ */
std::unique_ptr<CurveEval> mesh_to_curve_convert(const MeshComponent &mesh_component,
const IndexMask selection);
diff --git a/source/blender/geometry/GEO_realize_instances.hh b/source/blender/geometry/GEO_realize_instances.hh
new file mode 100644
index 00000000000..ac16196667d
--- /dev/null
+++ b/source/blender/geometry/GEO_realize_instances.hh
@@ -0,0 +1,52 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+#include "BKE_geometry_set.hh"
+
+namespace blender::geometry {
+
+struct RealizeInstancesOptions {
+ /**
+ * The default is to generate new ids for every element (when there was any id attribute in the
+ * input). This avoids having a geometry that contains the same id many times.
+ * When this is `true` the ids on the original geometries are kept unchanged and ids on instances
+ * are ignored. Ids are zero initialized when the original geometry did not have an id.
+ */
+ bool keep_original_ids = false;
+ /**
+ * When `true` the output geometry will contain all the generic attributes that existed on
+ * instances. Otherwise, instance attributes are ignored.
+ */
+ bool realize_instance_attributes = true;
+};
+
+/**
+ * Join all instances into a single geometry component for each geometry type. For example, all
+ * mesh instances (including the already realized mesh) are joined into a single mesh. The output
+ * geometry set does not contain any instances. If the input did not contain any instances, it is
+ * returned directly.
+ *
+ * The `id` attribute has special handling. If there is an id attribute on any component, the
+ * output will contain an `id` attribute as well. The output id is generated by mixing/hashing ids
+ * of instances and of the instanced geometry data.
+ */
+GeometrySet realize_instances(GeometrySet geometry_set, const RealizeInstancesOptions &options);
+
+GeometrySet realize_instances_legacy(GeometrySet geometry_set);
+
+} // namespace blender::geometry
diff --git a/source/blender/geometry/intern/mesh_to_curve_convert.cc b/source/blender/geometry/intern/mesh_to_curve_convert.cc
index 7aaaec9f0c5..0cbec35ec7a 100644
--- a/source/blender/geometry/intern/mesh_to_curve_convert.cc
+++ b/source/blender/geometry/intern/mesh_to_curve_convert.cc
@@ -260,11 +260,6 @@ static Vector<std::pair<int, int>> get_selected_edges(const Mesh &mesh, const In
return selected_edges;
}
-/**
- * Convert the mesh into one or many poly splines. Since splines cannot have branches,
- * intersections of more than three edges will become breaks in splines. Attributes that
- * are not built-in on meshes and not curves are transferred to the result curve.
- */
std::unique_ptr<CurveEval> mesh_to_curve_convert(const MeshComponent &mesh_component,
const IndexMask selection)
{
diff --git a/source/blender/geometry/intern/realize_instances.cc b/source/blender/geometry/intern/realize_instances.cc
new file mode 100644
index 00000000000..ae513bf88e9
--- /dev/null
+++ b/source/blender/geometry/intern/realize_instances.cc
@@ -0,0 +1,1347 @@
+/*
+ * 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 "GEO_realize_instances.hh"
+
+#include "DNA_collection_types.h"
+#include "DNA_layer_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_pointcloud_types.h"
+
+#include "BLI_noise.hh"
+#include "BLI_task.hh"
+
+#include "BKE_collection.h"
+#include "BKE_geometry_set_instances.hh"
+#include "BKE_material.h"
+#include "BKE_mesh.h"
+#include "BKE_pointcloud.h"
+#include "BKE_spline.hh"
+#include "BKE_type_conversions.hh"
+
+namespace blender::geometry {
+
+using blender::bke::AttributeIDRef;
+using blender::bke::custom_data_type_to_cpp_type;
+using blender::bke::CustomDataAttributes;
+using blender::bke::object_get_evaluated_geometry_set;
+using blender::bke::OutputAttribute;
+using blender::bke::OutputAttribute_Typed;
+using blender::bke::ReadAttributeLookup;
+using blender::fn::CPPType;
+using blender::fn::GArray;
+using blender::fn::GMutableSpan;
+using blender::fn::GSpan;
+using blender::fn::GVArray;
+using blender::fn::GVArray_GSpan;
+
+/**
+ * An ordered set of attribute ids. Attributes are ordered to avoid name lookups in many places.
+ * Once the attributes are ordered, they can just be referred to by index.
+ */
+struct OrderedAttributes {
+ VectorSet<AttributeIDRef> ids;
+ Vector<AttributeKind> kinds;
+
+ int size() const
+ {
+ return this->kinds.size();
+ }
+
+ IndexRange index_range() const
+ {
+ return this->kinds.index_range();
+ }
+};
+
+struct AttributeFallbacksArray {
+ /**
+ * Instance attribute values used as fallback when the geometry does not have the
+ * corresponding attributes itself. The pointers point to attributes stored in the instances
+ * component or in #r_temporary_arrays. The order depends on the corresponding #OrderedAttributes
+ * instance.
+ */
+ Array<const void *> array;
+
+ AttributeFallbacksArray(int size) : array(size, nullptr)
+ {
+ }
+};
+
+struct PointCloudRealizeInfo {
+ const PointCloud *pointcloud = nullptr;
+ /** Matches the order stored in #AllPointCloudsInfo.attributes. */
+ Array<std::optional<GVArray_GSpan>> attributes;
+ /** Id attribute on the point cloud. If there are no ids, this #Span is empty. */
+ Span<int> stored_ids;
+};
+
+struct RealizePointCloudTask {
+ /** Starting index in the final realized point cloud. */
+ int start_index;
+ /** Preprocessed information about the point cloud. */
+ const PointCloudRealizeInfo *pointcloud_info;
+ /** Transformation that is applied to all positions. */
+ float4x4 transform;
+ AttributeFallbacksArray attribute_fallbacks;
+ /** Only used when the output contains an output attribute. */
+ uint32_t id = 0;
+};
+
+/** Start indices in the final output mesh. */
+struct MeshElementStartIndices {
+ int vertex = 0;
+ int edge = 0;
+ int poly = 0;
+ int loop = 0;
+};
+
+struct MeshRealizeInfo {
+ const Mesh *mesh = nullptr;
+ /** Maps old material indices to new material indices. */
+ Array<int> material_index_map;
+ /** Matches the order in #AllMeshesInfo.attributes. */
+ Array<std::optional<GVArray_GSpan>> attributes;
+ /** Vertex ids stored on the mesh. If there are no ids, this #Span is empty. */
+ Span<int> stored_vertex_ids;
+};
+
+struct RealizeMeshTask {
+ MeshElementStartIndices start_indices;
+ const MeshRealizeInfo *mesh_info;
+ /** Transformation that is applied to all positions. */
+ float4x4 transform;
+ AttributeFallbacksArray attribute_fallbacks;
+ /** Only used when the output contains an output attribute. */
+ uint32_t id = 0;
+};
+
+struct RealizeCurveInfo {
+ const CurveEval *curve = nullptr;
+ /**
+ * Matches the order in #AllCurvesInfo.attributes. For point attributes, the `std::optional`
+ * will be empty.
+ */
+ Array<std::optional<GVArray_GSpan>> spline_attributes;
+};
+
+struct RealizeCurveTask {
+ /* Start index in the final curve. */
+ int start_spline_index = 0;
+ const RealizeCurveInfo *curve_info;
+ /* Transformation applied to the position of control points and handles. */
+ float4x4 transform;
+ AttributeFallbacksArray attribute_fallbacks;
+ /** Only used when the output contains an output attribute. */
+ uint32_t id = 0;
+};
+
+struct AllPointCloudsInfo {
+ /** Ordering of all attributes that are propagated to the output point cloud generically. */
+ OrderedAttributes attributes;
+ /** Ordering of the original point clouds that are joined. */
+ VectorSet<const PointCloud *> order;
+ /** Preprocessed data about every original point cloud. This is ordered by #order. */
+ Array<PointCloudRealizeInfo> realize_info;
+ bool create_id_attribute = false;
+};
+
+struct AllMeshesInfo {
+ /** Ordering of all attributes that are propagated to the output mesh generically. */
+ OrderedAttributes attributes;
+ /** Ordering of the original meshes that are joined. */
+ VectorSet<const Mesh *> order;
+ /** Preprocessed data about every original mesh. This is ordered by #order. */
+ Array<MeshRealizeInfo> realize_info;
+ /** Ordered materials on the output mesh. */
+ VectorSet<Material *> materials;
+ bool create_id_attribute = false;
+};
+
+struct AllCurvesInfo {
+ /** Ordering of all attributes that are propagated to the output curve generically. */
+ OrderedAttributes attributes;
+ /** Ordering of the original curves that are joined. */
+ VectorSet<const CurveEval *> order;
+ /** Preprocessed data about every original curve. This is ordered by #order. */
+ Array<RealizeCurveInfo> realize_info;
+ bool create_id_attribute = false;
+};
+
+/** Collects all tasks that need to be executed to realize all instances. */
+struct GatherTasks {
+ Vector<RealizePointCloudTask> pointcloud_tasks;
+ Vector<RealizeMeshTask> mesh_tasks;
+ Vector<RealizeCurveTask> curve_tasks;
+
+ /* Volumes only have very simple support currently. Only the first found volume is put into the
+ * output. */
+ UserCounter<VolumeComponent> first_volume;
+};
+
+/** Current offsets while during the gather operation. */
+struct GatherOffsets {
+ int pointcloud_offset = 0;
+ MeshElementStartIndices mesh_offsets;
+ int spline_offset = 0;
+};
+
+struct GatherTasksInfo {
+ /** Static information about all geometries that are joined. */
+ const AllPointCloudsInfo &pointclouds;
+ const AllMeshesInfo &meshes;
+ const AllCurvesInfo &curves;
+ bool create_id_attribute_on_any_component = false;
+
+ /**
+ * Under some circumstances, temporary arrays need to be allocated during the gather operation.
+ * For example, when an instance attribute has to be realized as a different data type. This
+ * array owns all the temporary arrays so that they can live until all processing is done.
+ * Use #std::unique_ptr to avoid depending on whether #GArray has an inline buffer or not.
+ */
+ Vector<std::unique_ptr<GArray<>>> &r_temporary_arrays;
+
+ /** All gathered tasks. */
+ GatherTasks r_tasks;
+ /** Current offsets while gathering tasks. */
+ GatherOffsets r_offsets;
+};
+
+/**
+ * Information about the parent instances in the current context.
+ */
+struct InstanceContext {
+ /** Ordered by #AllPointCloudsInfo.attributes. */
+ AttributeFallbacksArray pointclouds;
+ /** Ordered by #AllMeshesInfo.attributes. */
+ AttributeFallbacksArray meshes;
+ /** Ordered by #AllCurvesInfo.attributes. */
+ AttributeFallbacksArray curves;
+ /** Id mixed from all parent instances. */
+ uint32_t id = 0;
+
+ InstanceContext(const GatherTasksInfo &gather_info)
+ : pointclouds(gather_info.pointclouds.attributes.size()),
+ meshes(gather_info.meshes.attributes.size()),
+ curves(gather_info.curves.attributes.size())
+ {
+ }
+};
+
+/* -------------------------------------------------------------------- */
+/** \name Gather Realize Tasks
+ * \{ */
+
+/* Forward declaration. */
+static void gather_realize_tasks_recursive(GatherTasksInfo &gather_info,
+ const GeometrySet &geometry_set,
+ const float4x4 &base_transform,
+ const InstanceContext &base_instance_context);
+
+/**
+ * Checks which of the #ordered_attributes exist on the #instances_component. For each attribute
+ * that exists on the instances, a pair is returned that contains the attribute index and the
+ * corresponding attribute data.
+ */
+static Vector<std::pair<int, GSpan>> prepare_attribute_fallbacks(
+ GatherTasksInfo &gather_info,
+ const InstancesComponent &instances_component,
+ const OrderedAttributes &ordered_attributes)
+{
+ Vector<std::pair<int, GSpan>> attributes_to_override;
+ const CustomDataAttributes &attributes = instances_component.attributes();
+ attributes.foreach_attribute(
+ [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
+ const int attribute_index = ordered_attributes.ids.index_of_try(attribute_id);
+ if (attribute_index == -1) {
+ /* The attribute is not propagated to the final geometry. */
+ return true;
+ }
+ GSpan span = *attributes.get_for_read(attribute_id);
+ const CustomDataType expected_type = ordered_attributes.kinds[attribute_index].data_type;
+ if (meta_data.data_type != expected_type) {
+ const CPPType &from_type = span.type();
+ const CPPType &to_type = *custom_data_type_to_cpp_type(expected_type);
+ const bke::DataTypeConversions &conversions = bke::get_implicit_type_conversions();
+ if (!conversions.is_convertible(from_type, to_type)) {
+ /* Ignore the attribute because it can not be converted to the desired type. */
+ return true;
+ }
+ /* Convert the attribute on the instances component to the expected attribute type. */
+ std::unique_ptr<GArray<>> temporary_array = std::make_unique<GArray<>>(
+ to_type, instances_component.instances_amount());
+ conversions.convert_to_initialized_n(span, temporary_array->as_mutable_span());
+ span = temporary_array->as_span();
+ gather_info.r_temporary_arrays.append(std::move(temporary_array));
+ }
+ attributes_to_override.append({attribute_index, span});
+ return true;
+ },
+ ATTR_DOMAIN_INSTANCE);
+ return attributes_to_override;
+}
+
+/**
+ * Calls #fn for every geometry in the given #InstanceReference. Also passes on the transformation
+ * that is applied to every instance.
+ */
+static void foreach_geometry_in_reference(
+ const InstanceReference &reference,
+ const float4x4 &base_transform,
+ const uint32_t id,
+ FunctionRef<void(const GeometrySet &geometry_set, const float4x4 &transform, uint32_t id)> fn)
+{
+ switch (reference.type()) {
+ case InstanceReference::Type::Object: {
+ const Object &object = reference.object();
+ const GeometrySet object_geometry_set = object_get_evaluated_geometry_set(object);
+ fn(object_geometry_set, base_transform, id);
+ break;
+ }
+ case InstanceReference::Type::Collection: {
+ Collection &collection = reference.collection();
+ float4x4 offset_matrix = float4x4::identity();
+ sub_v3_v3(offset_matrix.values[3], collection.instance_offset);
+ int index = 0;
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (&collection, object) {
+ const GeometrySet object_geometry_set = object_get_evaluated_geometry_set(*object);
+ const float4x4 matrix = base_transform * offset_matrix * object->obmat;
+ const int sub_id = noise::hash(id, index);
+ fn(object_geometry_set, matrix, sub_id);
+ index++;
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+ break;
+ }
+ case InstanceReference::Type::GeometrySet: {
+ const GeometrySet &instance_geometry_set = reference.geometry_set();
+ fn(instance_geometry_set, base_transform, id);
+ break;
+ }
+ case InstanceReference::Type::None: {
+ break;
+ }
+ }
+}
+
+static void gather_realize_tasks_for_instances(GatherTasksInfo &gather_info,
+ const InstancesComponent &instances_component,
+ const float4x4 &base_transform,
+ const InstanceContext &base_instance_context)
+{
+ const Span<InstanceReference> references = instances_component.references();
+ const Span<int> handles = instances_component.instance_reference_handles();
+ const Span<float4x4> transforms = instances_component.instance_transforms();
+
+ Span<int> stored_instance_ids;
+ if (gather_info.create_id_attribute_on_any_component) {
+ std::optional<GSpan> ids = instances_component.attributes().get_for_read("id");
+ if (ids.has_value()) {
+ stored_instance_ids = ids->typed<int>();
+ }
+ }
+
+ /* Prepare attribute fallbacks. */
+ InstanceContext instance_context = base_instance_context;
+ Vector<std::pair<int, GSpan>> pointcloud_attributes_to_override = prepare_attribute_fallbacks(
+ gather_info, instances_component, gather_info.pointclouds.attributes);
+ Vector<std::pair<int, GSpan>> mesh_attributes_to_override = prepare_attribute_fallbacks(
+ gather_info, instances_component, gather_info.meshes.attributes);
+ Vector<std::pair<int, GSpan>> curve_attributes_to_override = prepare_attribute_fallbacks(
+ gather_info, instances_component, gather_info.curves.attributes);
+
+ for (const int i : transforms.index_range()) {
+ const int handle = handles[i];
+ const float4x4 &transform = transforms[i];
+ const InstanceReference &reference = references[handle];
+ const float4x4 new_base_transform = base_transform * transform;
+
+ /* Update attribute fallbacks for the current instance. */
+ for (const std::pair<int, GSpan> &pair : pointcloud_attributes_to_override) {
+ instance_context.pointclouds.array[pair.first] = pair.second[i];
+ }
+ for (const std::pair<int, GSpan> &pair : mesh_attributes_to_override) {
+ instance_context.meshes.array[pair.first] = pair.second[i];
+ }
+ for (const std::pair<int, GSpan> &pair : curve_attributes_to_override) {
+ instance_context.curves.array[pair.first] = pair.second[i];
+ }
+
+ uint32_t local_instance_id = 0;
+ if (gather_info.create_id_attribute_on_any_component) {
+ if (stored_instance_ids.is_empty()) {
+ local_instance_id = (uint32_t)i;
+ }
+ else {
+ local_instance_id = (uint32_t)stored_instance_ids[i];
+ }
+ }
+ const uint32_t instance_id = noise::hash(base_instance_context.id, local_instance_id);
+
+ /* Add realize tasks for all referenced geometry sets recursively. */
+ foreach_geometry_in_reference(reference,
+ new_base_transform,
+ instance_id,
+ [&](const GeometrySet &instance_geometry_set,
+ const float4x4 &transform,
+ const uint32_t id) {
+ instance_context.id = id;
+ gather_realize_tasks_recursive(gather_info,
+ instance_geometry_set,
+ transform,
+ instance_context);
+ });
+ }
+}
+
+/**
+ * Gather tasks for all geometries in the #geometry_set.
+ */
+static void gather_realize_tasks_recursive(GatherTasksInfo &gather_info,
+ const GeometrySet &geometry_set,
+ const float4x4 &base_transform,
+ const InstanceContext &base_instance_context)
+{
+ for (const GeometryComponent *component : geometry_set.get_components_for_read()) {
+ const GeometryComponentType type = component->type();
+ switch (type) {
+ case GEO_COMPONENT_TYPE_MESH: {
+ const MeshComponent &mesh_component = *static_cast<const MeshComponent *>(component);
+ const Mesh *mesh = mesh_component.get_for_read();
+ if (mesh != nullptr && mesh->totvert > 0) {
+ const int mesh_index = gather_info.meshes.order.index_of(mesh);
+ const MeshRealizeInfo &mesh_info = gather_info.meshes.realize_info[mesh_index];
+ gather_info.r_tasks.mesh_tasks.append({gather_info.r_offsets.mesh_offsets,
+ &mesh_info,
+ base_transform,
+ base_instance_context.meshes,
+ base_instance_context.id});
+ gather_info.r_offsets.mesh_offsets.vertex += mesh->totvert;
+ gather_info.r_offsets.mesh_offsets.edge += mesh->totedge;
+ gather_info.r_offsets.mesh_offsets.loop += mesh->totloop;
+ gather_info.r_offsets.mesh_offsets.poly += mesh->totpoly;
+ }
+ break;
+ }
+ case GEO_COMPONENT_TYPE_POINT_CLOUD: {
+ const PointCloudComponent &pointcloud_component =
+ *static_cast<const PointCloudComponent *>(component);
+ const PointCloud *pointcloud = pointcloud_component.get_for_read();
+ if (pointcloud != nullptr && pointcloud->totpoint > 0) {
+ const int pointcloud_index = gather_info.pointclouds.order.index_of(pointcloud);
+ const PointCloudRealizeInfo &pointcloud_info =
+ gather_info.pointclouds.realize_info[pointcloud_index];
+ gather_info.r_tasks.pointcloud_tasks.append({gather_info.r_offsets.pointcloud_offset,
+ &pointcloud_info,
+ base_transform,
+ base_instance_context.pointclouds,
+ base_instance_context.id});
+ gather_info.r_offsets.pointcloud_offset += pointcloud->totpoint;
+ }
+ break;
+ }
+ case GEO_COMPONENT_TYPE_CURVE: {
+ const CurveComponent &curve_component = *static_cast<const CurveComponent *>(component);
+ const CurveEval *curve = curve_component.get_for_read();
+ if (curve != nullptr && !curve->splines().is_empty()) {
+ const int curve_index = gather_info.curves.order.index_of(curve);
+ const RealizeCurveInfo &curve_info = gather_info.curves.realize_info[curve_index];
+ gather_info.r_tasks.curve_tasks.append({gather_info.r_offsets.spline_offset,
+ &curve_info,
+ base_transform,
+ base_instance_context.curves,
+ base_instance_context.id});
+ gather_info.r_offsets.spline_offset += curve->splines().size();
+ }
+ break;
+ }
+ case GEO_COMPONENT_TYPE_INSTANCES: {
+ const InstancesComponent &instances_component = *static_cast<const InstancesComponent *>(
+ component);
+ gather_realize_tasks_for_instances(
+ gather_info, instances_component, base_transform, base_instance_context);
+ break;
+ }
+ case GEO_COMPONENT_TYPE_VOLUME: {
+ const VolumeComponent *volume_component = static_cast<const VolumeComponent *>(component);
+ if (!gather_info.r_tasks.first_volume) {
+ volume_component->user_add();
+ gather_info.r_tasks.first_volume = const_cast<VolumeComponent *>(volume_component);
+ }
+ break;
+ }
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Point Cloud
+ * \{ */
+
+static OrderedAttributes gather_generic_pointcloud_attributes_to_propagate(
+ const GeometrySet &in_geometry_set, const RealizeInstancesOptions &options, bool &r_create_id)
+{
+ Vector<GeometryComponentType> src_component_types;
+ src_component_types.append(GEO_COMPONENT_TYPE_POINT_CLOUD);
+ if (options.realize_instance_attributes) {
+ src_component_types.append(GEO_COMPONENT_TYPE_INSTANCES);
+ }
+
+ Map<AttributeIDRef, AttributeKind> attributes_to_propagate;
+ in_geometry_set.gather_attributes_for_propagation(
+ src_component_types, GEO_COMPONENT_TYPE_POINT_CLOUD, true, attributes_to_propagate);
+ attributes_to_propagate.remove("position");
+ r_create_id = attributes_to_propagate.pop_try("id").has_value();
+ OrderedAttributes ordered_attributes;
+ for (const auto item : attributes_to_propagate.items()) {
+ ordered_attributes.ids.add_new(item.key);
+ ordered_attributes.kinds.append(item.value);
+ }
+ return ordered_attributes;
+}
+
+static void gather_pointclouds_to_realize(const GeometrySet &geometry_set,
+ VectorSet<const PointCloud *> &r_pointclouds)
+{
+ if (const PointCloud *pointcloud = geometry_set.get_pointcloud_for_read()) {
+ if (pointcloud->totpoint > 0) {
+ r_pointclouds.add(pointcloud);
+ }
+ }
+ if (const InstancesComponent *instances =
+ geometry_set.get_component_for_read<InstancesComponent>()) {
+ instances->foreach_referenced_geometry([&](const GeometrySet &instance_geometry_set) {
+ gather_pointclouds_to_realize(instance_geometry_set, r_pointclouds);
+ });
+ }
+}
+
+static AllPointCloudsInfo preprocess_pointclouds(const GeometrySet &geometry_set,
+ const RealizeInstancesOptions &options)
+{
+ AllPointCloudsInfo info;
+ info.attributes = gather_generic_pointcloud_attributes_to_propagate(
+ geometry_set, options, info.create_id_attribute);
+
+ gather_pointclouds_to_realize(geometry_set, info.order);
+ info.realize_info.reinitialize(info.order.size());
+ for (const int pointcloud_index : info.realize_info.index_range()) {
+ PointCloudRealizeInfo &pointcloud_info = info.realize_info[pointcloud_index];
+ const PointCloud *pointcloud = info.order[pointcloud_index];
+ pointcloud_info.pointcloud = pointcloud;
+
+ /* Access attributes. */
+ PointCloudComponent component;
+ component.replace(const_cast<PointCloud *>(pointcloud), GeometryOwnershipType::ReadOnly);
+ pointcloud_info.attributes.reinitialize(info.attributes.size());
+ for (const int attribute_index : info.attributes.index_range()) {
+ const AttributeIDRef &attribute_id = info.attributes.ids[attribute_index];
+ const CustomDataType data_type = info.attributes.kinds[attribute_index].data_type;
+ const AttributeDomain domain = info.attributes.kinds[attribute_index].domain;
+ if (component.attribute_exists(attribute_id)) {
+ GVArray attribute = component.attribute_get_for_read(attribute_id, domain, data_type);
+ pointcloud_info.attributes[attribute_index].emplace(std::move(attribute));
+ }
+ }
+ if (info.create_id_attribute) {
+ ReadAttributeLookup ids_lookup = component.attribute_try_get_for_read("id");
+ if (ids_lookup) {
+ pointcloud_info.stored_ids = ids_lookup.varray.get_internal_span().typed<int>();
+ }
+ }
+ }
+ return info;
+}
+
+static void execute_realize_pointcloud_task(const RealizeInstancesOptions &options,
+ const RealizePointCloudTask &task,
+ PointCloud &dst_pointcloud,
+ MutableSpan<GMutableSpan> dst_attribute_spans,
+ MutableSpan<int> all_dst_ids)
+{
+ const PointCloudRealizeInfo &pointcloud_info = *task.pointcloud_info;
+ const PointCloud &pointcloud = *pointcloud_info.pointcloud;
+ const Span<float3> src_positions{(float3 *)pointcloud.co, pointcloud.totpoint};
+ const IndexRange point_slice{task.start_index, pointcloud.totpoint};
+ MutableSpan<float3> dst_positions{(float3 *)dst_pointcloud.co + task.start_index,
+ pointcloud.totpoint};
+ MutableSpan<int> dst_ids = all_dst_ids.slice(task.start_index, pointcloud.totpoint);
+
+ /* Copy transformed positions. */
+ threading::parallel_for(IndexRange(pointcloud.totpoint), 1024, [&](const IndexRange range) {
+ for (const int i : range) {
+ dst_positions[i] = task.transform * src_positions[i];
+ }
+ });
+ /* Create point ids. */
+ if (!all_dst_ids.is_empty()) {
+ if (options.keep_original_ids) {
+ if (pointcloud_info.stored_ids.is_empty()) {
+ dst_ids.fill(0);
+ }
+ else {
+ dst_ids.copy_from(pointcloud_info.stored_ids);
+ }
+ }
+ else {
+ threading::parallel_for(IndexRange(pointcloud.totpoint), 1024, [&](const IndexRange range) {
+ if (pointcloud_info.stored_ids.is_empty()) {
+ for (const int i : range) {
+ dst_ids[i] = noise::hash(task.id, i);
+ }
+ }
+ else {
+ for (const int i : range) {
+ dst_ids[i] = noise::hash(task.id, pointcloud_info.stored_ids[i]);
+ }
+ }
+ });
+ }
+ }
+ /* Copy generic attributes. */
+ threading::parallel_for(
+ dst_attribute_spans.index_range(), 10, [&](const IndexRange attribute_range) {
+ for (const int attribute_index : attribute_range) {
+ GMutableSpan dst_span = dst_attribute_spans[attribute_index].slice(point_slice);
+ const CPPType &cpp_type = dst_span.type();
+ const void *attribute_fallback = task.attribute_fallbacks.array[attribute_index];
+ if (pointcloud_info.attributes[attribute_index].has_value()) {
+ /* Copy attribute from the original point cloud. */
+ const GSpan src_span = *pointcloud_info.attributes[attribute_index];
+ threading::parallel_for(
+ IndexRange(pointcloud.totpoint), 1024, [&](const IndexRange range) {
+ cpp_type.copy_assign_n(
+ src_span.slice(range).data(), dst_span.slice(range).data(), range.size());
+ });
+ }
+ else {
+ if (attribute_fallback == nullptr) {
+ attribute_fallback = cpp_type.default_value();
+ }
+ /* As the fallback value for the attribute. */
+ threading::parallel_for(
+ IndexRange(pointcloud.totpoint), 1024, [&](const IndexRange range) {
+ cpp_type.fill_assign_n(
+ attribute_fallback, dst_span.slice(range).data(), range.size());
+ });
+ }
+ }
+ });
+}
+
+static void execute_realize_pointcloud_tasks(const RealizeInstancesOptions &options,
+ const AllPointCloudsInfo &all_pointclouds_info,
+ const Span<RealizePointCloudTask> tasks,
+ const OrderedAttributes &ordered_attributes,
+ GeometrySet &r_realized_geometry)
+{
+ if (tasks.is_empty()) {
+ return;
+ }
+
+ const RealizePointCloudTask &last_task = tasks.last();
+ const PointCloud &last_pointcloud = *last_task.pointcloud_info->pointcloud;
+ const int tot_points = last_task.start_index + last_pointcloud.totpoint;
+
+ /* Allocate new point cloud. */
+ PointCloud *dst_pointcloud = BKE_pointcloud_new_nomain(tot_points);
+ PointCloudComponent &dst_component =
+ r_realized_geometry.get_component_for_write<PointCloudComponent>();
+ dst_component.replace(dst_pointcloud);
+
+ /* Prepare id attribute. */
+ OutputAttribute_Typed<int> point_ids;
+ MutableSpan<int> point_ids_span;
+ if (all_pointclouds_info.create_id_attribute) {
+ point_ids = dst_component.attribute_try_get_for_output_only<int>("id", ATTR_DOMAIN_POINT);
+ point_ids_span = point_ids.as_span();
+ }
+
+ /* Prepare generic output attributes. */
+ Vector<OutputAttribute> dst_attributes;
+ Vector<GMutableSpan> dst_attribute_spans;
+ for (const int attribute_index : ordered_attributes.index_range()) {
+ const AttributeIDRef &attribute_id = ordered_attributes.ids[attribute_index];
+ const CustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type;
+ OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
+ attribute_id, ATTR_DOMAIN_POINT, data_type);
+ dst_attribute_spans.append(dst_attribute.as_span());
+ dst_attributes.append(std::move(dst_attribute));
+ }
+
+ /* Actually execute all tasks. */
+ threading::parallel_for(tasks.index_range(), 100, [&](const IndexRange task_range) {
+ for (const int task_index : task_range) {
+ const RealizePointCloudTask &task = tasks[task_index];
+ execute_realize_pointcloud_task(
+ options, task, *dst_pointcloud, dst_attribute_spans, point_ids_span);
+ }
+ });
+
+ /* Save modified attributes. */
+ for (OutputAttribute &dst_attribute : dst_attributes) {
+ dst_attribute.save();
+ }
+ if (point_ids) {
+ point_ids.save();
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Mesh
+ * \{ */
+
+static OrderedAttributes gather_generic_mesh_attributes_to_propagate(
+ const GeometrySet &in_geometry_set, const RealizeInstancesOptions &options, bool &r_create_id)
+{
+ Vector<GeometryComponentType> src_component_types;
+ src_component_types.append(GEO_COMPONENT_TYPE_MESH);
+ if (options.realize_instance_attributes) {
+ src_component_types.append(GEO_COMPONENT_TYPE_INSTANCES);
+ }
+
+ Map<AttributeIDRef, AttributeKind> attributes_to_propagate;
+ in_geometry_set.gather_attributes_for_propagation(
+ src_component_types, GEO_COMPONENT_TYPE_MESH, true, attributes_to_propagate);
+ attributes_to_propagate.remove("position");
+ attributes_to_propagate.remove("normal");
+ attributes_to_propagate.remove("material_index");
+ attributes_to_propagate.remove("shade_smooth");
+ attributes_to_propagate.remove("crease");
+ r_create_id = attributes_to_propagate.pop_try("id").has_value();
+ OrderedAttributes ordered_attributes;
+ for (const auto item : attributes_to_propagate.items()) {
+ ordered_attributes.ids.add_new(item.key);
+ ordered_attributes.kinds.append(item.value);
+ }
+ return ordered_attributes;
+}
+
+static void gather_meshes_to_realize(const GeometrySet &geometry_set,
+ VectorSet<const Mesh *> &r_meshes)
+{
+ if (const Mesh *mesh = geometry_set.get_mesh_for_read()) {
+ if (mesh->totvert > 0) {
+ r_meshes.add(mesh);
+ }
+ }
+ if (const InstancesComponent *instances =
+ geometry_set.get_component_for_read<InstancesComponent>()) {
+ instances->foreach_referenced_geometry([&](const GeometrySet &instance_geometry_set) {
+ gather_meshes_to_realize(instance_geometry_set, r_meshes);
+ });
+ }
+}
+
+static AllMeshesInfo preprocess_meshes(const GeometrySet &geometry_set,
+ const RealizeInstancesOptions &options)
+{
+ AllMeshesInfo info;
+ info.attributes = gather_generic_mesh_attributes_to_propagate(
+ geometry_set, options, info.create_id_attribute);
+
+ gather_meshes_to_realize(geometry_set, info.order);
+ for (const Mesh *mesh : info.order) {
+ for (const int slot_index : IndexRange(mesh->totcol)) {
+ Material *material = mesh->mat[slot_index];
+ info.materials.add(material);
+ }
+ }
+ info.realize_info.reinitialize(info.order.size());
+ for (const int mesh_index : info.realize_info.index_range()) {
+ MeshRealizeInfo &mesh_info = info.realize_info[mesh_index];
+ const Mesh *mesh = info.order[mesh_index];
+ mesh_info.mesh = mesh;
+
+ /* Create material index mapping. */
+ mesh_info.material_index_map.reinitialize(mesh->totcol);
+ for (const int old_slot_index : IndexRange(mesh->totcol)) {
+ Material *material = mesh->mat[old_slot_index];
+ const int new_slot_index = info.materials.index_of(material);
+ mesh_info.material_index_map[old_slot_index] = new_slot_index;
+ }
+
+ /* Access attributes. */
+ MeshComponent component;
+ component.replace(const_cast<Mesh *>(mesh), GeometryOwnershipType::ReadOnly);
+ mesh_info.attributes.reinitialize(info.attributes.size());
+ for (const int attribute_index : info.attributes.index_range()) {
+ const AttributeIDRef &attribute_id = info.attributes.ids[attribute_index];
+ const CustomDataType data_type = info.attributes.kinds[attribute_index].data_type;
+ const AttributeDomain domain = info.attributes.kinds[attribute_index].domain;
+ if (component.attribute_exists(attribute_id)) {
+ GVArray attribute = component.attribute_get_for_read(attribute_id, domain, data_type);
+ mesh_info.attributes[attribute_index].emplace(std::move(attribute));
+ }
+ }
+ if (info.create_id_attribute) {
+ ReadAttributeLookup ids_lookup = component.attribute_try_get_for_read("id");
+ if (ids_lookup) {
+ mesh_info.stored_vertex_ids = ids_lookup.varray.get_internal_span().typed<int>();
+ }
+ }
+ }
+ return info;
+}
+
+static void execute_realize_mesh_task(const RealizeInstancesOptions &options,
+ const RealizeMeshTask &task,
+ const OrderedAttributes &ordered_attributes,
+ Mesh &dst_mesh,
+ MutableSpan<GMutableSpan> dst_attribute_spans,
+ MutableSpan<int> all_dst_vertex_ids)
+{
+ const MeshRealizeInfo &mesh_info = *task.mesh_info;
+ const Mesh &mesh = *mesh_info.mesh;
+
+ const Span<MVert> src_verts{mesh.mvert, mesh.totvert};
+ const Span<MEdge> src_edges{mesh.medge, mesh.totedge};
+ const Span<MLoop> src_loops{mesh.mloop, mesh.totloop};
+ const Span<MPoly> src_polys{mesh.mpoly, mesh.totpoly};
+
+ MutableSpan<MVert> dst_verts{dst_mesh.mvert + task.start_indices.vertex, mesh.totvert};
+ MutableSpan<MEdge> dst_edges{dst_mesh.medge + task.start_indices.edge, mesh.totedge};
+ MutableSpan<MLoop> dst_loops{dst_mesh.mloop + task.start_indices.loop, mesh.totloop};
+ MutableSpan<MPoly> dst_polys{dst_mesh.mpoly + task.start_indices.poly, mesh.totpoly};
+
+ MutableSpan<int> dst_vertex_ids = all_dst_vertex_ids.slice(task.start_indices.vertex,
+ mesh.totvert);
+
+ const Span<int> material_index_map = mesh_info.material_index_map;
+
+ threading::parallel_for(IndexRange(mesh.totvert), 1024, [&](const IndexRange vert_range) {
+ for (const int i : vert_range) {
+ const MVert &src_vert = src_verts[i];
+ MVert &dst_vert = dst_verts[i];
+ dst_vert = src_vert;
+ copy_v3_v3(dst_vert.co, task.transform * float3(src_vert.co));
+ }
+ });
+ threading::parallel_for(IndexRange(mesh.totedge), 1024, [&](const IndexRange edge_range) {
+ for (const int i : edge_range) {
+ const MEdge &src_edge = src_edges[i];
+ MEdge &dst_edge = dst_edges[i];
+ dst_edge = src_edge;
+ dst_edge.v1 += task.start_indices.vertex;
+ dst_edge.v2 += task.start_indices.vertex;
+ }
+ });
+ threading::parallel_for(IndexRange(mesh.totloop), 1024, [&](const IndexRange loop_range) {
+ for (const int i : loop_range) {
+ const MLoop &src_loop = src_loops[i];
+ MLoop &dst_loop = dst_loops[i];
+ dst_loop = src_loop;
+ dst_loop.v += task.start_indices.vertex;
+ dst_loop.e += task.start_indices.edge;
+ }
+ });
+ threading::parallel_for(IndexRange(mesh.totpoly), 1024, [&](const IndexRange poly_range) {
+ for (const int i : poly_range) {
+ const MPoly &src_poly = src_polys[i];
+ MPoly &dst_poly = dst_polys[i];
+ dst_poly = src_poly;
+ dst_poly.loopstart += task.start_indices.loop;
+ if (src_poly.mat_nr >= 0 && src_poly.mat_nr < mesh.totcol) {
+ dst_poly.mat_nr = material_index_map[src_poly.mat_nr];
+ }
+ else {
+ /* The material index was invalid before. */
+ dst_poly.mat_nr = 0;
+ }
+ }
+ });
+ /* Create id attribute. */
+ if (!all_dst_vertex_ids.is_empty()) {
+ if (options.keep_original_ids) {
+ if (mesh_info.stored_vertex_ids.is_empty()) {
+ dst_vertex_ids.fill(0);
+ }
+ else {
+ dst_vertex_ids.copy_from(mesh_info.stored_vertex_ids);
+ }
+ }
+ else {
+ threading::parallel_for(IndexRange(mesh.totvert), 1024, [&](const IndexRange vert_range) {
+ if (mesh_info.stored_vertex_ids.is_empty()) {
+ for (const int i : vert_range) {
+ dst_vertex_ids[i] = noise::hash(task.id, i);
+ }
+ }
+ else {
+ for (const int i : vert_range) {
+ const int original_id = mesh_info.stored_vertex_ids[i];
+ dst_vertex_ids[i] = noise::hash(task.id, original_id);
+ }
+ }
+ });
+ }
+ }
+ /* Copy generic attributes. */
+ threading::parallel_for(
+ dst_attribute_spans.index_range(), 10, [&](const IndexRange attribute_range) {
+ for (const int attribute_index : attribute_range) {
+ const AttributeDomain domain = ordered_attributes.kinds[attribute_index].domain;
+ IndexRange element_slice;
+ switch (domain) {
+ case ATTR_DOMAIN_POINT:
+ element_slice = IndexRange(task.start_indices.vertex, mesh.totvert);
+ break;
+ case ATTR_DOMAIN_EDGE:
+ element_slice = IndexRange(task.start_indices.edge, mesh.totedge);
+ break;
+ case ATTR_DOMAIN_CORNER:
+ element_slice = IndexRange(task.start_indices.loop, mesh.totloop);
+ break;
+ case ATTR_DOMAIN_FACE:
+ element_slice = IndexRange(task.start_indices.poly, mesh.totpoly);
+ break;
+ default:
+ BLI_assert_unreachable();
+ }
+ GMutableSpan dst_span = dst_attribute_spans[attribute_index].slice(element_slice);
+ const CPPType &cpp_type = dst_span.type();
+ const void *attribute_fallback = task.attribute_fallbacks.array[attribute_index];
+ if (mesh_info.attributes[attribute_index].has_value()) {
+ const GSpan src_span = *mesh_info.attributes[attribute_index];
+ threading::parallel_for(
+ IndexRange(element_slice.size()), 1024, [&](const IndexRange sub_range) {
+ cpp_type.copy_assign_n(src_span.slice(sub_range).data(),
+ dst_span.slice(sub_range).data(),
+ sub_range.size());
+ });
+ }
+ else {
+ if (attribute_fallback == nullptr) {
+ attribute_fallback = cpp_type.default_value();
+ }
+ threading::parallel_for(
+ IndexRange(element_slice.size()), 1024, [&](const IndexRange sub_range) {
+ cpp_type.fill_assign_n(
+ attribute_fallback, dst_span.slice(sub_range).data(), sub_range.size());
+ });
+ }
+ }
+ });
+}
+
+static void execute_realize_mesh_tasks(const RealizeInstancesOptions &options,
+ const AllMeshesInfo &all_meshes_info,
+ const Span<RealizeMeshTask> tasks,
+ const OrderedAttributes &ordered_attributes,
+ const VectorSet<Material *> &ordered_materials,
+ GeometrySet &r_realized_geometry)
+{
+ if (tasks.is_empty()) {
+ return;
+ }
+
+ const RealizeMeshTask &last_task = tasks.last();
+ const Mesh &last_mesh = *last_task.mesh_info->mesh;
+ const int tot_vertices = last_task.start_indices.vertex + last_mesh.totvert;
+ const int tot_edges = last_task.start_indices.edge + last_mesh.totedge;
+ const int tot_loops = last_task.start_indices.loop + last_mesh.totloop;
+ const int tot_poly = last_task.start_indices.poly + last_mesh.totpoly;
+
+ Mesh *dst_mesh = BKE_mesh_new_nomain(tot_vertices, tot_edges, 0, tot_loops, tot_poly);
+ MeshComponent &dst_component = r_realized_geometry.get_component_for_write<MeshComponent>();
+ dst_component.replace(dst_mesh);
+
+ /* Copy settings from the first input geometry set with a mesh. */
+ const RealizeMeshTask &first_task = tasks.first();
+ const Mesh &first_mesh = *first_task.mesh_info->mesh;
+ BKE_mesh_copy_parameters_for_eval(dst_mesh, &first_mesh);
+
+ /* Add materials. */
+ for (const int i : IndexRange(ordered_materials.size())) {
+ Material *material = ordered_materials[i];
+ BKE_id_material_eval_assign(&dst_mesh->id, i + 1, material);
+ }
+
+ /* Prepare id attribute. */
+ OutputAttribute_Typed<int> vertex_ids;
+ MutableSpan<int> vertex_ids_span;
+ if (all_meshes_info.create_id_attribute) {
+ vertex_ids = dst_component.attribute_try_get_for_output_only<int>("id", ATTR_DOMAIN_POINT);
+ vertex_ids_span = vertex_ids.as_span();
+ }
+
+ /* Prepare generic output attributes. */
+ Vector<OutputAttribute> dst_attributes;
+ Vector<GMutableSpan> dst_attribute_spans;
+ for (const int attribute_index : ordered_attributes.index_range()) {
+ const AttributeIDRef &attribute_id = ordered_attributes.ids[attribute_index];
+ const AttributeDomain domain = ordered_attributes.kinds[attribute_index].domain;
+ const CustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type;
+ OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
+ attribute_id, domain, data_type);
+ dst_attribute_spans.append(dst_attribute.as_span());
+ dst_attributes.append(std::move(dst_attribute));
+ }
+
+ /* Actually execute all tasks. */
+ threading::parallel_for(tasks.index_range(), 100, [&](const IndexRange task_range) {
+ for (const int task_index : task_range) {
+ const RealizeMeshTask &task = tasks[task_index];
+ execute_realize_mesh_task(
+ options, task, ordered_attributes, *dst_mesh, dst_attribute_spans, vertex_ids_span);
+ }
+ });
+
+ /* Save modified attributes. */
+ for (OutputAttribute &dst_attribute : dst_attributes) {
+ dst_attribute.save();
+ }
+ if (vertex_ids) {
+ vertex_ids.save();
+ }
+
+ BKE_mesh_normals_tag_dirty(dst_mesh);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Curve
+ * \{ */
+
+static OrderedAttributes gather_generic_curve_attributes_to_propagate(
+ const GeometrySet &in_geometry_set, const RealizeInstancesOptions &options, bool &r_create_id)
+{
+ Vector<GeometryComponentType> src_component_types;
+ src_component_types.append(GEO_COMPONENT_TYPE_CURVE);
+ if (options.realize_instance_attributes) {
+ src_component_types.append(GEO_COMPONENT_TYPE_INSTANCES);
+ }
+
+ Map<AttributeIDRef, AttributeKind> attributes_to_propagate;
+ in_geometry_set.gather_attributes_for_propagation(
+ src_component_types, GEO_COMPONENT_TYPE_CURVE, true, attributes_to_propagate);
+ attributes_to_propagate.remove("position");
+ attributes_to_propagate.remove("cyclic");
+ attributes_to_propagate.remove("resolution");
+ attributes_to_propagate.remove("tilt");
+ attributes_to_propagate.remove("radius");
+ attributes_to_propagate.remove("handle_right");
+ attributes_to_propagate.remove("handle_left");
+ r_create_id = attributes_to_propagate.pop_try("id").has_value();
+ OrderedAttributes ordered_attributes;
+ for (const auto item : attributes_to_propagate.items()) {
+ ordered_attributes.ids.add_new(item.key);
+ ordered_attributes.kinds.append(item.value);
+ }
+ return ordered_attributes;
+}
+
+static void gather_curves_to_realize(const GeometrySet &geometry_set,
+ VectorSet<const CurveEval *> &r_curves)
+{
+ if (const CurveEval *curve = geometry_set.get_curve_for_read()) {
+ if (!curve->splines().is_empty()) {
+ r_curves.add(curve);
+ }
+ }
+ if (const InstancesComponent *instances =
+ geometry_set.get_component_for_read<InstancesComponent>()) {
+ instances->foreach_referenced_geometry([&](const GeometrySet &instance_geometry_set) {
+ gather_curves_to_realize(instance_geometry_set, r_curves);
+ });
+ }
+}
+
+static AllCurvesInfo preprocess_curves(const GeometrySet &geometry_set,
+ const RealizeInstancesOptions &options)
+{
+ AllCurvesInfo info;
+ info.attributes = gather_generic_curve_attributes_to_propagate(
+ geometry_set, options, info.create_id_attribute);
+
+ gather_curves_to_realize(geometry_set, info.order);
+ info.realize_info.reinitialize(info.order.size());
+ for (const int curve_index : info.realize_info.index_range()) {
+ RealizeCurveInfo &curve_info = info.realize_info[curve_index];
+ const CurveEval *curve = info.order[curve_index];
+ curve_info.curve = curve;
+
+ /* Access attributes. */
+ CurveComponent component;
+ component.replace(const_cast<CurveEval *>(curve), GeometryOwnershipType::ReadOnly);
+ curve_info.spline_attributes.reinitialize(info.attributes.size());
+ for (const int attribute_index : info.attributes.index_range()) {
+ const AttributeDomain domain = info.attributes.kinds[attribute_index].domain;
+ if (domain != ATTR_DOMAIN_CURVE) {
+ continue;
+ }
+ const AttributeIDRef &attribute_id = info.attributes.ids[attribute_index];
+ const CustomDataType data_type = info.attributes.kinds[attribute_index].data_type;
+ if (component.attribute_exists(attribute_id)) {
+ GVArray attribute = component.attribute_get_for_read(attribute_id, domain, data_type);
+ curve_info.spline_attributes[attribute_index].emplace(std::move(attribute));
+ }
+ }
+ }
+ return info;
+}
+
+static void execute_realize_curve_task(const RealizeInstancesOptions &options,
+ const AllCurvesInfo &all_curves_info,
+ const RealizeCurveTask &task,
+ const OrderedAttributes &ordered_attributes,
+ MutableSpan<SplinePtr> dst_splines,
+ MutableSpan<GMutableSpan> dst_spline_attributes)
+{
+ const RealizeCurveInfo &curve_info = *task.curve_info;
+ const CurveEval &curve = *curve_info.curve;
+
+ const Span<SplinePtr> src_splines = curve.splines();
+
+ /* Initialize point attributes. */
+ threading::parallel_for(src_splines.index_range(), 100, [&](const IndexRange src_spline_range) {
+ for (const int src_spline_index : src_spline_range) {
+ const int dst_spline_index = src_spline_index + task.start_spline_index;
+ const Spline &src_spline = *src_splines[src_spline_index];
+ SplinePtr dst_spline = src_spline.copy_without_attributes();
+ dst_spline->transform(task.transform);
+ const int spline_size = dst_spline->size();
+
+ const CustomDataAttributes &src_point_attributes = src_spline.attributes;
+ CustomDataAttributes &dst_point_attributes = dst_spline->attributes;
+
+ /* Create point ids. */
+ if (all_curves_info.create_id_attribute) {
+ dst_point_attributes.create("id", CD_PROP_INT32);
+ MutableSpan<int> dst_point_ids = dst_point_attributes.get_for_write("id")->typed<int>();
+ std::optional<GSpan> src_point_ids_opt = src_point_attributes.get_for_read("id");
+ if (options.keep_original_ids) {
+ if (src_point_ids_opt.has_value()) {
+ const Span<int> src_point_ids = src_point_ids_opt->typed<int>();
+ dst_point_ids.copy_from(src_point_ids);
+ }
+ else {
+ dst_point_ids.fill(0);
+ }
+ }
+ else {
+ if (src_point_ids_opt.has_value()) {
+ const Span<int> src_point_ids = src_point_ids_opt->typed<int>();
+ for (const int i : IndexRange(dst_spline->size())) {
+ dst_point_ids[i] = noise::hash(task.id, src_point_ids[i]);
+ }
+ }
+ else {
+ for (const int i : IndexRange(dst_spline->size())) {
+ /* Mix spline index into the id, because otherwise points on different splines will
+ * get the same id. */
+ dst_point_ids[i] = noise::hash(task.id, src_spline_index, i);
+ }
+ }
+ }
+ }
+
+ /* Copy generic point attributes. */
+ for (const int attribute_index : ordered_attributes.index_range()) {
+ const AttributeDomain domain = ordered_attributes.kinds[attribute_index].domain;
+ if (domain != ATTR_DOMAIN_POINT) {
+ continue;
+ }
+ const CustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type;
+ const CPPType &cpp_type = *custom_data_type_to_cpp_type(data_type);
+ const AttributeIDRef &attribute_id = ordered_attributes.ids[attribute_index];
+ const void *attribute_fallback = task.attribute_fallbacks.array[attribute_index];
+ const std::optional<GSpan> src_span_opt = src_point_attributes.get_for_read(attribute_id);
+ void *dst_buffer = MEM_malloc_arrayN(spline_size, cpp_type.size(), __func__);
+ if (src_span_opt.has_value()) {
+ const GSpan src_span = *src_span_opt;
+ cpp_type.copy_construct_n(src_span.data(), dst_buffer, spline_size);
+ }
+ else {
+ if (attribute_fallback == nullptr) {
+ attribute_fallback = cpp_type.default_value();
+ }
+ cpp_type.fill_construct_n(attribute_fallback, dst_buffer, spline_size);
+ }
+ dst_point_attributes.create_by_move(attribute_id, data_type, dst_buffer);
+ }
+
+ dst_splines[dst_spline_index] = std::move(dst_spline);
+ }
+ });
+ /* Initialize spline attributes. */
+ for (const int attribute_index : ordered_attributes.index_range()) {
+ const AttributeDomain domain = ordered_attributes.kinds[attribute_index].domain;
+ if (domain != ATTR_DOMAIN_CURVE) {
+ continue;
+ }
+ const CustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type;
+ const CPPType &cpp_type = *custom_data_type_to_cpp_type(data_type);
+
+ GMutableSpan dst_span = dst_spline_attributes[attribute_index].slice(task.start_spline_index,
+ src_splines.size());
+ if (curve_info.spline_attributes[attribute_index].has_value()) {
+ const GSpan src_span = *curve_info.spline_attributes[attribute_index];
+ cpp_type.copy_construct_n(src_span.data(), dst_span.data(), src_splines.size());
+ }
+ else {
+ const void *attribute_fallback = task.attribute_fallbacks.array[attribute_index];
+ if (attribute_fallback == nullptr) {
+ attribute_fallback = cpp_type.default_value();
+ }
+ cpp_type.fill_construct_n(attribute_fallback, dst_span.data(), src_splines.size());
+ }
+ }
+}
+
+static void execute_realize_curve_tasks(const RealizeInstancesOptions &options,
+ const AllCurvesInfo &all_curves_info,
+ const Span<RealizeCurveTask> tasks,
+ const OrderedAttributes &ordered_attributes,
+ GeometrySet &r_realized_geometry)
+{
+ if (tasks.is_empty()) {
+ return;
+ }
+
+ const RealizeCurveTask &last_task = tasks.last();
+ const CurveEval &last_curve = *last_task.curve_info->curve;
+ const int tot_splines = last_task.start_spline_index + last_curve.splines().size();
+
+ Array<SplinePtr> dst_splines(tot_splines);
+
+ CurveEval *dst_curve = new CurveEval();
+ dst_curve->attributes.reallocate(tot_splines);
+ CustomDataAttributes &spline_attributes = dst_curve->attributes;
+
+ /* Prepare spline attributes. */
+ Vector<GMutableSpan> dst_spline_attributes;
+ for (const int attribute_index : ordered_attributes.index_range()) {
+ const AttributeIDRef &attribute_id = ordered_attributes.ids[attribute_index];
+ const CustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type;
+ const AttributeDomain domain = ordered_attributes.kinds[attribute_index].domain;
+ if (domain == ATTR_DOMAIN_CURVE) {
+ spline_attributes.create(attribute_id, data_type);
+ dst_spline_attributes.append(*spline_attributes.get_for_write(attribute_id));
+ }
+ else {
+ dst_spline_attributes.append({CPPType::get<float>()});
+ }
+ }
+
+ /* Actually execute all tasks. */
+ threading::parallel_for(tasks.index_range(), 100, [&](const IndexRange task_range) {
+ for (const int task_index : task_range) {
+ const RealizeCurveTask &task = tasks[task_index];
+ execute_realize_curve_task(
+ options, all_curves_info, task, ordered_attributes, dst_splines, dst_spline_attributes);
+ }
+ });
+
+ dst_curve->add_splines(dst_splines);
+
+ CurveComponent &dst_component = r_realized_geometry.get_component_for_write<CurveComponent>();
+ dst_component.replace(dst_curve);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Realize Instances
+ * \{ */
+
+static void remove_id_attribute_from_instances(GeometrySet &geometry_set)
+{
+ geometry_set.modify_geometry_sets([&](GeometrySet &sub_geometry) {
+ if (sub_geometry.has<InstancesComponent>()) {
+ InstancesComponent &component = geometry_set.get_component_for_write<InstancesComponent>();
+ component.attributes().remove("id");
+ }
+ });
+}
+
+GeometrySet realize_instances(GeometrySet geometry_set, const RealizeInstancesOptions &options)
+{
+ /* The algorithm works in three steps:
+ * 1. Preprocess each unique geometry that is instanced (e.g. each `Mesh`).
+ * 2. Gather "tasks" that need to be executed to realize the instances. Each task corresponds to
+ * instances of the previously preprocessed geometry.
+ * 3. Execute all tasks in parallel.
+ */
+
+ if (!geometry_set.has_instances()) {
+ return geometry_set;
+ }
+
+ if (options.keep_original_ids) {
+ remove_id_attribute_from_instances(geometry_set);
+ }
+
+ AllPointCloudsInfo all_pointclouds_info = preprocess_pointclouds(geometry_set, options);
+ AllMeshesInfo all_meshes_info = preprocess_meshes(geometry_set, options);
+ AllCurvesInfo all_curves_info = preprocess_curves(geometry_set, options);
+
+ Vector<std::unique_ptr<GArray<>>> temporary_arrays;
+ const bool create_id_attribute = all_pointclouds_info.create_id_attribute ||
+ all_meshes_info.create_id_attribute ||
+ all_curves_info.create_id_attribute;
+ GatherTasksInfo gather_info = {all_pointclouds_info,
+ all_meshes_info,
+ all_curves_info,
+ create_id_attribute,
+ temporary_arrays};
+ const float4x4 transform = float4x4::identity();
+ InstanceContext attribute_fallbacks(gather_info);
+ gather_realize_tasks_recursive(gather_info, geometry_set, transform, attribute_fallbacks);
+
+ GeometrySet new_geometry_set;
+ execute_realize_pointcloud_tasks(options,
+ all_pointclouds_info,
+ gather_info.r_tasks.pointcloud_tasks,
+ all_pointclouds_info.attributes,
+ new_geometry_set);
+ execute_realize_mesh_tasks(options,
+ all_meshes_info,
+ gather_info.r_tasks.mesh_tasks,
+ all_meshes_info.attributes,
+ all_meshes_info.materials,
+ new_geometry_set);
+ execute_realize_curve_tasks(options,
+ all_curves_info,
+ gather_info.r_tasks.curve_tasks,
+ all_curves_info.attributes,
+ new_geometry_set);
+
+ if (gather_info.r_tasks.first_volume) {
+ new_geometry_set.add(*gather_info.r_tasks.first_volume);
+ }
+
+ return new_geometry_set;
+}
+
+GeometrySet realize_instances_legacy(GeometrySet geometry_set)
+{
+ RealizeInstancesOptions options;
+ options.keep_original_ids = true;
+ options.realize_instance_attributes = false;
+ return realize_instances(std::move(geometry_set), options);
+}
+
+/** \} */
+
+} // namespace blender::geometry
diff --git a/source/blender/gpencil_modifiers/CMakeLists.txt b/source/blender/gpencil_modifiers/CMakeLists.txt
index afcd551d0af..5ee75619259 100644
--- a/source/blender/gpencil_modifiers/CMakeLists.txt
+++ b/source/blender/gpencil_modifiers/CMakeLists.txt
@@ -62,6 +62,7 @@ set(SRC
intern/MOD_gpencilnoise.c
intern/MOD_gpenciloffset.c
intern/MOD_gpencilopacity.c
+ intern/MOD_gpencilshrinkwrap.c
intern/MOD_gpencilsimplify.c
intern/MOD_gpencilsmooth.c
intern/MOD_gpencilsubdiv.c
diff --git a/source/blender/gpencil_modifiers/MOD_gpencil_lineart.h b/source/blender/gpencil_modifiers/MOD_gpencil_lineart.h
index 7d75ed5804e..95028ee959d 100644
--- a/source/blender/gpencil_modifiers/MOD_gpencil_lineart.h
+++ b/source/blender/gpencil_modifiers/MOD_gpencil_lineart.h
@@ -23,6 +23,7 @@
#include "DNA_windowmanager_types.h"
/* Operator types should be in exposed header. */
+
void OBJECT_OT_lineart_bake_strokes(struct wmOperatorType *ot);
void OBJECT_OT_lineart_bake_strokes_all(struct wmOperatorType *ot);
void OBJECT_OT_lineart_clear(struct wmOperatorType *ot);
diff --git a/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h b/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h
index d9285f44a37..56cee115760 100644
--- a/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h
+++ b/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h
@@ -48,6 +48,7 @@ extern GpencilModifierTypeInfo modifierType_Gpencil_WeightProximity;
extern GpencilModifierTypeInfo modifierType_Gpencil_WeightAngle;
extern GpencilModifierTypeInfo modifierType_Gpencil_Lineart;
extern GpencilModifierTypeInfo modifierType_Gpencil_Dash;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Shrinkwrap;
/* MOD_gpencil_util.c */
void gpencil_modifier_type_init(GpencilModifierTypeInfo *types[]);
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c b/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c
index 2e241ea5848..fe78a7e7bcc 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c
@@ -203,9 +203,6 @@ void gpencil_modifier_curve_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiTemplateCurveMapping(layout, ptr, "curve", 0, false, false, false, false);
}
-/**
- * Draw modifier error message.
- */
void gpencil_modifier_panel_end(uiLayout *layout, PointerRNA *ptr)
{
GpencilModifierData *md = ptr->data;
@@ -232,7 +229,7 @@ PointerRNA *gpencil_modifier_panel_get_property_pointers(Panel *panel, PointerRN
UI_block_lock_clear(block);
UI_block_lock_set(block, ID_IS_LINKED((Object *)ptr->owner_id), ERROR_LIBDATA_MESSAGE);
- uiLayoutSetContextPointer(panel->layout, "modifier", ptr);
+ UI_panel_context_pointer_set(panel, "modifier", ptr);
return ptr;
}
@@ -312,7 +309,7 @@ static void gpencil_modifier_panel_header(const bContext *UNUSED(C), Panel *pane
PointerRNA *ptr = UI_panel_custom_data_get(panel);
GpencilModifierData *md = (GpencilModifierData *)ptr->data;
- uiLayoutSetContextPointer(panel->layout, "modifier", ptr);
+ UI_panel_context_pointer_set(panel, "modifier", ptr);
const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
bool narrow_panel = (panel->sizex < UI_UNIT_X * 9 && panel->sizex != 0);
@@ -360,9 +357,6 @@ static void gpencil_modifier_panel_header(const bContext *UNUSED(C), Panel *pane
/** \name Modifier Registration Helpers
* \{ */
-/**
- * Create a panel in the context's region
- */
PanelType *gpencil_modifier_panel_register(ARegionType *region_type,
GpencilModifierType type,
PanelDrawFn draw)
@@ -390,12 +384,6 @@ PanelType *gpencil_modifier_panel_register(ARegionType *region_type,
return panel_type;
}
-/**
- * Add a child panel to the parent.
- *
- * \note To create the panel type's idname, it appends the \a name argument to the \a parent's
- * idname.
- */
PanelType *gpencil_modifier_subpanel_register(ARegionType *region_type,
const char *name,
const char *label,
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.h b/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.h
index 782b36d47ed..2cccd6e15dd 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.h
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.h
@@ -37,15 +37,27 @@ void gpencil_modifier_masking_panel_draw(Panel *panel, bool use_material, bool u
void gpencil_modifier_curve_header_draw(const bContext *C, Panel *panel);
void gpencil_modifier_curve_panel_draw(const bContext *C, Panel *panel);
+/**
+ * Draw modifier error message.
+ */
void gpencil_modifier_panel_end(struct uiLayout *layout, PointerRNA *ptr);
struct PointerRNA *gpencil_modifier_panel_get_property_pointers(struct Panel *panel,
struct PointerRNA *r_ob_ptr);
+/**
+ * Create a panel in the context's region
+ */
PanelType *gpencil_modifier_panel_register(struct ARegionType *region_type,
GpencilModifierType type,
PanelDrawFn draw);
+/**
+ * Add a child panel to the parent.
+ *
+ * \note To create the panel type's idname, it appends the \a name argument to the \a parent's
+ * idname.
+ */
struct PanelType *gpencil_modifier_subpanel_register(struct ARegionType *region_type,
const char *name,
const char *label,
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
index 9ea146c77f2..f6a85919de4 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
@@ -67,10 +67,10 @@ void gpencil_modifier_type_init(GpencilModifierTypeInfo *types[])
INIT_GP_TYPE(WeightProximity);
INIT_GP_TYPE(Lineart);
INIT_GP_TYPE(Dash);
+ INIT_GP_TYPE(Shrinkwrap);
#undef INIT_GP_TYPE
}
-/* verify if valid layer, material and pass index */
bool is_stroke_affected_by_modifier(Object *ob,
char *mlayername,
const Material *material,
@@ -147,7 +147,6 @@ bool is_stroke_affected_by_modifier(Object *ob,
return true;
}
-/* verify if valid vertex group *and return weight */
float get_modifier_point_weight(MDeformVert *dvert, bool inverse, int def_nr)
{
float weight = 1.0f;
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h
index 2878ad4c73a..59ed11a02f3 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h
@@ -29,6 +29,9 @@ struct Object;
struct bGPDlayer;
struct bGPDstroke;
+/**
+ * Verify if valid layer, material and pass index.
+ */
bool is_stroke_affected_by_modifier(struct Object *ob,
char *mlayername,
const struct Material *material,
@@ -42,4 +45,7 @@ bool is_stroke_affected_by_modifier(struct Object *ob,
const bool inv3,
const bool inv4);
+/**
+ * Verify if valid vertex group *and return weight.
+ */
float get_modifier_point_weight(struct MDeformVert *dvert, bool inverse, int def_nr);
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c b/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c
index 7d2eb4b2c75..6a4d0de5c80 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c
@@ -313,8 +313,6 @@ static void panel_draw(const bContext *C, Panel *panel)
UI_TEMPLATE_LIST_FLAG_NONE);
uiLayout *col = uiLayoutColumn(row, false);
- uiLayoutSetContextPointer(col, "modifier", ptr);
-
uiLayout *sub = uiLayoutColumn(col, true);
uiItemO(sub, "", ICON_ADD, "GPENCIL_OT_segment_add");
uiItemO(sub, "", ICON_REMOVE, "GPENCIL_OT_segment_remove");
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillength.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillength.c
index 80b60547e92..af0067e06aa 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencillength.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillength.c
@@ -23,8 +23,10 @@
#include <stdio.h>
+#include "BLI_hash.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
+#include "BLI_rand.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -56,6 +58,7 @@
#include "MOD_gpencil_util.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
static void initData(GpencilModifierData *md)
{
@@ -71,6 +74,20 @@ static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
BKE_gpencil_modifier_copydata_generic(md, target);
}
+static float *noise_table(int len, int offset, int seed)
+{
+ float *table = MEM_callocN(sizeof(float) * len, __func__);
+ for (int i = 0; i < len; i++) {
+ table[i] = BLI_hash_int_01(BLI_hash_int_2d(seed, i + offset + 1));
+ }
+ return table;
+}
+
+BLI_INLINE float table_sample(float *table, float x)
+{
+ return interpf(table[(int)ceilf(x)], table[(int)floor(x)], fractf(x));
+}
+
static bool gpencil_modify_stroke(bGPDstroke *gps,
const float length,
const float overshoot_fac,
@@ -104,9 +121,15 @@ static bool gpencil_modify_stroke(bGPDstroke *gps,
return changed;
}
-static void applyLength(LengthGpencilModifierData *lmd, bGPdata *gpd, bGPDstroke *gps)
+static void applyLength(GpencilModifierData *md,
+ Depsgraph *depsgraph,
+ bGPdata *gpd,
+ bGPDframe *gpf,
+ bGPDstroke *gps,
+ Object *ob)
{
bool changed = false;
+ LengthGpencilModifierData *lmd = (LengthGpencilModifierData *)md;
const float len = (lmd->mode == GP_LENGTH_ABSOLUTE) ? 1.0f :
BKE_gpencil_stroke_length(gps, true);
const int totpoints = gps->totpoints;
@@ -120,11 +143,48 @@ static void applyLength(LengthGpencilModifierData *lmd, bGPdata *gpd, bGPDstroke
int first_mode = 1;
float second_fac = lmd->end_fac;
int second_mode = 2;
+
+ float rand[2] = {0.0f, 0.0f};
+ if (lmd->rand_start_fac != 0.0 || lmd->rand_end_fac != 0.0) {
+ int seed = lmd->seed;
+
+ /* Make sure different modifiers get different seeds. */
+ seed += BLI_hash_string(ob->id.name + 2);
+ seed += BLI_hash_string(md->name);
+
+ if (lmd->flag & GP_LENGTH_USE_RANDOM) {
+ seed += ((int)DEG_get_ctime(depsgraph)) / lmd->step;
+ }
+
+ float rand_offset = BLI_hash_int_01(seed);
+
+ /* Get stroke index for random offset. */
+ int rnd_index = BLI_findindex(&gpf->strokes, gps);
+ const uint primes[2] = {2, 3};
+ double offset[2] = {0.0f, 0.0f};
+ double r[2];
+
+ float *noise_table_length = noise_table(4, (int)floor(lmd->rand_offset), seed + 2);
+
+ /* To ensure a nice distribution, we use halton sequence and offset using the seed. */
+ BLI_halton_2d(primes, offset, rnd_index, r);
+ for (int j = 0; j < 2; j++) {
+ float noise = table_sample(noise_table_length, j * 2 + fractf(lmd->rand_offset));
+
+ rand[j] = fmodf(r[j] + rand_offset, 1.0f);
+ rand[j] = fabs(fmodf(sin(rand[j] * 12.9898f + j * 78.233f) * 43758.5453f, 1.0f) + noise);
+ }
+
+ MEM_SAFE_FREE(noise_table_length);
+
+ first_fac = first_fac + rand[0] * lmd->rand_start_fac;
+ second_fac = second_fac + rand[1] * lmd->rand_end_fac;
+ }
+
if (first_fac < 0) {
SWAP(float, first_fac, second_fac);
SWAP(int, first_mode, second_mode);
}
-
const int first_extra_point_count = ceil(first_fac * lmd->point_density);
const int second_extra_point_count = ceil(second_fac * lmd->point_density);
@@ -161,10 +221,10 @@ static void applyLength(LengthGpencilModifierData *lmd, bGPdata *gpd, bGPDstroke
}
static void deformStroke(GpencilModifierData *md,
- Depsgraph *UNUSED(depsgraph),
+ Depsgraph *depsgraph,
Object *ob,
bGPDlayer *gpl,
- bGPDframe *UNUSED(gpf),
+ bGPDframe *gpf,
bGPDstroke *gps)
{
bGPdata *gpd = ob->data;
@@ -187,7 +247,7 @@ static void deformStroke(GpencilModifierData *md,
/* Don't affect cyclic strokes as they have no start/end. */
return;
}
- applyLength(lmd, gpd, gps);
+ applyLength(md, depsgraph, gpd, gpf, gps, ob);
}
static void bakeModifier(Main *UNUSED(bmain),
@@ -214,6 +274,39 @@ static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk,
walk(userData, ob, (ID **)&mmd->material, IDWALK_CB_USER);
}
+static void random_header_draw(const bContext *UNUSED(C), Panel *panel)
+{
+ uiLayout *layout = panel->layout;
+
+ PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, NULL);
+
+ uiItemR(layout, ptr, "use_random", 0, IFACE_("Randomize"), ICON_NONE);
+}
+
+static void random_panel_draw(const bContext *UNUSED(C), Panel *panel)
+{
+ uiLayout *layout = panel->layout;
+
+ PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, NULL);
+
+ uiLayoutSetPropSep(layout, true);
+
+ uiLayoutSetActive(layout, RNA_boolean_get(ptr, "use_random"));
+
+ uiItemR(layout, ptr, "step", 0, NULL, ICON_NONE);
+}
+
+static void offset_panel_draw(const bContext *UNUSED(C), Panel *panel)
+{
+ uiLayout *layout = panel->layout;
+ PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, NULL);
+ uiLayoutSetPropSep(layout, true);
+ uiItemR(layout, ptr, "random_start_factor", 0, IFACE_("Random Offset Start"), ICON_NONE);
+ uiItemR(layout, ptr, "random_end_factor", 0, IFACE_("Random Offset End"), ICON_NONE);
+ uiItemR(layout, ptr, "random_offset", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "seed", 0, NULL, ICON_NONE);
+}
+
static void panel_draw(const bContext *UNUSED(C), Panel *panel)
{
uiLayout *layout = panel->layout;
@@ -277,6 +370,10 @@ static void panelRegister(ARegionType *region_type)
region_type, eGpencilModifierType_Length, panel_draw);
gpencil_modifier_subpanel_register(
region_type, "curvature", "", curvature_header_draw, curvature_panel_draw, panel_type);
+ PanelType *offset_panel = gpencil_modifier_subpanel_register(
+ region_type, "offset", "Random Offsets", NULL, offset_panel_draw, panel_type);
+ gpencil_modifier_subpanel_register(
+ region_type, "randomize", "", random_header_draw, random_panel_draw, offset_panel);
gpencil_modifier_subpanel_register(
region_type, "mask", "Influence", NULL, mask_panel_draw, panel_type);
}
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c
new file mode 100644
index 00000000000..6990b41e6ce
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c
@@ -0,0 +1,350 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017, Blender Foundation
+ * This is a new part of Blender
+ */
+
+/** \file
+ * \ingroup modifiers
+ */
+
+#include <stdio.h>
+#include <string.h> /* For #MEMCPY_STRUCT_AFTER. */
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_defaults.h"
+#include "DNA_gpencil_modifier_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+
+#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_gpencil_geom.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_lib_query.h"
+#include "BKE_main.h"
+#include "BKE_modifier.h"
+#include "BKE_scene.h"
+#include "BKE_screen.h"
+#include "BKE_shrinkwrap.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "RNA_access.h"
+
+#include "MOD_gpencil_modifiertypes.h"
+#include "MOD_gpencil_ui_common.h"
+#include "MOD_gpencil_util.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
+
+static void initData(GpencilModifierData *md)
+{
+ ShrinkwrapGpencilModifierData *gpmd = (ShrinkwrapGpencilModifierData *)md;
+
+ BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(gpmd, modifier));
+
+ MEMCPY_STRUCT_AFTER(gpmd, DNA_struct_default_get(ShrinkwrapGpencilModifierData), modifier);
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copydata_generic(md, target);
+}
+
+static void deformStroke(GpencilModifierData *md,
+ Depsgraph *UNUSED(depsgraph),
+ Object *ob,
+ bGPDlayer *gpl,
+ bGPDframe *UNUSED(gpf),
+ bGPDstroke *gps)
+{
+ bGPdata *gpd = ob->data;
+ ShrinkwrapGpencilModifierData *mmd = (ShrinkwrapGpencilModifierData *)md;
+ const int def_nr = BKE_object_defgroup_name_index(ob, mmd->vgname);
+
+ if (!is_stroke_affected_by_modifier(ob,
+ mmd->layername,
+ mmd->material,
+ mmd->pass_index,
+ mmd->layer_pass,
+ 1,
+ gpl,
+ gps,
+ mmd->flag & GP_SHRINKWRAP_INVERT_LAYER,
+ mmd->flag & GP_SHRINKWRAP_INVERT_PASS,
+ mmd->flag & GP_SHRINKWRAP_INVERT_LAYERPASS,
+ mmd->flag & GP_SHRINKWRAP_INVERT_MATERIAL)) {
+ return;
+ }
+
+ if ((mmd->cache_data == NULL) || (mmd->target == ob) || (mmd->aux_target == ob)) {
+ return;
+ }
+
+ bGPDspoint *pt = gps->points;
+ float(*vert_coords)[3] = MEM_mallocN(sizeof(float[3]) * gps->totpoints, __func__);
+ int i;
+ /* Prepare array of points. */
+ for (i = 0; i < gps->totpoints; i++, pt++) {
+ copy_v3_v3(vert_coords[i], &pt->x);
+ }
+
+ shrinkwrapGpencilModifier_deform(mmd, ob, gps->dvert, def_nr, vert_coords, gps->totpoints);
+
+ /* Apply deformed coordinates. */
+ pt = gps->points;
+ for (i = 0; i < gps->totpoints; i++, pt++) {
+ copy_v3_v3(&pt->x, vert_coords[i]);
+ /* Smooth stroke. */
+ if (mmd->smooth_factor > 0.0f) {
+ for (int r = 0; r < mmd->smooth_step; r++) {
+ BKE_gpencil_stroke_smooth_point(gps, i, mmd->smooth_factor, true);
+ }
+ }
+ }
+
+ MEM_freeN(vert_coords);
+
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(gpd, gps);
+}
+
+static void bakeModifier(Main *UNUSED(bmain),
+ Depsgraph *depsgraph,
+ GpencilModifierData *md,
+ Object *ob)
+{
+ ShrinkwrapGpencilModifierData *mmd = (ShrinkwrapGpencilModifierData *)md;
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ bGPdata *gpd = ob->data;
+ int oldframe = (int)DEG_get_ctime(depsgraph);
+
+ if ((mmd->target == ob) || (mmd->aux_target == ob)) {
+ return;
+ }
+
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
+ /* Apply shrinkwrap effects on this frame. */
+ CFRA = gpf->framenum;
+ BKE_scene_graph_update_for_newframe(depsgraph);
+
+ /* Recalculate shrinkwrap data. */
+ if (mmd->cache_data) {
+ BKE_shrinkwrap_free_tree(mmd->cache_data);
+ MEM_SAFE_FREE(mmd->cache_data);
+ }
+ Object *ob_target = DEG_get_evaluated_object(depsgraph, mmd->target);
+ Mesh *target = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob_target, false);
+ mmd->cache_data = MEM_callocN(sizeof(ShrinkwrapTreeData), __func__);
+ if (BKE_shrinkwrap_init_tree(
+ mmd->cache_data, target, mmd->shrink_type, mmd->shrink_mode, false)) {
+
+ /* Compute shrinkwrap effects on this frame. */
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
+ deformStroke(md, depsgraph, ob, gpl, gpf, gps);
+ }
+ }
+ /* Free data. */
+ if (mmd->cache_data) {
+ BKE_shrinkwrap_free_tree(mmd->cache_data);
+ MEM_SAFE_FREE(mmd->cache_data);
+ }
+ }
+ }
+
+ /* Return frame state and DB to original state. */
+ CFRA = oldframe;
+ BKE_scene_graph_update_for_newframe(depsgraph);
+}
+
+static void freeData(GpencilModifierData *md)
+{
+ ShrinkwrapGpencilModifierData *mmd = (ShrinkwrapGpencilModifierData *)md;
+ if (mmd->cache_data) {
+ BKE_shrinkwrap_free_tree(mmd->cache_data);
+ MEM_SAFE_FREE(mmd->cache_data);
+ }
+}
+
+static bool isDisabled(GpencilModifierData *md, int UNUSED(userRenderParams))
+{
+ ShrinkwrapGpencilModifierData *mmd = (ShrinkwrapGpencilModifierData *)md;
+
+ /* The object type check is only needed here in case we have a placeholder
+ * object assigned (because the library containing the mesh is missing).
+ *
+ * In other cases it should be impossible to have a type mismatch.
+ */
+ if (!mmd->target || mmd->target->type != OB_MESH) {
+ return true;
+ }
+ if (mmd->aux_target && mmd->aux_target->type != OB_MESH) {
+ return true;
+ }
+ return false;
+}
+
+static void updateDepsgraph(GpencilModifierData *md,
+ const ModifierUpdateDepsgraphContext *ctx,
+ const int UNUSED(mode))
+{
+ ShrinkwrapGpencilModifierData *mmd = (ShrinkwrapGpencilModifierData *)md;
+ CustomData_MeshMasks mask = {0};
+
+ if (BKE_shrinkwrap_needs_normals(mmd->shrink_type, mmd->shrink_mode)) {
+ mask.vmask |= CD_MASK_NORMAL;
+ mask.lmask |= CD_MASK_NORMAL | CD_MASK_CUSTOMLOOPNORMAL;
+ }
+
+ if (mmd->target != NULL) {
+ DEG_add_object_relation(ctx->node, mmd->target, DEG_OB_COMP_TRANSFORM, "Shrinkwrap Modifier");
+ DEG_add_object_relation(ctx->node, mmd->target, DEG_OB_COMP_GEOMETRY, "Shrinkwrap Modifier");
+ DEG_add_customdata_mask(ctx->node, mmd->target, &mask);
+ if (mmd->shrink_type == MOD_SHRINKWRAP_TARGET_PROJECT) {
+ DEG_add_special_eval_flag(ctx->node, &mmd->target->id, DAG_EVAL_NEED_SHRINKWRAP_BOUNDARY);
+ }
+ }
+ if (mmd->aux_target != NULL) {
+ DEG_add_object_relation(
+ ctx->node, mmd->aux_target, DEG_OB_COMP_TRANSFORM, "Shrinkwrap Modifier");
+ DEG_add_object_relation(
+ ctx->node, mmd->aux_target, DEG_OB_COMP_GEOMETRY, "Shrinkwrap Modifier");
+ DEG_add_customdata_mask(ctx->node, mmd->aux_target, &mask);
+ if (mmd->shrink_type == MOD_SHRINKWRAP_TARGET_PROJECT) {
+ DEG_add_special_eval_flag(
+ ctx->node, &mmd->aux_target->id, DAG_EVAL_NEED_SHRINKWRAP_BOUNDARY);
+ }
+ }
+ DEG_add_modifier_to_transform_relation(ctx->node, "Shrinkwrap Modifier");
+}
+
+static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
+{
+ ShrinkwrapGpencilModifierData *mmd = (ShrinkwrapGpencilModifierData *)md;
+
+ walk(userData, ob, (ID **)&mmd->target, IDWALK_CB_NOP);
+ walk(userData, ob, (ID **)&mmd->aux_target, IDWALK_CB_NOP);
+ walk(userData, ob, (ID **)&mmd->material, IDWALK_CB_USER);
+}
+
+static void panel_draw(const bContext *UNUSED(C), Panel *panel)
+{
+ uiLayout *row, *col;
+ uiLayout *layout = panel->layout;
+ int toggles_flag = UI_ITEM_R_TOGGLE | UI_ITEM_R_FORCE_BLANK_DECORATE;
+
+ PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, NULL);
+
+ uiLayoutSetPropSep(layout, true);
+
+ int wrap_method = RNA_enum_get(ptr, "wrap_method");
+
+ uiItemR(layout, ptr, "wrap_method", 0, NULL, ICON_NONE);
+
+ if (ELEM(wrap_method,
+ MOD_SHRINKWRAP_PROJECT,
+ MOD_SHRINKWRAP_NEAREST_SURFACE,
+ MOD_SHRINKWRAP_TARGET_PROJECT)) {
+ uiItemR(layout, ptr, "wrap_mode", 0, NULL, ICON_NONE);
+ }
+
+ if (wrap_method == MOD_SHRINKWRAP_PROJECT) {
+ uiItemR(layout, ptr, "project_limit", 0, IFACE_("Limit"), ICON_NONE);
+ uiItemR(layout, ptr, "subsurf_levels", 0, NULL, ICON_NONE);
+
+ col = uiLayoutColumn(layout, false);
+ row = uiLayoutRowWithHeading(col, true, IFACE_("Axis"));
+ uiItemR(row, ptr, "use_project_x", toggles_flag, NULL, ICON_NONE);
+ uiItemR(row, ptr, "use_project_y", toggles_flag, NULL, ICON_NONE);
+ uiItemR(row, ptr, "use_project_z", toggles_flag, NULL, ICON_NONE);
+
+ uiItemR(col, ptr, "use_negative_direction", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_positive_direction", 0, NULL, ICON_NONE);
+
+ uiItemR(layout, ptr, "cull_face", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ col = uiLayoutColumn(layout, false);
+ uiLayoutSetActive(col,
+ RNA_boolean_get(ptr, "use_negative_direction") &&
+ RNA_enum_get(ptr, "cull_face") != 0);
+ uiItemR(col, ptr, "use_invert_cull", 0, NULL, ICON_NONE);
+ }
+
+ uiItemR(layout, ptr, "target", 0, NULL, ICON_NONE);
+ if (wrap_method == MOD_SHRINKWRAP_PROJECT) {
+ uiItemR(layout, ptr, "auxiliary_target", 0, NULL, ICON_NONE);
+ }
+ uiItemR(layout, ptr, "offset", 0, NULL, ICON_NONE);
+
+ uiLayoutSetPropSep(layout, true);
+
+ uiItemR(layout, ptr, "smooth_factor", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "smooth_step", 0, IFACE_("Repeat"), ICON_NONE);
+
+ gpencil_modifier_panel_end(layout, ptr);
+}
+
+static void mask_panel_draw(const bContext *UNUSED(C), Panel *panel)
+{
+ gpencil_modifier_masking_panel_draw(panel, true, true);
+}
+
+static void panelRegister(ARegionType *region_type)
+{
+ PanelType *panel_type = gpencil_modifier_panel_register(
+ region_type, eGpencilModifierType_Shrinkwrap, panel_draw);
+ gpencil_modifier_subpanel_register(
+ region_type, "mask", "Influence", NULL, mask_panel_draw, panel_type);
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Shrinkwrap = {
+ /* name */ "Shrinkwrap",
+ /* structName */ "ShrinkwrapGpencilModifierData",
+ /* structSize */ sizeof(ShrinkwrapGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ eGpencilModifierTypeFlag_SupportsEditmode,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ deformStroke,
+ /* generateStrokes */ NULL,
+ /* bakeModifier */ bakeModifier,
+ /* remapTime */ NULL,
+
+ /* initData */ initData,
+ /* freeData */ freeData,
+ /* isDisabled */ isDisabled,
+ /* updateDepsgraph */ updateDepsgraph,
+ /* dependsOnTime */ NULL,
+ /* foreachIDLink */ foreachIDLink,
+ /* foreachTexLink */ NULL,
+ /* panelRegister */ panelRegister,
+};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c
index b00db1ba2d2..a63cbb53645 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c
@@ -132,7 +132,7 @@ static void deformStroke(GpencilModifierData *md,
const float val = mmd->factor * weight;
/* perform smoothing */
if (mmd->flag & GP_SMOOTH_MOD_LOCATION) {
- BKE_gpencil_stroke_smooth_point(gps, i, val);
+ BKE_gpencil_stroke_smooth_point(gps, i, val, false);
}
if (mmd->flag & GP_SMOOTH_MOD_STRENGTH) {
BKE_gpencil_stroke_smooth_strength(gps, i, val);
diff --git a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
index 869f93f832e..2ef72da03fd 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
+++ b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
@@ -485,7 +485,7 @@ typedef struct LineartBoundingArea {
(((a) + DBL_TRIANGLE_LIM) >= (b) && ((a)-DBL_TRIANGLE_LIM) <= (b))
/* Notes on this function:
-
+ *
* r_ratio: The ratio on segment a1-a2. When r_ratio is very close to zero or one, it
* fixes the value to zero or one, this makes it easier to identify "on the tip" situations.
*
@@ -649,9 +649,18 @@ void MOD_lineart_destroy_render_data(struct LineartGpencilModifierData *lmd);
void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb);
void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb);
+/**
+ * This function only connects two different chains. It will not do any clean up or smart chaining.
+ * So no: removing overlapping chains, removal of short isolated segments, and no loop reduction is
+ * implemented yet.
+ */
void MOD_lineart_chain_connect(LineartRenderBuffer *rb);
void MOD_lineart_chain_discard_short(LineartRenderBuffer *rb, const float threshold);
void MOD_lineart_chain_clip_at_border(LineartRenderBuffer *rb);
+/**
+ * This should always be the last stage!, see the end of
+ * #MOD_lineart_chain_split_for_fixed_occlusion().
+ */
void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshold_rad);
void MOD_lineart_smooth_chains(LineartRenderBuffer *rb, float tolerance);
void MOD_lineart_chain_offset_towards_camera(LineartRenderBuffer *rb,
@@ -661,6 +670,11 @@ void MOD_lineart_chain_offset_towards_camera(LineartRenderBuffer *rb,
int MOD_lineart_chain_count(const LineartEdgeChain *ec);
void MOD_lineart_chain_clear_picked_flag(LineartCache *lc);
+/**
+ * This is the entry point of all line art calculations.
+ *
+ * \return True when a change is made.
+ */
bool MOD_lineart_compute_feature_lines(struct Depsgraph *depsgraph,
struct LineartGpencilModifierData *lmd,
struct LineartCache **cached_result,
@@ -668,15 +682,24 @@ bool MOD_lineart_compute_feature_lines(struct Depsgraph *depsgraph,
struct Scene;
+/**
+ * This only gets initial "biggest" tile.
+ */
LineartBoundingArea *MOD_lineart_get_parent_bounding_area(LineartRenderBuffer *rb,
double x,
double y);
+/**
+ * Wrapper for more convenience.
+ */
LineartBoundingArea *MOD_lineart_get_bounding_area(LineartRenderBuffer *rb, double x, double y);
struct bGPDframe;
struct bGPDlayer;
+/**
+ * Wrapper for external calls.
+ */
void MOD_lineart_gpencil_generate(LineartCache *cache,
struct Depsgraph *depsgraph,
struct Object *ob,
@@ -697,6 +720,9 @@ void MOD_lineart_gpencil_generate(LineartCache *cache,
const char *vgname,
int modifier_flags);
+/**
+ * Length is in image space.
+ */
float MOD_lineart_chain_compute_length(LineartEdgeChain *ec);
void ED_operatortypes_lineart(void);
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c
index 88dcfb89c25..0deb8b1c335 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c
@@ -794,11 +794,6 @@ static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartRenderBuf
return closest_cre;
}
-/**
- * This function only connects two different chains. It will not do any clean up or smart chaining.
- * So no: removing overlapping chains, removal of short isolated segments, and no loop reduction is
- * implemented yet.
- */
void MOD_lineart_chain_connect(LineartRenderBuffer *rb)
{
LineartEdgeChain *ec;
@@ -881,9 +876,6 @@ void MOD_lineart_chain_connect(LineartRenderBuffer *rb)
}
}
-/**
- * Length is in image space.
- */
float MOD_lineart_chain_compute_length(LineartEdgeChain *ec)
{
LineartEdgeChainItem *eci;
@@ -1072,10 +1064,6 @@ void MOD_lineart_chain_clip_at_border(LineartRenderBuffer *rb)
}
}
-/**
- * This should always be the last stage!, see the end of
- * #MOD_lineart_chain_split_for_fixed_occlusion().
- */
void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshold_rad)
{
LineartEdgeChain *ec, *new_ec;
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
index 88d717eb032..d9a32711833 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
@@ -502,10 +502,6 @@ static void lineart_main_occlusion_begin(LineartRenderBuffer *rb)
rb->edge_mark.last = rb->edge_mark.first;
rb->floating.last = rb->floating.first;
- /* This is needed because the occlusion function expects the camera vector to point towards the
- * camera. */
- negate_v3_db(rb->view_vector);
-
TaskPool *tp = BLI_task_pool_create(NULL, TASK_PRIORITY_HIGH);
for (i = 0; i < thread_count; i++) {
@@ -579,9 +575,7 @@ static int lineart_point_on_line_segment(double v[2], double v0[2], double v1[2]
c2 = ratiod(v0[1], v1[1], v[1]);
return (c2 >= -DBL_TRIANGLE_LIM && c2 <= 1 + DBL_TRIANGLE_LIM);
}
- else {
- return false;
- }
+ return false;
}
if (!LRT_DOUBLE_CLOSE_ENOUGH(v1[1], v0[1])) {
@@ -592,9 +586,7 @@ static int lineart_point_on_line_segment(double v[2], double v0[2], double v1[2]
c1 = ratiod(v0[0], v1[0], v[0]);
return (c1 >= -DBL_TRIANGLE_LIM && c1 <= 1 + DBL_TRIANGLE_LIM);
}
- else {
- return false;
- }
+ return false;
}
if (LRT_DOUBLE_CLOSE_ENOUGH(c1, c2) && c1 >= 0 && c1 <= 1) {
@@ -2336,9 +2328,9 @@ static bool lineart_edge_from_triangle(const LineartTriangle *tri,
* if returns true, then from/to will carry the occluded segments
* in ratio from `e->v1` to `e->v2`. The line is later cut with these two values.
*
- * TODO: (Yiming) This function uses a convoluted method that needs to be redesigned.
+ * TODO(@Yiming): This function uses a convoluted method that needs to be redesigned.
*
- * 1) The lineart_intersect_seg_seg() and lineart_point_triangle_relation() are separate calls,
+ * 1) The #lineart_intersect_seg_seg() and #lineart_point_triangle_relation() are separate calls,
* which would potentially return results that doesn't agree, especially when it's an edge
* extruding from one of the triangle's point. To get the information using one math process can
* solve this problem.
@@ -2350,7 +2342,7 @@ static bool lineart_edge_from_triangle(const LineartTriangle *tri,
* I keep this function as-is because it's still fast, and more importantly the output value
* threshold is already in tune with the cutting function in the next stage.
* While current "edge aligned" fix isn't ideal, it does solve most of the precision issue
- * especially in ortho camera mode.
+ * especially in orthographic camera mode.
*/
static bool lineart_triangle_edge_image_space_occlusion(SpinLock *UNUSED(spl),
const LineartTriangle *tri,
@@ -3010,7 +3002,7 @@ static void lineart_triangle_intersect_in_bounding_area(LineartRenderBuffer *rb,
*/
static void lineart_main_get_view_vector(LineartRenderBuffer *rb)
{
- float direction[3] = {0, 0, -1};
+ float direction[3] = {0, 0, 1};
float trans[3];
float inv[4][4];
float obmat_no_scale[4][4];
@@ -3767,9 +3759,6 @@ static bool lineart_get_edge_bounding_areas(LineartRenderBuffer *rb,
return true;
}
-/**
- * This only gets initial "biggest" tile.
- */
LineartBoundingArea *MOD_lineart_get_parent_bounding_area(LineartRenderBuffer *rb,
double x,
double y)
@@ -3841,9 +3830,6 @@ static LineartBoundingArea *lineart_get_bounding_area(LineartRenderBuffer *rb, d
return iba;
}
-/**
- * Wrapper for more convenience.
- */
LineartBoundingArea *MOD_lineart_get_bounding_area(LineartRenderBuffer *rb, double x, double y)
{
LineartBoundingArea *ba;
@@ -4149,11 +4135,6 @@ static LineartBoundingArea *lineart_bounding_area_next(LineartBoundingArea *this
return 0;
}
-/**
- * This is the entry point of all line art calculations.
- *
- * \return True when a change is made.
- */
bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph,
LineartGpencilModifierData *lmd,
LineartCache **cached_result,
@@ -4398,7 +4379,7 @@ static void lineart_gpencil_generate(LineartCache *cache,
}
}
}
- if (types & LRT_EDGE_FLAG_INTERSECTION) {
+ if (ec->type & LRT_EDGE_FLAG_INTERSECTION) {
if (mask_switches & LRT_GPENCIL_INTERSECTION_MATCH) {
if (ec->intersection_mask != intersection_mask) {
continue;
@@ -4481,9 +4462,6 @@ static void lineart_gpencil_generate(LineartCache *cache,
}
}
-/**
- * Wrapper for external calls.
- */
void MOD_lineart_gpencil_generate(LineartCache *cache,
Depsgraph *depsgraph,
Object *ob,
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c
index b74499daf6b..c53404a87e2 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c
@@ -444,7 +444,6 @@ static int lineart_gpencil_clear_strokes_all_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-/* Bake all line art modifiers on the current object. */
void OBJECT_OT_lineart_bake_strokes(wmOperatorType *ot)
{
ot->name = "Bake Line Art";
@@ -456,7 +455,6 @@ void OBJECT_OT_lineart_bake_strokes(wmOperatorType *ot)
ot->modal = lineart_gpencil_bake_strokes_commom_modal;
}
-/* Bake all lineart objects in the scene. */
void OBJECT_OT_lineart_bake_strokes_all(wmOperatorType *ot)
{
ot->name = "Bake Line Art (All)";
@@ -468,7 +466,6 @@ void OBJECT_OT_lineart_bake_strokes_all(wmOperatorType *ot)
ot->modal = lineart_gpencil_bake_strokes_commom_modal;
}
-/* clear all line art modifiers on the current object. */
void OBJECT_OT_lineart_clear(wmOperatorType *ot)
{
ot->name = "Clear Baked Line Art";
@@ -478,7 +475,6 @@ void OBJECT_OT_lineart_clear(wmOperatorType *ot)
ot->exec = lineart_gpencil_clear_strokes_exec;
}
-/* clear all lineart objects in the scene. */
void OBJECT_OT_lineart_clear_all(wmOperatorType *ot)
{
ot->name = "Clear Baked Line Art (All)";
diff --git a/source/blender/gpu/GPU_batch.h b/source/blender/gpu/GPU_batch.h
index 911c8cc2e42..a8bc4f271c9 100644
--- a/source/blender/gpu/GPU_batch.h
+++ b/source/blender/gpu/GPU_batch.h
@@ -102,25 +102,48 @@ void GPU_batch_init_ex(GPUBatch *batch,
GPUVertBuf *vert,
GPUIndexBuf *elem,
eGPUBatchFlag owns_flag);
+/**
+ * This will share the VBOs with the new batch.
+ */
void GPU_batch_copy(GPUBatch *batch_dst, GPUBatch *batch_src);
#define GPU_batch_create(prim, verts, elem) GPU_batch_create_ex(prim, verts, elem, 0)
#define GPU_batch_init(batch, prim, verts, elem) GPU_batch_init_ex(batch, prim, verts, elem, 0)
-/* Same as discard but does not free. (does not call free callback). */
+/**
+ * Same as discard but does not free. (does not call free callback).
+ */
void GPU_batch_clear(GPUBatch *);
-void GPU_batch_discard(GPUBatch *); /* verts & elem are not discarded */
+/**
+ * \note Verts & elem are not discarded.
+ */
+void GPU_batch_discard(GPUBatch *);
+/**
+ * \note Override ONLY the first instance VBO (and free them if owned).
+ */
void GPU_batch_instbuf_set(GPUBatch *, GPUVertBuf *, bool own_vbo); /* Instancing */
+/**
+ * \note Override any previously assigned elem (and free it if owned).
+ */
void GPU_batch_elembuf_set(GPUBatch *batch, GPUIndexBuf *elem, bool own_ibo);
int GPU_batch_instbuf_add_ex(GPUBatch *, GPUVertBuf *, bool own_vbo);
+/**
+ * Returns the index of verts in the batch.
+ */
int GPU_batch_vertbuf_add_ex(GPUBatch *, GPUVertBuf *, bool own_vbo);
#define GPU_batch_vertbuf_add(batch, verts) GPU_batch_vertbuf_add_ex(batch, verts, false)
void GPU_batch_set_shader(GPUBatch *batch, GPUShader *shader);
+/**
+ * Bind program bound to IMM to the batch.
+ *
+ * XXX Use this with much care. Drawing with the #GPUBatch API is not compatible with IMM.
+ * DO NOT DRAW WITH THE BATCH BEFORE CALLING #immUnbindProgram.
+ */
void GPU_batch_program_set_imm_shader(GPUBatch *batch);
void GPU_batch_program_set_builtin(GPUBatch *batch, eGPUBuiltinShader shader_id);
void GPU_batch_program_set_builtin_with_config(GPUBatch *batch,
@@ -129,6 +152,7 @@ void GPU_batch_program_set_builtin_with_config(GPUBatch *batch,
/* Will only work after setting the batch program. */
/* TODO(fclem): These need to be replaced by GPU_shader_uniform_* with explicit shader. */
+
#define GPU_batch_uniform_1i(batch, name, x) GPU_shader_uniform_1i((batch)->shader, name, x);
#define GPU_batch_uniform_1b(batch, name, x) GPU_shader_uniform_1b((batch)->shader, name, x);
#define GPU_batch_uniform_1f(batch, name, x) GPU_shader_uniform_1f((batch)->shader, name, x);
@@ -151,14 +175,19 @@ void GPU_batch_program_set_builtin_with_config(GPUBatch *batch,
void GPU_batch_draw(GPUBatch *batch);
void GPU_batch_draw_range(GPUBatch *batch, int v_first, int v_count);
+/**
+ * Draw multiple instance of a batch without having any instance attributes.
+ */
void GPU_batch_draw_instanced(GPUBatch *batch, int i_count);
-/* This does not bind/unbind shader and does not call GPU_matrix_bind() */
+/**
+ * This does not bind/unbind shader and does not call GPU_matrix_bind().
+ */
void GPU_batch_draw_advanced(GPUBatch *, int v_first, int v_count, int i_first, int i_count);
#if 0 /* future plans */
-/* Can multiple batches share a GPUVertBuf? Use ref count? */
+/* Can multiple batches share a #GPUVertBuf? Use ref count? */
/* We often need a batch with its own data, to be created and discarded together. */
/* WithOwn variants reduce number of system allocations. */
diff --git a/source/blender/gpu/GPU_batch_presets.h b/source/blender/gpu/GPU_batch_presets.h
index 19f200fecbf..73c9172f2ba 100644
--- a/source/blender/gpu/GPU_batch_presets.h
+++ b/source/blender/gpu/GPU_batch_presets.h
@@ -35,7 +35,8 @@ extern "C" {
/* gpu_batch_presets.c */
-/* Replacement for gluSphere */
+/* Replacement for #gluSphere */
+
struct GPUBatch *GPU_batch_preset_sphere(int lod) ATTR_WARN_UNUSED_RESULT;
struct GPUBatch *GPU_batch_preset_sphere_wire(int lod) ATTR_WARN_UNUSED_RESULT;
struct GPUBatch *GPU_batch_preset_panel_drag_widget(const float pixelsize,
@@ -43,6 +44,9 @@ struct GPUBatch *GPU_batch_preset_panel_drag_widget(const float pixelsize,
const float col_dark[4],
const float width) ATTR_WARN_UNUSED_RESULT;
+/**
+ * To be used with procedural placement inside shader.
+ */
struct GPUBatch *GPU_batch_preset_quad(void);
void gpu_batch_presets_init(void);
diff --git a/source/blender/gpu/GPU_batch_utils.h b/source/blender/gpu/GPU_batch_utils.h
index 37dccc4621c..660ae0c8844 100644
--- a/source/blender/gpu/GPU_batch_utils.h
+++ b/source/blender/gpu/GPU_batch_utils.h
@@ -30,6 +30,16 @@ extern "C" {
struct rctf;
/* gpu_batch_utils.c */
+
+/**
+ * Creates triangles from a byte-array of polygons.
+ *
+ * See 'make_shape_2d_from_blend.py' utility to create data to pass to this function.
+ *
+ * \param polys_flat: Pairs of X, Y coordinates (repeating to signify closing the polygon).
+ * \param polys_flat_len: Length of the array (must be an even number).
+ * \param rect: Optional region to map the byte 0..255 coords to. When not set use -1..1.
+ */
struct GPUBatch *GPU_batch_tris_from_poly_2d_encoded(
const uchar *polys_flat, uint polys_flat_len, const struct rctf *rect) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1);
@@ -37,7 +47,11 @@ struct GPUBatch *GPU_batch_wire_from_poly_2d_encoded(
const uchar *polys_flat, uint polys_flat_len, const struct rctf *rect) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1);
-/* Only use by draw manager. Use the presets function instead for interface. */
+/**
+ * Replacement for #gluSphere.
+ *
+ * \note Only use by draw manager. Use the presets function instead for interface.
+ */
struct GPUBatch *gpu_batch_sphere(int lat_res, int lon_res) ATTR_WARN_UNUSED_RESULT;
#ifdef __cplusplus
diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h
index b770bde65fc..9ba283bf65f 100644
--- a/source/blender/gpu/GPU_buffers.h
+++ b/source/blender/gpu/GPU_buffers.h
@@ -44,11 +44,17 @@ struct Mesh;
struct PBVH;
struct SubdivCCG;
-/* Buffers for drawing from PBVH grids. */
+/**
+ * Buffers for drawing from PBVH grids.
+ */
typedef struct GPU_PBVH_Buffers GPU_PBVH_Buffers;
-/* Build must be called once before using the other functions, used every time
- * mesh topology changes. Threaded. */
+/**
+ * Build must be called once before using the other functions,
+ * used every time mesh topology changes.
+ *
+ * Threaded: do not call any functions that use OpenGL calls!
+ */
GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const struct MPoly *mpoly,
const struct MLoop *mloop,
const struct MLoopTri *looptri,
@@ -58,23 +64,36 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const struct MPoly *mpoly,
const int face_indices_len,
const struct Mesh *mesh);
+/**
+ * Threaded: do not call any functions that use OpenGL calls!
+ */
GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build(int totgrid, unsigned int **grid_hidden);
+/**
+ * Threaded: do not call any functions that use OpenGL calls!
+ */
GPU_PBVH_Buffers *GPU_pbvh_bmesh_buffers_build(bool smooth_shading);
-/* Free part of data for update. Not thread safe, must run in OpenGL main thread. */
+/**
+ * Free part of data for update. Not thread safe, must run in OpenGL main thread.
+ */
void GPU_pbvh_bmesh_buffers_update_free(GPU_PBVH_Buffers *buffers);
void GPU_pbvh_grid_buffers_update_free(GPU_PBVH_Buffers *buffers,
const struct DMFlagMat *grid_flag_mats,
const int *grid_indices);
-/* Update mesh buffers without topology changes. Threaded. */
+/**
+ * Update mesh buffers without topology changes. Threaded.
+ */
enum {
GPU_PBVH_BUFFERS_SHOW_MASK = (1 << 1),
GPU_PBVH_BUFFERS_SHOW_VCOL = (1 << 2),
GPU_PBVH_BUFFERS_SHOW_SCULPT_FACE_SETS = (1 << 3),
};
+/**
+ * Threaded: do not call any functions that use OpenGL calls!
+ */
void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
const struct MVert *mvert,
const float *vmask,
@@ -85,6 +104,11 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
const struct MPropCol *vtcol,
const int update_flags);
+/**
+ * Creates a vertex buffer (coordinate, normal, color) and,
+ * if smooth shading, an element index buffer.
+ * Threaded: do not call any functions that use OpenGL calls!
+ */
void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
struct BMesh *bm,
struct GSet *bm_faces,
@@ -92,6 +116,9 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
struct GSet *bm_other_verts,
const int update_flags);
+/**
+ * Threaded: do not call any functions that use OpenGL calls!
+ */
void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
struct SubdivCCG *subdiv_ccg,
struct CCGElem **grids,
@@ -104,13 +131,17 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
const struct CCGKey *key,
const int update_flags);
-/* Finish update. Not thread safe, must run in OpenGL main thread. */
+/**
+ * Finish update. Not thread safe, must run in OpenGL main thread.
+ */
void GPU_pbvh_buffers_update_flush(GPU_PBVH_Buffers *buffers);
-/* Free buffers. Not thread safe, must run in OpenGL main thread. */
+/**
+ * Free buffers. Not thread safe, must run in OpenGL main thread.
+ */
void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers);
-/* draw */
+/** Draw. */
struct GPUBatch *GPU_pbvh_buffers_batch_get(GPU_PBVH_Buffers *buffers, bool fast, bool wires);
short GPU_pbvh_buffers_material_index_get(GPU_PBVH_Buffers *buffers);
diff --git a/source/blender/gpu/GPU_capabilities.h b/source/blender/gpu/GPU_capabilities.h
index 5b5d0f16c9f..9cd1dbd37f1 100644
--- a/source/blender/gpu/GPU_capabilities.h
+++ b/source/blender/gpu/GPU_capabilities.h
@@ -64,6 +64,9 @@ bool GPU_shader_image_load_store_support(void);
bool GPU_mem_stats_supported(void);
void GPU_mem_stats_get(int *totalmem, int *freemem);
+/**
+ * Return support for the active context + window.
+ */
bool GPU_stereo_quadbuffer_support(void);
#ifdef __cplusplus
diff --git a/source/blender/gpu/GPU_context.h b/source/blender/gpu/GPU_context.h
index 82f13424502..5189fa1ae41 100644
--- a/source/blender/gpu/GPU_context.h
+++ b/source/blender/gpu/GPU_context.h
@@ -44,8 +44,14 @@ void GPU_backend_exit(void);
typedef struct GPUContext GPUContext;
GPUContext *GPU_context_create(void *ghost_window);
+/**
+ * To be called after #GPU_context_active_set(ctx_to_destroy).
+ */
void GPU_context_discard(GPUContext *);
+/**
+ * Ctx can be NULL.
+ */
void GPU_context_active_set(GPUContext *);
GPUContext *GPU_context_active_get(void);
diff --git a/source/blender/gpu/GPU_debug.h b/source/blender/gpu/GPU_debug.h
index f67e850ad80..9796ac63272 100644
--- a/source/blender/gpu/GPU_debug.h
+++ b/source/blender/gpu/GPU_debug.h
@@ -33,7 +33,14 @@ extern "C" {
void GPU_debug_group_begin(const char *name);
void GPU_debug_group_end(void);
+/**
+ * Return a formatted string showing the current group hierarchy in this format:
+ * "Group1 > Group 2 > Group3 > ... > GroupN : "
+ */
void GPU_debug_get_groups_names(int name_buf_len, char *r_name_buf);
+/**
+ * Return true if inside a debug group with the same name.
+ */
bool GPU_debug_group_match(const char *ref);
#ifdef __cplusplus
diff --git a/source/blender/gpu/GPU_framebuffer.h b/source/blender/gpu/GPU_framebuffer.h
index bf0ab3dc533..b203c49a7f1 100644
--- a/source/blender/gpu/GPU_framebuffer.h
+++ b/source/blender/gpu/GPU_framebuffer.h
@@ -62,6 +62,9 @@ typedef struct GPUOffScreen GPUOffScreen;
GPUFrameBuffer *GPU_framebuffer_create(const char *name);
void GPU_framebuffer_free(GPUFrameBuffer *fb);
void GPU_framebuffer_bind(GPUFrameBuffer *fb);
+/**
+ * Workaround for binding a SRGB frame-buffer without doing the SRGB transform.
+ */
void GPU_framebuffer_bind_no_srgb(GPUFrameBuffer *fb);
void GPU_framebuffer_restore(void);
@@ -69,6 +72,9 @@ bool GPU_framebuffer_bound(GPUFrameBuffer *fb);
bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256]);
GPUFrameBuffer *GPU_framebuffer_active_get(void);
+/**
+ * Returns the default frame-buffer. Will always exists even if it's just a dummy.
+ */
GPUFrameBuffer *GPU_framebuffer_back_get(void);
#define GPU_FRAMEBUFFER_FREE_SAFE(fb) \
@@ -113,6 +119,12 @@ void GPU_framebuffer_texture_detach(GPUFrameBuffer *fb, struct GPUTexture *tex);
GPU_framebuffer_config_array(*(_fb), config, (sizeof(config) / sizeof(GPUAttachment))); \
} while (0)
+/**
+ * First #GPUAttachment in *config is always the depth/depth_stencil buffer.
+ * Following #GPUAttachments are color buffers.
+ * Setting #GPUAttachment.mip to -1 will leave the texture in this slot.
+ * Setting #GPUAttachment.tex to NULL will detach the texture in this slot.
+ */
void GPU_framebuffer_config_array(GPUFrameBuffer *fb, const GPUAttachment *config, int config_len);
#define GPU_ATTACHMENT_NONE \
@@ -156,8 +168,16 @@ void GPU_framebuffer_texture_cubeface_attach(
/* Frame-buffer operations. */
+/**
+ * Viewport and scissor size is stored per frame-buffer.
+ * It is only reset to its original dimensions explicitly OR when binding the frame-buffer after
+ * modifying its attachments.
+ */
void GPU_framebuffer_viewport_set(GPUFrameBuffer *fb, int x, int y, int w, int h);
void GPU_framebuffer_viewport_get(GPUFrameBuffer *fb, int r_viewport[4]);
+/**
+ * Reset to its attachment(s) size.
+ */
void GPU_framebuffer_viewport_reset(GPUFrameBuffer *fb);
void GPU_framebuffer_clear(GPUFrameBuffer *fb,
@@ -184,6 +204,9 @@ void GPU_framebuffer_clear(GPUFrameBuffer *fb,
#define GPU_framebuffer_clear_color_depth_stencil(fb, col, depth, stencil) \
GPU_framebuffer_clear(fb, GPU_COLOR_BIT | GPU_DEPTH_BIT | GPU_STENCIL_BIT, col, depth, stencil)
+/**
+ * Clear all textures attached to this frame-buffer with a different color.
+ */
void GPU_framebuffer_multi_clear(GPUFrameBuffer *fb, const float (*clear_cols)[4]);
void GPU_framebuffer_read_depth(
@@ -198,6 +221,9 @@ void GPU_framebuffer_read_color(GPUFrameBuffer *fb,
eGPUDataFormat format,
void *data);
+/**
+ * Read_slot and write_slot are only used for color buffers.
+ */
void GPU_framebuffer_blit(GPUFrameBuffer *fb_read,
int read_slot,
GPUFrameBuffer *fb_write,
@@ -233,6 +259,9 @@ int GPU_offscreen_width(const GPUOffScreen *ofs);
int GPU_offscreen_height(const GPUOffScreen *ofs);
struct GPUTexture *GPU_offscreen_color_texture(const GPUOffScreen *ofs);
+/**
+ * \note only to be used by viewport code!
+ */
void GPU_offscreen_viewport_data_get(GPUOffScreen *ofs,
GPUFrameBuffer **r_fb,
struct GPUTexture **r_color,
diff --git a/source/blender/gpu/GPU_immediate.h b/source/blender/gpu/GPU_immediate.h
index edb7c9fe5b5..a175fc65ba4 100644
--- a/source/blender/gpu/GPU_immediate.h
+++ b/source/blender/gpu/GPU_immediate.h
@@ -39,7 +39,7 @@ extern "C" {
/** Returns a cleared vertex format, ready for #add_attr. */
GPUVertFormat *immVertexFormat(void);
-/** Every immBegin must have a program bound first. */
+/** Every #immBegin must have a program bound first. */
void immBindShader(GPUShader *shader);
/** Call after your last immEnd, or before binding another program. */
void immUnbindProgram(void);
@@ -50,10 +50,12 @@ void immBegin(GPUPrimType, uint vertex_len);
void immBeginAtMost(GPUPrimType, uint max_vertex_len);
void immEnd(void); /* finishes and draws. */
-/* immBegin a batch, then use standard immFunctions as usual. */
-/* immEnd will finalize the batch instead of drawing. */
-/* Then you can draw it as many times as you like!
+/* - #immBegin a batch, then use standard `imm*` functions as usual.
+ * - #immEnd will finalize the batch instead of drawing.
+ *
+ * Then you can draw it as many times as you like!
* Partially replaces the need for display lists. */
+
GPUBatch *immBeginBatch(GPUPrimType, uint vertex_len);
GPUBatch *immBeginBatchAtMost(GPUPrimType, uint vertex_len);
@@ -81,12 +83,14 @@ void immAttr4ub(uint attr_id, unsigned char r, unsigned char g, unsigned char b,
void immAttr3ubv(uint attr_id, const unsigned char data[3]);
void immAttr4ubv(uint attr_id, const unsigned char data[4]);
-/* Explicitly skip an attribute. */
-/* This advanced option kills automatic value copying for this attr_id. */
+/* Explicitly skip an attribute.
+ * This advanced option kills automatic value copying for this attr_id. */
+
void immAttrSkip(uint attr_id);
-/* Provide one last attribute value & end the current vertex. */
-/* This is most often used for 2D or 3D position (similar to glVertex). */
+/* Provide one last attribute value & end the current vertex.
+ * This is most often used for 2D or 3D position (similar to #glVertex). */
+
void immVertex2f(uint attr_id, float x, float y);
void immVertex3f(uint attr_id, float x, float y, float z);
void immVertex4f(uint attr_id, float x, float y, float z, float w);
@@ -101,6 +105,7 @@ void immVertex3fv(uint attr_id, const float data[3]);
void immVertex2iv(uint attr_id, const int data[2]);
/* Provide uniform values that don't change for the entire draw call. */
+
void immUniform1i(const char *name, int x);
void immUniform1f(const char *name, float x);
void immUniform2f(const char *name, float x, float y);
@@ -109,6 +114,9 @@ void immUniform3f(const char *name, float x, float y, float z);
void immUniform3fv(const char *name, const float data[3]);
void immUniform4f(const char *name, float x, float y, float z, float w);
void immUniform4fv(const char *name, const float data[4]);
+/**
+ * Note array index is not supported for name (i.e: "array[0]").
+ */
void immUniformArray4fv(const char *bare_name, const float *data, int count);
void immUniformMatrix4fv(const char *name, const float data[4][4]);
@@ -116,7 +124,8 @@ void immBindTexture(const char *name, GPUTexture *tex);
void immBindTextureSampler(const char *name, GPUTexture *tex, eGPUSamplerState state);
/* Convenience functions for setting "uniform vec4 color". */
-/* The rgb functions have implicit alpha = 1.0. */
+/* The RGB functions have implicit alpha = 1.0. */
+
void immUniformColor4f(float r, float g, float b, float a);
void immUniformColor4fv(const float rgba[4]);
void immUniformColor3f(float r, float g, float b);
@@ -135,7 +144,7 @@ void immUniformColor4ubv(const unsigned char rgba[4]);
*/
void immBindBuiltinProgram(eGPUBuiltinShader shader_id);
-/* Extend immUniformColor to take Blender's themes */
+/** Extend #immUniformColor to take Blender's themes. */
void immUniformThemeColor(int color_id);
void immUniformThemeColorAlpha(int color_id, float a);
void immUniformThemeColor3(int color_id);
diff --git a/source/blender/gpu/GPU_immediate_util.h b/source/blender/gpu/GPU_immediate_util.h
index 047c3d3da00..102bd6c284c 100644
--- a/source/blender/gpu/GPU_immediate_util.h
+++ b/source/blender/gpu/GPU_immediate_util.h
@@ -31,32 +31,85 @@ extern "C" {
void immRectf(uint pos, float x1, float y1, float x2, float y2);
void immRecti(uint pos, int x1, int y1, int x2, int y2);
-/* Same as immRectf/immRecti but does not call immBegin/immEnd. To use with GPU_PRIM_TRIS. */
+/**
+ * Same as #immRectf / #immRecti but does not call #immBegin / #immEnd.
+ * To use with #GPU_PRIM_TRIS.
+ */
void immRectf_fast(uint pos, float x1, float y1, float x2, float y2);
void immRectf_fast_with_color(
uint pos, uint col, float x1, float y1, float x2, float y2, const float color[4]);
void immRecti_fast_with_color(
uint pos, uint col, int x1, int y1, int x2, int y2, const float color[4]);
+/**
+ * Pack color into 3 bytes
+ *
+ * This define converts a numerical value to the equivalent 24-bit
+ * color, while not being endian-sensitive. On little-endian, this
+ * is the same as doing a 'naive' indexing, on big-endian, it is not!
+ *
+ * \note BGR format (i.e. 0xBBGGRR)...
+ *
+ * \param x: color.
+ */
void imm_cpack(uint x);
+/**
+ * Draw a circle outline with the given \a radius.
+ * The circle is centered at \a x, \a y and drawn in the XY plane.
+ *
+ * \param shdr_pos: The vertex attribute number for position.
+ * \param x: Horizontal center.
+ * \param y: Vertical center.
+ * \param radius: The circle's radius.
+ * \param nsegments: The number of segments to use in drawing (more = smoother).
+ */
void imm_draw_circle_wire_2d(uint shdr_pos, float x, float y, float radius, int nsegments);
+/**
+ * Draw a filled circle with the given \a radius.
+ * The circle is centered at \a x, \a y and drawn in the XY plane.
+ *
+ * \param shdr_pos: The vertex attribute number for position.
+ * \param x: Horizontal center.
+ * \param y: Vertical center.
+ * \param radius: The circle's radius.
+ * \param nsegments: The number of segments to use in drawing (more = smoother).
+ */
void imm_draw_circle_fill_2d(uint shdr_pos, float x, float y, float radius, int nsegments);
void imm_draw_circle_wire_aspect_2d(
- uint shdr_pos, float x, float y, float rad_x, float rad_y, int nsegments);
+ uint shdr_pos, float x, float y, float radius_x, float radius_y, int nsegments);
void imm_draw_circle_fill_aspect_2d(
- uint shdr_pos, float x, float y, float rad_x, float rad_y, int nsegments);
+ uint shdr_pos, float x, float y, float radius_x, float radius_y, int nsegments);
-/* use this version when GPUVertFormat has a vec3 position */
+/**
+ * Use this version when #GPUVertFormat has a vec3 position.
+ */
void imm_draw_circle_wire_3d(uint pos, float x, float y, float radius, int nsegments);
void imm_draw_circle_dashed_3d(uint pos, float x, float y, float radius, int nsegments);
void imm_draw_circle_fill_3d(uint pos, float x, float y, float radius, int nsegments);
-/* same as 'imm_draw_disk_partial_fill_2d', except it draws a wire arc. */
+/**
+ * Same as 'imm_draw_disk_partial_fill_2d', except it draws a wire arc.
+ */
void imm_draw_circle_partial_wire_2d(
uint pos, float x, float y, float radius, int nsegments, float start, float sweep);
+/**
+ * Draw a filled arc with the given inner and outer radius.
+ * The circle is centered at \a x, \a y and drawn in the XY plane.
+ *
+ * \note Arguments are `gluPartialDisk` compatible.
+ *
+ * \param pos: The vertex attribute number for position.
+ * \param x: Horizontal center.
+ * \param y: Vertical center.
+ * \param rad_inner: The inner circle's radius.
+ * \param rad_outer: The outer circle's radius (can be zero).
+ * \param nsegments: The number of segments to use in drawing (more = smoother).
+ * \param start: Specifies the starting angle, in degrees, of the disk portion.
+ * \param sweep: Specifies the sweep angle, in degrees, of the disk portion.
+ */
void imm_draw_disk_partial_fill_2d(uint pos,
float x,
float y,
@@ -66,9 +119,21 @@ void imm_draw_disk_partial_fill_2d(uint pos,
float start,
float sweep);
+/**
+ * Draw a lined box.
+ *
+ * \param pos: The vertex attribute number for position.
+ * \param x1: left.
+ * \param y1: bottom.
+ * \param x2: right.
+ * \param y2: top.
+ */
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);
+/**
+ * Draw a standard checkerboard to indicate transparent backgrounds.
+ */
void imm_draw_box_checker_2d_ex(float x1,
float y1,
float x2,
@@ -85,6 +150,18 @@ void imm_draw_cube_corners_3d(uint pos,
const float aspect[3],
const float factor);
+/**
+ * Draw a cylinder. Replacement for #gluCylinder.
+ * \warning Slow, better use it only if you no other choices.
+ *
+ * \param pos: The vertex attribute number for position.
+ * \param nor: The vertex attribute number for normal.
+ * \param base: Specifies the radius of the cylinder at z = 0.
+ * \param top: Specifies the radius of the cylinder at z = height.
+ * \param height: Specifies the height of the cylinder.
+ * \param slices: Specifies the number of subdivisions around the z axis.
+ * \param stacks: Specifies the number of subdivisions along the z axis.
+ */
void imm_draw_cylinder_fill_normal_3d(
uint pos, uint nor, float base, float top, float height, int slices, int stacks);
void imm_draw_cylinder_wire_3d(
@@ -92,7 +169,7 @@ void imm_draw_cylinder_wire_3d(
void imm_draw_cylinder_fill_3d(
uint pos, float base, float top, float height, int slices, int stacks);
-void imm_drawcircball(const float cent[3], float rad, const float tmat[4][4], uint pos);
+void imm_drawcircball(const float cent[3], float radius, const float tmat[4][4], uint pos);
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h
index e64521768f9..ea3028e539b 100644
--- a/source/blender/gpu/GPU_material.h
+++ b/source/blender/gpu/GPU_material.h
@@ -54,7 +54,7 @@ typedef struct GPUMaterial GPUMaterial;
typedef struct GPUNode GPUNode;
typedef struct GPUNodeLink GPUNodeLink;
-/* Functions to create GPU Materials nodes */
+/* Functions to create GPU Materials nodes. */
typedef enum eGPUType {
/* Keep in sync with GPU_DATATYPE_STR */
@@ -180,10 +180,17 @@ struct GPUUniformBuf *GPU_material_sss_profile_get(GPUMaterial *material,
int sample_len,
struct GPUTexture **tex_profile);
-/* High level functions to create and use GPU materials */
+/**
+ * High level functions to create and use GPU materials.
+ */
GPUMaterial *GPU_material_from_nodetree_find(struct ListBase *gpumaterials,
const void *engine_type,
int options);
+/**
+ * \note Caller must use #GPU_material_from_nodetree_find to re-use existing materials,
+ * This is enforced since constructing other arguments to this function may be expensive
+ * so only do this when they are needed.
+ */
GPUMaterial *GPU_material_from_nodetree(struct Scene *scene,
struct Material *ma,
struct bNodeTree *ntree,
@@ -205,10 +212,21 @@ void GPU_materials_free(struct Main *bmain);
struct Scene *GPU_material_scene(GPUMaterial *material);
struct GPUPass *GPU_material_get_pass(GPUMaterial *material);
struct GPUShader *GPU_material_get_shader(GPUMaterial *material);
+/**
+ * Return can be NULL if it's a world material.
+ */
struct Material *GPU_material_get_material(GPUMaterial *material);
+/**
+ * Return true if the material compilation has not yet begin or begin.
+ */
eGPUMaterialStatus GPU_material_status(GPUMaterial *mat);
struct GPUUniformBuf *GPU_material_uniform_buffer_get(GPUMaterial *material);
+/**
+ * Create dynamic UBO from parameters
+ *
+ * \param inputs: Items are #LinkData, data is #GPUInput (`BLI_genericNodeN(GPUInput)`).
+ */
void GPU_material_uniform_buffer_create(GPUMaterial *material, ListBase *inputs);
struct GPUUniformBuf *GPU_material_create_sss_profile_ubo(void);
diff --git a/source/blender/gpu/GPU_matrix.h b/source/blender/gpu/GPU_matrix.h
index edf16f04349..bfd4a14d112 100644
--- a/source/blender/gpu/GPU_matrix.h
+++ b/source/blender/gpu/GPU_matrix.h
@@ -31,7 +31,10 @@ extern "C" {
struct GPUShader;
-void GPU_matrix_reset(void); /* to Identity transform & empty stack */
+/**
+ * To Identity transform & empty stack.
+ */
+void GPU_matrix_reset(void);
/* ModelView Matrix (2D or 3D) */
@@ -52,9 +55,13 @@ void GPU_matrix_translate_3fv(const float vec[3]);
void GPU_matrix_scale_3f(float x, float y, float z);
void GPU_matrix_scale_3fv(const float vec[3]);
-/* Axis of rotation should be a unit vector. */
+/**
+ * Axis of rotation should be a unit vector.
+ */
void GPU_matrix_rotate_3f(float deg, float x, float y, float z);
-/* Axis of rotation should be a unit vector. */
+/**
+ * Axis of rotation should be a unit vector.
+ */
void GPU_matrix_rotate_3fv(float deg, const float axis[3]);
void GPU_matrix_rotate_axis(float deg, char axis); /* TODO: enum for axis? */
@@ -78,12 +85,12 @@ void GPU_matrix_scale_2f(float x, float y);
void GPU_matrix_scale_2fv(const float vec[2]);
void GPU_matrix_rotate_2d(float deg);
-/* Projection Matrix (2D or 3D) */
+/* Projection Matrix (2D or 3D). */
void GPU_matrix_push_projection(void);
void GPU_matrix_pop_projection(void);
-/* 3D Projection Matrix */
+/* 3D Projection Matrix. */
void GPU_matrix_identity_projection_set(void);
void GPU_matrix_projection_set(const float m[4][4]);
@@ -136,11 +143,12 @@ bool GPU_matrix_unproject_3fv(const float win[3],
const int view[4],
float r_world[3]);
-/* 2D Projection Matrix */
+/* 2D Projection Matrix. */
void GPU_matrix_ortho_2d_set(float left, float right, float bottom, float top);
-/* functions to get matrix values */
+/* Functions to get matrix values. */
+
const float (*GPU_matrix_model_view_get(float m[4][4]))[4];
const float (*GPU_matrix_projection_get(float m[4][4]))[4];
const float (*GPU_matrix_model_view_projection_get(float m[4][4]))[4];
@@ -148,12 +156,19 @@ const float (*GPU_matrix_model_view_projection_get(float m[4][4]))[4];
const float (*GPU_matrix_normal_get(float m[3][3]))[3];
const float (*GPU_matrix_normal_inverse_get(float m[3][3]))[3];
-/* set uniform values for currently bound shader */
+/**
+ * Set uniform values for currently bound shader.
+ */
void GPU_matrix_bind(struct GPUShader *shader);
bool GPU_matrix_dirty_get(void); /* since last bind */
-/* own working polygon offset */
+/**
+ * Own working polygon offset.
+ */
float GPU_polygon_offset_calc(const float (*winmat)[4], float viewdist, float dist);
+/**
+ * \note \a viewdist is only for orthographic projections at the moment.
+ */
void GPU_polygon_offset(float viewdist, float dist);
/* Python API needs to be able to inspect the stack so errors raise exceptions
diff --git a/source/blender/gpu/GPU_platform.h b/source/blender/gpu/GPU_platform.h
index fa7d5d7fba8..0d80c0ed8af 100644
--- a/source/blender/gpu/GPU_platform.h
+++ b/source/blender/gpu/GPU_platform.h
@@ -66,7 +66,10 @@ typedef enum eGPUSupportLevel {
extern "C" {
#endif
+/* GPU Types */
+
bool GPU_type_matches(eGPUDeviceType device, eGPUOSType os, eGPUDriverType driver);
+
eGPUSupportLevel GPU_platform_support_level(void);
const char *GPU_platform_vendor(void);
const char *GPU_platform_renderer(void);
diff --git a/source/blender/gpu/GPU_select.h b/source/blender/gpu/GPU_select.h
index d28363253b1..c02af763311 100644
--- a/source/blender/gpu/GPU_select.h
+++ b/source/blender/gpu/GPU_select.h
@@ -31,7 +31,7 @@ extern "C" {
struct rcti;
-/* flags for mode of operation */
+/** Flags for mode of operation. */
enum {
GPU_SELECT_ALL = 1,
/* gpu_select_query */
@@ -42,21 +42,48 @@ enum {
GPU_SELECT_PICK_NEAREST = 5,
};
+/**
+ * Initialize and provide buffer for results.
+ */
void GPU_select_begin(
unsigned int *buffer, unsigned int bufsize, const struct rcti *input, char mode, int oldhits);
+/**
+ * Loads a new selection id and ends previous query, if any.
+ * In second pass of selection it also returns
+ * if id has been hit on the first pass already.
+ * Thus we can skip drawing un-hit objects.
+ *
+ * \warning We rely on the order of object rendering on passes to be the same for this to work.
+ */
bool GPU_select_load_id(unsigned int id);
void GPU_select_finalize(void);
+/**
+ * Cleanup and flush selection results to buffer.
+ * Return number of hits and hits in buffer.
+ * if \a dopass is true, we will do a second pass with occlusion queries to get the closest hit.
+ */
unsigned int GPU_select_end(void);
-/* cache selection region */
+/* Cache selection region. */
+
bool GPU_select_is_cached(void);
void GPU_select_cache_begin(void);
void GPU_select_cache_load_id(void);
void GPU_select_cache_end(void);
-/* utilities */
+/* Utilities. */
+
+/**
+ * Helper function, nothing special but avoids doing inline since hits aren't sorted by depth
+ * and purpose of 4x buffer indices isn't so clear.
+ *
+ * Note that comparing depth as uint is fine.
+ */
const uint *GPU_select_buffer_near(const uint *buffer, int hits);
uint GPU_select_buffer_remove_by_id(uint *buffer, int hits, uint select_id);
+/**
+ * Part of the solution copied from `rect_subregion_stride_calc`.
+ */
void GPU_select_buffer_stride_realign(const struct rcti *src, const struct rcti *dst, uint *r_buf);
#ifdef __cplusplus
diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h
index 614af01b17b..5c373551494 100644
--- a/source/blender/gpu/GPU_shader.h
+++ b/source/blender/gpu/GPU_shader.h
@@ -70,6 +70,26 @@ GPUShader *GPU_shader_create_ex(const char *vertcode,
struct GPU_ShaderCreateFromArray_Params {
const char **vert, **geom, **frag, **defs;
};
+/**
+ * Use via #GPU_shader_create_from_arrays macro (avoids passing in param).
+ *
+ * Similar to #DRW_shader_create_with_lib with the ability to include libs for each type of shader.
+ *
+ * It has the advantage that each item can be conditionally included
+ * without having to build the string inline, then free it.
+ *
+ * \param params: NULL terminated arrays of strings.
+ *
+ * Example:
+ * \code{.c}
+ * sh = GPU_shader_create_from_arrays({
+ * .vert = (const char *[]){shader_lib_glsl, shader_vert_glsl, NULL},
+ * .geom = (const char *[]){shader_geom_glsl, NULL},
+ * .frag = (const char *[]){shader_frag_glsl, NULL},
+ * .defs = (const char *[]){"#define DEFINE\n", test ? "#define OTHER_DEFINE\n" : "", NULL},
+ * });
+ * \endcode
+ */
struct GPUShader *GPU_shader_create_from_arrays_impl(
const struct GPU_ShaderCreateFromArray_Params *params, const char *func, int line);
@@ -88,10 +108,13 @@ void GPU_shader_unbind(void);
const char *GPU_shader_get_name(GPUShader *shader);
-/* Returns true if transform feedback was successfully enabled. */
+/**
+ * Returns true if transform feedback was successfully enabled.
+ */
bool GPU_shader_transform_feedback_enable(GPUShader *shader, struct GPUVertBuf *vertbuf);
void GPU_shader_transform_feedback_disable(GPUShader *shader);
+/** DEPRECATED: Kept only because of BGL API. */
int GPU_shader_get_program(GPUShader *shader);
typedef enum {
@@ -134,6 +157,7 @@ void GPU_shader_set_srgb_uniform(GPUShader *shader);
int GPU_shader_get_uniform(GPUShader *shader, const char *name);
int GPU_shader_get_builtin_uniform(GPUShader *shader, int builtin);
int GPU_shader_get_builtin_block(GPUShader *shader, int builtin);
+/** DEPRECATED: Kept only because of Python GPU API. */
int GPU_shader_get_uniform_block(GPUShader *shader, const char *name);
int GPU_shader_get_ssbo(GPUShader *shader, const char *name);
diff --git a/source/blender/gpu/GPU_state.h b/source/blender/gpu/GPU_state.h
index 1c1211d2a3e..fa70a8934db 100644
--- a/source/blender/gpu/GPU_state.h
+++ b/source/blender/gpu/GPU_state.h
@@ -48,8 +48,8 @@ ENUM_OPERATORS(eGPUBarrier, GPU_BARRIER_SHADER_STORAGE)
* Defines the fixed pipeline blending equation.
* SRC is the output color from the shader.
* DST is the color from the frame-buffer.
- * The blending equation is :
- * (SRC * A) + (DST * B).
+ * The blending equation is:
+ * `(SRC * A) + (DST * B)`.
* The blend mode will modify the A and B parameters.
*/
typedef enum eGPUBlend {
@@ -124,10 +124,23 @@ void GPU_front_facing(bool invert);
void GPU_depth_range(float near, float far);
void GPU_scissor_test(bool enable);
void GPU_line_smooth(bool enable);
+/**
+ * \note By convention, this is set as needed and not reset back to 1.0.
+ * This means code that draws lines must always set the line width beforehand,
+ * but is not expected to restore it's previous value.
+ */
void GPU_line_width(float width);
void GPU_logic_op_xor_set(bool enable);
void GPU_point_size(float size);
void GPU_polygon_smooth(bool enable);
+
+/**
+ * Programmable point size:
+ * - Shaders set their own point size when enabled
+ * - Use GPU_point_size when disabled.
+ *
+ * TODO: remove and use program point size everywhere.
+ */
void GPU_program_point_size(bool enable);
void GPU_scissor(int x, int y, int width, int height);
void GPU_scissor_get(int coords[4]);
@@ -158,6 +171,9 @@ eGPUDepthTest GPU_depth_test_get(void);
eGPUWriteMask GPU_write_mask_get(void);
uint GPU_stencil_mask_get(void);
eGPUStencilTest GPU_stencil_test_get(void);
+/**
+ * \note Already pre-multiplied by `U.pixelsize`.
+ */
float GPU_line_width_get(void);
void GPU_flush(void);
@@ -165,6 +181,10 @@ void GPU_finish(void);
void GPU_apply_state(void);
void GPU_bgl_start(void);
+
+/**
+ * Just turn off the `bgl` safeguard system. Can be called even without #GPU_bgl_start.
+ */
void GPU_bgl_end(void);
bool GPU_bgl_get(void);
diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h
index deff9e47871..54e9bde70d8 100644
--- a/source/blender/gpu/GPU_texture.h
+++ b/source/blender/gpu/GPU_texture.h
@@ -32,7 +32,8 @@ struct GPUVertBuf;
/** Opaque type hiding blender::gpu::Texture. */
typedef struct GPUTexture GPUTexture;
-/* GPU Samplers state
+/**
+ * GPU Samplers state
* - Specify the sampler state to bind a texture with.
* - Internally used by textures.
* - All states are created at startup to avoid runtime costs.
@@ -60,8 +61,9 @@ typedef enum eGPUSamplerState {
} \
} while (0)
-/* `GPU_SAMPLER_MAX` is not a valid enum value, but only a limit.
- * It also creates a bad mask for the `NOT` operator in `ENUM_OPERATORS`.
+/**
+ * #GPU_SAMPLER_MAX is not a valid enum value, but only a limit.
+ * It also creates a bad mask for the `NOT` operator in #ENUM_OPERATORS.
*/
static const int GPU_SAMPLER_MAX = (GPU_SAMPLER_ICON + 1);
ENUM_OPERATORS(eGPUSamplerState, GPU_SAMPLER_ICON)
@@ -70,6 +72,9 @@ ENUM_OPERATORS(eGPUSamplerState, GPU_SAMPLER_ICON)
extern "C" {
#endif
+/**
+ * Update user defined sampler states.
+ */
void GPU_samplers_update(void);
/* GPU Texture
@@ -84,11 +89,13 @@ void GPU_samplers_update(void);
* - if created with from_blender, will not free the texture
*/
-/* Wrapper to supported OpenGL/Vulkan texture internal storage
+/**
+ * Wrapper to supported OpenGL/Vulkan texture internal storage
* If you need a type just un-comment it. Be aware that some formats
* are not supported by render-buffers. All of the following formats
* are part of the OpenGL 3.3 core
- * specification. */
+ * specification.
+ */
typedef enum eGPUTextureFormat {
/* Formats texture & render-buffer. */
GPU_RGBA8UI,
@@ -221,12 +228,19 @@ GPUTexture *GPU_texture_create_cube_array(
const char *name, int w, int d, int mip_len, eGPUTextureFormat format, const float *data);
/* Special textures. */
+
GPUTexture *GPU_texture_create_from_vertbuf(const char *name, struct GPUVertBuf *vert);
/**
* \a data should hold all the data for all mipmaps.
*/
+/**
+ * DDS texture loading. Return NULL if support is not available.
+ */
GPUTexture *GPU_texture_create_compressed_2d(
const char *name, int w, int h, int miplen, eGPUTextureFormat format, const void *data);
+/**
+ * Create an error texture that will bind an invalid texture (pink) at draw time.
+ */
GPUTexture *GPU_texture_create_error(int dimension, bool array);
void GPU_texture_update_mipmap(GPUTexture *tex,
@@ -234,6 +248,9 @@ void GPU_texture_update_mipmap(GPUTexture *tex,
eGPUDataFormat gpu_data_format,
const void *pixels);
+/**
+ * \note Updates only mip 0.
+ */
void GPU_texture_update(GPUTexture *tex, eGPUDataFormat data_format, const void *data);
void GPU_texture_update_sub(GPUTexture *tex,
eGPUDataFormat data_format,
@@ -244,9 +261,20 @@ void GPU_texture_update_sub(GPUTexture *tex,
int width,
int height,
int depth);
+/**
+ * Makes data interpretation aware of the source layout.
+ * Skipping pixels correctly when changing rows when doing partial update.
+ */
void GPU_unpack_row_length_set(uint len);
void *GPU_texture_read(GPUTexture *tex, eGPUDataFormat data_format, int miplvl);
+/**
+ * Fills the whole texture with the same data for all pixels.
+ * \warning Only work for 2D texture for now.
+ * \warning Only clears the mip 0 of the texture.
+ * \param data_format: data format of the pixel data.
+ * \param data: 1 pixel worth of data to fill the texture with.
+ */
void GPU_texture_clear(GPUTexture *tex, eGPUDataFormat data_format, const void *data);
void GPU_texture_free(GPUTexture *tex);
@@ -261,6 +289,9 @@ void GPU_texture_image_bind(GPUTexture *tex, int unit);
void GPU_texture_image_unbind(GPUTexture *tex);
void GPU_texture_image_unbind_all(void);
+/**
+ * Copy a texture content to a similar texture. Only MIP 0 is copied.
+ */
void GPU_texture_copy(GPUTexture *dst, GPUTexture *src);
void GPU_texture_generate_mipmap(GPUTexture *tex);
@@ -292,7 +323,8 @@ int GPU_texture_opengl_bindcode(const GPUTexture *tex);
void GPU_texture_get_mipmap_size(GPUTexture *tex, int lvl, int *size);
-/* utilities */
+/* Utilities. */
+
size_t GPU_texture_component_len(eGPUTextureFormat format);
size_t GPU_texture_dataformat_size(eGPUDataFormat data_format);
diff --git a/source/blender/gpu/GPU_uniform_buffer.h b/source/blender/gpu/GPU_uniform_buffer.h
index 4efac0a8c00..c9ea1582ad4 100644
--- a/source/blender/gpu/GPU_uniform_buffer.h
+++ b/source/blender/gpu/GPU_uniform_buffer.h
@@ -40,6 +40,12 @@ struct ListBase;
typedef struct GPUUniformBuf GPUUniformBuf;
GPUUniformBuf *GPU_uniformbuf_create_ex(size_t size, const void *data, const char *name);
+/**
+ * Create UBO from inputs list.
+ * Return NULL if failed to create or if \param inputs: is empty.
+ *
+ * \param inputs: ListBase of #BLI_genericNodeN(#GPUInput).
+ */
GPUUniformBuf *GPU_uniformbuf_create_from_list(struct ListBase *inputs, const char *name);
#define GPU_uniformbuf_create(size) GPU_uniformbuf_create_ex(size, NULL, __func__);
diff --git a/source/blender/gpu/GPU_vertex_buffer.h b/source/blender/gpu/GPU_vertex_buffer.h
index 2c54016daa7..62a495abfb3 100644
--- a/source/blender/gpu/GPU_vertex_buffer.h
+++ b/source/blender/gpu/GPU_vertex_buffer.h
@@ -79,10 +79,13 @@ GPUVertBuf *GPU_vertbuf_create_with_format_ex(const GPUVertFormat *, GPUUsageTyp
*/
const void *GPU_vertbuf_read(GPUVertBuf *verts);
void *GPU_vertbuf_unmap(const GPUVertBuf *verts, const void *mapped_data);
+/** Same as discard but does not free. */
void GPU_vertbuf_clear(GPUVertBuf *verts);
void GPU_vertbuf_discard(GPUVertBuf *);
-/* Avoid GPUVertBuf datablock being free but not its data. */
+/**
+ * Avoid GPUVertBuf data-block being free but not its data.
+ */
void GPU_vertbuf_handle_ref_add(GPUVertBuf *verts);
void GPU_vertbuf_handle_ref_remove(GPUVertBuf *verts);
@@ -93,25 +96,42 @@ void GPU_vertbuf_init_with_format_ex(GPUVertBuf *, const GPUVertFormat *, GPUUsa
GPUVertBuf *GPU_vertbuf_duplicate(GPUVertBuf *verts);
+/**
+ * Create a new allocation, discarding any existing data.
+ */
void GPU_vertbuf_data_alloc(GPUVertBuf *, uint v_len);
+/**
+ * Resize buffer keeping existing data.
+ */
void GPU_vertbuf_data_resize(GPUVertBuf *, uint v_len);
+/**
+ * Set vertex count but does not change allocation.
+ * Only this many verts will be uploaded to the GPU and rendered.
+ * This is useful for streaming data.
+ */
void GPU_vertbuf_data_len_set(GPUVertBuf *, uint v_len);
-/* The most important #set_attr variant is the untyped one. Get it right first.
+/**
+ * The most important #set_attr variant is the untyped one. Get it right first.
* It takes a void* so the app developer is responsible for matching their app data types
* to the vertex attribute's type and component count. They're in control of both, so this
- * should not be a problem. */
-
+ * should not be a problem.
+ */
void GPU_vertbuf_attr_set(GPUVertBuf *, uint a_idx, uint v_idx, const void *data);
+/** Fills a whole vertex (all attributes). Data must match packed layout. */
void GPU_vertbuf_vert_set(GPUVertBuf *verts, uint v_idx, const void *data);
-/* Tightly packed, non interleaved input data. */
+/**
+ * Tightly packed, non interleaved input data.
+ */
void GPU_vertbuf_attr_fill(GPUVertBuf *, uint a_idx, const void *data);
void GPU_vertbuf_attr_fill_stride(GPUVertBuf *, uint a_idx, uint stride, const void *data);
-/* For low level access only */
+/**
+ * For low level access only.
+ */
typedef struct GPUVertBufRaw {
uint size;
uint stride;
@@ -138,18 +158,32 @@ GPU_INLINE uint GPU_vertbuf_raw_used(GPUVertBufRaw *a)
void GPU_vertbuf_attr_get_raw_data(GPUVertBuf *, uint a_idx, GPUVertBufRaw *access);
+/**
+ * Returns the data buffer and set it to null internally to avoid freeing.
+ * \note Be careful when using this. The data needs to match the expected format.
+ */
void *GPU_vertbuf_steal_data(GPUVertBuf *verts);
+/**
+ * \note Be careful when using this. The data needs to match the expected format.
+ */
void *GPU_vertbuf_get_data(const GPUVertBuf *verts);
const GPUVertFormat *GPU_vertbuf_get_format(const GPUVertBuf *verts);
uint GPU_vertbuf_get_vertex_alloc(const GPUVertBuf *verts);
uint GPU_vertbuf_get_vertex_len(const GPUVertBuf *verts);
GPUVertBufStatus GPU_vertbuf_get_status(const GPUVertBuf *verts);
+/**
+ * Should be rename to #GPU_vertbuf_data_upload.
+ */
void GPU_vertbuf_use(GPUVertBuf *);
void GPU_vertbuf_bind_as_ssbo(struct GPUVertBuf *verts, int binding);
-/* XXX do not use. */
+/**
+ * XXX: do not use!
+ * This is just a wrapper for the use of the Hair refine workaround.
+ * To be used with #GPU_vertbuf_use().
+ */
void GPU_vertbuf_update_sub(GPUVertBuf *verts, uint start, uint len, void *data);
/* Metrics */
diff --git a/source/blender/gpu/GPU_vertex_format.h b/source/blender/gpu/GPU_vertex_format.h
index 0d5388c6b82..4af9901a88c 100644
--- a/source/blender/gpu/GPU_vertex_format.h
+++ b/source/blender/gpu/GPU_vertex_format.h
@@ -113,8 +113,33 @@ uint GPU_vertformat_attr_add(
GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode);
void GPU_vertformat_alias_add(GPUVertFormat *, const char *alias);
+/**
+ * Makes vertex attribute from the next vertices to be accessible in the vertex shader.
+ * For an attribute named "attr" you can access the next nth vertex using "attr{number}".
+ * Use this function after specifying all the attributes in the format.
+ *
+ * NOTE: This does NOT work when using indexed rendering.
+ * NOTE: Only works for first attribute name. (this limitation can be changed if needed)
+ *
+ * WARNING: this function creates a lot of aliases/attributes, make sure to keep the attribute
+ * name short to avoid overflowing the name-buffer.
+ */
void GPU_vertformat_multiload_enable(GPUVertFormat *format, int load_count);
+/**
+ * Make attribute layout non-interleaved.
+ * Warning! This does not change data layout!
+ * Use direct buffer access to fill the data.
+ * This is for advanced usage.
+ *
+ * De-interleaved data means all attribute data for each attribute
+ * is stored continuously like this:
+ * 000011112222
+ * instead of:
+ * 012012012012
+ *
+ * \note This is per attribute de-interleaving, NOT per component.
+ */
void GPU_vertformat_deinterleave(GPUVertFormat *format);
int GPU_vertformat_attr_id_get(const GPUVertFormat *, const char *name);
@@ -126,10 +151,16 @@ BLI_INLINE const char *GPU_vertformat_attr_name_get(const GPUVertFormat *format,
return format->names + attr->names[n_idx];
}
-/* WARNING: Can only rename using a string with same character count.
- * WARNING: This removes all other aliases of this attribute. */
+/**
+ * \warning Can only rename using a string with same character count.
+ * \warning This removes all other aliases of this attribute.
+ */
void GPU_vertformat_attr_rename(GPUVertFormat *format, int attr, const char *new_name);
+/**
+ * \warning Always add a prefix to the result of this function as
+ * the generated string can start with a number and not be a valid attribute name.
+ */
void GPU_vertformat_safe_attr_name(const char *attr_name, char *r_safe_name, uint max_len);
/* format conversion */
diff --git a/source/blender/gpu/GPU_viewport.h b/source/blender/gpu/GPU_viewport.h
index 4d9970dac90..c4948d68298 100644
--- a/source/blender/gpu/GPU_viewport.h
+++ b/source/blender/gpu/GPU_viewport.h
@@ -49,12 +49,26 @@ GPUViewport *GPU_viewport_create(void);
GPUViewport *GPU_viewport_stereo_create(void);
void GPU_viewport_bind(GPUViewport *viewport, int view, const rcti *rect);
void GPU_viewport_unbind(GPUViewport *viewport);
+/**
+ * Merge and draw the buffers of \a viewport into the currently active framebuffer, performing
+ * color transform to display space.
+ *
+ * \param rect: Coordinates to draw into. By swapping min and max values, drawing can be done
+ * with inversed axis coordinates (upside down or sideways).
+ */
void GPU_viewport_draw_to_screen(GPUViewport *viewport, int view, const rcti *rect);
+/**
+ * Version of #GPU_viewport_draw_to_screen() that lets caller decide if display colorspace
+ * transform should be performed.
+ */
void GPU_viewport_draw_to_screen_ex(GPUViewport *viewport,
int view,
const rcti *rect,
bool display_colorspace,
bool do_overlay_merge);
+/**
+ * Must be executed inside Draw-manager OpenGL Context.
+ */
void GPU_viewport_free(GPUViewport *viewport);
void GPU_viewport_colorspace_set(GPUViewport *viewport,
@@ -62,7 +76,13 @@ void GPU_viewport_colorspace_set(GPUViewport *viewport,
const ColorManagedDisplaySettings *display_settings,
float dither);
+/**
+ * Should be called from DRW after DRW_opengl_context_enable.
+ */
void GPU_viewport_bind_from_offscreen(GPUViewport *viewport, struct GPUOffScreen *ofs);
+/**
+ * Clear vars assigned from offscreen, so we don't free data owned by `GPUOffScreen`.
+ */
void GPU_viewport_unbind_from_offscreen(GPUViewport *viewport,
struct GPUOffScreen *ofs,
bool display_colorspace,
@@ -70,6 +90,9 @@ void GPU_viewport_unbind_from_offscreen(GPUViewport *viewport,
struct DRWData **GPU_viewport_data_get(GPUViewport *viewport);
+/**
+ * Merge the stereo textures. `color` and `overlay` texture will be modified.
+ */
void GPU_viewport_stereo_composite(GPUViewport *viewport, Stereo3dFormat *stereo_format);
void GPU_viewport_tag_update(GPUViewport *viewport);
@@ -82,6 +105,9 @@ GPUTexture *GPU_viewport_color_texture(GPUViewport *viewport, int view);
GPUTexture *GPU_viewport_overlay_texture(GPUViewport *viewport, int view);
GPUTexture *GPU_viewport_depth_texture(GPUViewport *viewport);
+/**
+ * Overlay frame-buffer for drawing outside of DRW module.
+ */
GPUFrameBuffer *GPU_viewport_framebuffer_overlay_get(GPUViewport *viewport);
#ifdef __cplusplus
diff --git a/source/blender/gpu/intern/gpu_batch.cc b/source/blender/gpu/intern/gpu_batch.cc
index 0e5c7900da9..2874dea775f 100644
--- a/source/blender/gpu/intern/gpu_batch.cc
+++ b/source/blender/gpu/intern/gpu_batch.cc
@@ -50,7 +50,7 @@ using namespace blender::gpu;
/** \name Creation & Deletion
* \{ */
-GPUBatch *GPU_batch_calloc(void)
+GPUBatch *GPU_batch_calloc()
{
GPUBatch *batch = GPUBackend::get()->batch_alloc();
memset(batch, 0, sizeof(*batch));
@@ -90,7 +90,6 @@ void GPU_batch_init_ex(GPUBatch *batch,
batch->shader = nullptr;
}
-/* This will share the VBOs with the new batch. */
void GPU_batch_copy(GPUBatch *batch_dst, GPUBatch *batch_src)
{
GPU_batch_init_ex(
@@ -137,7 +136,6 @@ void GPU_batch_discard(GPUBatch *batch)
/** \name Buffers Management
* \{ */
-/* NOTE: Override ONLY the first instance vbo (and free them if owned). */
void GPU_batch_instbuf_set(GPUBatch *batch, GPUVertBuf *inst, bool own_vbo)
{
BLI_assert(inst);
@@ -151,7 +149,6 @@ void GPU_batch_instbuf_set(GPUBatch *batch, GPUVertBuf *inst, bool own_vbo)
SET_FLAG_FROM_TEST(batch->flag, own_vbo, GPU_BATCH_OWNS_INST_VBO);
}
-/* NOTE: Override any previously assigned elem (and free it if owned). */
void GPU_batch_elembuf_set(GPUBatch *batch, GPUIndexBuf *elem, bool own_ibo)
{
BLI_assert(elem);
@@ -188,7 +185,6 @@ int GPU_batch_instbuf_add_ex(GPUBatch *batch, GPUVertBuf *insts, bool own_vbo)
return -1;
}
-/* Returns the index of verts in the batch. */
int GPU_batch_vertbuf_add_ex(GPUBatch *batch, GPUVertBuf *verts, bool own_vbo)
{
BLI_assert(verts);
@@ -243,7 +239,6 @@ void GPU_batch_draw_range(GPUBatch *batch, int v_first, int v_count)
GPU_batch_draw_advanced(batch, v_first, v_count, 0, 0);
}
-/* Draw multiple instance of a batch without having any instance attributes. */
void GPU_batch_draw_instanced(GPUBatch *batch, int i_count)
{
BLI_assert(batch->inst[0] == nullptr);
@@ -301,9 +296,6 @@ void GPU_batch_program_set_builtin(GPUBatch *batch, eGPUBuiltinShader shader_id)
GPU_batch_program_set_builtin_with_config(batch, shader_id, GPU_SHADER_CFG_DEFAULT);
}
-/* Bind program bound to IMM to the batch.
- * XXX Use this with much care. Drawing with the GPUBatch API is not compatible with IMM.
- * DO NOT DRAW WITH THE BATCH BEFORE CALLING immUnbindProgram. */
void GPU_batch_program_set_imm_shader(GPUBatch *batch)
{
GPU_batch_set_shader(batch, immGetShader());
@@ -315,12 +307,12 @@ void GPU_batch_program_set_imm_shader(GPUBatch *batch)
/** \name Init/Exit
* \{ */
-void gpu_batch_init(void)
+void gpu_batch_init()
{
gpu_batch_presets_init();
}
-void gpu_batch_exit(void)
+void gpu_batch_exit()
{
gpu_batch_presets_exit();
}
diff --git a/source/blender/gpu/intern/gpu_batch_presets.c b/source/blender/gpu/intern/gpu_batch_presets.c
index 6a1645a71d8..b97378ad638 100644
--- a/source/blender/gpu/intern/gpu_batch_presets.c
+++ b/source/blender/gpu/intern/gpu_batch_presets.c
@@ -154,7 +154,6 @@ GPUBatch *GPU_batch_preset_sphere_wire(int lod)
/** \name Create Sphere (3D)
* \{ */
-/* Replacement for gluSphere */
GPUBatch *gpu_batch_sphere(int lat_res, int lon_res)
{
const float lon_inc = 2 * M_PI / lon_res;
@@ -331,7 +330,6 @@ GPUBatch *GPU_batch_preset_panel_drag_widget(const float pixelsize,
return g_presets_2d.batch.panel_drag_widget;
}
-/* To be used with procedural placement inside shader. */
GPUBatch *GPU_batch_preset_quad(void)
{
if (!g_presets_2d.batch.quad) {
diff --git a/source/blender/gpu/intern/gpu_batch_utils.c b/source/blender/gpu/intern/gpu_batch_utils.c
index e2d03d27035..a381df5974a 100644
--- a/source/blender/gpu/intern/gpu_batch_utils.c
+++ b/source/blender/gpu/intern/gpu_batch_utils.c
@@ -33,15 +33,6 @@
/** \name Polygon Creation (2D)
* \{ */
-/**
- * Creates triangles from a byte-array of polygons.
- *
- * See 'make_shape_2d_from_blend.py' utility to create data to pass to this function.
- *
- * \param polys_flat: Pairs of X, Y coordinates (repeating to signify closing the polygon).
- * \param polys_flat_len: Length of the array (must be an even number).
- * \param rect: Optional region to map the byte 0..255 coords to. When not set use -1..1.
- */
GPUBatch *GPU_batch_tris_from_poly_2d_encoded(const uchar *polys_flat,
uint polys_flat_len,
const rctf *rect)
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
index 43483916236..bd24616820a 100644
--- a/source/blender/gpu/intern/gpu_buffers.c
+++ b/source/blender/gpu/intern/gpu_buffers.c
@@ -57,6 +57,10 @@
/* XXX: the rest of the code in this file is used for optimized PBVH
* drawing and doesn't interact at all with the buffer code above */
+/* -------------------------------------------------------------------- */
+/** \name Private Types
+ * \{ */
+
struct GPU_PBVH_Buffers {
GPUIndexBuf *index_buf, *index_buf_fast;
GPUIndexBuf *index_lines_buf, *index_lines_buf_fast;
@@ -204,7 +208,6 @@ static bool gpu_pbvh_is_looptri_visible(const MLoopTri *lt,
sculpt_face_sets[lt->poly] > SCULPT_FACE_SET_NONE);
}
-/* Threaded - do not call any functions that use OpenGL calls! */
void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
const MVert *mvert,
const float *vmask,
@@ -337,7 +340,6 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
buffers->mvert = mvert;
}
-/* Threaded - do not call any functions that use OpenGL calls! */
GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const MPoly *mpoly,
const MLoop *mloop,
const MLoopTri *looptri,
@@ -584,7 +586,6 @@ void GPU_pbvh_grid_buffers_update_free(GPU_PBVH_Buffers *buffers,
}
}
-/* Threaded - do not call any functions that use OpenGL calls! */
void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
SubdivCCG *subdiv_ccg,
CCGElem **grids,
@@ -764,7 +765,6 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
buffers->show_overlay = !empty_mask || !default_face_set;
}
-/* Threaded - do not call any functions that use OpenGL calls! */
GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build(int totgrid, BLI_bitmap **grid_hidden)
{
GPU_PBVH_Buffers *buffers;
@@ -878,9 +878,6 @@ void GPU_pbvh_bmesh_buffers_update_free(GPU_PBVH_Buffers *buffers)
}
}
-/* Creates a vertex buffer (coordinate, normal, color) and, if smooth
- * shading, an element index buffer.
- * Threaded - do not call any functions that use OpenGL calls! */
void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
BMesh *bm,
GSet *bm_faces,
@@ -1048,7 +1045,6 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
/** \name Generic
* \{ */
-/* Threaded - do not call any functions that use OpenGL calls! */
GPU_PBVH_Buffers *GPU_pbvh_bmesh_buffers_build(bool smooth_shading)
{
GPU_PBVH_Buffers *buffers;
diff --git a/source/blender/gpu/intern/gpu_capabilities.cc b/source/blender/gpu/intern/gpu_capabilities.cc
index c6e9dc210cb..f12fd96d1ba 100644
--- a/source/blender/gpu/intern/gpu_capabilities.cc
+++ b/source/blender/gpu/intern/gpu_capabilities.cc
@@ -44,7 +44,7 @@ using namespace blender::gpu;
/** \name Capabilities
* \{ */
-int GPU_max_texture_size(void)
+int GPU_max_texture_size()
{
return GCaps.max_texture_size;
}
@@ -57,27 +57,27 @@ int GPU_texture_size_with_limit(int res, bool limit_gl_texture_size)
return min_ii(reslimit, res);
}
-int GPU_max_texture_layers(void)
+int GPU_max_texture_layers()
{
return GCaps.max_texture_layers;
}
-int GPU_max_textures_vert(void)
+int GPU_max_textures_vert()
{
return GCaps.max_textures_vert;
}
-int GPU_max_textures_geom(void)
+int GPU_max_textures_geom()
{
return GCaps.max_textures_geom;
}
-int GPU_max_textures_frag(void)
+int GPU_max_textures_frag()
{
return GCaps.max_textures_frag;
}
-int GPU_max_textures(void)
+int GPU_max_textures()
{
return GCaps.max_textures;
}
@@ -92,37 +92,37 @@ int GPU_max_work_group_size(int index)
return GCaps.max_work_group_size[index];
}
-int GPU_max_uniforms_vert(void)
+int GPU_max_uniforms_vert()
{
return GCaps.max_uniforms_vert;
}
-int GPU_max_uniforms_frag(void)
+int GPU_max_uniforms_frag()
{
return GCaps.max_uniforms_frag;
}
-int GPU_max_batch_indices(void)
+int GPU_max_batch_indices()
{
return GCaps.max_batch_indices;
}
-int GPU_max_batch_vertices(void)
+int GPU_max_batch_vertices()
{
return GCaps.max_batch_vertices;
}
-int GPU_max_vertex_attribs(void)
+int GPU_max_vertex_attribs()
{
return GCaps.max_vertex_attribs;
}
-int GPU_max_varying_floats(void)
+int GPU_max_varying_floats()
{
return GCaps.max_varying_floats;
}
-int GPU_extensions_len(void)
+int GPU_extensions_len()
{
return GCaps.extensions_len;
}
@@ -132,43 +132,43 @@ const char *GPU_extension_get(int i)
return GCaps.extension_get ? GCaps.extension_get(i) : "\0";
}
-bool GPU_mip_render_workaround(void)
+bool GPU_mip_render_workaround()
{
return GCaps.mip_render_workaround;
}
-bool GPU_depth_blitting_workaround(void)
+bool GPU_depth_blitting_workaround()
{
return GCaps.depth_blitting_workaround;
}
-bool GPU_use_main_context_workaround(void)
+bool GPU_use_main_context_workaround()
{
return GCaps.use_main_context_workaround;
}
-bool GPU_crappy_amd_driver(void)
+bool GPU_crappy_amd_driver()
{
/* Currently are the same drivers with the `unused_fb_slot` problem. */
return GCaps.broken_amd_driver;
}
-bool GPU_use_hq_normals_workaround(void)
+bool GPU_use_hq_normals_workaround()
{
return GCaps.use_hq_normals_workaround;
}
-bool GPU_compute_shader_support(void)
+bool GPU_compute_shader_support()
{
return GCaps.compute_shader_support;
}
-bool GPU_shader_storage_buffer_objects_support(void)
+bool GPU_shader_storage_buffer_objects_support()
{
return GCaps.shader_storage_buffer_objects_support;
}
-bool GPU_shader_image_load_store_support(void)
+bool GPU_shader_image_load_store_support()
{
return GCaps.shader_image_load_store_support;
}
@@ -179,7 +179,7 @@ bool GPU_shader_image_load_store_support(void)
/** \name Memory statistics
* \{ */
-bool GPU_mem_stats_supported(void)
+bool GPU_mem_stats_supported()
{
return GCaps.mem_stats_support;
}
@@ -189,8 +189,7 @@ void GPU_mem_stats_get(int *totalmem, int *freemem)
Context::get()->memory_statistics_get(totalmem, freemem);
}
-/* Return support for the active context + window. */
-bool GPU_stereo_quadbuffer_support(void)
+bool GPU_stereo_quadbuffer_support()
{
return Context::get()->front_right != nullptr;
}
diff --git a/source/blender/gpu/intern/gpu_context.cc b/source/blender/gpu/intern/gpu_context.cc
index 943a6151ced..5af15d1bc3d 100644
--- a/source/blender/gpu/intern/gpu_context.cc
+++ b/source/blender/gpu/intern/gpu_context.cc
@@ -109,7 +109,6 @@ GPUContext *GPU_context_create(void *ghost_window)
return wrap(ctx);
}
-/* to be called after GPU_context_active_set(ctx_to_destroy) */
void GPU_context_discard(GPUContext *ctx_)
{
Context *ctx = unwrap(ctx_);
@@ -117,7 +116,6 @@ void GPU_context_discard(GPUContext *ctx_)
active_ctx = nullptr;
}
-/* ctx can be NULL */
void GPU_context_active_set(GPUContext *ctx_)
{
Context *ctx = unwrap(ctx_);
@@ -133,7 +131,7 @@ void GPU_context_active_set(GPUContext *ctx_)
}
}
-GPUContext *GPU_context_active_get(void)
+GPUContext *GPU_context_active_get()
{
return wrap(Context::get());
}
@@ -146,12 +144,12 @@ GPUContext *GPU_context_active_get(void)
static std::mutex main_context_mutex;
-void GPU_context_main_lock(void)
+void GPU_context_main_lock()
{
main_context_mutex.lock();
}
-void GPU_context_main_unlock(void)
+void GPU_context_main_unlock()
{
main_context_mutex.unlock();
}
@@ -180,7 +178,7 @@ void GPU_backend_init(eGPUBackendType backend_type)
}
}
-void GPU_backend_exit(void)
+void GPU_backend_exit()
{
/* TODO: assert no resource left. Currently UI textures are still not freed in their context
* correctly. */
diff --git a/source/blender/gpu/intern/gpu_debug.cc b/source/blender/gpu/intern/gpu_debug.cc
index 2d9fb7822ae..85cec67d2a7 100644
--- a/source/blender/gpu/intern/gpu_debug.cc
+++ b/source/blender/gpu/intern/gpu_debug.cc
@@ -45,7 +45,7 @@ void GPU_debug_group_begin(const char *name)
ctx->debug_group_begin(name, stack.size());
}
-void GPU_debug_group_end(void)
+void GPU_debug_group_end()
{
if (!(G.debug & G_DEBUG_GPU)) {
return;
@@ -55,10 +55,6 @@ void GPU_debug_group_end(void)
ctx->debug_group_end();
}
-/**
- * Return a formatted string showing the current group hierarchy in this format:
- * "Group1 > Group 2 > Group3 > ... > GroupN : "
- */
void GPU_debug_get_groups_names(int name_buf_len, char *r_name_buf)
{
Context *ctx = Context::get();
@@ -77,7 +73,6 @@ void GPU_debug_get_groups_names(int name_buf_len, char *r_name_buf)
r_name_buf[sz - 3] = '\0';
}
-/* Return true if inside a debug group with the same name. */
bool GPU_debug_group_match(const char *ref)
{
/* Otherwise there will be no names. */
diff --git a/source/blender/gpu/intern/gpu_framebuffer.cc b/source/blender/gpu/intern/gpu_framebuffer.cc
index 9099a6e4245..3404eb67e28 100644
--- a/source/blender/gpu/intern/gpu_framebuffer.cc
+++ b/source/blender/gpu/intern/gpu_framebuffer.cc
@@ -216,18 +216,12 @@ void GPU_framebuffer_bind(GPUFrameBuffer *gpu_fb)
unwrap(gpu_fb)->bind(enable_srgb);
}
-/**
- * Workaround for binding a SRGB frame-buffer without doing the SRGB transform.
- */
void GPU_framebuffer_bind_no_srgb(GPUFrameBuffer *gpu_fb)
{
const bool enable_srgb = false;
unwrap(gpu_fb)->bind(enable_srgb);
}
-/**
- * For stereo rendering.
- */
void GPU_backbuffer_bind(eGPUBackBuffer buffer)
{
Context *ctx = Context::get();
@@ -240,19 +234,18 @@ void GPU_backbuffer_bind(eGPUBackBuffer buffer)
}
}
-void GPU_framebuffer_restore(void)
+void GPU_framebuffer_restore()
{
Context::get()->back_left->bind(false);
}
-GPUFrameBuffer *GPU_framebuffer_active_get(void)
+GPUFrameBuffer *GPU_framebuffer_active_get()
{
Context *ctx = Context::get();
return wrap(ctx ? ctx->active_fb : nullptr);
}
-/* Returns the default frame-buffer. Will always exists even if it's just a dummy. */
-GPUFrameBuffer *GPU_framebuffer_back_get(void)
+GPUFrameBuffer *GPU_framebuffer_back_get()
{
Context *ctx = Context::get();
return wrap(ctx ? ctx->back_left : nullptr);
@@ -302,12 +295,6 @@ void GPU_framebuffer_texture_detach(GPUFrameBuffer *fb, GPUTexture *tex)
unwrap(tex)->detach_from(unwrap(fb));
}
-/**
- * First GPUAttachment in *config is always the depth/depth_stencil buffer.
- * Following GPUAttachments are color buffers.
- * Setting GPUAttachment.mip to -1 will leave the texture in this slot.
- * Setting GPUAttachment.tex to NULL will detach the texture in this slot.
- */
void GPU_framebuffer_config_array(GPUFrameBuffer *gpu_fb,
const GPUAttachment *config,
int config_len)
@@ -341,11 +328,6 @@ void GPU_framebuffer_config_array(GPUFrameBuffer *gpu_fb,
/* ---------- Viewport & Scissor Region ----------- */
-/**
- * Viewport and scissor size is stored per frame-buffer.
- * It is only reset to its original dimensions explicitly OR when binding the frame-buffer after
- * modifying its attachments.
- */
void GPU_framebuffer_viewport_set(GPUFrameBuffer *gpu_fb, int x, int y, int width, int height)
{
int viewport_rect[4] = {x, y, width, height};
@@ -357,9 +339,6 @@ void GPU_framebuffer_viewport_get(GPUFrameBuffer *gpu_fb, int r_viewport[4])
unwrap(gpu_fb)->viewport_get(r_viewport);
}
-/**
- * Reset to its attachment(s) size.
- */
void GPU_framebuffer_viewport_reset(GPUFrameBuffer *gpu_fb)
{
unwrap(gpu_fb)->viewport_reset();
@@ -376,9 +355,6 @@ void GPU_framebuffer_clear(GPUFrameBuffer *gpu_fb,
unwrap(gpu_fb)->clear(buffers, clear_col, clear_depth, clear_stencil);
}
-/**
- * Clear all textures attached to this frame-buffer with a different color.
- */
void GPU_framebuffer_multi_clear(GPUFrameBuffer *gpu_fb, const float (*clear_cols)[4])
{
unwrap(gpu_fb)->clear_multi(clear_cols);
@@ -425,7 +401,6 @@ void GPU_frontbuffer_read_pixels(
Context::get()->front_left->read(GPU_COLOR_BIT, format, rect, channels, 0, data);
}
-/* read_slot and write_slot are only used for color buffers. */
/* TODO(fclem): port as texture operation. */
void GPU_framebuffer_blit(GPUFrameBuffer *gpufb_read,
int read_slot,
@@ -466,11 +441,6 @@ void GPU_framebuffer_blit(GPUFrameBuffer *gpufb_read,
prev_fb->bind(true);
}
-/**
- * Use this if you need to custom down-sample your texture and use the previous mip-level as
- * input. This function only takes care of the correct texture handling. It execute the callback
- * for each texture level.
- */
void GPU_framebuffer_recursive_downsample(GPUFrameBuffer *gpu_fb,
int max_lvl,
void (*callback)(void *userData, int level),
@@ -514,14 +484,14 @@ void GPU_framebuffer_push(GPUFrameBuffer *fb)
FrameBufferStack.top++;
}
-GPUFrameBuffer *GPU_framebuffer_pop(void)
+GPUFrameBuffer *GPU_framebuffer_pop()
{
BLI_assert(FrameBufferStack.top > 0);
FrameBufferStack.top--;
return FrameBufferStack.framebuffers[FrameBufferStack.top];
}
-uint GPU_framebuffer_stack_level_get(void)
+uint GPU_framebuffer_stack_level_get()
{
return FrameBufferStack.top;
}
@@ -704,9 +674,6 @@ GPUTexture *GPU_offscreen_color_texture(const GPUOffScreen *ofs)
return ofs->color;
}
-/**
- * \note only to be used by viewport code!
- */
void GPU_offscreen_viewport_data_get(GPUOffScreen *ofs,
GPUFrameBuffer **r_fb,
GPUTexture **r_color,
diff --git a/source/blender/gpu/intern/gpu_immediate.cc b/source/blender/gpu/intern/gpu_immediate.cc
index cdd56a117db..7ca93252683 100644
--- a/source/blender/gpu/intern/gpu_immediate.cc
+++ b/source/blender/gpu/intern/gpu_immediate.cc
@@ -89,7 +89,6 @@ void immUnbindProgram()
imm->shader = nullptr;
}
-/* XXX do not use it. Special hack to use OCIO with batch API. */
GPUShader *immGetShader()
{
return imm->shader;
@@ -603,7 +602,6 @@ void immUniform4fv(const char *name, const float data[4])
GPU_shader_uniform_4fv(imm->shader, name, data);
}
-/* Note array index is not supported for name (i.e: "array[0]"). */
void immUniformArray4fv(const char *name, const float *data, int count)
{
GPU_shader_uniform_4fv_array(imm->shader, name, count, (const float(*)[4])data);
diff --git a/source/blender/gpu/intern/gpu_immediate_util.c b/source/blender/gpu/intern/gpu_immediate_util.c
index df18b89bd67..37a423d41a0 100644
--- a/source/blender/gpu/intern/gpu_immediate_util.c
+++ b/source/blender/gpu/intern/gpu_immediate_util.c
@@ -143,17 +143,6 @@ void immRecti_complete(int x1, int y1, int x2, int y2, const float color[4])
}
#endif
-/**
- * Pack color into 3 bytes
- *
- * This define converts a numerical value to the equivalent 24-bit
- * color, while not being endian-sensitive. On little-endian, this
- * is the same as doing a 'naive' indexing, on big-endian, it is not!
- *
- * \note BGR format (i.e. 0xBBGGRR)...
- *
- * \param x: color.
- */
void imm_cpack(uint x)
{
immUniformColor3ub(((x)&0xFF), (((x) >> 8) & 0xFF), (((x) >> 16) & 0xFF));
@@ -163,64 +152,44 @@ static void imm_draw_circle(GPUPrimType prim_type,
const uint shdr_pos,
float x,
float y,
- float rad_x,
- float rad_y,
+ float radius_x,
+ float radius_y,
int nsegments)
{
immBegin(prim_type, nsegments);
for (int i = 0; i < nsegments; i++) {
const float angle = (float)(2 * M_PI) * ((float)i / (float)nsegments);
- immVertex2f(shdr_pos, x + (rad_x * cosf(angle)), y + (rad_y * sinf(angle)));
+ immVertex2f(shdr_pos, x + (radius_x * cosf(angle)), y + (radius_y * sinf(angle)));
}
immEnd();
}
-/**
- * Draw a circle outline with the given \a radius.
- * The circle is centered at \a x, \a y and drawn in the XY plane.
- *
- * \param shdr_pos: The vertex attribute number for position.
- * \param x: Horizontal center.
- * \param y: Vertical center.
- * \param rad: The circle's radius.
- * \param nsegments: The number of segments to use in drawing (more = smoother).
- */
-void imm_draw_circle_wire_2d(uint shdr_pos, float x, float y, float rad, int nsegments)
+void imm_draw_circle_wire_2d(uint shdr_pos, float x, float y, float radius, int nsegments)
{
- imm_draw_circle(GPU_PRIM_LINE_LOOP, shdr_pos, x, y, rad, rad, nsegments);
+ imm_draw_circle(GPU_PRIM_LINE_LOOP, shdr_pos, x, y, radius, radius, nsegments);
}
-/**
- * Draw a filled circle with the given \a radius.
- * The circle is centered at \a x, \a y and drawn in the XY plane.
- *
- * \param shdr_pos: The vertex attribute number for position.
- * \param x: Horizontal center.
- * \param y: Vertical center.
- * \param rad: The circle's radius.
- * \param nsegments: The number of segments to use in drawing (more = smoother).
- */
-void imm_draw_circle_fill_2d(uint shdr_pos, float x, float y, float rad, int nsegments)
+void imm_draw_circle_fill_2d(uint shdr_pos, float x, float y, float radius, int nsegments)
{
- imm_draw_circle(GPU_PRIM_TRI_FAN, shdr_pos, x, y, rad, rad, nsegments);
+ imm_draw_circle(GPU_PRIM_TRI_FAN, shdr_pos, x, y, radius, radius, nsegments);
}
void imm_draw_circle_wire_aspect_2d(
- uint shdr_pos, float x, float y, float rad_x, float rad_y, int nsegments)
+ uint shdr_pos, float x, float y, float radius_x, float radius_y, int nsegments)
{
- imm_draw_circle(GPU_PRIM_LINE_LOOP, shdr_pos, x, y, rad_x, rad_y, nsegments);
+ imm_draw_circle(GPU_PRIM_LINE_LOOP, shdr_pos, x, y, radius_x, radius_y, nsegments);
}
void imm_draw_circle_fill_aspect_2d(
- uint shdr_pos, float x, float y, float rad_x, float rad_y, int nsegments)
+ uint shdr_pos, float x, float y, float radius_x, float radius_y, int nsegments)
{
- imm_draw_circle(GPU_PRIM_TRI_FAN, shdr_pos, x, y, rad_x, rad_y, nsegments);
+ imm_draw_circle(GPU_PRIM_TRI_FAN, shdr_pos, x, y, radius_x, radius_y, nsegments);
}
static void imm_draw_circle_partial(GPUPrimType prim_type,
uint pos,
float x,
float y,
- float rad,
+ float radius,
int nsegments,
float start,
float sweep)
@@ -234,15 +203,15 @@ static void imm_draw_circle_partial(GPUPrimType prim_type,
const float angle = interpf(angle_start, angle_end, ((float)i / (float)(nsegments - 1)));
const float angle_sin = sinf(angle);
const float angle_cos = cosf(angle);
- immVertex2f(pos, x + rad * angle_cos, y + rad * angle_sin);
+ immVertex2f(pos, x + radius * angle_cos, y + radius * angle_sin);
}
immEnd();
}
void imm_draw_circle_partial_wire_2d(
- uint pos, float x, float y, float rad, int nsegments, float start, float sweep)
+ uint pos, float x, float y, float radius, int nsegments, float start, float sweep)
{
- imm_draw_circle_partial(GPU_PRIM_LINE_STRIP, pos, x, y, rad, nsegments, start, sweep);
+ imm_draw_circle_partial(GPU_PRIM_LINE_STRIP, pos, x, y, radius, nsegments, start, sweep);
}
static void imm_draw_disk_partial(GPUPrimType prim_type,
@@ -274,21 +243,6 @@ static void imm_draw_disk_partial(GPUPrimType prim_type,
immEnd();
}
-/**
- * Draw a filled arc with the given inner and outer radius.
- * The circle is centered at \a x, \a y and drawn in the XY plane.
- *
- * \note Arguments are `gluPartialDisk` compatible.
- *
- * \param pos: The vertex attribute number for position.
- * \param x: Horizontal center.
- * \param y: Vertical center.
- * \param rad_inner: The inner circle's radius.
- * \param rad_outer: The outer circle's radius (can be zero).
- * \param nsegments: The number of segments to use in drawing (more = smoother).
- * \param start: Specifies the starting angle, in degrees, of the disk portion.
- * \param sweep: Specifies the sweep angle, in degrees, of the disk portion.
- */
void imm_draw_disk_partial_fill_2d(uint pos,
float x,
float y,
@@ -303,40 +257,31 @@ void imm_draw_disk_partial_fill_2d(uint pos,
}
static void imm_draw_circle_3D(
- GPUPrimType prim_type, uint pos, float x, float y, float rad, int nsegments)
+ GPUPrimType prim_type, uint pos, float x, float y, float radius, int nsegments)
{
immBegin(prim_type, nsegments);
for (int i = 0; i < nsegments; i++) {
float angle = (float)(2 * M_PI) * ((float)i / (float)nsegments);
- immVertex3f(pos, x + rad * cosf(angle), y + rad * sinf(angle), 0.0f);
+ immVertex3f(pos, x + radius * cosf(angle), y + radius * sinf(angle), 0.0f);
}
immEnd();
}
-void imm_draw_circle_wire_3d(uint pos, float x, float y, float rad, int nsegments)
+void imm_draw_circle_wire_3d(uint pos, float x, float y, float radius, int nsegments)
{
- imm_draw_circle_3D(GPU_PRIM_LINE_LOOP, pos, x, y, rad, nsegments);
+ imm_draw_circle_3D(GPU_PRIM_LINE_LOOP, pos, x, y, radius, nsegments);
}
-void imm_draw_circle_dashed_3d(uint pos, float x, float y, float rad, int nsegments)
+void imm_draw_circle_dashed_3d(uint pos, float x, float y, float radius, int nsegments)
{
- imm_draw_circle_3D(GPU_PRIM_LINES, pos, x, y, rad, nsegments / 2);
+ imm_draw_circle_3D(GPU_PRIM_LINES, pos, x, y, radius, nsegments / 2);
}
-void imm_draw_circle_fill_3d(uint pos, float x, float y, float rad, int nsegments)
+void imm_draw_circle_fill_3d(uint pos, float x, float y, float radius, int nsegments)
{
- imm_draw_circle_3D(GPU_PRIM_TRI_FAN, pos, x, y, rad, nsegments);
+ imm_draw_circle_3D(GPU_PRIM_TRI_FAN, pos, x, y, radius, nsegments);
}
-/**
- * Draw a lined box.
- *
- * \param pos: The vertex attribute number for position.
- * \param x1: left.
- * \param y1: bottom.
- * \param x2: right.
- * \param y2: top.
- */
void imm_draw_box_wire_2d(uint pos, float x1, float y1, float x2, float y2)
{
immBegin(GPU_PRIM_LINE_LOOP, 4);
@@ -358,9 +303,6 @@ void imm_draw_box_wire_3d(uint pos, float x1, float y1, float x2, float y2)
immEnd();
}
-/**
- * Draw a standard checkerboard to indicate transparent backgrounds.
- */
void imm_draw_box_checker_2d_ex(float x1,
float y1,
float x2,
@@ -458,18 +400,6 @@ void imm_draw_cube_corners_3d(uint pos,
immEnd();
}
-/**
- * Draw a cylinder. Replacement for gluCylinder.
- * _warning_ : Slow, better use it only if you no other choices.
- *
- * \param pos: The vertex attribute number for position.
- * \param nor: The vertex attribute number for normal.
- * \param base: Specifies the radius of the cylinder at z = 0.
- * \param top: Specifies the radius of the cylinder at z = height.
- * \param height: Specifies the height of the cylinder.
- * \param slices: Specifies the number of subdivisions around the z axis.
- * \param stacks: Specifies the number of subdivisions along the z axis.
- */
void imm_draw_cylinder_fill_normal_3d(
uint pos, uint nor, float base, float top, float height, int slices, int stacks)
{
@@ -608,7 +538,7 @@ void imm_draw_cylinder_fill_3d(
static void circball_array_fill(const float verts[CIRCLE_RESOL][3],
const float cent[3],
- float rad,
+ const float radius,
const float tmat[4][4])
{
/* 32 values of sin function (still same result!) */
@@ -632,8 +562,8 @@ static void circball_array_fill(const float verts[CIRCLE_RESOL][3],
float vx[3], vy[3];
float *viter = (float *)verts;
- mul_v3_v3fl(vx, tmat[0], rad);
- mul_v3_v3fl(vy, tmat[1], rad);
+ mul_v3_v3fl(vx, tmat[0], radius);
+ mul_v3_v3fl(vy, tmat[1], radius);
for (uint a = 0; a < CIRCLE_RESOL; a++, viter += 3) {
viter[0] = cent[0] + sinval[a] * vx[0] + cosval[a] * vy[0];
@@ -642,11 +572,11 @@ static void circball_array_fill(const float verts[CIRCLE_RESOL][3],
}
}
-void imm_drawcircball(const float cent[3], float rad, const float tmat[4][4], uint pos)
+void imm_drawcircball(const float cent[3], float radius, const float tmat[4][4], uint pos)
{
float verts[CIRCLE_RESOL][3];
- circball_array_fill(verts, cent, rad, tmat);
+ circball_array_fill(verts, cent, radius, tmat);
immBegin(GPU_PRIM_LINE_LOOP, CIRCLE_RESOL);
for (int i = 0; i < CIRCLE_RESOL; i++) {
diff --git a/source/blender/gpu/intern/gpu_index_buffer.cc b/source/blender/gpu/intern/gpu_index_buffer.cc
index be7470e79c1..3472cc24a74 100644
--- a/source/blender/gpu/intern/gpu_index_buffer.cc
+++ b/source/blender/gpu/intern/gpu_index_buffer.cc
@@ -349,7 +349,7 @@ uint32_t *IndexBuf::unmap(const uint32_t *mapped_memory) const
/** \name C-API
* \{ */
-GPUIndexBuf *GPU_indexbuf_calloc(void)
+GPUIndexBuf *GPU_indexbuf_calloc()
{
return wrap(GPUBackend::get()->indexbuf_alloc());
}
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index 6872a08e854..3804f2f0dd1 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -115,7 +115,6 @@ enum {
/* Functions */
-/* Returns the address of the future pointer to coba_tex */
GPUTexture **gpu_material_ramp_texture_row_set(GPUMaterial *mat,
int size,
float *pixels,
@@ -212,7 +211,6 @@ GPUShader *GPU_material_get_shader(GPUMaterial *material)
return material->pass ? GPU_pass_shader_get(material->pass) : NULL;
}
-/* Return can be NULL if it's a world material. */
Material *GPU_material_get_material(GPUMaterial *material)
{
return material->ma;
@@ -223,11 +221,6 @@ GPUUniformBuf *GPU_material_uniform_buffer_get(GPUMaterial *material)
return material->ubo;
}
-/**
- * Create dynamic UBO from parameters
- *
- * \param inputs: Items are #LinkData, data is #GPUInput (`BLI_genericNodeN(GPUInput)`).
- */
void GPU_material_uniform_buffer_create(GPUMaterial *material, ListBase *inputs)
{
#ifndef NDEBUG
@@ -545,7 +538,6 @@ GSet *gpu_material_used_libraries(GPUMaterial *material)
return material->used_libraries;
}
-/* Return true if the material compilation has not yet begin or begin. */
eGPUMaterialStatus GPU_material_status(GPUMaterial *mat)
{
return mat->status;
@@ -592,11 +584,6 @@ GPUMaterial *GPU_material_from_nodetree_find(ListBase *gpumaterials,
return NULL;
}
-/**
- * \note Caller must use #GPU_material_from_nodetree_find to re-use existing materials,
- * This is enforced since constructing other arguments to this function may be expensive
- * so only do this when they are needed.
- */
GPUMaterial *GPU_material_from_nodetree(Scene *scene,
struct Material *ma,
struct bNodeTree *ntree,
diff --git a/source/blender/gpu/intern/gpu_matrix.cc b/source/blender/gpu/intern/gpu_matrix.cc
index bbcc241f5e3..cf3f7f5e778 100644
--- a/source/blender/gpu/intern/gpu_matrix.cc
+++ b/source/blender/gpu/intern/gpu_matrix.cc
@@ -67,7 +67,7 @@ struct GPUMatrixState {
#define ProjectionStack Context::get()->matrix_state->projection_stack
#define Projection ProjectionStack.stack[ProjectionStack.top]
-GPUMatrixState *GPU_matrix_state_create(void)
+GPUMatrixState *GPU_matrix_state_create()
{
#define MATRIX_4X4_IDENTITY \
{ \
@@ -99,7 +99,7 @@ static void gpu_matrix_state_active_set_dirty(bool value)
state->dirty = value;
}
-void GPU_matrix_reset(void)
+void GPU_matrix_reset()
{
GPUMatrixState *state = Context::get()->matrix_state;
state->model_view_stack.top = 0;
@@ -132,28 +132,28 @@ static void checkmat(cosnt float *m)
#endif
-void GPU_matrix_push(void)
+void GPU_matrix_push()
{
BLI_assert(ModelViewStack.top + 1 < MATRIX_STACK_DEPTH);
ModelViewStack.top++;
copy_m4_m4(ModelView, ModelViewStack.stack[ModelViewStack.top - 1]);
}
-void GPU_matrix_pop(void)
+void GPU_matrix_pop()
{
BLI_assert(ModelViewStack.top > 0);
ModelViewStack.top--;
gpu_matrix_state_active_set_dirty(true);
}
-void GPU_matrix_push_projection(void)
+void GPU_matrix_push_projection()
{
BLI_assert(ProjectionStack.top + 1 < MATRIX_STACK_DEPTH);
ProjectionStack.top++;
copy_m4_m4(Projection, ProjectionStack.stack[ProjectionStack.top - 1]);
}
-void GPU_matrix_pop_projection(void)
+void GPU_matrix_pop_projection()
{
BLI_assert(ProjectionStack.top > 0);
ProjectionStack.top--;
@@ -167,7 +167,7 @@ void GPU_matrix_set(const float m[4][4])
gpu_matrix_state_active_set_dirty(true);
}
-void GPU_matrix_identity_projection_set(void)
+void GPU_matrix_identity_projection_set()
{
unit_m4(Projection);
CHECKMAT(Projection3D);
@@ -181,7 +181,7 @@ void GPU_matrix_projection_set(const float m[4][4])
gpu_matrix_state_active_set_dirty(true);
}
-void GPU_matrix_identity_set(void)
+void GPU_matrix_identity_set()
{
unit_m4(ModelView);
gpu_matrix_state_active_set_dirty(true);
@@ -668,7 +668,7 @@ void GPU_matrix_bind(GPUShader *shader)
gpu_matrix_state_active_set_dirty(false);
}
-bool GPU_matrix_dirty_get(void)
+bool GPU_matrix_dirty_get()
{
GPUMatrixState *state = Context::get()->matrix_state;
return state->dirty;
@@ -677,17 +677,18 @@ bool GPU_matrix_dirty_get(void)
/* -------------------------------------------------------------------- */
/** \name Python API Helpers
* \{ */
+
BLI_STATIC_ASSERT(GPU_PY_MATRIX_STACK_LEN + 1 == MATRIX_STACK_DEPTH, "define mismatch");
/* Return int since caller is may subtract. */
-int GPU_matrix_stack_level_get_model_view(void)
+int GPU_matrix_stack_level_get_model_view()
{
GPUMatrixState *state = Context::get()->matrix_state;
return (int)state->model_view_stack.top;
}
-int GPU_matrix_stack_level_get_projection(void)
+int GPU_matrix_stack_level_get_projection()
{
GPUMatrixState *state = Context::get()->matrix_state;
return (int)state->projection_stack.top;
@@ -733,9 +734,6 @@ float GPU_polygon_offset_calc(const float (*winmat)[4], float viewdist, float di
return winmat[3][2] * -0.0025f * dist;
}
-/**
- * \note \a viewdist is only for ortho at the moment.
- */
void GPU_polygon_offset(float viewdist, float dist)
{
static float winmat[4][4], offset = 0.0f;
diff --git a/source/blender/gpu/intern/gpu_node_graph.c b/source/blender/gpu/intern/gpu_node_graph.c
index 585cb296bac..50ff450ac79 100644
--- a/source/blender/gpu/intern/gpu_node_graph.c
+++ b/source/blender/gpu/intern/gpu_node_graph.c
@@ -791,7 +791,6 @@ static void gpu_node_free(GPUNode *node)
MEM_freeN(node);
}
-/* Free intermediate node graph. */
void gpu_node_graph_free_nodes(GPUNodeGraph *graph)
{
GPUNode *node;
@@ -803,7 +802,6 @@ void gpu_node_graph_free_nodes(GPUNodeGraph *graph)
graph->outlink = NULL;
}
-/* Free both node graph and requested attributes and textures. */
void gpu_node_graph_free(GPUNodeGraph *graph)
{
BLI_freelistN(&graph->outlink_aovs);
diff --git a/source/blender/gpu/intern/gpu_node_graph.h b/source/blender/gpu/intern/gpu_node_graph.h
index 929191cff73..8a112ac9c4d 100644
--- a/source/blender/gpu/intern/gpu_node_graph.h
+++ b/source/blender/gpu/intern/gpu_node_graph.h
@@ -167,12 +167,21 @@ typedef struct GPUNodeGraph {
void gpu_node_graph_prune_unused(GPUNodeGraph *graph);
void gpu_node_graph_finalize_uniform_attrs(GPUNodeGraph *graph);
+/**
+ * Free intermediate node graph.
+ */
void gpu_node_graph_free_nodes(GPUNodeGraph *graph);
+/**
+ * Free both node graph and requested attributes and textures.
+ */
void gpu_node_graph_free(GPUNodeGraph *graph);
/* Material calls */
struct GPUNodeGraph *gpu_material_node_graph(struct GPUMaterial *material);
+/**
+ * Returns the address of the future pointer to coba_tex.
+ */
struct GPUTexture **gpu_material_ramp_texture_row_set(struct GPUMaterial *mat,
int size,
float *pixels,
diff --git a/source/blender/gpu/intern/gpu_platform.cc b/source/blender/gpu/intern/gpu_platform.cc
index 49dde473300..34834a62268 100644
--- a/source/blender/gpu/intern/gpu_platform.cc
+++ b/source/blender/gpu/intern/gpu_platform.cc
@@ -127,37 +127,36 @@ eGPUSupportLevel GPU_platform_support_level()
return GPG.support_level;
}
-const char *GPU_platform_vendor(void)
+const char *GPU_platform_vendor()
{
BLI_assert(GPG.initialized);
return GPG.vendor;
}
-const char *GPU_platform_renderer(void)
+const char *GPU_platform_renderer()
{
BLI_assert(GPG.initialized);
return GPG.renderer;
}
-const char *GPU_platform_version(void)
+const char *GPU_platform_version()
{
BLI_assert(GPG.initialized);
return GPG.version;
}
-const char *GPU_platform_support_level_key(void)
+const char *GPU_platform_support_level_key()
{
BLI_assert(GPG.initialized);
return GPG.support_key;
}
-const char *GPU_platform_gpu_name(void)
+const char *GPU_platform_gpu_name()
{
BLI_assert(GPG.initialized);
return GPG.gpu_name;
}
-/* GPU Types */
bool GPU_type_matches(eGPUDeviceType device, eGPUOSType os, eGPUDriverType driver)
{
BLI_assert(GPG.initialized);
diff --git a/source/blender/gpu/intern/gpu_select.c b/source/blender/gpu/intern/gpu_select.c
index 3c89f082e9b..aadb52fb49c 100644
--- a/source/blender/gpu/intern/gpu_select.c
+++ b/source/blender/gpu/intern/gpu_select.c
@@ -71,9 +71,6 @@ static GPUSelectState g_select_state = {0};
/** \name Public API
* \{ */
-/**
- * initialize and provide buffer for results
- */
void GPU_select_begin(uint *buffer, uint bufsize, const rcti *input, char mode, int oldhits)
{
if (mode == GPU_SELECT_NEAREST_SECOND_PASS) {
@@ -107,14 +104,6 @@ void GPU_select_begin(uint *buffer, uint bufsize, const rcti *input, char mode,
}
}
-/**
- * loads a new selection id and ends previous query, if any.
- * In second pass of selection it also returns
- * if id has been hit on the first pass already.
- * Thus we can skip drawing un-hit objects.
- *
- * \warning We rely on the order of object rendering on passes to be the same for this to work.
- */
bool GPU_select_load_id(uint id)
{
/* if no selection mode active, ignore */
@@ -133,11 +122,6 @@ bool GPU_select_load_id(uint id)
}
}
-/**
- * Cleanup and flush selection results to buffer.
- * Return number of hits and hits in buffer.
- * if \a dopass is true, we will do a second pass with occlusion queries to get the closest hit.
- */
uint GPU_select_end(void)
{
uint hits = 0;
@@ -205,12 +189,6 @@ bool GPU_select_is_cached(void)
/** \name Utilities
* \{ */
-/**
- * Helper function, nothing special but avoids doing inline since hits aren't sorted by depth
- * and purpose of 4x buffer indices isn't so clear.
- *
- * Note that comparing depth as uint is fine.
- */
const uint *GPU_select_buffer_near(const uint *buffer, int hits)
{
const uint *buffer_near = NULL;
@@ -244,7 +222,6 @@ uint GPU_select_buffer_remove_by_id(uint *buffer, int hits, uint select_id)
return hits_final;
}
-/* Part of the solution copied from `rect_subregion_stride_calc`. */
void GPU_select_buffer_stride_realign(const rcti *src, const rcti *dst, uint *r_buf)
{
const int x = dst->xmin - src->xmin;
diff --git a/source/blender/gpu/intern/gpu_select_pick.c b/source/blender/gpu/intern/gpu_select_pick.c
index a8907859bf4..737e4c6e874 100644
--- a/source/blender/gpu/intern/gpu_select_pick.c
+++ b/source/blender/gpu/intern/gpu_select_pick.c
@@ -730,7 +730,6 @@ void gpu_select_pick_cache_end(void)
BLI_freelistN(&g_pick_state.cache.bufs);
}
-/* is drawing needed? */
bool gpu_select_pick_is_cached(void)
{
return g_pick_state.is_cached;
diff --git a/source/blender/gpu/intern/gpu_select_private.h b/source/blender/gpu/intern/gpu_select_private.h
index e49feb3fc50..e5a84a037a6 100644
--- a/source/blender/gpu/intern/gpu_select_private.h
+++ b/source/blender/gpu/intern/gpu_select_private.h
@@ -30,16 +30,21 @@ extern "C" {
#endif
/* gpu_select_pick */
+
void gpu_select_pick_begin(uint (*buffer)[4], uint bufsize, const rcti *input, char mode);
bool gpu_select_pick_load_id(uint id, bool end);
uint gpu_select_pick_end(void);
void gpu_select_pick_cache_begin(void);
void gpu_select_pick_cache_end(void);
+/**
+ * \return true if drawing is not needed.
+ */
bool gpu_select_pick_is_cached(void);
void gpu_select_pick_cache_load_id(void);
/* gpu_select_sample_query */
+
void gpu_select_query_begin(
uint (*buffer)[4], uint bufsize, const rcti *input, char mode, int oldhits);
bool gpu_select_query_load_id(uint id);
diff --git a/source/blender/gpu/intern/gpu_select_sample_query.cc b/source/blender/gpu/intern/gpu_select_sample_query.cc
index 047ce0cfb35..a430d4a9d62 100644
--- a/source/blender/gpu/intern/gpu_select_sample_query.cc
+++ b/source/blender/gpu/intern/gpu_select_sample_query.cc
@@ -151,7 +151,7 @@ bool gpu_select_query_load_id(uint id)
return true;
}
-uint gpu_select_query_end(void)
+uint gpu_select_query_end()
{
uint hits = 0;
const uint maxhits = g_query_state.bufsize;
diff --git a/source/blender/gpu/intern/gpu_shader.cc b/source/blender/gpu/intern/gpu_shader.cc
index 9340d311472..1b6cb196534 100644
--- a/source/blender/gpu/intern/gpu_shader.cc
+++ b/source/blender/gpu/intern/gpu_shader.cc
@@ -284,26 +284,6 @@ static const char *string_join_array_maybe_alloc(const char **str_arr, bool *r_i
return str_arr[0];
}
-/**
- * Use via #GPU_shader_create_from_arrays macro (avoids passing in param).
- *
- * Similar to #DRW_shader_create_with_lib with the ability to include libs for each type of shader.
- *
- * It has the advantage that each item can be conditionally included
- * without having to build the string inline, then free it.
- *
- * \param params: NULL terminated arrays of strings.
- *
- * Example:
- * \code{.c}
- * sh = GPU_shader_create_from_arrays({
- * .vert = (const char *[]){shader_lib_glsl, shader_vert_glsl, NULL},
- * .geom = (const char *[]){shader_geom_glsl, NULL},
- * .frag = (const char *[]){shader_frag_glsl, NULL},
- * .defs = (const char *[]){"#define DEFINE\n", test ? "#define OTHER_DEFINE\n" : "", NULL},
- * });
- * \endcode
- */
struct GPUShader *GPU_shader_create_from_arrays_impl(
const struct GPU_ShaderCreateFromArray_Params *params, const char *func, int line)
{
@@ -431,7 +411,6 @@ int GPU_shader_get_ssbo(GPUShader *shader, const char *name)
return ssbo ? ssbo->location : -1;
}
-/* DEPRECATED. */
int GPU_shader_get_uniform_block(GPUShader *shader, const char *name)
{
ShaderInterface *interface = unwrap(shader)->interface;
@@ -466,7 +445,6 @@ int GPU_shader_get_attribute(GPUShader *shader, const char *name)
/** \name Getters
* \{ */
-/* DEPRECATED: Kept only because of BGL API */
int GPU_shader_get_program(GPUShader *shader)
{
return unwrap(shader)->program_handle_get();
diff --git a/source/blender/gpu/intern/gpu_shader_interface.cc b/source/blender/gpu/intern/gpu_shader_interface.cc
index ae94112b17b..937f49ccaec 100644
--- a/source/blender/gpu/intern/gpu_shader_interface.cc
+++ b/source/blender/gpu/intern/gpu_shader_interface.cc
@@ -65,14 +65,17 @@ static void sort_input_list(MutableSpan<ShaderInput> dst)
}
}
-/* Sorts all inputs inside their respective array.
- * This is to allow fast hash collision detection.
- * See ShaderInterface::input_lookup for more details. */
void ShaderInterface::sort_inputs()
{
+ /* Sorts all inputs inside their respective array.
+ * This is to allow fast hash collision detection.
+ * See `ShaderInterface::input_lookup` for more details. */
+
sort_input_list(MutableSpan<ShaderInput>(inputs_, attr_len_));
sort_input_list(MutableSpan<ShaderInput>(inputs_ + attr_len_, ubo_len_));
sort_input_list(MutableSpan<ShaderInput>(inputs_ + attr_len_ + ubo_len_, uniform_len_));
+ sort_input_list(
+ MutableSpan<ShaderInput>(inputs_ + attr_len_ + ubo_len_ + uniform_len_, ssbo_len_));
}
void ShaderInterface::debug_print()
diff --git a/source/blender/gpu/intern/gpu_shader_interface.hh b/source/blender/gpu/intern/gpu_shader_interface.hh
index ebed7b15170..12a7ffabcc6 100644
--- a/source/blender/gpu/intern/gpu_shader_interface.hh
+++ b/source/blender/gpu/intern/gpu_shader_interface.hh
@@ -130,7 +130,9 @@ class ShaderInterface {
inline uint32_t set_input_name(ShaderInput *input, char *name, uint32_t name_len) const;
- /* Finalize interface construction by sorting the ShaderInputs for faster lookups. */
+ /**
+ * Finalize interface construction by sorting the #ShaderInputs for faster lookups.
+ */
void sort_inputs(void);
private:
diff --git a/source/blender/gpu/intern/gpu_state.cc b/source/blender/gpu/intern/gpu_state.cc
index 9ee8a8b8d32..a43ddb09ff8 100644
--- a/source/blender/gpu/intern/gpu_state.cc
+++ b/source/blender/gpu/intern/gpu_state.cc
@@ -165,11 +165,6 @@ void GPU_depth_range(float near, float far)
copy_v2_fl2(state.depth_range, near, far);
}
-/**
- * \note By convention, this is set as needed and not reset back to 1.0.
- * This means code that draws lines must always set the line width beforehand,
- * but is not expected to restore it's previous value.
- */
void GPU_line_width(float width)
{
width = max_ff(1.0f, width * PIXELSIZE);
@@ -184,10 +179,6 @@ void GPU_point_size(float size)
state.point_size = size * ((state.point_size > 0.0) ? 1.0f : -1.0f);
}
-/* Programmable point size
- * - shaders set their own point size when enabled
- * - use GPU_point_size when disabled */
-/* TODO: remove and use program point size everywhere. */
void GPU_program_point_size(bool enable)
{
StateManager *stack = Context::get()->state_manager;
@@ -264,7 +255,6 @@ eGPUStencilTest GPU_stencil_test_get()
return (eGPUStencilTest)state.stencil_test;
}
-/* NOTE: Already premultiplied by U.pixelsize. */
float GPU_line_width_get()
{
const GPUStateMutable &state = Context::get()->state_manager->mutable_state;
@@ -363,7 +353,6 @@ void GPU_bgl_start()
}
}
-/* Just turn off the bgl safeguard system. Can be called even without GPU_bgl_start. */
void GPU_bgl_end()
{
Context *ctx = Context::get();
diff --git a/source/blender/gpu/intern/gpu_texture.cc b/source/blender/gpu/intern/gpu_texture.cc
index 2744c0c5e17..c7e2043b790 100644
--- a/source/blender/gpu/intern/gpu_texture.cc
+++ b/source/blender/gpu/intern/gpu_texture.cc
@@ -298,7 +298,6 @@ GPUTexture *GPU_texture_create_cube_array(
name, w, w, d, GPU_TEXTURE_CUBE_ARRAY, mip_len, format, GPU_DATA_FLOAT, data);
}
-/* DDS texture loading. Return NULL if support is not available. */
GPUTexture *GPU_texture_create_compressed_2d(
const char *name, int w, int h, int miplen, eGPUTextureFormat tex_format, const void *data)
{
@@ -337,7 +336,6 @@ GPUTexture *GPU_texture_create_from_vertbuf(const char *name, GPUVertBuf *vert)
return reinterpret_cast<GPUTexture *>(tex);
}
-/* Create an error texture that will bind an invalid texture (pink) at draw time. */
GPUTexture *GPU_texture_create_error(int dimension, bool is_array)
{
float pixel[4] = {1.0f, 0.0f, 1.0f, 1.0f};
@@ -386,27 +384,17 @@ void *GPU_texture_read(GPUTexture *tex_, eGPUDataFormat data_format, int miplvl)
return tex->read(miplvl, data_format);
}
-/**
- * Fills the whole texture with the same data for all pixels.
- * \warning Only work for 2D texture for now.
- * \warning Only clears the mip 0 of the texture.
- * \param data_format: data format of the pixel data.
- * \param data: 1 pixel worth of data to fill the texture with.
- */
void GPU_texture_clear(GPUTexture *tex, eGPUDataFormat data_format, const void *data)
{
BLI_assert(data != nullptr); /* Do not accept NULL as parameter. */
reinterpret_cast<Texture *>(tex)->clear(data_format, data);
}
-/* NOTE: Updates only mip 0. */
void GPU_texture_update(GPUTexture *tex, eGPUDataFormat data_format, const void *data)
{
reinterpret_cast<Texture *>(tex)->update(data_format, data);
}
-/* Makes data interpretation aware of the source layout.
- * Skipping pixels correctly when changing rows when doing partial update. */
void GPU_unpack_row_length_set(uint len)
{
Context::get()->state_manager->texture_unpack_row_length_set(len);
@@ -461,7 +449,6 @@ void GPU_texture_generate_mipmap(GPUTexture *tex)
reinterpret_cast<Texture *>(tex)->generate_mipmap();
}
-/* Copy a texture content to a similar texture. Only MIP 0 is copied. */
void GPU_texture_copy(GPUTexture *dst_, GPUTexture *src_)
{
Texture *src = reinterpret_cast<Texture *>(src_);
@@ -626,7 +613,6 @@ void GPU_texture_get_mipmap_size(GPUTexture *tex, int lvl, int *r_size)
* Override texture sampler state for one sampler unit only.
* \{ */
-/* Update user defined sampler states. */
void GPU_samplers_update(void)
{
GPUBackend::get()->samplers_update();
diff --git a/source/blender/gpu/intern/gpu_uniform_buffer.cc b/source/blender/gpu/intern/gpu_uniform_buffer.cc
index 3a9269d1753..332875ba81f 100644
--- a/source/blender/gpu/intern/gpu_uniform_buffer.cc
+++ b/source/blender/gpu/intern/gpu_uniform_buffer.cc
@@ -201,12 +201,6 @@ GPUUniformBuf *GPU_uniformbuf_create_ex(size_t size, const void *data, const cha
return wrap(ubo);
}
-/**
- * Create UBO from inputs list.
- * Return NULL if failed to create or if \param inputs: is empty.
- *
- * \param inputs: ListBase of #BLI_genericNodeN(#GPUInput).
- */
GPUUniformBuf *GPU_uniformbuf_create_from_list(ListBase *inputs, const char *name)
{
/* There is no point on creating an UBO if there is no arguments. */
@@ -245,7 +239,7 @@ void GPU_uniformbuf_unbind(GPUUniformBuf *ubo)
unwrap(ubo)->unbind();
}
-void GPU_uniformbuf_unbind_all(void)
+void GPU_uniformbuf_unbind_all()
{
/* FIXME */
}
diff --git a/source/blender/gpu/intern/gpu_vertex_buffer.cc b/source/blender/gpu/intern/gpu_vertex_buffer.cc
index 7ff68242c17..5ed9648387f 100644
--- a/source/blender/gpu/intern/gpu_vertex_buffer.cc
+++ b/source/blender/gpu/intern/gpu_vertex_buffer.cc
@@ -159,7 +159,6 @@ void *GPU_vertbuf_unmap(const GPUVertBuf *verts, const void *mapped_data)
return unwrap(verts)->unmap(mapped_data);
}
-/** Same as discard but does not free. */
void GPU_vertbuf_clear(GPUVertBuf *verts)
{
unwrap(verts)->clear();
@@ -183,21 +182,16 @@ void GPU_vertbuf_handle_ref_remove(GPUVertBuf *verts)
/* -------- Data update -------- */
-/* create a new allocation, discarding any existing data */
void GPU_vertbuf_data_alloc(GPUVertBuf *verts, uint v_len)
{
unwrap(verts)->allocate(v_len);
}
-/* resize buffer keeping existing data */
void GPU_vertbuf_data_resize(GPUVertBuf *verts, uint v_len)
{
unwrap(verts)->resize(v_len);
}
-/* Set vertex count but does not change allocation.
- * Only this many verts will be uploaded to the GPU and rendered.
- * This is useful for streaming data. */
void GPU_vertbuf_data_len_set(GPUVertBuf *verts_, uint v_len)
{
VertBuf *verts = unwrap(verts_);
@@ -229,7 +223,6 @@ void GPU_vertbuf_attr_fill(GPUVertBuf *verts_, uint a_idx, const void *data)
GPU_vertbuf_attr_fill_stride(verts_, a_idx, stride, data);
}
-/** Fills a whole vertex (all attributes). Data must match packed layout. */
void GPU_vertbuf_vert_set(GPUVertBuf *verts_, uint v_idx, const void *data)
{
VertBuf *verts = unwrap(verts_);
@@ -284,15 +277,12 @@ void GPU_vertbuf_attr_get_raw_data(GPUVertBuf *verts_, uint a_idx, GPUVertBufRaw
/* -------- Getters -------- */
-/* NOTE: Be careful when using this. The data needs to match the expected format. */
void *GPU_vertbuf_get_data(const GPUVertBuf *verts)
{
/* TODO: Assert that the format has no padding. */
return unwrap(verts)->data;
}
-/* Returns the data buffer and set it to null internally to avoid freeing.
- * NOTE: Be careful when using this. The data needs to match the expected format. */
void *GPU_vertbuf_steal_data(GPUVertBuf *verts_)
{
VertBuf *verts = unwrap(verts_);
@@ -328,7 +318,6 @@ uint GPU_vertbuf_get_memory_usage()
return VertBuf::memory_usage;
}
-/* Should be rename to GPU_vertbuf_data_upload */
void GPU_vertbuf_use(GPUVertBuf *verts)
{
unwrap(verts)->upload();
@@ -339,8 +328,6 @@ void GPU_vertbuf_bind_as_ssbo(struct GPUVertBuf *verts, int binding)
unwrap(verts)->bind_as_ssbo(binding);
}
-/* XXX this is just a wrapper for the use of the Hair refine workaround.
- * To be used with GPU_vertbuf_use(). */
void GPU_vertbuf_update_sub(GPUVertBuf *verts, uint start, uint len, void *data)
{
unwrap(verts)->update_sub(start, len, data);
diff --git a/source/blender/gpu/intern/gpu_vertex_format.cc b/source/blender/gpu/intern/gpu_vertex_format.cc
index 78a119bcec8..ad45f2a4d7b 100644
--- a/source/blender/gpu/intern/gpu_vertex_format.cc
+++ b/source/blender/gpu/intern/gpu_vertex_format.cc
@@ -190,17 +190,6 @@ void GPU_vertformat_alias_add(GPUVertFormat *format, const char *alias)
attr->names[attr->name_len++] = copy_attr_name(format, alias);
}
-/**
- * Makes vertex attribute from the next vertices to be accessible in the vertex shader.
- * For an attribute named "attr" you can access the next nth vertex using "attr{number}".
- * Use this function after specifying all the attributes in the format.
- *
- * NOTE: This does NOT work when using indexed rendering.
- * NOTE: Only works for first attribute name. (this limitation can be changed if needed)
- *
- * WARNING: this function creates a lot of aliases/attributes, make sure to keep the attribute
- * name short to avoid overflowing the name-buffer.
- */
void GPU_vertformat_multiload_enable(GPUVertFormat *format, int load_count)
{
/* Sanity check. Maximum can be upgraded if needed. */
@@ -271,8 +260,6 @@ static void safe_bytes(char out[11], const char data[8])
}
}
-/* Warning: Always add a prefix to the result of this function as
- * the generated string can start with a number and not be a valid attribute name. */
void GPU_vertformat_safe_attr_name(const char *attr_name, char *r_safe_name, uint UNUSED(max_len))
{
char data[8] = {0};
@@ -306,20 +293,6 @@ void GPU_vertformat_safe_attr_name(const char *attr_name, char *r_safe_name, uin
#endif
}
-/**
- * Make attribute layout non-interleaved.
- * Warning! This does not change data layout!
- * Use direct buffer access to fill the data.
- * This is for advanced usage.
- *
- * De-interleaved data means all attribute data for each attribute
- * is stored continuously like this:
- * 000011112222
- * instead of:
- * 012012012012
- *
- * \note This is per attribute de-interleaving, NOT per component.
- */
void GPU_vertformat_deinterleave(GPUVertFormat *format)
{
/* Ideally we should change the stride and offset here. This would allow
diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c
index ccd9a4c061b..c604859fa94 100644
--- a/source/blender/gpu/intern/gpu_viewport.c
+++ b/source/blender/gpu/intern/gpu_viewport.c
@@ -194,7 +194,6 @@ void GPU_viewport_bind(GPUViewport *viewport, int view, const rcti *rect)
viewport->active_view = view;
}
-/* Should be called from DRW after DRW_opengl_context_enable. */
void GPU_viewport_bind_from_offscreen(GPUViewport *viewport, struct GPUOffScreen *ofs)
{
GPUTexture *color, *depth;
@@ -258,7 +257,6 @@ void GPU_viewport_colorspace_set(GPUViewport *viewport,
viewport->do_color_management = true;
}
-/* Merge the stereo textures. `color` and `overlay` texture will be modified. */
void GPU_viewport_stereo_composite(GPUViewport *viewport, Stereo3dFormat *stereo_format)
{
if (!ELEM(stereo_format->display_mode, S3D_DISPLAY_ANAGLYPH, S3D_DISPLAY_INTERLACE)) {
@@ -452,10 +450,6 @@ static void gpu_viewport_draw_colormanaged(GPUViewport *viewport,
}
}
-/**
- * Version of #GPU_viewport_draw_to_screen() that lets caller decide if display colorspace
- * transform should be performed.
- */
void GPU_viewport_draw_to_screen_ex(GPUViewport *viewport,
int view,
const rcti *rect,
@@ -508,21 +502,11 @@ void GPU_viewport_draw_to_screen_ex(GPUViewport *viewport,
viewport, view, &pos_rect, &uv_rect, display_colorspace, do_overlay_merge);
}
-/**
- * Merge and draw the buffers of \a viewport into the currently active framebuffer, performing
- * color transform to display space.
- *
- * \param rect: Coordinates to draw into. By swapping min and max values, drawing can be done
- * with inversed axis coordinates (upside down or sideways).
- */
void GPU_viewport_draw_to_screen(GPUViewport *viewport, int view, const rcti *rect)
{
GPU_viewport_draw_to_screen_ex(viewport, view, rect, true, true);
}
-/**
- * Clear vars assigned from offscreen, so we don't free data owned by `GPUOffScreen`.
- */
void GPU_viewport_unbind_from_offscreen(GPUViewport *viewport,
struct GPUOffScreen *ofs,
bool display_colorspace,
@@ -587,18 +571,17 @@ GPUTexture *GPU_viewport_depth_texture(GPUViewport *viewport)
return viewport->depth_tx;
}
-/* Overlay framebuffer for drawing outside of DRW module. */
GPUFrameBuffer *GPU_viewport_framebuffer_overlay_get(GPUViewport *viewport)
{
- GPU_framebuffer_ensure_config(&viewport->overlay_fb,
- {
- GPU_ATTACHMENT_TEXTURE(viewport->depth_tx),
- GPU_ATTACHMENT_TEXTURE(viewport->color_overlay_tx[0]),
- });
+ GPU_framebuffer_ensure_config(
+ &viewport->overlay_fb,
+ {
+ GPU_ATTACHMENT_TEXTURE(viewport->depth_tx),
+ GPU_ATTACHMENT_TEXTURE(viewport->color_overlay_tx[viewport->active_view]),
+ });
return viewport->overlay_fb;
}
-/* Must be executed inside Draw-manager OpenGL Context. */
void GPU_viewport_free(GPUViewport *viewport)
{
if (viewport->draw_data) {
diff --git a/source/blender/gpu/opengl/gl_backend.cc b/source/blender/gpu/opengl/gl_backend.cc
index 2855d5078ff..7bb88894b81 100644
--- a/source/blender/gpu/opengl/gl_backend.cc
+++ b/source/blender/gpu/opengl/gl_backend.cc
@@ -412,14 +412,23 @@ static void detect_workarounds()
if (GLContext::debug_layer_support == false) {
GLContext::debug_layer_workaround = true;
}
+
+ /* Broken glGenerateMipmap on macOS 10.15.7 security update. */
+ if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_MAC, GPU_DRIVER_ANY) &&
+ strstr(renderer, "HD Graphics 4000")) {
+ GLContext::generate_mipmap_workaround = true;
+ }
} // namespace blender::gpu
/** Internal capabilities. */
+
GLint GLContext::max_cubemap_size = 0;
GLint GLContext::max_texture_3d_size = 0;
GLint GLContext::max_ubo_binds = 0;
GLint GLContext::max_ubo_size = 0;
+
/** Extensions. */
+
bool GLContext::base_instance_support = false;
bool GLContext::clear_texture_support = false;
bool GLContext::copy_image_support = false;
@@ -433,9 +442,12 @@ bool GLContext::texture_cube_map_array_support = false;
bool GLContext::texture_filter_anisotropic_support = false;
bool GLContext::texture_gather_support = false;
bool GLContext::vertex_attrib_binding_support = false;
+
/** Workarounds. */
+
bool GLContext::debug_layer_workaround = false;
bool GLContext::unused_fb_slot_workaround = false;
+bool GLContext::generate_mipmap_workaround = false;
float GLContext::derivative_signs[2] = {1.0f, 1.0f};
void GLBackend::capabilities_init()
diff --git a/source/blender/gpu/opengl/gl_batch.cc b/source/blender/gpu/opengl/gl_batch.cc
index fc1d1006d0d..83cb0ddd053 100644
--- a/source/blender/gpu/opengl/gl_batch.cc
+++ b/source/blender/gpu/opengl/gl_batch.cc
@@ -74,7 +74,6 @@ void GLVaoCache::init()
vao_id_ = 0;
}
-/* Create a new VAO object and store it in the cache. */
void GLVaoCache::insert(const GLShaderInterface *interface, GLuint vao)
{
/* Now insert the cache. */
@@ -191,7 +190,6 @@ void GLVaoCache::clear()
this->init();
}
-/* Return 0 on cache miss (invalid VAO) */
GLuint GLVaoCache::lookup(const GLShaderInterface *interface)
{
const int count = (is_dynamic_vao_count) ? dynamic_vaos.count : GPU_VAO_STATIC_LEN;
@@ -205,8 +203,6 @@ GLuint GLVaoCache::lookup(const GLShaderInterface *interface)
return 0;
}
-/* The GLVaoCache object is only valid for one GLContext.
- * Reset the cache if trying to draw in another context; */
void GLVaoCache::context_check()
{
GLContext *ctx = GLContext::get();
@@ -276,6 +272,7 @@ GLuint GLVaoCache::vao_get(GPUBatch *batch)
return vao_id_;
}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/gpu/opengl/gl_batch.hh b/source/blender/gpu/opengl/gl_batch.hh
index 704b6471dd5..a2b5f8fc15e 100644
--- a/source/blender/gpu/opengl/gl_batch.hh
+++ b/source/blender/gpu/opengl/gl_batch.hh
@@ -43,9 +43,11 @@ class GLShaderInterface;
#define GPU_VAO_STATIC_LEN 3
-/* VAO management: remembers all geometry state (vertex attribute bindings & element buffer)
- * for each shader interface. Start with a static number of vaos and fallback to dynamic count
- * if necessary. Once a batch goes dynamic it does not go back. */
+/**
+ * VAO management: remembers all geometry state (vertex attribute bindings & element buffer)
+ * for each shader interface. Start with a static number of VAO's and fallback to dynamic count
+ * if necessary. Once a batch goes dynamic it does not go back.
+ */
class GLVaoCache {
private:
/** Context for which the vao_cache_ was generated. */
@@ -80,13 +82,23 @@ class GLVaoCache {
GLuint vao_get(GPUBatch *batch);
GLuint base_instance_vao_get(GPUBatch *batch, int i_first);
+ /**
+ * Return 0 on cache miss (invalid VAO).
+ */
GLuint lookup(const GLShaderInterface *interface);
+ /**
+ * Create a new VAO object and store it in the cache.
+ */
void insert(const GLShaderInterface *interface, GLuint vao_id);
void remove(const GLShaderInterface *interface);
void clear(void);
private:
void init(void);
+ /**
+ * The #GLVaoCache object is only valid for one #GLContext.
+ * Reset the cache if trying to draw in another context;.
+ */
void context_check(void);
};
@@ -100,6 +112,7 @@ class GLBatch : public Batch {
void bind(int i_first);
/* Convenience getters. */
+
GLIndexBuf *elem_(void) const
{
return static_cast<GLIndexBuf *>(unwrap(elem));
diff --git a/source/blender/gpu/opengl/gl_context.hh b/source/blender/gpu/opengl/gl_context.hh
index 0222adaba25..40107ca9ef7 100644
--- a/source/blender/gpu/opengl/gl_context.hh
+++ b/source/blender/gpu/opengl/gl_context.hh
@@ -56,11 +56,14 @@ class GLSharedOrphanLists {
class GLContext : public Context {
public:
/** Capabilities. */
+
static GLint max_cubemap_size;
static GLint max_texture_3d_size;
static GLint max_ubo_size;
static GLint max_ubo_binds;
+
/** Extensions. */
+
static bool base_instance_support;
static bool clear_texture_support;
static bool copy_image_support;
@@ -74,9 +77,12 @@ class GLContext : public Context {
static bool texture_filter_anisotropic_support;
static bool texture_gather_support;
static bool vertex_attrib_binding_support;
+
/** Workarounds. */
+
static bool debug_layer_workaround;
static bool unused_fb_slot_workaround;
+ static bool generate_mipmap_workaround;
static float derivative_signs[2];
/** VBO for missing vertex attrib binding. Avoid undefined behavior on some implementation. */
diff --git a/source/blender/gpu/opengl/gl_debug.cc b/source/blender/gpu/opengl/gl_debug.cc
index 3e259235515..0a06d9cdb7c 100644
--- a/source/blender/gpu/opengl/gl_debug.cc
+++ b/source/blender/gpu/opengl/gl_debug.cc
@@ -142,7 +142,6 @@ static void APIENTRY debug_callback(GLenum UNUSED(source),
#undef APIENTRY
-/* This function needs to be called once per context. */
void init_gl_callbacks()
{
CLOG_ENSURE(&LOG);
diff --git a/source/blender/gpu/opengl/gl_debug.hh b/source/blender/gpu/opengl/gl_debug.hh
index 892fb1d2ddb..3964e5da550 100644
--- a/source/blender/gpu/opengl/gl_debug.hh
+++ b/source/blender/gpu/opengl/gl_debug.hh
@@ -88,8 +88,16 @@ namespace debug {
void raise_gl_error(const char *info);
void check_gl_error(const char *info);
void check_gl_resources(const char *info);
+/**
+ * This function needs to be called once per context.
+ */
void init_gl_callbacks(void);
+/**
+ * Initialize a fallback layer (to KHR_debug) that covers only some functions.
+ * We override the functions pointers by our own implementation that just checks #glGetError.
+ * Some additional functions (not overridable) are covered inside the header using wrappers.
+ */
void init_debug_layer(void);
void object_label(GLenum type, GLuint object, const char *name);
diff --git a/source/blender/gpu/opengl/gl_debug_layer.cc b/source/blender/gpu/opengl/gl_debug_layer.cc
index a5225f98fd9..e624cb9ee46 100644
--- a/source/blender/gpu/opengl/gl_debug_layer.cc
+++ b/source/blender/gpu/opengl/gl_debug_layer.cc
@@ -105,11 +105,6 @@ DEBUG_FUNC_DECLARE(PFNGLUSEPROGRAMPROC, void, glUseProgram, GLuint, program);
#undef DEBUG_FUNC_DECLARE
-/**
- * Initialize a fallback layer (to KHR_debug) that covers only some functions.
- * We override the functions pointers by our own implementation that just checks #glGetError.
- * Some additional functions (not overridable) are covered inside the header using wrappers.
- */
void init_debug_layer()
{
#define DEBUG_WRAP(function) \
diff --git a/source/blender/gpu/opengl/gl_drawlist.cc b/source/blender/gpu/opengl/gl_drawlist.cc
index 50ab5574cd2..8b000784fc8 100644
--- a/source/blender/gpu/opengl/gl_drawlist.cc
+++ b/source/blender/gpu/opengl/gl_drawlist.cc
@@ -236,5 +236,3 @@ void GLDrawList::submit()
/* Avoid keeping reference to the batch. */
batch_ = nullptr;
}
-
-/** \} */
diff --git a/source/blender/gpu/opengl/gl_framebuffer.cc b/source/blender/gpu/opengl/gl_framebuffer.cc
index 8da114d9270..13f03195437 100644
--- a/source/blender/gpu/opengl/gl_framebuffer.cc
+++ b/source/blender/gpu/opengl/gl_framebuffer.cc
@@ -110,7 +110,6 @@ void GLFrameBuffer::init()
/** \name Config
* \{ */
-/* This is a rather slow operation. Don't check in normal cases. */
bool GLFrameBuffer::check(char err_out[256])
{
this->bind(true);
@@ -451,9 +450,6 @@ void GLFrameBuffer::read(eGPUFrameBufferBits plane,
glReadPixels(UNPACK4(area), format, type, r_data);
}
-/**
- * Copy \a src at the give offset inside \a dst.
- */
void GLFrameBuffer::blit_to(
eGPUFrameBufferBits planes, int src_slot, FrameBuffer *dst_, int dst_slot, int x, int y)
{
diff --git a/source/blender/gpu/opengl/gl_framebuffer.hh b/source/blender/gpu/opengl/gl_framebuffer.hh
index 7b2c73d7042..21b5931440d 100644
--- a/source/blender/gpu/opengl/gl_framebuffer.hh
+++ b/source/blender/gpu/opengl/gl_framebuffer.hh
@@ -79,6 +79,9 @@ class GLFrameBuffer : public FrameBuffer {
void bind(bool enabled_srgb) override;
+ /**
+ * This is a rather slow operation. Don't check in normal cases.
+ */
bool check(char err_out[256]) override;
void clear(eGPUFrameBufferBits buffers,
@@ -97,6 +100,9 @@ class GLFrameBuffer : public FrameBuffer {
int slot,
void *r_data) override;
+ /**
+ * Copy \a src at the give offset inside \a dst.
+ */
void blit_to(eGPUFrameBufferBits planes,
int src_slot,
FrameBuffer *dst,
diff --git a/source/blender/gpu/opengl/gl_shader.cc b/source/blender/gpu/opengl/gl_shader.cc
index 66a1bd5ceb7..cd2c3caad46 100644
--- a/source/blender/gpu/opengl/gl_shader.cc
+++ b/source/blender/gpu/opengl/gl_shader.cc
@@ -137,7 +137,6 @@ char *GLShader::glsl_patch_get(GLenum gl_stage)
return glsl_patch_default_get();
}
-/* Create, compile and attach the shader stage to the shader program. */
GLuint GLShader::create_shader_stage(GLenum gl_stage, MutableSpan<const char *> sources)
{
GLuint shader = glCreateShader(gl_stage);
@@ -258,7 +257,6 @@ void GLShader::unbind()
* TODO(fclem): Should be replaced by compute shaders.
* \{ */
-/* Should be called before linking. */
void GLShader::transform_feedback_names_set(Span<const char *> name_list,
const eGPUShaderTFBType geom_type)
{
diff --git a/source/blender/gpu/opengl/gl_shader.hh b/source/blender/gpu/opengl/gl_shader.hh
index 770bc29747e..57e33392d9f 100644
--- a/source/blender/gpu/opengl/gl_shader.hh
+++ b/source/blender/gpu/opengl/gl_shader.hh
@@ -53,13 +53,14 @@ class GLShader : public Shader {
GLShader(const char *name);
~GLShader();
- /* Return true on success. */
+ /** Return true on success. */
void vertex_shader_from_glsl(MutableSpan<const char *> sources) override;
void geometry_shader_from_glsl(MutableSpan<const char *> sources) override;
void fragment_shader_from_glsl(MutableSpan<const char *> sources) override;
void compute_shader_from_glsl(MutableSpan<const char *> sources) override;
bool finalize(void) override;
+ /** Should be called before linking. */
void transform_feedback_names_set(Span<const char *> name_list,
const eGPUShaderTFBType geom_type) override;
bool transform_feedback_enable(GPUVertBuf *buf) override;
@@ -73,12 +74,13 @@ class GLShader : public Shader {
void vertformat_from_shader(GPUVertFormat *format) const override;
- /* DEPRECATED: Kept only because of BGL API. */
+ /** DEPRECATED: Kept only because of BGL API. */
int program_handle_get(void) const override;
private:
char *glsl_patch_get(GLenum gl_stage);
+ /** Create, compile and attach the shader stage to the shader program. */
GLuint create_shader_stage(GLenum gl_stage, MutableSpan<const char *> sources);
MEM_CXX_CLASS_ALLOC_FUNCS("GLShader");
diff --git a/source/blender/gpu/opengl/gl_state.cc b/source/blender/gpu/opengl/gl_state.cc
index d737cf88a13..bfc691df4b3 100644
--- a/source/blender/gpu/opengl/gl_state.cc
+++ b/source/blender/gpu/opengl/gl_state.cc
@@ -84,7 +84,6 @@ void GLStateManager::apply_state()
active_fb->apply_state();
};
-/* Will set all the states regardless of the current ones. */
void GLStateManager::force_state()
{
/* Little exception for clip distances since they need to keep the old count correct. */
@@ -482,7 +481,6 @@ void GLStateManager::texture_bind(Texture *tex_, eGPUSamplerState sampler_type,
dirty_texture_binds_ |= 1ULL << unit;
}
-/* Bind the texture to slot 0 for editing purpose. Used by legacy pipeline. */
void GLStateManager::texture_bind_temp(GLTexture *tex)
{
glActiveTexture(GL_TEXTURE0);
diff --git a/source/blender/gpu/opengl/gl_state.hh b/source/blender/gpu/opengl/gl_state.hh
index 3b4b40b1d10..979644b41c9 100644
--- a/source/blender/gpu/opengl/gl_state.hh
+++ b/source/blender/gpu/opengl/gl_state.hh
@@ -72,11 +72,17 @@ class GLStateManager : public StateManager {
GLStateManager();
void apply_state(void) override;
+ /**
+ * Will set all the states regardless of the current ones.
+ */
void force_state(void) override;
void issue_barrier(eGPUBarrier barrier_bits) override;
void texture_bind(Texture *tex, eGPUSamplerState sampler, int unit) override;
+ /**
+ * Bind the texture to slot 0 for editing purpose. Used by legacy pipeline.
+ */
void texture_bind_temp(GLTexture *tex);
void texture_unbind(Texture *tex) override;
void texture_unbind_all(void) override;
diff --git a/source/blender/gpu/opengl/gl_texture.cc b/source/blender/gpu/opengl/gl_texture.cc
index db1fda63c28..d84d21d3021 100644
--- a/source/blender/gpu/opengl/gl_texture.cc
+++ b/source/blender/gpu/opengl/gl_texture.cc
@@ -62,7 +62,6 @@ GLTexture::~GLTexture()
GLContext::tex_free(tex_id_);
}
-/* Return true on success. */
bool GLTexture::init_internal()
{
if ((format_ == GPU_DEPTH24_STENCIL8) && GPU_depth_blitting_workaround()) {
@@ -100,7 +99,6 @@ bool GLTexture::init_internal()
return true;
}
-/* Return true on success. */
bool GLTexture::init_internal(GPUVertBuf *vbo)
{
GLVertBuf *gl_vbo = static_cast<GLVertBuf *>(unwrap(vbo));
@@ -123,7 +121,6 @@ bool GLTexture::init_internal(GPUVertBuf *vbo)
return true;
}
-/* Will create enough mipmaps up to get to the given level. */
void GLTexture::ensure_mipmaps(int miplvl)
{
int effective_h = (type_ == GPU_TEXTURE_1D_ARRAY) ? 0 : h_;
@@ -225,6 +222,8 @@ void GLTexture::update_sub_direct_state_access(
break;
}
}
+
+ has_pixels_ = true;
}
void GLTexture::update_sub(
@@ -288,6 +287,8 @@ void GLTexture::update_sub(
break;
}
}
+
+ has_pixels_ = true;
}
/**
@@ -307,6 +308,16 @@ void GLTexture::generate_mipmap()
return;
}
+ if (GLContext::generate_mipmap_workaround) {
+ /* Broken glGenerateMipmap, don't call it and render without mipmaps.
+ * If no top level pixels have been filled in, the levels will get filled by
+ * other means and there is no need to disable mipmapping. */
+ if (has_pixels_) {
+ this->mip_range_set(0, 0);
+ }
+ return;
+ }
+
/* Down-sample from mip 0 using implementation. */
if (GLContext::direct_state_access_support) {
glGenerateTextureMipmap(tex_id_);
@@ -337,6 +348,8 @@ void GLTexture::clear(eGPUDataFormat data_format, const void *data)
GPU_framebuffer_bind(prev_fb);
}
+
+ has_pixels_ = true;
}
void GLTexture::copy_to(Texture *dst_)
@@ -363,6 +376,8 @@ void GLTexture::copy_to(Texture *dst_)
GPU_framebuffer_blit(
src->framebuffer_get(), 0, dst->framebuffer_get(), 0, to_framebuffer_bits(format_));
}
+
+ has_pixels_ = true;
}
void *GLTexture::read(int mip, eGPUDataFormat type)
@@ -452,6 +467,7 @@ struct GPUFrameBuffer *GLTexture::framebuffer_get()
GPUTexture *gputex = reinterpret_cast<GPUTexture *>(static_cast<Texture *>(this));
framebuffer_ = GPU_framebuffer_create(name_);
GPU_framebuffer_texture_attach(framebuffer_, gputex, 0, 0);
+ has_pixels_ = true;
return framebuffer_;
}
diff --git a/source/blender/gpu/opengl/gl_texture.hh b/source/blender/gpu/opengl/gl_texture.hh
index 2a480e71017..eb979444f5a 100644
--- a/source/blender/gpu/opengl/gl_texture.hh
+++ b/source/blender/gpu/opengl/gl_texture.hh
@@ -53,6 +53,8 @@ class GLTexture : public Texture {
/** True if this texture is bound to at least one texture unit. */
/* TODO(fclem): How do we ensure thread safety here? */
bool is_bound_ = false;
+ /** True if pixels in the texture have been initialized. */
+ bool has_pixels_ = false;
public:
GLTexture(const char *name);
@@ -61,6 +63,12 @@ class GLTexture : public Texture {
void update_sub(
int mip, int offset[3], int extent[3], eGPUDataFormat type, const void *data) override;
+ /**
+ * This will create the mipmap images and populate them with filtered data from base level.
+ *
+ * \warning Depth textures are not populated but they have their mips correctly defined.
+ * \warning This resets the mipmap range.
+ */
void generate_mipmap(void) override;
void copy_to(Texture *dst) override;
void clear(eGPUDataFormat format, const void *data) override;
@@ -78,11 +86,14 @@ class GLTexture : public Texture {
static void samplers_update(void);
protected:
+ /** Return true on success. */
bool init_internal(void) override;
+ /** Return true on success. */
bool init_internal(GPUVertBuf *vbo) override;
private:
bool proxy_check(int mip);
+ /** Will create enough mipmaps up to get to the given level. */
void ensure_mipmaps(int mip);
void update_sub_direct_state_access(
int mip, int offset[3], int extent[3], GLenum gl_format, GLenum gl_type, const void *data);
@@ -292,7 +303,9 @@ inline GLenum to_gl(eGPUDataFormat format)
}
}
-/* Definitely not complete, edit according to the gl specification. */
+/**
+ * Definitely not complete, edit according to the OpenGL specification.
+ */
inline GLenum to_gl_data_format(eGPUTextureFormat format)
{
/* You can add any of the available type to this list
@@ -364,7 +377,9 @@ inline GLenum to_gl_data_format(eGPUTextureFormat format)
}
}
-/* Assume Unorm / Float target. Used with glReadPixels. */
+/**
+ * Assume Unorm / Float target. Used with #glReadPixels.
+ */
inline GLenum channel_len_to_gl(int channel_len)
{
switch (channel_len) {
diff --git a/source/blender/gpu/opengl/gl_vertex_array.cc b/source/blender/gpu/opengl/gl_vertex_array.cc
index e324916b934..282ede5ba9b 100644
--- a/source/blender/gpu/opengl/gl_vertex_array.cc
+++ b/source/blender/gpu/opengl/gl_vertex_array.cc
@@ -108,7 +108,6 @@ static uint16_t vbo_bind(const ShaderInterface *interface,
return enabled_attrib;
}
-/* Update the Attribute Binding of the currently bound VAO. */
void GLVertArray::update_bindings(const GLuint vao,
const GPUBatch *batch_, /* Should be GLBatch. */
const ShaderInterface *interface,
@@ -156,7 +155,6 @@ void GLVertArray::update_bindings(const GLuint vao,
}
}
-/* Another version of update_bindings for Immediate mode. */
void GLVertArray::update_bindings(const GLuint vao,
const uint v_first,
const GPUVertFormat *format,
diff --git a/source/blender/gpu/opengl/gl_vertex_array.hh b/source/blender/gpu/opengl/gl_vertex_array.hh
index 7037986e31e..0f9b61f9648 100644
--- a/source/blender/gpu/opengl/gl_vertex_array.hh
+++ b/source/blender/gpu/opengl/gl_vertex_array.hh
@@ -33,11 +33,17 @@ namespace gpu {
namespace GLVertArray {
+/**
+ * Update the Attribute Binding of the currently bound VAO.
+ */
void update_bindings(const GLuint vao,
const GPUBatch *batch,
const ShaderInterface *interface,
const int base_instance);
+/**
+ * Another version of update_bindings for Immediate mode.
+ */
void update_bindings(const GLuint vao,
const uint v_first,
const GPUVertFormat *format,
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_frag.glsl
index 44a9db76834..43f259671fa 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_frag.glsl
@@ -13,7 +13,7 @@ uniform float dash_factor; /* if > 1.0, solid line. */
/* More advanced mode, allowing for complex, multi-colored patterns.
* Enabled when colors_len > 0. */
-/* Note: max number of steps/colors in pattern is 32! */
+/* NOTE: max number of steps/colors in pattern is 32! */
uniform int colors_len; /* Enabled if > 0, 1 for solid line. */
uniform vec4 colors[32];
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl
index 7853aae31a1..1def3abec26 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl
@@ -4,13 +4,128 @@ float smootherstep(float edge0, float edge1, float x)
return x * x * x * (x * (x * 6.0 - 15.0) + 10.0);
}
+vec3 smootherstep(vec3 edge0, vec3 edge1, vec3 x)
+{
+ x = clamp(safe_divide((x - edge0), (edge1 - edge0)), 0.0, 1.0);
+ return x * x * x * (x * (x * 6.0 - 15.0) + 10.0);
+}
+
+void vector_map_range_linear(float value,
+ float fromMin,
+ float fromMax,
+ float toMin,
+ float toMax,
+ float steps,
+ vec3 v_value,
+ vec3 v_from_min,
+ vec3 v_from_max,
+ vec3 v_to_min,
+ vec3 v_to_max,
+ vec3 v_steps,
+ float use_clamp,
+ out float result,
+ out vec3 v_result)
+{
+ vec3 factor = safe_divide((v_value - v_from_min), (v_from_max - v_from_min));
+ v_result = v_to_min + factor * (v_to_max - v_to_min);
+ if (use_clamp > 0.0) {
+ v_result.x = (v_to_min.x > v_to_max.x) ? clamp(v_result.x, v_to_max.x, v_to_min.x) :
+ clamp(v_result.x, v_to_min.x, v_to_max.x);
+ v_result.y = (v_to_min.y > v_to_max.y) ? clamp(v_result.y, v_to_max.y, v_to_min.y) :
+ clamp(v_result.y, v_to_min.y, v_to_max.y);
+ v_result.z = (v_to_min.z > v_to_max.z) ? clamp(v_result.z, v_to_max.z, v_to_min.z) :
+ clamp(v_result.z, v_to_min.z, v_to_max.z);
+ }
+}
+
+void vector_map_range_stepped(float value,
+ float fromMin,
+ float fromMax,
+ float toMin,
+ float toMax,
+ float steps,
+ vec3 v_value,
+ vec3 v_from_min,
+ vec3 v_from_max,
+ vec3 v_to_min,
+ vec3 v_to_max,
+ vec3 v_steps,
+ float use_clamp,
+ out float result,
+ out vec3 v_result)
+{
+ vec3 factor = safe_divide((v_value - v_from_min), (v_from_max - v_from_min));
+ factor = safe_divide(floor(factor * (v_steps + 1.0)), v_steps);
+ v_result = v_to_min + factor * (v_to_max - v_to_min);
+ if (use_clamp > 0.0) {
+ v_result.x = (v_to_min.x > v_to_max.x) ? clamp(v_result.x, v_to_max.x, v_to_min.x) :
+ clamp(v_result.x, v_to_min.x, v_to_max.x);
+ v_result.y = (v_to_min.y > v_to_max.y) ? clamp(v_result.y, v_to_max.y, v_to_min.y) :
+ clamp(v_result.y, v_to_min.y, v_to_max.y);
+ v_result.z = (v_to_min.z > v_to_max.z) ? clamp(v_result.z, v_to_max.z, v_to_min.z) :
+ clamp(v_result.z, v_to_min.z, v_to_max.z);
+ }
+}
+
+void vector_map_range_smoothstep(float value,
+ float fromMin,
+ float fromMax,
+ float toMin,
+ float toMax,
+ float steps,
+ vec3 v_value,
+ vec3 v_from_min,
+ vec3 v_from_max,
+ vec3 v_to_min,
+ vec3 v_to_max,
+ vec3 v_steps,
+ float use_clamp,
+ out float result,
+ out vec3 v_result)
+{
+ vec3 factor = safe_divide((v_value - v_from_min), (v_from_max - v_from_min));
+ factor = clamp(factor, 0.0, 1.0);
+ factor = (3.0 - 2.0 * factor) * (factor * factor);
+ v_result = v_to_min + factor * (v_to_max - v_to_min);
+}
+
+void vector_map_range_smootherstep(float value,
+ float fromMin,
+ float fromMax,
+ float toMin,
+ float toMax,
+ float steps,
+ vec3 v_value,
+ vec3 v_from_min,
+ vec3 v_from_max,
+ vec3 v_to_min,
+ vec3 v_to_max,
+ vec3 v_steps,
+ float use_clamp,
+ out float result,
+ out vec3 v_result)
+{
+ vec3 factor = safe_divide((v_value - v_from_min), (v_from_max - v_from_min));
+ factor = clamp(factor, 0.0, 1.0);
+ factor = factor * factor * factor * (factor * (factor * 6.0 - 15.0) + 10.0);
+ v_result = v_to_min + factor * (v_to_max - v_to_min);
+}
+
void map_range_linear(float value,
float fromMin,
float fromMax,
float toMin,
float toMax,
float steps,
- out float result)
+ vec3 v_value,
+ vec3 v_from_min,
+ vec3 v_from_max,
+ vec3 v_to_min,
+ vec3 v_to_max,
+ vec3 v_steps,
+ float use_clamp,
+ out float result,
+ out vec3 v_result)
{
if (fromMax != fromMin) {
result = toMin + ((value - fromMin) / (fromMax - fromMin)) * (toMax - toMin);
@@ -26,7 +141,15 @@ void map_range_stepped(float value,
float toMin,
float toMax,
float steps,
- out float result)
+ vec3 v_value,
+ vec3 v_from_min,
+ vec3 v_from_max,
+ vec3 v_to_min,
+ vec3 v_to_max,
+ vec3 v_steps,
+ float use_clamp,
+ out float result,
+ out vec3 v_result)
{
if (fromMax != fromMin) {
float factor = (value - fromMin) / (fromMax - fromMin);
@@ -44,7 +167,15 @@ void map_range_smoothstep(float value,
float toMin,
float toMax,
float steps,
- out float result)
+ vec3 v_value,
+ vec3 v_from_min,
+ vec3 v_from_max,
+ vec3 v_to_min,
+ vec3 v_to_max,
+ vec3 v_steps,
+ float use_clamp,
+ out float result,
+ out vec3 v_result)
{
if (fromMax != fromMin) {
float factor = (fromMin > fromMax) ? 1.0 - smoothstep(fromMax, fromMin, value) :
@@ -62,7 +193,15 @@ void map_range_smootherstep(float value,
float toMin,
float toMax,
float steps,
- out float result)
+ vec3 v_value,
+ vec3 v_from_min,
+ vec3 v_from_max,
+ vec3 v_to_min,
+ vec3 v_to_max,
+ vec3 v_steps,
+ float use_clamp,
+ out float result,
+ out vec3 v_result)
{
if (fromMax != fromMin) {
float factor = (fromMin > fromMax) ? 1.0 - smootherstep(fromMax, fromMin, value) :
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_magic.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_magic.glsl
index 942c507cc38..1dc5ff433a8 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_magic.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_magic.glsl
@@ -1,7 +1,8 @@
void node_tex_magic(
vec3 co, float scale, float distortion, float depth, out vec4 color, out float fac)
{
- vec3 p = co * scale;
+ vec3 p = mod(co * scale, 2.0 * M_PI);
+
float x = sin((p.x + p.y + p.z) * 5.0);
float y = cos((-p.x + p.y - p.z) * 5.0);
float z = -cos((-p.x - p.y + p.z) * 5.0);
diff --git a/source/blender/ikplugin/intern/itasc_plugin.cpp b/source/blender/ikplugin/intern/itasc_plugin.cpp
index a9e1692ebf0..949efb522f3 100644
--- a/source/blender/ikplugin/intern/itasc_plugin.cpp
+++ b/source/blender/ikplugin/intern/itasc_plugin.cpp
@@ -1876,9 +1876,10 @@ static void execute_scene(struct Depsgraph *depsgraph,
}
}
-/*---------------------------------------------------
- * plugin interface
- */
+/* -------------------------------------------------------------------- */
+/** \name Plugin Interface
+ * \{ */
+
void itasc_initialize_tree(struct Depsgraph *depsgraph,
struct Scene *scene,
Object *ob,
@@ -2012,3 +2013,5 @@ void itasc_test_constraint(struct Object *ob, struct bConstraint *cons)
break;
}
}
+
+/** \} */
diff --git a/source/blender/imbuf/CMakeLists.txt b/source/blender/imbuf/CMakeLists.txt
index be0e364c85f..479f4f7e82f 100644
--- a/source/blender/imbuf/CMakeLists.txt
+++ b/source/blender/imbuf/CMakeLists.txt
@@ -64,6 +64,7 @@ set(SRC
intern/thumbs.c
intern/thumbs_blend.c
intern/thumbs_font.c
+ intern/transform.cc
intern/util.c
intern/util_gpu.c
intern/writeimage.c
diff --git a/source/blender/imbuf/IMB_colormanagement.h b/source/blender/imbuf/IMB_colormanagement.h
index 53b0e295385..3ea8ac47f17 100644
--- a/source/blender/imbuf/IMB_colormanagement.h
+++ b/source/blender/imbuf/IMB_colormanagement.h
@@ -45,7 +45,9 @@ struct bContext;
struct ColorManagedDisplay;
struct ColorSpace;
-/* ** Generic functions ** */
+/* -------------------------------------------------------------------- */
+/** \name Generic Functions
+ * \{ */
void IMB_colormanagement_check_file_config(struct Main *bmain);
@@ -67,13 +69,35 @@ bool IMB_colormanagement_space_is_scene_linear(struct ColorSpace *colorspace);
bool IMB_colormanagement_space_is_srgb(struct ColorSpace *colorspace);
bool IMB_colormanagement_space_name_is_data(const char *name);
+/**
+ * Convert a float RGB triplet to the correct luminance weighted average.
+ *
+ * Grayscale, or Luma is a distillation of RGB data values down to a weighted average
+ * based on the luminance positions of the red, green, and blue primaries.
+ * Given that the internal reference space may be arbitrarily set, any
+ * effort to glean the luminance coefficients must be aware of the reference
+ * space primaries.
+ *
+ * See http://wiki.blender.org/index.php/User:Nazg-gul/ColorManagement#Luminance
+ */
BLI_INLINE float IMB_colormanagement_get_luminance(const float rgb[3]);
+/**
+ * Byte equivalent of #IMB_colormanagement_get_luminance().
+ */
BLI_INLINE unsigned char IMB_colormanagement_get_luminance_byte(const unsigned char[3]);
BLI_INLINE void IMB_colormanagement_xyz_to_rgb(float rgb[3], const float xyz[3]);
BLI_INLINE void IMB_colormanagement_rgb_to_xyz(float xyz[3], const float rgb[3]);
const float *IMB_colormanagement_get_xyz_to_rgb(void);
-/* ** Color space transformation functions ** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Color Space Transformation Functions
+ * \{ */
+
+/**
+ * Convert the whole buffer from specified by name color space to another.
+ */
void IMB_colormanagement_transform(float *buffer,
int width,
int height,
@@ -81,6 +105,10 @@ void IMB_colormanagement_transform(float *buffer,
const char *from_colorspace,
const char *to_colorspace,
bool predivide);
+/**
+ * Convert the whole buffer from specified by name color space to another
+ * will do threaded conversion.
+ */
void IMB_colormanagement_transform_threaded(float *buffer,
int width,
int height,
@@ -88,6 +116,9 @@ void IMB_colormanagement_transform_threaded(float *buffer,
const char *from_colorspace,
const char *to_colorspace,
bool predivide);
+/**
+ * Similar to #IMB_colormanagement_transform_threaded, but operates on byte buffer.
+ */
void IMB_colormanagement_transform_byte(unsigned char *buffer,
int width,
int height,
@@ -100,6 +131,9 @@ void IMB_colormanagement_transform_byte_threaded(unsigned char *buffer,
int channels,
const char *from_colorspace,
const char *to_colorspace);
+/**
+ * Similar to #IMB_colormanagement_transform_byte_threaded, but gets float buffer from display one.
+ */
void IMB_colormanagement_transform_from_byte(float *float_buffer,
unsigned char *byte_buffer,
int width,
@@ -118,12 +152,20 @@ void IMB_colormanagement_transform_v4(float pixel[4],
const char *from_colorspace,
const char *to_colorspace);
+/**
+ * Convert pixel from specified by descriptor color space to scene linear
+ * used by performance-critical areas such as renderer and baker.
+ */
void IMB_colormanagement_colorspace_to_scene_linear_v3(float pixel[3],
struct ColorSpace *colorspace);
void IMB_colormanagement_colorspace_to_scene_linear_v4(float pixel[4],
bool predivide,
struct ColorSpace *colorspace);
+/**
+ * Same as #IMB_colormanagement_colorspace_to_scene_linear_v4,
+ * but converts colors in opposite direction.
+ */
void IMB_colormanagement_scene_linear_to_colorspace_v3(float pixel[3],
struct ColorSpace *colorspace);
@@ -150,14 +192,36 @@ void IMB_colormanagement_imbuf_to_float_texture(float *out_buffer,
const struct ImBuf *ibuf,
const bool store_premultiplied);
+/**
+ * Conversion between color picking role. Typically we would expect such a
+ * requirements:
+ * - It is approximately perceptually linear, so that the HSV numbers and
+ * the HSV cube/circle have an intuitive distribution.
+ * - It has the same gamut as the scene linear color space.
+ * - Color picking values 0..1 map to scene linear values in the 0..1 range,
+ * so that picked albedo values are energy conserving.
+ */
void IMB_colormanagement_scene_linear_to_color_picking_v3(float pixel[3]);
void IMB_colormanagement_color_picking_to_scene_linear_v3(float pixel[3]);
+/**
+ * Conversion between sRGB, for rare cases like hex color or copy/pasting
+ * between UI theme and scene linear colors.
+ */
void IMB_colormanagement_scene_linear_to_srgb_v3(float pixel[3]);
void IMB_colormanagement_srgb_to_scene_linear_v3(float pixel[3]);
+/**
+ * Convert pixel from scene linear to display space using default view
+ * used by performance-critical areas such as color-related widgets where we want to reduce
+ * amount of per-widget allocations.
+ */
void IMB_colormanagement_scene_linear_to_display_v3(float pixel[3],
struct ColorManagedDisplay *display);
+/**
+ * Same as #IMB_colormanagement_scene_linear_to_display_v3,
+ * but converts color in opposite direction.
+ */
void IMB_colormanagement_display_to_scene_linear_v3(float pixel[3],
struct ColorManagedDisplay *display);
@@ -178,6 +242,18 @@ void IMB_colormanagement_imbuf_make_display_space(
const struct ColorManagedViewSettings *view_settings,
const struct ColorManagedDisplaySettings *display_settings);
+/**
+ * Prepare image buffer to be saved on disk, applying color management if needed
+ * color management would be applied if image is saving as render result and if
+ * file format is not expecting float buffer to be in linear space (currently
+ * JPEG2000 and TIFF are such formats -- they're storing image as float but
+ * file itself stores applied color space).
+ *
+ * Both byte and float buffers would contain applied color space, and result's
+ * float_colorspace would be set to display color space. This should be checked
+ * in image format write callback and if float_colorspace is not NULL, no color
+ * space transformation should be applied on this buffer.
+ */
struct ImBuf *IMB_colormanagement_imbuf_for_write(
struct ImBuf *ibuf,
bool save_as_render,
@@ -196,7 +272,11 @@ void IMB_colormanagement_buffer_make_display_space(
const struct ColorManagedViewSettings *view_settings,
const struct ColorManagedDisplaySettings *display_settings);
-/* ** Public display buffers interfaces ** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Public Display Buffers Interfaces
+ * \{ */
void IMB_colormanagement_display_settings_from_ctx(
const struct bContext *C,
@@ -207,11 +287,17 @@ const char *IMB_colormanagement_get_display_colorspace_name(
const struct ColorManagedViewSettings *view_settings,
const struct ColorManagedDisplaySettings *display_settings);
+/**
+ * Acquire display buffer for given image buffer using specified view and display settings.
+ */
unsigned char *IMB_display_buffer_acquire(
struct ImBuf *ibuf,
const struct ColorManagedViewSettings *view_settings,
const struct ColorManagedDisplaySettings *display_settings,
void **cache_handle);
+/**
+ * Same as #IMB_display_buffer_acquire but gets view and display settings from context.
+ */
unsigned char *IMB_display_buffer_acquire_ctx(const struct bContext *C,
struct ImBuf *ibuf,
void **cache_handle);
@@ -227,24 +313,47 @@ void IMB_display_buffer_transform_apply(unsigned char *display_buffer,
void IMB_display_buffer_release(void *cache_handle);
-/* ** Display functions ** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Display Functions
+ * \{ */
+
int IMB_colormanagement_display_get_named_index(const char *name);
const char *IMB_colormanagement_display_get_indexed_name(int index);
const char *IMB_colormanagement_display_get_default_name(void);
+/**
+ * Used by performance-critical pixel processing areas, such as color widgets.
+ */
struct ColorManagedDisplay *IMB_colormanagement_display_get_named(const char *name);
const char *IMB_colormanagement_display_get_none_name(void);
const char *IMB_colormanagement_display_get_default_view_transform_name(
struct ColorManagedDisplay *display);
-/* ** View functions ** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Functions
+ * \{ */
+
int IMB_colormanagement_view_get_named_index(const char *name);
const char *IMB_colormanagement_view_get_indexed_name(int index);
-/* ** Look functions ** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Look Functions
+ * \{ */
+
int IMB_colormanagement_look_get_named_index(const char *name);
const char *IMB_colormanagement_look_get_indexed_name(int index);
-/* ** Color space functions ** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Color Space Functions
+ * \{ */
+
int IMB_colormanagement_colorspace_get_named_index(const char *name);
const char *IMB_colormanagement_colorspace_get_indexed_name(int index);
const char *IMB_colormanagement_view_get_default_name(const char *display_name);
@@ -252,7 +361,12 @@ const char *IMB_colormanagement_view_get_default_name(const char *display_name);
void IMB_colormanagement_colorspace_from_ibuf_ftype(
struct ColorManagedColorspaceSettings *colorspace_settings, struct ImBuf *ibuf);
-/* ** RNA helper functions ** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name RNA Helper Functions
+ * \{ */
+
void IMB_colormanagement_display_items_add(struct EnumPropertyItem **items, int *totitem);
void IMB_colormanagement_view_items_add(struct EnumPropertyItem **items,
int *totitem,
@@ -262,7 +376,12 @@ void IMB_colormanagement_look_items_add(struct EnumPropertyItem **items,
const char *view_name);
void IMB_colormanagement_colorspace_items_add(struct EnumPropertyItem **items, int *totitem);
-/* ** Tile-based buffer management ** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Tile-based Buffer Management
+ * \{ */
+
void IMB_partial_display_buffer_update(struct ImBuf *ibuf,
const float *linear_buffer,
const unsigned char *byte_buffer,
@@ -293,7 +412,12 @@ void IMB_partial_display_buffer_update_threaded(
void IMB_partial_display_buffer_update_delayed(
struct ImBuf *ibuf, int xmin, int ymin, int xmax, int ymax);
-/* ** Pixel processor functions ** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Pixel Processor Functions
+ * \{ */
+
struct ColormanageProcessor *IMB_colormanagement_display_processor_new(
const struct ColorManagedViewSettings *view_settings,
const struct ColorManagedDisplaySettings *display_settings);
@@ -321,17 +445,40 @@ void IMB_colormanagement_processor_apply_byte(struct ColormanageProcessor *cm_pr
int channels);
void IMB_colormanagement_processor_free(struct ColormanageProcessor *cm_processor);
-/* ** OpenGL drawing routines using GLSL for color space transform ** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name OpenGL Drawing Routines Using GLSL for Color Space Transform
+ * \{ */
-/* Test if GLSL drawing is supported for combination of graphics card and this configuration */
+/**
+ * Test if GLSL drawing is supported for combination of graphics card and this configuration.
+ */
bool IMB_colormanagement_support_glsl_draw(const struct ColorManagedViewSettings *view_settings);
-/* Configures GLSL shader for conversion from scene linear to display space */
+/**
+ * Configures GLSL shader for conversion from scene linear to display space.
+ */
bool IMB_colormanagement_setup_glsl_draw(
const struct ColorManagedViewSettings *view_settings,
const struct ColorManagedDisplaySettings *display_settings,
float dither,
bool predivide);
-/* Same as above, but display space conversion happens from a specified space */
+/**
+ * \note Same as IMB_colormanagement_setup_glsl_draw,
+ * but display space conversion happens from a specified space.
+ *
+ * Configures GLSL shader for conversion from specified to
+ * display color space
+ *
+ * Will create appropriate OCIO processor and setup GLSL shader,
+ * so further 2D texture usage will use this conversion.
+ *
+ * When there's no need to apply transform on 2D textures, use
+ * IMB_colormanagement_finish_glsl_draw().
+ *
+ * This is low-level function, use ED_draw_imbuf_ctx if you
+ * only need to display given image buffer
+ */
bool IMB_colormanagement_setup_glsl_draw_from_space(
const struct ColorManagedViewSettings *view_settings,
const struct ColorManagedDisplaySettings *display_settings,
@@ -339,20 +486,31 @@ bool IMB_colormanagement_setup_glsl_draw_from_space(
float dither,
bool predivide,
bool do_overlay_merge);
-/* Same as setup_glsl_draw, but color management settings are guessing from a given context */
+/**
+ * Same as setup_glsl_draw, but color management settings are guessing from a given context.
+ */
bool IMB_colormanagement_setup_glsl_draw_ctx(const struct bContext *C,
float dither,
bool predivide);
-/* Same as setup_glsl_draw_from_space,
- * but color management settings are guessing from a given context. */
+/**
+ * Same as `setup_glsl_draw_from_space`,
+ * but color management settings are guessing from a given context.
+ */
bool IMB_colormanagement_setup_glsl_draw_from_space_ctx(const struct bContext *C,
struct ColorSpace *colorspace,
float dither,
bool predivide);
-/* Finish GLSL-based display space conversion */
+/**
+ * Finish GLSL-based display space conversion.
+ */
void IMB_colormanagement_finish_glsl_draw(void);
-/* ** View transform ** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Transform
+ * \{ */
+
void IMB_colormanagement_init_default_view_settings(
struct ColorManagedViewSettings *view_settings,
const struct ColorManagedDisplaySettings *display_settings);
@@ -368,6 +526,8 @@ enum {
COLOR_ROLE_DATA,
};
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h
index 7bfd1074ac6..1f698c65382 100644
--- a/source/blender/imbuf/IMB_imbuf.h
+++ b/source/blender/imbuf/IMB_imbuf.h
@@ -199,6 +199,17 @@ bool addzbuffloatImBuf(struct ImBuf *ibuf);
size_t IMB_get_size_in_memory(struct ImBuf *ibuf);
/**
+ * \brief Get the length of the rect of the given image buffer in terms of pixels.
+ *
+ * This is the width * the height of the image buffer.
+ * This function is preferred over `ibuf->x * ibuf->y` due to overflow issues when
+ * working with large resolution images (30kx30k).
+ *
+ * \attention Defined in allocimbuf.c
+ */
+size_t IMB_get_rect_len(const struct ImBuf *ibuf);
+
+/**
*
* \attention Defined in rectop.c
*/
@@ -244,8 +255,14 @@ void IMB_blend_color_float(float dst[4],
const float src2[4],
IMB_BlendMode mode);
+/**
+ * In-place image crop.
+ */
void IMB_rect_crop(struct ImBuf *ibuf, const struct rcti *crop);
+/**
+ * In-place size setting (caller must fill in buffer contents).
+ */
void IMB_rect_size_set(struct ImBuf *ibuf, const uint size[2]);
void IMB_rectclip(struct ImBuf *dbuf,
@@ -342,7 +359,9 @@ typedef enum eIMBInterpolationFilterMode {
IMB_FILTER_BILINEAR,
} eIMBInterpolationFilterMode;
-/* Defaults to BL_proxy within the directory of the animation. */
+/**
+ * Defaults to BL_proxy within the directory of the animation.
+ */
void IMB_anim_set_index_dir(struct anim *anim, const char *dir);
void IMB_anim_get_fname(struct anim *anim, char *file, int size);
@@ -352,7 +371,9 @@ IMB_Proxy_Size IMB_anim_proxy_get_existing(struct anim *anim);
struct IndexBuildContext;
-/* Prepare context for proxies/time-codes builder. */
+/**
+ * Prepare context for proxies/time-codes builder
+ */
struct IndexBuildContext *IMB_anim_index_rebuild_context(struct anim *anim,
IMB_Timecode_Type tcs_in_use,
IMB_Proxy_Size proxy_sizes_in_use,
@@ -360,13 +381,17 @@ struct IndexBuildContext *IMB_anim_index_rebuild_context(struct anim *anim,
const bool overwrite,
struct GSet *file_list);
-/* Will rebuild all used indices and proxies at once. */
+/**
+ * Will rebuild all used indices and proxies at once.
+ */
void IMB_anim_index_rebuild(struct IndexBuildContext *context,
short *stop,
short *do_update,
float *progress);
-/* Finish rebuilding proxies/time-codes and free temporary contexts used. */
+/**
+ * Finish rebuilding proxies/time-codes and free temporary contexts used.
+ */
void IMB_anim_index_rebuild_finish(struct IndexBuildContext *context, short stop);
/**
@@ -442,8 +467,20 @@ void IMB_free_anim(struct anim *anim);
void IMB_filter(struct ImBuf *ibuf);
void IMB_mask_filter_extend(char *mask, int width, int height);
void IMB_mask_clear(struct ImBuf *ibuf, const char *mask, int val);
+/**
+ * If alpha is zero, it checks surrounding pixels and averages color. sets new alphas to 1.0
+ * When a mask is given, the mask will be used instead of the alpha channel, where only
+ * pixels with a mask value of 0 will be written to, and only pixels with a mask value of 1
+ * will be used for the average. The mask will be set to one for the pixels which were written.
+ */
void IMB_filter_extend(struct ImBuf *ibuf, char *mask, int filter);
+/**
+ * Frees too (if there) and recreates new data.
+ */
void IMB_makemipmap(struct ImBuf *ibuf, int use_filter);
+/**
+ * Thread-safe version, only recreates existing maps.
+ */
void IMB_remakemipmap(struct ImBuf *ibuf, int use_filter);
struct ImBuf *IMB_getmipmap(struct ImBuf *ibuf, int level);
@@ -452,6 +489,9 @@ struct ImBuf *IMB_getmipmap(struct ImBuf *ibuf, int level);
* \attention Defined in cache.c
*/
+/**
+ * Presumed to be called when no threads are running.
+ */
void IMB_tile_cache_params(int totthread, int maxmem);
unsigned int *IMB_gettile(struct ImBuf *ibuf, int tx, int ty, int thread);
void IMB_tiles_to_rect(struct ImBuf *ibuf);
@@ -471,6 +511,8 @@ struct ImBuf *IMB_onehalf(struct ImBuf *ibuf1);
/**
*
* \attention Defined in scaling.c
+ *
+ * Return true if \a ibuf is modified.
*/
bool IMB_scaleImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy);
@@ -478,6 +520,9 @@ bool IMB_scaleImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy);
*
* \attention Defined in scaling.c
*/
+/**
+ * Return true if \a ibuf is modified.
+ */
bool IMB_scalefastImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy);
/**
@@ -520,16 +565,27 @@ int imb_get_anim_type(const char *filepath);
*/
bool IMB_isfloat(const struct ImBuf *ibuf);
-/* Do byte/float and colorspace conversions need to take alpha into account? */
+/**
+ * Test if color-space conversions of pixels in buffer need to take into account alpha.
+ */
bool IMB_alpha_affects_rgb(const struct ImBuf *ibuf);
-/* create char buffer, color corrected if necessary, for ImBufs that lack one */
+/**
+ * Create char buffer, color corrected if necessary, for ImBufs that lack one.
+ */
void IMB_rect_from_float(struct ImBuf *ibuf);
void IMB_float_from_rect(struct ImBuf *ibuf);
+/**
+ * No profile conversion.
+ */
void IMB_color_to_bw(struct ImBuf *ibuf);
void IMB_saturation(struct ImBuf *ibuf, float sat);
-/* converting pixel buffers */
+/* Converting pixel buffers. */
+
+/**
+ * Float to byte pixels, output 4-channel RGBA.
+ */
void IMB_buffer_byte_from_float(unsigned char *rect_to,
const float *rect_from,
int channels_from,
@@ -541,6 +597,9 @@ void IMB_buffer_byte_from_float(unsigned char *rect_to,
int height,
int stride_to,
int stride_from);
+/**
+ * Float to byte pixels, output 4-channel RGBA.
+ */
void IMB_buffer_byte_from_float_mask(unsigned char *rect_to,
const float *rect_from,
int channels_from,
@@ -551,6 +610,9 @@ void IMB_buffer_byte_from_float_mask(unsigned char *rect_to,
int stride_to,
int stride_from,
char *mask);
+/**
+ * Byte to float pixels, input and output 4-channel RGBA.
+ */
void IMB_buffer_float_from_byte(float *rect_to,
const unsigned char *rect_from,
int profile_to,
@@ -560,6 +622,9 @@ void IMB_buffer_float_from_byte(float *rect_to,
int height,
int stride_to,
int stride_from);
+/**
+ * Float to float pixels, output 4-channel RGBA.
+ */
void IMB_buffer_float_from_float(float *rect_to,
const float *rect_from,
int channels_from,
@@ -580,6 +645,9 @@ void IMB_buffer_float_from_float_threaded(float *rect_to,
int height,
int stride_to,
int stride_from);
+/**
+ * Float to float pixels, output 4-channel RGBA.
+ */
void IMB_buffer_float_from_float_mask(float *rect_to,
const float *rect_from,
int channels_from,
@@ -588,6 +656,9 @@ void IMB_buffer_float_from_float_mask(float *rect_to,
int stride_to,
int stride_from,
char *mask);
+/**
+ * Byte to byte pixels, input and output 4-channel RGBA.
+ */
void IMB_buffer_byte_from_byte(unsigned char *rect_to,
const unsigned char *rect_from,
int profile_to,
@@ -605,6 +676,8 @@ void IMB_buffer_float_premultiply(float *buf, int width, int height);
* rgba to abgr. size * 4 color bytes are reordered.
*
* \attention Defined in imageprocess.c
+ *
+ * Only this one is used liberally here, and in imbuf.
*/
void IMB_convert_rgba_to_abgr(struct ImBuf *ibuf);
@@ -612,27 +685,50 @@ void IMB_convert_rgba_to_abgr(struct ImBuf *ibuf);
*
* \attention defined in imageprocess.c
*/
+
void bicubic_interpolation(
- struct ImBuf *in, struct ImBuf *out, float u, float v, int xout, int yout);
+ const struct ImBuf *in, struct ImBuf *out, float u, float v, int xout, int yout);
void nearest_interpolation(
- struct ImBuf *in, struct ImBuf *out, float u, float v, int xout, int yout);
+ const struct ImBuf *in, struct ImBuf *out, float u, float v, int xout, int yout);
void bilinear_interpolation(
- struct ImBuf *in, struct ImBuf *out, float u, float v, int xout, int yout);
+ const struct ImBuf *in, struct ImBuf *out, float u, float v, int xout, int yout);
+typedef void (*InterpolationColorFunction)(
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
void bicubic_interpolation_color(
- struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
+
+/* Functions assumes out to be zeroed, only does RGBA. */
+
+void nearest_interpolation_color_char(
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
+void nearest_interpolation_color_fl(
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
void nearest_interpolation_color(
- struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
void nearest_interpolation_color_wrap(
- struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
void bilinear_interpolation_color(
- struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
+void bilinear_interpolation_color_char(
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
+void bilinear_interpolation_color_fl(
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
+/**
+ * Note about wrapping, the u/v still needs to be within the image bounds,
+ * just the interpolation is wrapped.
+ * This the same as bilinear_interpolation_color except it wraps
+ * rather than using empty and emptyI.
+ */
void bilinear_interpolation_color_wrap(
- struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
void IMB_alpha_under_color_float(float *rect_float, int x, int y, float backcol[3]);
void IMB_alpha_under_color_byte(unsigned char *rect, int x, int y, const float backcol[3]);
+/**
+ * Sample pixel of image using NEAREST method.
+ */
void IMB_sampleImageAtLocation(
struct ImBuf *ibuf, float x, float y, bool make_linear_rgb, float color[4]);
@@ -686,7 +782,7 @@ struct ImBuf *IMB_double_y(struct ImBuf *ibuf1);
void IMB_flipx(struct ImBuf *ibuf);
void IMB_flipy(struct ImBuf *ibuf);
-/* Premultiply alpha */
+/* Pre-multiply alpha. */
void IMB_premultiply_alpha(struct ImBuf *ibuf);
void IMB_unpremultiply_alpha(struct ImBuf *ibuf);
@@ -702,7 +798,27 @@ void IMB_freezbuffloatImBuf(struct ImBuf *ibuf);
*
* \attention Defined in rectop.c
*/
+/**
+ * Replace pixels of entire image with solid color.
+ * \param drect: An image to be filled with color. It must be 4 channel image.
+ * \param col: RGBA color, which is assigned directly to both byte (via scaling) and float buffers.
+ */
void IMB_rectfill(struct ImBuf *drect, const float col[4]);
+/**
+ * Blend pixels of image area with solid color.
+ *
+ * For images with `uchar` buffer use color matching image color-space.
+ * For images with float buffer use color display color-space.
+ * If display color-space can not be referenced, use color in SRGB color-space.
+ *
+ * \param ibuf: an image to be filled with color. It must be 4 channel image.
+ * \param col: RGBA color.
+ * \param x1, y1, x2, y2: (x1, y1) defines starting point of the rectangular area to be filled,
+ * (x2, y2) is the end point. Note that values are allowed to be loosely ordered, which means that
+ * x2 is allowed to be lower than x1, as well as y2 is allowed to be lower than y1. No matter the
+ * order the area between x1 and x2, and y1 and y2 is filled.
+ * \param display: color-space reference for display space.
+ */
void IMB_rectfill_area(struct ImBuf *ibuf,
const float col[4],
int x1,
@@ -710,12 +826,23 @@ void IMB_rectfill_area(struct ImBuf *ibuf,
int x2,
int y2,
struct ColorManagedDisplay *display);
+/**
+ * Replace pixels of image area with solid color.
+ * \param ibuf: an image to be filled with color. It must be 4 channel image.
+ * \param col: RGBA color, which is assigned directly to both byte (via scaling) and float buffers.
+ * \param x1, y1, x2, y2: (x1, y1) defines starting point of the rectangular area to be filled,
+ * (x2, y2) is the end point. Note that values are allowed to be loosely ordered, which means that
+ * x2 is allowed to be lower than x1, as well as y2 is allowed to be lower than y1. No matter the
+ * order the area between x1 and x2, and y1 and y2 is filled.
+ */
void IMB_rectfill_area_replace(
const struct ImBuf *ibuf, const float col[4], int x1, int y1, int x2, int y2);
void IMB_rectfill_alpha(struct ImBuf *ibuf, const float value);
-/* This should not be here, really,
- * we needed it for operating on render data, IMB_rectfill_area calls it. */
+/**
+ * This should not be here, really,
+ * we needed it for operating on render data, #IMB_rectfill_area calls it.
+ */
void buf_rectfill_area(unsigned char *rect,
float *rectf,
int width,
@@ -727,23 +854,34 @@ void buf_rectfill_area(unsigned char *rect,
int x2,
int y2);
-/* exported for image tools in blender, to quickly allocate 32 bits rect */
+/**
+ * Exported for image tools in blender, to quickly allocate 32 bits rect.
+ */
void *imb_alloc_pixels(
unsigned int x, unsigned int y, unsigned int channels, size_t typesize, const char *name);
bool imb_addrectImBuf(struct ImBuf *ibuf);
+/**
+ * Any free `ibuf->rect` frees mipmaps to be sure, creation is in render on first request.
+ */
void imb_freerectImBuf(struct ImBuf *ibuf);
bool imb_addrectfloatImBuf(struct ImBuf *ibuf);
+/**
+ * Any free `ibuf->rect` frees mipmaps to be sure, creation is in render on first request.
+ */
void imb_freerectfloatImBuf(struct ImBuf *ibuf);
void imb_freemipmapImBuf(struct ImBuf *ibuf);
bool imb_addtilesImBuf(struct ImBuf *ibuf);
void imb_freetilesImBuf(struct ImBuf *ibuf);
+/** Free all pixel data (associated with image size). */
void imb_freerectImbuf_all(struct ImBuf *ibuf);
-/* threaded processors */
+/**
+ * Threaded processors.
+ */
void IMB_processor_apply_threaded(
int buffer_lines,
int handle_size,
@@ -756,13 +894,48 @@ void IMB_processor_apply_threaded_scanlines(int total_scanlines,
ScanlineThreadFunc do_thread,
void *custom_data);
-void IMB_transform(struct ImBuf *src,
+/**
+ * \brief Transform modes to use for IMB_transform function.
+ *
+ * These are not flags as the combination of cropping and repeat can lead to different expectation.
+ */
+typedef enum eIMBTransformMode {
+ /** \brief Do not crop or repeat. */
+ IMB_TRANSFORM_MODE_REGULAR = 0,
+ /** \brief Crop the source buffer. */
+ IMB_TRANSFORM_MODE_CROP_SRC = 1,
+ /** \brief Wrap repeat the source buffer. Only supported in with nearest filtering. */
+ IMB_TRANSFORM_MODE_WRAP_REPEAT = 2,
+} eIMBTransformMode;
+
+/**
+ * \brief Transform source image buffer onto destination image buffer using a transform matrix.
+ *
+ * \param src Image buffer to read from.
+ * \param dst Image buffer to write to. rect or rect_float must already be initialized.
+ * - dst buffer must be a 4 channel buffers.
+ * - Only one data type buffer will be used (rect_float has priority over rect)
+ * \param mode Cropping/Wrap repeat effect to apply during transformation.
+ * \param filter Interpolation to use during sampling.
+ * \param transform_matrix Transformation matrix to use.
+ * The given matrix should transform between dst pixel space to src pixel space.
+ * One unit is one pixel.
+ * \param src_crop cropping region how to crop the source buffer. Should only be passed when mode
+ * is set to #IMB_TRANSFORM_MODE_CROP_SRC. For any other mode this should be empty.
+ *
+ * During transformation no data/color conversion will happens.
+ * When transforming between float images the number of channels of the source buffer may be
+ * between 1 and 4. When source buffer has one channel the data will be read as a gray scale value.
+ */
+void IMB_transform(const struct ImBuf *src,
struct ImBuf *dst,
- float transform_matrix[4][4],
- struct rctf *src_crop,
- const eIMBInterpolationFilterMode filter);
+ const eIMBTransformMode mode,
+ const eIMBInterpolationFilterMode filter,
+ const float transform_matrix[4][4],
+ const struct rctf *src_crop);
+
+/* FFMPEG */
-/* ffmpeg */
void IMB_ffmpeg_init(void);
const char *IMB_ffmpeg_last_error(void);
@@ -775,8 +948,17 @@ struct GPUTexture *IMB_create_gpu_texture(const char *name,
bool use_high_bitdepth,
bool use_premult,
bool limit_gl_texture_size);
+/**
+ * The `ibuf` is only here to detect the storage type. The produced texture will have undefined
+ * content. It will need to be populated by using #IMB_update_gpu_texture_sub().
+ */
struct GPUTexture *IMB_touch_gpu_texture(
const char *name, struct ImBuf *ibuf, int w, int h, int layers, bool use_high_bitdepth);
+/**
+ * Will update a #GPUTexture using the content of the #ImBuf. Only one layer will be updated.
+ * Will resize the ibuf if needed.
+ * Z is the layer to update. Unused if the texture is 2D.
+ */
void IMB_update_gpu_texture_sub(struct GPUTexture *tex,
struct ImBuf *ibuf,
int x,
@@ -788,7 +970,6 @@ void IMB_update_gpu_texture_sub(struct GPUTexture *tex,
bool use_premult);
/**
- *
* \attention defined in stereoimbuf.c
*/
void IMB_stereo3d_write_dimensions(const char mode,
@@ -815,9 +996,15 @@ float *IMB_stereo3d_from_rectf(struct ImageFormatData *im_format,
const size_t channels,
float *rectf_left,
float *rectf_right);
+/**
+ * Left/right are always float.
+ */
struct ImBuf *IMB_stereo3d_ImBuf(struct ImageFormatData *im_format,
struct ImBuf *ibuf_left,
struct ImBuf *ibuf_right);
+/**
+ * Reading a stereo encoded ibuf (*left) and generating two ibufs from it (*left and *right).
+ */
void IMB_ImBufFromStereo3d(struct Stereo3dFormat *s3d,
struct ImBuf *ibuf_stereo,
struct ImBuf **r_ibuf_left,
diff --git a/source/blender/imbuf/IMB_imbuf_types.h b/source/blender/imbuf/IMB_imbuf_types.h
index 9697064b445..58148743b7e 100644
--- a/source/blender/imbuf/IMB_imbuf_types.h
+++ b/source/blender/imbuf/IMB_imbuf_types.h
@@ -143,10 +143,9 @@ typedef struct ImbFormatOptions {
char quality;
} ImbFormatOptions;
-/**
- * \name Imbuf Component flags
+/* -------------------------------------------------------------------- */
+/** \name Imbuf Component flags
* \brief These flags determine the components of an ImBuf struct.
- *
* \{ */
typedef enum eImBufFlags {
@@ -175,6 +174,11 @@ typedef enum eImBufFlags {
} eImBufFlags;
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Image Buffer
+ * \{ */
+
typedef struct ImBuf {
struct ImBuf *next, *prev; /** < allow lists of #ImBufs, for caches or flip-books. */
@@ -301,11 +305,14 @@ enum {
IB_PERSISTENT = (1 << 5),
};
-/**
- * \name Imbuf preset profile tags
- * \brief Some predefined color space profiles that 8 bit imbufs can represent
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Imbuf Preset Profile Tags
*
+ * \brief Some predefined color space profiles that 8 bit imbufs can represent.
* \{ */
+
#define IB_PROFILE_NONE 0
#define IB_PROFILE_LINEAR_RGB 1
#define IB_PROFILE_SRGB 2
@@ -322,7 +329,7 @@ enum {
# endif /* DDS_MAKEFOURCC */
/*
- * FOURCC codes for DX compressed-texture pixel formats
+ * FOURCC codes for DX compressed-texture pixel formats.
*/
# define FOURCC_DDS (DDS_MAKEFOURCC('D', 'D', 'S', ' '))
@@ -337,13 +344,13 @@ extern const char *imb_ext_image[];
extern const char *imb_ext_movie[];
extern const char *imb_ext_audio[];
-/* image formats that can only be loaded via filepath */
+/** Image formats that can only be loaded via filepath. */
extern const char *imb_ext_image_filepath_only[];
-/**
- * \name Imbuf Color Management Flag
- * \brief Used with #ImBuf.colormanage_flag
+/* -------------------------------------------------------------------- */
+/** \name Imbuf Color Management Flag
*
+ * \brief Used with #ImBuf.colormanage_flag
* \{ */
enum {
diff --git a/source/blender/imbuf/IMB_moviecache.h b/source/blender/imbuf/IMB_moviecache.h
index d32346a8418..156a060c621 100644
--- a/source/blender/imbuf/IMB_moviecache.h
+++ b/source/blender/imbuf/IMB_moviecache.h
@@ -70,6 +70,9 @@ void IMB_moviecache_cleanup(struct MovieCache *cache,
void *userdata),
void *userdata);
+/**
+ * Get segments of cached frames. Useful for debugging cache policies.
+ */
void IMB_moviecache_get_cache_segments(
struct MovieCache *cache, int proxy, int render_flags, int *r_totseg, int **r_points);
diff --git a/source/blender/imbuf/IMB_thumbs.h b/source/blender/imbuf/IMB_thumbs.h
index e1a315a0bd2..6a739002fb3 100644
--- a/source/blender/imbuf/IMB_thumbs.h
+++ b/source/blender/imbuf/IMB_thumbs.h
@@ -48,47 +48,66 @@ typedef enum ThumbSource {
THB_SOURCE_FONT,
} ThumbSource;
-/* don't generate thumbs for images bigger than this (100mb) */
+/**
+ * Don't generate thumbs for images bigger than this (100mb).
+ */
#define THUMB_SIZE_MAX (100 * 1024 * 1024)
#define PREVIEW_RENDER_DEFAULT_HEIGHT 128
#define PREVIEW_RENDER_LARGE_HEIGHT 256
-/* Note this can also be used as versioning system,
+/**
+ * Note this can also be used as versioning system,
* to force refreshing all thumbnails if e.g. we change some thumb generating code or so.
- * Only used by fonts so far. */
+ * Only used by fonts so far.
+ */
#define THUMB_DEFAULT_HASH "00000000000000000000000000000000"
-/* create thumbnail for file and returns new imbuf for thumbnail */
+/**
+ * Create thumbnail for file and returns new imbuf for thumbnail.
+ */
struct ImBuf *IMB_thumb_create(const char *path,
ThumbSize size,
ThumbSource source,
struct ImBuf *img);
-/* read thumbnail for file and returns new imbuf for thumbnail */
+/**
+ * Read thumbnail for file and returns new imbuf for thumbnail.
+ */
struct ImBuf *IMB_thumb_read(const char *path, ThumbSize size);
-/* delete all thumbs for the file */
+/**
+ * Delete all thumbs for the file.
+ */
void IMB_thumb_delete(const char *path, ThumbSize size);
-/* return the state of the thumb, needed to determine how to manage the thumb */
+/**
+ * Create the thumb if necessary and manage failed and old thumbs.
+ */
struct ImBuf *IMB_thumb_manage(const char *path, ThumbSize size, ThumbSource source);
-/* create the necessary dirs to store the thumbnails */
+/**
+ * Create the necessary dirs to store the thumbnails.
+ */
void IMB_thumb_makedirs(void);
-/* special function for loading a thumbnail embedded into a blend file */
+/**
+ * Special function for loading a thumbnail embedded into a blend file.
+ */
struct ImBuf *IMB_thumb_load_blend(const char *blen_path,
const char *blen_group,
const char *blen_id);
-/* special function for previewing fonts */
+/**
+ * Special function for previewing fonts.
+ */
struct ImBuf *IMB_thumb_load_font(const char *filename, unsigned int x, unsigned int y);
bool IMB_thumb_load_font_get_hash(char *r_hash);
void IMB_thumb_clear_translations(void);
void IMB_thumb_ensure_translations(void);
/* Threading */
+
void IMB_thumb_locks_acquire(void);
void IMB_thumb_locks_release(void);
void IMB_thumb_path_lock(const char *path);
diff --git a/source/blender/imbuf/intern/IMB_filetype.h b/source/blender/imbuf/intern/IMB_filetype.h
index c8f6135f330..104458ffa7a 100644
--- a/source/blender/imbuf/intern/IMB_filetype.h
+++ b/source/blender/imbuf/intern/IMB_filetype.h
@@ -22,7 +22,9 @@
#include "IMB_imbuf.h"
-/* Generic File Type */
+/* -------------------------------------------------------------------- */
+/** \name Generic File Type
+ * \{ */
struct ImBuf;
@@ -78,11 +80,19 @@ void imb_tile_cache_init(void);
void imb_tile_cache_exit(void);
void imb_loadtile(struct ImBuf *ibuf, int tx, int ty, unsigned int *rect);
+/**
+ * External free.
+ */
void imb_tile_cache_tile_free(struct ImBuf *ibuf, int tx, int ty);
+/** \} */
+
/* Type Specific Functions */
-/* png */
+/* -------------------------------------------------------------------- */
+/** \name Format: PNG (#IMB_FTYPE_PNG)
+ * \{ */
+
bool imb_is_a_png(const unsigned char *mem, const size_t size);
struct ImBuf *imb_loadpng(const unsigned char *mem,
size_t size,
@@ -90,7 +100,12 @@ struct ImBuf *imb_loadpng(const unsigned char *mem,
char colorspace[IM_MAX_SPACE]);
bool imb_savepng(struct ImBuf *ibuf, const char *filepath, int flags);
-/* targa */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Format: TARGA (#IMB_FTYPE_TGA)
+ * \{ */
+
bool imb_is_a_targa(const unsigned char *buf, const size_t size);
struct ImBuf *imb_loadtarga(const unsigned char *mem,
size_t size,
@@ -98,15 +113,28 @@ struct ImBuf *imb_loadtarga(const unsigned char *mem,
char colorspace[IM_MAX_SPACE]);
bool imb_savetarga(struct ImBuf *ibuf, const char *filepath, int flags);
-/* iris */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Format: IRIS (#IMB_FTYPE_IMAGIC)
+ * \{ */
+
bool imb_is_a_iris(const unsigned char *mem, const size_t size);
+/**
+ * Read in a B/W RGB or RGBA iris image file and return an image buffer.
+ */
struct ImBuf *imb_loadiris(const unsigned char *mem,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
bool imb_saveiris(struct ImBuf *ibuf, const char *filepath, int flags);
-/* jp2 */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Format: JP2 (#IMB_FTYPE_JP2)
+ * \{ */
+
bool imb_is_a_jp2(const unsigned char *buf, const size_t size);
struct ImBuf *imb_load_jp2(const unsigned char *mem,
size_t size,
@@ -117,7 +145,12 @@ struct ImBuf *imb_load_jp2_filepath(const char *filepath,
char colorspace[IM_MAX_SPACE]);
bool imb_save_jp2(struct ImBuf *ibuf, const char *filepath, int flags);
-/* jpeg */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Format: JPEG (#IMB_FTYPE_JPG)
+ * \{ */
+
bool imb_is_a_jpeg(const unsigned char *mem, const size_t size);
bool imb_savejpeg(struct ImBuf *ibuf, const char *filepath, int flags);
struct ImBuf *imb_load_jpeg(const unsigned char *buffer,
@@ -125,15 +158,26 @@ struct ImBuf *imb_load_jpeg(const unsigned char *buffer,
int flags,
char colorspace[IM_MAX_SPACE]);
-/* bmp */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Format: BMP (#IMB_FTYPE_BMP)
+ * \{ */
+
bool imb_is_a_bmp(const unsigned char *buf, const size_t size);
struct ImBuf *imb_bmp_decode(const unsigned char *mem,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
+/* Found write info at http://users.ece.gatech.edu/~slabaugh/personal/c/bitmapUnix.c */
bool imb_savebmp(struct ImBuf *ibuf, const char *filepath, int flags);
-/* cineon */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Format: CINEON (#IMB_FTYPE_CINEON)
+ * \{ */
+
bool imb_is_a_cineon(const unsigned char *buf, const size_t size);
bool imb_save_cineon(struct ImBuf *buf, const char *filepath, int flags);
struct ImBuf *imb_load_cineon(const unsigned char *mem,
@@ -141,7 +185,12 @@ struct ImBuf *imb_load_cineon(const unsigned char *mem,
int flags,
char colorspace[IM_MAX_SPACE]);
-/* dpx */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Format: DPX (#IMB_FTYPE_DPX)
+ * \{ */
+
bool imb_is_a_dpx(const unsigned char *buf, const size_t size);
bool imb_save_dpx(struct ImBuf *buf, const char *filepath, int flags);
struct ImBuf *imb_load_dpx(const unsigned char *mem,
@@ -149,7 +198,12 @@ struct ImBuf *imb_load_dpx(const unsigned char *mem,
int flags,
char colorspace[IM_MAX_SPACE]);
-/* hdr */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Format: HDR (#IMB_FTYPE_RADHDR)
+ * \{ */
+
bool imb_is_a_hdr(const unsigned char *buf, const size_t size);
struct ImBuf *imb_loadhdr(const unsigned char *mem,
size_t size,
@@ -157,13 +211,44 @@ struct ImBuf *imb_loadhdr(const unsigned char *mem,
char colorspace[IM_MAX_SPACE]);
bool imb_savehdr(struct ImBuf *ibuf, const char *filepath, int flags);
-/* tiff */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Format: TIFF (#IMB_FTYPE_TIF)
+ * \{ */
+
void imb_inittiff(void);
bool imb_is_a_tiff(const unsigned char *buf, const size_t size);
+/**
+ * Loads a TIFF file.
+ * \param mem: Memory containing the TIFF file.
+ * \param size: Size of the mem buffer.
+ * \param flags: If flags has IB_test set then the file is not actually loaded,
+ * but all other operations take place.
+ *
+ * \return A newly allocated #ImBuf structure if successful, otherwise NULL.
+ */
struct ImBuf *imb_loadtiff(const unsigned char *mem,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
void imb_loadtiletiff(
struct ImBuf *ibuf, const unsigned char *mem, size_t size, int tx, int ty, unsigned int *rect);
+/**
+ * Saves a TIFF file.
+ *
+ * #ImBuf structures with 1, 3 or 4 bytes per pixel (GRAY, RGB, RGBA
+ * respectively) are accepted, and interpreted correctly. Note that the TIFF
+ * convention is to use pre-multiplied alpha, which can be achieved within
+ * Blender by setting "Premul" alpha handling. Other alpha conventions are
+ * not strictly correct, but are permitted anyhow.
+ *
+ * \param ibuf: Image buffer.
+ * \param filepath: Name of the TIFF file to create.
+ * \param flags: Currently largely ignored.
+ *
+ * \return 1 if the function is successful, 0 on failure.
+ */
bool imb_savetiff(struct ImBuf *ibuf, const char *filepath, int flags);
+
+/** \} */
diff --git a/source/blender/imbuf/intern/IMB_filter.h b/source/blender/imbuf/intern/IMB_filter.h
index 556362d78c1..434750e6736 100644
--- a/source/blender/imbuf/intern/IMB_filter.h
+++ b/source/blender/imbuf/intern/IMB_filter.h
@@ -34,4 +34,7 @@ void IMB_premultiply_rect_float(float *rect_float, int channels, int w, int h);
void IMB_unpremultiply_rect(unsigned int *rect, char planes, int w, int h);
void IMB_unpremultiply_rect_float(float *rect_float, int channels, int w, int h);
+/**
+ * Result in ibuf2, scaling should be done correctly.
+ */
void imb_onehalf_no_alloc(struct ImBuf *ibuf2, struct ImBuf *ibuf1);
diff --git a/source/blender/imbuf/intern/allocimbuf.c b/source/blender/imbuf/intern/allocimbuf.c
index 1369f8cc0f8..197d7e6b1d5 100644
--- a/source/blender/imbuf/intern/allocimbuf.c
+++ b/source/blender/imbuf/intern/allocimbuf.c
@@ -93,7 +93,6 @@ void imb_freemipmapImBuf(ImBuf *ibuf)
ibuf->miptot = 0;
}
-/* any free rect frees mipmaps to be sure, creation is in render on first request */
void imb_freerectfloatImBuf(ImBuf *ibuf)
{
if (ibuf == NULL) {
@@ -111,7 +110,6 @@ void imb_freerectfloatImBuf(ImBuf *ibuf)
ibuf->mall &= ~IB_rectfloat;
}
-/* any free rect frees mipmaps to be sure, creation is in render on first request */
void imb_freerectImBuf(ImBuf *ibuf)
{
if (ibuf == NULL) {
@@ -197,7 +195,6 @@ void IMB_freezbuffloatImBuf(ImBuf *ibuf)
ibuf->mall &= ~IB_zbuffloat;
}
-/** Free all pixel data (associated with image size). */
void imb_freerectImbuf_all(ImBuf *ibuf)
{
imb_freerectImBuf(ibuf);
@@ -403,9 +400,10 @@ bool imb_addrectfloatImBuf(ImBuf *ibuf)
return false;
}
-/* question; why also add zbuf? */
bool imb_addrectImBuf(ImBuf *ibuf)
{
+ /* Question; why also add ZBUF (when `planes > 32`)? */
+
if (ibuf == NULL) {
return false;
}
@@ -430,9 +428,6 @@ bool imb_addrectImBuf(ImBuf *ibuf)
return false;
}
-/**
- * \param take_ownership: When true, the buffers become owned by the resulting image.
- */
struct ImBuf *IMB_allocFromBufferOwn(
unsigned int *rect, float *rectf, unsigned int w, unsigned int h, unsigned int channels)
{
@@ -580,7 +575,6 @@ bool IMB_initImBuf(
return true;
}
-/* does no zbuffers? */
ImBuf *IMB_dupImBuf(const ImBuf *ibuf1)
{
ImBuf *ibuf2, tbuf;
@@ -669,6 +663,11 @@ ImBuf *IMB_dupImBuf(const ImBuf *ibuf1)
return ibuf2;
}
+size_t IMB_get_rect_len(const ImBuf *ibuf)
+{
+ return (size_t)ibuf->x * (size_t)ibuf->y;
+}
+
size_t IMB_get_size_in_memory(ImBuf *ibuf)
{
int a;
diff --git a/source/blender/imbuf/intern/bmp.c b/source/blender/imbuf/intern/bmp.c
index 5b9d78f5614..b44b12999bf 100644
--- a/source/blender/imbuf/intern/bmp.c
+++ b/source/blender/imbuf/intern/bmp.c
@@ -306,7 +306,6 @@ static int putShortLSB(ushort us, FILE *ofile)
return putc((us >> 8) & 0xFF, ofile);
}
-/* Found write info at http://users.ece.gatech.edu/~slabaugh/personal/c/bitmapUnix.c */
bool imb_savebmp(ImBuf *ibuf, const char *filepath, int UNUSED(flags))
{
BMPINFOHEADER infoheader;
diff --git a/source/blender/imbuf/intern/cache.c b/source/blender/imbuf/intern/cache.c
index 02d1fe3710a..ce11e1c3f80 100644
--- a/source/blender/imbuf/intern/cache.c
+++ b/source/blender/imbuf/intern/cache.c
@@ -153,7 +153,6 @@ static void imb_global_cache_tile_unload(ImGlobalTile *gtile)
GLOBAL_CACHE.totmem -= sizeof(unsigned int) * ibuf->tilex * ibuf->tiley;
}
-/* external free */
void imb_tile_cache_tile_free(ImBuf *ibuf, int tx, int ty)
{
ImGlobalTile *gtile, lookuptile;
@@ -248,7 +247,6 @@ void imb_tile_cache_exit(void)
}
}
-/* presumed to be called when no threads are running */
void IMB_tile_cache_params(int totthread, int maxmem)
{
int a;
diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c
index c8c6f39507f..6e9e5dd3ddb 100644
--- a/source/blender/imbuf/intern/colormanagement.c
+++ b/source/blender/imbuf/intern/colormanagement.c
@@ -1968,7 +1968,6 @@ static void colormanagement_transform_ex(unsigned char *byte_buffer,
IMB_colormanagement_processor_free(cm_processor);
}
-/* convert the whole buffer from specified by name color space to another */
void IMB_colormanagement_transform(float *buffer,
int width,
int height,
@@ -1981,9 +1980,6 @@ void IMB_colormanagement_transform(float *buffer,
NULL, buffer, width, height, channels, from_colorspace, to_colorspace, predivide, false);
}
-/* convert the whole buffer from specified by name color space to another
- * will do threaded conversion
- */
void IMB_colormanagement_transform_threaded(float *buffer,
int width,
int height,
@@ -1996,7 +1992,6 @@ void IMB_colormanagement_transform_threaded(float *buffer,
NULL, buffer, width, height, channels, from_colorspace, to_colorspace, predivide, true);
}
-/* Similar to functions above, but operates on byte buffer. */
void IMB_colormanagement_transform_byte(unsigned char *buffer,
int width,
int height,
@@ -2018,7 +2013,6 @@ void IMB_colormanagement_transform_byte_threaded(unsigned char *buffer,
buffer, NULL, width, height, channels, from_colorspace, to_colorspace, false, true);
}
-/* Similar to above, but gets float buffer from display one. */
void IMB_colormanagement_transform_from_byte(float *float_buffer,
unsigned char *byte_buffer,
int width,
@@ -2098,9 +2092,6 @@ void IMB_colormanagement_transform_v4(float pixel[4],
IMB_colormanagement_processor_free(cm_processor);
}
-/* convert pixel from specified by descriptor color space to scene linear
- * used by performance-critical areas such as renderer and baker
- */
void IMB_colormanagement_colorspace_to_scene_linear_v3(float pixel[3], ColorSpace *colorspace)
{
OCIO_ConstCPUProcessorRcPtr *processor;
@@ -2118,7 +2109,6 @@ void IMB_colormanagement_colorspace_to_scene_linear_v3(float pixel[3], ColorSpac
}
}
-/* same as above, but converts colors in opposite direction */
void IMB_colormanagement_scene_linear_to_colorspace_v3(float pixel[3], ColorSpace *colorspace)
{
OCIO_ConstCPUProcessorRcPtr *processor;
@@ -2315,14 +2305,6 @@ void IMB_colormanagement_imbuf_to_float_texture(float *out_buffer,
}
}
-/* Conversion between color picking role. Typically we would expect such a
- * requirements:
- * - It is approximately perceptually linear, so that the HSV numbers and
- * the HSV cube/circle have an intuitive distribution.
- * - It has the same gamut as the scene linear color space.
- * - Color picking values 0..1 map to scene linear values in the 0..1 range,
- * so that picked albedo values are energy conserving.
- */
void IMB_colormanagement_scene_linear_to_color_picking_v3(float pixel[3])
{
if (!global_color_picking_state.cpu_processor_to && !global_color_picking_state.failed) {
@@ -2377,8 +2359,6 @@ void IMB_colormanagement_color_picking_to_scene_linear_v3(float pixel[3])
}
}
-/* Conversion between sRGB, for rare cases like hex color or copy/pasting
- * between UI theme and scene linear colors. */
void IMB_colormanagement_scene_linear_to_srgb_v3(float pixel[3])
{
mul_m3_v3(imbuf_rgb_to_xyz, pixel);
@@ -2393,10 +2373,6 @@ void IMB_colormanagement_srgb_to_scene_linear_v3(float pixel[3])
mul_m3_v3(imbuf_xyz_to_rgb, pixel);
}
-/* convert pixel from scene linear to display space using default view
- * used by performance-critical areas such as color-related widgets where we want to reduce
- * amount of per-widget allocations
- */
void IMB_colormanagement_scene_linear_to_display_v3(float pixel[3], ColorManagedDisplay *display)
{
OCIO_ConstCPUProcessorRcPtr *processor = display_from_scene_linear_processor(display);
@@ -2406,7 +2382,6 @@ void IMB_colormanagement_scene_linear_to_display_v3(float pixel[3], ColorManaged
}
}
-/* same as above, but converts color in opposite direction */
void IMB_colormanagement_display_to_scene_linear_v3(float pixel[3], ColorManagedDisplay *display)
{
OCIO_ConstCPUProcessorRcPtr *processor = display_to_scene_linear_processor(display);
@@ -2468,17 +2443,6 @@ void IMB_colormanagement_imbuf_make_display_space(
colormanagement_imbuf_make_display_space(ibuf, view_settings, display_settings, false);
}
-/* prepare image buffer to be saved on disk, applying color management if needed
- * color management would be applied if image is saving as render result and if
- * file format is not expecting float buffer to be in linear space (currently
- * JPEG2000 and TIFF are such formats -- they're storing image as float but
- * file itself stores applied color space).
- *
- * Both byte and float buffers would contain applied color space, and result's
- * float_colorspace would be set to display color space. This should be checked
- * in image format write callback and if float_colorspace is not NULL, no color
- * space transformation should be applied on this buffer.
- */
ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf,
bool save_as_render,
bool allocate_result,
@@ -2640,7 +2604,6 @@ void IMB_colormanagement_buffer_make_display_space(
/** \name Public Display Buffers Interfaces
* \{ */
-/* acquire display buffer for given image buffer using specified view and display settings */
unsigned char *IMB_display_buffer_acquire(ImBuf *ibuf,
const ColorManagedViewSettings *view_settings,
const ColorManagedDisplaySettings *display_settings,
@@ -2738,7 +2701,6 @@ unsigned char *IMB_display_buffer_acquire(ImBuf *ibuf,
return display_buffer;
}
-/* same as IMB_display_buffer_acquire but gets view and display settings from context */
unsigned char *IMB_display_buffer_acquire_ctx(const bContext *C, ImBuf *ibuf, void **cache_handle)
{
ColorManagedViewSettings *view_settings;
@@ -2899,7 +2861,6 @@ const char *IMB_colormanagement_display_get_default_name(void)
return display->name;
}
-/* used by performance-critical pixel processing areas, such as color widgets */
ColorManagedDisplay *IMB_colormanagement_display_get_named(const char *name)
{
return colormanage_display_get_named(name);
@@ -4027,19 +3988,6 @@ bool IMB_colormanagement_support_glsl_draw(const ColorManagedViewSettings *UNUSE
return OCIO_supportGPUShader();
}
-/**
- * Configures GLSL shader for conversion from specified to
- * display color space
- *
- * Will create appropriate OCIO processor and setup GLSL shader,
- * so further 2D texture usage will use this conversion.
- *
- * When there's no need to apply transform on 2D textures, use
- * IMB_colormanagement_finish_glsl_draw().
- *
- * This is low-level function, use ED_draw_imbuf_ctx if you
- * only need to display given image buffer
- */
bool IMB_colormanagement_setup_glsl_draw_from_space(
const ColorManagedViewSettings *view_settings,
const ColorManagedDisplaySettings *display_settings,
@@ -4097,7 +4045,6 @@ bool IMB_colormanagement_setup_glsl_draw_from_space(
return global_gpu_state.gpu_shader_bound;
}
-/* Configures GLSL shader for conversion from scene linear to display space */
bool IMB_colormanagement_setup_glsl_draw(const ColorManagedViewSettings *view_settings,
const ColorManagedDisplaySettings *display_settings,
float dither,
@@ -4107,10 +4054,6 @@ bool IMB_colormanagement_setup_glsl_draw(const ColorManagedViewSettings *view_se
view_settings, display_settings, NULL, dither, predivide, false);
}
-/**
- * Same as setup_glsl_draw_from_space,
- * but color management settings are guessing from a given context.
- */
bool IMB_colormanagement_setup_glsl_draw_from_space_ctx(const bContext *C,
struct ColorSpace *from_colorspace,
float dither,
@@ -4125,13 +4068,11 @@ bool IMB_colormanagement_setup_glsl_draw_from_space_ctx(const bContext *C,
view_settings, display_settings, from_colorspace, dither, predivide, false);
}
-/* Same as setup_glsl_draw, but color management settings are guessing from a given context */
bool IMB_colormanagement_setup_glsl_draw_ctx(const bContext *C, float dither, bool predivide)
{
return IMB_colormanagement_setup_glsl_draw_from_space_ctx(C, NULL, dither, predivide);
}
-/* Finish GLSL-based display space conversion */
void IMB_colormanagement_finish_glsl_draw(void)
{
if (global_gpu_state.gpu_shader_bound) {
diff --git a/source/blender/imbuf/intern/colormanagement_inline.c b/source/blender/imbuf/intern/colormanagement_inline.c
index c304ad8d8e5..6e57a8cc1b2 100644
--- a/source/blender/imbuf/intern/colormanagement_inline.c
+++ b/source/blender/imbuf/intern/colormanagement_inline.c
@@ -27,23 +27,11 @@
#include "BLI_math_vector.h"
#include "IMB_colormanagement_intern.h"
-/* Convert a float RGB triplet to the correct luminance weighted average.
- *
- * Grayscale, or Luma is a distillation of RGB data values down to a weighted average
- * based on the luminance positions of the red, green, and blue primaries.
- * Given that the internal reference space may be arbitrarily set, any
- * effort to glean the luminance coefficients must be aware of the reference
- * space primaries.
- *
- * See http://wiki.blender.org/index.php/User:Nazg-gul/ColorManagement#Luminance
- */
-
float IMB_colormanagement_get_luminance(const float rgb[3])
{
return dot_v3v3(imbuf_luma_coefficients, rgb);
}
-/* Byte equivalent of IMB_colormanagement_get_luminance(). */
unsigned char IMB_colormanagement_get_luminance_byte(const unsigned char rgb[3])
{
float rgbf[3];
diff --git a/source/blender/imbuf/intern/dds/BlockDXT.cpp b/source/blender/imbuf/intern/dds/BlockDXT.cpp
index 4e4fca864a0..e471b6834ae 100644
--- a/source/blender/imbuf/intern/dds/BlockDXT.cpp
+++ b/source/blender/imbuf/intern/dds/BlockDXT.cpp
@@ -158,7 +158,6 @@ uint BlockDXT1::evaluatePaletteNV5x(Color32 color_array[4]) const
return 3;
}
-/* Evaluate palette assuming 3 color block. */
void BlockDXT1::evaluatePalette3(Color32 color_array[4]) const
{
color_array[0].b = (col0.b << 3) | (col0.b >> 2);
@@ -184,7 +183,6 @@ void BlockDXT1::evaluatePalette3(Color32 color_array[4]) const
color_array[3].a = 0x00;
}
-/* Evaluate palette assuming 4 color block. */
void BlockDXT1::evaluatePalette4(Color32 color_array[4]) const
{
color_array[0].b = (col0.b << 3) | (col0.b >> 2);
@@ -247,14 +245,12 @@ void BlockDXT1::setIndices(const int *idx)
}
}
-/** Flip DXT1 block vertically. */
inline void BlockDXT1::flip4()
{
swap(row[0], row[3]);
swap(row[1], row[2]);
}
-/** Flip half DXT1 block vertically. */
inline void BlockDXT1::flip2()
{
swap(row[0], row[1]);
@@ -299,27 +295,23 @@ void AlphaBlockDXT3::decodeBlock(ColorBlock *block) const
block->color(0xF).a = (alphaF << 4) | alphaF;
}
-/** Flip DXT3 alpha block vertically. */
void AlphaBlockDXT3::flip4()
{
swap(row[0], row[3]);
swap(row[1], row[2]);
}
-/** Flip half DXT3 alpha block vertically. */
void AlphaBlockDXT3::flip2()
{
swap(row[0], row[1]);
}
-/** Flip DXT3 block vertically. */
void BlockDXT3::flip4()
{
alpha.flip4();
color.flip4();
}
-/** Flip half DXT3 block vertically. */
void BlockDXT3::flip2()
{
alpha.flip2();
@@ -458,21 +450,18 @@ void BlockDXT5::decodeBlockNV5x(ColorBlock *block) const
alpha.decodeBlock(block);
}
-/** Flip DXT5 block vertically. */
void BlockDXT5::flip4()
{
alpha.flip4();
color.flip4();
}
-/** Flip half DXT5 block vertically. */
void BlockDXT5::flip2()
{
alpha.flip2();
color.flip2();
}
-/** Decode ATI1 block. */
void BlockATI1::decodeBlock(ColorBlock *block) const
{
uint8 alpha_array[8];
@@ -488,19 +477,16 @@ void BlockATI1::decodeBlock(ColorBlock *block) const
}
}
-/** Flip ATI1 block vertically. */
void BlockATI1::flip4()
{
alpha.flip4();
}
-/** Flip half ATI1 block vertically. */
void BlockATI1::flip2()
{
alpha.flip2();
}
-/** Decode ATI2 block. */
void BlockATI2::decodeBlock(ColorBlock *block) const
{
uint8 alpha_array[8];
@@ -525,14 +511,12 @@ void BlockATI2::decodeBlock(ColorBlock *block) const
}
}
-/** Flip ATI2 block vertically. */
void BlockATI2::flip4()
{
x.flip4();
y.flip4();
}
-/** Flip half ATI2 block vertically. */
void BlockATI2::flip2()
{
x.flip2();
@@ -586,14 +570,12 @@ void BlockCTX1::setIndices(const int *idx)
}
}
-/** Flip CTX1 block vertically. */
inline void BlockCTX1::flip4()
{
swap(row[0], row[3]);
swap(row[1], row[2]);
}
-/** Flip half CTX1 block vertically. */
inline void BlockCTX1::flip2()
{
swap(row[0], row[1]);
diff --git a/source/blender/imbuf/intern/dds/BlockDXT.h b/source/blender/imbuf/intern/dds/BlockDXT.h
index 1fefa7c739d..eb2d5f8726c 100644
--- a/source/blender/imbuf/intern/dds/BlockDXT.h
+++ b/source/blender/imbuf/intern/dds/BlockDXT.h
@@ -69,7 +69,9 @@ struct BlockDXT1 {
uint evaluatePalette(Color32 color_array[4]) const;
uint evaluatePaletteNV5x(Color32 color_array[4]) const;
+ /** Evaluate palette assuming 3 color block. */
void evaluatePalette3(Color32 color_array[4]) const;
+ /** Evaluate palette assuming 4 color block. */
void evaluatePalette4(Color32 color_array[4]) const;
void decodeBlock(ColorBlock *block) const;
@@ -77,7 +79,9 @@ struct BlockDXT1 {
void setIndices(const int *idx);
+ /** Flip DXT1 block vertically. */
void flip4();
+ /** Flip half DXT1 block vertically. */
void flip2();
};
@@ -113,7 +117,9 @@ struct AlphaBlockDXT3 {
void decodeBlock(ColorBlock *block) const;
+ /** Flip DXT3 alpha block vertically. */
void flip4();
+ /** Flip half DXT3 alpha block vertically. */
void flip2();
};
@@ -125,7 +131,9 @@ struct BlockDXT3 {
void decodeBlock(ColorBlock *block) const;
void decodeBlockNV5x(ColorBlock *block) const;
+ /** Flip DXT3 block vertically. */
void flip4();
+ /** Flip half DXT3 block vertically. */
void flip2();
};
@@ -253,7 +261,9 @@ struct BlockDXT5 {
void decodeBlock(ColorBlock *block) const;
void decodeBlockNV5x(ColorBlock *block) const;
+ /** Flip DXT5 block vertically. */
void flip4();
+ /** Flip half DXT5 block vertically. */
void flip2();
};
@@ -261,9 +271,12 @@ struct BlockDXT5 {
struct BlockATI1 {
AlphaBlockDXT5 alpha;
+ /** Decode ATI1 block. */
void decodeBlock(ColorBlock *block) const;
+ /** Flip ATI1 block vertically. */
void flip4();
+ /** Flip half ATI1 block vertically. */
void flip2();
};
@@ -272,9 +285,12 @@ struct BlockATI2 {
AlphaBlockDXT5 x;
AlphaBlockDXT5 y;
+ /** Decode ATI2 block. */
void decodeBlock(ColorBlock *block) const;
+ /** Flip ATI2 block vertically. */
void flip4();
+ /** Flip half ATI2 block vertically. */
void flip2();
};
@@ -292,7 +308,9 @@ struct BlockCTX1 {
void decodeBlock(ColorBlock *block) const;
+ /** Flip CTX1 block vertically. */
void flip4();
+ /** Flip half CTX1 block vertically. */
void flip2();
};
diff --git a/source/blender/imbuf/intern/dds/ColorBlock.cpp b/source/blender/imbuf/intern/dds/ColorBlock.cpp
index 6974e0bf99d..0ab98c01f6f 100644
--- a/source/blender/imbuf/intern/dds/ColorBlock.cpp
+++ b/source/blender/imbuf/intern/dds/ColorBlock.cpp
@@ -46,7 +46,6 @@ inline static uint colorDistance(Color32 c0, Color32 c1)
}
#endif
-/** Init the color block from an array of colors. */
ColorBlock::ColorBlock(const uint *linearImage)
{
for (uint i = 0; i < 16; i++) {
@@ -54,7 +53,6 @@ ColorBlock::ColorBlock(const uint *linearImage)
}
}
-/** Init the color block with the contents of the given block. */
ColorBlock::ColorBlock(const ColorBlock &block)
{
for (uint i = 0; i < 16; i++) {
@@ -62,7 +60,6 @@ ColorBlock::ColorBlock(const ColorBlock &block)
}
}
-/** Initialize this color block. */
ColorBlock::ColorBlock(const Image *img, uint x, uint y)
{
init(img, x, y);
@@ -153,7 +150,6 @@ void ColorBlock::swizzle(uint x, uint y, uint z, uint w)
}
}
-/** Returns true if the block has a single color. */
bool ColorBlock::isSingleColor(Color32 mask /*= Color32(0xFF, 0xFF, 0xFF, 0x00) */) const
{
uint u = m_color[0].u & mask.u;
@@ -234,7 +230,6 @@ Color32 ColorBlock::averageColor() const
}
#endif
-/** Return true if the block is not fully opaque. */
bool ColorBlock::hasAlpha() const
{
for (const auto &i : m_color) {
diff --git a/source/blender/imbuf/intern/dds/ColorBlock.h b/source/blender/imbuf/intern/dds/ColorBlock.h
index 934837bb129..1dee5c76c9e 100644
--- a/source/blender/imbuf/intern/dds/ColorBlock.h
+++ b/source/blender/imbuf/intern/dds/ColorBlock.h
@@ -35,8 +35,11 @@
/** Uncompressed 4x4 color block. */
struct ColorBlock {
ColorBlock() = default;
+ /** Init the color block from an array of colors. */
ColorBlock(const uint *linearImage);
+ /** Init the color block with the contents of the given block. */
ColorBlock(const ColorBlock &block);
+ /** Initialize this color block. */
ColorBlock(const Image *img, uint x, uint y);
void init(const Image *img, uint x, uint y);
@@ -45,7 +48,9 @@ struct ColorBlock {
void swizzle(uint x, uint y, uint z, uint w); /* 0=r, 1=g, 2=b, 3=a, 4=0xFF, 5=0 */
+ /** Returns true if the block has a single color. */
bool isSingleColor(Color32 mask = Color32(0xFF, 0xFF, 0xFF, 0x00)) const;
+ /** Return true if the block is not fully opaque. */
bool hasAlpha() const;
/* Accessors */
diff --git a/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp b/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp
index b665996b18f..efa438c2af5 100644
--- a/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp
+++ b/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp
@@ -1107,8 +1107,6 @@ void DirectDrawSurface::mipmap(Image *img, uint face, uint mipmap)
}
}
-/* It was easier to copy this function from upstream than to resync.
- * This should be removed if a resync ever occurs. */
void *DirectDrawSurface::readData(uint &rsize)
{
uint header_size = 128; // sizeof(DDSHeader);
diff --git a/source/blender/imbuf/intern/dds/DirectDrawSurface.h b/source/blender/imbuf/intern/dds/DirectDrawSurface.h
index 381fa51f75c..343a7367f91 100644
--- a/source/blender/imbuf/intern/dds/DirectDrawSurface.h
+++ b/source/blender/imbuf/intern/dds/DirectDrawSurface.h
@@ -157,6 +157,10 @@ class DirectDrawSurface {
void setUserVersion(int version);
void mipmap(Image *img, uint f, uint m);
+ /**
+ * It was easier to copy this function from upstream than to resync.
+ * This should be removed if a resync ever occurs.
+ */
void *readData(uint &size);
// void mipmap(FloatImage *img, uint f, uint m);
@@ -174,7 +178,8 @@ class DirectDrawSurface {
void readBlock(ColorBlock *rgba);
private:
- Stream stream; /* Memory where DDS file resides. */
+ /** Memory where DDS file resides. */
+ Stream stream;
DDSHeader header;
};
diff --git a/source/blender/imbuf/intern/dds/FlipDXT.cpp b/source/blender/imbuf/intern/dds/FlipDXT.cpp
index 2acf072556a..359d6f30cdc 100644
--- a/source/blender/imbuf/intern/dds/FlipDXT.cpp
+++ b/source/blender/imbuf/intern/dds/FlipDXT.cpp
@@ -168,7 +168,6 @@ static void FlipDXT5BlockHalf(uint8_t *block)
FlipDXT1BlockHalf(block + 8);
}
-/* Flips a DXTC image, by flipping and swapping DXTC blocks as appropriate. */
int FlipDXTCImage(
unsigned int width, unsigned int height, unsigned int levels, int fourcc, uint8_t *data)
{
diff --git a/source/blender/imbuf/intern/dds/FlipDXT.h b/source/blender/imbuf/intern/dds/FlipDXT.h
index d35157251bd..b4f71e4eca7 100644
--- a/source/blender/imbuf/intern/dds/FlipDXT.h
+++ b/source/blender/imbuf/intern/dds/FlipDXT.h
@@ -18,6 +18,10 @@
#include "BLI_sys_types.h"
-/* flip compressed DXT image vertically to fit OpenGL convention */
+/**
+ * Flips a DXTC image, by flipping and swapping DXTC blocks as appropriate.
+ *
+ * Use to flip vertically to fit OpenGL convention.
+ */
int FlipDXTCImage(
unsigned int width, unsigned int height, unsigned int levels, int fourcc, uint8_t *data);
diff --git a/source/blender/imbuf/intern/divers.c b/source/blender/imbuf/intern/divers.c
index e6f42da1597..4841f7b5039 100644
--- a/source/blender/imbuf/intern/divers.c
+++ b/source/blender/imbuf/intern/divers.c
@@ -102,13 +102,11 @@ MINLINE void float_to_byte_dither_v4(
b[3] = unit_float_to_uchar_clamp(f[3]);
}
-/* Test if colorspace conversions of pixels in buffer need to take into account alpha. */
bool IMB_alpha_affects_rgb(const ImBuf *ibuf)
{
return (ibuf->flags & IB_alphamode_channel_packed) == 0;
}
-/* float to byte pixels, output 4-channel RGBA */
void IMB_buffer_byte_from_float(uchar *rect_to,
const float *rect_from,
int channels_from,
@@ -275,7 +273,6 @@ void IMB_buffer_byte_from_float(uchar *rect_to,
}
}
-/* float to byte pixels, output 4-channel RGBA */
void IMB_buffer_byte_from_float_mask(uchar *rect_to,
const float *rect_from,
int channels_from,
@@ -366,7 +363,6 @@ void IMB_buffer_byte_from_float_mask(uchar *rect_to,
}
}
-/* Byte to float pixels, input and output 4-channel RGBA. */
void IMB_buffer_float_from_byte(float *rect_to,
const uchar *rect_from,
int profile_to,
@@ -386,7 +382,7 @@ void IMB_buffer_float_from_byte(float *rect_to,
/* RGBA input */
for (y = 0; y < height; y++) {
- const uchar *from = rect_from + stride_from * y * 4;
+ const uchar *from = rect_from + ((size_t)stride_from) * y * 4;
float *to = rect_to + ((size_t)stride_to) * y * 4;
if (profile_to == profile_from) {
@@ -426,7 +422,6 @@ void IMB_buffer_float_from_byte(float *rect_to,
}
}
-/* float to float pixels, output 4-channel RGBA */
void IMB_buffer_float_from_float(float *rect_to,
const float *rect_from,
int channels_from,
@@ -592,7 +587,6 @@ void IMB_buffer_float_from_float_threaded(float *rect_to,
}
}
-/* float to float pixels, output 4-channel RGBA */
void IMB_buffer_float_from_float_mask(float *rect_to,
const float *rect_from,
int channels_from,
@@ -646,7 +640,6 @@ void IMB_buffer_float_from_float_mask(float *rect_to,
}
}
-/* byte to byte pixels, input and output 4-channel RGBA */
void IMB_buffer_byte_from_byte(uchar *rect_to,
const uchar *rect_from,
int profile_to,
@@ -791,17 +784,14 @@ void IMB_float_from_rect(ImBuf *ibuf)
*/
rect_float = ibuf->rect_float;
if (rect_float == NULL) {
- size_t size;
-
- size = ((size_t)ibuf->x) * ibuf->y;
- size = sizeof(float[4]) * size;
- ibuf->channels = 4;
-
+ const size_t size = IMB_get_rect_len(ibuf) * sizeof(float[4]);
rect_float = MEM_callocN(size, "IMB_float_from_rect");
if (rect_float == NULL) {
return;
}
+
+ ibuf->channels = 4;
}
/* first, create float buffer in non-linear space */
@@ -837,7 +827,6 @@ void IMB_float_from_rect(ImBuf *ibuf)
/** \name Color to Grayscale
* \{ */
-/* no profile conversion */
void IMB_color_to_bw(ImBuf *ibuf)
{
float *rct_fl = ibuf->rect_float;
@@ -845,13 +834,13 @@ void IMB_color_to_bw(ImBuf *ibuf)
size_t i;
if (rct_fl) {
- for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, rct_fl += 4) {
+ for (i = IMB_get_rect_len(ibuf); i > 0; i--, rct_fl += 4) {
rct_fl[0] = rct_fl[1] = rct_fl[2] = IMB_colormanagement_get_luminance(rct_fl);
}
}
if (rct) {
- for (i = ((size_t)ibuf->x * ibuf->y); i > 0; i--, rct += 4) {
+ for (i = IMB_get_rect_len(ibuf); i > 0; i--, rct += 4) {
rct[0] = rct[1] = rct[2] = IMB_colormanagement_get_luminance_byte(rct);
}
}
@@ -892,7 +881,7 @@ void IMB_saturation(ImBuf *ibuf, float sat)
if (rct) {
float rgb[3];
- for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, rct += 4) {
+ for (i = IMB_get_rect_len(ibuf); i > 0; i--, rct += 4) {
rgb_uchar_to_float(rgb, rct);
rgb_to_hsv_v(rgb, hsv);
hsv_to_rgb(hsv[0], hsv[1] * sat, hsv[2], rgb, rgb + 1, rgb + 2);
@@ -901,7 +890,7 @@ void IMB_saturation(ImBuf *ibuf, float sat)
}
if (rct_fl) {
- for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, rct_fl += 4) {
+ for (i = IMB_get_rect_len(ibuf); i > 0; i--, rct_fl += 4) {
rgb_to_hsv_v(rct_fl, hsv);
hsv_to_rgb(hsv[0], hsv[1] * sat, hsv[2], rct_fl, rct_fl + 1, rct_fl + 2);
}
diff --git a/source/blender/imbuf/intern/filter.c b/source/blender/imbuf/intern/filter.c
index 343c8cd8f64..324bc9806c1 100644
--- a/source/blender/imbuf/intern/filter.c
+++ b/source/blender/imbuf/intern/filter.c
@@ -420,12 +420,6 @@ static int check_pixel_assigned(
return res;
}
-/**
- * if alpha is zero, it checks surrounding pixels and averages color. sets new alphas to 1.0
- *
- * When a mask is given, only effect pixels with a mask value of 1,
- * defined as #BAKE_MASK_MARGIN in rendercore.c
- */
void IMB_filter_extend(struct ImBuf *ibuf, char *mask, int filter)
{
const int width = ibuf->x;
@@ -557,7 +551,6 @@ void IMB_filter_extend(struct ImBuf *ibuf, char *mask, int filter)
}
}
-/* threadsafe version, only recreates existing maps */
void IMB_remakemipmap(ImBuf *ibuf, int use_filter)
{
ImBuf *hbuf = ibuf;
@@ -594,7 +587,6 @@ void IMB_remakemipmap(ImBuf *ibuf, int use_filter)
}
}
-/* frees too (if there) and recreates new data */
void IMB_makemipmap(ImBuf *ibuf, int use_filter)
{
ImBuf *hbuf = ibuf;
diff --git a/source/blender/imbuf/intern/imageprocess.c b/source/blender/imbuf/intern/imageprocess.c
index 0ec1e4c19d8..23c4c53d602 100644
--- a/source/blender/imbuf/intern/imageprocess.c
+++ b/source/blender/imbuf/intern/imageprocess.c
@@ -40,7 +40,6 @@
#include "IMB_imbuf_types.h"
#include <math.h>
-/* Only this one is used liberally here, and in imbuf */
void IMB_convert_rgba_to_abgr(struct ImBuf *ibuf)
{
size_t size;
@@ -76,7 +75,8 @@ void IMB_convert_rgba_to_abgr(struct ImBuf *ibuf)
}
}
-static void pixel_from_buffer(struct ImBuf *ibuf, unsigned char **outI, float **outF, int x, int y)
+static void pixel_from_buffer(
+ const struct ImBuf *ibuf, unsigned char **outI, float **outF, int x, int y)
{
size_t offset = ((size_t)ibuf->x) * y * 4 + 4 * x;
@@ -95,7 +95,7 @@ static void pixel_from_buffer(struct ImBuf *ibuf, unsigned char **outI, float **
* \{ */
void bicubic_interpolation_color(
- struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
{
if (outF) {
BLI_bicubic_interpolation_fl(in->rect_float, outF, in->x, in->y, 4, u, v);
@@ -105,7 +105,7 @@ void bicubic_interpolation_color(
}
}
-void bicubic_interpolation(ImBuf *in, ImBuf *out, float u, float v, int xout, int yout)
+void bicubic_interpolation(const ImBuf *in, ImBuf *out, float u, float v, int xout, int yout)
{
unsigned char *outI = NULL;
float *outF = NULL;
@@ -126,16 +126,16 @@ void bicubic_interpolation(ImBuf *in, ImBuf *out, float u, float v, int xout, in
/** \name Bi-Linear Interpolation
* \{ */
-BLI_INLINE void bilinear_interpolation_color_fl(
- struct ImBuf *in, unsigned char UNUSED(outI[4]), float outF[4], float u, float v)
+void bilinear_interpolation_color_fl(
+ const struct ImBuf *in, unsigned char UNUSED(outI[4]), float outF[4], float u, float v)
{
BLI_assert(outF);
BLI_assert(in->rect_float);
BLI_bilinear_interpolation_fl(in->rect_float, outF, in->x, in->y, 4, u, v);
}
-BLI_INLINE void bilinear_interpolation_color_char(
- struct ImBuf *in, unsigned char outI[4], float UNUSED(outF[4]), float u, float v)
+void bilinear_interpolation_color_char(
+ const struct ImBuf *in, unsigned char outI[4], float UNUSED(outF[4]), float u, float v)
{
BLI_assert(outI);
BLI_assert(in->rect);
@@ -143,7 +143,7 @@ BLI_INLINE void bilinear_interpolation_color_char(
}
void bilinear_interpolation_color(
- struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
{
if (outF) {
BLI_bilinear_interpolation_fl(in->rect_float, outF, in->x, in->y, 4, u, v);
@@ -156,12 +156,8 @@ void bilinear_interpolation_color(
/* function assumes out to be zero'ed, only does RGBA */
/* BILINEAR INTERPOLATION */
-/* Note about wrapping, the u/v still needs to be within the image bounds,
- * just the interpolation is wrapped.
- * This the same as bilinear_interpolation_color except it wraps
- * rather than using empty and emptyI. */
void bilinear_interpolation_color_wrap(
- struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
{
float *row1, *row2, *row3, *row4, a, b;
unsigned char *row1I, *row2I, *row3I, *row4I;
@@ -232,7 +228,7 @@ void bilinear_interpolation_color_wrap(
}
}
-void bilinear_interpolation(ImBuf *in, ImBuf *out, float u, float v, int xout, int yout)
+void bilinear_interpolation(const ImBuf *in, ImBuf *out, float u, float v, int xout, int yout)
{
unsigned char *outI = NULL;
float *outF = NULL;
@@ -253,9 +249,8 @@ void bilinear_interpolation(ImBuf *in, ImBuf *out, float u, float v, int xout, i
/** \name Nearest Interpolation
* \{ */
-/* functions assumes out to be zero'ed, only does RGBA */
-BLI_INLINE void nearest_interpolation_color_char(
- struct ImBuf *in, unsigned char outI[4], float UNUSED(outF[4]), float u, float v)
+void nearest_interpolation_color_char(
+ const struct ImBuf *in, unsigned char outI[4], float UNUSED(outF[4]), float u, float v)
{
BLI_assert(outI);
BLI_assert(in->rect);
@@ -269,7 +264,7 @@ BLI_INLINE void nearest_interpolation_color_char(
return;
}
- const size_t offset = (in->x * y1 + x1) * 4;
+ const size_t offset = ((size_t)in->x * y1 + x1) * 4;
const unsigned char *dataI = (unsigned char *)in->rect + offset;
outI[0] = dataI[0];
outI[1] = dataI[1];
@@ -277,8 +272,8 @@ BLI_INLINE void nearest_interpolation_color_char(
outI[3] = dataI[3];
}
-BLI_INLINE void nearest_interpolation_color_fl(
- struct ImBuf *in, unsigned char UNUSED(outI[4]), float outF[4], float u, float v)
+void nearest_interpolation_color_fl(
+ const struct ImBuf *in, unsigned char UNUSED(outI[4]), float outF[4], float u, float v)
{
BLI_assert(outF);
BLI_assert(in->rect_float);
@@ -292,13 +287,13 @@ BLI_INLINE void nearest_interpolation_color_fl(
return;
}
- const size_t offset = (in->x * y1 + x1) * 4;
+ const size_t offset = ((size_t)in->x * y1 + x1) * 4;
const float *dataF = in->rect_float + offset;
copy_v4_v4(outF, dataF);
}
void nearest_interpolation_color(
- struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
{
if (outF) {
nearest_interpolation_color_fl(in, outI, outF, u, v);
@@ -309,7 +304,7 @@ void nearest_interpolation_color(
}
void nearest_interpolation_color_wrap(
- struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
{
const float *dataF;
unsigned char *dataI;
@@ -347,7 +342,7 @@ void nearest_interpolation_color_wrap(
}
}
-void nearest_interpolation(ImBuf *in, ImBuf *out, float u, float v, int xout, int yout)
+void nearest_interpolation(const ImBuf *in, ImBuf *out, float u, float v, int xout, int yout)
{
unsigned char *outI = NULL;
float *outF = NULL;
@@ -362,146 +357,6 @@ void nearest_interpolation(ImBuf *in, ImBuf *out, float u, float v, int xout, in
nearest_interpolation_color(in, outI, outF, u, v);
}
-/* -------------------------------------------------------------------- */
-/** \name Image transform
- * \{ */
-typedef struct TransformUserData {
- ImBuf *src;
- ImBuf *dst;
- float start_uv[2];
- float add_x[2];
- float add_y[2];
- rctf src_crop;
-} TransformUserData;
-
-static void imb_transform_calc_start_uv(const float transform_matrix[4][4], float r_start_uv[2])
-{
- float r_start_uv_temp[3];
- float orig[3];
- zero_v3(orig);
- mul_v3_m4v3(r_start_uv_temp, transform_matrix, orig);
- copy_v2_v2(r_start_uv, r_start_uv_temp);
-}
-
-static void imb_transform_calc_add_x(const float transform_matrix[4][4],
- const float start_uv[2],
- const int width,
- float r_add_x[2])
-{
- float r_add_x_temp[3];
- float uv_max_x[3];
- zero_v3(uv_max_x);
- uv_max_x[0] = width;
- uv_max_x[1] = 0.0f;
- mul_v3_m4v3(r_add_x_temp, transform_matrix, uv_max_x);
- sub_v2_v2(r_add_x_temp, start_uv);
- mul_v2_fl(r_add_x_temp, 1.0f / width);
- copy_v2_v2(r_add_x, r_add_x_temp);
-}
-
-static void imb_transform_calc_add_y(const float transform_matrix[4][4],
- const float start_uv[2],
- const int height,
- float r_add_y[2])
-{
- float r_add_y_temp[3];
- float uv_max_y[3];
- zero_v3(uv_max_y);
- uv_max_y[0] = 0.0f;
- uv_max_y[1] = height;
- mul_v3_m4v3(r_add_y_temp, transform_matrix, uv_max_y);
- sub_v2_v2(r_add_y_temp, start_uv);
- mul_v2_fl(r_add_y_temp, 1.0f / height);
- copy_v2_v2(r_add_y, r_add_y_temp);
-}
-
-typedef void (*InterpolationColorFunction)(
- struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
-BLI_INLINE void imb_transform_scanlines(const TransformUserData *user_data,
- int scanline,
- InterpolationColorFunction interpolation)
-{
- const int width = user_data->dst->x;
-
- float uv[2];
- madd_v2_v2v2fl(uv, user_data->start_uv, user_data->add_y, scanline);
-
- unsigned char *outI = NULL;
- float *outF = NULL;
- pixel_from_buffer(user_data->dst, &outI, &outF, 0, scanline);
-
- for (int xi = 0; xi < width; xi++) {
- if (uv[0] >= user_data->src_crop.xmin && uv[0] < user_data->src_crop.xmax &&
- uv[1] >= user_data->src_crop.ymin && uv[1] < user_data->src_crop.ymax) {
- interpolation(user_data->src, outI, outF, uv[0], uv[1]);
- }
- add_v2_v2(uv, user_data->add_x);
- if (outI) {
- outI += 4;
- }
- if (outF) {
- outF += 4;
- }
- }
-}
-
-static void imb_transform_nearest_scanlines(void *custom_data, int scanline)
-{
- const TransformUserData *user_data = custom_data;
- InterpolationColorFunction interpolation = NULL;
- if (user_data->dst->rect_float) {
- interpolation = nearest_interpolation_color_fl;
- }
- else {
- interpolation = nearest_interpolation_color_char;
- }
- imb_transform_scanlines(user_data, scanline, interpolation);
-}
-
-static void imb_transform_bilinear_scanlines(void *custom_data, int scanline)
-{
- const TransformUserData *user_data = custom_data;
- InterpolationColorFunction interpolation = NULL;
- if (user_data->dst->rect_float) {
- interpolation = bilinear_interpolation_color_fl;
- }
- else if (user_data->dst->rect) {
- interpolation = bilinear_interpolation_color_char;
- }
- imb_transform_scanlines(user_data, scanline, interpolation);
-}
-
-static ScanlineThreadFunc imb_transform_scanline_func(const eIMBInterpolationFilterMode filter)
-{
- ScanlineThreadFunc scanline_func = NULL;
- switch (filter) {
- case IMB_FILTER_NEAREST:
- scanline_func = imb_transform_nearest_scanlines;
- break;
- case IMB_FILTER_BILINEAR:
- scanline_func = imb_transform_bilinear_scanlines;
- break;
- }
- return scanline_func;
-}
-
-void IMB_transform(struct ImBuf *src,
- struct ImBuf *dst,
- float transform_matrix[4][4],
- struct rctf *src_crop,
- const eIMBInterpolationFilterMode filter)
-{
- TransformUserData user_data;
- user_data.src = src;
- user_data.dst = dst;
- user_data.src_crop = *src_crop;
- imb_transform_calc_start_uv(transform_matrix, user_data.start_uv);
- imb_transform_calc_add_x(transform_matrix, user_data.start_uv, src->x, user_data.add_x);
- imb_transform_calc_add_y(transform_matrix, user_data.start_uv, src->y, user_data.add_y);
- ScanlineThreadFunc scanline_func = imb_transform_scanline_func(filter);
- IMB_processor_apply_threaded_scanlines(dst->y, scanline_func, &user_data);
-}
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -643,7 +498,6 @@ void IMB_alpha_under_color_byte(unsigned char *rect, int x, int y, const float b
/** \name Sample Pixel
* \{ */
-/* Sample pixel of image using NEAREST method. */
void IMB_sampleImageAtLocation(ImBuf *ibuf, float x, float y, bool make_linear_rgb, float color[4])
{
if (ibuf->rect_float) {
diff --git a/source/blender/imbuf/intern/iris.c b/source/blender/imbuf/intern/iris.c
index 6a7ad87d53d..dc714e6e85a 100644
--- a/source/blender/imbuf/intern/iris.c
+++ b/source/blender/imbuf/intern/iris.c
@@ -251,12 +251,6 @@ bool imb_is_a_iris(const uchar *mem, size_t size)
return ((GS(mem) == IMAGIC) || (GSS(mem) == IMAGIC));
}
-/*
- * longimagedata -
- * read in a B/W RGB or RGBA iris image file and return a
- * pointer to an array of ints.
- */
-
struct ImBuf *imb_loadiris(const uchar *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
{
uint *base, *lptr = NULL;
diff --git a/source/blender/imbuf/intern/moviecache.c b/source/blender/imbuf/intern/moviecache.c
index 8923ba98e08..f290ab1a060 100644
--- a/source/blender/imbuf/intern/moviecache.c
+++ b/source/blender/imbuf/intern/moviecache.c
@@ -268,6 +268,7 @@ void IMB_moviecache_destruct(void)
{
if (limitor) {
delete_MEM_CacheLimiter(limitor);
+ limitor = NULL;
}
}
@@ -495,7 +496,6 @@ void IMB_moviecache_cleanup(MovieCache *cache,
}
}
-/* get segments of cached frames. useful for debugging cache policies */
void IMB_moviecache_get_cache_segments(
MovieCache *cache, int proxy, int render_flags, int *r_totseg, int **r_points)
{
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp
index adf09f8dda8..e1b9853ac21 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp
@@ -327,10 +327,6 @@ static half float_to_half_safe(const float value)
extern "C" {
-/**
- * Test presence of OpenEXR file.
- * \param mem: pointer to loaded OpenEXR bitstream
- */
bool imb_is_a_openexr(const unsigned char *mem, const size_t size)
{
/* No define is exposed for this size. */
@@ -781,9 +777,6 @@ static void imb_exr_insert_view_name(char *name_full, const char *passname, cons
}
}
-/* adds flattened ExrChannels */
-/* xstride, ystride and rect can be done in set_channel too, for tile writing */
-/* passname does not include view */
void IMB_exr_add_channel(void *handle,
const char *layname,
const char *passname,
@@ -840,7 +833,6 @@ void IMB_exr_add_channel(void *handle,
BLI_addtail(&data->channels, echan);
}
-/* used for output files (from RenderResult) (single and multilayer, single and multiview) */
bool IMB_exr_begin_write(void *handle,
const char *filename,
int width,
@@ -896,8 +888,6 @@ bool IMB_exr_begin_write(void *handle,
return (data->ofile != nullptr);
}
-/* only used for writing temp. render results (not image files)
- * (FSA and Save Buffers) */
void IMB_exrtile_begin_write(
void *handle, const char *filename, int mipmap, int width, int height, int tilex, int tiley)
{
@@ -963,7 +953,6 @@ void IMB_exrtile_begin_write(
}
}
-/* read from file */
bool IMB_exr_begin_read(
void *handle, const char *filename, int *width, int *height, const bool parse_channels)
{
@@ -1024,8 +1013,6 @@ bool IMB_exr_begin_read(
return true;
}
-/* still clumsy name handling, layers/channels can be ordered as list in list later */
-/* passname here is the raw channel name without the layer */
void IMB_exr_set_channel(
void *handle, const char *layname, const char *passname, int xstride, int ystride, float *rect)
{
@@ -1167,8 +1154,6 @@ void IMB_exr_write_channels(void *handle)
}
}
-/* temporary function, used for FSA and Save Buffers */
-/* called once per tile * view */
void IMB_exrtile_write_channels(
void *handle, int partx, int party, int level, const char *viewname, bool empty)
{
@@ -1937,8 +1922,8 @@ struct ImBuf *imb_load_openexr(const unsigned char *mem,
file = new MultiPartInputFile(*membuf);
Box2i dw = file->header(0).dataWindow();
- const int width = dw.max.x - dw.min.x + 1;
- const int height = dw.max.y - dw.min.y + 1;
+ const size_t width = dw.max.x - dw.min.x + 1;
+ const size_t height = dw.max.y - dw.min.y + 1;
// printf("OpenEXR-load: image data window %d %d %d %d\n",
// dw.min.x, dw.min.y, dw.max.x, dw.max.y);
@@ -2001,8 +1986,8 @@ struct ImBuf *imb_load_openexr(const unsigned char *mem,
const bool has_luma = exr_has_luma(*file);
FrameBuffer frameBuffer;
float *first;
- int xstride = sizeof(float[4]);
- int ystride = -xstride * width;
+ size_t xstride = sizeof(float[4]);
+ size_t ystride = -xstride * width;
imb_addrectfloatImBuf(ibuf);
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.h b/source/blender/imbuf/intern/openexr/openexr_api.h
index 940715690a7..14336620926 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.h
+++ b/source/blender/imbuf/intern/openexr/openexr_api.h
@@ -32,6 +32,10 @@ extern "C" {
void imb_initopenexr(void);
void imb_exitopenexr(void);
+/**
+ * Test presence of OpenEXR file.
+ * \param mem: pointer to loaded OpenEXR bit-stream.
+ */
bool imb_is_a_openexr(const unsigned char *mem, const size_t size);
bool imb_save_openexr(struct ImBuf *ibuf, const char *name, int flags);
diff --git a/source/blender/imbuf/intern/openexr/openexr_multi.h b/source/blender/imbuf/intern/openexr/openexr_multi.h
index 82a5d161ded..6694c32820b 100644
--- a/source/blender/imbuf/intern/openexr/openexr_multi.h
+++ b/source/blender/imbuf/intern/openexr/openexr_multi.h
@@ -23,7 +23,7 @@
#pragma once
-/* experiment with more advanced exr api */
+/* Experiment with more advanced EXR API. */
/* XXX layer+pass name max 64? */
/* This api also supports max 8 channels per pass now. easy to fix! */
@@ -41,6 +41,12 @@ struct StampData;
void *IMB_exr_get_handle(void);
void *IMB_exr_get_handle_name(const char *name);
+
+/**
+ * Adds flattened #ExrChannel's
+ * `xstride`, `ystride` and `rect` can be done in set_channel too, for tile writing.
+ * \param passname: Does not include view.
+ */
void IMB_exr_add_channel(void *handle,
const char *layname,
const char *passname,
@@ -50,17 +56,32 @@ void IMB_exr_add_channel(void *handle,
float *rect,
bool use_half_float);
+/**
+ * Read from file.
+ */
bool IMB_exr_begin_read(
void *handle, const char *filename, int *width, int *height, const bool parse_channels);
+/**
+ * Used for output files (from #RenderResult) (single and multi-layer, single and multi-view).
+ */
bool IMB_exr_begin_write(void *handle,
const char *filename,
int width,
int height,
int compress,
const struct StampData *stamp);
+/**
+ * Only used for writing temp. render results (not image files)
+ * (FSA and Save Buffers).
+ */
void IMB_exrtile_begin_write(
void *handle, const char *filename, int mipmap, int width, int height, int tilex, int tiley);
+/**
+ * Still clumsy name handling, layers/channels can be ordered as list in list later.
+ *
+ * \param passname: Here is the raw channel name without the layer.
+ */
void IMB_exr_set_channel(void *handle,
const char *layname,
const char *passname,
@@ -74,6 +95,10 @@ float *IMB_exr_channel_rect(void *handle,
void IMB_exr_read_channels(void *handle);
void IMB_exr_write_channels(void *handle);
+/**
+ * Temporary function, used for FSA and Save Buffers.
+ * called once per `tile * view`.
+ */
void IMB_exrtile_write_channels(
void *handle, int partx, int party, int level, const char *viewname, bool empty);
void IMB_exr_clear_channels(void *handle);
diff --git a/source/blender/imbuf/intern/rectop.c b/source/blender/imbuf/intern/rectop.c
index 4b5d68b9c13..1d81ee768e9 100644
--- a/source/blender/imbuf/intern/rectop.c
+++ b/source/blender/imbuf/intern/rectop.c
@@ -251,9 +251,6 @@ static void rect_crop_16bytes(void **buf_p, const int size_src[2], const rcti *c
*buf_p = (void *)MEM_reallocN(*buf_p, sizeof(uint[4]) * size_dst[0] * size_dst[1]);
}
-/**
- * In-place image crop.
- */
void IMB_rect_crop(ImBuf *ibuf, const rcti *crop)
{
const int size_src[2] = {
@@ -302,9 +299,6 @@ static void rect_realloc_16bytes(void **buf_p, const uint size[2])
*buf_p = MEM_mallocN(sizeof(uint[4]) * size[0] * size[1], __func__);
}
-/**
- * In-place size setting (caller must fill in buffer contents).
- */
void IMB_rect_size_set(ImBuf *ibuf, const uint size[2])
{
BLI_assert(size[0] > 0 && size[1] > 0);
@@ -1070,11 +1064,6 @@ void IMB_rectblend_threaded(ImBuf *dbuf,
}
}
-/**
- * Replace pixels of entire image with solid color.
- * \param ibuf: An image to be filled with color. It must be 4 channel image.
- * \param col: RGBA color, which is assigned directly to both byte (via scaling) and float buffers.
- */
void IMB_rectfill(ImBuf *drect, const float col[4])
{
int num;
@@ -1107,15 +1096,6 @@ void IMB_rectfill(ImBuf *drect, const float col[4])
}
}
-/**
- * Replace pixels of image area with solid color.
- * \param ibuf: an image to be filled with color. It must be 4 channel image.
- * \param col: RGBA color, which is assigned directly to both byte (via scaling) and float buffers.
- * \param x1, y1, x2, y2: (x1, y1) defines starting point of the rectangular area to be filled,
- * (x2, y2) is the end point. Note that values are allowed to be loosely ordered, which means that
- * x2 is allowed to be lower than x1, as well as y2 is allowed to be lower than y1. No matter the
- * order the area between x1 and x2, and y1 and y2 is filled.
- */
void IMB_rectfill_area_replace(
const ImBuf *ibuf, const float col[4], int x1, int y1, int x2, int y2)
{
@@ -1273,21 +1253,6 @@ void buf_rectfill_area(unsigned char *rect,
}
}
-/**
- * Blend pixels of image area with solid color.
- *
- * For images with `uchar` buffer use color matching image color-space.
- * For images with float buffer use color display color-space.
- * If display color-space can not be referenced, use color in SRGB color-space.
- *
- * \param ibuf: an image to be filled with color. It must be 4 channel image.
- * \param col: RGBA color.
- * \param x1, y1, x2, y2: (x1, y1) defines starting point of the rectangular area to be filled,
- * (x2, y2) is the end point. Note that values are allowed to be loosely ordered, which means that
- * x2 is allowed to be lower than x1, as well as y2 is allowed to be lower than y1. No matter the
- * order the area between x1 and x2, and y1 and y2 is filled.
- * \param display: color-space reference for display space.
- */
void IMB_rectfill_area(ImBuf *ibuf,
const float col[4],
int x1,
diff --git a/source/blender/imbuf/intern/scaling.c b/source/blender/imbuf/intern/scaling.c
index 1c4b7af6ef1..a18ba6748de 100644
--- a/source/blender/imbuf/intern/scaling.c
+++ b/source/blender/imbuf/intern/scaling.c
@@ -372,7 +372,6 @@ MINLINE void premul_ushort_to_straight_uchar(unsigned char *result, const unsign
}
}
-/* result in ibuf2, scaling should be done correctly */
void imb_onehalf_no_alloc(struct ImBuf *ibuf2, struct ImBuf *ibuf1)
{
int x, y;
@@ -912,7 +911,7 @@ static ImBuf *scaledownx(struct ImBuf *ibuf, int newx)
{
const int do_rect = (ibuf->rect != NULL);
const int do_float = (ibuf->rect_float != NULL);
- const size_t rect_size = ibuf->x * ibuf->y * 4;
+ const size_t rect_size = IMB_get_rect_len(ibuf) * 4;
uchar *rect, *_newrect, *newrect;
float *rectf, *_newrectf, *newrectf;
@@ -1053,7 +1052,7 @@ static ImBuf *scaledowny(struct ImBuf *ibuf, int newy)
{
const int do_rect = (ibuf->rect != NULL);
const int do_float = (ibuf->rect_float != NULL);
- const size_t rect_size = ibuf->x * ibuf->y * 4;
+ const size_t rect_size = IMB_get_rect_len(ibuf) * 4;
uchar *rect, *_newrect, *newrect;
float *rectf, *_newrectf, *newrectf;
@@ -1661,9 +1660,6 @@ static void scalefast_Z_ImBuf(ImBuf *ibuf, int newx, int newy)
}
}
-/**
- * Return true if \a ibuf is modified.
- */
bool IMB_scaleImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy)
{
BLI_assert_msg(newx > 0 && newy > 0, "Images must be at least 1 on both dimensions!");
@@ -1709,9 +1705,6 @@ struct imbufRGBA {
float r, g, b, a;
};
-/**
- * Return true if \a ibuf is modified.
- */
bool IMB_scalefastImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy)
{
BLI_assert_msg(newx > 0 && newy > 0, "Images must be at least 1 on both dimensions!");
diff --git a/source/blender/imbuf/intern/stereoimbuf.c b/source/blender/imbuf/intern/stereoimbuf.c
index d3c91b55f22..dae2604802f 100644
--- a/source/blender/imbuf/intern/stereoimbuf.c
+++ b/source/blender/imbuf/intern/stereoimbuf.c
@@ -757,7 +757,6 @@ float *IMB_stereo3d_from_rectf(ImageFormatData *im_format,
return r_rectf;
}
-/* left/right are always float */
ImBuf *IMB_stereo3d_ImBuf(ImageFormatData *im_format, ImBuf *ibuf_left, ImBuf *ibuf_right)
{
ImBuf *ibuf_stereo = NULL;
@@ -1275,7 +1274,6 @@ static void imb_stereo3d_read_topbottom(Stereo3DData *s3d)
/** \name Preparing To Call The Read Functions
* \{ */
-/* reading a stereo encoded ibuf (*left) and generating two ibufs from it (*left and *right) */
void IMB_ImBufFromStereo3d(Stereo3dFormat *s3d,
ImBuf *ibuf_stereo3d,
ImBuf **r_ibuf_left,
diff --git a/source/blender/imbuf/intern/thumbs.c b/source/blender/imbuf/intern/thumbs.c
index aa1da65253d..c39ce2e9a2a 100644
--- a/source/blender/imbuf/intern/thumbs.c
+++ b/source/blender/imbuf/intern/thumbs.c
@@ -523,7 +523,6 @@ ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, Im
path, uri, thumb_name, false, THUMB_DEFAULT_HASH, NULL, NULL, size, source, img);
}
-/* read thumbnail for file and returns new imbuf for thumbnail */
ImBuf *IMB_thumb_read(const char *path, ThumbSize size)
{
char thumb[FILE_MAX];
@@ -540,7 +539,6 @@ ImBuf *IMB_thumb_read(const char *path, ThumbSize size)
return img;
}
-/* delete all thumbs for the file */
void IMB_thumb_delete(const char *path, ThumbSize size)
{
char thumb[FILE_MAX];
@@ -559,7 +557,6 @@ void IMB_thumb_delete(const char *path, ThumbSize size)
}
}
-/* create the thumb if necessary and manage failed and old thumbs */
ImBuf *IMB_thumb_manage(const char *org_path, ThumbSize size, ThumbSource source)
{
char thumb_path[FILE_MAX];
diff --git a/source/blender/imbuf/intern/tiff.c b/source/blender/imbuf/intern/tiff.c
index 623c00fa670..6ad373845fc 100644
--- a/source/blender/imbuf/intern/tiff.c
+++ b/source/blender/imbuf/intern/tiff.c
@@ -553,15 +553,6 @@ void imb_inittiff(void)
}
}
-/**
- * Loads a TIFF file.
- * \param mem: Memory containing the TIFF file.
- * \param size: Size of the mem buffer.
- * \param flags: If flags has IB_test set then the file is not actually loaded,
- * but all other operations take place.
- *
- * \return A newly allocated #ImBuf structure if successful, otherwise NULL.
- */
ImBuf *imb_loadtiff(const unsigned char *mem,
size_t size,
int flags,
@@ -744,21 +735,6 @@ void imb_loadtiletiff(
/** \name Save TIFF
* \{ */
-/**
- * Saves a TIFF file.
- *
- * #ImBuf structures with 1, 3 or 4 bytes per pixel (GRAY, RGB, RGBA
- * respectively) are accepted, and interpreted correctly. Note that the TIFF
- * convention is to use pre-multiplied alpha, which can be achieved within
- * Blender by setting "Premul" alpha handling. Other alpha conventions are
- * not strictly correct, but are permitted anyhow.
- *
- * \param ibuf: Image buffer.
- * \param name: Name of the TIFF file to create.
- * \param flags: Currently largely ignored.
- *
- * \return 1 if the function is successful, 0 on failure.
- */
bool imb_savetiff(ImBuf *ibuf, const char *filepath, int flags)
{
TIFF *image = NULL;
diff --git a/source/blender/imbuf/intern/transform.cc b/source/blender/imbuf/intern/transform.cc
new file mode 100644
index 00000000000..e1c451a8412
--- /dev/null
+++ b/source/blender/imbuf/intern/transform.cc
@@ -0,0 +1,604 @@
+/*
+ * 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 imbuf
+ */
+
+#include <array>
+#include <type_traits>
+
+#include "BLI_math.h"
+#include "BLI_rect.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+namespace blender::imbuf::transform {
+
+struct TransformUserData {
+ /** \brief Source image buffer to read from. */
+ const ImBuf *src;
+ /** \brief Destination image buffer to write to. */
+ ImBuf *dst;
+ /** \brief UV coordinates at the origin (0,0) in source image space. */
+ float start_uv[2];
+
+ /**
+ * \brief delta UV coordinates along the source image buffer, when moving a single pixel in the X
+ * axis of the dst image buffer.
+ */
+ float add_x[2];
+
+ /**
+ * \brief delta UV coordinate along the source image buffer, when moving a single pixel in the Y
+ * axes of the dst image buffer.
+ */
+ float add_y[2];
+
+ /**
+ * \brief Cropping region in source image pixel space.
+ */
+ rctf src_crop;
+
+ /**
+ * \brief Initialize the start_uv, add_x and add_y fields based on the given transform matrix.
+ */
+ void init(const float transform_matrix[4][4])
+ {
+ init_start_uv(transform_matrix);
+ init_add_x(transform_matrix);
+ init_add_y(transform_matrix);
+ }
+
+ private:
+ void init_start_uv(const float transform_matrix[4][4])
+ {
+ float start_uv_v3[3];
+ float orig[3];
+ zero_v3(orig);
+ mul_v3_m4v3(start_uv_v3, transform_matrix, orig);
+ copy_v2_v2(start_uv, start_uv_v3);
+ }
+
+ void init_add_x(const float transform_matrix[4][4])
+ {
+ const int width = src->x;
+ float add_x_v3[3];
+ float uv_max_x[3];
+ zero_v3(uv_max_x);
+ uv_max_x[0] = width;
+ uv_max_x[1] = 0.0f;
+ mul_v3_m4v3(add_x_v3, transform_matrix, uv_max_x);
+ sub_v2_v2(add_x_v3, start_uv);
+ mul_v2_fl(add_x_v3, 1.0f / width);
+ copy_v2_v2(add_x, add_x_v3);
+ }
+
+ void init_add_y(const float transform_matrix[4][4])
+ {
+ const int height = src->y;
+ float add_y_v3[3];
+ float uv_max_y[3];
+ zero_v3(uv_max_y);
+ uv_max_y[0] = 0.0f;
+ uv_max_y[1] = height;
+ mul_v3_m4v3(add_y_v3, transform_matrix, uv_max_y);
+ sub_v2_v2(add_y_v3, start_uv);
+ mul_v2_fl(add_y_v3, 1.0f / height);
+ copy_v2_v2(add_y, add_y_v3);
+ }
+};
+
+/**
+ * \brief Base class for source discarding.
+ *
+ * The class decides if a specific uv coordinate from the source buffer should be ignored.
+ * This is used to mix multiple images over a single output buffer. Discarded pixels will
+ * not change the output buffer.
+ */
+class BaseDiscard {
+ public:
+ virtual ~BaseDiscard() = default;
+
+ /**
+ * \brief Should the source pixel at the given uv coordinate be discarded.
+ */
+ virtual bool should_discard(const TransformUserData &user_data, const float uv[2]) = 0;
+};
+
+/**
+ * \brief Crop uv-coordinates that are outside the user data src_crop rect.
+ */
+class CropSource : public BaseDiscard {
+ public:
+ /**
+ * \brief Should the source pixel at the given uv coordinate be discarded.
+ *
+ * Uses user_data.src_crop to determine if the uv coordinate should be skipped.
+ */
+ bool should_discard(const TransformUserData &user_data, const float uv[2]) override
+ {
+ return uv[0] < user_data.src_crop.xmin || uv[0] >= user_data.src_crop.xmax ||
+ uv[1] < user_data.src_crop.ymin || uv[1] >= user_data.src_crop.ymax;
+ }
+};
+
+/**
+ * \brief Discard that does not discard anything.
+ */
+class NoDiscard : public BaseDiscard {
+ public:
+ /**
+ * \brief Should the source pixel at the given uv coordinate be discarded.
+ *
+ * Will never discard any pixels.
+ */
+ bool should_discard(const TransformUserData &UNUSED(user_data),
+ const float UNUSED(uv[2])) override
+ {
+ return false;
+ }
+};
+
+/**
+ * \brief Pointer to a pixel to write to in serial.
+ */
+template<
+ /**
+ * \brief Kind of buffer.
+ * Possible options: float, unsigned char.
+ */
+ typename StorageType = float,
+
+ /**
+ * \brief Number of channels of a single pixel.
+ */
+ int NumChannels = 4>
+class PixelPointer {
+ public:
+ static const int ChannelLen = NumChannels;
+
+ private:
+ StorageType *pointer;
+
+ public:
+ void init_pixel_pointer(const ImBuf *image_buffer, int x, int y)
+ {
+ const size_t offset = (y * (size_t)image_buffer->x + x) * NumChannels;
+
+ if constexpr (std::is_same_v<StorageType, float>) {
+ pointer = image_buffer->rect_float + offset;
+ }
+ else if constexpr (std::is_same_v<StorageType, unsigned char>) {
+ pointer = const_cast<unsigned char *>(
+ static_cast<const unsigned char *>(static_cast<const void *>(image_buffer->rect)) +
+ offset);
+ }
+ else {
+ pointer = nullptr;
+ }
+ }
+
+ /**
+ * \brief Get pointer to the current pixel to write to.
+ */
+ StorageType *get_pointer()
+ {
+ return pointer;
+ }
+
+ void increase_pixel_pointer()
+ {
+ pointer += NumChannels;
+ }
+};
+
+/**
+ * \brief Wrapping mode for the uv coordinates.
+ *
+ * Subclasses have the ability to change the UV coordinates when sampling the source buffer.
+ */
+class BaseUVWrapping {
+ public:
+ /**
+ * \brief modify the given u coordinate.
+ */
+ virtual float modify_u(const ImBuf *source_buffer, float u) = 0;
+
+ /**
+ * \brief modify the given v coordinate.
+ */
+ virtual float modify_v(const ImBuf *source_buffer, float v) = 0;
+};
+
+/**
+ * \brief UVWrapping method that does not modify the UV coordinates.
+ */
+class PassThroughUV : public BaseUVWrapping {
+ public:
+ float modify_u(const ImBuf *UNUSED(source_buffer), float u) override
+ {
+ return u;
+ }
+
+ float modify_v(const ImBuf *UNUSED(source_buffer), float v) override
+ {
+ return v;
+ }
+};
+
+/**
+ * \brief UVWrapping method that wrap repeats the UV coordinates.
+ */
+class WrapRepeatUV : public BaseUVWrapping {
+ public:
+ float modify_u(const ImBuf *source_buffer, float u) override
+
+ {
+ int x = (int)floor(u);
+ x = x % source_buffer->x;
+ if (x < 0) {
+ x += source_buffer->x;
+ }
+ return x;
+ }
+
+ float modify_v(const ImBuf *source_buffer, float v) override
+ {
+ int y = (int)floor(v);
+ y = y % source_buffer->y;
+ if (y < 0) {
+ y += source_buffer->y;
+ }
+ return y;
+ }
+};
+
+/**
+ * \brief Read a sample from an image buffer.
+ *
+ * A sampler can read from an image buffer.
+ *
+ */
+template<
+ /** \brief Interpolation mode to use when sampling. */
+ eIMBInterpolationFilterMode Filter,
+
+ /** \brief storage type of a single pixel channel (unsigned char or float). */
+ typename StorageType,
+ /**
+ * \brief number of channels if the image to read.
+ *
+ * Must match the actual channels of the image buffer that is sampled.
+ */
+ int NumChannels,
+ /**
+ * \brief Wrapping method to perform
+ *
+ * Should be a subclass of BaseUVWrapper
+ */
+ typename UVWrapping>
+class Sampler {
+ UVWrapping uv_wrapper;
+
+ public:
+ using ChannelType = StorageType;
+ static const int ChannelLen = NumChannels;
+ using SampleType = std::array<StorageType, NumChannels>;
+
+ void sample(const ImBuf *source, const float u, const float v, SampleType &r_sample)
+ {
+ if constexpr (Filter == IMB_FILTER_BILINEAR && std::is_same_v<StorageType, float> &&
+ NumChannels == 4) {
+ const float wrapped_u = uv_wrapper.modify_u(source, u);
+ const float wrapped_v = uv_wrapper.modify_v(source, v);
+ bilinear_interpolation_color_fl(source, nullptr, &r_sample[0], wrapped_u, wrapped_v);
+ }
+ else if constexpr (Filter == IMB_FILTER_NEAREST &&
+ std::is_same_v<StorageType, unsigned char> && NumChannels == 4) {
+ const float wrapped_u = uv_wrapper.modify_u(source, u);
+ const float wrapped_v = uv_wrapper.modify_v(source, v);
+ nearest_interpolation_color_char(source, &r_sample[0], nullptr, wrapped_u, wrapped_v);
+ }
+ else if constexpr (Filter == IMB_FILTER_BILINEAR &&
+ std::is_same_v<StorageType, unsigned char> && NumChannels == 4) {
+ const float wrapped_u = uv_wrapper.modify_u(source, u);
+ const float wrapped_v = uv_wrapper.modify_v(source, v);
+ bilinear_interpolation_color_char(source, &r_sample[0], nullptr, wrapped_u, wrapped_v);
+ }
+ else if constexpr (Filter == IMB_FILTER_BILINEAR && std::is_same_v<StorageType, float>) {
+ if constexpr (std::is_same_v<UVWrapping, WrapRepeatUV>) {
+ BLI_bilinear_interpolation_wrap_fl(
+ source->rect_float, &r_sample[0], source->x, source->y, NumChannels, u, v, true, true);
+ }
+ else {
+ const float wrapped_u = uv_wrapper.modify_u(source, u);
+ const float wrapped_v = uv_wrapper.modify_v(source, v);
+ BLI_bilinear_interpolation_fl(source->rect_float,
+ &r_sample[0],
+ source->x,
+ source->y,
+ NumChannels,
+ wrapped_u,
+ wrapped_v);
+ }
+ }
+ else if constexpr (Filter == IMB_FILTER_NEAREST && std::is_same_v<StorageType, float>) {
+ const float wrapped_u = uv_wrapper.modify_u(source, u);
+ const float wrapped_v = uv_wrapper.modify_v(source, v);
+ sample_nearest_float(source, wrapped_u, wrapped_v, r_sample);
+ }
+ else {
+ /* Unsupported sampler. */
+ BLI_assert_unreachable();
+ }
+ }
+
+ private:
+ void sample_nearest_float(const ImBuf *source,
+ const float u,
+ const float v,
+ SampleType &r_sample)
+ {
+ BLI_STATIC_ASSERT(std::is_same_v<StorageType, float>);
+
+ /* ImBuf in must have a valid rect or rect_float, assume this is already checked */
+ int x1 = (int)(u);
+ int y1 = (int)(v);
+
+ /* Break when sample outside image is requested. */
+ if (x1 < 0 || x1 >= source->x || y1 < 0 || y1 >= source->y) {
+ for (int i = 0; i < NumChannels; i++) {
+ r_sample[i] = 0.0f;
+ }
+ return;
+ }
+
+ const size_t offset = ((size_t)source->x * y1 + x1) * NumChannels;
+ const float *dataF = source->rect_float + offset;
+ for (int i = 0; i < NumChannels; i++) {
+ r_sample[i] = dataF[i];
+ }
+ }
+};
+
+/**
+ * \brief Change the number of channels and store it.
+ *
+ * Template class to convert and store a sample in a PixelPointer.
+ * It supports:
+ * - 4 channel unsigned char -> 4 channel unsigned char.
+ * - 4 channel float -> 4 channel float.
+ * - 3 channel float -> 4 channel float.
+ * - 2 channel float -> 4 channel float.
+ * - 1 channel float -> 4 channel float.
+ */
+template<typename StorageType, int SourceNumChannels, int DestinationNumChannels>
+class ChannelConverter {
+ public:
+ using SampleType = std::array<StorageType, SourceNumChannels>;
+ using PixelType = PixelPointer<StorageType, DestinationNumChannels>;
+
+ /**
+ * \brief Convert the number of channels of the given sample to match the pixel pointer and store
+ * it at the location the pixel_pointer points at.
+ */
+ void convert_and_store(const SampleType &sample, PixelType &pixel_pointer)
+ {
+ if constexpr (std::is_same_v<StorageType, unsigned char>) {
+ BLI_STATIC_ASSERT(SourceNumChannels == 4, "Unsigned chars always have 4 channels.");
+ BLI_STATIC_ASSERT(DestinationNumChannels == 4, "Unsigned chars always have 4 channels.");
+
+ copy_v4_v4_uchar(pixel_pointer.get_pointer(), &sample[0]);
+ }
+ else if constexpr (std::is_same_v<StorageType, float> && SourceNumChannels == 4 &&
+ DestinationNumChannels == 4) {
+ copy_v4_v4(pixel_pointer.get_pointer(), &sample[0]);
+ }
+ else if constexpr (std::is_same_v<StorageType, float> && SourceNumChannels == 3 &&
+ DestinationNumChannels == 4) {
+ copy_v4_fl4(pixel_pointer.get_pointer(), sample[0], sample[1], sample[2], 1.0f);
+ }
+ else if constexpr (std::is_same_v<StorageType, float> && SourceNumChannels == 2 &&
+ DestinationNumChannels == 4) {
+ copy_v4_fl4(pixel_pointer.get_pointer(), sample[0], sample[1], 0.0f, 1.0f);
+ }
+ else if constexpr (std::is_same_v<StorageType, float> && SourceNumChannels == 1 &&
+ DestinationNumChannels == 4) {
+ copy_v4_fl4(pixel_pointer.get_pointer(), sample[0], sample[0], sample[0], 1.0f);
+ }
+ else {
+ BLI_assert_unreachable();
+ }
+ }
+};
+
+/**
+ * \brief Processor for a scanline.
+ */
+template<
+ /**
+ * \brief Discard function to use.
+ *
+ * \attention Should be a subclass of BaseDiscard.
+ */
+ typename Discard,
+
+ /**
+ * \brief Color interpolation function to read from the source buffer.
+ */
+ typename Sampler,
+
+ /**
+ * \brief Kernel to store to the destination buffer.
+ * Should be an PixelPointer
+ */
+ typename OutputPixelPointer>
+class ScanlineProcessor {
+ Discard discarder;
+ OutputPixelPointer output;
+ Sampler sampler;
+
+ /**
+ * \brief Channels sizzling logic to convert between the input image buffer and the output image
+ * buffer.
+ */
+ ChannelConverter<typename Sampler::ChannelType,
+ Sampler::ChannelLen,
+ OutputPixelPointer::ChannelLen>
+ channel_converter;
+
+ public:
+ /**
+ * \brief Inner loop of the transformations, processing a full scanline.
+ */
+ void process(const TransformUserData *user_data, int scanline)
+ {
+ const int width = user_data->dst->x;
+
+ float uv[2];
+ madd_v2_v2v2fl(uv, user_data->start_uv, user_data->add_y, scanline);
+
+ output.init_pixel_pointer(user_data->dst, 0, scanline);
+ for (int xi = 0; xi < width; xi++) {
+ if (!discarder.should_discard(*user_data, uv)) {
+ typename Sampler::SampleType sample;
+ sampler.sample(user_data->src, uv[0], uv[1], sample);
+ channel_converter.convert_and_store(sample, output);
+ }
+
+ add_v2_v2(uv, user_data->add_x);
+ output.increase_pixel_pointer();
+ }
+ }
+};
+
+/**
+ * \brief callback function for threaded transformation.
+ */
+template<typename Processor> void transform_scanline_function(void *custom_data, int scanline)
+{
+ const TransformUserData *user_data = static_cast<const TransformUserData *>(custom_data);
+ Processor processor;
+ processor.process(user_data, scanline);
+}
+
+template<eIMBInterpolationFilterMode Filter,
+ typename StorageType,
+ int SourceNumChannels,
+ int DestinationNumChannels>
+ScanlineThreadFunc get_scanline_function(const eIMBTransformMode mode)
+
+{
+ switch (mode) {
+ case IMB_TRANSFORM_MODE_REGULAR:
+ return transform_scanline_function<
+ ScanlineProcessor<NoDiscard,
+ Sampler<Filter, StorageType, SourceNumChannels, PassThroughUV>,
+ PixelPointer<StorageType, DestinationNumChannels>>>;
+ case IMB_TRANSFORM_MODE_CROP_SRC:
+ return transform_scanline_function<
+ ScanlineProcessor<CropSource,
+ Sampler<Filter, StorageType, SourceNumChannels, PassThroughUV>,
+ PixelPointer<StorageType, DestinationNumChannels>>>;
+ case IMB_TRANSFORM_MODE_WRAP_REPEAT:
+ return transform_scanline_function<
+ ScanlineProcessor<NoDiscard,
+ Sampler<Filter, StorageType, SourceNumChannels, WrapRepeatUV>,
+ PixelPointer<StorageType, DestinationNumChannels>>>;
+ }
+
+ BLI_assert_unreachable();
+ return nullptr;
+}
+
+template<eIMBInterpolationFilterMode Filter>
+ScanlineThreadFunc get_scanline_function(const TransformUserData *user_data,
+ const eIMBTransformMode mode)
+{
+ const ImBuf *src = user_data->src;
+ const ImBuf *dst = user_data->dst;
+
+ if (src->channels == 4 && dst->channels == 4) {
+ return get_scanline_function<Filter, float, 4, 4>(mode);
+ }
+ if (src->channels == 3 && dst->channels == 4) {
+ return get_scanline_function<Filter, float, 3, 4>(mode);
+ }
+ if (src->channels == 2 && dst->channels == 4) {
+ return get_scanline_function<Filter, float, 2, 4>(mode);
+ }
+ if (src->channels == 1 && dst->channels == 4) {
+ return get_scanline_function<Filter, float, 1, 4>(mode);
+ }
+ return nullptr;
+}
+
+template<eIMBInterpolationFilterMode Filter>
+static void transform_threaded(TransformUserData *user_data, const eIMBTransformMode mode)
+{
+ ScanlineThreadFunc scanline_func = nullptr;
+
+ if (user_data->dst->rect_float && user_data->src->rect_float) {
+ scanline_func = get_scanline_function<Filter>(user_data, mode);
+ }
+ else if (user_data->dst->rect && user_data->src->rect) {
+ /* Number of channels is always 4 when using unsigned char buffers (sRGB + straight alpha). */
+ scanline_func = get_scanline_function<Filter, unsigned char, 4, 4>(mode);
+ }
+
+ if (scanline_func != nullptr) {
+ IMB_processor_apply_threaded_scanlines(user_data->dst->y, scanline_func, user_data);
+ }
+}
+
+} // namespace blender::imbuf::transform
+
+extern "C" {
+
+using namespace blender::imbuf::transform;
+
+void IMB_transform(const struct ImBuf *src,
+ struct ImBuf *dst,
+ const eIMBTransformMode mode,
+ const eIMBInterpolationFilterMode filter,
+ const float transform_matrix[4][4],
+ const struct rctf *src_crop)
+{
+ BLI_assert_msg(mode != IMB_TRANSFORM_MODE_CROP_SRC || src_crop != nullptr,
+ "No source crop rect given, but crop source is requested. Or source crop rect "
+ "was given, but crop source was not requested.");
+
+ TransformUserData user_data;
+ user_data.src = src;
+ user_data.dst = dst;
+ if (mode == IMB_TRANSFORM_MODE_CROP_SRC) {
+ user_data.src_crop = *src_crop;
+ }
+ user_data.init(transform_matrix);
+
+ if (filter == IMB_FILTER_NEAREST) {
+ transform_threaded<IMB_FILTER_NEAREST>(&user_data, mode);
+ }
+ else {
+ transform_threaded<IMB_FILTER_BILINEAR>(&user_data, mode);
+ }
+}
+}
diff --git a/source/blender/imbuf/intern/util.c b/source/blender/imbuf/intern/util.c
index 1bb047f1317..18ed4710e78 100644
--- a/source/blender/imbuf/intern/util.c
+++ b/source/blender/imbuf/intern/util.c
@@ -98,7 +98,7 @@ const char *imb_ext_movie[] = {
".mpg2", ".vob", ".mkv", ".flv", ".divx", ".xvid", ".mxf", ".webm", NULL,
};
-/* sort of wrong being here... */
+/** Sort of wrong having audio extensions in imbuf. */
const char *imb_ext_audio[] = {
".wav",
".ogg",
diff --git a/source/blender/imbuf/intern/util_gpu.c b/source/blender/imbuf/intern/util_gpu.c
index 2b99a0aa81d..cc6fef634d5 100644
--- a/source/blender/imbuf/intern/util_gpu.c
+++ b/source/blender/imbuf/intern/util_gpu.c
@@ -162,8 +162,6 @@ static void *imb_gpu_get_data(const ImBuf *ibuf,
return data_rect;
}
-/* The ibuf is only here to detect the storage type. The produced texture will have undefined
- * content. It will need to be populated by using IMB_update_gpu_texture_sub(). */
GPUTexture *IMB_touch_gpu_texture(
const char *name, ImBuf *ibuf, int w, int h, int layers, bool use_high_bitdepth)
{
@@ -183,9 +181,6 @@ GPUTexture *IMB_touch_gpu_texture(
return tex;
}
-/* Will update a GPUTexture using the content of the ImBuf. Only one layer will be updated.
- * Will resize the ibuf if needed.
- * z is the layer to update. Unused if the texture is 2D. */
void IMB_update_gpu_texture_sub(GPUTexture *tex,
ImBuf *ibuf,
int x,
diff --git a/source/blender/io/alembic/exporter/abc_archive.cc b/source/blender/io/alembic/exporter/abc_archive.cc
index e066704cd24..c070539fc94 100644
--- a/source/blender/io/alembic/exporter/abc_archive.cc
+++ b/source/blender/io/alembic/exporter/abc_archive.cc
@@ -51,7 +51,7 @@ static MetaData create_abc_metadata(const Main *bmain, double scene_fps)
{
MetaData abc_metadata;
- std::string abc_user_description(bmain->name);
+ std::string abc_user_description(bmain->filepath);
if (abc_user_description.empty()) {
abc_user_description = "unknown";
}
diff --git a/source/blender/io/alembic/exporter/abc_subdiv_disabler.cc b/source/blender/io/alembic/exporter/abc_subdiv_disabler.cc
index 8073e157c13..bd12f3c10d3 100644
--- a/source/blender/io/alembic/exporter/abc_subdiv_disabler.cc
+++ b/source/blender/io/alembic/exporter/abc_subdiv_disabler.cc
@@ -72,8 +72,6 @@ void SubdivModifierDisabler::disable_modifiers()
}
}
-/* Check if the mesh is a subsurf, ignoring disabled modifiers and
- * displace if it's after subsurf. */
ModifierData *SubdivModifierDisabler::get_subdiv_modifier(Scene *scene, Object *ob)
{
ModifierData *md = static_cast<ModifierData *>(ob->modifiers.last);
diff --git a/source/blender/io/alembic/exporter/abc_subdiv_disabler.h b/source/blender/io/alembic/exporter/abc_subdiv_disabler.h
index 3556df7ff31..c6541fd8afe 100644
--- a/source/blender/io/alembic/exporter/abc_subdiv_disabler.h
+++ b/source/blender/io/alembic/exporter/abc_subdiv_disabler.h
@@ -45,6 +45,10 @@ class SubdivModifierDisabler final {
void disable_modifiers();
+ /**
+ * Check if the mesh is a subsurf, ignoring disabled modifiers and
+ * displace if it's after subsurf.
+ */
static ModifierData *get_subdiv_modifier(Scene *scene, Object *ob);
};
diff --git a/source/blender/io/alembic/exporter/abc_writer_points.cc b/source/blender/io/alembic/exporter/abc_writer_points.cc
index 70608fdbe92..2db9ad4ffab 100644
--- a/source/blender/io/alembic/exporter/abc_writer_points.cc
+++ b/source/blender/io/alembic/exporter/abc_writer_points.cc
@@ -112,7 +112,7 @@ void ABCPointsWriter::do_write(HierarchyContext &context)
}
state.time = DEG_get_ctime(args_.depsgraph);
- if (psys_get_particle_state(&sim, p, &state, 0) == 0) {
+ if (psys_get_particle_state(&sim, p, &state, false) == 0) {
continue;
}
diff --git a/source/blender/io/alembic/intern/abc_axis_conversion.cc b/source/blender/io/alembic/intern/abc_axis_conversion.cc
index 23b24d2fd9a..78ea7166faf 100644
--- a/source/blender/io/alembic/intern/abc_axis_conversion.cc
+++ b/source/blender/io/alembic/intern/abc_axis_conversion.cc
@@ -75,8 +75,6 @@ void create_swapped_rotation_matrix(float rot_x_mat[3][3],
} // namespace
// alembicvoidcreate_swapped_rotation_matrix(floatrot_x_mat[3][3],floatrot_y_mat[3][3],floatrot_z_mat[3][3],constfloateuler[3],AbcAxisSwapModemode)
-/* Convert matrix from Z=up to Y=up or vice versa.
- * Use yup_mat = zup_mat for in-place conversion. */
void copy_m44_axis_swap(float dst_mat[4][4], float src_mat[4][4], AbcAxisSwapMode mode)
{
float dst_rot[3][3], src_rot[3][3], dst_scale_mat[4][4];
@@ -139,8 +137,6 @@ void copy_m44_axis_swap(float dst_mat[4][4], float src_mat[4][4], AbcAxisSwapMod
mul_m4_m4m4(dst_mat, dst_mat, dst_scale_mat);
}
-/* Recompute transform matrix of object in new coordinate system
- * (from Z-Up to Y-Up). */
void create_transform_matrix(Object *obj,
float r_yup_mat[4][4],
AbcMatrixMode mode,
diff --git a/source/blender/io/alembic/intern/abc_axis_conversion.h b/source/blender/io/alembic/intern/abc_axis_conversion.h
index 30988222fb7..21b95ec717e 100644
--- a/source/blender/io/alembic/intern/abc_axis_conversion.h
+++ b/source/blender/io/alembic/intern/abc_axis_conversion.h
@@ -70,20 +70,27 @@ BLI_INLINE void copy_yup_from_zup(short yup[3], const short zup[3])
}
/* Names are given in (dst, src) order, just like
- * the parameters of copy_m44_axis_swap() */
+ * the parameters of copy_m44_axis_swap(). */
+
typedef enum {
ABC_ZUP_FROM_YUP = 1,
ABC_YUP_FROM_ZUP = 2,
} AbcAxisSwapMode;
-/* Create a rotation matrix for each axis from euler angles.
- * Euler angles are swapped to change coordinate system. */
+/**
+ * Create a rotation matrix for each axis from euler angles.
+ * Euler angles are swapped to change coordinate system.
+ */
void create_swapped_rotation_matrix(float rot_x_mat[3][3],
float rot_y_mat[3][3],
float rot_z_mat[3][3],
const float euler[3],
AbcAxisSwapMode mode);
+/**
+ * Convert matrix from Z=up to Y=up or vice versa.
+ * Use yup_mat = zup_mat for in-place conversion.
+ */
void copy_m44_axis_swap(float dst_mat[4][4], float src_mat[4][4], AbcAxisSwapMode mode);
typedef enum {
@@ -91,6 +98,10 @@ typedef enum {
ABC_MATRIX_LOCAL = 2,
} AbcMatrixMode;
+/**
+ * Recompute transform matrix of object in new coordinate system
+ * (from Z-Up to Y-Up).
+ */
void create_transform_matrix(Object *obj,
float r_yup_mat[4][4],
AbcMatrixMode mode,
diff --git a/source/blender/io/alembic/intern/abc_customdata.cc b/source/blender/io/alembic/intern/abc_customdata.cc
index 188e8daac8f..830ec731e20 100644
--- a/source/blender/io/alembic/intern/abc_customdata.cc
+++ b/source/blender/io/alembic/intern/abc_customdata.cc
@@ -36,6 +36,7 @@
#include "BLI_utildefines.h"
#include "BKE_customdata.h"
+#include "BKE_mesh.h"
/* NOTE: for now only UVs and Vertex Colors are supported for streaming.
* Although Alembic only allows for a single UV layer per {I|O}Schema, and does
@@ -253,7 +254,8 @@ static void write_mcol(const OCompoundProperty &prop,
void write_generated_coordinates(const OCompoundProperty &prop, CDStreamConfig &config)
{
- const void *customdata = CustomData_get_layer(&config.mesh->vdata, CD_ORCO);
+ Mesh *mesh = config.mesh;
+ const void *customdata = CustomData_get_layer(&mesh->vdata, CD_ORCO);
if (customdata == nullptr) {
/* Data not available, so don't even bother creating an Alembic property for it. */
return;
@@ -268,6 +270,11 @@ void write_generated_coordinates(const OCompoundProperty &prop, CDStreamConfig &
coords[vertex_idx].setValue(orco_yup[0], orco_yup[1], orco_yup[2]);
}
+ /* ORCOs are always stored in the normalized 0..1 range in Blender, but Alembic stores them
+ * unnormalized, so we need to unnormalize (invert transform) them. */
+ BKE_mesh_orco_verts_transform(
+ mesh, reinterpret_cast<float(*)[3]>(&coords[0]), mesh->totvert, true);
+
if (!config.abc_orco.valid()) {
/* Create the Alembic property and keep a reference so future frames can reuse it. */
config.abc_orco = OV3fGeomParam(prop, propNameOriginalCoordinates, false, kVertexScope, 1);
@@ -536,13 +543,14 @@ void read_generated_coordinates(const ICompoundProperty &prop,
IV3fGeomParam::Sample sample = param.getExpandedValue(iss);
Alembic::AbcGeom::V3fArraySamplePtr abc_ocro = sample.getVals();
const size_t totvert = abc_ocro.get()->size();
+ Mesh *mesh = config.mesh;
void *cd_data;
- if (CustomData_has_layer(&config.mesh->vdata, CD_ORCO)) {
- cd_data = CustomData_get_layer(&config.mesh->vdata, CD_ORCO);
+ if (CustomData_has_layer(&mesh->vdata, CD_ORCO)) {
+ cd_data = CustomData_get_layer(&mesh->vdata, CD_ORCO);
}
else {
- cd_data = CustomData_add_layer(&config.mesh->vdata, CD_ORCO, CD_CALLOC, nullptr, totvert);
+ cd_data = CustomData_add_layer(&mesh->vdata, CD_ORCO, CD_CALLOC, nullptr, totvert);
}
float(*orcodata)[3] = static_cast<float(*)[3]>(cd_data);
@@ -550,6 +558,10 @@ void read_generated_coordinates(const ICompoundProperty &prop,
const Imath::V3f &abc_coords = (*abc_ocro)[vertex_idx];
copy_zup_from_yup(orcodata[vertex_idx], abc_coords.getValue());
}
+
+ /* ORCOs are always stored in the normalized 0..1 range in Blender, but Alembic stores them
+ * unnormalized, so we need to normalize them. */
+ BKE_mesh_orco_verts_transform(mesh, orcodata, mesh->totvert, false);
}
void read_custom_data(const std::string &iobject_full_name,
@@ -591,12 +603,6 @@ void read_custom_data(const std::string &iobject_full_name,
}
}
-/* UVs can be defined per-loop (one value per vertex per face), or per-vertex (one value per
- * vertex). The first case is the most common, as this is the standard way of storing this data
- * given that some vertices might be on UV seams and have multiple possible UV coordinates; the
- * second case can happen when the mesh is split according to the UV islands, in which case storing
- * a single UV value per vertex allows to deduplicate data and thus to reduce the file size since
- * vertices are guaranteed to only have a single UV coordinate. */
AbcUvScope get_uv_scope(const Alembic::AbcGeom::GeometryScope scope,
const CDStreamConfig &config,
const Alembic::AbcGeom::UInt32ArraySamplePtr &indices)
diff --git a/source/blender/io/alembic/intern/abc_customdata.h b/source/blender/io/alembic/intern/abc_customdata.h
index 5eae6307474..97a9235753f 100644
--- a/source/blender/io/alembic/intern/abc_customdata.h
+++ b/source/blender/io/alembic/intern/abc_customdata.h
@@ -132,6 +132,14 @@ typedef enum {
ABC_UV_SCOPE_VERTEX,
} AbcUvScope;
+/**
+ * UVs can be defined per-loop (one value per vertex per face), or per-vertex (one value per
+ * vertex). The first case is the most common, as this is the standard way of storing this data
+ * given that some vertices might be on UV seams and have multiple possible UV coordinates; the
+ * second case can happen when the mesh is split according to the UV islands, in which case storing
+ * a single UV value per vertex allows to de-duplicate data and thus to reduce the file size since
+ * vertices are guaranteed to only have a single UV coordinate.
+ */
AbcUvScope get_uv_scope(const Alembic::AbcGeom::GeometryScope scope,
const CDStreamConfig &config,
const Alembic::AbcGeom::UInt32ArraySamplePtr &indices);
diff --git a/source/blender/io/alembic/intern/abc_reader_curves.cc b/source/blender/io/alembic/intern/abc_reader_curves.cc
index d2ec7fb84db..bd1e57da648 100644
--- a/source/blender/io/alembic/intern/abc_reader_curves.cc
+++ b/source/blender/io/alembic/intern/abc_reader_curves.cc
@@ -274,12 +274,6 @@ void AbcCurveReader::read_curve_sample(Curve *cu,
}
}
-/* NOTE: Alembic only stores data about control points, but the Mesh
- * passed from the cache modifier contains the displist, which has more data
- * than the control points, so to avoid corrupting the displist we modify the
- * object directly and create a new Mesh from that. Also we might need to
- * create new or delete existing NURBS in the curve.
- */
Mesh *AbcCurveReader::read_mesh(Mesh *existing_mesh,
const ISampleSelector &sample_sel,
int /*read_flag*/,
diff --git a/source/blender/io/alembic/intern/abc_reader_curves.h b/source/blender/io/alembic/intern/abc_reader_curves.h
index df5d68d7850..6bc0691a870 100644
--- a/source/blender/io/alembic/intern/abc_reader_curves.h
+++ b/source/blender/io/alembic/intern/abc_reader_curves.h
@@ -43,6 +43,13 @@ class AbcCurveReader final : public AbcObjectReader {
const char **err_str) const override;
void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel) override;
+ /**
+ * \note Alembic only stores data about control points, but the Mesh
+ * passed from the cache modifier contains the displist, which has more data
+ * than the control points, so to avoid corrupting the displist we modify the
+ * object directly and create a new Mesh from that. Also we might need to
+ * create new or delete existing NURBS in the curve.
+ */
struct Mesh *read_mesh(struct Mesh *existing_mesh,
const Alembic::Abc::ISampleSelector &sample_sel,
const int read_flag,
diff --git a/source/blender/io/alembic/intern/abc_reader_object.cc b/source/blender/io/alembic/intern/abc_reader_object.cc
index a6d46c4b42a..4a359c49d26 100644
--- a/source/blender/io/alembic/intern/abc_reader_object.cc
+++ b/source/blender/io/alembic/intern/abc_reader_object.cc
@@ -67,7 +67,6 @@ AbcObjectReader::AbcObjectReader(const IObject &object, ImportSettings &settings
determine_inherits_xform();
}
-/* Determine whether we can inherit our parent's XForm */
void AbcObjectReader::determine_inherits_xform()
{
m_inherits_xform = false;
diff --git a/source/blender/io/alembic/intern/abc_reader_object.h b/source/blender/io/alembic/intern/abc_reader_object.h
index 6e97f841a88..f1c07da0764 100644
--- a/source/blender/io/alembic/intern/abc_reader_object.h
+++ b/source/blender/io/alembic/intern/abc_reader_object.h
@@ -171,6 +171,7 @@ class AbcObjectReader {
void read_matrix(float r_mat[4][4], const float time, const float scale, bool &is_constant);
protected:
+ /** Determine whether we can inherit our parent's XForm. */
void determine_inherits_xform();
};
diff --git a/source/blender/io/alembic/intern/abc_util.cc b/source/blender/io/alembic/intern/abc_util.cc
index 3d3ba0347c5..952fe1fa783 100644
--- a/source/blender/io/alembic/intern/abc_util.cc
+++ b/source/blender/io/alembic/intern/abc_util.cc
@@ -63,15 +63,6 @@ std::string get_valid_abc_name(const char *name)
return name_string;
}
-/**
- * \brief get_object_dag_path_name returns the name under which the object
- * will be exported in the Alembic file. It is of the form
- * "[../grandparent/]parent/object" if dupli_parent is NULL, or
- * "dupli_parent/[../grandparent/]parent/object" otherwise.
- * \param ob:
- * \param dupli_parent:
- * \return
- */
std::string get_object_dag_path_name(const Object *const ob, Object *dupli_parent)
{
std::string name = get_id_name(ob);
diff --git a/source/blender/io/alembic/intern/abc_util.h b/source/blender/io/alembic/intern/abc_util.h
index ced9fde0f85..3a0b2852eea 100644
--- a/source/blender/io/alembic/intern/abc_util.h
+++ b/source/blender/io/alembic/intern/abc_util.h
@@ -35,6 +35,15 @@ struct ImportSettings;
std::string get_id_name(const ID *const id);
std::string get_id_name(const Object *const ob);
std::string get_valid_abc_name(const char *name);
+/**
+ * \brief get_object_dag_path_name returns the name under which the object
+ * will be exported in the Alembic file. It is of the form
+ * "[../grandparent/]parent/object" if dupli_parent is NULL, or
+ * "dupli_parent/[../grandparent/]parent/object" otherwise.
+ * \param ob:
+ * \param dupli_parent:
+ * \return
+ */
std::string get_object_dag_path_name(const Object *const ob, Object *dupli_parent);
/* Convert from float to Alembic matrix representations. Does NOT convert from Z-up to Y-up. */
diff --git a/source/blender/io/collada/AnimationExporter.cpp b/source/blender/io/collada/AnimationExporter.cpp
index 56274e7e6ca..56fd0938eea 100644
--- a/source/blender/io/collada/AnimationExporter.cpp
+++ b/source/blender/io/collada/AnimationExporter.cpp
@@ -126,7 +126,6 @@ bool AnimationExporter::exportAnimations()
return animation_count;
}
-/* called for each exported object */
void AnimationExporter::exportAnimation(Object *ob, BCAnimationSampler &sampler)
{
bool container_is_open = false;
@@ -165,16 +164,6 @@ void AnimationExporter::exportAnimation(Object *ob, BCAnimationSampler &sampler)
close_animation_container(container_is_open);
}
-/*
- * Export all animation FCurves of an Object.
- *
- * NOTE: This uses the keyframes as sample points,
- * and exports "baked keyframes" while keeping the tangent information
- * of the FCurves intact. This works for simple cases, but breaks
- * especially when negative scales are involved in the animation.
- * And when parent inverse matrices are involved (when exporting
- * object hierarchies)
- */
void AnimationExporter::export_curve_animation_set(Object *ob,
BCAnimationSampler &sampler,
bool export_as_matrix)
@@ -254,7 +243,6 @@ BC_global_rotation_type AnimationExporter::get_global_rotation_type(Object *ob)
return (apply_global_rotation) ? BC_DATA_ROTATION : BC_OBJECT_ROTATION;
}
-/* Write bone animations in transform matrix sources. */
void AnimationExporter::export_bone_animations_recursive(Object *ob,
Bone *bone,
BCAnimationSampler &sampler)
@@ -277,14 +265,6 @@ void AnimationExporter::export_bone_animations_recursive(Object *ob,
}
}
-/**
- * In some special cases the exported Curve needs to be replaced
- * by a modified curve (for collada purposes)
- * This method checks if a conversion is necessary and if applicable
- * returns a pointer to the modified BCAnimationCurve.
- * IMPORTANT: the modified curve must be deleted by the caller when no longer needed
- * if no conversion is needed this method returns a NULL;
- */
BCAnimationCurve *AnimationExporter::get_modified_export_curve(Object *ob,
BCAnimationCurve &curve,
BCAnimationCurveMap &curves)
@@ -657,9 +637,6 @@ std::string AnimationExporter::collada_source_from_values(
return source_id;
}
-/*
- * Create a collada matrix source for a set of samples
- */
std::string AnimationExporter::collada_source_from_values(
BCMatrixSampleMap &samples,
const std::string &anim_id,
@@ -823,10 +800,6 @@ std::string AnimationExporter::get_collada_name(std::string channel_type) const
return tm_name;
}
-/*
- * Assign sid of the animated parameter or transform for rotation,
- * axis name is always appended and the value of append_axis is ignored
- */
std::string AnimationExporter::get_collada_sid(const BCAnimationCurve &curve,
const std::string axis_name)
{
diff --git a/source/blender/io/collada/AnimationExporter.h b/source/blender/io/collada/AnimationExporter.h
index fd691184e8b..11732af33ba 100644
--- a/source/blender/io/collada/AnimationExporter.h
+++ b/source/blender/io/collada/AnimationExporter.h
@@ -100,7 +100,7 @@ class AnimationExporter : COLLADASW::LibraryAnimations {
bool exportAnimations();
- /* called for each exported object */
+ /** Called for each exported object. */
void operator()(Object *ob);
protected:
@@ -148,25 +148,34 @@ class AnimationExporter : COLLADASW::LibraryAnimations {
std::vector<std::vector<std::string>> anim_meta;
- /* Main entry point into Animation export (called for each exported object) */
+ /** Main entry point into Animation export (called for each exported object). */
void exportAnimation(Object *ob, BCAnimationSampler &sampler);
- /* export animation as separate trans/rot/scale curves */
+ /**
+ * Export all animation FCurves of an Object.
+ *
+ * \note This uses the keyframes as sample points,
+ * and exports "baked keyframes" while keeping the tangent information
+ * of the FCurves intact. This works for simple cases, but breaks
+ * especially when negative scales are involved in the animation.
+ * And when parent inverse matrices are involved (when exporting
+ * object hierarchies)
+ */
void export_curve_animation_set(Object *ob, BCAnimationSampler &sampler, bool export_as_matrix);
- /* export one single curve */
+ /** Export one single curve. */
void export_curve_animation(Object *ob, BCAnimationCurve &curve);
- /* export animation as matrix data */
+ /** Export animation as matrix data. */
void export_matrix_animation(Object *ob, BCAnimationSampler &sampler);
- /* step through the bone hierarchy */
+ /** Write bone animations in transform matrix sources (step through the bone hierarchy). */
void export_bone_animations_recursive(Object *ob_arm, Bone *bone, BCAnimationSampler &sampler);
- /* Export for one bone */
+ /** Export for one bone. */
void export_bone_animation(Object *ob, Bone *bone, BCFrames &frames, BCMatrixSampleMap &samples);
- /* call to the low level collada exporter */
+ /** Call to the low level collada exporter. */
void export_collada_curve_animation(std::string id,
std::string name,
std::string target,
@@ -174,7 +183,7 @@ class AnimationExporter : COLLADASW::LibraryAnimations {
BCAnimationCurve &curve,
BC_global_rotation_type global_rotation_type);
- /* call to the low level collada exporter */
+ /** Call to the low level collada exporter. */
void export_collada_matrix_animation(std::string id,
std::string name,
std::string target,
@@ -183,29 +192,38 @@ class AnimationExporter : COLLADASW::LibraryAnimations {
BC_global_rotation_type global_rotation_type,
Matrix &parentinv);
+ /**
+ * In some special cases the exported Curve needs to be replaced
+ * by a modified curve (for collada purposes)
+ * This method checks if a conversion is necessary and if applicable
+ * returns a pointer to the modified BCAnimationCurve.
+ * IMPORTANT: the modified curve must be deleted by the caller when no longer needed
+ * if no conversion is needed this method returns a NULL;
+ */
BCAnimationCurve *get_modified_export_curve(Object *ob,
BCAnimationCurve &curve,
BCAnimationCurveMap &curves);
- /* Helper functions */
+ /* Helper functions. */
+
void openAnimationWithClip(std::string id, std::string name);
bool open_animation_container(bool has_container, Object *ob);
void close_animation_container(bool has_container);
- /* Input and Output sources (single valued) */
+ /** Input and Output sources (single valued). */
std::string collada_source_from_values(BC_animation_source_type source_type,
COLLADASW::InputSemantic::Semantics semantic,
std::vector<float> &values,
const std::string &anim_id,
const std::string axis_name);
- /* Output sources (matrix data) */
+ /** Output sources (matrix data). * Create a collada matrix source for a set of samples. */
std::string collada_source_from_values(BCMatrixSampleMap &samples,
const std::string &anim_id,
BC_global_rotation_type global_rotation_type,
Matrix &parentinv);
- /* Interpolation sources */
+ /** Interpolation sources. */
std::string collada_linear_interpolation_source(int tot, const std::string &anim_id);
/* source ID = animation_name + semantic_suffix */
@@ -240,6 +258,10 @@ class AnimationExporter : COLLADASW::LibraryAnimations {
std::string get_axis_name(std::string channel, int id);
std::string get_collada_name(std::string channel_type) const;
+ /**
+ * Assign sid of the animated parameter or transform for rotation,
+ * axis name is always appended and the value of append_axis is ignored.
+ */
std::string get_collada_sid(const BCAnimationCurve &curve, const std::string axis_name);
/* ===================================== */
diff --git a/source/blender/io/collada/AnimationImporter.cpp b/source/blender/io/collada/AnimationImporter.cpp
index 5b6391c1b9c..870db4a15d3 100644
--- a/source/blender/io/collada/AnimationImporter.cpp
+++ b/source/blender/io/collada/AnimationImporter.cpp
@@ -81,7 +81,6 @@ void AnimationImporter::add_bezt(FCurve *fcu,
calchandles_fcurve(fcu);
}
-/* create one or several fcurves depending on the number of parameters being animated */
void AnimationImporter::animation_to_fcurves(COLLADAFW::AnimationCurve *curve)
{
COLLADAFW::FloatOrDoubleArray &input = curve->getInputValues();
@@ -323,7 +322,6 @@ bool AnimationImporter::write_animation(const COLLADAFW::Animation *anim)
return true;
}
-/* called on post-process stage after writeVisualScenes */
bool AnimationImporter::write_animation_list(const COLLADAFW::AnimationList *animlist)
{
const COLLADAFW::UniqueId &animlist_id = animlist->getUniqueId();
@@ -343,11 +341,6 @@ bool AnimationImporter::write_animation_list(const COLLADAFW::AnimationList *ani
return true;
}
-/**
- * \todo refactor read_node_transform to not automatically apply anything,
- * but rather return the transform matrix, so caller can do with it what is
- * necessary. Same for \ref get_node_mat
- */
void AnimationImporter::read_node_transform(COLLADAFW::Node *node, Object *ob)
{
float mat[4][4];
@@ -463,7 +456,6 @@ virtual void AnimationImporter::change_eul_to_quat(Object *ob, bAction *act)
}
#endif
-/* sets the rna_path and array index to curve */
void AnimationImporter::modify_fcurve(std::vector<FCurve *> *curves,
const char *rna_path,
int array_index,
@@ -535,8 +527,6 @@ static int get_animation_axis_index(const COLLADABU::Math::Vector3 &axis)
return index;
}
-/* creates the rna_paths and array indices of fcurves from animations using transformation and
- * bound animation class of each animation. */
void AnimationImporter::Assign_transform_animations(
COLLADAFW::Transformation *transform,
const COLLADAFW::AnimationList::AnimationBinding *binding,
@@ -654,8 +644,6 @@ void AnimationImporter::Assign_transform_animations(
}
}
-/* creates the rna_paths and array indices of fcurves from animations using color and bound
- * animation class of each animation. */
void AnimationImporter::Assign_color_animations(const COLLADAFW::UniqueId &listid,
ListBase *AnimCurves,
const char *anim_type)
@@ -765,11 +753,6 @@ float AnimationImporter::convert_to_focal_length(float in_xfov,
return fov_to_focallength(xfov, sensorx);
}
-/*
- * Lens animations must be stored in COLLADA by using FOV,
- * while blender internally uses focal length.
- * The imported animation curves must be converted appropriately.
- */
void AnimationImporter::Assign_lens_animations(const COLLADAFW::UniqueId &listid,
ListBase *AnimCurves,
const double aspect,
@@ -1403,8 +1386,6 @@ void AnimationImporter::add_bone_animation_sampled(Object *ob,
chan->rotmode = ROT_MODE_QUAT;
}
-/* Check if object is animated by checking if animlist_map
- * holds the animlist_id of node transforms */
AnimationImporter::AnimMix *AnimationImporter::get_animation_type(
const COLLADAFW::Node *node,
std::map<COLLADAFW::UniqueId, const COLLADAFW::Object *> FW_object_map)
@@ -1514,7 +1495,6 @@ int AnimationImporter::setAnimType(const COLLADAFW::Animatable *prop, int types,
return anim_type;
}
-/* Is not used anymore. */
void AnimationImporter::find_frames_old(std::vector<float> *frames,
COLLADAFW::Node *node,
COLLADAFW::Transformation::TransformationType tm_type)
@@ -1579,9 +1559,6 @@ void AnimationImporter::find_frames_old(std::vector<float> *frames,
}
}
-/* prerequisites:
- * animlist_map - map animlist id -> animlist
- * curve_map - map anim id -> curve(s) */
Object *AnimationImporter::translate_animation_OLD(
COLLADAFW::Node *node,
std::map<COLLADAFW::UniqueId, Object *> &object_map,
@@ -1854,9 +1831,6 @@ Object *AnimationImporter::translate_animation_OLD(
return job;
}
-/* internal, better make it private
- * warning: evaluates only rotation and only assigns matrix transforms now
- * prerequisites: animlist_map, curve_map */
void AnimationImporter::evaluate_transform_at_frame(float mat[4][4],
COLLADAFW::Node *node,
float fra)
@@ -1915,7 +1889,6 @@ static void report_class_type_unsupported(const char *path,
}
}
-/* return true to indicate that mat contains a sane value */
bool AnimationImporter::evaluate_animation(COLLADAFW::Transformation *tm,
float mat[4][4],
float fra,
@@ -2063,7 +2036,6 @@ bool AnimationImporter::evaluate_animation(COLLADAFW::Transformation *tm,
return false;
}
-/* gives a world-space mat of joint at rest position */
void AnimationImporter::get_joint_rest_mat(float mat[4][4],
COLLADAFW::Node *root,
COLLADAFW::Node *node)
@@ -2079,7 +2051,6 @@ void AnimationImporter::get_joint_rest_mat(float mat[4][4],
}
}
-/* gives a world-space mat, end's mat not included */
bool AnimationImporter::calc_joint_parent_mat_rest(float mat[4][4],
float par[4][4],
COLLADAFW::Node *node,
diff --git a/source/blender/io/collada/AnimationImporter.h b/source/blender/io/collada/AnimationImporter.h
index 44001366adc..a4624a18cd5 100644
--- a/source/blender/io/collada/AnimationImporter.h
+++ b/source/blender/io/collada/AnimationImporter.h
@@ -75,7 +75,9 @@ class AnimationImporter : private TransformReader, public AnimationImporterBase
float value,
eBezTriple_Interpolation ipo = BEZT_IPO_LIN);
- /* create one or several fcurves depending on the number of parameters being animated */
+ /**
+ * Create one or several fcurves depending on the number of parameters being animated.
+ */
void animation_to_fcurves(COLLADAFW::AnimationCurve *curve);
void fcurve_deg_to_rad(FCurve *cu);
@@ -143,9 +145,14 @@ class AnimationImporter : private TransformReader, public AnimationImporterBase
void set_import_from_version(std::string import_from_version);
bool write_animation(const COLLADAFW::Animation *anim);
- /* called on post-process stage after writeVisualScenes */
+ /** Called on post-process stage after writeVisualScenes. */
bool write_animation_list(const COLLADAFW::AnimationList *animlist);
+ /**
+ * \todo refactor read_node_transform to not automatically apply anything,
+ * but rather return the transform matrix, so caller can do with it what is
+ * necessary. Same for \ref get_node_mat
+ */
void read_node_transform(COLLADAFW::Node *node, Object *ob);
#if 0
virtual void change_eul_to_quat(Object *ob, bAction *act);
@@ -157,6 +164,10 @@ class AnimationImporter : private TransformReader, public AnimationImporterBase
std::map<COLLADAFW::UniqueId, const COLLADAFW::Object *> FW_object_map,
std::map<COLLADAFW::UniqueId, Material *> uid_material_map);
+ /**
+ * Check if object is animated by checking if animlist_map
+ * holds the animlist_id of node transforms.
+ */
AnimMix *get_animation_type(
const COLLADAFW::Node *node,
std::map<COLLADAFW::UniqueId, const COLLADAFW::Object *> FW_object_map);
@@ -173,18 +184,31 @@ class AnimationImporter : private TransformReader, public AnimationImporterBase
COLLADAFW::Node *node,
COLLADAFW::Transformation *tm);
+ /**
+ * Creates the rna_paths and array indices of fcurves from animations using transformation and
+ * bound animation class of each animation.
+ */
void Assign_transform_animations(COLLADAFW::Transformation *transform,
const COLLADAFW::AnimationList::AnimationBinding *binding,
std::vector<FCurve *> *curves,
bool is_joint,
char *joint_path);
+ /**
+ * Creates the rna_paths and array indices of fcurves from animations using color and bound
+ * animation class of each animation.
+ */
void Assign_color_animations(const COLLADAFW::UniqueId &listid,
ListBase *AnimCurves,
const char *anim_type);
void Assign_float_animations(const COLLADAFW::UniqueId &listid,
ListBase *AnimCurves,
const char *anim_type);
+ /**
+ * Lens animations must be stored in COLLADA by using FOV,
+ * while blender internally uses focal length.
+ * The imported animation curves must be converted appropriately.
+ */
void Assign_lens_animations(const COLLADAFW::UniqueId &listid,
ListBase *AnimCurves,
const double aspect,
@@ -194,14 +218,17 @@ class AnimationImporter : private TransformReader, public AnimationImporterBase
int setAnimType(const COLLADAFW::Animatable *prop, int type, int addition);
+ /** Sets the rna_path and array index to curve. */
void modify_fcurve(std::vector<FCurve *> *curves,
const char *rna_path,
int array_index,
int scale = 1);
void unused_fcurve(std::vector<FCurve *> *curves);
- /* prerequisites:
+ /**
+ * Prerequisites:
* animlist_map - map animlist id -> animlist
- * curve_map - map anim id -> curve(s) */
+ * curve_map - map anim id -> curve(s).
+ */
Object *translate_animation_OLD(COLLADAFW::Node *node,
std::map<COLLADAFW::UniqueId, Object *> &object_map,
std::map<COLLADAFW::UniqueId, COLLADAFW::Node *> &root_map,
@@ -209,24 +236,27 @@ class AnimationImporter : private TransformReader, public AnimationImporterBase
Object *par_job = NULL);
void find_frames(std::vector<float> *frames, std::vector<FCurve *> *curves);
+ /** Is not used anymore. */
void find_frames_old(std::vector<float> *frames,
COLLADAFW::Node *node,
COLLADAFW::Transformation::TransformationType tm_type);
- /* internal, better make it private
- * warning: evaluates only rotation
- * prerequisites: animlist_map, curve_map */
+ /**
+ * Internal, better make it private
+ * warning: evaluates only rotation and only assigns matrix transforms now
+ * prerequisites: animlist_map, curve_map.
+ */
void evaluate_transform_at_frame(float mat[4][4], COLLADAFW::Node *node, float fra);
- /* return true to indicate that mat contains a sane value */
+ /** Return true to indicate that mat contains a sane value. */
bool evaluate_animation(COLLADAFW::Transformation *tm,
float mat[4][4],
float fra,
const char *node_id);
- /* gives a world-space mat of joint at rest position */
+ /** Gives a world-space mat of joint at rest position. */
void get_joint_rest_mat(float mat[4][4], COLLADAFW::Node *root, COLLADAFW::Node *node);
- /* gives a world-space mat, end's mat not included */
+ /** * Gives a world-space mat, end's mat not included. */
bool calc_joint_parent_mat_rest(float mat[4][4],
float par[4][4],
COLLADAFW::Node *node,
@@ -239,8 +269,10 @@ class AnimationImporter : private TransformReader, public AnimationImporterBase
#endif
#if 0
- /* recursively evaluates joint tree until end is found, mat then is world-space matrix of end
- * mat must be identity on enter, node must be root */
+ /**
+ * Recursively evaluates joint tree until end is found, mat then is world-space matrix of end
+ * mat must be identity on enter, node must be root.
+ */
bool evaluate_joint_world_transform_at_frame(
float mat[4][4], float par[4][4], COLLADAFW::Node *node, COLLADAFW::Node *end, float fra);
#endif
diff --git a/source/blender/io/collada/ArmatureExporter.cpp b/source/blender/io/collada/ArmatureExporter.cpp
index 28f5f9d40bc..5da70211bfd 100644
--- a/source/blender/io/collada/ArmatureExporter.cpp
+++ b/source/blender/io/collada/ArmatureExporter.cpp
@@ -40,7 +40,6 @@
#include "GeometryExporter.h"
#include "SceneExporter.h"
-/* write bone nodes */
void ArmatureExporter::add_armature_bones(Object *ob_arm,
ViewLayer *view_layer,
SceneExporter *se,
@@ -144,7 +143,6 @@ void ArmatureExporter::find_objects_using_armature(Object *ob_arm,
}
#endif
-/* parent_mat is armature-space */
void ArmatureExporter::add_bone_node(Bone *bone,
Object *ob_arm,
SceneExporter *se,
diff --git a/source/blender/io/collada/ArmatureExporter.h b/source/blender/io/collada/ArmatureExporter.h
index b994741f342..c1b58f0071c 100644
--- a/source/blender/io/collada/ArmatureExporter.h
+++ b/source/blender/io/collada/ArmatureExporter.h
@@ -62,6 +62,7 @@ class ArmatureExporter : public COLLADASW::LibraryControllers,
{
}
+ /* write bone nodes */
void add_armature_bones(Object *ob_arm,
ViewLayer *view_layer,
SceneExporter *se,
@@ -83,8 +84,11 @@ class ArmatureExporter : public COLLADASW::LibraryControllers,
void find_objects_using_armature(Object *ob_arm, std::vector<Object *> &objects, Scene *sce);
#endif
- /* Scene, SceneExporter and the list of child_objects
- * are required for writing bone parented objects */
+ /**
+ * Scene, SceneExporter and the list of child_objects
+ * are required for writing bone parented objects.
+ * \param parent_mat: is armature-space.
+ */
void add_bone_node(Bone *bone,
Object *ob_arm,
SceneExporter *se,
diff --git a/source/blender/io/collada/ArmatureImporter.cpp b/source/blender/io/collada/ArmatureImporter.cpp
index 72fb8820be5..cfe9ed6b2e0 100644
--- a/source/blender/io/collada/ArmatureImporter.cpp
+++ b/source/blender/io/collada/ArmatureImporter.cpp
@@ -220,12 +220,6 @@ int ArmatureImporter::create_bone(SkinInfo *skin,
return chain_length + 1;
}
-/**
- * Collada only knows Joints, hence bones at the end of a bone chain
- * don't have a defined length. This function guesses reasonable
- * tail locations for the affected bones (nodes which don't have any connected child)
- * Hint: The extended_bones set gets populated in ArmatureImporter::create_bone
- */
void ArmatureImporter::fix_leaf_bone_hierarchy(bArmature *armature,
Bone *bone,
bool fix_orientation)
@@ -757,11 +751,6 @@ bool ArmatureImporter::node_is_decomposed(const COLLADAFW::Node *node)
return true;
}
-/**
- * root - if this joint is the top joint in hierarchy, if a joint
- * is a child of a node (not joint), root should be true since
- * this is where we build armature bones from
- */
void ArmatureImporter::add_root_joint(COLLADAFW::Node *node, Object *parent)
{
root_joints.push_back(node);
@@ -786,7 +775,6 @@ void ArmatureImporter::add_root_joint(COLLADAFW::Node *node)
}
#endif
-/* here we add bones to armatures, having armatures previously created in write_controller */
void ArmatureImporter::make_armatures(bContext *C, std::vector<Object *> &objects_to_scale)
{
Main *bmain = CTX_data_main(C);
@@ -1042,7 +1030,6 @@ void ArmatureImporter::get_rna_path_for_joint(COLLADAFW::Node *node,
BLI_snprintf(joint_path, count, "pose.bones[\"%s\"]", bone_name_esc);
}
-/* gives a world-space mat */
bool ArmatureImporter::get_joint_bind_mat(float m[4][4], COLLADAFW::Node *joint)
{
std::map<COLLADAFW::UniqueId, SkinInfo>::iterator it;
diff --git a/source/blender/io/collada/ArmatureImporter.h b/source/blender/io/collada/ArmatureImporter.h
index 16265e66a8e..ea78efeb5d7 100644
--- a/source/blender/io/collada/ArmatureImporter.h
+++ b/source/blender/io/collada/ArmatureImporter.h
@@ -111,6 +111,12 @@ class ArmatureImporter : private TransformReader {
std::vector<std::string> &layer_labels,
BoneExtensionMap &extended_bones);
+ /**
+ * Collada only knows Joints, hence bones at the end of a bone chain
+ * don't have a defined length. This function guesses reasonable
+ * tail locations for the affected bones (nodes which don't have any connected child)
+ * Hint: The extended_bones set gets populated in ArmatureImporter::create_bone
+ */
void fix_leaf_bone_hierarchy(bArmature *armature, Bone *bone, bool fix_orientation);
void fix_leaf_bone(bArmature *armature, EditBone *ebone, BoneExtended *be, bool fix_orientation);
void fix_parent_connect(bArmature *armature, Bone *bone);
@@ -152,15 +158,20 @@ class ArmatureImporter : private TransformReader {
const ImportSettings *import_settings);
~ArmatureImporter();
+ /**
+ * root - if this joint is the top joint in hierarchy, if a joint
+ * is a child of a node (not joint), root should be true since
+ * this is where we build armature bones from
+ */
void add_root_joint(COLLADAFW::Node *node, Object *parent);
- /* here we add bones to armatures, having armatures previously created in write_controller */
+ /** Here we add bones to armatures, having armatures previously created in write_controller. */
void make_armatures(bContext *C, std::vector<Object *> &objects_to_scale);
void make_shape_keys(bContext *C);
#if 0
- /* link with meshes, create vertex groups, assign weights */
+ /** Link with meshes, create vertex groups, assign weights. */
void link_armature(Object *ob_arm,
const COLLADAFW::UniqueId &geom_id,
const COLLADAFW::UniqueId &controller_data_id);
@@ -176,7 +187,7 @@ class ArmatureImporter : private TransformReader {
void get_rna_path_for_joint(COLLADAFW::Node *node, char *joint_path, size_t count);
- /* gives a world-space mat */
+ /** Gives a world-space mat. */
bool get_joint_bind_mat(float m[4][4], COLLADAFW::Node *joint);
void set_tags_map(TagsMap &tags_map);
diff --git a/source/blender/io/collada/BCAnimationSampler.cpp b/source/blender/io/collada/BCAnimationSampler.cpp
index 953af5adffc..a2d711050cb 100644
--- a/source/blender/io/collada/BCAnimationSampler.cpp
+++ b/source/blender/io/collada/BCAnimationSampler.cpp
@@ -418,11 +418,6 @@ void BCAnimationSampler::generate_transforms(Object *ob, Bone *bone, BCAnimation
}
}
-/**
- * Collect all keyframes from all animation curves related to the object.
- * The bc_get... functions check for NULL and correct object type.
- * The #add_keyframes_from() function checks for NULL.
- */
void BCAnimationSampler::initialize_keyframes(BCFrameSet &frameset, Object *ob)
{
frameset.clear();
@@ -517,7 +512,6 @@ BCSample &BCSampleFrame::add(Object *ob)
return *sample;
}
-/* Get the matrix for the given key, returns Unity when the key does not exist */
const BCSample *BCSampleFrame::get_sample(Object *ob) const
{
BCSampleMap::const_iterator it = sampleMap.find(ob);
@@ -537,7 +531,6 @@ const BCMatrix *BCSampleFrame::get_sample_matrix(Object *ob) const
return &sample->get_matrix();
}
-/* Get the matrix for the given Bone, returns Unity when the Object is not sampled. */
const BCMatrix *BCSampleFrame::get_sample_matrix(Object *ob, Bone *bone) const
{
BCSampleMap::const_iterator it = sampleMap.find(ob);
@@ -550,13 +543,11 @@ const BCMatrix *BCSampleFrame::get_sample_matrix(Object *ob, Bone *bone) const
return bc_bone;
}
-/* Check if the key is in this BCSampleFrame */
bool BCSampleFrame::has_sample_for(Object *ob) const
{
return sampleMap.find(ob) != sampleMap.end();
}
-/* Check if the Bone is in this BCSampleFrame */
bool BCSampleFrame::has_sample_for(Object *ob, Bone *bone) const
{
const BCMatrix *bc_bone = get_sample_matrix(ob, bone);
@@ -575,7 +566,6 @@ BCSample &BCSampleFrameContainer::add(Object *ob, int frame_index)
/* Below are the getters which we need to export the data */
/* ====================================================== */
-/* Return either the BCSampleFrame or NULL if frame does not exist. */
BCSampleFrame *BCSampleFrameContainer::get_frame(int frame_index)
{
BCSampleFrameMap::iterator it = sample_frames.find(frame_index);
@@ -583,7 +573,6 @@ BCSampleFrame *BCSampleFrameContainer::get_frame(int frame_index)
return frame;
}
-/* Return a list of all frames that need to be sampled */
int BCSampleFrameContainer::get_frames(std::vector<int> &frames) const
{
frames.clear(); /* safety; */
diff --git a/source/blender/io/collada/BCAnimationSampler.h b/source/blender/io/collada/BCAnimationSampler.h
index 19b1bc35264..c78590b8e37 100644
--- a/source/blender/io/collada/BCAnimationSampler.h
+++ b/source/blender/io/collada/BCAnimationSampler.h
@@ -89,11 +89,16 @@ class BCSampleFrame {
BCSample &add(Object *ob);
/* Following methods return NULL if object is not in the sampleMap. */
+
+ /** Get the matrix for the given key, returns Unity when the key does not exist. */
const BCSample *get_sample(Object *ob) const;
const BCMatrix *get_sample_matrix(Object *ob) const;
+ /** Get the matrix for the given Bone, returns Unity when the Object is not sampled. */
const BCMatrix *get_sample_matrix(Object *ob, Bone *bone) const;
+ /** Check if the key is in this BCSampleFrame. */
bool has_sample_for(Object *ob) const;
+ /** Check if the Bone is in this BCSampleFrame. */
bool has_sample_for(Object *ob, Bone *bone) const;
};
@@ -134,8 +139,10 @@ class BCSampleFrameContainer {
}
BCSample &add(Object *ob, int frame_index);
- BCSampleFrame *get_frame(int frame_index); /* returns NULL if frame does not exist */
+ /** Return either the #BCSampleFrame or NULL if frame does not exist. */
+ BCSampleFrame *get_frame(int frame_index);
+ /** Return a list of all frames that need to be sampled. */
int get_frames(std::vector<int> &frames) const;
int get_frames(Object *ob, BCFrames &frames) const;
int get_frames(Object *ob, Bone *bone, BCFrames &frames) const;
@@ -159,6 +166,11 @@ class BCAnimationSampler {
void generate_transforms(Object *ob, Bone *bone, BCAnimationCurveMap &curves);
void initialize_curves(BCAnimationCurveMap &curves, Object *ob);
+ /**
+ * Collect all keyframes from all animation curves related to the object.
+ * The bc_get... functions check for NULL and correct object type.
+ * The #add_keyframes_from() function checks for NULL.
+ */
void initialize_keyframes(BCFrameSet &frameset, Object *ob);
BCSample &sample_object(Object *ob, int frame_index, bool for_opensim);
void update_animation_curves(BCAnimation &animation,
diff --git a/source/blender/io/collada/BCMath.cpp b/source/blender/io/collada/BCMath.cpp
index 51c86ee53f2..c3ee3355a41 100644
--- a/source/blender/io/collada/BCMath.cpp
+++ b/source/blender/io/collada/BCMath.cpp
@@ -183,8 +183,6 @@ void BCMatrix::unit()
quat_to_eul(this->rot, this->q);
}
-/* We need double here because the OpenCollada API needs it.
- * precision = -1 indicates to not limit the precision. */
void BCMatrix::get_matrix(DMatrix &mat, const bool transposed, const int precision) const
{
for (int i = 0; i < 4; i++) {
diff --git a/source/blender/io/collada/BCMath.h b/source/blender/io/collada/BCMath.h
index c57d5c6301f..503a76541fd 100644
--- a/source/blender/io/collada/BCMath.h
+++ b/source/blender/io/collada/BCMath.h
@@ -78,6 +78,10 @@ class BCMatrix {
BCMatrix(Object *ob);
BCMatrix();
+ /**
+ * We need double here because the OpenCollada API needs it.
+ * precision = -1 indicates to not limit the precision.
+ */
void get_matrix(DMatrix &matrix, const bool transposed = false, const int precision = -1) const;
void get_matrix(Matrix &matrix,
const bool transposed = false,
diff --git a/source/blender/io/collada/BCSampleData.cpp b/source/blender/io/collada/BCSampleData.cpp
index 339dc829742..9915514dc01 100644
--- a/source/blender/io/collada/BCSampleData.cpp
+++ b/source/blender/io/collada/BCSampleData.cpp
@@ -39,7 +39,6 @@ void BCSample::add_bone_matrix(Bone *bone, Matrix &mat)
bonemats[bone] = matrix;
}
-/* Get channel value */
bool BCSample::get_value(std::string channel_target, const int array_index, float *val) const
{
std::string bname = bc_string_before(channel_target, ".");
diff --git a/source/blender/io/collada/BCSampleData.h b/source/blender/io/collada/BCSampleData.h
index 06d234e2c3e..dccc5228c4f 100644
--- a/source/blender/io/collada/BCSampleData.h
+++ b/source/blender/io/collada/BCSampleData.h
@@ -53,6 +53,7 @@ class BCSample {
void add_bone_matrix(Bone *bone, Matrix &mat);
+ /** Get channel value. */
bool get_value(std::string channel_target, const int array_index, float *val) const;
const BCMatrix &get_matrix() const;
const BCMatrix *get_matrix(Bone *bone) const; /* returns NULL if bone is not animated */
diff --git a/source/blender/io/collada/BlenderContext.cpp b/source/blender/io/collada/BlenderContext.cpp
index ab420e79ba7..2a1968d00d2 100644
--- a/source/blender/io/collada/BlenderContext.cpp
+++ b/source/blender/io/collada/BlenderContext.cpp
@@ -31,12 +31,6 @@ bool bc_is_base_node(LinkNode *export_set, Object *ob, ViewLayer *view_layer)
return (root == ob);
}
-/**
- * Returns the highest selected ancestor
- * returns NULL if no ancestor is selected
- * IMPORTANT: This function expects that all exported objects have set:
- * ob->id.tag & LIB_TAG_DOIT
- */
Object *bc_get_highest_exported_ancestor_or_self(LinkNode *export_set,
Object *ob,
ViewLayer *view_layer)
diff --git a/source/blender/io/collada/BlenderContext.h b/source/blender/io/collada/BlenderContext.h
index 9163b30c86f..86738bbd242 100644
--- a/source/blender/io/collada/BlenderContext.h
+++ b/source/blender/io/collada/BlenderContext.h
@@ -38,6 +38,12 @@ static const BC_global_up_axis BC_DEFAULT_UP = BC_GLOBAL_UP_Z;
bool bc_is_in_Export_set(LinkNode *export_set, Object *ob, ViewLayer *view_layer);
bool bc_is_base_node(LinkNode *export_set, Object *ob, ViewLayer *view_layer);
+/**
+ * Returns the highest selected ancestor
+ * returns NULL if no ancestor is selected
+ * IMPORTANT: This function expects that all exported objects have set:
+ * `ob->id.tag & LIB_TAG_DOIT`
+ */
Object *bc_get_highest_exported_ancestor_or_self(LinkNode *export_set,
Object *ob,
ViewLayer *view_layer);
diff --git a/source/blender/io/collada/ControllerExporter.cpp b/source/blender/io/collada/ControllerExporter.cpp
index d768d2e44e8..6c13c83fbc7 100644
--- a/source/blender/io/collada/ControllerExporter.cpp
+++ b/source/blender/io/collada/ControllerExporter.cpp
@@ -161,8 +161,6 @@ std::string ControllerExporter::get_controller_id(Key *key, Object *ob)
return translate_id(id_name(ob)) + MORPH_CONTROLLER_ID_SUFFIX;
}
-/* ob should be of type OB_MESH
- * both args are required */
void ControllerExporter::export_skin_controller(Object *ob, Object *ob_arm)
{
/* joint names
@@ -377,7 +375,6 @@ std::string ControllerExporter::add_morph_weights(Key *key, Object *ob)
return source_id;
}
-/* Added to implement support for animations. */
void ControllerExporter::add_weight_extras(Key *key)
{
/* can also try the base element and param alternative */
diff --git a/source/blender/io/collada/ControllerExporter.h b/source/blender/io/collada/ControllerExporter.h
index 0aec9e8d179..d262d21012b 100644
--- a/source/blender/io/collada/ControllerExporter.h
+++ b/source/blender/io/collada/ControllerExporter.h
@@ -91,8 +91,7 @@ class ControllerExporter : public COLLADASW::LibraryControllers,
std::string get_controller_id(Key *key, Object *ob);
- /* ob should be of type OB_MESH
- * both args are required */
+ /** `ob` should be of type OB_MESH, both arguments are required. */
void export_skin_controller(Object *ob, Object *ob_arm);
void export_morph_controller(Object *ob, Key *key);
@@ -107,6 +106,9 @@ class ControllerExporter : public COLLADASW::LibraryControllers,
std::string add_morph_weights(Key *key, Object *ob);
+ /**
+ * Added to implement support for animations.
+ */
void add_weight_extras(Key *key);
std::string add_joints_source(Object *ob_arm,
diff --git a/source/blender/io/collada/DocumentImporter.cpp b/source/blender/io/collada/DocumentImporter.cpp
index 35bdc0a4e06..013df2fa2b7 100644
--- a/source/blender/io/collada/DocumentImporter.cpp
+++ b/source/blender/io/collada/DocumentImporter.cpp
@@ -320,10 +320,6 @@ void DocumentImporter::translate_anim_recursive(COLLADAFW::Node *node,
}
}
-/**
- * If the imported file was made with Blender, return the Blender version used,
- * otherwise return an empty std::string
- */
std::string DocumentImporter::get_import_version(const COLLADAFW::FileInfo *asset)
{
const char AUTORING_TOOL[] = "authoring_tool";
@@ -347,10 +343,6 @@ std::string DocumentImporter::get_import_version(const COLLADAFW::FileInfo *asse
return "";
}
-/**
- * When this method is called, the writer must write the global document asset.
- * \return The writer should return true, if writing succeeded, false otherwise.
- */
bool DocumentImporter::writeGlobalAsset(const COLLADAFW::FileInfo *asset)
{
unit_converter.read_asset(asset);
@@ -359,10 +351,6 @@ bool DocumentImporter::writeGlobalAsset(const COLLADAFW::FileInfo *asset)
return true;
}
-/**
- * When this method is called, the writer must write the scene.
- * \return The writer should return true, if writing succeeded, false otherwise.
- */
bool DocumentImporter::writeScene(const COLLADAFW::Scene *scene)
{
/* XXX could store the scene id, but do nothing for now */
@@ -476,8 +464,6 @@ Object *DocumentImporter::create_instance_node(Object *source_ob,
return obn;
}
-/* to create constraints off node <extra> tags. Assumes only constraint data in
- * current <extra> with blender profile. */
void DocumentImporter::create_constraints(ExtraTags *et, Object *ob)
{
if (et && et->isProfile("blender")) {
@@ -712,10 +698,6 @@ finally:
return root_objects;
}
-/**
- * When this method is called, the writer must write the entire visual scene.
- * Return The writer should return true, if writing succeeded, false otherwise.
- */
bool DocumentImporter::writeVisualScene(const COLLADAFW::VisualScene *visualScene)
{
if (mImportStage == Fetching_Controller_data) {
@@ -738,11 +720,6 @@ bool DocumentImporter::writeVisualScene(const COLLADAFW::VisualScene *visualScen
return true;
}
-/**
- * When this method is called, the writer must handle all nodes contained in the
- * library nodes.
- * \return The writer should return true, if writing succeeded, false otherwise.
- */
bool DocumentImporter::writeLibraryNodes(const COLLADAFW::LibraryNodes *libraryNodes)
{
if (mImportStage == Fetching_Controller_data) {
@@ -762,10 +739,6 @@ bool DocumentImporter::writeLibraryNodes(const COLLADAFW::LibraryNodes *libraryN
return true;
}
-/**
- * When this method is called, the writer must write the geometry.
- * \return The writer should return true, if writing succeeded, false otherwise.
- */
bool DocumentImporter::writeGeometry(const COLLADAFW::Geometry *geom)
{
if (mImportStage == Fetching_Controller_data) {
@@ -775,10 +748,6 @@ bool DocumentImporter::writeGeometry(const COLLADAFW::Geometry *geom)
return mesh_importer.write_geometry(geom);
}
-/**
- * When this method is called, the writer must write the material.
- * \return The writer should return true, if writing succeeded, false otherwise.
- */
bool DocumentImporter::writeMaterial(const COLLADAFW::Material *cmat)
{
if (mImportStage == Fetching_Controller_data) {
@@ -821,10 +790,6 @@ void DocumentImporter::write_profile_COMMON(COLLADAFW::EffectCommon *ef, Materia
matNode.update_material_nodetree();
}
-/**
- * When this method is called, the writer must write the effect.
- * \return The writer should return true, if writing succeeded, false otherwise.
- */
bool DocumentImporter::writeEffect(const COLLADAFW::Effect *effect)
{
if (mImportStage == Fetching_Controller_data) {
@@ -860,10 +825,6 @@ bool DocumentImporter::writeEffect(const COLLADAFW::Effect *effect)
return true;
}
-/**
- * When this method is called, the writer must write the camera.
- * \return The writer should return true, if writing succeeded, false otherwise.
- */
bool DocumentImporter::writeCamera(const COLLADAFW::Camera *camera)
{
if (mImportStage == Fetching_Controller_data) {
@@ -973,10 +934,6 @@ bool DocumentImporter::writeCamera(const COLLADAFW::Camera *camera)
return true;
}
-/**
- * When this method is called, the writer must write the image.
- * \return The writer should return true, if writing succeeded, false otherwise.
- */
bool DocumentImporter::writeImage(const COLLADAFW::Image *image)
{
if (mImportStage == Fetching_Controller_data) {
@@ -1013,10 +970,6 @@ bool DocumentImporter::writeImage(const COLLADAFW::Image *image)
return true;
}
-/**
- * When this method is called, the writer must write the light.
- * \return The writer should return true, if writing succeeded, false otherwise.
- */
bool DocumentImporter::writeLight(const COLLADAFW::Light *light)
{
if (mImportStage == Fetching_Controller_data) {
@@ -1164,7 +1117,6 @@ bool DocumentImporter::writeLight(const COLLADAFW::Light *light)
return true;
}
-/* this function is called only for animations that pass COLLADAFW::validate */
bool DocumentImporter::writeAnimation(const COLLADAFW::Animation *anim)
{
if (mImportStage == Fetching_Controller_data) {
@@ -1174,7 +1126,6 @@ bool DocumentImporter::writeAnimation(const COLLADAFW::Animation *anim)
return anim_importer.write_animation(anim);
}
-/* called on post-process stage after writeVisualScenes */
bool DocumentImporter::writeAnimationList(const COLLADAFW::AnimationList *animationList)
{
if (mImportStage == Fetching_Controller_data) {
@@ -1186,10 +1137,10 @@ bool DocumentImporter::writeAnimationList(const COLLADAFW::AnimationList *animat
}
#if WITH_OPENCOLLADA_ANIMATION_CLIP
-/* Since opencollada 1.6.68
- * called on post-process stage after writeVisualScenes */
bool DocumentImporter::writeAnimationClip(const COLLADAFW::AnimationClip *animationClip)
{
+ /* Since opencollada 1.6.68: called on post-process stage after writeVisualScenes. */
+
if (mImportStage == Fetching_Controller_data) {
return true;
}
@@ -1200,16 +1151,11 @@ bool DocumentImporter::writeAnimationClip(const COLLADAFW::AnimationClip *animat
}
#endif
-/**
- * When this method is called, the writer must write the skin controller data.
- * \return The writer should return true, if writing succeeded, false otherwise.
- */
bool DocumentImporter::writeSkinControllerData(const COLLADAFW::SkinControllerData *skin)
{
return armature_importer.write_skin_controller_data(skin);
}
-/* this is called on postprocess, before writeVisualScenes */
bool DocumentImporter::writeController(const COLLADAFW::Controller *controller)
{
if (mImportStage == Fetching_Controller_data) {
diff --git a/source/blender/io/collada/DocumentImporter.h b/source/blender/io/collada/DocumentImporter.h
index 8e553f1ce7a..63faaca4711 100644
--- a/source/blender/io/collada/DocumentImporter.h
+++ b/source/blender/io/collada/DocumentImporter.h
@@ -64,6 +64,10 @@ class DocumentImporter : COLLADAFW::IWriter {
Object *create_camera_object(COLLADAFW::InstanceCamera *, Scene *);
Object *create_light_object(COLLADAFW::InstanceLight *, Scene *);
Object *create_instance_node(Object *, COLLADAFW::Node *, COLLADAFW::Node *, Scene *, bool);
+ /**
+ * To create constraints off node <extra> tags. Assumes only constraint data in
+ * current <extra> with blender profile.
+ */
void create_constraints(ExtraTags *et, Object *ob);
std::vector<Object *> *write_node(COLLADAFW::Node *, COLLADAFW::Node *, Scene *, Object *, bool);
void write_profile_COMMON(COLLADAFW::EffectCommon *, Material *);
@@ -86,17 +90,44 @@ class DocumentImporter : COLLADAFW::IWriter {
*/
void finish();
+ /**
+ * When this method is called, the writer must write the global document asset.
+ * \return The writer should return true, if writing succeeded, false otherwise.
+ */
bool writeGlobalAsset(const COLLADAFW::FileInfo *);
+ /**
+ * If the imported file was made with Blender, return the Blender version used,
+ * otherwise return an empty std::string
+ */
std::string get_import_version(const COLLADAFW::FileInfo *asset);
+ /**
+ * When this method is called, the writer must write the scene.
+ * \return The writer should return true, if writing succeeded, false otherwise.
+ */
bool writeScene(const COLLADAFW::Scene *);
+ /**
+ * When this method is called, the writer must write the entire visual scene.
+ * Return The writer should return true, if writing succeeded, false otherwise.
+ */
bool writeVisualScene(const COLLADAFW::VisualScene *);
+ /**
+ * When this method is called, the writer must handle all nodes contained in the
+ * library nodes.
+ * \return The writer should return true, if writing succeeded, false otherwise.
+ */
bool writeLibraryNodes(const COLLADAFW::LibraryNodes *);
+ /**
+ * This function is called only for animations that pass COLLADAFW::validate.
+ */
bool writeAnimation(const COLLADAFW::Animation *);
+ /**
+ * Called on post-process stage after writeVisualScenes.
+ */
bool writeAnimationList(const COLLADAFW::AnimationList *);
#if WITH_OPENCOLLADA_ANIMATION_CLIP
@@ -105,20 +136,49 @@ class DocumentImporter : COLLADAFW::IWriter {
bool writeAnimationClip(const COLLADAFW::AnimationClip *animationClip);
#endif
+ /**
+ * When this method is called, the writer must write the geometry.
+ * \return The writer should return true, if writing succeeded, false otherwise.
+ */
bool writeGeometry(const COLLADAFW::Geometry *);
+ /**
+ * When this method is called, the writer must write the material.
+ * \return The writer should return true, if writing succeeded, false otherwise.
+ */
bool writeMaterial(const COLLADAFW::Material *);
+ /**
+ * When this method is called, the writer must write the effect.
+ * \return The writer should return true, if writing succeeded, false otherwise.
+ */
bool writeEffect(const COLLADAFW::Effect *);
+ /**
+ * When this method is called, the writer must write the camera.
+ * \return The writer should return true, if writing succeeded, false otherwise.
+ */
bool writeCamera(const COLLADAFW::Camera *);
+ /**
+ * When this method is called, the writer must write the image.
+ * \return The writer should return true, if writing succeeded, false otherwise.
+ */
bool writeImage(const COLLADAFW::Image *);
+ /**
+ * When this method is called, the writer must write the light.
+ * \return The writer should return true, if writing succeeded, false otherwise.
+ */
bool writeLight(const COLLADAFW::Light *);
+ /**
+ * When this method is called, the writer must write the skin controller data.
+ * \return The writer should return true, if writing succeeded, false otherwise.
+ */
bool writeSkinControllerData(const COLLADAFW::SkinControllerData *);
+ /** This is called on post-process, before writeVisualScenes. */
bool writeController(const COLLADAFW::Controller *);
bool writeFormulas(const COLLADAFW::Formulas *);
diff --git a/source/blender/io/collada/GeometryExporter.cpp b/source/blender/io/collada/GeometryExporter.cpp
index 382bb8a6e36..eeee220fd2c 100644
--- a/source/blender/io/collada/GeometryExporter.cpp
+++ b/source/blender/io/collada/GeometryExporter.cpp
@@ -324,7 +324,6 @@ std::string GeometryExporter::makeVertexColorSourceId(std::string &geom_id, char
return result;
}
-/* powerful because it handles both cases when there is material and when there's not */
void GeometryExporter::create_mesh_primitive_list(short material_index,
bool has_uvs,
bool has_color,
@@ -441,7 +440,6 @@ void GeometryExporter::create_mesh_primitive_list(short material_index,
finish_and_delete_primitive_List(is_triangulated, primitive_list);
}
-/* creates <source> for positions */
void GeometryExporter::createVertsSource(std::string geom_id, Mesh *me)
{
#if 0
@@ -542,7 +540,6 @@ std::string GeometryExporter::makeTexcoordSourceId(std::string &geom_id,
return getIdBySemantics(geom_id, COLLADASW::InputSemantic::TEXCOORD) + suffix;
}
-/* creates <source> for texcoords */
void GeometryExporter::createTexcoordsSource(std::string geom_id, Mesh *me)
{
@@ -593,7 +590,6 @@ bool operator<(const Normal &a, const Normal &b)
return a.x < b.x || (a.x == b.x && (a.y < b.y || (a.y == b.y && a.z < b.z)));
}
-/* creates <source> for normals */
void GeometryExporter::createNormalsSource(std::string geom_id, Mesh *me, std::vector<Normal> &nor)
{
#if 0
diff --git a/source/blender/io/collada/GeometryExporter.h b/source/blender/io/collada/GeometryExporter.h
index 948aafa760d..e6e08f2b977 100644
--- a/source/blender/io/collada/GeometryExporter.h
+++ b/source/blender/io/collada/GeometryExporter.h
@@ -72,7 +72,7 @@ class GeometryExporter : COLLADASW::LibraryGeometries {
void createLooseEdgeList(Object *ob, Mesh *me, std::string &geom_id);
- /* powerful because it handles both cases when there is material and when there's not */
+ /** Powerful because it handles both cases when there is material and when there's not. */
void create_mesh_primitive_list(short material_index,
bool has_uvs,
bool has_color,
@@ -81,17 +81,17 @@ class GeometryExporter : COLLADASW::LibraryGeometries {
std::string &geom_id,
std::vector<BCPolygonNormalsIndices> &norind);
- /* creates <source> for positions */
+ /** Creates <source> for positions. */
void createVertsSource(std::string geom_id, Mesh *me);
void createVertexColorSource(std::string geom_id, Mesh *me);
std::string makeTexcoordSourceId(std::string &geom_id, int layer_index, bool is_single_layer);
- /* creates <source> for texcoords */
+ /** Creates <source> for texcoords. */
void createTexcoordsSource(std::string geom_id, Mesh *me);
- /* creates <source> for normals */
+ /** Creates <source> for normals. */
void createNormalsSource(std::string geom_id, Mesh *me, std::vector<Normal> &nor);
void create_normals(std::vector<Normal> &nor,
diff --git a/source/blender/io/collada/Materials.cpp b/source/blender/io/collada/Materials.cpp
index 81f0cc608d2..1f358accc4e 100644
--- a/source/blender/io/collada/Materials.cpp
+++ b/source/blender/io/collada/Materials.cpp
@@ -91,7 +91,6 @@ void MaterialNode::setShaderType()
#endif
}
-/* returns null if material already has a node tree */
bNodeTree *MaterialNode::prepare_material_nodetree()
{
if (material->nodetree) {
diff --git a/source/blender/io/collada/Materials.h b/source/blender/io/collada/Materials.h
index 1886acb7a6a..e68f67bf049 100644
--- a/source/blender/io/collada/Materials.h
+++ b/source/blender/io/collada/Materials.h
@@ -45,6 +45,7 @@ class MaterialNode {
bNode *shader_node;
bNode *output_node;
+ /** Returns null if material already has a node tree. */
bNodeTree *prepare_material_nodetree();
bNode *add_node(int node_type, int locx, int locy, std::string label);
void add_link(bNode *from_node, int from_index, bNode *to_node, int to_index);
diff --git a/source/blender/io/collada/MeshImporter.cpp b/source/blender/io/collada/MeshImporter.cpp
index ef486375ce3..036819af6a3 100644
--- a/source/blender/io/collada/MeshImporter.cpp
+++ b/source/blender/io/collada/MeshImporter.cpp
@@ -267,7 +267,6 @@ void MeshImporter::print_index_list(COLLADAFW::IndexList &index_list)
}
#endif
-/* checks if mesh has supported primitive types: lines, polylist, triangles, triangle_fans */
bool MeshImporter::is_nice_mesh(COLLADAFW::Mesh *mesh)
{
COLLADAFW::MeshPrimitiveArray &prim_arr = mesh->getMeshPrimitives();
@@ -356,12 +355,6 @@ void MeshImporter::read_vertices(COLLADAFW::Mesh *mesh, Mesh *me)
}
}
-/* =====================================================================
- * condition 1: The Primitive has normals
- * condition 2: The number of normals equals the number of faces.
- * return true if both conditions apply.
- * return false otherwise.
- * ===================================================================== */
bool MeshImporter::primitive_has_useable_normals(COLLADAFW::MeshPrimitive *mp)
{
@@ -385,10 +378,6 @@ bool MeshImporter::primitive_has_useable_normals(COLLADAFW::MeshPrimitive *mp)
return has_useable_normals;
}
-/* =====================================================================
- * Assume that only TRIANGLES, TRIANGLE_FANS, POLYLIST and POLYGONS
- * have faces. (to be verified)
- * ===================================================================== */
bool MeshImporter::primitive_has_faces(COLLADAFW::MeshPrimitive *mp)
{
@@ -420,12 +409,6 @@ static std::string extract_vcolname(const COLLADAFW::String &collada_id)
return colname;
}
-/* =================================================================
- * Return the number of faces by summing up
- * the face-counts of the parts.
- * hint: This is done because `mesh->getFacesCount()` does
- * count loose edges as extra faces, which is not what we want here.
- * ================================================================= */
void MeshImporter::allocate_poly_data(COLLADAFW::Mesh *collada_mesh, Mesh *me)
{
COLLADAFW::MeshPrimitiveArray &prim_arr = collada_mesh->getMeshPrimitives();
@@ -554,13 +537,6 @@ unsigned int MeshImporter::get_loose_edge_count(COLLADAFW::Mesh *mesh)
return loose_edge_count;
}
-/* =================================================================
- * This function is copied from source/blender/editors/mesh/mesh_data.c
- *
- * TODO: (As discussed with sergey-) :
- * Maybe move this function to blenderkernel/intern/mesh.c
- * and add definition to BKE_mesh.c
- * ================================================================= */
void MeshImporter::mesh_add_edges(Mesh *mesh, int len)
{
CustomData edata;
@@ -594,12 +570,6 @@ void MeshImporter::mesh_add_edges(Mesh *mesh, int len)
mesh->totedge = totedge;
}
-/* =================================================================
- * Read all loose edges.
- * Important: This function assumes that all edges from existing
- * faces have already been generated and added to me->medge
- * So this function MUST be called after read_faces() (see below)
- * ================================================================= */
void MeshImporter::read_lines(COLLADAFW::Mesh *mesh, Mesh *me)
{
unsigned int loose_edge_count = get_loose_edge_count(mesh);
@@ -633,13 +603,6 @@ void MeshImporter::read_lines(COLLADAFW::Mesh *mesh, Mesh *me)
}
}
-/* =======================================================================
- * Read all faces from TRIANGLES, TRIANGLE_FANS, POLYLIST, POLYGON
- * Important: This function MUST be called before read_lines()
- * Otherwise we will lose all edges from faces (see read_lines() above)
- *
- * TODO: import uv set names
- * ======================================================================== */
void MeshImporter::read_polys(COLLADAFW::Mesh *collada_mesh, Mesh *me)
{
unsigned int i;
@@ -965,11 +928,6 @@ static void bc_remove_materials_from_object(Object *ob, Mesh *me)
}
}
-/**
- * Returns the list of Users of the given Mesh object.
- * NOTE: This function uses the object user flag to control
- * which objects have already been processed.
- */
std::vector<Object *> MeshImporter::get_all_users_of(Mesh *reference_mesh)
{
std::vector<Object *> mesh_users;
@@ -985,24 +943,6 @@ std::vector<Object *> MeshImporter::get_all_users_of(Mesh *reference_mesh)
return mesh_users;
}
-/**
- *
- * During import all materials have been assigned to Object.
- * Now we iterate over the imported objects and optimize
- * the assignments as follows:
- *
- * for each imported geometry:
- * if number of users is 1:
- * get the user (object)
- * move the materials from Object to Data
- * else:
- * determine which materials are assigned to the first user
- * check if all other users have the same materials in the same order
- * if the check is positive:
- * Add the materials of the first user to the geometry
- * adjust all other users accordingly.
- *
- */
void MeshImporter::optimize_material_assignements()
{
for (Object *ob : imported_objects) {
@@ -1035,14 +975,6 @@ void MeshImporter::optimize_material_assignements()
}
}
-/**
- * We do not know in advance which objects will share geometries.
- * And we do not know either if the objects which share geometries
- * come along with different materials. So we first create the objects
- * and assign the materials to Object, then in a later cleanup we decide
- * which materials shall be moved to the created geometries. Also see
- * optimize_material_assignements() above.
- */
void MeshImporter::assign_material_to_geom(
COLLADAFW::MaterialBinding cmaterial,
std::map<COLLADAFW::UniqueId, Material *> &uid_material_map,
@@ -1165,7 +1097,6 @@ Object *MeshImporter::create_mesh_object(
return ob;
}
-/* create a mesh storing a pointer in a map so it can be retrieved later by geometry UID */
bool MeshImporter::write_geometry(const COLLADAFW::Geometry *geom)
{
diff --git a/source/blender/io/collada/MeshImporter.h b/source/blender/io/collada/MeshImporter.h
index 6f4f62b7f0f..95ac32a1b4c 100644
--- a/source/blender/io/collada/MeshImporter.h
+++ b/source/blender/io/collada/MeshImporter.h
@@ -122,23 +122,60 @@ class MeshImporter : public MeshImporterBase {
void print_index_list(COLLADAFW::IndexList &index_list);
#endif
+ /** Checks if mesh has supported primitive types: lines, polylist, triangles, triangle_fans. */
bool is_nice_mesh(COLLADAFW::Mesh *mesh);
void read_vertices(COLLADAFW::Mesh *mesh, Mesh *me);
+ /**
+ * Condition 1: The Primitive has normals
+ * condition 2: The number of normals equals the number of faces.
+ * return true if both conditions apply.
+ * return false otherwise.
+ */
bool primitive_has_useable_normals(COLLADAFW::MeshPrimitive *mp);
+ /**
+ * Assume that only TRIANGLES, TRIANGLE_FANS, POLYLIST and POLYGONS
+ * have faces. (to be verified).
+ */
bool primitive_has_faces(COLLADAFW::MeshPrimitive *mp);
+ /**
+ * This function is copied from source/blender/editors/mesh/mesh_data.c
+ *
+ * TODO: (As discussed with sergey-) :
+ * Maybe move this function to `blenderkernel/intern/mesh.c`.
+ * and add definition to BKE_mesh.c.
+ */
static void mesh_add_edges(Mesh *mesh, int len);
unsigned int get_loose_edge_count(COLLADAFW::Mesh *mesh);
CustomData create_edge_custom_data(EdgeHash *eh);
+ /**
+ * Return the number of faces by summing up
+ * the face-counts of the parts.
+ * hint: This is done because `mesh->getFacesCount()` does
+ * count loose edges as extra faces, which is not what we want here.
+ */
void allocate_poly_data(COLLADAFW::Mesh *collada_mesh, Mesh *me);
/* TODO: import uv set names */
+ /**
+ * Read all faces from TRIANGLES, TRIANGLE_FANS, POLYLIST, POLYGON
+ * Important: This function MUST be called before read_lines()
+ * Otherwise we will lose all edges from faces (see read_lines() above)
+ *
+ * TODO: import uv set names.
+ */
void read_polys(COLLADAFW::Mesh *mesh, Mesh *me);
+ /**
+ * Read all loose edges.
+ * Important: This function assumes that all edges from existing
+ * faces have already been generated and added to me->medge
+ * So this function MUST be called after read_faces() (see below)
+ */
void read_lines(COLLADAFW::Mesh *mesh, Mesh *me);
unsigned int get_vertex_count(COLLADAFW::Polygons *mp, int index);
@@ -146,6 +183,11 @@ class MeshImporter : public MeshImporterBase {
bool is_flat_face(unsigned int *nind, COLLADAFW::MeshVertexData &nor, int count);
+ /**
+ * Returns the list of Users of the given Mesh object.
+ * NOTE: This function uses the object user flag to control
+ * which objects have already been processed.
+ */
std::vector<Object *> get_all_users_of(Mesh *reference_mesh);
public:
@@ -159,8 +201,34 @@ class MeshImporter : public MeshImporterBase {
virtual Mesh *get_mesh_by_geom_uid(const COLLADAFW::UniqueId &geom_uid);
+ /**
+ *
+ * During import all materials have been assigned to Object.
+ * Now we iterate over the imported objects and optimize
+ * the assignments as follows:
+ *
+ * for each imported geometry:
+ * if number of users is 1:
+ * get the user (object)
+ * move the materials from Object to Data
+ * else:
+ * determine which materials are assigned to the first user
+ * check if all other users have the same materials in the same order
+ * if the check is positive:
+ * Add the materials of the first user to the geometry
+ * adjust all other users accordingly.
+ *
+ */
void optimize_material_assignements();
+ /**
+ * We do not know in advance which objects will share geometries.
+ * And we do not know either if the objects which share geometries
+ * come along with different materials. So we first create the objects
+ * and assign the materials to Object, then in a later cleanup we decide
+ * which materials shall be moved to the created geometries. Also see
+ * optimize_material_assignements() above.
+ */
void assign_material_to_geom(COLLADAFW::MaterialBinding cmaterial,
std::map<COLLADAFW::UniqueId, Material *> &uid_material_map,
Object *ob,
@@ -172,7 +240,7 @@ class MeshImporter : public MeshImporterBase {
bool isController,
std::map<COLLADAFW::UniqueId, Material *> &uid_material_map);
- /* create a mesh storing a pointer in a map so it can be retrieved later by geometry UID */
+ /** Create a mesh storing a pointer in a map so it can be retrieved later by geometry UID. */
bool write_geometry(const COLLADAFW::Geometry *geom);
std::string *get_geometry_name(const std::string &mesh_name);
};
diff --git a/source/blender/io/collada/SkinInfo.cpp b/source/blender/io/collada/SkinInfo.cpp
index f0e1c5e4c26..3b740b9cd8c 100644
--- a/source/blender/io/collada/SkinInfo.cpp
+++ b/source/blender/io/collada/SkinInfo.cpp
@@ -53,9 +53,6 @@ template<class T> static const char *bc_get_joint_name(T *node)
return id.empty() ? node->getOriginalId().c_str() : id.c_str();
}
-/* This is used to store data passed in write_controller_data.
- * Arrays from COLLADAFW::SkinControllerData lose ownership, so do this class members
- * so that arrays don't get freed until we free them explicitly. */
SkinInfo::SkinInfo() = default;
SkinInfo::SkinInfo(const SkinInfo &skin)
@@ -77,7 +74,6 @@ SkinInfo::SkinInfo(UnitConverter *conv) : unit_converter(conv), ob_arm(nullptr),
{
}
-/* nobody owns the data after this, so it should be freed manually with releaseMemory */
template<class T> void SkinInfo::transfer_array_data(T &src, T &dest)
{
dest.setData(src.getData(), src.getCount());
@@ -85,7 +81,6 @@ template<class T> void SkinInfo::transfer_array_data(T &src, T &dest)
dest.yieldOwnerShip();
}
-/* when src is const we cannot src.yieldOwnerShip, this is used by copy constructor */
void SkinInfo::transfer_int_array_data_const(const COLLADAFW::IntValuesArray &src,
COLLADAFW::IntValuesArray &dest)
{
@@ -124,9 +119,6 @@ void SkinInfo::free()
// weights.releaseMemory();
}
-/* using inverse bind matrices to construct armature
- * it is safe to invert them to get the original matrices
- * because if they are inverse matrices, they can be inverted */
void SkinInfo::add_joint(const COLLADABU::Math::Matrix4 &matrix)
{
JointData jd;
@@ -152,7 +144,6 @@ void SkinInfo::set_controller(const COLLADAFW::SkinController *co)
}
}
-/* called from write_controller */
Object *SkinInfo::create_armature(Main *bmain, Scene *scene, ViewLayer *view_layer)
{
ob_arm = bc_add_object(bmain, scene, view_layer, OB_ARMATURE, nullptr);
@@ -193,11 +184,6 @@ const COLLADAFW::UniqueId &SkinInfo::get_controller_uid()
return controller_uid;
}
-/* check if this skin controller references a joint or any descendant of it
- *
- * some nodes may not be referenced by SkinController,
- * in this case to determine if the node belongs to this armature,
- * we need to search down the tree */
bool SkinInfo::uses_joint_or_descendant(COLLADAFW::Node *node)
{
const COLLADAFW::UniqueId &uid = node->getUniqueId();
diff --git a/source/blender/io/collada/SkinInfo.h b/source/blender/io/collada/SkinInfo.h
index 7ce66b22a5f..49a820f2fcd 100644
--- a/source/blender/io/collada/SkinInfo.h
+++ b/source/blender/io/collada/SkinInfo.h
@@ -35,9 +35,11 @@
#include "TransformReader.h"
#include "collada_internal.h"
-/* This is used to store data passed in write_controller_data.
- * Arrays from COLLADAFW::SkinControllerData lose ownership, so do this class members
- * so that arrays don't get freed until we free them explicitly. */
+/**
+ * This is used to store data passed in write_controller_data.
+ * Arrays from #COLLADAFW::SkinControllerData lose ownership, so do this class members
+ * so that arrays don't get freed until we free them explicitly.
+ */
class SkinInfo {
private:
/* to build armature bones from inverse bind matrices */
@@ -69,10 +71,10 @@ class SkinInfo {
SkinInfo(const SkinInfo &skin);
SkinInfo(UnitConverter *conv);
- /* nobody owns the data after this, so it should be freed manually with releaseMemory */
+ /** Nobody owns the data after this, so it should be freed manually with releaseMemory. */
template<typename T> void transfer_array_data(T &src, T &dest);
- /* when src is const we cannot src.yieldOwnerShip, this is used by copy constructor */
+ /** When src is const we cannot `src.yieldOwnerShip`, this is used by copy constructor. */
void transfer_int_array_data_const(const COLLADAFW::IntValuesArray &src,
COLLADAFW::IntValuesArray &dest);
@@ -83,14 +85,16 @@ class SkinInfo {
void free();
- /* using inverse bind matrices to construct armature
+ /**
+ * Using inverse bind matrices to construct armature
* it is safe to invert them to get the original matrices
- * because if they are inverse matrices, they can be inverted */
+ * because if they are inverse matrices, they can be inverted.
+ */
void add_joint(const COLLADABU::Math::Matrix4 &matrix);
void set_controller(const COLLADAFW::SkinController *co);
- /* called from write_controller */
+ /** Called from write_controller. */
Object *create_armature(Main *bmain, Scene *scene, ViewLayer *view_layer);
Object *set_armature(Object *ob_arm);
@@ -101,11 +105,13 @@ class SkinInfo {
const COLLADAFW::UniqueId &get_controller_uid();
- /* check if this skin controller references a joint or any descendant of it
+ /**
+ * Check if this skin controller references a joint or any descendant of it
*
* some nodes may not be referenced by SkinController,
* in this case to determine if the node belongs to this armature,
- * we need to search down the tree */
+ * we need to search down the tree.
+ */
bool uses_joint_or_descendant(COLLADAFW::Node *node);
void link_armature(bContext *C,
diff --git a/source/blender/io/collada/collada_internal.cpp b/source/blender/io/collada/collada_internal.cpp
index bd6f496c8ec..5592f5393a2 100644
--- a/source/blender/io/collada/collada_internal.cpp
+++ b/source/blender/io/collada/collada_internal.cpp
@@ -213,7 +213,6 @@ void clear_global_id_map()
global_id_map.clear();
}
-/** Look at documentation of translate_map */
std::string translate_id(const char *idString)
{
std::string id = std::string(idString);
diff --git a/source/blender/io/collada/collada_internal.h b/source/blender/io/collada/collada_internal.h
index e3894093507..cdd19ebe9a7 100644
--- a/source/blender/io/collada/collada_internal.h
+++ b/source/blender/io/collada/collada_internal.h
@@ -76,6 +76,7 @@ class UnitConverter {
extern void clear_global_id_map();
/** Look at documentation of translate_map */
extern std::string translate_id(const std::string &id);
+/** Look at documentation of translate_map */
extern std::string translate_id(const char *idString);
extern std::string id_name(void *id);
diff --git a/source/blender/io/collada/collada_utils.cpp b/source/blender/io/collada/collada_utils.cpp
index c1f25ea9a26..d3655c10655 100644
--- a/source/blender/io/collada/collada_utils.cpp
+++ b/source/blender/io/collada/collada_utils.cpp
@@ -92,9 +92,10 @@ float bc_get_float_value(const COLLADAFW::FloatOrDoubleArray &array, unsigned in
return array.getDoubleValues()->getData()[index];
}
-/* copied from /editors/object/object_relations.c */
int bc_test_parent_loop(Object *par, Object *ob)
{
+ /* Copied from /editors/object/object_relations.c */
+
/* test if 'ob' is a parent somewhere in par's parents */
if (par == nullptr) {
@@ -289,9 +290,10 @@ bool bc_has_object_type(LinkNode *export_set, short obtype)
return false;
}
-/* Use bubble sort algorithm for sorting the export set */
void bc_bubble_sort_by_Object_name(LinkNode *export_set)
{
+ /* Use bubble sort algorithm for sorting the export set. */
+
bool sorted = false;
LinkNode *node;
for (node = export_set; node->next && !sorted; node = node->next) {
@@ -312,11 +314,6 @@ void bc_bubble_sort_by_Object_name(LinkNode *export_set)
}
}
-/* Check if a bone is the top most exportable bone in the bone hierarchy.
- * When deform_bones_only == false, then only bones with NO parent
- * can be root bones. Otherwise the top most deform bones in the hierarchy
- * are root bones.
- */
bool bc_is_root_bone(Bone *aBone, bool deform_bones_only)
{
if (deform_bones_only) {
@@ -360,12 +357,6 @@ std::string bc_replace_string(std::string data,
return data;
}
-/**
- * Calculate a rescale factor such that the imported scene's scale
- * is preserved. I.e. 1 meter in the import will also be
- * 1 meter in the current scene.
- */
-
void bc_match_scale(Object *ob, UnitConverter &bc_unit, bool scale_to_scene)
{
if (scale_to_scene) {
@@ -386,9 +377,6 @@ void bc_match_scale(std::vector<Object *> *objects_done,
}
}
-/*
- * Convenience function to get only the needed components of a matrix
- */
void bc_decompose(float mat[4][4], float *loc, float eul[3], float quat[4], float *size)
{
if (size) {
@@ -408,17 +396,6 @@ void bc_decompose(float mat[4][4], float *loc, float eul[3], float quat[4], floa
}
}
-/*
- * Create rotation_quaternion from a delta rotation and a reference quat
- *
- * Input:
- * mat_from: The rotation matrix before rotation
- * mat_to : The rotation matrix after rotation
- * qref : the quat corresponding to mat_from
- *
- * Output:
- * rot : the calculated result (quaternion)
- */
void bc_rotate_from_reference_quat(float quat_to[4], float quat_from[4], float mat_to[4][4])
{
float qd[4];
@@ -457,9 +434,6 @@ void bc_triangulate_mesh(Mesh *me)
BM_mesh_free(bm);
}
-/*
- * A bone is a leaf when it has no children or all children are not connected.
- */
bool bc_is_leaf_bone(Bone *bone)
{
for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) {
@@ -501,11 +475,6 @@ int bc_set_layer(int bitfield, int layer, bool enable)
return bitfield;
}
-/**
- * This method creates a new extension map when needed.
- * \note The ~BoneExtensionManager destructor takes care
- * to delete the created maps when the manager is removed.
- */
BoneExtensionMap &BoneExtensionManager::getExtensionMap(bArmature *armature)
{
std::string key = armature->id.name;
@@ -535,7 +504,6 @@ BoneExtensionManager::~BoneExtensionManager()
* See ArmatureImporter::fix_leaf_bones()
* and ArmatureImporter::connect_bone_chains()
*/
-
BoneExtended::BoneExtended(EditBone *aBone)
{
this->set_name(aBone->name);
@@ -697,9 +665,6 @@ int BoneExtended::get_use_connect()
return this->use_connect;
}
-/**
- * Stores a 4*4 matrix as a custom bone property array of size 16
- */
void bc_set_IDPropertyMatrix(EditBone *ebone, const char *key, float mat[4][4])
{
IDProperty *idgroup = (IDProperty *)ebone->prop;
@@ -745,19 +710,11 @@ static void bc_set_IDProperty(EditBone *ebone, const char *key, float value)
}
#endif
-/**
- * Get a custom property when it exists.
- * This function is also used to check if a property exists.
- */
IDProperty *bc_get_IDProperty(Bone *bone, std::string key)
{
return (bone->prop == nullptr) ? nullptr : IDP_GetPropertyFromGroup(bone->prop, key.c_str());
}
-/**
- * Read a custom bone property and convert to float
- * Return def if the property does not exist.
- */
float bc_get_property(Bone *bone, std::string key, float def)
{
float result = def;
@@ -780,14 +737,6 @@ float bc_get_property(Bone *bone, std::string key, float def)
return result;
}
-/**
- * Read a custom bone property and convert to matrix
- * Return true if conversion was successful
- *
- * Return false if:
- * - the property does not exist
- * - is not an array of size 16
- */
bool bc_get_property_matrix(Bone *bone, std::string key, float mat[4][4])
{
IDProperty *property = bc_get_IDProperty(bone, key);
@@ -803,9 +752,6 @@ bool bc_get_property_matrix(Bone *bone, std::string key, float mat[4][4])
return false;
}
-/**
- * get a vector that is stored in 3 custom properties (used in Blender <= 2.78)
- */
void bc_get_property_vector(Bone *bone, std::string key, float val[3], const float def[3])
{
val[0] = bc_get_property(bone, key + "_x", def[0]);
@@ -1014,12 +960,6 @@ void bc_apply_global_transform(Vector &to_vec, const BCMatrix &global_transform,
mul_v3_m4v3(to_vec, transform, to_vec);
}
-/**
- * Check if custom information about bind matrix exists and modify the from_mat
- * accordingly.
- *
- * NOTE: This is old style for Blender <= 2.78 only kept for compatibility
- */
void bc_create_restpose_mat(BCExportSettings &export_settings,
Bone *bone,
float to_mat[4][4],
diff --git a/source/blender/io/collada/collada_utils.h b/source/blender/io/collada/collada_utils.h
index d0a5d37d6d2..cf62ea0a275 100644
--- a/source/blender/io/collada/collada_utils.h
+++ b/source/blender/io/collada/collada_utils.h
@@ -143,6 +143,12 @@ extern char *bc_CustomData_get_layer_name(const CustomData *data, int type, int
extern char *bc_CustomData_get_active_layer_name(const CustomData *data, int type);
extern void bc_bubble_sort_by_Object_name(LinkNode *export_set);
+/**
+ * Check if a bone is the top most exportable bone in the bone hierarchy.
+ * When deform_bones_only == false, then only bones with NO parent
+ * can be root bones. Otherwise the top most deform bones in the hierarchy
+ * are root bones.
+ */
extern bool bc_is_root_bone(Bone *aBone, bool deform_bones_only);
extern int bc_get_active_UVLayer(Object *ob);
@@ -195,17 +201,39 @@ extern std::string bc_replace_string(std::string data,
const std::string &pattern,
const std::string &replacement);
extern std::string bc_url_encode(std::string data);
+/**
+ * Calculate a rescale factor such that the imported scene's scale
+ * is preserved. I.e. 1 meter in the import will also be
+ * 1 meter in the current scene.
+ */
extern void bc_match_scale(Object *ob, UnitConverter &bc_unit, bool scale_to_scene);
extern void bc_match_scale(std::vector<Object *> *objects_done,
UnitConverter &bc_unit,
bool scale_to_scene);
+/**
+ * Convenience function to get only the needed components of a matrix.
+ */
extern void bc_decompose(float mat[4][4], float *loc, float eul[3], float quat[4], float *size);
+/**
+ * Create rotation_quaternion from a delta rotation and a reference quat
+ *
+ * Input:
+ * mat_from: The rotation matrix before rotation
+ * mat_to : The rotation matrix after rotation
+ * qref : the quat corresponding to mat_from
+ *
+ * Output:
+ * rot : the calculated result (quaternion).
+ */
extern void bc_rotate_from_reference_quat(float quat_to[4],
float quat_from[4],
float mat_to[4][4]);
extern void bc_triangulate_mesh(Mesh *me);
+/**
+ * A bone is a leaf when it has no children or all children are not connected.
+ */
extern bool bc_is_leaf_bone(Bone *bone);
extern EditBone *bc_get_edit_bone(bArmature *armature, char *name);
extern int bc_set_layer(int bitfield, int layer, bool enable);
@@ -224,12 +252,34 @@ void bc_copy_v44_m4d(std::vector<std::vector<double>> &r, double (&a)[4][4]);
void bc_sanitize_v3(double v[3], int precision);
void bc_sanitize_v3(float v[3], int precision);
+/**
+ * Get a custom property when it exists.
+ * This function is also used to check if a property exists.
+ */
extern IDProperty *bc_get_IDProperty(Bone *bone, std::string key);
extern void bc_set_IDProperty(EditBone *ebone, const char *key, float value);
+/**
+ * Stores a 4*4 matrix as a custom bone property array of size 16.
+ */
extern void bc_set_IDPropertyMatrix(EditBone *ebone, const char *key, float mat[4][4]);
+/**
+ * Read a custom bone property and convert to float
+ * Return def if the property does not exist.
+ */
extern float bc_get_property(Bone *bone, std::string key, float def);
+/**
+ * Get a vector that is stored in 3 custom properties (used in Blender <= 2.78).
+ */
extern void bc_get_property_vector(Bone *bone, std::string key, float val[3], const float def[3]);
+/**
+ * Read a custom bone property and convert to matrix
+ * Return true if conversion was successful
+ *
+ * Return false if:
+ * - the property does not exist
+ * - is not an array of size 16
+ */
extern bool bc_get_property_matrix(Bone *bone, std::string key, float mat[4][4]);
extern void bc_enable_fcurves(bAction *act, char *bone_name);
@@ -258,6 +308,12 @@ extern void bc_apply_global_transform(Matrix &to_mat,
extern void bc_apply_global_transform(Vector &to_vec,
const BCMatrix &global_transform,
const bool invert = false);
+/**
+ * Check if custom information about bind matrix exists and modify the from_mat
+ * accordingly.
+ *
+ * \note This is old style for Blender <= 2.78 only kept for compatibility.
+ */
extern void bc_create_restpose_mat(BCExportSettings &export_settings,
Bone *bone,
float to_mat[4][4],
@@ -364,6 +420,11 @@ class BoneExtensionManager {
std::map<std::string, BoneExtensionMap *> extended_bone_maps;
public:
+ /**
+ * This method creates a new extension map when needed.
+ * \note The ~BoneExtensionManager destructor takes care
+ * to delete the created maps when the manager is removed.
+ */
BoneExtensionMap &getExtensionMap(bArmature *armature);
~BoneExtensionManager();
};
diff --git a/source/blender/io/gpencil/gpencil_io.h b/source/blender/io/gpencil/gpencil_io.h
index cb004910c1e..ea328a531c6 100644
--- a/source/blender/io/gpencil/gpencil_io.h
+++ b/source/blender/io/gpencil/gpencil_io.h
@@ -85,7 +85,13 @@ typedef enum eGpencilExportFrame {
GP_EXPORT_FRAME_SCENE = 2,
} eGpencilExportFrame;
+/**
+ * Main export entry point function.
+ */
bool gpencil_io_export(const char *filename, struct GpencilIOParams *iparams);
+/**
+ * Main import entry point function.
+ */
bool gpencil_io_import(const char *filename, struct GpencilIOParams *iparams);
#ifdef __cplusplus
diff --git a/source/blender/io/gpencil/intern/gpencil_io_base.cc b/source/blender/io/gpencil/intern/gpencil_io_base.cc
index 294f6bfccb7..f031648d2ed 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_base.cc
+++ b/source/blender/io/gpencil/intern/gpencil_io_base.cc
@@ -145,7 +145,6 @@ void GpencilIO::prepare_camera_params(Scene *scene, const GpencilIOParams *ipara
}
}
-/** Create a list of selected objects sorted from back to front */
void GpencilIO::create_object_list()
{
ViewLayer *view_layer = CTX_data_view_layer(params_.C);
@@ -194,17 +193,12 @@ void GpencilIO::create_object_list()
});
}
-/**
- * Set file input_text full path.
- * \param filename: Path of the file provided by save dialog.
- */
void GpencilIO::filename_set(const char *filename)
{
BLI_strncpy(filename_, filename, FILE_MAX);
BLI_path_abs(filename_, BKE_main_blendfile_path(bmain_));
}
-/** Convert to screenspace. */
bool GpencilIO::gpencil_3D_point_to_screen_space(const float3 co, float2 &r_co)
{
float3 parent_co = diff_mat_ * co;
@@ -244,7 +238,6 @@ bool GpencilIO::gpencil_3D_point_to_screen_space(const float3 co, float2 &r_co)
return false;
}
-/** Convert to render space. */
float2 GpencilIO::gpencil_3D_point_to_render_space(const float3 co)
{
float3 parent_co = diff_mat_ * co;
@@ -266,7 +259,6 @@ float2 GpencilIO::gpencil_3D_point_to_render_space(const float3 co)
return r_co;
}
-/** Convert to 2D. */
float2 GpencilIO::gpencil_3D_point_to_2D(const float3 co)
{
const bool is_camera = (bool)(rv3d_->persp == RV3D_CAMOB);
@@ -278,7 +270,6 @@ float2 GpencilIO::gpencil_3D_point_to_2D(const float3 co)
return result;
}
-/** Get radius of point. */
float GpencilIO::stroke_point_radius_get(bGPDlayer *gpl, bGPDstroke *gps)
{
bGPDspoint *pt = &gps->points[0];
@@ -338,7 +329,6 @@ bool GpencilIO::is_camera_mode()
return is_camera_;
}
-/* Calculate selected strokes boundbox. */
void GpencilIO::selected_objects_boundbox_calc()
{
const float gap = 10.0f;
diff --git a/source/blender/io/gpencil/intern/gpencil_io_base.hh b/source/blender/io/gpencil/intern/gpencil_io_base.hh
index 02758883f19..6437796648d 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_base.hh
+++ b/source/blender/io/gpencil/intern/gpencil_io_base.hh
@@ -87,11 +87,16 @@ class GpencilIO {
float stroke_color_[4], fill_color_[4];
/* Geometry functions. */
+ /** Convert to screenspace. */
bool gpencil_3D_point_to_screen_space(const float3 co, float2 &r_co);
+ /** Convert to render space. */
float2 gpencil_3D_point_to_render_space(const float3 co);
+ /** Convert to 2D. */
float2 gpencil_3D_point_to_2D(const float3 co);
+ /** Get radius of point. */
float stroke_point_radius_get(struct bGPDlayer *gpl, struct bGPDstroke *gps);
+ /** Create a list of selected objects sorted from back to front */
void create_object_list();
bool is_camera_mode();
@@ -101,8 +106,13 @@ class GpencilIO {
void prepare_layer_export_matrix(struct Object *ob, struct bGPDlayer *gpl);
void prepare_stroke_export_colors(struct Object *ob, struct bGPDstroke *gps);
+ /* Calculate selected strokes boundbox. */
void selected_objects_boundbox_calc();
void selected_objects_boundbox_get(rctf *boundbox);
+ /**
+ * Set file input_text full path.
+ * \param filename: Path of the file provided by save dialog.
+ */
void filename_set(const char *filename);
private:
diff --git a/source/blender/io/gpencil/intern/gpencil_io_capi.cc b/source/blender/io/gpencil/intern/gpencil_io_capi.cc
index 95f5839682f..92ce165e059 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_capi.cc
+++ b/source/blender/io/gpencil/intern/gpencil_io_capi.cc
@@ -177,7 +177,6 @@ static bool gpencil_io_export_frame_svg(GpencilExporterSVG *exporter,
}
#endif
-/* Main import entry point function. */
bool gpencil_io_import(const char *filename, GpencilIOParams *iparams)
{
GpencilImporterSVG importer = GpencilImporterSVG(filename, iparams);
@@ -185,7 +184,6 @@ bool gpencil_io_import(const char *filename, GpencilIOParams *iparams)
return gpencil_io_import_frame(&importer, *iparams);
}
-/* Main export entry point function. */
bool gpencil_io_export(const char *filename, GpencilIOParams *iparams)
{
Depsgraph *depsgraph_ = CTX_data_depsgraph_pointer(iparams->C);
diff --git a/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc b/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc
index 82f8444d43e..7539fba1343 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc
+++ b/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc
@@ -109,7 +109,6 @@ bool GpencilExporterPDF::write()
return (res == 0) ? true : false;
}
-/* Create pdf document. */
bool GpencilExporterPDF::create_document()
{
pdf_ = HPDF_New(error_handler, nullptr);
@@ -120,7 +119,6 @@ bool GpencilExporterPDF::create_document()
return true;
}
-/* Add page. */
bool GpencilExporterPDF::add_page()
{
/* Add a new page object. */
@@ -136,7 +134,6 @@ bool GpencilExporterPDF::add_page()
return true;
}
-/* Main layer loop. */
void GpencilExporterPDF::export_gpencil_layers()
{
/* If is doing a set of frames, the list of objects can change for each frame. */
@@ -229,10 +226,6 @@ void GpencilExporterPDF::export_gpencil_layers()
}
}
-/**
- * Export a stroke using polyline or polygon
- * \param do_fill: True if the stroke is only fill
- */
void GpencilExporterPDF::export_stroke_to_polyline(bGPDlayer *gpl,
bGPDstroke *gps,
const bool is_stroke,
@@ -288,10 +281,6 @@ void GpencilExporterPDF::export_stroke_to_polyline(bGPDlayer *gpl,
HPDF_Page_GRestore(page_);
}
-/**
- * Set color.
- * \param do_fill: True if the stroke is only fill.
- */
void GpencilExporterPDF::color_set(bGPDlayer *gpl, const bool do_fill)
{
const float fill_opacity = fill_color_[3] * gpl->opacity;
diff --git a/source/blender/io/gpencil/intern/gpencil_io_export_pdf.hh b/source/blender/io/gpencil/intern/gpencil_io_export_pdf.hh
index 89d97f79783..18de321914c 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_export_pdf.hh
+++ b/source/blender/io/gpencil/intern/gpencil_io_export_pdf.hh
@@ -45,20 +45,31 @@ class GpencilExporterPDF : public GpencilExporter {
protected:
private:
- /* PDF document. */
+ /** PDF document. */
HPDF_Doc pdf_;
- /* PDF page. */
+ /** PDF page. */
HPDF_Page page_;
+ /** Create PDF document. */
bool create_document();
+ /** Add page. */
bool add_page();
+ /** Main layer loop. */
void export_gpencil_layers();
+ /**
+ * Export a stroke using poly-line or polygon
+ * \param do_fill: True if the stroke is only fill
+ */
void export_stroke_to_polyline(bGPDlayer *gpl,
bGPDstroke *gps,
const bool is_stroke,
const bool do_fill,
const bool normalize);
+ /**
+ * Set color.
+ * \param do_fill: True if the stroke is only fill.
+ */
void color_set(bGPDlayer *gpl, const bool do_fill);
};
diff --git a/source/blender/io/gpencil/intern/gpencil_io_export_svg.cc b/source/blender/io/gpencil/intern/gpencil_io_export_svg.cc
index a9745415d40..09eac7a2813 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_export_svg.cc
+++ b/source/blender/io/gpencil/intern/gpencil_io_export_svg.cc
@@ -97,7 +97,6 @@ bool GpencilExporterSVG::write()
return result;
}
-/* Create document header and main svg node. */
void GpencilExporterSVG::create_document_header()
{
/* Add a custom document declaration node. */
@@ -133,7 +132,6 @@ void GpencilExporterSVG::create_document_header()
main_node_.append_attribute("viewBox").set_value(viewbox.c_str());
}
-/* Main layer loop. */
void GpencilExporterSVG::export_gpencil_layers()
{
const bool is_clipping = is_camera_mode() && (params_.flag & GP_EXPORT_CLIP_CAMERA) != 0;
@@ -254,11 +252,6 @@ void GpencilExporterSVG::export_gpencil_layers()
}
}
-/**
- * Export a stroke using SVG path
- * \param node_gpl: Node of the layer.
- * \param do_fill: True if the stroke is only fill
- */
void GpencilExporterSVG::export_stroke_to_path(bGPDlayer *gpl,
bGPDstroke *gps,
pugi::xml_node node_gpl,
@@ -303,11 +296,6 @@ void GpencilExporterSVG::export_stroke_to_path(bGPDlayer *gpl,
node_gps.append_attribute("d").set_value(txt.c_str());
}
-/**
- * Export a stroke using polyline or polygon
- * \param node_gpl: Node of the layer.
- * \param do_fill: True if the stroke is only fill
- */
void GpencilExporterSVG::export_stroke_to_polyline(bGPDlayer *gpl,
bGPDstroke *gps,
pugi::xml_node node_gpl,
@@ -351,11 +339,6 @@ void GpencilExporterSVG::export_stroke_to_polyline(bGPDlayer *gpl,
node_gps.append_attribute("points").set_value(txt.c_str());
}
-/**
- * Set color SVG string for stroke
- * \param node_gps: Stroke node.
- * \param do_fill: True if the stroke is only fill.
- */
void GpencilExporterSVG::color_string_set(bGPDlayer *gpl,
bGPDstroke *gps,
pugi::xml_node node_gps,
@@ -392,16 +375,6 @@ void GpencilExporterSVG::color_string_set(bGPDlayer *gpl,
}
}
-/**
- * Create a SVG rectangle
- * \param node: Parent node
- * \param x: X location
- * \param y: Y location
- * \param width: width of the rectangle
- * \param height: Height of the rectangle
- * \param thickness: Thickness of the line
- * \param hexcolor: Color of the line
- */
void GpencilExporterSVG::add_rect(pugi::xml_node node,
float x,
float y,
@@ -422,15 +395,6 @@ void GpencilExporterSVG::add_rect(pugi::xml_node node,
}
}
-/**
- * Create SVG text
- * \param node: Parent node
- * \param x: X location
- * \param y: Y location
- * \param text: Text to include
- * \param size: Size of the text
- * \param hexcolor: Color of the text
- */
void GpencilExporterSVG::add_text(pugi::xml_node node,
float x,
float y,
@@ -448,7 +412,6 @@ void GpencilExporterSVG::add_text(pugi::xml_node node,
nodetxt.text().set(text.c_str());
}
-/** Convert a color to Hex value (#FFFFFF). */
std::string GpencilExporterSVG::rgb_to_hexstr(const float color[3])
{
uint8_t r = color[0] * 255.0f;
diff --git a/source/blender/io/gpencil/intern/gpencil_io_export_svg.hh b/source/blender/io/gpencil/intern/gpencil_io_export_svg.hh
index 6d8a0c2f6ac..b3175978072 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_export_svg.hh
+++ b/source/blender/io/gpencil/intern/gpencil_io_export_svg.hh
@@ -42,6 +42,16 @@ class GpencilExporterSVG : public GpencilExporter {
bool write();
protected:
+ /**
+ * Create a SVG rectangle
+ * \param node: Parent node
+ * \param x: X location
+ * \param y: Y location
+ * \param width: width of the rectangle
+ * \param height: Height of the rectangle
+ * \param thickness: Thickness of the line
+ * \param hexcolor: Color of the line
+ */
static void add_rect(pugi::xml_node node,
float x,
float y,
@@ -50,6 +60,15 @@ class GpencilExporterSVG : public GpencilExporter {
float thickness,
std::string hexcolor);
+ /**
+ * Create SVG text
+ * \param node: Parent node
+ * \param x: X location
+ * \param y: Y location
+ * \param text: Text to include
+ * \param size: Size of the text
+ * \param hexcolor: Color of the text
+ */
static void add_text(pugi::xml_node node,
float x,
float y,
@@ -58,31 +77,49 @@ class GpencilExporterSVG : public GpencilExporter {
std::string hexcolor);
private:
- /* XML doc. */
+ /** XML doc. */
pugi::xml_document main_doc_;
- /* Main document node. */
+ /** Main document node. */
pugi::xml_node main_node_;
/** Frame node. */
pugi::xml_node frame_node_;
+ /** Create document header and main SVG node. */
void create_document_header();
+ /** Main layer loop. */
void export_gpencil_layers();
+ /**
+ * Export a stroke using SVG path
+ * \param node_gpl: Node of the layer.
+ * \param do_fill: True if the stroke is only fill
+ */
void export_stroke_to_path(struct bGPDlayer *gpl,
struct bGPDstroke *gps,
pugi::xml_node node_gpl,
const bool do_fill);
+ /**
+ * Export a stroke using poly-line or polygon
+ * \param node_gpl: Node of the layer.
+ * \param do_fill: True if the stroke is only fill
+ */
void export_stroke_to_polyline(struct bGPDlayer *gpl,
struct bGPDstroke *gps,
pugi::xml_node node_gpl,
const bool is_stroke,
const bool do_fill);
+ /**
+ * Set color SVG string for stroke
+ * \param node_gps: Stroke node.
+ * \param do_fill: True if the stroke is only fill.
+ */
void color_string_set(struct bGPDlayer *gpl,
struct bGPDstroke *gps,
pugi::xml_node node_gps,
const bool do_fill);
+ /** Convert a color to Hex value (#FFFFFF). */
std::string rgb_to_hexstr(const float color[3]);
};
diff --git a/source/blender/io/usd/intern/usd_capi_export.cc b/source/blender/io/usd/intern/usd_capi_export.cc
index efa31df25c1..0cc3fde8c6c 100644
--- a/source/blender/io/usd/intern/usd_capi_export.cc
+++ b/source/blender/io/usd/intern/usd_capi_export.cc
@@ -223,7 +223,7 @@ bool USD_export(bContext *C,
return export_ok;
}
-int USD_get_version(void)
+int USD_get_version()
{
/* USD 19.11 defines:
*
diff --git a/source/blender/io/usd/intern/usd_reader_curve.cc b/source/blender/io/usd/intern/usd_reader_curve.cc
index 12de1d82c72..5007d204020 100644
--- a/source/blender/io/usd/intern/usd_reader_curve.cc
+++ b/source/blender/io/usd/intern/usd_reader_curve.cc
@@ -108,11 +108,11 @@ void USDCurvesReader::read_curve_sample(Curve *cu, const double motionSampleTime
* Perhaps to be replaced by Blender/USD Schema. */
if (!usdNormals.empty()) {
/* Set extrusion to 1.0f. */
- curve_->ext1 = 1.0f;
+ curve_->extrude = 1.0f;
}
else {
/* Set bevel depth to 1.0f. */
- curve_->ext2 = 1.0f;
+ curve_->bevel_radius = 1.0f;
}
size_t idx = 0;
@@ -164,7 +164,7 @@ void USDCurvesReader::read_curve_sample(Curve *cu, const double motionSampleTime
bp->f1 = SELECT;
bp->weight = weight;
- float radius = curve_->width;
+ float radius = curve_->offset;
if (idx < usdWidths.size()) {
radius = usdWidths[idx];
}
diff --git a/source/blender/io/usd/intern/usd_reader_material.cc b/source/blender/io/usd/intern/usd_reader_material.cc
index 317dfd2a62b..db0c5785a68 100644
--- a/source/blender/io/usd/intern/usd_reader_material.cc
+++ b/source/blender/io/usd/intern/usd_reader_material.cc
@@ -298,7 +298,6 @@ Material *USDMaterialReader::add_material(const pxr::UsdShadeMaterial &usd_mater
return mtl;
}
-/* Create the Principled BSDF shader node network. */
void USDMaterialReader::import_usd_preview(Material *mtl,
const pxr::UsdShadeShader &usd_shader) const
{
@@ -416,7 +415,6 @@ void USDMaterialReader::set_principled_node_inputs(bNode *principled,
}
}
-/* Convert the given USD shader input to an input on the given Blender node. */
void USDMaterialReader::set_node_input(const pxr::UsdShadeInput &usd_input,
bNode *dest_node,
const char *dest_socket_name,
@@ -484,8 +482,6 @@ void USDMaterialReader::set_node_input(const pxr::UsdShadeInput &usd_input,
}
}
-/* Follow the connected source of the USD input to create corresponding inputs
- * for the given Blender node. */
void USDMaterialReader::follow_connection(const pxr::UsdShadeInput &usd_input,
bNode *dest_node,
const char *dest_socket_name,
@@ -594,8 +590,6 @@ void USDMaterialReader::convert_usd_uv_texture(const pxr::UsdShadeShader &usd_sh
}
}
-/* Load the texture image node's texture from the path given by the USD shader's
- * file input value. */
void USDMaterialReader::load_tex_image(const pxr::UsdShadeShader &usd_shader,
bNode *tex_image) const
{
@@ -653,10 +647,6 @@ void USDMaterialReader::load_tex_image(const pxr::UsdShadeShader &usd_shader,
}
}
-/* This function creates a Blender UV Map node, under the simplifying assumption that
- * UsdPrimvarReader_float2 shaders output UV coordinates.
- * TODO(makowalski): investigate supporting conversion to other Blender node types
- * (e.g., Attribute Nodes) if needed. */
void USDMaterialReader::convert_usd_primvar_reader_float2(
const pxr::UsdShadeShader &usd_shader,
const pxr::TfToken & /* usd_source_name */,
diff --git a/source/blender/io/usd/intern/usd_reader_material.h b/source/blender/io/usd/intern/usd_reader_material.h
index a17504bd590..fb40b4f2f6d 100644
--- a/source/blender/io/usd/intern/usd_reader_material.h
+++ b/source/blender/io/usd/intern/usd_reader_material.h
@@ -90,12 +90,14 @@ class USDMaterialReader {
Material *add_material(const pxr::UsdShadeMaterial &usd_material) const;
protected:
+ /** Create the Principled BSDF shader node network. */
void import_usd_preview(Material *mtl, const pxr::UsdShadeShader &usd_shader) const;
void set_principled_node_inputs(bNode *principled_node,
bNodeTree *ntree,
const pxr::UsdShadeShader &usd_shader) const;
+ /** Convert the given USD shader input to an input on the given Blender node. */
void set_node_input(const pxr::UsdShadeInput &usd_input,
bNode *dest_node,
const char *dest_socket_name,
@@ -103,6 +105,10 @@ class USDMaterialReader {
int column,
NodePlacementContext *r_ctx) const;
+ /**
+ * Follow the connected source of the USD input to create corresponding inputs
+ * for the given Blender node.
+ */
void follow_connection(const pxr::UsdShadeInput &usd_input,
bNode *dest_node,
const char *dest_socket_name,
@@ -118,8 +124,18 @@ class USDMaterialReader {
int column,
NodePlacementContext *r_ctx) const;
+ /**
+ * Load the texture image node's texture from the path given by the USD shader's
+ * file input value.
+ */
void load_tex_image(const pxr::UsdShadeShader &usd_shader, bNode *tex_image) const;
+ /**
+ * This function creates a Blender UV Map node, under the simplifying assumption that
+ * UsdPrimvarReader_float2 shaders output UV coordinates.
+ * TODO(makowalski): investigate supporting conversion to other Blender node types
+ * (e.g., Attribute Nodes) if needed.
+ */
void convert_usd_primvar_reader_float2(const pxr::UsdShadeShader &usd_shader,
const pxr::TfToken &usd_source_name,
bNode *dest_node,
diff --git a/source/blender/io/usd/intern/usd_reader_mesh.cc b/source/blender/io/usd/intern/usd_reader_mesh.cc
index 5c8bd88e87a..3ad1d4adf18 100644
--- a/source/blender/io/usd/intern/usd_reader_mesh.cc
+++ b/source/blender/io/usd/intern/usd_reader_mesh.cc
@@ -589,7 +589,6 @@ void USDMeshReader::process_normals_face_varying(Mesh *mesh)
MEM_freeN(lnors);
}
-/* Set USD uniform (per-face) normals as Blender loop normals. */
void USDMeshReader::process_normals_uniform(Mesh *mesh)
{
if (normals_.empty()) {
diff --git a/source/blender/io/usd/intern/usd_reader_mesh.h b/source/blender/io/usd/intern/usd_reader_mesh.h
index 54ad144d191..9ed73ba5a28 100644
--- a/source/blender/io/usd/intern/usd_reader_mesh.h
+++ b/source/blender/io/usd/intern/usd_reader_mesh.h
@@ -75,6 +75,7 @@ class USDMeshReader : public USDGeomReader {
private:
void process_normals_vertex_varying(Mesh *mesh);
void process_normals_face_varying(Mesh *mesh);
+ /** Set USD uniform (per-face) normals as Blender loop normals. */
void process_normals_uniform(Mesh *mesh);
void readFaceSetsSample(Main *bmain, Mesh *mesh, double motionSampleTime);
void assign_facesets_to_mpoly(double motionSampleTime,
diff --git a/source/blender/io/usd/intern/usd_reader_nurbs.cc b/source/blender/io/usd/intern/usd_reader_nurbs.cc
index d6977d9c91a..8370804b776 100644
--- a/source/blender/io/usd/intern/usd_reader_nurbs.cc
+++ b/source/blender/io/usd/intern/usd_reader_nurbs.cc
@@ -112,11 +112,11 @@ void USDNurbsReader::read_curve_sample(Curve *cu, const double motionSampleTime)
* Perhaps to be replaced by Blender USD Schema. */
if (!usdNormals.empty()) {
/* Set extrusion to 1. */
- curve_->ext1 = 1.0f;
+ curve_->extrude = 1.0f;
}
else {
/* Set bevel depth to 1. */
- curve_->ext2 = 1.0f;
+ curve_->bevel_radius = 1.0f;
}
size_t idx = 0;
diff --git a/source/blender/io/usd/intern/usd_reader_stage.cc b/source/blender/io/usd/intern/usd_reader_stage.cc
index 8c4cc18a9af..9df5611bec9 100644
--- a/source/blender/io/usd/intern/usd_reader_stage.cc
+++ b/source/blender/io/usd/intern/usd_reader_stage.cc
@@ -110,11 +110,6 @@ USDPrimReader *USDStageReader::create_reader(const pxr::UsdPrim &prim)
return nullptr;
}
-/* Returns true if the given prim should be included in the
- * traversal based on the import options and the prim's visibility
- * attribute. Note that the prim will be trivially included
- * if it has no visibility attribute or if the visibility
- * is inherited. */
bool USDStageReader::include_by_visibility(const pxr::UsdGeomImageable &imageable) const
{
if (!params_.import_visible_only) {
@@ -140,11 +135,6 @@ bool USDStageReader::include_by_visibility(const pxr::UsdGeomImageable &imageabl
return visibility != pxr::UsdGeomTokens->invisible;
}
-/* Returns true if the given prim should be included in the
- * traversal based on the import options and the prim's purpose
- * attribute. E.g., return false (to exclude the prim) if the prim
- * represents guide geometry and the 'Import Guide' option is
- * toggled off. */
bool USDStageReader::include_by_purpose(const pxr::UsdGeomImageable &imageable) const
{
if (params_.import_guide && params_.import_proxy && params_.import_render) {
diff --git a/source/blender/io/usd/intern/usd_reader_stage.h b/source/blender/io/usd/intern/usd_reader_stage.h
index ba223962c0c..df5f83067c1 100644
--- a/source/blender/io/usd/intern/usd_reader_stage.h
+++ b/source/blender/io/usd/intern/usd_reader_stage.h
@@ -82,8 +82,22 @@ class USDStageReader {
private:
USDPrimReader *collect_readers(Main *bmain, const pxr::UsdPrim &prim);
+ /**
+ * Returns true if the given prim should be included in the
+ * traversal based on the import options and the prim's visibility
+ * attribute. Note that the prim will be trivially included
+ * if it has no visibility attribute or if the visibility
+ * is inherited.
+ */
bool include_by_visibility(const pxr::UsdGeomImageable &imageable) const;
+ /**
+ * Returns true if the given prim should be included in the
+ * traversal based on the import options and the prim's purpose
+ * attribute. E.g., return false (to exclude the prim) if the prim
+ * represents guide geometry and the 'Import Guide' option is
+ * toggled off.
+ */
bool include_by_purpose(const pxr::UsdGeomImageable &imageable) const;
};
diff --git a/source/blender/io/usd/intern/usd_writer_abstract.cc b/source/blender/io/usd/intern/usd_writer_abstract.cc
index 6965ecf6249..2b5326eb4c1 100644
--- a/source/blender/io/usd/intern/usd_writer_abstract.cc
+++ b/source/blender/io/usd/intern/usd_writer_abstract.cc
@@ -121,7 +121,6 @@ void USDAbstractWriter::write_visibility(const HierarchyContext &context,
usd_value_writer_.SetAttribute(attr_visibility, pxr::VtValue(visibility), timecode);
}
-/* Reference the original data instead of writing a copy. */
bool USDAbstractWriter::mark_as_instance(const HierarchyContext &context, const pxr::UsdPrim &prim)
{
BLI_assert(context.is_instance());
@@ -134,7 +133,7 @@ bool USDAbstractWriter::mark_as_instance(const HierarchyContext &context, const
pxr::SdfPath ref_path(context.original_export_path);
if (!prim.GetReferences().AddInternalReference(ref_path)) {
- /* See this URL for a description fo why referencing may fail"
+ /* See this URL for a description for why referencing may fail"
* https://graphics.pixar.com/usd/docs/api/class_usd_references.html#Usd_Failing_References
*/
printf("USD Export warning: unable to add reference from %s to %s, not instancing object\n",
diff --git a/source/blender/io/usd/intern/usd_writer_abstract.h b/source/blender/io/usd/intern/usd_writer_abstract.h
index 6f143a7e241..dd81dd47c83 100644
--- a/source/blender/io/usd/intern/usd_writer_abstract.h
+++ b/source/blender/io/usd/intern/usd_writer_abstract.h
@@ -52,13 +52,15 @@ class USDAbstractWriter : public AbstractHierarchyWriter {
virtual void write(HierarchyContext &context) override;
- /* Returns true if the data to be written is actually supported. This would, for example, allow a
+ /**
+ * Returns true if the data to be written is actually supported. This would, for example, allow a
* hypothetical camera writer accept a perspective camera but reject an orthogonal one.
*
* Returning false from a transform writer will prevent the object and all its descendants from
* being exported. Returning false from a data writer (object data, hair, or particles) will
* only prevent that data from being written (and thus cause the object to be exported as an
- * Empty). */
+ * Empty).
+ */
virtual bool is_supported(const HierarchyContext *context) const;
const pxr::SdfPath &usd_path() const;
@@ -73,8 +75,12 @@ class USDAbstractWriter : public AbstractHierarchyWriter {
const pxr::UsdTimeCode timecode,
pxr::UsdGeomImageable &usd_geometry);
- /* Turn `prim` into an instance referencing `context.original_export_path`.
- * Return true when the instancing was successful, false otherwise. */
+ /**
+ * Turn `prim` into an instance referencing `context.original_export_path`.
+ * Return true when the instancing was successful, false otherwise.
+ *
+ * Reference the original data instead of writing a copy.
+ */
virtual bool mark_as_instance(const HierarchyContext &context, const pxr::UsdPrim &prim);
};
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index 2c04d0b06ef..6a478f9abb5 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -461,7 +461,7 @@ typedef struct LibraryWeakReference {
enum ePreviewImage_Flag {
PRV_CHANGED = (1 << 0),
PRV_USER_EDITED = (1 << 1), /* if user-edited, do not auto-update this anymore! */
- PRV_UNFINISHED = (1 << 2), /* The preview is not done rendering yet. */
+ PRV_RENDERING = (1 << 2), /* Rendering was invoked. Cleared on file read. */
};
/* for PreviewImage->tag */
diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h
index e899e6bd3ec..8e7551e1703 100644
--- a/source/blender/makesdna/DNA_action_types.h
+++ b/source/blender/makesdna/DNA_action_types.h
@@ -682,6 +682,10 @@ typedef struct bAction {
int idroot;
char _pad[4];
+ /** Start and end of the manually set intended playback frame range. Used by UI and
+ * some editing tools, but doesn't directly affect animation evaluation in any way. */
+ float frame_start, frame_end;
+
PreviewImage *preview;
} bAction;
@@ -695,6 +699,10 @@ typedef enum eAction_Flags {
ACT_MUTED = (1 << 9),
/* ACT_PROTECTED = (1 << 10), */ /* UNUSED */
/* ACT_DISABLED = (1 << 11), */ /* UNUSED */
+ /** The action has a manually set intended playback frame range. */
+ ACT_FRAME_RANGE = (1 << 12),
+ /** The action is intended to be a cycle (requires ACT_FRAME_RANGE). */
+ ACT_CYCLIC = (1 << 13),
} eAction_Flags;
/* ************************************************ */
diff --git a/source/blender/makesdna/DNA_curve_defaults.h b/source/blender/makesdna/DNA_curve_defaults.h
index 557615fd047..614653db2b8 100644
--- a/source/blender/makesdna/DNA_curve_defaults.h
+++ b/source/blender/makesdna/DNA_curve_defaults.h
@@ -34,7 +34,7 @@
.pathlen = 100, \
.resolu = 12, \
.resolv = 12, \
- .width = 1.0, \
+ .offset = 1.0, \
.wordspace = 1.0, \
.spacing = 1.0f, \
.linedist = 1.0, \
diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h
index a2433dbbbbd..c1c8fe06121 100644
--- a/source/blender/makesdna/DNA_curve_types.h
+++ b/source/blender/makesdna/DNA_curve_types.h
@@ -228,16 +228,15 @@ typedef struct Curve {
/** Creation-time type of curve datablock. */
short type;
- /** Keep a short because of BKE_object_obdata_texspace_get(). */
- short texflag;
- char _pad0[6];
+ char texflag;
+ char _pad0[7];
short twist_mode;
float twist_smooth, smallcaps_scale;
int pathlen;
short bevresol, totcol;
int flag;
- float width, ext1, ext2;
+ float offset, extrude, bevel_radius;
/* default */
short resolu, resolv;
@@ -421,10 +420,8 @@ enum {
enum {
CU_POLY = 0,
CU_BEZIER = 1,
- CU_BSPLINE = 2,
- CU_CARDINAL = 3,
CU_NURBS = 4,
- CU_TYPE = (CU_POLY | CU_BEZIER | CU_BSPLINE | CU_CARDINAL | CU_NURBS),
+ CU_TYPE = (CU_POLY | CU_BEZIER | CU_NURBS),
/* only for adding */
CU_PRIMITIVE = 0xF00,
@@ -457,6 +454,8 @@ enum {
typedef enum eBezTriple_Flag {
/* SELECT */
BEZT_FLAG_TEMP_TAG = (1 << 1), /* always clear. */
+ /* Can be used to ignore keyframe points for certain operations. */
+ BEZT_FLAG_IGNORE_TAG = (1 << 2),
} eBezTriple_Flag;
/* h1 h2 (beztriple) */
diff --git a/source/blender/makesdna/DNA_defaults.h b/source/blender/makesdna/DNA_defaults.h
index 1549e33b267..6e986129143 100644
--- a/source/blender/makesdna/DNA_defaults.h
+++ b/source/blender/makesdna/DNA_defaults.h
@@ -36,7 +36,9 @@ extern "C" {
extern const void *DNA_default_table[SDNA_TYPE_MAX];
-char *_DNA_struct_default_alloc_impl(const char *data_src, size_t size, const char *alloc_str);
+uint8_t *_DNA_struct_default_alloc_impl(const uint8_t *data_src,
+ size_t size,
+ const char *alloc_str);
/**
* Wrap with macro that casts correctly.
diff --git a/source/blender/makesdna/DNA_effect_types.h b/source/blender/makesdna/DNA_effect_types.h
index 3de13169616..2e086a2834c 100644
--- a/source/blender/makesdna/DNA_effect_types.h
+++ b/source/blender/makesdna/DNA_effect_types.h
@@ -27,7 +27,7 @@
extern "C" {
#endif
-/* Don't forget, new effects also in writefile.c for DNA! */
+/* Don't forget, new effects also in `writefile.c` for DNA! */
#define PAF_MAXMULT 4
diff --git a/source/blender/makesdna/DNA_fileglobal_types.h b/source/blender/makesdna/DNA_fileglobal_types.h
index a0285215ff9..3b6fb60cc2e 100644
--- a/source/blender/makesdna/DNA_fileglobal_types.h
+++ b/source/blender/makesdna/DNA_fileglobal_types.h
@@ -50,7 +50,7 @@ typedef struct FileGlobal {
/** Hash from buildinfo. */
char build_hash[16];
/** File path where this was saved, for recover (1024 = FILE_MAX). */
- char filename[1024];
+ char filepath[1024];
} FileGlobal;
/* minversion: in file, the oldest past blender version you can use compliant */
diff --git a/source/blender/makesdna/DNA_genfile.h b/source/blender/makesdna/DNA_genfile.h
index fda1cbaeae6..5e0cff9fd83 100644
--- a/source/blender/makesdna/DNA_genfile.h
+++ b/source/blender/makesdna/DNA_genfile.h
@@ -83,6 +83,9 @@ enum eSDNA_StructCompare {
SDNA_CMP_UNKNOWN = 3,
};
+/**
+ * Constructs and returns a decoded SDNA structure from the given encoded SDNA data block.
+ */
struct SDNA *DNA_sdna_from_data(const void *data,
const int data_len,
bool do_endian_swap,
@@ -97,22 +100,58 @@ const struct SDNA *DNA_sdna_current_get(void);
void DNA_sdna_current_free(void);
struct DNA_ReconstructInfo;
+/**
+ * Pre-process information about how structs in \a newsdna can be reconstructed from structs in
+ * \a oldsdna. This information is then used to speedup #DNA_struct_reconstruct.
+ */
struct DNA_ReconstructInfo *DNA_reconstruct_info_create(const struct SDNA *oldsdna,
const struct SDNA *newsdna,
const char *compare_flags);
void DNA_reconstruct_info_free(struct DNA_ReconstructInfo *reconstruct_info);
+/**
+ * Returns the index of the struct info for the struct with the specified name.
+ */
int DNA_struct_find_nr_ex(const struct SDNA *sdna, const char *str, unsigned int *index_last);
int DNA_struct_find_nr(const struct SDNA *sdna, const char *str);
+/**
+ * Does endian swapping on the fields of a struct value.
+ *
+ * \param sdna: SDNA of the struct_nr belongs to
+ * \param struct_nr: Index of struct info within sdna
+ * \param data: Struct data that is to be converted
+ */
void DNA_struct_switch_endian(const struct SDNA *sdna, int struct_nr, char *data);
+/**
+ * Constructs and returns an array of byte flags with one element for each struct in oldsdna,
+ * indicating how it compares to newsdna.
+ */
const char *DNA_struct_get_compareflags(const struct SDNA *sdna, const struct SDNA *newsdna);
+/**
+ * \param reconstruct_info: Information preprocessed by #DNA_reconstruct_info_create.
+ * \param old_struct_nr: Index of struct info within oldsdna.
+ * \param blocks: The number of array elements.
+ * \param old_blocks: Array of struct data.
+ * \return An allocated reconstructed struct.
+ */
void *DNA_struct_reconstruct(const struct DNA_ReconstructInfo *reconstruct_info,
int old_struct_nr,
int blocks,
const void *old_blocks);
+/**
+ * Returns the offset of the field with the specified name and type within the specified
+ * struct type in #SDNA, -1 on failure.
+ */
int DNA_elem_offset(struct SDNA *sdna, const char *stype, const char *vartype, const char *name);
+/**
+ * Returns the size of struct fields of the specified type and name.
+ *
+ * \param type: Index into sdna->types/types_size
+ * \param name: Index into sdna->names,
+ * needed to extract possible pointer/array information.
+ */
int DNA_elem_size_nr(const struct SDNA *sdna, short type, short name);
bool DNA_struct_find(const struct SDNA *sdna, const char *stype);
@@ -121,11 +160,22 @@ bool DNA_struct_elem_find(const struct SDNA *sdna,
const char *vartype,
const char *name);
+/**
+ * Returns the size in bytes of a primitive type.
+ */
int DNA_elem_type_size(const eSDNA_Type elem_nr);
+/**
+ * Rename a struct
+ */
bool DNA_sdna_patch_struct(struct SDNA *sdna,
const char *struct_name_old,
const char *struct_name_new);
+/**
+ * Replace \a elem_old with \a elem_new for struct \a struct_name
+ * handles search & replace, maintaining surrounding non-identifier characters
+ * such as pointer & array size.
+ */
bool DNA_sdna_patch_struct_member(struct SDNA *sdna,
const char *struct_name,
const char *elem_old,
@@ -134,14 +184,28 @@ bool DNA_sdna_patch_struct_member(struct SDNA *sdna,
void DNA_sdna_alias_data_ensure(struct SDNA *sdna);
/* Alias lookups (using runtime struct member names). */
+
+/**
+ * \note requires #DNA_sdna_alias_data_ensure_structs_map to be called.
+ */
int DNA_struct_alias_find_nr_ex(const struct SDNA *sdna,
const char *str,
unsigned int *index_last);
+/**
+ * \note requires #DNA_sdna_alias_data_ensure_structs_map to be called.
+ */
int DNA_struct_alias_find_nr(const struct SDNA *sdna, const char *str);
+/**
+ * \note requires #DNA_sdna_alias_data_ensure_structs_map to be called.
+ */
bool DNA_struct_alias_elem_find(const struct SDNA *sdna,
const char *stype,
const char *vartype,
const char *name);
+/**
+ * Separated from #DNA_sdna_alias_data_ensure because it's not needed
+ * unless we want to lookup aliased struct names (#DNA_struct_alias_find_nr and friends).
+ */
void DNA_sdna_alias_data_ensure_structs_map(struct SDNA *sdna);
#ifdef __cplusplus
diff --git a/source/blender/makesdna/DNA_gpencil_modifier_defaults.h b/source/blender/makesdna/DNA_gpencil_modifier_defaults.h
index 1ad884bee8f..88eb164c2b4 100644
--- a/source/blender/makesdna/DNA_gpencil_modifier_defaults.h
+++ b/source/blender/makesdna/DNA_gpencil_modifier_defaults.h
@@ -333,6 +333,11 @@
.point_density = 30.0f,\
.segment_influence = 0.0f,\
.max_angle = DEG2RAD(170.0f),\
+ .rand_start_fac = 0.0f,\
+ .rand_end_fac = 0.0f,\
+ .rand_offset = 0.0f,\
+ .seed = 0,\
+ .step = 4,\
}
#define _DNA_DEFAULT_DashGpencilModifierData \
@@ -353,5 +358,26 @@
.mat_nr = -1, \
}
+#define _DNA_DEFAULT_ShrinkwrapGpencilModifierData \
+ { \
+ .target = NULL, \
+ .aux_target = NULL, \
+ .keep_dist = 0.05f, \
+ .shrink_type = MOD_SHRINKWRAP_NEAREST_SURFACE, \
+ .shrink_opts = MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR, \
+ .shrink_mode = 0, \
+ .proj_limit = 0.0f, \
+ .proj_axis = 0, \
+ .subsurf_levels = 0, \
+ .material = NULL, \
+ .layername = "", \
+ .vgname = "", \
+ .pass_index = 0, \
+ .flag = 0, \
+ .layer_pass = 0, \
+ .smooth_factor = 0.05f, \
+ .smooth_step = 1, \
+ }
+
/* clang-format off */
diff --git a/source/blender/makesdna/DNA_gpencil_modifier_types.h b/source/blender/makesdna/DNA_gpencil_modifier_types.h
index 339714da255..0f69a256f56 100644
--- a/source/blender/makesdna/DNA_gpencil_modifier_types.h
+++ b/source/blender/makesdna/DNA_gpencil_modifier_types.h
@@ -28,6 +28,7 @@ extern "C" {
#endif
struct LatticeDeformData;
+struct ShrinkwrapTreeData;
/* WARNING ALERT! TYPEDEF VALUES ARE WRITTEN IN FILES! SO DO NOT CHANGE!
* (ONLY ADD NEW ITEMS AT THE END)
@@ -58,6 +59,7 @@ typedef enum GpencilModifierType {
eGpencilModifierType_WeightProximity = 21,
eGpencilModifierType_Dash = 22,
eGpencilModifierType_WeightAngle = 23,
+ eGpencilModifierType_Shrinkwrap = 24,
/* Keep last. */
NUM_GREASEPENCIL_MODIFIER_TYPES,
} GpencilModifierType;
@@ -490,10 +492,17 @@ typedef struct LengthGpencilModifierData {
int layer_pass;
/** Length. */
float start_fac, end_fac;
+ /** Random length factors. */
+ float rand_start_fac, rand_end_fac, rand_offset;
/** Overshoot trajectory factor. */
float overshoot_fac;
+ /** (first element is the index) random values. */
+ int seed;
+ /** How many frames before recalculate randoms. */
+ int step;
/** Modifier mode. */
int mode;
+ char _pad[4];
/* Curvature parameters. */
float point_density;
float segment_influence;
@@ -507,6 +516,7 @@ typedef enum eLengthGpencil_Flag {
GP_LENGTH_INVERT_MATERIAL = (1 << 3),
GP_LENGTH_USE_CURVATURE = (1 << 4),
GP_LENGTH_INVERT_CURVATURE = (1 << 5),
+ GP_LENGTH_USE_RANDOM = (1 << 6),
} eLengthGpencil_Flag;
typedef enum eLengthGpencil_Type {
@@ -728,7 +738,7 @@ typedef struct SmoothGpencilModifierData {
int pass_index;
/** Several flags. */
int flag;
- /** Factor of noise. */
+ /** Factor of smooth. */
float factor;
/** How many times apply smooth. */
int step;
@@ -1073,6 +1083,60 @@ typedef struct LineartGpencilModifierData {
} LineartGpencilModifierData;
+typedef struct ShrinkwrapGpencilModifierData {
+ GpencilModifierData modifier;
+ /** Shrink target. */
+ struct Object *target;
+ /** Additional shrink target. */
+ struct Object *aux_target;
+ /** Material for filtering. */
+ struct Material *material;
+ /** Layer name. */
+ char layername[64];
+ /** Optional vertexgroup filter name, MAX_VGROUP_NAME. */
+ char vgname[64];
+ /** Custom index for passes. */
+ int pass_index;
+ /** Flags. */
+ int flag;
+ /** Custom index for passes. */
+ int layer_pass;
+ /** Distance offset to keep from mesh/projection point. */
+ float keep_dist;
+ /** Shrink type projection. */
+ short shrink_type;
+ /** Shrink options. */
+ char shrink_opts;
+ /** Shrink to surface mode. */
+ char shrink_mode;
+ /** Limit the projection ray cast. */
+ float proj_limit;
+ /** Axis to project over. */
+ char proj_axis;
+
+ /** If using projection over vertex normal this controls the level of subsurface that must be
+ * done before getting the vertex coordinates and normal
+ */
+ char subsurf_levels;
+ char _pad[6];
+ /** Factor of smooth. */
+ float smooth_factor;
+ /** How many times apply smooth. */
+ int smooth_step;
+
+ /** Runtime only. */
+ struct ShrinkwrapTreeData *cache_data;
+} ShrinkwrapGpencilModifierData;
+
+typedef enum eShrinkwrapGpencil_Flag {
+ GP_SHRINKWRAP_INVERT_LAYER = (1 << 0),
+ GP_SHRINKWRAP_INVERT_PASS = (1 << 1),
+ GP_SHRINKWRAP_INVERT_LAYERPASS = (1 << 3),
+ GP_SHRINKWRAP_INVERT_MATERIAL = (1 << 4),
+ /* Keep next bit as is to be equals to mesh modifier flag to reuse functions. */
+ GP_SHRINKWRAP_INVERT_VGROUP = (1 << 6),
+} eShrinkwrapGpencil_Flag;
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h
index 3943c063c39..77cb553c7c7 100644
--- a/source/blender/makesdna/DNA_mesh_types.h
+++ b/source/blender/makesdna/DNA_mesh_types.h
@@ -74,7 +74,7 @@ struct MLoopTri_Store {
int len_alloc;
};
-/* not saved in file! */
+/* Runtime data, not saved in files. */
typedef struct Mesh_Runtime {
/* Evaluated mesh for objects which do not have effective modifiers.
* This mesh is used as a result of modifier stack evaluation.
@@ -82,27 +82,33 @@ typedef struct Mesh_Runtime {
struct Mesh *mesh_eval;
void *eval_mutex;
- struct EditMeshData *edit_data;
- void *batch_cache;
+ /** Needed to ensure some thread-safety during render data pre-processing. */
+ void *render_mutex;
- struct SubdivCCG *subdiv_ccg;
- void *_pad1;
- int subdiv_ccg_tot_level;
- char _pad2[4];
+ /** Lazily initialized SoA data from the #edit_mesh field in #Mesh. */
+ struct EditMeshData *edit_data;
- int64_t cd_dirty_vert;
- int64_t cd_dirty_edge;
- int64_t cd_dirty_loop;
- int64_t cd_dirty_poly;
+ /**
+ * Data used to efficiently draw the mesh in the viewport, especially useful when
+ * the same mesh is used in many objects or instances. See `draw_cache_impl_mesh.c`.
+ */
+ void *batch_cache;
+ /** Cache for derived triangulation of the mesh. */
struct MLoopTri_Store looptris;
- /** `BVHCache` defined in 'BKE_bvhutil.c' */
+ /** Cache for BVH trees generated for the mesh. Defined in 'BKE_bvhutil.c' */
struct BVHCache *bvh_cache;
- /** Non-manifold boundary data for Shrinkwrap Target Project. */
+ /** Cache of non-manifold boundary data for Shrinkwrap Target Project. */
struct ShrinkwrapBoundaryData *shrinkwrap_data;
+ /** Needed in case we need to lazily initialize the mesh. */
+ CustomData_MeshMasks cd_mask_extra;
+
+ struct SubdivCCG *subdiv_ccg;
+ int subdiv_ccg_tot_level;
+
/** Set by modifier stack if only deformed from original. */
char deformed_only;
/**
@@ -122,14 +128,15 @@ typedef struct Mesh_Runtime {
*/
char wrapper_type_finalize;
- char _pad[4];
-
- /** Needed in case we need to lazily initialize the mesh. */
- CustomData_MeshMasks cd_mask_extra;
+ /**
+ * Used to mark when derived data needs to be recalculated for a certain layer.
+ * Currently only normals.
+ */
- /** Needed to ensure some thread-safety during render data pre-processing. */
- void *render_mutex;
- void *_pad3;
+ int64_t cd_dirty_vert;
+ int64_t cd_dirty_edge;
+ int64_t cd_dirty_loop;
+ int64_t cd_dirty_poly;
} Mesh_Runtime;
@@ -141,101 +148,191 @@ typedef struct Mesh {
/** Old animation system, deprecated for 2.5. */
struct Ipo *ipo DNA_DEPRECATED;
struct Key *key;
- struct Material **mat;
- struct MSelect *mselect;
- /* BMESH ONLY */
- /* New face structures. */
- struct MPoly *mpoly;
- struct MLoop *mloop;
- struct MLoopUV *mloopuv;
- struct MLoopCol *mloopcol;
- /* END BMESH ONLY */
+ /**
+ * An array of materials, with length #totcol. These can be overridden by material slots
+ * on #Object. Indices in #MPoly.mat_nr control which material is used for every face.
+ */
+ struct Material **mat;
/**
- * Legacy face storage (quads & tries only),
- * faces are now stored in #Mesh.mpoly & #Mesh.mloop arrays.
- *
- * \note This would be marked deprecated however the particles still use this at run-time
- * for placing particles on the mesh (something which should be eventually upgraded).
+ * Array of vertices. Edges and faces are defined by indices into this array.
+ * \note This pointer is for convenient access to the #CD_MVERT layer in #vdata.
*/
- struct MFace *mface;
- /** Store tessellation face UV's and texture here. */
- struct MTFace *mtface;
- /** Deprecated, use mtface. */
- struct TFace *tface DNA_DEPRECATED;
- /** Array of verts. */
struct MVert *mvert;
- /** Array of edges. */
+ /**
+ * Array of edges, containing vertex indices. For simple triangle or quad meshes, edges could be
+ * calculated from the #MPoly and #MLoop arrays, however, edges need to be stored explicitly to
+ * edge domain attributes and to support loose edges that aren't connected to faces.
+ * \note This pointer is for convenient access to the #CD_MEDGE layer in #edata.
+ */
struct MEdge *medge;
- /** Deform-group vertices. */
- struct MDeformVert *dvert;
- /** List of bDeformGroup names and flag only. */
- ListBase vertex_group_names;
+ /**
+ * Face topology storage of the size and offset of each face's section of the #mloop face corner
+ * array. Also stores various flags and the `material_index` attribute.
+ * \note This pointer is for convenient access to the #CD_MPOLY layer in #pdata.
+ */
+ struct MPoly *mpoly;
+ /**
+ * The vertex and edge index at each face corner.
+ * \note This pointer is for convenient access to the #CD_MLOOP layer in #ldata.
+ */
+ struct MLoop *mloop;
- /* array of colors for the tessellated faces, must be number of tessellated
- * faces * 4 in length */
- struct MCol *mcol;
- struct Mesh *texcomesh;
+ /** The number of vertices (#MVert) in the mesh, and the size of #vdata. */
+ int totvert;
+ /** The number of edges (#MEdge) in the mesh, and the size of #edata. */
+ int totedge;
+ /** The number of polygons/faces (#MPoly) in the mesh, and the size of #pdata. */
+ int totpoly;
+ /** The number of face corners (#MLoop) in the mesh, and the size of #ldata. */
+ int totloop;
- /* When the object is available, the preferred access method is: BKE_editmesh_from_object(ob) */
- /** Not saved in file. */
- struct BMEditMesh *edit_mesh;
+ CustomData vdata, edata, pdata, ldata;
+
+ /** "Vertex group" vertices. */
+ struct MDeformVert *dvert;
+ /**
+ * List of vertex group (#bDeformGroup) names and flags only. Actual weights are stored in dvert.
+ * \note This pointer is for convenient access to the #CD_MDEFORMVERT layer in #vdata.
+ */
+ ListBase vertex_group_names;
+ /** The active index in the #vertex_group_names list. */
+ int vertex_group_active_index;
- struct CustomData vdata, edata, fdata;
+ /**
+ * The index of the active attribute in the UI. The attribute list is a combination of the
+ * generic type attributes from vertex, edge, face, and corner custom data.
+ */
+ int attributes_active_index;
- /* BMESH ONLY */
- struct CustomData pdata, ldata;
- /* END BMESH ONLY */
+ /**
+ * 2D vector data used for UVs. "UV" data can also be stored as generic attributes in #ldata.
+ * \note This pointer is for convenient access to the #CD_MLOOPUV layer in #ldata.
+ */
+ struct MLoopUV *mloopuv;
+ /**
+ * The active vertex corner color layer, if it exists. Also called "Vertex Color" in Blender's
+ * UI, even though it is stored per face corner.
+ * \note This pointer is for convenient access to the #CD_MLOOPCOL layer in #ldata.
+ */
+ struct MLoopCol *mloopcol;
- int totvert, totedge, totface, totselect;
+ /**
+ * Runtime storage of the edit mode mesh. If it exists, it generally has the most up-to-date
+ * information about the mesh.
+ * \note When the object is available, the preferred access method is #BKE_editmesh_from_object.
+ */
+ struct BMEditMesh *edit_mesh;
- /* BMESH ONLY */
- int totpoly, totloop;
- /* END BMESH ONLY */
+ /**
+ * This array represents the selection order when the user manually picks elements in edit-mode,
+ * some tools take advantage of this information. All elements in this array are expected to be
+ * selected, see #BKE_mesh_mselect_validate which ensures this. For procedurally created meshes,
+ * this is generally empty (selections are stored as boolean attributes in the corresponding
+ * custom data).
+ */
+ struct MSelect *mselect;
- int attributes_active_index;
- int vertex_group_active_index;
+ /** The length of the #mselect array. */
+ int totselect;
- /* the last selected vertex/edge/face are used for the active face however
- * this means the active face must always be selected, this is to keep track
- * of the last selected face and is similar to the old active face flag where
- * the face does not need to be selected, -1 is inactive */
+ /**
+ * In most cases the last selected element (see #mselect) represents the active element.
+ * For faces we make an exception and store the active face separately so it can be active
+ * even when no faces are selected. This is done to prevent flickering in the material properties
+ * and UV Editor which base the content they display on the current material which is controlled
+ * by the active face.
+ *
+ * \note This is mainly stored for use in edit-mode.
+ */
int act_face;
- /* texture space, copied as one block in editobject.c */
+ /**
+ * An optional mesh owned elsewhere (by #Main) that can be used to override
+ * the texture space #loc and #size.
+ * \note Vertex indices should be aligned for this to work usefully.
+ */
+ struct Mesh *texcomesh;
+
+ /** Texture space location and size, used for procedural coordinates when rendering. */
float loc[3];
float size[3];
+ char texflag;
- short texflag, flag;
+ /** Various flags used when editing the mesh. */
+ char editflag;
+ /** Mostly more flags used when editing or displaying the mesh. */
+ short flag;
+
+ /**
+ * The angle for auto smooth in radians. `M_PI` (180 degrees) causes all edges to be smooth.
+ */
float smoothresh;
- /* customdata flag, for bevel-weight and crease, which are now optional */
- char cd_flag, _pad;
+ /**
+ * Flag for choosing whether or not so store bevel weight and crease as custom data layers in the
+ * edit mesh (they are always stored in #MVert and #MEdge currently). In the future, this data
+ * may be stored as generic named attributes (see T89054 and T93602).
+ */
+ char cd_flag;
- char subdiv DNA_DEPRECATED, subdivr DNA_DEPRECATED;
- /** Only kept for backwards compat, not used anymore. */
- char subsurftype DNA_DEPRECATED;
- char editflag;
+ /**
+ * User-defined symmetry flag (#eMeshSymmetryType) that causes editing operations to maintain
+ * symmetrical geometry. Supported by operations such as transform and weight-painting.
+ */
+ char symmetry;
+ /** The length of the #mat array. */
short totcol;
- float remesh_voxel_size;
- float remesh_voxel_adaptivity;
+ /** Choice between different remesh methods in the UI. */
char remesh_mode;
- /* Indicates the symmetry that a mesh has, according to the artist, so that tools can
- * consistently ensure that this symmetry is maintained. */
- char symmetry;
+ char subdiv DNA_DEPRECATED;
+ char subdivr DNA_DEPRECATED;
+ char subsurftype DNA_DEPRECATED;
- char _pad1[2];
+ /**
+ * Deprecated. Store of runtime data for tessellation face UVs and texture.
+ *
+ * \note This would be marked deprecated, however the particles still use this at run-time
+ * for placing particles on the mesh (something which should be eventually upgraded).
+ */
+ struct MTFace *mtface;
+ /** Deprecated, use mtface. */
+ struct TFace *tface DNA_DEPRECATED;
+
+ /* Deprecated. Array of colors for the tessellated faces, must be number of tessellated
+ * faces * 4 in length. This is stored in #fdata, and deprecated. */
+ struct MCol *mcol;
+
+ /**
+ * Deprecated face storage (quads & triangles only);
+ * faces are now pointed to by #Mesh.mpoly and #Mesh.mloop.
+ *
+ * \note This would be marked deprecated, however the particles still use this at run-time
+ * for placing particles on the mesh (something which should be eventually upgraded).
+ */
+ struct MFace *mface;
+ /* Deprecated storage of old faces (only triangles or quads). */
+ CustomData fdata;
+ /* Deprecated size of #fdata. */
+ int totface;
+
+ /** Per-mesh settings for voxel remesh. */
+ float remesh_voxel_size;
+ float remesh_voxel_adaptivity;
int face_sets_color_seed;
/* Stores the initial Face Set to be rendered white. This way the overlay can be enabled by
* default and Face Sets can be used without affecting the color of the mesh. */
int face_sets_color_default;
+ char _pad1[4];
+
void *_pad2;
+
Mesh_Runtime runtime;
} Mesh;
diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h
index 4bc1de3b78e..03991dff0ce 100644
--- a/source/blender/makesdna/DNA_meshdata_types.h
+++ b/source/blender/makesdna/DNA_meshdata_types.h
@@ -106,19 +106,15 @@ enum {
};
/**
- * Mesh Loops.
- * Each loop represents the corner of a polygon (#MPoly).
+ * Mesh Face Corners.
+ * "Loop" is an internal name for the corner of a polygon (#MPoly).
*
* Typically accessed from #Mesh.mloop.
*/
typedef struct MLoop {
- /** Vertex index. */
+ /** Vertex index into an #MVert array. */
unsigned int v;
- /**
- * Edge index.
- *
- * \note The e here is because we want to move away from relying on edge hashes.
- */
+ /** Edge index into an #MEdge array. */
unsigned int e;
} MLoop;
@@ -291,8 +287,22 @@ typedef struct MDeformWeight {
float weight;
} MDeformWeight;
+/**
+ * Stores all of an element's vertex groups, and their weight values.
+ */
typedef struct MDeformVert {
+ /**
+ * Array of weight indices and values.
+ * - There must not be any duplicate #def_nr indices.
+ * - Groups in the array are unordered.
+ * - Indices outside the usable range of groups are ignored.
+ */
struct MDeformWeight *dw;
+ /**
+ * The length of the #dw array.
+ * \note This is not necessarily the same length as the total number of vertex groups.
+ * However, generally it isn't larger.
+ */
int totweight;
/** Flag is only in use as a run-time tag at the moment. */
int flag;
diff --git a/source/blender/makesdna/DNA_meta_types.h b/source/blender/makesdna/DNA_meta_types.h
index d257363b6ef..e489ba7d7ac 100644
--- a/source/blender/makesdna/DNA_meta_types.h
+++ b/source/blender/makesdna/DNA_meta_types.h
@@ -83,8 +83,8 @@ typedef struct MetaBall {
char flag, flag2;
short totcol;
/** Used to store MB_AUTOSPACE. */
- short texflag;
- char _pad[1];
+ char texflag;
+ char _pad[2];
/**
* ID data is older than edit-mode data (TODO: move to edit-mode struct).
diff --git a/source/blender/makesdna/DNA_modifier_defaults.h b/source/blender/makesdna/DNA_modifier_defaults.h
index 5b2694f420b..78ab41031a6 100644
--- a/source/blender/makesdna/DNA_modifier_defaults.h
+++ b/source/blender/makesdna/DNA_modifier_defaults.h
@@ -429,6 +429,7 @@
.uv_offset = {0.0f, 0.0f}, \
.uv_offset_copy = {0.0f, 0.0f}, \
.mirror_ob = NULL, \
+ .use_correct_order_on_merge = true, \
}
#define _DNA_DEFAULT_MultiresModifierData \
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index 631db64ddd3..f7a468264c3 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -374,7 +374,15 @@ typedef struct MirrorModifierData {
short flag;
float tolerance;
float bisect_threshold;
- char _pad[4];
+
+ /** Mirror modifier used to merge the old vertex into its new copy, which would break code
+ * relying on access to the original geometry vertices. However, modifying this behavior to the
+ * correct one (i.e. merging the copy vertices into their original sources) has several potential
+ * effects on other modifiers and tools, so we need to keep that incorrect behavior for existing
+ * modifiers, and only use the new correct one for new modifiers. */
+ uint8_t use_correct_order_on_merge;
+
+ char _pad[3];
float uv_offset[2];
float uv_offset_copy[2];
struct Object *mirror_ob;
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index 59cf4da26f6..dc5acb9d5b2 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -304,8 +304,6 @@ typedef struct bNode {
/** Entire boundbox (world-space). */
rctf totr;
- /** Optional buttons area. */
- rctf butr;
/** Optional preview area. */
rctf prvr;
/**
@@ -325,8 +323,6 @@ typedef struct bNode {
char branch_tag;
/** Used at runtime when iterating over node branches. */
char iter_flag;
- /** Runtime during drawing. */
- struct uiBlock *block;
/**
* XXX: eevee only, id of screen space reflection layer,
@@ -375,8 +371,7 @@ typedef struct bNode {
/* node is disabled */
#define NODE_MUTED 512
// #define NODE_CUSTOM_NAME 1024 /* deprecated! */
-/* group node types: use const outputs by default */
-#define NODE_CONST_OUTPUT (1 << 11)
+// #define NODE_CONST_OUTPUT (1 << 11) /* deprecated */
/* node is always behind others */
#define NODE_BACKGROUND (1 << 12)
/* automatic flag for nodes included in transforms */
@@ -1209,6 +1204,16 @@ typedef struct NodeDenoise {
char prefilter;
} NodeDenoise;
+typedef struct NodeMapRange {
+ /* CustomDataType */
+ uint8_t data_type;
+
+ /* NodeMapRangeType. */
+ uint8_t interpolation_type;
+ uint8_t clamp;
+ char _pad[5];
+} NodeMapRange;
+
typedef struct NodeAttributeClamp {
/* CustomDataType. */
uint8_t data_type;
@@ -1606,6 +1611,16 @@ typedef struct NodeGeometryViewer {
int8_t data_type;
} NodeGeometryViewer;
+typedef struct NodeFunctionCompare {
+ /* NodeCompareOperation */
+ int8_t operation;
+ /* eNodeSocketDatatype */
+ int8_t data_type;
+ /* NodeCompareMode */
+ int8_t mode;
+ char _pad[1];
+} NodeFunctionCompare;
+
/* script node mode */
#define NODE_SCRIPT_INTERNAL 0
#define NODE_SCRIPT_EXTERNAL 1
@@ -1886,14 +1901,25 @@ enum {
};
/* Float compare node operations. */
-typedef enum FloatCompareOperation {
- NODE_FLOAT_COMPARE_LESS_THAN = 0,
- NODE_FLOAT_COMPARE_LESS_EQUAL = 1,
- NODE_FLOAT_COMPARE_GREATER_THAN = 2,
- NODE_FLOAT_COMPARE_GREATER_EQUAL = 3,
- NODE_FLOAT_COMPARE_EQUAL = 4,
- NODE_FLOAT_COMPARE_NOT_EQUAL = 5,
-} FloatCompareOperation;
+typedef enum NodeCompareMode {
+ NODE_COMPARE_MODE_ELEMENT = 0,
+ NODE_COMPARE_MODE_LENGTH = 1,
+ NODE_COMPARE_MODE_AVERAGE = 2,
+ NODE_COMPARE_MODE_DOT_PRODUCT = 3,
+ NODE_COMPARE_MODE_DIRECTION = 4
+} NodeCompareMode;
+
+typedef enum NodeCompareOperation {
+ NODE_COMPARE_LESS_THAN = 0,
+ NODE_COMPARE_LESS_EQUAL = 1,
+ NODE_COMPARE_GREATER_THAN = 2,
+ NODE_COMPARE_GREATER_EQUAL = 3,
+ NODE_COMPARE_EQUAL = 4,
+ NODE_COMPARE_NOT_EQUAL = 5,
+ NODE_COMPARE_COLOR_BRIGHTER = 6,
+ NODE_COMPARE_COLOR_DARKER = 7,
+
+} NodeCompareOperation;
/* Float to Int node operations. */
typedef enum FloatToIntRoundingMode {
@@ -2272,6 +2298,10 @@ typedef enum GeometryNodeDeleteGeometryMode {
GEO_NODE_DELETE_GEOMETRY_MODE_ONLY_FACE = 2,
} GeometryNodeDeleteGeometryMode;
+typedef enum GeometryNodeRealizeInstancesFlag {
+ GEO_NODE_REALIZE_INSTANCES_LEGACY_BEHAVIOR = (1 << 0),
+} GeometryNodeRealizeInstancesFlag;
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/makesdna/DNA_outliner_types.h b/source/blender/makesdna/DNA_outliner_types.h
index ebf3d4a248c..a50d0524998 100644
--- a/source/blender/makesdna/DNA_outliner_types.h
+++ b/source/blender/makesdna/DNA_outliner_types.h
@@ -41,13 +41,13 @@ typedef struct TreeStoreElem {
/** Used only to store data in blend files. */
typedef struct TreeStore {
- /** Was previously used for memory preallocation. */
+ /** Was previously used for memory pre-allocation. */
int totelem DNA_DEPRECATED;
/** Number of elements in data array. */
int usedelem;
/**
- * Elements to be packed from mempool in writefile.c
- * or extracted to mempool in readfile.c
+ * Elements to be packed from mempool in `writefile.c`
+ * or extracted to mempool in `readfile.c`.
*/
TreeStoreElem *data;
} TreeStore;
diff --git a/source/blender/makesdna/DNA_pointcache_types.h b/source/blender/makesdna/DNA_pointcache_types.h
index 7de0bb29c46..2b6e1c4f7de 100644
--- a/source/blender/makesdna/DNA_pointcache_types.h
+++ b/source/blender/makesdna/DNA_pointcache_types.h
@@ -131,8 +131,8 @@ typedef struct PointCache {
void (*free_edit)(struct PTCacheEdit *edit);
} PointCache;
+/** #PointCache.flag */
enum {
- /* pointcache->flag */
PTCACHE_BAKED = 1 << 0,
PTCACHE_OUTDATED = 1 << 1,
PTCACHE_SIMULATION_VALID = 1 << 2,
diff --git a/source/blender/makesdna/DNA_scene_defaults.h b/source/blender/makesdna/DNA_scene_defaults.h
index 9ecf94ebd6e..d2c4f22bc23 100644
--- a/source/blender/makesdna/DNA_scene_defaults.h
+++ b/source/blender/makesdna/DNA_scene_defaults.h
@@ -375,3 +375,5 @@
}
/* clang-format off */
+
+/** \} */
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 634e97f782f..c66ac3a6211 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -720,6 +720,7 @@ typedef struct RenderData {
/* path to render output */
/** 1024 = FILE_MAX. */
+ /* NOTE: Excluded from `BKE_bpath_foreach_path_` / `scene_foreach_path` code. */
char pic[1024];
/* stamps flags. */
diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h
index 03110f6e1be..a4c254d6e5a 100644
--- a/source/blender/makesdna/DNA_screen_types.h
+++ b/source/blender/makesdna/DNA_screen_types.h
@@ -154,6 +154,9 @@ typedef struct Panel_Runtime {
/* Pointer to the panel's block. Useful when changes to panel #uiBlocks
* need some context from traversal of the panel "tree". */
struct uiBlock *block;
+
+ /* Non-owning pointer. The context is stored in the block. */
+ struct bContextStore *context;
} Panel_Runtime;
/** The part from uiBlock that needs saved in file. */
@@ -458,6 +461,9 @@ typedef struct ARegion_Runtime {
/* The offset needed to not overlap with window scrollbars. Only used by HUD regions for now. */
int offset_x, offset_y;
+
+ /* Maps uiBlock->name to uiBlock for faster lookups. */
+ struct GHash *block_name_map;
} ARegion_Runtime;
typedef struct ARegion {
diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h
index 9e6cf907444..e1bba60396a 100644
--- a/source/blender/makesdna/DNA_sequence_types.h
+++ b/source/blender/makesdna/DNA_sequence_types.h
@@ -180,8 +180,7 @@ typedef struct Sequence {
int startdisp, enddisp;
float sat;
float mul;
- char tmp_tag;
- char _pad[3];
+ float _pad;
short anim_preseek; /* UNUSED. */
/** Streamindex for movie or sound files with several streams. */
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index 7fb15fc8508..a7a19be5b3e 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -281,7 +281,7 @@ typedef struct SpaceOutliner {
* Note that treestore may contain duplicate elements if element
* is used multiple times in outliner tree (e. g. linked objects)
* Also note that BLI_mempool can not be read/written in DNA directly,
- * therefore readfile.c/writefile.c linearize treestore into TreeStore structure
+ * therefore `readfile.c/writefile.c` linearize treestore into TreeStore structure
*/
struct BLI_mempool *treestore;
@@ -1514,12 +1514,15 @@ typedef struct bNodeTreePath {
} bNodeTreePath;
typedef struct SpaceNodeOverlay {
+ /* eSpaceNodeOverlay_Flag */
int flag;
} SpaceNodeOverlay;
typedef enum eSpaceNodeOverlay_Flag {
SN_OVERLAY_SHOW_OVERLAYS = (1 << 1),
SN_OVERLAY_SHOW_WIRE_COLORS = (1 << 2),
+ SN_OVERLAY_SHOW_TIMINGS = (1 << 3),
+ SN_OVERLAY_SHOW_PATH = (1 << 4),
} eSpaceNodeOverlay_Flag;
typedef struct SpaceNode {
@@ -2003,6 +2006,7 @@ typedef enum eSpaceSpreadsheet_ContextType {
} eSpaceSpreadsheet_ContextType;
typedef enum eSpreadsheetColumnValueType {
+ SPREADSHEET_VALUE_TYPE_UNKNOWN = -1,
SPREADSHEET_VALUE_TYPE_BOOL = 0,
SPREADSHEET_VALUE_TYPE_INT32 = 1,
SPREADSHEET_VALUE_TYPE_FLOAT = 2,
diff --git a/source/blender/makesdna/intern/dna_defaults.c b/source/blender/makesdna/intern/dna_defaults.c
index 2dbbb35c3ca..1d4257328a4 100644
--- a/source/blender/makesdna/intern/dna_defaults.c
+++ b/source/blender/makesdna/intern/dna_defaults.c
@@ -324,6 +324,7 @@ SDNA_DEFAULT_DECL_STRUCT(LineartGpencilModifierData);
SDNA_DEFAULT_DECL_STRUCT(LengthGpencilModifierData);
SDNA_DEFAULT_DECL_STRUCT(DashGpencilModifierData);
SDNA_DEFAULT_DECL_STRUCT(DashGpencilModifierSegment);
+SDNA_DEFAULT_DECL_STRUCT(ShrinkwrapGpencilModifierData);
#undef SDNA_DEFAULT_DECL_STRUCT
@@ -555,13 +556,16 @@ const void *DNA_default_table[SDNA_TYPE_MAX] = {
SDNA_DEFAULT_DECL(LengthGpencilModifierData),
SDNA_DEFAULT_DECL(DashGpencilModifierData),
SDNA_DEFAULT_DECL(DashGpencilModifierSegment),
+ SDNA_DEFAULT_DECL(ShrinkwrapGpencilModifierData),
};
#undef SDNA_DEFAULT_DECL
#undef SDNA_DEFAULT_DECL_EX
-char *_DNA_struct_default_alloc_impl(const char *data_src, size_t size, const char *alloc_str)
+uint8_t *_DNA_struct_default_alloc_impl(const uint8_t *data_src,
+ size_t size,
+ const char *alloc_str)
{
- char *data_dst = MEM_mallocN(size, alloc_str);
+ uint8_t *data_dst = MEM_mallocN(size, alloc_str);
memcpy(data_dst, data_src, size);
return data_dst;
}
diff --git a/source/blender/makesdna/intern/dna_genfile.c b/source/blender/makesdna/intern/dna_genfile.c
index 8aa2a07d071..bdf29b22787 100644
--- a/source/blender/makesdna/intern/dna_genfile.c
+++ b/source/blender/makesdna/intern/dna_genfile.c
@@ -177,13 +177,6 @@ static bool ispointer(const char *name)
return (name[0] == '*' || (name[0] == '(' && name[1] == '*'));
}
-/**
- * Returns the size of struct fields of the specified type and name.
- *
- * \param type: Index into sdna->types/types_size
- * \param name: Index into sdna->names,
- * needed to extract possible pointer/array information.
- */
int DNA_elem_size_nr(const SDNA *sdna, short type, short name)
{
const char *cp = sdna->names[name];
@@ -265,9 +258,6 @@ static int dna_struct_find_nr_ex_impl(
return -1;
}
-/**
- * Returns the index of the struct info for the struct with the specified name.
- */
int DNA_struct_find_nr_ex(const SDNA *sdna, const char *str, unsigned int *index_last)
{
return dna_struct_find_nr_ex_impl(
@@ -284,7 +274,6 @@ int DNA_struct_find_nr_ex(const SDNA *sdna, const char *str, unsigned int *index
index_last);
}
-/** \note requires #DNA_sdna_alias_data_ensure_structs_map to be called. */
int DNA_struct_alias_find_nr_ex(const SDNA *sdna, const char *str, unsigned int *index_last)
{
#ifdef WITH_DNA_GHASH
@@ -310,7 +299,6 @@ int DNA_struct_find_nr(const SDNA *sdna, const char *str)
return DNA_struct_find_nr_ex(sdna, str, &index_last_dummy);
}
-/** \note requires #DNA_sdna_alias_data_ensure_structs_map to be called. */
int DNA_struct_alias_find_nr(const SDNA *sdna, const char *str)
{
unsigned int index_last_dummy = UINT_MAX;
@@ -544,9 +532,6 @@ static bool init_structDNA(SDNA *sdna, bool do_endian_swap, const char **r_error
return true;
}
-/**
- * Constructs and returns a decoded SDNA structure from the given encoded SDNA data block.
- */
SDNA *DNA_sdna_from_data(const void *data,
const int data_len,
bool do_endian_swap,
@@ -691,10 +676,6 @@ static void set_compare_flags_for_struct(const SDNA *oldsdna,
compare_flags[old_struct_index] = SDNA_CMP_EQUAL;
}
-/**
- * Constructs and returns an array of byte flags with one element for each struct in oldsdna,
- * indicating how it compares to newsdna.
- */
const char *DNA_struct_get_compareflags(const SDNA *oldsdna, const SDNA *newsdna)
{
if (oldsdna->structs_len == 0) {
@@ -1018,13 +999,6 @@ static int get_member_size_in_bytes(const SDNA *sdna, const SDNA_StructMember *m
return type_size * array_length;
}
-/**
- * Does endian swapping on the fields of a struct value.
- *
- * \param sdna: SDNA of the struct_nr belongs to
- * \param struct_nr: Index of struct info within sdna
- * \param data: Struct data that is to be converted
- */
void DNA_struct_switch_endian(const SDNA *sdna, int struct_nr, char *data)
{
if (struct_nr == -1) {
@@ -1230,13 +1204,6 @@ static void reconstruct_structs(const DNA_ReconstructInfo *reconstruct_info,
}
}
-/**
- * \param reconstruct_info: Information preprocessed by #DNA_reconstruct_info_create.
- * \param old_struct_nr: Index of struct info within oldsdna.
- * \param blocks: The number of array elements.
- * \param old_blocks: Array of struct data.
- * \return An allocated reconstructed struct.
- */
void *DNA_struct_reconstruct(const DNA_ReconstructInfo *reconstruct_info,
int old_struct_nr,
int blocks,
@@ -1534,10 +1501,6 @@ static int compress_reconstruct_steps(ReconstructStep *steps, const int old_step
return new_step_count;
}
-/**
- * Pre-process information about how structs in \a newsdna can be reconstructed from structs in
- * \a oldsdna. This information is then used to speedup #DNA_struct_reconstruct.
- */
DNA_ReconstructInfo *DNA_reconstruct_info_create(const SDNA *oldsdna,
const SDNA *newsdna,
const char *compare_flags)
@@ -1597,10 +1560,6 @@ void DNA_reconstruct_info_free(DNA_ReconstructInfo *reconstruct_info)
MEM_freeN(reconstruct_info);
}
-/**
- * Returns the offset of the field with the specified name and type within the specified
- * struct type in #SDNA, -1 on failure.
- */
int DNA_elem_offset(SDNA *sdna, const char *stype, const char *vartype, const char *name)
{
const int SDNAnr = DNA_struct_find_nr(sdna, stype);
@@ -1632,7 +1591,6 @@ bool DNA_struct_elem_find(const SDNA *sdna,
return false;
}
-/** \note requires #DNA_sdna_alias_data_ensure_structs_map to be called. */
bool DNA_struct_alias_elem_find(const SDNA *sdna,
const char *stype,
const char *vartype,
@@ -1651,9 +1609,6 @@ bool DNA_struct_alias_elem_find(const SDNA *sdna,
return false;
}
-/**
- * Returns the size in bytes of a primitive type.
- */
int DNA_elem_type_size(const eSDNA_Type elem_nr)
{
/* should contain all enum types */
@@ -1696,9 +1651,6 @@ static bool DNA_sdna_patch_struct_nr(SDNA *sdna,
sdna->types[struct_info->type] = struct_name_new;
return true;
}
-/**
- * Rename a struct
- */
bool DNA_sdna_patch_struct(SDNA *sdna, const char *struct_name_old, const char *struct_name_new)
{
const int struct_name_old_nr = DNA_struct_find_nr(sdna, struct_name_old);
@@ -1756,11 +1708,6 @@ static bool DNA_sdna_patch_struct_member_nr(SDNA *sdna,
}
return false;
}
-/**
- * Replace \a elem_old with \a elem_new for struct \a struct_name
- * handles search & replace, maintaining surrounding non-identifier characters
- * such as pointer & array size.
- */
bool DNA_sdna_patch_struct_member(SDNA *sdna,
const char *struct_name,
const char *elem_old,
@@ -1909,10 +1856,6 @@ void DNA_sdna_alias_data_ensure(SDNA *sdna)
BLI_ghash_free(elem_map_alias_from_static, MEM_freeN, NULL);
}
-/**
- * Separated from #DNA_sdna_alias_data_ensure because it's not needed
- * unless we want to lookup aliased struct names (#DNA_struct_alias_find_nr and friends).
- */
void DNA_sdna_alias_data_ensure_structs_map(SDNA *sdna)
{
DNA_sdna_alias_data_ensure(sdna);
diff --git a/source/blender/makesdna/intern/dna_rename_defs.h b/source/blender/makesdna/intern/dna_rename_defs.h
index 9b8bfb5af15..c5769d7eee4 100644
--- a/source/blender/makesdna/intern/dna_rename_defs.h
+++ b/source/blender/makesdna/intern/dna_rename_defs.h
@@ -50,7 +50,9 @@
/* No include guard (intentional). */
-/* Match RNA names where possible, keep sorted. */
+/* Match RNA names where possible. */
+
+/* NOTE: Keep sorted! */
DNA_STRUCT_RENAME(Lamp, Light)
DNA_STRUCT_RENAME(SpaceButs, SpaceProperties)
@@ -63,20 +65,24 @@ DNA_STRUCT_RENAME_ELEM(Bone, curveInY, curve_in_z)
DNA_STRUCT_RENAME_ELEM(Bone, curveOutX, curve_out_x)
DNA_STRUCT_RENAME_ELEM(Bone, curveOutY, curve_out_z)
DNA_STRUCT_RENAME_ELEM(Bone, scaleIn, scale_in_x)
-DNA_STRUCT_RENAME_ELEM(Bone, scale_in_y, scale_in_z)
DNA_STRUCT_RENAME_ELEM(Bone, scaleOut, scale_out_x)
+DNA_STRUCT_RENAME_ELEM(Bone, scale_in_y, scale_in_z)
DNA_STRUCT_RENAME_ELEM(Bone, scale_out_y, scale_out_z)
DNA_STRUCT_RENAME_ELEM(BrushGpencilSettings, gradient_f, hardeness)
DNA_STRUCT_RENAME_ELEM(BrushGpencilSettings, gradient_s, aspect_ratio)
DNA_STRUCT_RENAME_ELEM(Camera, YF_dofdist, dof_distance)
-DNA_STRUCT_RENAME_ELEM(Curve, len_wchar, len_char32)
DNA_STRUCT_RENAME_ELEM(Camera, clipend, clip_end)
DNA_STRUCT_RENAME_ELEM(Camera, clipsta, clip_start)
DNA_STRUCT_RENAME_ELEM(Collection, dupli_ofs, instance_offset)
+DNA_STRUCT_RENAME_ELEM(Curve, ext1, extrude)
+DNA_STRUCT_RENAME_ELEM(Curve, ext2, bevel_radius)
+DNA_STRUCT_RENAME_ELEM(Curve, len_wchar, len_char32)
+DNA_STRUCT_RENAME_ELEM(Curve, width, offset)
DNA_STRUCT_RENAME_ELEM(Editing, over_border, overlay_frame_rect)
DNA_STRUCT_RENAME_ELEM(Editing, over_cfra, overlay_frame_abs)
DNA_STRUCT_RENAME_ELEM(Editing, over_flag, overlay_frame_flag)
DNA_STRUCT_RENAME_ELEM(Editing, over_ofs, overlay_frame_ofs)
+DNA_STRUCT_RENAME_ELEM(FileGlobal, filename, filepath)
DNA_STRUCT_RENAME_ELEM(FluidDomainSettings, cache_frame_pause_guiding, cache_frame_pause_guide)
DNA_STRUCT_RENAME_ELEM(FluidDomainSettings, guiding_alpha, guide_alpha)
DNA_STRUCT_RENAME_ELEM(FluidDomainSettings, guiding_beta, guide_beta)
@@ -86,17 +92,23 @@ DNA_STRUCT_RENAME_ELEM(FluidDomainSettings, guiding_vel_factor, guide_vel_factor
DNA_STRUCT_RENAME_ELEM(FluidEffectorSettings, guiding_mode, guide_mode)
DNA_STRUCT_RENAME_ELEM(Image, name, filepath)
DNA_STRUCT_RENAME_ELEM(Library, name, filepath)
+DNA_STRUCT_RENAME_ELEM(LineartGpencilModifierData, line_types, edge_types)
+DNA_STRUCT_RENAME_ELEM(LineartGpencilModifierData, transparency_flags, mask_switches)
+DNA_STRUCT_RENAME_ELEM(LineartGpencilModifierData, transparency_mask, material_mask_bits)
DNA_STRUCT_RENAME_ELEM(MaskLayer, restrictflag, visibility_flag)
+DNA_STRUCT_RENAME_ELEM(MaterialLineArt, transparency_mask, material_mask_bits)
DNA_STRUCT_RENAME_ELEM(MovieClip, name, filepath)
DNA_STRUCT_RENAME_ELEM(Object, col, color)
DNA_STRUCT_RENAME_ELEM(Object, dup_group, instance_collection)
DNA_STRUCT_RENAME_ELEM(Object, dupfacesca, instance_faces_scale)
-DNA_STRUCT_RENAME_ELEM(Object, size, scale)
DNA_STRUCT_RENAME_ELEM(Object, restrictflag, visibility_flag)
+DNA_STRUCT_RENAME_ELEM(Object, size, scale)
DNA_STRUCT_RENAME_ELEM(ParticleSettings, dup_group, instance_collection)
DNA_STRUCT_RENAME_ELEM(ParticleSettings, dup_ob, instance_object)
DNA_STRUCT_RENAME_ELEM(ParticleSettings, dupliweights, instance_weights)
+DNA_STRUCT_RENAME_ELEM(RigidBodyWorld, steps_per_second, substeps_per_frame)
DNA_STRUCT_RENAME_ELEM(SpaceSeq, overlay_type, overlay_frame_type)
+DNA_STRUCT_RENAME_ELEM(SurfaceDeformModifierData, numverts, num_bind_verts)
DNA_STRUCT_RENAME_ELEM(Text, name, filepath)
DNA_STRUCT_RENAME_ELEM(ThemeSpace, scrubbing_background, time_scrub_background)
DNA_STRUCT_RENAME_ELEM(ThemeSpace, show_back_grad, background_type)
@@ -114,8 +126,8 @@ DNA_STRUCT_RENAME_ELEM(bPoseChannel, curveInY, curve_in_z)
DNA_STRUCT_RENAME_ELEM(bPoseChannel, curveOutX, curve_out_x)
DNA_STRUCT_RENAME_ELEM(bPoseChannel, curveOutY, curve_out_z)
DNA_STRUCT_RENAME_ELEM(bPoseChannel, scaleIn, scale_in_x)
-DNA_STRUCT_RENAME_ELEM(bPoseChannel, scale_in_y, scale_in_z)
DNA_STRUCT_RENAME_ELEM(bPoseChannel, scaleOut, scale_out_x)
+DNA_STRUCT_RENAME_ELEM(bPoseChannel, scale_in_y, scale_in_z)
DNA_STRUCT_RENAME_ELEM(bPoseChannel, scale_out_y, scale_out_z)
DNA_STRUCT_RENAME_ELEM(bSameVolumeConstraint, flag, free_axis)
DNA_STRUCT_RENAME_ELEM(bSound, name, filepath)
@@ -136,12 +148,8 @@ DNA_STRUCT_RENAME_ELEM(bTheme, tstatusbar, space_statusbar)
DNA_STRUCT_RENAME_ELEM(bTheme, ttopbar, space_topbar)
DNA_STRUCT_RENAME_ELEM(bTheme, tuserpref, space_preferences)
DNA_STRUCT_RENAME_ELEM(bTheme, tv3d, space_view3d)
-DNA_STRUCT_RENAME_ELEM(RigidBodyWorld, steps_per_second, substeps_per_frame)
/* Write with a different name, old Blender versions crash loading files with non-NULL
* global_areas. See D9442. */
DNA_STRUCT_RENAME_ELEM(wmWindow, global_area_map, global_areas)
-DNA_STRUCT_RENAME_ELEM(LineartGpencilModifierData, line_types, edge_types)
-DNA_STRUCT_RENAME_ELEM(LineartGpencilModifierData, transparency_flags, mask_switches)
-DNA_STRUCT_RENAME_ELEM(LineartGpencilModifierData, transparency_mask, material_mask_bits)
-DNA_STRUCT_RENAME_ELEM(SurfaceDeformModifierData, numverts, num_bind_verts)
-DNA_STRUCT_RENAME_ELEM(MaterialLineArt, transparency_mask, material_mask_bits)
+
+/* NOTE: Keep sorted! */
diff --git a/source/blender/makesdna/intern/dna_utils.c b/source/blender/makesdna/intern/dna_utils.c
index f050934b5b3..b2e2e263ea3 100644
--- a/source/blender/makesdna/intern/dna_utils.c
+++ b/source/blender/makesdna/intern/dna_utils.c
@@ -39,10 +39,6 @@
/** \name Struct Member Evaluation
* \{ */
-/**
- * Parses the `[n1][n2]...` on the end of an array name
- * and returns the number of array elements `n1 * n2 ...`.
- */
int DNA_elem_array_size(const char *str)
{
int result = 1;
@@ -106,9 +102,6 @@ uint DNA_elem_id_offset_end(const char *elem_full)
return elem_full_offset;
}
-/**
- * \a elem_dst must be at least the size of \a elem_src.
- */
uint DNA_elem_id_strip_copy(char *elem_dst, const char *elem_src)
{
const uint elem_src_offset = DNA_elem_id_offset_start(elem_src);
@@ -129,10 +122,6 @@ uint DNA_elem_id_strip(char *elem)
return elem_trim_len;
}
-/**
- * Check if 'var' matches '*var[3]' for eg,
- * return true if it does, with start/end offsets.
- */
bool DNA_elem_id_match(const char *elem_search,
const int elem_search_len,
const char *elem_full,
@@ -151,9 +140,6 @@ bool DNA_elem_id_match(const char *elem_search,
return false;
}
-/**
- * Return a renamed dna name, allocated from \a mem_arena.
- */
char *DNA_elem_id_rename(struct MemArena *mem_arena,
const char *elem_src,
const int elem_src_len,
@@ -297,19 +283,15 @@ void DNA_alias_maps(enum eDNA_RenameDir version_dir, GHash **r_struct_map, GHash
/** \name Struct Name Legacy Hack
* \{ */
-/**
- * DNA Compatibility Hack
- * ======================
- *
- * Only keep this for compatibility: **NEVER ADD NEW STRINGS HERE**.
- *
- * The renaming here isn't complete, references to the old struct names
- * are still included in DNA, now fixing these struct names properly
- * breaks forward compatibility. Leave these as-is, but don't add to them!
- * See D4342#98780
- */
const char *DNA_struct_rename_legacy_hack_static_from_alias(const char *name)
{
+ /* Only keep this for compatibility: *NEVER ADD NEW STRINGS HERE*.
+ *
+ * The renaming here isn't complete, references to the old struct names
+ * are still included in DNA, now fixing these struct names properly
+ * breaks forward compatibility. Leave these as-is, but don't add to them!
+ * See D4342#98780. */
+
/* 'bScreen' replaces the old IrisGL 'Screen' struct */
if (STREQ("bScreen", name)) {
return "Screen";
diff --git a/source/blender/makesdna/intern/dna_utils.h b/source/blender/makesdna/intern/dna_utils.h
index f711056c575..b89c45a7a43 100644
--- a/source/blender/makesdna/intern/dna_utils.h
+++ b/source/blender/makesdna/intern/dna_utils.h
@@ -27,16 +27,30 @@ extern "C" {
struct GHash;
struct MemArena;
+/**
+ * Parses the `[n1][n2]...` on the end of an array name
+ * and returns the number of array elements `n1 * n2 ...`.
+ */
int DNA_elem_array_size(const char *str);
uint DNA_elem_id_offset_start(const char *elem_full);
uint DNA_elem_id_offset_end(const char *elem_full);
+/**
+ * \a elem_dst must be at least the size of \a elem_src.
+ */
uint DNA_elem_id_strip_copy(char *elem_dst, const char *elem_src);
uint DNA_elem_id_strip(char *elem);
+/**
+ * Check if 'var' matches '*var[3]' for eg,
+ * return true if it does, with start/end offsets.
+ */
bool DNA_elem_id_match(const char *elem_search,
const int elem_search_len,
const char *elem_full,
uint *r_elem_full_offset);
+/**
+ * Return a renamed dna name, allocated from \a mem_arena.
+ */
char *DNA_elem_id_rename(struct MemArena *mem_arena,
const char *elem_src,
const int elem_src_len,
@@ -56,6 +70,9 @@ void DNA_alias_maps(enum eDNA_RenameDir version_dir,
struct GHash **r_elem_map);
const char *DNA_struct_rename_legacy_hack_alias_from_static(const char *name);
+/**
+ * DNA Compatibility Hack.
+ */
const char *DNA_struct_rename_legacy_hack_static_from_alias(const char *name);
#ifdef __cplusplus
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index 188f933dba5..7fa7405add1 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -801,6 +801,11 @@ PropertyRNA *RNA_struct_name_property(const StructRNA *type);
const EnumPropertyItem *RNA_struct_property_tag_defines(const StructRNA *type);
PropertyRNA *RNA_struct_iterator_property(StructRNA *type);
StructRNA *RNA_struct_base(StructRNA *type);
+/**
+ * Use to find the sub-type directly below a base-type.
+ *
+ * So if type were `RNA_SpotLight`, `RNA_struct_base_of(type, &RNA_ID)` would return `&RNA_Light`.
+ */
const StructRNA *RNA_struct_base_child_of(const StructRNA *type, const StructRNA *parent_type);
bool RNA_struct_is_ID(const StructRNA *type);
@@ -823,16 +828,32 @@ struct IDProperty *RNA_struct_idprops(PointerRNA *ptr, bool create);
bool RNA_struct_idprops_check(StructRNA *srna);
bool RNA_struct_idprops_register_check(const StructRNA *type);
bool RNA_struct_idprops_datablock_allowed(const StructRNA *type);
+/**
+ * Whether given type implies datablock usage by IDProperties.
+ * This is used to prevent classes allowed to have IDProperties,
+ * but not datablock ones, to indirectly use some
+ * (e.g. by assigning an IDP_GROUP containing some IDP_ID pointers...).
+ */
bool RNA_struct_idprops_contains_datablock(const StructRNA *type);
+/**
+ * Remove an id-property.
+ */
bool RNA_struct_idprops_unset(PointerRNA *ptr, const char *identifier);
PropertyRNA *RNA_struct_find_property(PointerRNA *ptr, const char *identifier);
bool RNA_struct_contains_property(PointerRNA *ptr, PropertyRNA *prop_test);
unsigned int RNA_struct_count_properties(StructRNA *srna);
-/* lower level functions for access to type properties */
+/**
+ * Low level direct access to type->properties,
+ * note this ignores parent classes so should be used with care.
+ */
const struct ListBase *RNA_struct_type_properties(StructRNA *srna);
PropertyRNA *RNA_struct_type_find_property_no_base(StructRNA *srna, const char *identifier);
+/**
+ * \note #RNA_struct_find_property is a higher level alternative to this function
+ * which takes a #PointerRNA instead of a #StructRNA.
+ */
PropertyRNA *RNA_struct_type_find_property(StructRNA *srna, const char *identifier);
FunctionRNA *RNA_struct_find_function(StructRNA *srna, const char *identifier);
@@ -840,6 +861,9 @@ const struct ListBase *RNA_struct_type_functions(StructRNA *srna);
char *RNA_struct_name_get_alloc(PointerRNA *ptr, char *fixedbuf, int fixedlen, int *r_len);
+/**
+ * Use when registering structs with the #STRUCT_PUBLIC_NAMESPACE flag.
+ */
bool RNA_struct_available_or_report(struct ReportList *reports, const char *identifier);
bool RNA_struct_bl_idname_ok_or_report(struct ReportList *reports,
const char *identifier,
@@ -861,17 +885,32 @@ PropertyUnit RNA_property_unit(PropertyRNA *prop);
PropertyScaleType RNA_property_ui_scale(PropertyRNA *prop);
int RNA_property_flag(PropertyRNA *prop);
int RNA_property_override_flag(PropertyRNA *prop);
+/**
+ * Get the tags set for \a prop as int bitfield.
+ * \note Doesn't perform any validity check on the set bits. #RNA_def_property_tags does this
+ * in debug builds (to avoid performance issues in non-debug builds), which should be
+ * the only way to set tags. Hence, at this point we assume the tag bitfield to be valid.
+ */
int RNA_property_tags(PropertyRNA *prop);
bool RNA_property_builtin(PropertyRNA *prop);
void *RNA_property_py_data_get(PropertyRNA *prop);
int RNA_property_array_length(PointerRNA *ptr, PropertyRNA *prop);
bool RNA_property_array_check(PropertyRNA *prop);
+/**
+ * Return the size of Nth dimension.
+ */
int RNA_property_multi_array_length(PointerRNA *ptr, PropertyRNA *prop, int dimension);
+/**
+ * Used by BPY to make an array from the python object.
+ */
int RNA_property_array_dimension(PointerRNA *ptr, PropertyRNA *prop, int length[]);
char RNA_property_array_item_char(PropertyRNA *prop, int index);
int RNA_property_array_item_index(PropertyRNA *prop, char name);
+/**
+ * \return the maximum length including the \0 terminator. '0' is used when there is no maximum.
+ */
int RNA_property_string_maxlength(PropertyRNA *prop);
const char *RNA_property_ui_name(const PropertyRNA *prop);
@@ -906,6 +945,10 @@ bool RNA_enum_name(const EnumPropertyItem *item, const int value, const char **r
bool RNA_enum_description(const EnumPropertyItem *item, const int value, const char **description);
int RNA_enum_from_value(const EnumPropertyItem *item, const int value);
int RNA_enum_from_identifier(const EnumPropertyItem *item, const char *identifier);
+/**
+ * Take care using this with translated enums,
+ * prefer #RNA_enum_from_identifier where possible.
+ */
int RNA_enum_from_name(const EnumPropertyItem *item, const char *name);
unsigned int RNA_enum_items_count(const EnumPropertyItem *item);
@@ -967,27 +1010,54 @@ StructRNA *RNA_property_pointer_type(PointerRNA *ptr, PropertyRNA *prop);
bool RNA_property_pointer_poll(PointerRNA *ptr, PropertyRNA *prop, PointerRNA *value);
bool RNA_property_editable(PointerRNA *ptr, PropertyRNA *prop);
+/**
+ * Version of #RNA_property_editable that tries to return additional info in \a r_info
+ * that can be exposed in UI.
+ */
bool RNA_property_editable_info(PointerRNA *ptr, PropertyRNA *prop, const char **r_info);
+/**
+ * Same as RNA_property_editable(), except this checks individual items in an array.
+ */
bool RNA_property_editable_index(PointerRNA *ptr, PropertyRNA *prop, int index);
-/* without lib check, only checks the flag */
+/**
+ * Without lib check, only checks the flag.
+ */
bool RNA_property_editable_flag(PointerRNA *ptr, PropertyRNA *prop);
bool RNA_property_animateable(PointerRNA *ptr, PropertyRNA *prop);
bool RNA_property_animated(PointerRNA *ptr, PropertyRNA *prop);
+/**
+ * \note Does not take into account editable status, this has to be checked separately
+ * (using #RNA_property_editable_flag() usually).
+ */
bool RNA_property_overridable_get(PointerRNA *ptr, PropertyRNA *prop);
+/**
+ * Should only be used for custom properties.
+ */
bool RNA_property_overridable_library_set(PointerRNA *ptr,
PropertyRNA *prop,
const bool is_overridable);
bool RNA_property_overridden(PointerRNA *ptr, PropertyRNA *prop);
bool RNA_property_comparable(PointerRNA *ptr, PropertyRNA *prop);
+/**
+ * This function is to check if its possible to create a valid path from the ID
+ * its slow so don't call in a loop.
+ */
bool RNA_property_path_from_ID_check(PointerRNA *ptr, PropertyRNA *prop); /* slow, use with care */
void RNA_property_update(struct bContext *C, PointerRNA *ptr, PropertyRNA *prop);
+/**
+ * \param scene: may be NULL.
+ */
void RNA_property_update_main(struct Main *bmain,
struct Scene *scene,
PointerRNA *ptr,
PropertyRNA *prop);
+/**
+ * \note its possible this returns a false positive in the case of #PROP_CONTEXT_UPDATE
+ * but this isn't likely to be a performance problem.
+ */
bool RNA_property_update_check(struct PropertyRNA *prop);
/* Property Data */
@@ -1031,15 +1101,28 @@ char *RNA_property_string_get_alloc(
PointerRNA *ptr, PropertyRNA *prop, char *fixedbuf, int fixedlen, int *r_len);
void RNA_property_string_set(PointerRNA *ptr, PropertyRNA *prop, const char *value);
void RNA_property_string_set_bytes(PointerRNA *ptr, PropertyRNA *prop, const char *value, int len);
+/**
+ * \return the length without `\0` terminator.
+ */
int RNA_property_string_length(PointerRNA *ptr, PropertyRNA *prop);
void RNA_property_string_get_default(PropertyRNA *prop, char *value, int max_len);
char *RNA_property_string_get_default_alloc(
PointerRNA *ptr, PropertyRNA *prop, char *fixedbuf, int fixedlen, int *r_len);
+/**
+ * \return the length without `\0` terminator.
+ */
int RNA_property_string_default_length(PointerRNA *ptr, PropertyRNA *prop);
int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop);
void RNA_property_enum_set(PointerRNA *ptr, PropertyRNA *prop, int value);
int RNA_property_enum_get_default(PointerRNA *ptr, PropertyRNA *prop);
+/**
+ * Get the value of the item that is \a step items away from \a from_value.
+ *
+ * \param from_value: Item value to start stepping from.
+ * \param step: Absolute value defines step size, sign defines direction.
+ * E.g to get the next item, pass 1, for the previous -1.
+ */
int RNA_property_enum_step(
const struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, int from_value, int step);
@@ -1068,6 +1151,9 @@ int RNA_property_collection_lookup_string(PointerRNA *ptr,
PointerRNA *r_ptr);
int RNA_property_collection_lookup_string_index(
PointerRNA *ptr, PropertyRNA *prop, const char *key, PointerRNA *r_ptr, int *r_index);
+/**
+ * Zero return is an assignment error.
+ */
int RNA_property_collection_assign_int(PointerRNA *ptr,
PropertyRNA *prop,
const int key,
@@ -1125,31 +1211,99 @@ char *RNA_path_append(
char *RNA_path_back(const char *path);
#endif
-/* path_resolve() variants only ensure that a valid pointer (and optionally property) exist */
+/* RNA_path_resolve() variants only ensure that a valid pointer (and optionally property) exist. */
+
+/**
+ * Resolve the given RNA Path to find the pointer and/or property
+ * indicated by fully resolving the path.
+ *
+ * \warning Unlike \a RNA_path_resolve_property(), that one *will* try to follow RNAPointers,
+ * e.g. the path 'parent' applied to a RNAObject \a ptr will return the object.parent in \a r_ptr,
+ * and a NULL \a r_prop...
+ *
+ * \note Assumes all pointers provided are valid
+ * \return True if path can be resolved to a valid "pointer + property" OR "pointer only"
+ */
bool RNA_path_resolve(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop);
+/**
+ * Resolve the given RNA Path to find the pointer and/or property + array index
+ * indicated by fully resolving the path.
+ *
+ * \note Assumes all pointers provided are valid.
+ * \return True if path can be resolved to a valid "pointer + property" OR "pointer only"
+ */
bool RNA_path_resolve_full(
PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index);
+/**
+ * A version of #RNA_path_resolve_full doesn't check the value of #PointerRNA.data.
+ *
+ * \note While it's correct to ignore the value of #PointerRNA.data
+ * most callers need to know if the resulting pointer was found and not null.
+ */
bool RNA_path_resolve_full_maybe_null(
PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index);
-/* path_resolve_property() variants ensure that pointer + property both exist */
+/* RNA_path_resolve_property() variants ensure that pointer + property both exist. */
+
+/**
+ * Resolve the given RNA Path to find both the pointer AND property
+ * indicated by fully resolving the path.
+ *
+ * This is a convenience method to avoid logic errors and ugly syntax.
+ * \note Assumes all pointers provided are valid
+ * \return True only if both a valid pointer and property are found after resolving the path
+ */
bool RNA_path_resolve_property(PointerRNA *ptr,
const char *path,
PointerRNA *r_ptr,
PropertyRNA **r_prop);
+/**
+ * Resolve the given RNA Path to find the pointer AND property (as well as the array index)
+ * indicated by fully resolving the path.
+ *
+ * This is a convenience method to avoid logic errors and ugly syntax.
+ * \note Assumes all pointers provided are valid
+ * \return True only if both a valid pointer and property are found after resolving the path
+ */
bool RNA_path_resolve_property_full(
PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index);
-/* path_resolve_property_and_item_pointer() variants ensure that pointer + property both exist,
+/* RNA_path_resolve_property_and_item_pointer() variants ensure that pointer + property both exist,
* and resolve last Pointer value if possible (Pointer prop or item of a Collection prop). */
+
+/**
+ * Resolve the given RNA Path to find both the pointer AND property
+ * indicated by fully resolving the path, and get the value of the Pointer property
+ * (or item of the collection).
+ *
+ * This is a convenience method to avoid logic errors and ugly syntax,
+ * it combines both \a RNA_path_resolve and #RNA_path_resolve_property in a single call.
+ * \note Assumes all pointers provided are valid.
+ * \param r_item_ptr: The final Pointer or Collection item value.
+ * You must check for its validity before use!
+ * \return True only if both a valid pointer and property are found after resolving the path
+ */
bool RNA_path_resolve_property_and_item_pointer(PointerRNA *ptr,
const char *path,
PointerRNA *r_ptr,
PropertyRNA **r_prop,
PointerRNA *r_item_ptr);
+/**
+ * Resolve the given RNA Path to find both the pointer AND property (as well as the array index)
+ * indicated by fully resolving the path,
+ * and get the value of the Pointer property (or item of the collection).
+ *
+ * This is a convenience method to avoid logic errors and ugly syntax,
+ * it combines both \a RNA_path_resolve_full and
+ * \a RNA_path_resolve_property_full in a single call.
+ * \note Assumes all pointers provided are valid.
+ * \param r_item_ptr: The final Pointer or Collection item value.
+ * You must check for its validity before use!
+ * \return True only if both a valid pointer and property are found after resolving the path
+ */
bool RNA_path_resolve_property_and_item_pointer_full(PointerRNA *ptr,
const char *path,
PointerRNA *r_ptr,
@@ -1164,10 +1318,36 @@ struct PropertyElemRNA {
PropertyRNA *prop;
int index;
};
+/**
+ * Resolve the given RNA Path into a linked list of #PropertyElemRNA's.
+ *
+ * To be used when complex operations over path are needed, like e.g. get relative paths,
+ * to avoid too much string operations.
+ *
+ * \return True if there was no error while resolving the path
+ * \note Assumes all pointers provided are valid
+ */
bool RNA_path_resolve_elements(PointerRNA *ptr, const char *path, struct ListBase *r_elements);
+/**
+ * Find the path from the structure referenced by the pointer to the runtime RNA-defined
+ * #IDProperty object.
+ *
+ * \note Does *not* handle pure user-defined IDProperties (a.k.a. custom properties).
+ *
+ * \param ptr: Reference to the object owning the custom property storage.
+ * \param needle: Custom property object to find.
+ * \return Relative path or NULL.
+ */
char *RNA_path_from_struct_to_idproperty(PointerRNA *ptr, struct IDProperty *needle);
+/**
+ * Find the actual ID pointer and path from it to the given ID.
+ *
+ * \param id: ID reference to search the global owner for.
+ * \param[out] r_path: Path from the real ID to the initial ID.
+ * \return The ID pointer, or NULL in case of failure.
+ */
struct ID *RNA_find_real_ID_and_path(struct Main *bmain, struct ID *id, const char **r_path);
char *RNA_path_from_ID_to_struct(const PointerRNA *ptr);
@@ -1175,6 +1355,11 @@ char *RNA_path_from_ID_to_struct(const PointerRNA *ptr);
char *RNA_path_from_real_ID_to_struct(struct Main *bmain, PointerRNA *ptr, struct ID **r_real);
char *RNA_path_from_ID_to_property(PointerRNA *ptr, PropertyRNA *prop);
+/**
+ * \param index_dim: The dimension to show, 0 disables. 1 for 1d array, 2 for 2d. etc.
+ * \param index: The *flattened* index to use when \a `index_dim > 0`,
+ * this is expanded when used with multi-dimensional arrays.
+ */
char *RNA_path_from_ID_to_property_index(PointerRNA *ptr,
PropertyRNA *prop,
int index_dim,
@@ -1187,19 +1372,43 @@ char *RNA_path_from_real_ID_to_property_index(struct Main *bmain,
int index,
struct ID **r_real_id);
+/**
+ * \return the path to given ptr/prop from the closest ancestor of given type,
+ * if any (else return NULL).
+ */
char *RNA_path_resolve_from_type_to_property(struct PointerRNA *ptr,
struct PropertyRNA *prop,
const struct StructRNA *type);
+/**
+ * Get the ID as a python representation, eg:
+ * bpy.data.foo["bar"]
+ */
char *RNA_path_full_ID_py(struct Main *bmain, struct ID *id);
+/**
+ * Get the ID.struct as a python representation, eg:
+ * bpy.data.foo["bar"].some_struct
+ */
char *RNA_path_full_struct_py(struct Main *bmain, struct PointerRNA *ptr);
+/**
+ * Get the ID.struct.property as a python representation, eg:
+ * bpy.data.foo["bar"].some_struct.some_prop[10]
+ */
char *RNA_path_full_property_py_ex(
struct Main *bmain, PointerRNA *ptr, PropertyRNA *prop, int index, bool use_fallback);
char *RNA_path_full_property_py(struct Main *bmain,
struct PointerRNA *ptr,
struct PropertyRNA *prop,
int index);
+/**
+ * Get the struct.property as a python representation, eg:
+ * some_struct.some_prop[10]
+ */
char *RNA_path_struct_property_py(struct PointerRNA *ptr, struct PropertyRNA *prop, int index);
+/**
+ * Get the struct.property as a python representation, eg:
+ * some_prop[10]
+ */
char *RNA_path_property_py(const struct PointerRNA *ptr, struct PropertyRNA *prop, int index);
/* Quick name based property access
@@ -1314,24 +1523,38 @@ void RNA_collection_clear(PointerRNA *ptr, const char *name);
} \
((void)0)
-/* check if the idproperty exists, for operators */
+/**
+ * Check if the #IDproperty exists, for operators.
+ */
bool RNA_property_is_set_ex(PointerRNA *ptr, PropertyRNA *prop, bool use_ghost);
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop);
void RNA_property_unset(PointerRNA *ptr, PropertyRNA *prop);
bool RNA_struct_property_is_set_ex(PointerRNA *ptr, const char *identifier, bool use_ghost);
bool RNA_struct_property_is_set(PointerRNA *ptr, const char *identifier);
bool RNA_property_is_idprop(const PropertyRNA *prop);
+/**
+ * \note Mainly for the UI.
+ */
bool RNA_property_is_unlink(PropertyRNA *prop);
void RNA_struct_property_unset(PointerRNA *ptr, const char *identifier);
-/* python compatible string representation of this property, (must be freed!) */
+/**
+ * Python compatible string representation of this property, (must be freed!).
+ */
char *RNA_property_as_string(
struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, int index, int max_prop_length);
+/**
+ * String representation of a property, Python compatible but can be used for display too.
+ * \param C: can be NULL.
+ */
char *RNA_pointer_as_string_id(struct bContext *C, PointerRNA *ptr);
char *RNA_pointer_as_string(struct bContext *C,
PointerRNA *ptr,
PropertyRNA *prop_ptr,
PointerRNA *ptr_prop);
+/**
+ * \param C: can be NULL.
+ */
char *RNA_pointer_as_string_keywords_ex(struct bContext *C,
PointerRNA *ptr,
const bool as_function,
@@ -1383,7 +1606,9 @@ void RNA_parameter_get(ParameterList *parms, PropertyRNA *parm, void **value);
void RNA_parameter_get_lookup(ParameterList *parms, const char *identifier, void **value);
void RNA_parameter_set(ParameterList *parms, PropertyRNA *parm, const void *value);
void RNA_parameter_set_lookup(ParameterList *parms, const char *identifier, const void *value);
+
/* Only for PROP_DYNAMIC properties! */
+
int RNA_parameter_dynamic_length_get(ParameterList *parms, PropertyRNA *parm);
int RNA_parameter_dynamic_length_get_data(ParameterList *parms, PropertyRNA *parm, void *data);
void RNA_parameter_dynamic_length_set(ParameterList *parms, PropertyRNA *parm, int length);
@@ -1454,6 +1679,7 @@ StructRNA *ID_code_to_RNA_type(short idcode);
# define RNA_warning(format, ...) _RNA_warning("%s: " format "\n", __FUNCTION__, __VA_ARGS__)
#endif
+/** Use to implement the #RNA_warning macro which includes `__func__` suffix. */
void _RNA_warning(const char *format, ...) ATTR_PRINTF_FORMAT(1, 2);
/* Equals test. */
@@ -1520,6 +1746,16 @@ typedef enum eRNAOverrideStatus {
RNA_OVERRIDE_STATUS_LOCKED = 1 << 3,
} eRNAOverrideStatus;
+/**
+ * Check whether reference and local overridden data match (are the same),
+ * with respect to given restrictive sets of properties.
+ * If requested, will generate needed new property overrides, and/or restore values from reference.
+ *
+ * \param r_report_flags: If given,
+ * will be set with flags matching actions taken by the function on \a ptr_local.
+ *
+ * \return True if _resulting_ \a ptr_local does match \a ptr_reference.
+ */
bool RNA_struct_override_matches(struct Main *bmain,
struct PointerRNA *ptr_local,
struct PointerRNA *ptr_reference,
@@ -1529,6 +1765,10 @@ bool RNA_struct_override_matches(struct Main *bmain,
const eRNAOverrideMatch flags,
eRNAOverrideMatchResult *r_report_flags);
+/**
+ * Store needed second operands into \a storage data-block
+ * for differential override operations.
+ */
bool RNA_struct_override_store(struct Main *bmain,
struct PointerRNA *ptr_local,
struct PointerRNA *ptr_reference,
@@ -1544,6 +1784,10 @@ typedef enum eRNAOverrideApplyFlag {
RNA_OVERRIDE_APPLY_FLAG_IGNORE_ID_POINTERS = 1 << 0,
} eRNAOverrideApplyFlag;
+/**
+ * Apply given \a override operations on \a ptr_dst, using \a ptr_src
+ * (and \a ptr_storage for differential ops) as source.
+ */
void RNA_struct_override_apply(struct Main *bmain,
struct PointerRNA *ptr_dst,
struct PointerRNA *ptr_src,
diff --git a/source/blender/makesrna/RNA_define.h b/source/blender/makesrna/RNA_define.h
index 01e26cbb41c..3596a5f2234 100644
--- a/source/blender/makesrna/RNA_define.h
+++ b/source/blender/makesrna/RNA_define.h
@@ -49,6 +49,10 @@ void RNA_free(BlenderRNA *brna);
void RNA_define_verify_sdna(bool verify);
void RNA_define_animate_sdna(bool animate);
void RNA_define_fallback_property_update(int noteflag, const char *updatefunc);
+/**
+ * Properties defined when this is enabled are lib-overridable by default
+ * (except for Pointer ones).
+ */
void RNA_define_lib_overridable(const bool make_overridable);
void RNA_init(void);
@@ -56,6 +60,9 @@ void RNA_exit(void);
/* Struct */
+/**
+ * Struct Definition.
+ */
StructRNA *RNA_def_struct_ptr(BlenderRNA *brna, const char *identifier, StructRNA *srnafrom);
StructRNA *RNA_def_struct(BlenderRNA *brna, const char *identifier, const char *from);
void RNA_def_struct_sdna(StructRNA *srna, const char *structname);
@@ -72,6 +79,9 @@ void RNA_def_struct_register_funcs(StructRNA *srna,
const char *unreg,
const char *instance);
void RNA_def_struct_path_func(StructRNA *srna, const char *path);
+/**
+ * Only used in one case when we name the struct for the purpose of useful error messages.
+ */
void RNA_def_struct_identifier_no_struct_map(StructRNA *srna, const char *identifier);
void RNA_def_struct_identifier(BlenderRNA *brna, StructRNA *srna, const char *identifier);
void RNA_def_struct_ui_text(StructRNA *srna, const char *name, const char *description);
@@ -176,6 +186,9 @@ PropertyRNA *RNA_def_enum(StructOrFunctionRNA *cont,
int default_value,
const char *ui_name,
const char *ui_description);
+/**
+ * Same as above but sets #PROP_ENUM_FLAG before setting the default value.
+ */
PropertyRNA *RNA_def_enum_flag(StructOrFunctionRNA *cont,
const char *identifier,
const EnumPropertyItem *items,
@@ -362,6 +375,13 @@ void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag);
void RNA_def_property_clear_flag(PropertyRNA *prop, PropertyFlag flag);
void RNA_def_property_override_flag(PropertyRNA *prop, PropertyOverrideFlag flag);
void RNA_def_property_override_clear_flag(PropertyRNA *prop, PropertyOverrideFlag flag);
+/**
+ * Add the property-tags passed as \a tags to \a prop (if valid).
+ *
+ * \note Multiple tags can be set by passing them within \a tags (using bit-flags).
+ * \note Doesn't do any type-checking with the tags defined in the parent #StructRNA
+ * of \a prop. This should be done before (e.g. see #WM_operatortype_prop_tag).
+ */
void RNA_def_property_tags(PropertyRNA *prop, int tags);
void RNA_def_property_subtype(PropertyRNA *prop, PropertySubType subtype);
void RNA_def_property_array(PropertyRNA *prop, int length);
@@ -381,11 +401,25 @@ void RNA_def_property_boolean_array_default(PropertyRNA *prop, const bool *array
void RNA_def_property_int_default(PropertyRNA *prop, int value);
void RNA_def_property_int_array_default(PropertyRNA *prop, const int *array);
void RNA_def_property_float_default(PropertyRNA *prop, float value);
+/**
+ * Array must remain valid after this function finishes.
+ */
void RNA_def_property_float_array_default(PropertyRNA *prop, const float *array);
void RNA_def_property_enum_default(PropertyRNA *prop, int value);
void RNA_def_property_string_default(PropertyRNA *prop, const char *value);
void RNA_def_property_ui_text(PropertyRNA *prop, const char *name, const char *description);
+/**
+ * The values hare are a little confusing:
+ *
+ * \param step: Used as the value to increase/decrease when clicking on number buttons,
+ * as well as scaling mouse input for click-dragging number buttons.
+ * For floats this is (step * UI_PRECISION_FLOAT_SCALE), why? - nobody knows.
+ * For ints, whole values are used.
+ *
+ * \param precision: The number of zeros to show
+ * (as a whole number - common range is 1 - 6), see UI_PRECISION_FLOAT_MAX
+ */
void RNA_def_property_ui_range(
PropertyRNA *prop, double min, double max, double step, int precision);
void RNA_def_property_ui_scale_type(PropertyRNA *prop, PropertyScaleType scale_type);
@@ -395,6 +429,11 @@ void RNA_def_property_update(PropertyRNA *prop, int noteflag, const char *update
void RNA_def_property_editable_func(PropertyRNA *prop, const char *editable);
void RNA_def_property_editable_array_func(PropertyRNA *prop, const char *editable);
+/**
+ * Set custom callbacks for override operations handling.
+ *
+ * \note \a diff callback will also be used by RNA comparison/equality functions.
+ */
void RNA_def_property_override_funcs(PropertyRNA *prop,
const char *diff,
const char *store,
@@ -472,6 +511,9 @@ void RNA_def_property_translation_context(PropertyRNA *prop, const char *context
FunctionRNA *RNA_def_function(StructRNA *srna, const char *identifier, const char *call);
FunctionRNA *RNA_def_function_runtime(StructRNA *srna, const char *identifier, CallFunc call);
+/**
+ * C return value only! multiple RNA returns can be done with #RNA_def_function_output.
+ */
void RNA_def_function_return(FunctionRNA *func, PropertyRNA *ret);
void RNA_def_function_output(FunctionRNA *func, PropertyRNA *ret);
void RNA_def_function_flag(FunctionRNA *func, int flag);
@@ -514,7 +556,8 @@ void RNA_def_property_free_identifier_deferred_finish(StructOrFunctionRNA *cont_
void RNA_def_property_free_pointers_set_py_data_callback(
void (*py_data_clear_fn)(PropertyRNA *prop));
-/* utilities */
+/* Utilities. */
+
const char *RNA_property_typename(PropertyType type);
#define IS_DNATYPE_FLOAT_COMPAT(_str) (strcmp(_str, "float") == 0 || strcmp(_str, "double") == 0)
#define IS_DNATYPE_INT_COMPAT(_str) \
@@ -525,16 +568,19 @@ const char *RNA_property_typename(PropertyType type);
void RNA_identifier_sanitize(char *identifier, int property);
+/* Common arguments for length. */
+
extern const int rna_matrix_dimsize_3x3[];
extern const int rna_matrix_dimsize_4x4[];
extern const int rna_matrix_dimsize_4x2[];
+/* Common arguments for defaults. */
+
extern const float rna_default_axis_angle[4];
extern const float rna_default_quaternion[4];
extern const float rna_default_scale_3d[3];
-/* max size for dynamic defined type descriptors,
- * this value is arbitrary */
+/** Maximum size for dynamic defined type descriptors, this value is arbitrary. */
#define RNA_DYN_DESCR_MAX 240
#ifdef __cplusplus
diff --git a/source/blender/makesrna/RNA_enum_items.h b/source/blender/makesrna/RNA_enum_items.h
index fb18802483d..531af92c544 100644
--- a/source/blender/makesrna/RNA_enum_items.h
+++ b/source/blender/makesrna/RNA_enum_items.h
@@ -61,6 +61,8 @@ DEF_ENUM(rna_enum_object_shaderfx_type_items)
DEF_ENUM(rna_enum_modifier_triangulate_quad_method_items)
DEF_ENUM(rna_enum_modifier_triangulate_ngon_method_items)
DEF_ENUM(rna_enum_modifier_shrinkwrap_mode_items)
+DEF_ENUM(rna_enum_shrinkwrap_type_items)
+DEF_ENUM(rna_enum_shrinkwrap_face_cull_items)
DEF_ENUM(rna_enum_image_type_items)
DEF_ENUM(rna_enum_image_color_mode_items)
@@ -172,6 +174,7 @@ DEF_ENUM(rna_enum_mapping_type_items)
DEF_ENUM(rna_enum_node_vec_math_items)
DEF_ENUM(rna_enum_node_boolean_math_items)
DEF_ENUM(rna_enum_node_float_compare_items)
+DEF_ENUM(rna_enum_node_compare_operation_items)
DEF_ENUM(rna_enum_node_filter_items)
DEF_ENUM(rna_enum_node_float_to_int_items)
DEF_ENUM(rna_enum_node_map_range_items)
@@ -210,6 +213,7 @@ DEF_ENUM(rna_enum_attribute_type_with_auto_items)
DEF_ENUM(rna_enum_attribute_domain_items)
DEF_ENUM(rna_enum_attribute_domain_without_corner_items)
DEF_ENUM(rna_enum_attribute_domain_with_auto_items)
+DEF_ENUM(rna_enum_geometry_component_type_items)
DEF_ENUM(rna_enum_volume_grid_data_type_items)
@@ -221,7 +225,7 @@ DEF_ENUM(rna_enum_subdivision_boundary_smooth_items)
DEF_ENUM(rna_enum_transform_orientation_items)
-/* Not available to RNA pre-processing (`makrsrna`).
+/* Not available to RNA pre-processing (`makesrna`).
* Defined in editors for example. */
#ifndef RNA_MAKESRNA
diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h
index d7520834287..da07f1043a7 100644
--- a/source/blender/makesrna/RNA_enum_types.h
+++ b/source/blender/makesrna/RNA_enum_types.h
@@ -83,8 +83,10 @@ const EnumPropertyItem *rna_TransformOrientation_itemf(struct bContext *C,
struct PropertyRNA *prop,
bool *r_free);
-/* Generic functions, return an enum from library data, index is the position
- * in the linked list can add more for different types as needed */
+/**
+ * Generic functions, return an enum from library data, index is the position
+ * in the linked list can add more for different types as needed.
+ */
const EnumPropertyItem *RNA_action_itemf(struct bContext *C,
struct PointerRNA *ptr,
struct PropertyRNA *prop,
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index 40b5f3ed1da..b64fa58cf6b 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -438,12 +438,6 @@ static PropertyRNA *arraytypemap[IDP_NUMTYPES] = {
(PropertyRNA *)&rna_PropertyGroupItem_double_array,
};
-/* This function initializes a PropertyRNAOrID with all required info, from a given PropertyRNA
- * and PointerRNA data. It deals properly with the three cases (static RNA, runtime RNA, and
- * IDProperty).
- * WARNING: given `ptr` PointerRNA is assumed to be a valid data one here, calling code is
- * responsible to ensure that.
- */
void rna_property_rna_or_id_get(PropertyRNA *prop,
PointerRNA *ptr,
PropertyRNAOrID *r_prop_rna_or_id)
@@ -515,8 +509,6 @@ void rna_property_rna_or_id_get(PropertyRNA *prop,
}
}
-/* This function only returns an IDProperty,
- * or NULL (in case IDProp could not be found, or prop is a real RNA property). */
IDProperty *rna_idproperty_check(PropertyRNA **prop, PointerRNA *ptr)
{
PropertyRNAOrID prop_rna_or_id;
@@ -527,8 +519,6 @@ IDProperty *rna_idproperty_check(PropertyRNA **prop, PointerRNA *ptr)
return prop_rna_or_id.idprop;
}
-/* This function always return the valid, real data pointer, be it a regular RNA property one,
- * or an IDProperty one. */
PropertyRNA *rna_ensure_property_realdata(PropertyRNA **prop, PointerRNA *ptr)
{
PropertyRNAOrID prop_rna_or_id;
@@ -661,11 +651,6 @@ StructRNA *RNA_struct_base(StructRNA *type)
return type->base;
}
-/**
- * Use to find the subtype directly below a base-type.
- *
- * So if type were `RNA_SpotLIght`, `RNA_struct_base_of(type, &RNA_ID)` would return `&RNA_Light`.
- */
const StructRNA *RNA_struct_base_child_of(const StructRNA *type, const StructRNA *parent_type)
{
while (type) {
@@ -697,18 +682,11 @@ bool RNA_struct_idprops_datablock_allowed(const StructRNA *type)
return (type->flag & (STRUCT_NO_DATABLOCK_IDPROPERTIES | STRUCT_NO_IDPROPERTIES)) == 0;
}
-/**
- * Whether given type implies datablock usage by IDProperties.
- * This is used to prevent classes allowed to have IDProperties,
- * but not datablock ones, to indirectly use some
- * (e.g. by assigning an IDP_GROUP containing some IDP_ID pointers...).
- */
bool RNA_struct_idprops_contains_datablock(const StructRNA *type)
{
return (type->flag & (STRUCT_CONTAINS_DATABLOCK_IDPROPERTIES | STRUCT_ID)) != 0;
}
-/* remove an id-property */
bool RNA_struct_idprops_unset(PointerRNA *ptr, const char *identifier)
{
IDProperty *group = RNA_struct_idprops(ptr, 0);
@@ -825,8 +803,6 @@ unsigned int RNA_struct_count_properties(StructRNA *srna)
return counter;
}
-/* Low level direct access to type->properties,
- * note this ignores parent classes so should be used with care. */
const struct ListBase *RNA_struct_type_properties(StructRNA *srna)
{
return &srna->cont.properties;
@@ -837,10 +813,6 @@ PropertyRNA *RNA_struct_type_find_property_no_base(StructRNA *srna, const char *
return BLI_findstring_ptr(&srna->cont.properties, identifier, offsetof(PropertyRNA, identifier));
}
-/**
- * \note #RNA_struct_find_property is a higher level alternative to this function
- * which takes a #PointerRNA instead of a #StructRNA.
- */
PropertyRNA *RNA_struct_type_find_property(StructRNA *srna, const char *identifier)
{
for (; srna; srna = srna->base) {
@@ -953,9 +925,6 @@ char *RNA_struct_name_get_alloc(PointerRNA *ptr, char *fixedbuf, int fixedlen, i
return NULL;
}
-/**
- * Use when registering structs with the #STRUCT_PUBLIC_NAMESPACE flag.
- */
bool RNA_struct_available_or_report(ReportList *reports, const char *identifier)
{
const StructRNA *srna_exists = RNA_struct_find(identifier);
@@ -1098,12 +1067,6 @@ int RNA_property_flag(PropertyRNA *prop)
return rna_ensure_property(prop)->flag;
}
-/**
- * Get the tags set for \a prop as int bitfield.
- * \note Doesn't perform any validity check on the set bits. #RNA_def_property_tags does this
- * in debug builds (to avoid performance issues in non-debug builds), which should be
- * the only way to set tags. Hence, at this point we assume the tag bitfield to be valid.
- */
int RNA_property_tags(PropertyRNA *prop)
{
return rna_ensure_property(prop)->tags;
@@ -1129,7 +1092,6 @@ bool RNA_property_array_check(PropertyRNA *prop)
return rna_ensure_property_array_check(prop);
}
-/* used by BPY to make an array from the python object */
int RNA_property_array_dimension(PointerRNA *ptr, PropertyRNA *prop, int length[])
{
PropertyRNA *rprop = rna_ensure_property(prop);
@@ -1141,7 +1103,6 @@ int RNA_property_array_dimension(PointerRNA *ptr, PropertyRNA *prop, int length[
return rprop->arraydimension;
}
-/* Return the size of Nth dimension. */
int RNA_property_multi_array_length(PointerRNA *ptr, PropertyRNA *prop, int dim)
{
int len[RNA_MAX_ARRAY_DIMENSION];
@@ -1445,9 +1406,6 @@ int RNA_property_int_clamp(PointerRNA *ptr, PropertyRNA *prop, int *value)
return 0;
}
-/**
- * \return the maximum length including the \0 terminator. '0' is used when there is no maximum.
- */
int RNA_property_string_maxlength(PropertyRNA *prop)
{
StringPropertyRNA *sprop = (StringPropertyRNA *)rna_ensure_property(prop);
@@ -1774,10 +1732,6 @@ int RNA_enum_from_identifier(const EnumPropertyItem *item, const char *identifie
return -1;
}
-/**
- * Take care using this with translated enums,
- * prefer #RNA_enum_from_identifier where possible.
- */
int RNA_enum_from_name(const EnumPropertyItem *item, const char *name)
{
int i = 0;
@@ -1973,10 +1927,6 @@ bool RNA_property_editable(PointerRNA *ptr, PropertyRNA *prop_orig)
(!ID_IS_OVERRIDE_LIBRARY(id) || RNA_property_overridable_get(ptr, prop_orig)))));
}
-/**
- * Version of #RNA_property_editable that tries to return additional info in \a r_info
- * that can be exposed in UI.
- */
bool RNA_property_editable_info(PointerRNA *ptr, PropertyRNA *prop, const char **r_info)
{
ID *id = ptr->owner_id;
@@ -2027,7 +1977,6 @@ bool RNA_property_editable_flag(PointerRNA *ptr, PropertyRNA *prop)
return (flag & PROP_EDITABLE) != 0;
}
-/* same as RNA_property_editable(), except this checks individual items in an array */
bool RNA_property_editable_index(PointerRNA *ptr, PropertyRNA *prop, int index)
{
ID *id;
@@ -2090,8 +2039,6 @@ bool RNA_property_animated(PointerRNA *ptr, PropertyRNA *prop)
return false;
}
-/* this function is to check if its possible to create a valid path from the ID
- * its slow so don't call in a loop */
bool RNA_property_path_from_ID_check(PointerRNA *ptr, PropertyRNA *prop)
{
char *path = RNA_path_from_ID_to_property(ptr, prop);
@@ -2194,11 +2141,9 @@ static void rna_property_update(
}
}
-/* must keep in sync with 'rna_property_update'
- * NOTE: its possible this returns a false positive in the case of #PROP_CONTEXT_UPDATE
- * but this isn't likely to be a performance problem. */
bool RNA_property_update_check(PropertyRNA *prop)
{
+ /* NOTE: must keep in sync with #rna_property_update. */
return (prop->magic != RNA_MAGIC || prop->update || prop->noteflag);
}
@@ -2207,7 +2152,6 @@ void RNA_property_update(bContext *C, PointerRNA *ptr, PropertyRNA *prop)
rna_property_update(C, CTX_data_main(C), CTX_data_scene(C), ptr, prop);
}
-/* NOTE: `scene` pointer may be NULL. */
void RNA_property_update_main(Main *bmain, Scene *scene, PointerRNA *ptr, PropertyRNA *prop)
{
rna_property_update(NULL, bmain, scene, ptr, prop);
@@ -3277,7 +3221,6 @@ char *RNA_property_string_get_alloc(
return buf;
}
-/* this is the length without \0 terminator */
int RNA_property_string_length(PointerRNA *ptr, PropertyRNA *prop)
{
StringPropertyRNA *sprop = (StringPropertyRNA *)prop;
@@ -3417,7 +3360,6 @@ char *RNA_property_string_get_default_alloc(
return buf;
}
-/* this is the length without \0 terminator */
int RNA_property_string_default_length(PointerRNA *UNUSED(ptr), PropertyRNA *prop)
{
StringPropertyRNA *sprop = (StringPropertyRNA *)rna_ensure_property(prop);
@@ -3498,13 +3440,6 @@ int RNA_property_enum_get_default(PointerRNA *UNUSED(ptr), PropertyRNA *prop)
return eprop->defaultvalue;
}
-/**
- * Get the value of the item that is \a step items away from \a from_value.
- *
- * \param from_value: Item value to start stepping from.
- * \param step: Absolute value defines step size, sign defines direction.
- * E.g to get the next item, pass 1, for the previous -1.
- */
int RNA_property_enum_step(
const bContext *C, PointerRNA *ptr, PropertyRNA *prop, int from_value, int step)
{
@@ -4212,7 +4147,6 @@ int RNA_property_collection_lookup_string(PointerRNA *ptr,
return RNA_property_collection_lookup_string_index(ptr, prop, key, r_ptr, &index);
}
-/* zero return is an assignment error */
int RNA_property_collection_assign_int(PointerRNA *ptr,
PropertyRNA *prop,
const int key,
@@ -4987,6 +4921,10 @@ static char *rna_path_token_in_brackets(const char **path,
return buf;
}
+/**
+ * \return true when when the key in the path is correctly parsed and found in the collection
+ * or when the path is empty.
+ */
static bool rna_path_parse_collection_key(const char **path,
PointerRNA *ptr,
PropertyRNA *prop,
@@ -5002,6 +4940,7 @@ static bool rna_path_parse_collection_key(const char **path,
return true;
}
+ bool found = false;
if (**path == '[') {
bool quoted;
char *token;
@@ -5016,7 +4955,7 @@ static bool rna_path_parse_collection_key(const char **path,
/* check for "" to see if it is a string */
if (quoted) {
if (RNA_property_collection_lookup_string(ptr, prop, token, r_nextptr)) {
- /* pass */
+ found = true;
}
else {
r_nextptr->data = NULL;
@@ -5029,7 +4968,7 @@ static bool rna_path_parse_collection_key(const char **path,
return false; /* we can be sure the fixedbuf was used in this case */
}
if (RNA_property_collection_lookup_int(ptr, prop, intkey, r_nextptr)) {
- /* pass */
+ found = true;
}
else {
r_nextptr->data = NULL;
@@ -5042,7 +4981,7 @@ static bool rna_path_parse_collection_key(const char **path,
}
else {
if (RNA_property_collection_type_get(ptr, prop, r_nextptr)) {
- /* pass */
+ found = true;
}
else {
/* ensure we quit on invalid values */
@@ -5050,7 +4989,7 @@ static bool rna_path_parse_collection_key(const char **path,
}
}
- return true;
+ return found;
}
static bool rna_path_parse_array_index(const char **path,
@@ -5326,17 +5265,6 @@ static bool rna_path_parse(PointerRNA *ptr,
return true;
}
-/**
- * Resolve the given RNA Path to find the pointer and/or property
- * indicated by fully resolving the path.
- *
- * \warning Unlike \a RNA_path_resolve_property(), that one *will* try to follow RNAPointers,
- * e.g. the path 'parent' applied to a RNAObject \a ptr will return the object.parent in \a r_ptr,
- * and a NULL \a r_prop...
- *
- * \note Assumes all pointers provided are valid
- * \return True if path can be resolved to a valid "pointer + property" OR "pointer only"
- */
bool RNA_path_resolve(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop)
{
if (!rna_path_parse(ptr, path, r_ptr, r_prop, NULL, NULL, NULL, true)) {
@@ -5346,13 +5274,6 @@ bool RNA_path_resolve(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, Prop
return r_ptr->data != NULL;
}
-/**
- * Resolve the given RNA Path to find the pointer and/or property + array index
- * indicated by fully resolving the path.
- *
- * \note Assumes all pointers provided are valid.
- * \return True if path can be resolved to a valid "pointer + property" OR "pointer only"
- */
bool RNA_path_resolve_full(
PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
{
@@ -5363,26 +5284,12 @@ bool RNA_path_resolve_full(
return r_ptr->data != NULL;
}
-/**
- * A version of #RNA_path_resolve_full doesn't check the value of #PointerRNA.data.
- *
- * \note While it's correct to ignore the value of #PointerRNA.data
- * most callers need to know if the resulting pointer was found and not null.
- */
bool RNA_path_resolve_full_maybe_null(
PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
{
return rna_path_parse(ptr, path, r_ptr, r_prop, r_index, NULL, NULL, true);
}
-/**
- * Resolve the given RNA Path to find both the pointer AND property
- * indicated by fully resolving the path.
- *
- * This is a convenience method to avoid logic errors and ugly syntax.
- * \note Assumes all pointers provided are valid
- * \return True only if both a valid pointer and property are found after resolving the path
- */
bool RNA_path_resolve_property(PointerRNA *ptr,
const char *path,
PointerRNA *r_ptr,
@@ -5395,14 +5302,6 @@ bool RNA_path_resolve_property(PointerRNA *ptr,
return r_ptr->data != NULL && *r_prop != NULL;
}
-/**
- * Resolve the given RNA Path to find the pointer AND property (as well as the array index)
- * indicated by fully resolving the path.
- *
- * This is a convenience method to avoid logic errors and ugly syntax.
- * \note Assumes all pointers provided are valid
- * \return True only if both a valid pointer and property are found after resolving the path
- */
bool RNA_path_resolve_property_full(
PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
{
@@ -5413,18 +5312,6 @@ bool RNA_path_resolve_property_full(
return r_ptr->data != NULL && *r_prop != NULL;
}
-/**
- * Resolve the given RNA Path to find both the pointer AND property
- * indicated by fully resolving the path, and get the value of the Pointer property
- * (or item of the collection).
- *
- * This is a convenience method to avoid logic errors and ugly syntax,
- * it combines both \a RNA_path_resolve and #RNA_path_resolve_property in a single call.
- * \note Assumes all pointers provided are valid.
- * \param r_item_ptr: The final Pointer or Collection item value.
- * You must check for its validity before use!
- * \return True only if both a valid pointer and property are found after resolving the path
- */
bool RNA_path_resolve_property_and_item_pointer(PointerRNA *ptr,
const char *path,
PointerRNA *r_ptr,
@@ -5438,19 +5325,6 @@ bool RNA_path_resolve_property_and_item_pointer(PointerRNA *ptr,
return r_ptr->data != NULL && *r_prop != NULL;
}
-/**
- * Resolve the given RNA Path to find both the pointer AND property (as well as the array index)
- * indicated by fully resolving the path,
- * and get the value of the Pointer property (or item of the collection).
- *
- * This is a convenience method to avoid logic errors and ugly syntax,
- * it combines both \a RNA_path_resolve_full and
- * \a RNA_path_resolve_property_full in a single call.
- * \note Assumes all pointers provided are valid.
- * \param r_item_ptr: The final Pointer or Collection item value.
- * You must check for its validity before use!
- * \return True only if both a valid pointer and property are found after resolving the path
- */
bool RNA_path_resolve_property_and_item_pointer_full(PointerRNA *ptr,
const char *path,
PointerRNA *r_ptr,
@@ -5464,15 +5338,6 @@ bool RNA_path_resolve_property_and_item_pointer_full(PointerRNA *ptr,
return r_ptr->data != NULL && *r_prop != NULL;
}
-/**
- * Resolve the given RNA Path into a linked list of PropertyElemRNA's.
- *
- * To be used when complex operations over path are needed, like e.g. get relative paths,
- * to avoid too much string operations.
- *
- * \return True if there was no error while resolving the path
- * \note Assumes all pointers provided are valid
- */
bool RNA_path_resolve_elements(PointerRNA *ptr, const char *path, ListBase *r_elements)
{
return rna_path_parse(ptr, path, NULL, NULL, NULL, NULL, r_elements, false);
@@ -5723,16 +5588,6 @@ static char *rna_idp_path(PointerRNA *ptr,
return path;
}
-/**
- * Find the path from the structure referenced by the pointer to the runtime RNA-defined
- * #IDProperty object.
- *
- * \note Does *not* handle pure user-defined IDProperties (a.k.a. custom properties).
- *
- * \param ptr: Reference to the object owning the custom property storage.
- * \param needle: Custom property object to find.
- * \return Relative path or NULL.
- */
char *RNA_path_from_struct_to_idproperty(PointerRNA *ptr, IDProperty *needle)
{
IDProperty *haystack = RNA_struct_idprops(ptr, false);
@@ -5759,13 +5614,6 @@ static char *rna_path_from_ID_to_idpgroup(const PointerRNA *ptr)
return RNA_path_from_struct_to_idproperty(&id_ptr, ptr->data);
}
-/**
- * Find the actual ID pointer and path from it to the given ID.
- *
- * \param id: ID reference to search the global owner for.
- * \param[out] r_path: Path from the real ID to the initial ID.
- * \return The ID pointer, or NULL in case of failure.
- */
ID *RNA_find_real_ID_and_path(Main *bmain, ID *id, const char **r_path)
{
if (r_path) {
@@ -5918,11 +5766,6 @@ static void rna_path_array_multi_string_from_flat_index(PointerRNA *ptr,
}
}
-/**
- * \param index_dim: The dimension to show, 0 disables. 1 for 1d array, 2 for 2d. etc.
- * \param index: The *flattened* index to use when \a `index_dim > 0`,
- * this is expanded when used with multi-dimensional arrays.
- */
char *RNA_path_from_ID_to_property_index(PointerRNA *ptr,
PropertyRNA *prop,
int index_dim,
@@ -5994,10 +5837,6 @@ char *RNA_path_from_real_ID_to_property_index(
return path != NULL ? rna_prepend_real_ID_path(bmain, ptr->owner_id, path, r_real_id) : NULL;
}
-/**
- * \return the path to given ptr/prop from the closest ancestor of given type,
- * if any (else return NULL).
- */
char *RNA_path_resolve_from_type_to_property(PointerRNA *ptr,
PropertyRNA *prop,
const StructRNA *type)
@@ -6036,10 +5875,6 @@ char *RNA_path_resolve_from_type_to_property(PointerRNA *ptr,
return path;
}
-/**
- * Get the ID as a python representation, eg:
- * bpy.data.foo["bar"]
- */
char *RNA_path_full_ID_py(Main *bmain, ID *id)
{
const char *path;
@@ -6075,10 +5910,6 @@ char *RNA_path_full_ID_py(Main *bmain, ID *id)
path);
}
-/**
- * Get the ID.struct as a python representation, eg:
- * bpy.data.foo["bar"].some_struct
- */
char *RNA_path_full_struct_py(Main *bmain, struct PointerRNA *ptr)
{
char *id_path;
@@ -6107,10 +5938,6 @@ char *RNA_path_full_struct_py(Main *bmain, struct PointerRNA *ptr)
return ret;
}
-/**
- * Get the ID.struct.property as a python representation, eg:
- * bpy.data.foo["bar"].some_struct.some_prop[10]
- */
char *RNA_path_full_property_py_ex(
Main *bmain, PointerRNA *ptr, PropertyRNA *prop, int index, bool use_fallback)
{
@@ -6164,10 +5991,6 @@ char *RNA_path_full_property_py(Main *bmain, PointerRNA *ptr, PropertyRNA *prop,
return RNA_path_full_property_py_ex(bmain, ptr, prop, index, false);
}
-/**
- * Get the struct.property as a python representation, eg:
- * some_struct.some_prop[10]
- */
char *RNA_path_struct_property_py(PointerRNA *ptr, PropertyRNA *prop, int index)
{
char *data_path;
@@ -6205,10 +6028,6 @@ char *RNA_path_struct_property_py(PointerRNA *ptr, PropertyRNA *prop, int index)
return ret;
}
-/**
- * Get the struct.property as a python representation, eg:
- * some_prop[10]
- */
char *RNA_path_property_py(const PointerRNA *UNUSED(ptr), PropertyRNA *prop, int index)
{
char *ret;
@@ -6678,7 +6497,6 @@ bool RNA_property_is_idprop(const PropertyRNA *prop)
return (prop->magic != RNA_MAGIC);
}
-/* mainly for the UI */
bool RNA_property_is_unlink(PropertyRNA *prop)
{
const int flag = RNA_property_flag(prop);
@@ -6688,9 +6506,6 @@ bool RNA_property_is_unlink(PropertyRNA *prop)
return (flag & (PROP_NEVER_UNLINK | PROP_NEVER_NULL)) == 0;
}
-/* string representation of a property, python
- * compatible but can be used for display too,
- * context may be NULL */
char *RNA_pointer_as_string_id(bContext *C, PointerRNA *ptr)
{
DynStr *dynstr = BLI_dynstr_new();
@@ -6752,7 +6567,6 @@ char *RNA_pointer_as_string(bContext *C,
return rna_pointer_as_string__bldata(CTX_data_main(C), ptr_prop);
}
-/* context can be NULL */
char *RNA_pointer_as_string_keywords_ex(bContext *C,
PointerRNA *ptr,
const bool as_function,
@@ -8115,7 +7929,6 @@ bool RNA_property_assign_default(PointerRNA *ptr, PropertyRNA *prop)
}
}
-/* use RNA_warning macro which includes __func__ suffix */
void _RNA_warning(const char *format, ...)
{
va_list args;
diff --git a/source/blender/makesrna/intern/rna_access_compare_override.c b/source/blender/makesrna/intern/rna_access_compare_override.c
index be8972dbff3..35af92592e9 100644
--- a/source/blender/makesrna/intern/rna_access_compare_override.c
+++ b/source/blender/makesrna/intern/rna_access_compare_override.c
@@ -126,8 +126,6 @@ int RNA_property_override_flag(PropertyRNA *prop)
return rna_ensure_property(prop)->flag_override;
}
-/** \note Does not take into account editable status, this has to be checked separately
- * (using #RNA_property_editable_flag() usually). */
bool RNA_property_overridable_get(PointerRNA *ptr, PropertyRNA *prop)
{
if (prop->magic == RNA_MAGIC) {
@@ -170,7 +168,6 @@ bool RNA_property_overridable_get(PointerRNA *ptr, PropertyRNA *prop)
return (idprop->flag & IDP_FLAG_OVERRIDABLE_LIBRARY) != 0;
}
-/* Should only be used for custom properties */
bool RNA_property_overridable_library_set(PointerRNA *UNUSED(ptr),
PropertyRNA *prop,
const bool is_overridable)
@@ -614,37 +611,27 @@ static bool rna_property_override_operation_apply(Main *bmain,
}
/* get and set the default values as appropriate for the various types */
- const bool sucess = override_apply(bmain,
- ptr_dst,
- ptr_src,
- ptr_storage,
- prop_dst,
- prop_src,
- prop_storage,
- len_dst,
- len_src,
- len_storage,
- ptr_item_dst,
- ptr_item_src,
- ptr_item_storage,
- opop);
- if (sucess) {
+ const bool success = override_apply(bmain,
+ ptr_dst,
+ ptr_src,
+ ptr_storage,
+ prop_dst,
+ prop_src,
+ prop_storage,
+ len_dst,
+ len_src,
+ len_storage,
+ ptr_item_dst,
+ ptr_item_src,
+ ptr_item_storage,
+ opop);
+ if (success) {
RNA_property_update_main(bmain, NULL, ptr_dst, prop_dst);
}
- return sucess;
+ return success;
}
-/**
- * Check whether reference and local overridden data match (are the same),
- * with respect to given restrictive sets of properties.
- * If requested, will generate needed new property overrides, and/or restore values from reference.
- *
- * \param r_report_flags: If given,
- * will be set with flags matching actions taken by the function on \a ptr_local.
- *
- * \return True if _resulting_ \a ptr_local does match \a ptr_reference.
- */
bool RNA_struct_override_matches(Main *bmain,
PointerRNA *ptr_local,
PointerRNA *ptr_reference,
@@ -928,10 +915,6 @@ bool RNA_struct_override_matches(Main *bmain,
return matching;
}
-/**
- * Store needed second operands into \a storage data-block
- * for differential override operations.
- */
bool RNA_struct_override_store(Main *bmain,
PointerRNA *ptr_local,
PointerRNA *ptr_reference,
@@ -1076,7 +1059,12 @@ static void rna_porperty_override_collection_subitem_lookup(
*r_ptr_item_storage = private_ptr_item_storage;
}
- if ((*r_ptr_item_dst)->type == NULL) {
+ /* Note that there is no reason to report in case no item is expected, i.e. in case subitem name
+ * and index are invalid. This can often happen when inserting new items (constraint,
+ * modifier...) in a collection that supports it. */
+ if ((*r_ptr_item_dst)->type == NULL &&
+ ((opop->subitem_reference_name != NULL && opop->subitem_reference_name[0] != '\0') ||
+ opop->subitem_reference_index != -1)) {
CLOG_INFO(&LOG,
2,
"Failed to find destination sub-item '%s' (%d) of '%s' in new override data '%s'",
@@ -1085,7 +1073,9 @@ static void rna_porperty_override_collection_subitem_lookup(
op->rna_path,
ptr_dst->owner_id->name);
}
- if ((*r_ptr_item_src)->type == NULL) {
+ if ((*r_ptr_item_src)->type == NULL &&
+ ((opop->subitem_local_name != NULL && opop->subitem_local_name[0] != '\0') ||
+ opop->subitem_local_index != -1)) {
CLOG_INFO(&LOG,
2,
"Failed to find source sub-item '%s' (%d) of '%s' in old override data '%s'",
@@ -1195,10 +1185,6 @@ static void rna_property_override_apply_ex(Main *bmain,
}
}
-/**
- * Apply given \a override operations on \a ptr_dst, using \a ptr_src
- * (and \a ptr_storage for differential ops) as source.
- */
void RNA_struct_override_apply(Main *bmain,
PointerRNA *ptr_dst,
PointerRNA *ptr_src,
diff --git a/source/blender/makesrna/intern/rna_access_internal.h b/source/blender/makesrna/intern/rna_access_internal.h
index 73407123863..9f1be5bbd67 100644
--- a/source/blender/makesrna/intern/rna_access_internal.h
+++ b/source/blender/makesrna/intern/rna_access_internal.h
@@ -27,6 +27,13 @@
struct IDProperty;
struct PropertyRNAOrID;
+/**
+ * This function initializes a #PropertyRNAOrID with all required info, from a given #PropertyRNA
+ * and #PointerRNA data. It deals properly with the three cases
+ * (static RNA, runtime RNA, and #IDProperty).
+ * \warning given `ptr` #PointerRNA is assumed to be a valid data one here, calling code is
+ * responsible to ensure that.
+ */
void rna_property_rna_or_id_get(PropertyRNA *prop,
PointerRNA *ptr,
PropertyRNAOrID *r_prop_rna_or_id);
diff --git a/source/blender/makesrna/intern/rna_action.c b/source/blender/makesrna/intern/rna_action.c
index 2aa09a30c75..96e37dfebbb 100644
--- a/source/blender/makesrna/intern/rna_action.c
+++ b/source/blender/makesrna/intern/rna_action.c
@@ -246,12 +246,60 @@ static void rna_Action_active_pose_marker_index_range(
*max = max_ii(0, BLI_listbase_count(&act->markers) - 1);
}
-static void rna_Action_frame_range_get(PointerRNA *ptr, float *values)
+static void rna_Action_frame_range_get(PointerRNA *ptr, float *r_values)
+{
+ BKE_action_get_frame_range((bAction *)ptr->owner_id, &r_values[0], &r_values[1]);
+}
+
+static void rna_Action_frame_range_set(PointerRNA *ptr, const float *values)
+{
+ bAction *data = (bAction *)ptr->owner_id;
+
+ data->flag |= ACT_FRAME_RANGE;
+ data->frame_start = values[0];
+ data->frame_end = values[1];
+ CLAMP_MIN(data->frame_end, data->frame_start);
+}
+
+static void rna_Action_curve_frame_range_get(PointerRNA *ptr, float *values)
{ /* don't include modifiers because they too easily can have very large
* ranges: MINAFRAMEF to MAXFRAMEF. */
calc_action_range((bAction *)ptr->owner_id, values, values + 1, false);
}
+static void rna_Action_use_frame_range_set(PointerRNA *ptr, bool value)
+{
+ bAction *data = (bAction *)ptr->owner_id;
+
+ if (value) {
+ /* If the frame range is blank, initialize it by scanning F-Curves. */
+ if ((data->frame_start == data->frame_end) && (data->frame_start == 0)) {
+ calc_action_range(data, &data->frame_start, &data->frame_end, false);
+ }
+
+ data->flag |= ACT_FRAME_RANGE;
+ }
+ else {
+ data->flag &= ~ACT_FRAME_RANGE;
+ }
+}
+
+static void rna_Action_start_frame_set(PointerRNA *ptr, float value)
+{
+ bAction *data = (bAction *)ptr->owner_id;
+
+ data->frame_start = value;
+ CLAMP_MIN(data->frame_end, data->frame_start);
+}
+
+static void rna_Action_end_frame_set(PointerRNA *ptr, float value)
+{
+ bAction *data = (bAction *)ptr->owner_id;
+
+ data->frame_end = value;
+ CLAMP_MAX(data->frame_start, data->frame_end);
+}
+
/* Used to check if an action (value pointer)
* is suitable to be assigned to the ID-block that is ptr. */
bool rna_Action_id_poll(PointerRNA *ptr, PointerRNA value)
@@ -834,17 +882,73 @@ static void rna_def_action(BlenderRNA *brna)
rna_def_action_pose_markers(brna, prop);
/* properties */
+ prop = RNA_def_property(srna, "use_frame_range", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_FRAME_RANGE);
+ RNA_def_property_boolean_funcs(prop, NULL, "rna_Action_use_frame_range_set");
+ RNA_def_property_ui_text(
+ prop,
+ "Manual Frame Range",
+ "Manually specify the intended playback frame range for the action "
+ "(this range is used by some tools, but does not affect animation evaluation)");
+ RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+
+ prop = RNA_def_property(srna, "use_cyclic", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_CYCLIC);
+ RNA_def_property_ui_text(
+ prop,
+ "Cyclic Animation",
+ "The action is intended to be used as a cycle looping over its manually set "
+ "playback frame range (enabling this doesn't automatically make it loop)");
+ RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+
+ prop = RNA_def_property(srna, "frame_start", PROP_FLOAT, PROP_TIME);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_float_sdna(prop, NULL, "frame_start");
+ RNA_def_property_float_funcs(prop, NULL, "rna_Action_start_frame_set", NULL);
+ RNA_def_property_ui_range(prop, MINFRAME, MAXFRAME, 100, 0);
+ RNA_def_property_ui_text(
+ prop, "Start Frame", "The start frame of the manually set intended playback range");
+ RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+
+ prop = RNA_def_property(srna, "frame_end", PROP_FLOAT, PROP_TIME);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_float_sdna(prop, NULL, "frame_end");
+ RNA_def_property_float_funcs(prop, NULL, "rna_Action_end_frame_set", NULL);
+ RNA_def_property_ui_range(prop, MINFRAME, MAXFRAME, 100, 0);
+ RNA_def_property_ui_text(
+ prop, "End Frame", "The end frame of the manually set intended playback range");
+ RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+
+ prop = RNA_def_float_vector(
+ srna,
+ "frame_range",
+ 2,
+ NULL,
+ 0,
+ 0,
+ "Frame Range",
+ "The intended playback frame range of this action, using the manually set range "
+ "if available, or the combined frame range of all F-Curves within this action "
+ "if not (assigning sets the manual frame range)",
+ 0,
+ 0);
+ RNA_def_property_float_funcs(
+ prop, "rna_Action_frame_range_get", "rna_Action_frame_range_set", NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+
prop = RNA_def_float_vector(srna,
- "frame_range",
+ "curve_frame_range",
2,
NULL,
0,
0,
- "Frame Range",
- "The final frame range of all F-Curves within this action",
+ "Curve Frame Range",
+ "The combined frame range of all F-Curves within this action",
0,
0);
- RNA_def_property_float_funcs(prop, "rna_Action_frame_range_get", NULL, NULL);
+ RNA_def_property_float_funcs(prop, "rna_Action_curve_frame_range_get", NULL, NULL);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
/* special "type" limiter - should not really be edited in general,
diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c
index 690506fa517..7a934443907 100644
--- a/source/blender/makesrna/intern/rna_armature.c
+++ b/source/blender/makesrna/intern/rna_armature.c
@@ -669,10 +669,10 @@ static void rna_Armature_transform(bArmature *arm, float mat[16])
#else
-/* Settings for curved bbone settings -
- * The posemode values get applied over the top of the editmode ones. */
void rna_def_bone_curved_common(StructRNA *srna, bool is_posebone, bool is_editbone)
{
+ /* NOTE: The pose-mode values get applied over the top of the edit-mode ones. */
+
# define RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone, is_editbone) \
{ \
if (is_posebone) { \
diff --git a/source/blender/makesrna/intern/rna_asset.c b/source/blender/makesrna/intern/rna_asset.c
index 5d83da170b5..e79cbc838d4 100644
--- a/source/blender/makesrna/intern/rna_asset.c
+++ b/source/blender/makesrna/intern/rna_asset.c
@@ -307,7 +307,7 @@ const EnumPropertyItem *rna_asset_library_reference_itemf(bContext *UNUSED(C),
PropertyRNA *UNUSED(prop),
bool *r_free)
{
- const EnumPropertyItem *items = ED_asset_library_reference_to_rna_enum_itemf();
+ const EnumPropertyItem *items = ED_asset_library_reference_to_rna_enum_itemf(true);
if (!items) {
*r_free = false;
}
@@ -493,9 +493,6 @@ static void rna_def_asset_library_reference(BlenderRNA *brna)
srna, "Asset Library Reference", "Identifier to refer to the asset library");
}
-/**
- * \note the UI text and updating has to be set by the caller.
- */
PropertyRNA *rna_def_asset_library_reference_common(struct StructRNA *srna,
const char *get,
const char *set)
diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c
index bde348c1848..0c993660f39 100644
--- a/source/blender/makesrna/intern/rna_constraint.c
+++ b/source/blender/makesrna/intern/rna_constraint.c
@@ -3446,7 +3446,8 @@ static void rna_def_constraint_transform_cache(BlenderRNA *brna)
RNA_define_lib_overridable(false);
}
-/* base struct for constraints */
+/* Define the base struct for constraints. */
+
void RNA_def_constraint(BlenderRNA *brna)
{
StructRNA *srna;
diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c
index 8c89162f571..6cca0c51988 100644
--- a/source/blender/makesrna/intern/rna_curve.c
+++ b/source/blender/makesrna/intern/rna_curve.c
@@ -141,8 +141,6 @@ const EnumPropertyItem rna_enum_beztriple_interpolation_mode_items[] = {
static const EnumPropertyItem curve_type_items[] = {
{CU_POLY, "POLY", 0, "Poly", ""},
{CU_BEZIER, "BEZIER", 0, "Bezier", ""},
- {CU_BSPLINE, "BSPLINE", 0, "BSpline", ""},
- {CU_CARDINAL, "CARDINAL", 0, "Cardinal", ""},
{CU_NURBS, "NURBS", 0, "Ease", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -569,13 +567,13 @@ static void rna_Curve_resolution_v_update_data(Main *bmain, Scene *scene, Pointe
static float rna_Curve_offset_get(PointerRNA *ptr)
{
Curve *cu = (Curve *)ptr->owner_id;
- return cu->width - 1.0f;
+ return cu->offset - 1.0f;
}
static void rna_Curve_offset_set(PointerRNA *ptr, float value)
{
Curve *cu = (Curve *)ptr->owner_id;
- cu->width = 1.0f + value;
+ cu->offset = 1.0f + value;
}
static int rna_Curve_body_length(PointerRNA *ptr);
@@ -1656,14 +1654,14 @@ static void rna_def_curve(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Curve_bevel_resolution_update");
prop = RNA_def_property(srna, "offset", PROP_FLOAT, PROP_NONE | PROP_UNIT_LENGTH);
- RNA_def_property_float_sdna(prop, NULL, "width");
+ RNA_def_property_float_sdna(prop, NULL, "offset");
RNA_def_property_ui_range(prop, -1.0, 1.0, 0.1, 3);
RNA_def_property_float_funcs(prop, "rna_Curve_offset_get", "rna_Curve_offset_set", NULL);
RNA_def_property_ui_text(prop, "Offset", "Distance to move the curve parallel to its normals");
RNA_def_property_update(prop, 0, "rna_Curve_update_data");
prop = RNA_def_property(srna, "extrude", PROP_FLOAT, PROP_NONE | PROP_UNIT_LENGTH);
- RNA_def_property_float_sdna(prop, NULL, "ext1");
+ RNA_def_property_float_sdna(prop, NULL, "extrude");
RNA_def_property_ui_range(prop, 0, 100.0, 0.1, 3);
RNA_def_property_range(prop, 0.0, FLT_MAX);
RNA_def_property_ui_text(prop,
@@ -1673,7 +1671,7 @@ static void rna_def_curve(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Curve_update_data");
prop = RNA_def_property(srna, "bevel_depth", PROP_FLOAT, PROP_NONE | PROP_UNIT_LENGTH);
- RNA_def_property_float_sdna(prop, NULL, "ext2");
+ RNA_def_property_float_sdna(prop, NULL, "bevel_radius");
RNA_def_property_ui_range(prop, 0, 100.0, 0.1, 3);
RNA_def_property_ui_text(
prop, "Bevel Depth", "Radius of the bevel geometry, not including extrusion");
diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c
index bd5ade36eaa..b17ca7d8d59 100644
--- a/source/blender/makesrna/intern/rna_define.c
+++ b/source/blender/makesrna/intern/rna_define.c
@@ -753,10 +753,6 @@ void RNA_define_verify_sdna(bool verify)
DefRNA.verify = verify;
}
-/**
- * Properties defined when this is enabled are lib-overridable by default (except for Pointer
- * ones).
- */
void RNA_define_lib_overridable(const bool make_overridable)
{
DefRNA.make_overridable = make_overridable;
@@ -915,7 +911,6 @@ static StructDefRNA *rna_find_def_struct(StructRNA *srna)
return NULL;
}
-/* Struct Definition */
StructRNA *RNA_def_struct_ptr(BlenderRNA *brna, const char *identifier, StructRNA *srnafrom)
{
StructRNA *srna;
@@ -1243,9 +1238,6 @@ void RNA_def_struct_identifier(BlenderRNA *brna, StructRNA *srna, const char *id
srna->identifier = identifier;
}
-/**
- * Only used in one case when we name the struct for the purpose of useful error messages.
- */
void RNA_def_struct_identifier_no_struct_map(StructRNA *srna, const char *identifier)
{
if (DefRNA.preprocess) {
@@ -1532,13 +1524,6 @@ void RNA_def_property_override_clear_flag(PropertyRNA *prop, PropertyOverrideFla
prop->flag_override &= ~flag;
}
-/**
- * Add the property-tags passed as \a tags to \a prop (if valid).
- *
- * \note Multiple tags can be set by passing them within \a tags (using bitflags).
- * \note Doesn't do any type-checking with the tags defined in the parent StructRNA
- * of \a prop. This should be done before (e.g. see #WM_operatortype_prop_tag).
- */
void RNA_def_property_tags(PropertyRNA *prop, int tags)
{
prop->tags |= tags;
@@ -1616,12 +1601,10 @@ void RNA_def_property_array(PropertyRNA *prop, int length)
}
}
-/* common args for defaults. */
const float rna_default_quaternion[4] = {1, 0, 0, 0};
const float rna_default_axis_angle[4] = {0, 0, 1, 0};
const float rna_default_scale_3d[3] = {1, 1, 1};
-/* common args for length */
const int rna_matrix_dimsize_3x3[] = {3, 3};
const int rna_matrix_dimsize_4x4[] = {4, 4};
const int rna_matrix_dimsize_4x2[] = {4, 2};
@@ -1692,17 +1675,6 @@ void RNA_def_property_ui_icon(PropertyRNA *prop, int icon, int consecutive)
}
}
-/**
- * The values hare are a little confusing:
- *
- * \param step: Used as the value to increase/decrease when clicking on number buttons,
- * as well as scaling mouse input for click-dragging number buttons.
- * For floats this is (step * UI_PRECISION_FLOAT_SCALE), why? - nobody knows.
- * For ints, whole values are used.
- *
- * \param precision: The number of zeros to show
- * (as a whole number - common range is 1 - 6), see UI_PRECISION_FLOAT_MAX
- */
void RNA_def_property_ui_range(
PropertyRNA *prop, double min, double max, double step, int precision)
{
@@ -2082,7 +2054,6 @@ void RNA_def_property_float_default(PropertyRNA *prop, float value)
break;
}
}
-/* array must remain valid after this function finishes */
void RNA_def_property_float_array_default(PropertyRNA *prop, const float *array)
{
StructRNA *srna = DefRNA.laststruct;
@@ -2920,11 +2891,6 @@ void RNA_def_property_editable_array_func(PropertyRNA *prop, const char *editabl
}
}
-/**
- * Set custom callbacks for override operations handling.
- *
- * \note \a diff callback will also be used by RNA comparison/equality functions.
- */
void RNA_def_property_override_funcs(PropertyRNA *prop,
const char *diff,
const char *store,
@@ -3813,7 +3779,6 @@ PropertyRNA *RNA_def_enum(StructOrFunctionRNA *cont_,
return prop;
}
-/* same as above but sets 'PROP_ENUM_FLAG' before setting the default value */
PropertyRNA *RNA_def_enum_flag(StructOrFunctionRNA *cont_,
const char *identifier,
const EnumPropertyItem *items,
@@ -4320,7 +4285,6 @@ FunctionRNA *RNA_def_function_runtime(StructRNA *srna, const char *identifier, C
return func;
}
-/* C return value only!, multiple RNA returns can be done with RNA_def_function_output */
void RNA_def_function_return(FunctionRNA *func, PropertyRNA *ret)
{
if (ret->flag & PROP_DYNAMIC) {
diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c
index 82f3279146a..e06aac31124 100644
--- a/source/blender/makesrna/intern/rna_gpencil_modifier.c
+++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c
@@ -28,6 +28,7 @@
#include "DNA_gpencil_modifier_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_mesh_types.h"
+#include "DNA_modifier_types.h"
#include "DNA_object_force_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -144,6 +145,11 @@ const EnumPropertyItem rna_enum_object_greasepencil_modifier_type_items[] = {
ICON_MOD_OFFSET,
"Offset",
"Change stroke location, rotation or scale"},
+ {eGpencilModifierType_Shrinkwrap,
+ "SHRINKWRAP",
+ ICON_MOD_SHRINKWRAP,
+ "Shrinkwrap",
+ "Project the shape onto another object"},
{eGpencilModifierType_Smooth, "GP_SMOOTH", ICON_MOD_SMOOTH, "Smooth", "Smooth stroke"},
{eGpencilModifierType_Thick,
"GP_THICK",
@@ -269,6 +275,8 @@ static StructRNA *rna_GpencilModifier_refine(struct PointerRNA *ptr)
return &RNA_LengthGpencilModifier;
case eGpencilModifierType_Mirror:
return &RNA_MirrorGpencilModifier;
+ case eGpencilModifierType_Shrinkwrap:
+ return &RNA_ShrinkwrapGpencilModifier;
case eGpencilModifierType_Smooth:
return &RNA_SmoothGpencilModifier;
case eGpencilModifierType_Hook:
@@ -360,6 +368,7 @@ RNA_GP_MOD_VGROUP_NAME_SET(WeightProx, vgname);
RNA_GP_MOD_VGROUP_NAME_SET(WeightAngle, target_vgname);
RNA_GP_MOD_VGROUP_NAME_SET(WeightAngle, vgname);
RNA_GP_MOD_VGROUP_NAME_SET(Lineart, vgname);
+RNA_GP_MOD_VGROUP_NAME_SET(Shrinkwrap, vgname);
# undef RNA_GP_MOD_VGROUP_NAME_SET
@@ -392,6 +401,8 @@ RNA_GP_MOD_OBJECT_SET(Armature, object, OB_ARMATURE);
RNA_GP_MOD_OBJECT_SET(Lattice, object, OB_LATTICE);
RNA_GP_MOD_OBJECT_SET(Mirror, object, OB_EMPTY);
RNA_GP_MOD_OBJECT_SET(WeightProx, object, OB_EMPTY);
+RNA_GP_MOD_OBJECT_SET(Shrinkwrap, target, OB_MESH);
+RNA_GP_MOD_OBJECT_SET(Shrinkwrap, aux_target, OB_MESH);
# undef RNA_GP_MOD_OBJECT_SET
@@ -685,6 +696,16 @@ static void rna_TextureGpencilModifier_material_set(PointerRNA *ptr,
rna_GpencilModifier_material_set(ptr, value, ma_target, reports);
}
+static void rna_ShrinkwrapGpencilModifier_material_set(PointerRNA *ptr,
+ PointerRNA value,
+ struct ReportList *reports)
+{
+ ShrinkwrapGpencilModifierData *tmd = (ShrinkwrapGpencilModifierData *)ptr->data;
+ Material **ma_target = &tmd->material;
+
+ rna_GpencilModifier_material_set(ptr, value, ma_target, reports);
+}
+
static void rna_Lineart_start_level_set(PointerRNA *ptr, int value)
{
LineartGpencilModifierData *lmd = (LineartGpencilModifierData *)ptr->data;
@@ -756,6 +777,18 @@ static void rna_DashGpencilModifierSegment_name_set(PointerRNA *ptr, const char
BKE_animdata_fix_paths_rename_all(NULL, prefix, oldname, ds->name);
}
+static int rna_ShrinkwrapGpencilModifier_face_cull_get(PointerRNA *ptr)
+{
+ ShrinkwrapGpencilModifierData *swm = (ShrinkwrapGpencilModifierData *)ptr->data;
+ return swm->shrink_opts & MOD_SHRINKWRAP_CULL_TARGET_MASK;
+}
+
+static void rna_ShrinkwrapGpencilModifier_face_cull_set(struct PointerRNA *ptr, int value)
+{
+ ShrinkwrapGpencilModifierData *swm = (ShrinkwrapGpencilModifierData *)ptr->data;
+ swm->shrink_opts = (swm->shrink_opts & ~MOD_SHRINKWRAP_CULL_TARGET_MASK) | value;
+}
+
#else
static void rna_def_modifier_gpencilnoise(BlenderRNA *brna)
@@ -3455,6 +3488,43 @@ static void rna_def_modifier_gpencillength(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "End Factor", "Absolute added length to the end of each stroke");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+ prop = RNA_def_property(srna, "random_start_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "rand_start_fac");
+ RNA_def_property_ui_range(prop, -10.0f, 10.0f, 0.1, 1);
+ RNA_def_property_ui_text(
+ prop, "Random Start Factor", "Size of random length added to the start of each stroke");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "random_end_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "rand_end_fac");
+ RNA_def_property_ui_range(prop, -10.0f, 10.0f, 0.1, 1);
+ RNA_def_property_ui_text(
+ prop, "Random End Factor", "Size of random length added to the end of each stroke");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "random_offset", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "rand_offset");
+ RNA_def_property_ui_range(prop, 0.0f, 100.0f, 0.1, 3);
+ RNA_def_property_ui_text(
+ prop, "Random Noise Offset", "Smoothly offset each stroke's random value");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_random", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LENGTH_USE_RANDOM);
+ RNA_def_property_ui_text(prop, "Random", "Use random values over time");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "seed", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_ui_text(prop, "Seed", "Random seed");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "step", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "step");
+ RNA_def_property_range(prop, 1, 100);
+ RNA_def_property_ui_text(
+ prop, "Step", "Number of frames before recalculate random values again");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
prop = RNA_def_property(srna, "overshoot_factor", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "overshoot_fac");
RNA_def_property_range(prop, 0.0f, 1.0f);
@@ -3683,6 +3753,194 @@ static void rna_def_modifier_gpencildash(BlenderRNA *brna)
RNA_define_lib_overridable(false);
}
+static void rna_def_modifier_gpencilshrinkwrap(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "ShrinkwrapGpencilModifier", "GpencilModifier");
+ RNA_def_struct_ui_text(srna,
+ "Shrinkwrap Modifier",
+ "Shrink wrapping modifier to shrink wrap and object to a target");
+ RNA_def_struct_sdna(srna, "ShrinkwrapGpencilModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_MOD_SHRINKWRAP);
+
+ RNA_define_lib_overridable(true);
+
+ prop = RNA_def_property(srna, "wrap_method", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "shrink_type");
+ RNA_def_property_enum_items(prop, rna_enum_shrinkwrap_type_items);
+ RNA_def_property_ui_text(prop, "Wrap Method", "");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
+
+ prop = RNA_def_property(srna, "wrap_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "shrink_mode");
+ RNA_def_property_enum_items(prop, rna_enum_modifier_shrinkwrap_mode_items);
+ RNA_def_property_ui_text(
+ prop, "Snap Mode", "Select how vertices are constrained to the target surface");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
+
+ prop = RNA_def_property(srna, "cull_face", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "shrink_opts");
+ RNA_def_property_enum_items(prop, rna_enum_shrinkwrap_face_cull_items);
+ RNA_def_property_enum_funcs(prop,
+ "rna_ShrinkwrapGpencilModifier_face_cull_get",
+ "rna_ShrinkwrapGpencilModifier_face_cull_set",
+ NULL);
+ RNA_def_property_ui_text(
+ prop,
+ "Face Cull",
+ "Stop vertices from projecting to a face on the target when facing towards/away");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "target", PROP_POINTER, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Target", "Mesh target to shrink to");
+ RNA_def_property_pointer_funcs(
+ prop, NULL, "rna_ShrinkwrapGpencilModifier_target_set", NULL, "rna_Mesh_object_poll");
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
+
+ prop = RNA_def_property(srna, "auxiliary_target", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "aux_target");
+ RNA_def_property_ui_text(prop, "Auxiliary Target", "Additional mesh target to shrink to");
+ RNA_def_property_pointer_funcs(
+ prop, NULL, "rna_ShrinkwrapGpencilModifier_aux_target_set", NULL, "rna_Mesh_object_poll");
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
+
+ prop = RNA_def_property(srna, "offset", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_sdna(prop, NULL, "keep_dist");
+ RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
+ RNA_def_property_ui_range(prop, -100, 100, 1, 2);
+ RNA_def_property_ui_text(prop, "Offset", "Distance to keep from the target");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "project_limit", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_sdna(prop, NULL, "proj_limit");
+ RNA_def_property_range(prop, 0.0, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0, 100, 1, 2);
+ RNA_def_property_ui_text(
+ prop, "Project Limit", "Limit the distance used for projection (zero disables)");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_project_x", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "proj_axis", MOD_SHRINKWRAP_PROJECT_OVER_X_AXIS);
+ RNA_def_property_ui_text(prop, "X", "");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_project_y", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "proj_axis", MOD_SHRINKWRAP_PROJECT_OVER_Y_AXIS);
+ RNA_def_property_ui_text(prop, "Y", "");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_project_z", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "proj_axis", MOD_SHRINKWRAP_PROJECT_OVER_Z_AXIS);
+ RNA_def_property_ui_text(prop, "Z", "");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "subsurf_levels", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "subsurf_levels");
+ RNA_def_property_range(prop, 0, 6);
+ RNA_def_property_ui_range(prop, 0, 6, 1, -1);
+ RNA_def_property_ui_text(
+ prop,
+ "Subdivision Levels",
+ "Number of subdivisions that must be performed before extracting vertices' "
+ "positions and normals");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_negative_direction", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "shrink_opts", MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR);
+ RNA_def_property_ui_text(
+ prop, "Negative", "Allow vertices to move in the negative direction of axis");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_positive_direction", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "shrink_opts", MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR);
+ RNA_def_property_ui_text(
+ prop, "Positive", "Allow vertices to move in the positive direction of axis");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_invert_cull", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "shrink_opts", MOD_SHRINKWRAP_INVERT_CULL_TARGET);
+ RNA_def_property_ui_text(
+ prop, "Invert Cull", "When projecting in the negative direction invert the face cull mode");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "layer", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "layername");
+ RNA_def_property_ui_text(prop, "Layer", "Layer name");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_pointer_funcs(prop,
+ NULL,
+ "rna_ShrinkwrapGpencilModifier_material_set",
+ NULL,
+ "rna_GpencilModifier_material_poll");
+ RNA_def_property_ui_text(prop, "Material", "Material used for filtering effect");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "vgname");
+ RNA_def_property_ui_text(prop, "Vertex Group", "Vertex group name for modulating the deform");
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_ShrinkwrapGpencilModifier_vgname_set");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "pass_index");
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_text(prop, "Pass", "Pass index");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_layers", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SHRINKWRAP_INVERT_LAYER);
+ RNA_def_property_ui_text(prop, "Inverse Layers", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_materials", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SHRINKWRAP_INVERT_MATERIAL);
+ RNA_def_property_ui_text(prop, "Inverse Materials", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_material_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SHRINKWRAP_INVERT_PASS);
+ RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_vertex", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_SHRINKWRAP_INVERT_VGROUP);
+ RNA_def_property_ui_text(prop, "Inverse VertexGroup", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "layer_pass", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "layer_pass");
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_text(prop, "Pass", "Layer pass index");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_layer_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SHRINKWRAP_INVERT_LAYERPASS);
+ RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "smooth_factor", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "smooth_factor");
+ RNA_def_property_range(prop, 0, 1);
+ RNA_def_property_ui_text(prop, "Smooth Factor", "Amount of smoothing to apply");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "smooth_step", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "smooth_step");
+ RNA_def_property_range(prop, 1, 10);
+ RNA_def_property_ui_text(
+ prop, "Step", "Number of times to apply smooth (high numbers can reduce FPS)");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ RNA_define_lib_overridable(false);
+}
+
void RNA_def_greasepencil_modifier(BlenderRNA *brna)
{
StructRNA *srna;
@@ -3772,6 +4030,7 @@ void RNA_def_greasepencil_modifier(BlenderRNA *brna)
rna_def_modifier_gpencillineart(brna);
rna_def_modifier_gpencillength(brna);
rna_def_modifier_gpencildash(brna);
+ rna_def_modifier_gpencilshrinkwrap(brna);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c
index 4b52ceb6241..7d2697c8770 100644
--- a/source/blender/makesrna/intern/rna_image_api.c
+++ b/source/blender/makesrna/intern/rna_image_api.c
@@ -213,11 +213,17 @@ static void rna_Image_scale(Image *image, ReportList *reports, int width, int he
}
}
-static int rna_Image_gl_load(Image *image, ReportList *reports, int frame)
+static int rna_Image_gl_load(
+ Image *image, ReportList *reports, int frame, int layer_index, int pass_index)
{
ImageUser iuser;
BKE_imageuser_default(&iuser);
iuser.framenr = frame;
+ iuser.layer = layer_index;
+ iuser.pass = pass_index;
+ if (image->rr != NULL) {
+ BKE_image_multilayer_index(image->rr, &iuser);
+ }
GPUTexture *tex = BKE_image_get_gpu_texture(image, &iuser, NULL);
@@ -230,14 +236,15 @@ static int rna_Image_gl_load(Image *image, ReportList *reports, int frame)
return 0; /* GL_NO_ERROR */
}
-static int rna_Image_gl_touch(Image *image, ReportList *reports, int frame)
+static int rna_Image_gl_touch(
+ Image *image, ReportList *reports, int frame, int layer_index, int pass_index)
{
int error = 0; /* GL_NO_ERROR */
BKE_image_tag_time(image);
if (image->gputexture[TEXTARGET_2D][0] == NULL) {
- error = rna_Image_gl_load(image, reports, frame);
+ error = rna_Image_gl_load(image, reports, frame, layer_index, pass_index);
}
return error;
@@ -332,6 +339,24 @@ void RNA_api_image(StructRNA *srna)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_int(
func, "frame", 0, 0, INT_MAX, "Frame", "Frame of image sequence or movie", 0, INT_MAX);
+ RNA_def_int(func,
+ "layer_index",
+ 0,
+ 0,
+ INT_MAX,
+ "Layer",
+ "Index of layer that should be loaded",
+ 0,
+ INT_MAX);
+ RNA_def_int(func,
+ "pass_index",
+ 0,
+ 0,
+ INT_MAX,
+ "Pass",
+ "Index of pass that should be loaded",
+ 0,
+ INT_MAX);
/* return value */
parm = RNA_def_int(
func, "error", 0, -INT_MAX, INT_MAX, "Error", "OpenGL error value", -INT_MAX, INT_MAX);
@@ -346,6 +371,24 @@ void RNA_api_image(StructRNA *srna)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_int(
func, "frame", 0, 0, INT_MAX, "Frame", "Frame of image sequence or movie", 0, INT_MAX);
+ RNA_def_int(func,
+ "layer_index",
+ 0,
+ 0,
+ INT_MAX,
+ "Layer",
+ "Index of layer that should be loaded",
+ 0,
+ INT_MAX);
+ RNA_def_int(func,
+ "pass_index",
+ 0,
+ 0,
+ INT_MAX,
+ "Pass",
+ "Index of pass that should be loaded",
+ 0,
+ INT_MAX);
/* return value */
parm = RNA_def_int(
func, "error", 0, -INT_MAX, INT_MAX, "Error", "OpenGL error value", -INT_MAX, INT_MAX);
diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h
index fd6664ff0de..c1989a5b10d 100644
--- a/source/blender/makesrna/intern/rna_internal.h
+++ b/source/blender/makesrna/intern/rna_internal.h
@@ -251,6 +251,9 @@ bool rna_AnimaData_override_apply(struct Main *bmain,
void rna_def_animviz_common(struct StructRNA *srna);
void rna_def_motionpath_common(struct StructRNA *srna);
+/**
+ * Settings for curved bbone settings.
+ */
void rna_def_bone_curved_common(struct StructRNA *srna, bool is_posebone, bool is_editbone);
void rna_def_texmat_common(struct StructRNA *srna, const char *texspace_editable);
@@ -268,6 +271,9 @@ void rna_def_texpaint_slots(struct BlenderRNA *brna, struct StructRNA *srna);
void rna_def_view_layer_common(struct BlenderRNA *brna, struct StructRNA *srna, const bool scene);
int rna_AssetMetaData_editable(struct PointerRNA *ptr, const char **r_info);
+/**
+ * \note the UI text and updating has to be set by the caller.
+ */
PropertyRNA *rna_def_asset_library_reference_common(struct StructRNA *srna,
const char *get,
const char *set);
@@ -276,6 +282,9 @@ const EnumPropertyItem *rna_asset_library_reference_itemf(struct bContext *C,
struct PropertyRNA *prop,
bool *r_free);
+/**
+ * Common properties for Action/Bone Groups - related to color.
+ */
void rna_def_actionbone_group_common(struct StructRNA *srna,
int update_flag,
const char *update_cb);
@@ -509,8 +518,16 @@ extern StructRNA RNA_PropertyGroupItem;
extern StructRNA RNA_PropertyGroup;
#endif
+/**
+ * This function only returns an #IDProperty,
+ * or NULL (in case IDProp could not be found, or prop is a real RNA property).
+ */
struct IDProperty *rna_idproperty_check(struct PropertyRNA **prop,
struct PointerRNA *ptr) ATTR_WARN_UNUSED_RESULT;
+/**
+ * This function always return the valid, real data pointer, be it a regular RNA property one,
+ * or an #IDProperty one.
+ */
struct PropertyRNA *rna_ensure_property_realdata(struct PropertyRNA **prop,
struct PointerRNA *ptr) ATTR_WARN_UNUSED_RESULT;
struct PropertyRNA *rna_ensure_property(struct PropertyRNA *prop) ATTR_WARN_UNUSED_RESULT;
diff --git a/source/blender/makesrna/intern/rna_linestyle.c b/source/blender/makesrna/intern/rna_linestyle.c
index 8cd1ac0d963..93e8e4bc31e 100644
--- a/source/blender/makesrna/intern/rna_linestyle.c
+++ b/source/blender/makesrna/intern/rna_linestyle.c
@@ -949,8 +949,9 @@ static void rna_def_linestyle_modifiers(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Period", "Period of the noise");
RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
- prop = RNA_def_property(srna, "seed", PROP_INT, PROP_NONE);
+ prop = RNA_def_property(srna, "seed", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "seed");
+ RNA_def_property_range(prop, 1, SHRT_MAX);
RNA_def_property_ui_text(prop, "Seed", "Seed for the noise generation");
RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
@@ -1051,8 +1052,9 @@ static void rna_def_linestyle_modifiers(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Period", "Period of the noise");
RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
- prop = RNA_def_property(srna, "seed", PROP_INT, PROP_NONE);
+ prop = RNA_def_property(srna, "seed", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "seed");
+ RNA_def_property_range(prop, 1, SHRT_MAX);
RNA_def_property_ui_text(prop, "Seed", "Seed for the noise generation");
RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
@@ -1191,8 +1193,9 @@ static void rna_def_linestyle_modifiers(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Period", "Period of the noise");
RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
- prop = RNA_def_property(srna, "seed", PROP_INT, PROP_NONE);
+ prop = RNA_def_property(srna, "seed", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "seed");
+ RNA_def_property_range(prop, 1, SHRT_MAX);
RNA_def_property_ui_text(prop, "Seed", "Seed for the noise generation");
RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
@@ -1306,8 +1309,9 @@ static void rna_def_linestyle_modifiers(BlenderRNA *brna)
srna, "Sinus Displacement", "Add sinus displacement to stroke backbone geometry");
rna_def_geometry_modifier(srna);
- prop = RNA_def_property(srna, "wavelength", PROP_FLOAT, PROP_NONE);
+ prop = RNA_def_property(srna, "wavelength", PROP_FLOAT, PROP_UNSIGNED);
RNA_def_property_float_sdna(prop, NULL, "wavelength");
+ RNA_def_property_range(prop, 0.0001f, FLT_MAX);
RNA_def_property_ui_text(prop, "Wavelength", "Wavelength of the sinus displacement");
RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
diff --git a/source/blender/makesrna/intern/rna_main.c b/source/blender/makesrna/intern/rna_main.c
index 464abc6b543..a162aa26b78 100644
--- a/source/blender/makesrna/intern/rna_main.c
+++ b/source/blender/makesrna/intern/rna_main.c
@@ -56,9 +56,10 @@ static void rna_Main_use_autopack_set(PointerRNA *UNUSED(ptr), bool value)
}
}
-static bool rna_Main_is_saved_get(PointerRNA *UNUSED(ptr))
+static bool rna_Main_is_saved_get(PointerRNA *ptr)
{
- return G.relbase_valid;
+ const Main *bmain = (Main *)ptr->data;
+ return (bmain->filepath[0] != '\0');
}
static bool rna_Main_is_dirty_get(PointerRNA *ptr)
@@ -76,20 +77,20 @@ static bool rna_Main_is_dirty_get(PointerRNA *ptr)
static void rna_Main_filepath_get(PointerRNA *ptr, char *value)
{
Main *bmain = (Main *)ptr->data;
- BLI_strncpy(value, bmain->name, sizeof(bmain->name));
+ BLI_strncpy(value, bmain->filepath, sizeof(bmain->filepath));
}
static int rna_Main_filepath_length(PointerRNA *ptr)
{
Main *bmain = (Main *)ptr->data;
- return strlen(bmain->name);
+ return strlen(bmain->filepath);
}
# if 0
static void rna_Main_filepath_set(PointerRNA *ptr, const char *value)
{
Main *bmain = (Main *)ptr->data;
- BLI_strncpy(bmain->name, value, sizeof(bmain->name));
+ STRNCPY(bmain->filepath, value);
}
# endif
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index 9ad6771cda3..d46ae13b482 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -381,6 +381,42 @@ const EnumPropertyItem rna_enum_modifier_shrinkwrap_mode_items[] = {
{0, NULL, 0, NULL, NULL},
};
+const EnumPropertyItem rna_enum_shrinkwrap_type_items[] = {
+ {MOD_SHRINKWRAP_NEAREST_SURFACE,
+ "NEAREST_SURFACEPOINT",
+ 0,
+ "Nearest Surface Point",
+ "Shrink the mesh to the nearest target surface"},
+ {MOD_SHRINKWRAP_PROJECT,
+ "PROJECT",
+ 0,
+ "Project",
+ "Shrink the mesh to the nearest target surface along a given axis"},
+ {MOD_SHRINKWRAP_NEAREST_VERTEX,
+ "NEAREST_VERTEX",
+ 0,
+ "Nearest Vertex",
+ "Shrink the mesh to the nearest target vertex"},
+ {MOD_SHRINKWRAP_TARGET_PROJECT,
+ "TARGET_PROJECT",
+ 0,
+ "Target Normal Project",
+ "Shrink the mesh to the nearest target surface "
+ "along the interpolated vertex normals of the target"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+const EnumPropertyItem rna_enum_shrinkwrap_face_cull_items[] = {
+ {0, "OFF", 0, "Off", "No culling"},
+ {MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE,
+ "FRONT",
+ 0,
+ "Front",
+ "No projection when in front of the face"},
+ {MOD_SHRINKWRAP_CULL_TARGET_BACKFACE, "BACK", 0, "Back", "No projection when behind the face"},
+ {0, NULL, 0, NULL, NULL},
+};
+
#ifndef RNA_RUNTIME
/* use eWarp_Falloff_*** & eHook_Falloff_***, they're in sync */
static const EnumPropertyItem modifier_warp_falloff_items[] = {
@@ -4184,46 +4220,6 @@ static void rna_def_modifier_shrinkwrap(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
- static const EnumPropertyItem shrink_type_items[] = {
- {MOD_SHRINKWRAP_NEAREST_SURFACE,
- "NEAREST_SURFACEPOINT",
- 0,
- "Nearest Surface Point",
- "Shrink the mesh to the nearest target surface"},
- {MOD_SHRINKWRAP_PROJECT,
- "PROJECT",
- 0,
- "Project",
- "Shrink the mesh to the nearest target surface along a given axis"},
- {MOD_SHRINKWRAP_NEAREST_VERTEX,
- "NEAREST_VERTEX",
- 0,
- "Nearest Vertex",
- "Shrink the mesh to the nearest target vertex"},
- {MOD_SHRINKWRAP_TARGET_PROJECT,
- "TARGET_PROJECT",
- 0,
- "Target Normal Project",
- "Shrink the mesh to the nearest target surface "
- "along the interpolated vertex normals of the target"},
- {0, NULL, 0, NULL, NULL},
- };
-
- static const EnumPropertyItem shrink_face_cull_items[] = {
- {0, "OFF", 0, "Off", "No culling"},
- {MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE,
- "FRONT",
- 0,
- "Front",
- "No projection when in front of the face"},
- {MOD_SHRINKWRAP_CULL_TARGET_BACKFACE,
- "BACK",
- 0,
- "Back",
- "No projection when behind the face"},
- {0, NULL, 0, NULL, NULL},
- };
-
srna = RNA_def_struct(brna, "ShrinkwrapModifier", "Modifier");
RNA_def_struct_ui_text(srna,
"Shrinkwrap Modifier",
@@ -4235,7 +4231,7 @@ static void rna_def_modifier_shrinkwrap(BlenderRNA *brna)
prop = RNA_def_property(srna, "wrap_method", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "shrinkType");
- RNA_def_property_enum_items(prop, shrink_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_shrinkwrap_type_items);
RNA_def_property_ui_text(prop, "Wrap Method", "");
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
@@ -4248,7 +4244,7 @@ static void rna_def_modifier_shrinkwrap(BlenderRNA *brna)
prop = RNA_def_property(srna, "cull_face", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "shrinkOpts");
- RNA_def_property_enum_items(prop, shrink_face_cull_items);
+ RNA_def_property_enum_items(prop, rna_enum_shrinkwrap_face_cull_items);
RNA_def_property_enum_funcs(
prop, "rna_ShrinkwrapModifier_face_cull_get", "rna_ShrinkwrapModifier_face_cull_set", NULL);
RNA_def_property_ui_text(
diff --git a/source/blender/makesrna/intern/rna_nla.c b/source/blender/makesrna/intern/rna_nla.c
index b19836a7f12..230133a8f9d 100644
--- a/source/blender/makesrna/intern/rna_nla.c
+++ b/source/blender/makesrna/intern/rna_nla.c
@@ -885,6 +885,8 @@ static void rna_def_nlatrack(BlenderRNA *brna)
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "NLA Strips", "NLA Strips on this NLA-track");
+ rna_api_nlatrack_strips(brna, prop);
+
prop = RNA_def_boolean(srna,
"is_override_data",
false,
@@ -894,8 +896,6 @@ static void rna_def_nlatrack(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", NLATRACK_OVERRIDELIBRARY_LOCAL);
- rna_api_nlatrack_strips(brna, prop);
-
RNA_define_lib_overridable(true);
/* name property */
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index aef3823338b..df0271d81d5 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -39,6 +39,7 @@
#include "BKE_animsys.h"
#include "BKE_attribute.h"
#include "BKE_cryptomatte.h"
+#include "BKE_geometry_set.h"
#include "BKE_image.h"
#include "BKE_node.h"
#include "BKE_texture.h"
@@ -304,36 +305,68 @@ const EnumPropertyItem rna_enum_node_boolean_math_items[] = {
};
const EnumPropertyItem rna_enum_node_float_compare_items[] = {
- {NODE_FLOAT_COMPARE_LESS_THAN,
+ {NODE_COMPARE_LESS_THAN,
"LESS_THAN",
0,
"Less Than",
"True when the first input is smaller than second input"},
- {NODE_FLOAT_COMPARE_LESS_EQUAL,
+ {NODE_COMPARE_LESS_EQUAL,
"LESS_EQUAL",
0,
"Less Than or Equal",
"True when the first input is smaller than the second input or equal"},
- {NODE_FLOAT_COMPARE_GREATER_THAN,
+ {NODE_COMPARE_GREATER_THAN,
"GREATER_THAN",
0,
"Greater Than",
"True when the first input is greater than the second input"},
- {NODE_FLOAT_COMPARE_GREATER_EQUAL,
+ {NODE_COMPARE_GREATER_EQUAL,
"GREATER_EQUAL",
0,
"Greater Than or Equal",
"True when the first input is greater than the second input or equal"},
- {NODE_FLOAT_COMPARE_EQUAL,
- "EQUAL",
+ {NODE_COMPARE_EQUAL, "EQUAL", 0, "Equal", "True when both inputs are approximately equal"},
+ {NODE_COMPARE_NOT_EQUAL,
+ "NOT_EQUAL",
+ 0,
+ "Not Equal",
+ "True when both inputs are not approximately equal"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+const EnumPropertyItem rna_enum_node_compare_operation_items[] = {
+ {NODE_COMPARE_LESS_THAN,
+ "LESS_THAN",
+ 0,
+ "Less Than",
+ "True when the first input is smaller than second input"},
+ {NODE_COMPARE_LESS_EQUAL,
+ "LESS_EQUAL",
+ 0,
+ "Less Than or Equal",
+ "True when the first input is smaller than the second input or equal"},
+ {NODE_COMPARE_GREATER_THAN,
+ "GREATER_THAN",
0,
- "Equal",
- "True when both inputs are approximately equal"},
- {NODE_FLOAT_COMPARE_NOT_EQUAL,
+ "Greater Than",
+ "True when the first input is greater than the second input"},
+ {NODE_COMPARE_GREATER_EQUAL,
+ "GREATER_EQUAL",
+ 0,
+ "Greater Than or Equal",
+ "True when the first input is greater than the second input or equal"},
+ {NODE_COMPARE_EQUAL, "EQUAL", 0, "Equal", "True when both inputs are approximately equal"},
+ {NODE_COMPARE_NOT_EQUAL,
"NOT_EQUAL",
0,
"Not Equal",
"True when both inputs are not approximately equal"},
+ {NODE_COMPARE_COLOR_BRIGHTER,
+ "BRIGHTER",
+ 0,
+ "Brighter",
+ "True when the first input is brighter"},
+ {NODE_COMPARE_COLOR_DARKER, "DARKER", 0, "Darker", "True when the first input is darker"},
{0, NULL, 0, NULL, NULL},
};
@@ -1235,10 +1268,15 @@ static bNode *rna_NodeTree_node_new(bNodeTree *ntree,
ntreeTexCheckCyclics(ntree);
}
- ntreeUpdateTree(CTX_data_main(C), ntree);
+ Main *bmain = CTX_data_main(C);
+ ntreeUpdateTree(bmain, ntree);
nodeUpdate(ntree, node);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
+ if (node->type == GEO_NODE_INPUT_SCENE_TIME) {
+ DEG_relations_tag_update(bmain);
+ }
+
return node;
}
@@ -1853,7 +1891,7 @@ static void rna_Node_draw_buttons_ext(struct uiLayout *layout, bContext *C, Poin
RNA_parameter_list_free(&list);
}
-static void rna_Node_draw_label(bNodeTree *ntree, bNode *node, char *label, int maxlen)
+static void rna_Node_draw_label(const bNodeTree *ntree, const bNode *node, char *label, int maxlen)
{
extern FunctionRNA rna_Node_draw_label_func;
@@ -1865,7 +1903,7 @@ static void rna_Node_draw_label(bNodeTree *ntree, bNode *node, char *label, int
func = &rna_Node_draw_label_func; /* RNA_struct_find_function(&ptr, "draw_label"); */
- RNA_pointer_create(&ntree->id, &RNA_Node, node, &ptr);
+ RNA_pointer_create((ID *)&ntree->id, &RNA_Node, (bNode *)node, &ptr);
RNA_parameter_list_create(&list, &ptr, func);
node->typeinfo->rna_ext.call(NULL, &ptr, func, &list);
@@ -2069,10 +2107,76 @@ static const EnumPropertyItem *rna_GeometryNodeSwitch_type_itemf(bContext *UNUSE
return itemf_function_check(node_socket_data_type_items, switch_type_supported);
}
+static bool compare_type_supported(const EnumPropertyItem *item)
+{
+ return ELEM(item->value, SOCK_FLOAT, SOCK_INT, SOCK_VECTOR, SOCK_STRING, SOCK_RGBA);
+}
+
+static bool compare_main_operation_supported(const EnumPropertyItem *item)
+{
+ return !ELEM(item->value, NODE_COMPARE_COLOR_BRIGHTER, NODE_COMPARE_COLOR_DARKER);
+}
+
+static bool compare_rgba_operation_supported(const EnumPropertyItem *item)
+{
+ return ELEM(item->value,
+ NODE_COMPARE_EQUAL,
+ NODE_COMPARE_NOT_EQUAL,
+ NODE_COMPARE_COLOR_BRIGHTER,
+ NODE_COMPARE_COLOR_DARKER);
+}
+
+static bool compare_string_operation_supported(const EnumPropertyItem *item)
+{
+ return ELEM(item->value, NODE_COMPARE_EQUAL, NODE_COMPARE_NOT_EQUAL);
+}
+
+static bool compare_other_operation_supported(const EnumPropertyItem *UNUSED(item))
+{
+ return false;
+}
+
+static const EnumPropertyItem *rna_FunctionNodeCompare_type_itemf(bContext *UNUSED(C),
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
+{
+ *r_free = true;
+ return itemf_function_check(node_socket_data_type_items, compare_type_supported);
+}
+
+static const EnumPropertyItem *rna_FunctionNodeCompare_operation_itemf(bContext *UNUSED(C),
+ PointerRNA *ptr,
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
+{
+ *r_free = true;
+ bNode *node = ptr->data;
+ NodeFunctionCompare *data = (NodeFunctionCompare *)node->storage;
+
+ if (ELEM(data->data_type, SOCK_FLOAT, SOCK_INT, SOCK_VECTOR)) {
+ return itemf_function_check(rna_enum_node_compare_operation_items,
+ compare_main_operation_supported);
+ }
+ else if (data->data_type == SOCK_STRING) {
+ return itemf_function_check(rna_enum_node_compare_operation_items,
+ compare_string_operation_supported);
+ }
+ else if (data->data_type == SOCK_RGBA) {
+ return itemf_function_check(rna_enum_node_compare_operation_items,
+ compare_rgba_operation_supported);
+ }
+ else {
+ return itemf_function_check(rna_enum_node_compare_operation_items,
+ compare_other_operation_supported);
+ }
+}
+
static bool attribute_clamp_type_supported(const EnumPropertyItem *item)
{
return ELEM(item->value, CD_PROP_FLOAT, CD_PROP_FLOAT3, CD_PROP_INT32, CD_PROP_COLOR);
}
+
static const EnumPropertyItem *rna_GeometryNodeAttributeClamp_type_itemf(bContext *UNUSED(C),
PointerRNA *UNUSED(ptr),
PropertyRNA *UNUSED(prop),
@@ -2149,6 +2253,30 @@ static void rna_GeometryNodeAttributeRandomize_data_type_update(Main *bmain,
rna_Node_socket_update(bmain, scene, ptr);
}
+static void rna_GeometryNodeCompare_data_type_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ bNode *node = ptr->data;
+ NodeFunctionCompare *node_storage = (NodeFunctionCompare *)node->storage;
+
+ if (node_storage->data_type == SOCK_RGBA && !ELEM(node_storage->operation,
+ NODE_COMPARE_EQUAL,
+ NODE_COMPARE_NOT_EQUAL,
+ NODE_COMPARE_COLOR_BRIGHTER,
+ NODE_COMPARE_COLOR_DARKER)) {
+ node_storage->operation = NODE_COMPARE_EQUAL;
+ }
+ else if (node_storage->data_type == SOCK_STRING &&
+ !ELEM(node_storage->operation, NODE_COMPARE_EQUAL, NODE_COMPARE_NOT_EQUAL)) {
+ node_storage->operation = NODE_COMPARE_EQUAL;
+ }
+ else if (node_storage->data_type != SOCK_RGBA &&
+ ELEM(node_storage->operation, NODE_COMPARE_COLOR_BRIGHTER, NODE_COMPARE_COLOR_DARKER)) {
+ node_storage->operation = NODE_COMPARE_EQUAL;
+ }
+
+ rna_Node_socket_update(bmain, scene, ptr);
+}
+
static bool attribute_convert_type_supported(const EnumPropertyItem *item)
{
return ELEM(item->value,
@@ -3036,8 +3164,11 @@ static void rna_NodeSocketInterface_register_properties(bNodeTree *ntree,
RNA_parameter_list_free(&list);
}
-static void rna_NodeSocketInterface_init_socket(
- bNodeTree *ntree, bNodeSocket *stemp, bNode *node, bNodeSocket *sock, const char *data_path)
+static void rna_NodeSocketInterface_init_socket(bNodeTree *ntree,
+ const bNodeSocket *interface_socket,
+ bNode *node,
+ bNodeSocket *sock,
+ const char *data_path)
{
extern FunctionRNA rna_NodeSocketInterface_init_socket_func;
@@ -3045,11 +3176,11 @@ static void rna_NodeSocketInterface_init_socket(
ParameterList list;
FunctionRNA *func;
- if (!stemp->typeinfo) {
+ if (!interface_socket->typeinfo) {
return;
}
- RNA_pointer_create((ID *)ntree, &RNA_NodeSocketInterface, stemp, &ptr);
+ RNA_pointer_create((ID *)ntree, &RNA_NodeSocketInterface, (bNodeSocket *)interface_socket, &ptr);
RNA_pointer_create((ID *)ntree, &RNA_Node, node, &node_ptr);
RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &sock_ptr);
// RNA_struct_find_function(&ptr, "init_socket");
@@ -3059,13 +3190,13 @@ static void rna_NodeSocketInterface_init_socket(
RNA_parameter_set_lookup(&list, "node", &node_ptr);
RNA_parameter_set_lookup(&list, "socket", &sock_ptr);
RNA_parameter_set_lookup(&list, "data_path", &data_path);
- stemp->typeinfo->ext_interface.call(NULL, &ptr, func, &list);
+ interface_socket->typeinfo->ext_interface.call(NULL, &ptr, func, &list);
RNA_parameter_list_free(&list);
}
static void rna_NodeSocketInterface_from_socket(bNodeTree *ntree,
- bNodeSocket *stemp,
+ bNodeSocket *interface_socket,
bNode *node,
bNodeSocket *sock)
{
@@ -3075,11 +3206,11 @@ static void rna_NodeSocketInterface_from_socket(bNodeTree *ntree,
ParameterList list;
FunctionRNA *func;
- if (!stemp->typeinfo) {
+ if (!interface_socket->typeinfo) {
return;
}
- RNA_pointer_create((ID *)ntree, &RNA_NodeSocketInterface, stemp, &ptr);
+ RNA_pointer_create((ID *)ntree, &RNA_NodeSocketInterface, interface_socket, &ptr);
RNA_pointer_create((ID *)ntree, &RNA_Node, node, &node_ptr);
RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &sock_ptr);
// RNA_struct_find_function(&ptr, "from_socket");
@@ -3088,7 +3219,7 @@ static void rna_NodeSocketInterface_from_socket(bNodeTree *ntree,
RNA_parameter_list_create(&list, &ptr, func);
RNA_parameter_set_lookup(&list, "node", &node_ptr);
RNA_parameter_set_lookup(&list, "socket", &sock_ptr);
- stemp->typeinfo->ext_interface.call(NULL, &ptr, func, &list);
+ interface_socket->typeinfo->ext_interface.call(NULL, &ptr, func, &list);
RNA_parameter_list_free(&list);
}
@@ -4823,18 +4954,32 @@ static void def_clamp(StructRNA *srna)
static void def_map_range(StructRNA *srna)
{
+ static const EnumPropertyItem rna_enum_data_type_items[] = {
+ {CD_PROP_FLOAT, "FLOAT", 0, "Float", "Floating-point value"},
+ {CD_PROP_FLOAT3, "FLOAT_VECTOR", 0, "Vector", "3D vector with floating-point values"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ RNA_def_struct_sdna_from(srna, "NodeMapRange", "storage");
+
PropertyRNA *prop;
prop = RNA_def_property(srna, "clamp", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "custom1", 1);
+ RNA_def_property_boolean_sdna(prop, NULL, "clamp", 1);
RNA_def_property_ui_text(prop, "Clamp", "Clamp the result to the target range [To Min, To Max]");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
prop = RNA_def_property(srna, "interpolation_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "custom2");
+ RNA_def_property_enum_sdna(prop, NULL, "interpolation_type");
RNA_def_property_enum_items(prop, rna_enum_node_map_range_items);
RNA_def_property_ui_text(prop, "Interpolation Type", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update");
+
+ prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "data_type");
+ RNA_def_property_enum_items(prop, rna_enum_data_type_items);
+ RNA_def_property_ui_text(prop, "Data Type", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update");
}
static void def_math(StructRNA *srna)
@@ -4864,15 +5009,57 @@ static void def_boolean_math(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
-static void def_float_compare(StructRNA *srna)
+static void def_compare(StructRNA *srna)
{
+
+ static const EnumPropertyItem mode_items[] = {
+ {NODE_COMPARE_MODE_ELEMENT,
+ "ELEMENT",
+ 0,
+ "Element-Wise",
+ "Compare each element of the input vectors"},
+ {NODE_COMPARE_MODE_LENGTH, "LENGTH", 0, "Length", "Compare the length of the input vectors"},
+ {NODE_COMPARE_MODE_AVERAGE,
+ "AVERAGE",
+ 0,
+ "Average",
+ "Compare the average of the input vectors elements"},
+ {NODE_COMPARE_MODE_DOT_PRODUCT,
+ "DOT_PRODUCT",
+ 0,
+ "Dot Product",
+ "Compare the dot products of the input vectors"},
+ {NODE_COMPARE_MODE_DIRECTION,
+ "DIRECTION",
+ 0,
+ "Direction",
+ "Compare the direction of the input vectors"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
PropertyRNA *prop;
+ RNA_def_struct_sdna_from(srna, "NodeFunctionCompare", "storage");
+
prop = RNA_def_property(srna, "operation", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "custom1");
- RNA_def_property_enum_items(prop, rna_enum_node_float_compare_items);
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_FunctionNodeCompare_operation_itemf");
+ RNA_def_property_enum_items(prop, rna_enum_node_compare_operation_items);
+ RNA_def_property_enum_default(prop, NODE_COMPARE_EQUAL);
RNA_def_property_ui_text(prop, "Operation", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+
+ prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_FunctionNodeCompare_type_itemf");
+ RNA_def_property_enum_items(prop, node_socket_data_type_items);
+ RNA_def_property_enum_default(prop, SOCK_FLOAT);
+ RNA_def_property_ui_text(prop, "Input Type", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNodeCompare_data_type_update");
+
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, mode_items);
+ RNA_def_property_enum_default(prop, NODE_COMPARE_MODE_ELEMENT);
+ RNA_def_property_ui_text(prop, "Mode", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
static void def_float_to_int(StructRNA *srna)
@@ -9166,6 +9353,16 @@ static void def_geo_boolean(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
+static void def_geo_attribute_domain_size(StructRNA *srna)
+{
+ PropertyRNA *prop = RNA_def_property(srna, "component", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_enum_items(prop, rna_enum_geometry_component_type_items);
+ RNA_def_property_enum_default(prop, GEO_COMPONENT_TYPE_MESH);
+ RNA_def_property_ui_text(prop, "Component", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+}
+
static void def_geo_curve_primitive_bezier_segment(StructRNA *srna)
{
static const EnumPropertyItem mode_items[] = {
@@ -9578,7 +9775,7 @@ static void def_geo_attribute_attribute_compare(StructRNA *srna)
prop = RNA_def_property(srna, "operation", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_enum_node_float_compare_items);
- RNA_def_property_enum_default(prop, NODE_FLOAT_COMPARE_GREATER_THAN);
+ RNA_def_property_enum_default(prop, NODE_COMPARE_GREATER_THAN);
RNA_def_property_ui_text(prop, "Operation", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
@@ -11092,6 +11289,17 @@ static void def_geo_viewer(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update");
}
+static void def_geo_realize_instances(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "legacy_behavior", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "custom1", GEO_NODE_REALIZE_INSTANCES_LEGACY_BEHAVIOR);
+ RNA_def_property_ui_text(
+ prop, "Legacy Behavior", "Behave like before instance attributes existed");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update");
+}
+
/* -------------------------------------------------------------------------- */
static void rna_def_shader_node(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c
index 87173adc38f..76bfea00a79 100644
--- a/source/blender/makesrna/intern/rna_pose.c
+++ b/source/blender/makesrna/intern/rna_pose.c
@@ -869,7 +869,6 @@ static void rna_PoseChannel_custom_shape_transform_set(PointerRNA *ptr,
#else
-/* common properties for Action/Bone Groups - related to color */
void rna_def_actionbone_group_common(StructRNA *srna, int update_flag, const char *update_cb)
{
PropertyRNA *prop;
diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c
index e5009305fe5..285f6365ea1 100644
--- a/source/blender/makesrna/intern/rna_rna.c
+++ b/source/blender/makesrna/intern/rna_rna.c
@@ -1941,6 +1941,8 @@ int rna_property_override_diff_default(Main *bmain,
idx_a - 1);
# endif
op = NULL;
+
+ equals = false;
}
else if (is_id || is_valid_for_diffing) {
if (equals || do_create) {
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index c69a69290f9..5f1d9c5a5ce 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -3425,7 +3425,8 @@ static void rna_def_tool_settings(BlenderRNA *brna)
prop,
"Cycle-Aware Keying",
"For channels with cyclic extrapolation, keyframe insertion is automatically "
- "remapped inside the cycle time range, and keeps ends in sync");
+ "remapped inside the cycle time range, and keeps ends in sync. Curves newly added to "
+ "actions with a Manual Frame Range and Cyclic Animation are automatically made cyclic");
/* Keyframing */
prop = RNA_def_property(srna, "keyframe_type", PROP_ENUM, PROP_NONE);
@@ -5582,7 +5583,7 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna)
{FFMPEG_MPEG2, "MPEG2", 0, "MPEG-2", ""},
{FFMPEG_MPEG4, "MPEG4", 0, "MPEG-4", ""},
{FFMPEG_AVI, "AVI", 0, "AVI", ""},
- {FFMPEG_MOV, "QUICKTIME", 0, "Quicktime", ""},
+ {FFMPEG_MOV, "QUICKTIME", 0, "QuickTime", ""},
{FFMPEG_DV, "DV", 0, "DV", ""},
{FFMPEG_OGG, "OGG", 0, "Ogg", ""},
{FFMPEG_MKV, "MKV", 0, "Matroska", ""},
diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c
index f92043995dd..9be66a6553b 100644
--- a/source/blender/makesrna/intern/rna_sequencer.c
+++ b/source/blender/makesrna/intern/rna_sequencer.c
@@ -2272,7 +2272,8 @@ static void rna_def_filter_video(StructRNA *srna)
prop = RNA_def_property(srna, "use_reverse_frames", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_REVERSE_FRAMES);
RNA_def_property_ui_text(prop, "Reverse Frames", "Reverse frame order");
- RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update");
+ RNA_def_property_update(
+ prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update");
prop = RNA_def_property(srna, "color_multiply", PROP_FLOAT, PROP_UNSIGNED);
RNA_def_property_float_sdna(prop, NULL, "mul");
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index e7bcd387eaf..16e9a6208fb 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -73,6 +73,30 @@
#include "RNA_enum_types.h"
+const EnumPropertyItem rna_enum_geometry_component_type_items[] = {
+ {GEO_COMPONENT_TYPE_MESH,
+ "MESH",
+ ICON_MESH_DATA,
+ "Mesh",
+ "Mesh component containing point, corner, edge and face data"},
+ {GEO_COMPONENT_TYPE_POINT_CLOUD,
+ "POINTCLOUD",
+ ICON_POINTCLOUD_DATA,
+ "Point Cloud",
+ "Point cloud component containing only point data"},
+ {GEO_COMPONENT_TYPE_CURVE,
+ "CURVE",
+ ICON_CURVE_DATA,
+ "Curve",
+ "Curve component containing spline and control point data"},
+ {GEO_COMPONENT_TYPE_INSTANCES,
+ "INSTANCES",
+ ICON_EMPTY_AXIS,
+ "Instances",
+ "Instances of objects or collections"},
+ {0, NULL, 0, NULL, NULL},
+};
+
const EnumPropertyItem rna_enum_space_type_items[] = {
/* empty must be here for python, is skipped for UI */
{SPACE_EMPTY, "EMPTY", ICON_NONE, "Empty", ""},
@@ -7110,6 +7134,18 @@ static void rna_def_space_node_overlay(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Show Wire Colors", "Color node links based on their connected sockets");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE, NULL);
+
+ prop = RNA_def_property(srna, "show_timing", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "overlay.flag", SN_OVERLAY_SHOW_TIMINGS);
+ RNA_def_property_boolean_default(prop, false);
+ RNA_def_property_ui_text(prop, "Show Timing", "Display each node's last execution time");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE, NULL);
+
+ prop = RNA_def_property(srna, "show_context_path", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "overlay.flag", SN_OVERLAY_SHOW_PATH);
+ RNA_def_property_boolean_default(prop, true);
+ RNA_def_property_ui_text(prop, "Show Tree Path", "Display breadcrumbs for the editor's context");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE, NULL);
}
static void rna_def_space_node(BlenderRNA *brna)
@@ -7826,30 +7862,6 @@ static void rna_def_space_spreadsheet(BlenderRNA *brna)
PropertyRNA *prop;
StructRNA *srna;
- static const EnumPropertyItem geometry_component_type_items[] = {
- {GEO_COMPONENT_TYPE_MESH,
- "MESH",
- ICON_MESH_DATA,
- "Mesh",
- "Mesh component containing point, corner, edge and face data"},
- {GEO_COMPONENT_TYPE_POINT_CLOUD,
- "POINTCLOUD",
- ICON_POINTCLOUD_DATA,
- "Point Cloud",
- "Point cloud component containing only point data"},
- {GEO_COMPONENT_TYPE_CURVE,
- "CURVE",
- ICON_CURVE_DATA,
- "Curve",
- "Curve component containing spline and control point data"},
- {GEO_COMPONENT_TYPE_INSTANCES,
- "INSTANCES",
- ICON_EMPTY_AXIS,
- "Instances",
- "Instances of objects or collections"},
- {0, NULL, 0, NULL, NULL},
- };
-
static const EnumPropertyItem object_eval_state_items[] = {
{SPREADSHEET_OBJECT_EVAL_STATE_EVALUATED,
"EVALUATED",
@@ -7908,7 +7920,7 @@ static void rna_def_space_spreadsheet(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
prop = RNA_def_property(srna, "geometry_component_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, geometry_component_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_geometry_component_type_items);
RNA_def_property_ui_text(
prop, "Geometry Component", "Part of the geometry to display data from");
RNA_def_property_update(prop,
diff --git a/source/blender/makesrna/intern/rna_texture_api.c b/source/blender/makesrna/intern/rna_texture_api.c
index 83c1efd55bc..0920fe6679a 100644
--- a/source/blender/makesrna/intern/rna_texture_api.c
+++ b/source/blender/makesrna/intern/rna_texture_api.c
@@ -84,8 +84,8 @@ void RNA_api_texture(StructRNA *srna)
NULL,
-FLT_MAX,
FLT_MAX,
- "The result of the texture where (x,y,z,w) are (red, green, blue, intensity). For greyscale "
- "textures, often intensity only will be used",
+ "The result of the texture where (x,y,z,w) are (red, green, blue, intensity). "
+ "For grayscale textures, often intensity only will be used",
NULL,
-1e4,
1e4);
diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c
index 1cb1397a0ed..8c128292fd7 100644
--- a/source/blender/makesrna/intern/rna_wm.c
+++ b/source/blender/makesrna/intern/rna_wm.c
@@ -142,9 +142,10 @@ static const EnumPropertyItem event_ndof_type_items[] = {
};
#endif /* RNA_RUNTIME */
-/* not returned: CAPSLOCKKEY, UNKNOWNKEY */
const EnumPropertyItem rna_enum_event_type_items[] = {
- /* Note we abuse 'tooltip' message here to store a 'compact' form of some (too) long names. */
+ /* - Note we abuse 'tooltip' message here to store a 'compact' form of some (too) long names.
+ * - Intentionally excluded: #CAPSLOCKKEY, #UNKNOWNKEY.
+ */
{0, "NONE", 0, "", ""},
{LEFTMOUSE, "LEFTMOUSE", 0, "Left Mouse", "LMB"},
{MIDDLEMOUSE, "MIDDLEMOUSE", 0, "Middle Mouse", "MMB"},
diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt
index d9b9fa96d04..c30beaf001a 100644
--- a/source/blender/modifiers/CMakeLists.txt
+++ b/source/blender/modifiers/CMakeLists.txt
@@ -30,6 +30,7 @@ set(INC
../depsgraph
../editors/include
../functions
+ ../geometry
../makesdna
../makesrna
../nodes
diff --git a/source/blender/modifiers/MOD_modifiertypes.h b/source/blender/modifiers/MOD_modifiertypes.h
index f36cb7ded9c..2a0a7a02472 100644
--- a/source/blender/modifiers/MOD_modifiertypes.h
+++ b/source/blender/modifiers/MOD_modifiertypes.h
@@ -91,6 +91,10 @@ extern ModifierTypeInfo modifierType_VolumeDisplace;
extern ModifierTypeInfo modifierType_VolumeToMesh;
/* MOD_util.c */
+
+/**
+ * Only called by `BKE_modifier.h/modifier.c`
+ */
void modifier_type_init(ModifierTypeInfo *types[]);
#ifdef __cplusplus
diff --git a/source/blender/modifiers/MOD_nodes.h b/source/blender/modifiers/MOD_nodes.h
index 907dbe9c5f4..1105925162c 100644
--- a/source/blender/modifiers/MOD_nodes.h
+++ b/source/blender/modifiers/MOD_nodes.h
@@ -24,6 +24,11 @@ struct Object;
extern "C" {
#endif
+/**
+ * Rebuild the list of properties based on the sockets exposed as the modifier's node group
+ * inputs. If any properties correspond to the old properties by name and type, carry over
+ * the values.
+ */
void MOD_nodes_update_interface(struct Object *object, struct NodesModifierData *nmd);
void MOD_nodes_init(struct Main *bmain, struct NodesModifierData *nmd);
diff --git a/source/blender/modifiers/intern/MOD_curve.c b/source/blender/modifiers/intern/MOD_curve.c
index aae6d257766..20dbb299767 100644
--- a/source/blender/modifiers/intern/MOD_curve.c
+++ b/source/blender/modifiers/intern/MOD_curve.c
@@ -167,7 +167,7 @@ static void deformVertsEM(ModifierData *md,
int defgrp_index = -1;
if (ctx->object->type == OB_MESH && cmd->name[0] != '\0') {
- defgrp_index = BKE_id_defgroup_name_index(&mesh->id, cmd->name);
+ defgrp_index = BKE_object_defgroup_name_index(ctx->object, cmd->name);
if (defgrp_index != -1) {
use_dverts = true;
}
diff --git a/source/blender/modifiers/intern/MOD_mirror.c b/source/blender/modifiers/intern/MOD_mirror.c
index 7fd90c71c9f..bbac6589577 100644
--- a/source/blender/modifiers/intern/MOD_mirror.c
+++ b/source/blender/modifiers/intern/MOD_mirror.c
@@ -84,14 +84,17 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
static Mesh *mirrorModifier__doMirror(MirrorModifierData *mmd, Object *ob, Mesh *mesh)
{
Mesh *result = mesh;
+ const bool use_correct_order_on_merge = mmd->use_correct_order_on_merge;
/* check which axes have been toggled and mirror accordingly */
if (mmd->flag & MOD_MIR_AXIS_X) {
- result = BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(mmd, ob, result, 0);
+ result = BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(
+ mmd, ob, result, 0, use_correct_order_on_merge);
}
if (mmd->flag & MOD_MIR_AXIS_Y) {
Mesh *tmp = result;
- result = BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(mmd, ob, result, 1);
+ result = BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(
+ mmd, ob, result, 1, use_correct_order_on_merge);
if (tmp != mesh) {
/* free intermediate results */
BKE_id_free(NULL, tmp);
@@ -99,7 +102,8 @@ static Mesh *mirrorModifier__doMirror(MirrorModifierData *mmd, Object *ob, Mesh
}
if (mmd->flag & MOD_MIR_AXIS_Z) {
Mesh *tmp = result;
- result = BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(mmd, ob, result, 2);
+ result = BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(
+ mmd, ob, result, 2, use_correct_order_on_merge);
if (tmp != mesh) {
/* free intermediate results */
BKE_id_free(NULL, tmp);
diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc
index c1cdfa43920..ec6cbeb43bf 100644
--- a/source/blender/modifiers/intern/MOD_nodes.cc
+++ b/source/blender/modifiers/intern/MOD_nodes.cc
@@ -98,6 +98,7 @@
#include "NOD_node_declaration.hh"
#include "FN_field.hh"
+#include "FN_field_cpp_type.hh"
#include "FN_multi_function.hh"
using blender::Array;
@@ -113,9 +114,11 @@ using blender::StringRef;
using blender::StringRefNull;
using blender::Vector;
using blender::bke::OutputAttribute;
+using blender::fn::Field;
using blender::fn::GField;
using blender::fn::GMutablePointer;
using blender::fn::GPointer;
+using blender::fn::ValueOrField;
using blender::nodes::FieldInferencingInterface;
using blender::nodes::GeoNodeExecParams;
using blender::nodes::InputSocketFieldType;
@@ -265,6 +268,39 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
}
}
+static bool check_tree_for_time_node(const bNodeTree &tree,
+ Set<const bNodeTree *> &r_checked_trees)
+{
+ if (!r_checked_trees.add(&tree)) {
+ return false;
+ }
+ LISTBASE_FOREACH (const bNode *, node, &tree.nodes) {
+ if (node->type == GEO_NODE_INPUT_SCENE_TIME) {
+ return true;
+ }
+ if (node->type == NODE_GROUP) {
+ const bNodeTree *sub_tree = reinterpret_cast<const bNodeTree *>(node->id);
+ if (sub_tree && check_tree_for_time_node(*sub_tree, r_checked_trees)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+static bool dependsOnTime(struct Scene *UNUSED(scene),
+ ModifierData *md,
+ const int UNUSED(dag_eval_mode))
+{
+ const NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
+ const bNodeTree *tree = nmd->node_group;
+ if (tree == nullptr) {
+ return false;
+ }
+ Set<const bNodeTree *> checked_trees;
+ return check_tree_for_time_node(*tree, checked_trees);
+}
+
static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
{
NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
@@ -491,35 +527,34 @@ static void init_socket_cpp_value_from_property(const IDProperty &property,
else if (property.type == IDP_DOUBLE) {
value = (float)IDP_Double(&property);
}
- new (r_value) blender::fn::Field<float>(blender::fn::make_constant_field(value));
+ new (r_value) ValueOrField<float>(value);
break;
}
case SOCK_INT: {
int value = IDP_Int(&property);
- new (r_value) blender::fn::Field<int>(blender::fn::make_constant_field(value));
+ new (r_value) ValueOrField<int>(value);
break;
}
case SOCK_VECTOR: {
float3 value;
copy_v3_v3(value, (const float *)IDP_Array(&property));
- new (r_value) blender::fn::Field<float3>(blender::fn::make_constant_field(value));
+ new (r_value) ValueOrField<float3>(value);
break;
}
case SOCK_RGBA: {
blender::ColorGeometry4f value;
copy_v4_v4((float *)value, (const float *)IDP_Array(&property));
- new (r_value) blender::fn::Field<ColorGeometry4f>(blender::fn::make_constant_field(value));
+ new (r_value) ValueOrField<ColorGeometry4f>(value);
break;
}
case SOCK_BOOLEAN: {
bool value = IDP_Int(&property) != 0;
- new (r_value) blender::fn::Field<bool>(blender::fn::make_constant_field(value));
+ new (r_value) ValueOrField<bool>(value);
break;
}
case SOCK_STRING: {
std::string value = IDP_String(&property);
- new (r_value)
- blender::fn::Field<std::string>(blender::fn::make_constant_field(std::move(value)));
+ new (r_value) ValueOrField<std::string>(std::move(value));
break;
}
case SOCK_OBJECT: {
@@ -559,11 +594,6 @@ static void init_socket_cpp_value_from_property(const IDProperty &property,
}
}
-/**
- * Rebuild the list of properties based on the sockets exposed as the modifier's node group
- * inputs. If any properties correspond to the old properties by name and type, carry over
- * the values.
- */
void MOD_nodes_update_interface(Object *object, NodesModifierData *nmd)
{
if (nmd->node_group == nullptr) {
@@ -739,8 +769,13 @@ static void initialize_group_input(NodesModifierData &nmd,
if (use_attribute) {
const StringRef attribute_name{IDP_String(property_attribute_name)};
auto attribute_input = std::make_shared<blender::bke::AttributeFieldInput>(
- attribute_name, *socket_type.get_base_cpp_type());
- new (r_value) blender::fn::GField(std::move(attribute_input), 0);
+ attribute_name, *socket_type.base_cpp_type);
+ GField attribute_field{std::move(attribute_input), 0};
+ const blender::fn::ValueOrFieldCPPType *cpp_type =
+ dynamic_cast<const blender::fn::ValueOrFieldCPPType *>(
+ socket_type.geometry_nodes_cpp_type);
+ BLI_assert(cpp_type != nullptr);
+ cpp_type->construct_from_field(r_value, std::move(attribute_field));
}
else {
init_socket_cpp_value_from_property(
@@ -904,7 +939,11 @@ static void store_output_value_in_geometry(GeometrySet &geometry_set,
if (attribute_name.is_empty()) {
return;
}
- const GField &field = *(const GField *)value.get();
+ const blender::fn::ValueOrFieldCPPType *cpp_type =
+ dynamic_cast<const blender::fn::ValueOrFieldCPPType *>(value.type());
+ BLI_assert(cpp_type != nullptr);
+
+ const GField field = cpp_type->as_field(value.get());
const bNodeSocket *interface_socket = (bNodeSocket *)BLI_findlink(&nmd->node_group->outputs,
socket.index());
const AttributeDomain domain = (AttributeDomain)interface_socket->attribute_domain;
@@ -963,7 +1002,7 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree,
/* Initialize remaining group inputs. */
for (const OutputSocketRef *socket : remaining_input_sockets) {
- const CPPType &cpp_type = *socket->typeinfo()->get_geometry_nodes_cpp_type();
+ const CPPType &cpp_type = *socket->typeinfo()->geometry_nodes_cpp_type;
void *value_in = allocator.allocate(cpp_type.size(), cpp_type.alignment());
initialize_group_input(*nmd, *socket, value_in);
group_inputs.add_new({root_context, socket}, {cpp_type, value_in});
@@ -1584,7 +1623,7 @@ ModifierTypeInfo modifierType_Nodes = {
/* freeData */ freeData,
/* isDisabled */ isDisabled,
/* updateDepsgraph */ updateDepsgraph,
- /* dependsOnTime */ nullptr,
+ /* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ nullptr,
/* foreachIDLink */ foreachIDLink,
/* foreachTexLink */ foreachTexLink,
diff --git a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc
index badd633f648..4e808120f4a 100644
--- a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc
+++ b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc
@@ -16,9 +16,10 @@
#include "MOD_nodes_evaluator.hh"
+#include "BKE_type_conversions.hh"
+
#include "NOD_geometry_exec.hh"
#include "NOD_socket_declarations.hh"
-#include "NOD_type_conversions.hh"
#include "DEG_depsgraph_query.h"
@@ -35,13 +36,17 @@
#include "BLI_task.hh"
#include "BLI_vector_set.hh"
+#include <chrono>
+
namespace blender::modifiers::geometry_nodes {
using fn::CPPType;
using fn::Field;
-using fn::FieldCPPType;
using fn::GField;
using fn::GValueMap;
+using fn::GVArray;
+using fn::ValueOrField;
+using fn::ValueOrFieldCPPType;
using nodes::GeoNodeExecParams;
using namespace fn::multi_function_types;
@@ -309,10 +314,10 @@ class LockedNode : NonCopyable, NonMovable {
static const CPPType *get_socket_cpp_type(const SocketRef &socket)
{
const bNodeSocketType *typeinfo = socket.typeinfo();
- if (typeinfo->get_geometry_nodes_cpp_type == nullptr) {
+ if (typeinfo->geometry_nodes_cpp_type == nullptr) {
return nullptr;
}
- const CPPType *type = typeinfo->get_geometry_nodes_cpp_type();
+ const CPPType *type = typeinfo->geometry_nodes_cpp_type;
if (type == nullptr) {
return nullptr;
}
@@ -348,18 +353,19 @@ static bool get_implicit_socket_input(const SocketRef &socket, void *r_value)
GEO_NODE_CURVE_HANDLE_LEFT ?
"handle_left" :
"handle_right";
- new (r_value) Field<float3>(bke::AttributeFieldInput::Create<float3>(side));
+ new (r_value) ValueOrField<float3>(bke::AttributeFieldInput::Create<float3>(side));
return true;
}
- new (r_value) Field<float3>(bke::AttributeFieldInput::Create<float3>("position"));
+ new (r_value) ValueOrField<float3>(bke::AttributeFieldInput::Create<float3>("position"));
return true;
}
if (socket.typeinfo()->type == SOCK_INT) {
if (ELEM(bnode.type, FN_NODE_RANDOM_VALUE, GEO_NODE_INSTANCE_ON_POINTS)) {
- new (r_value) Field<int>(std::make_shared<bke::IDAttributeFieldInput>());
+ new (r_value)
+ ValueOrField<int>(Field<int>(std::make_shared<bke::IDAttributeFieldInput>()));
return true;
}
- new (r_value) Field<int>(std::make_shared<fn::IndexFieldInput>());
+ new (r_value) ValueOrField<int>(Field<int>(std::make_shared<fn::IndexFieldInput>()));
return true;
}
}
@@ -381,14 +387,23 @@ static bool node_supports_laziness(const DNode node)
return node->typeinfo()->geometry_node_execute_supports_laziness;
}
+struct NodeTaskRunState {
+ /** The node that should be run on the same thread after the current node finished. */
+ DNode next_node_to_run;
+};
+
/** Implements the callbacks that might be called when a node is executed. */
class NodeParamsProvider : public nodes::GeoNodeExecParamsProvider {
private:
GeometryNodesEvaluator &evaluator_;
NodeState &node_state_;
+ NodeTaskRunState *run_state_;
public:
- NodeParamsProvider(GeometryNodesEvaluator &evaluator, DNode dnode, NodeState &node_state);
+ NodeParamsProvider(GeometryNodesEvaluator &evaluator,
+ DNode dnode,
+ NodeState &node_state,
+ NodeTaskRunState *run_state);
bool can_get_input(StringRef identifier) const override;
bool can_set_output(StringRef identifier) const override;
@@ -402,6 +417,8 @@ class NodeParamsProvider : public nodes::GeoNodeExecParamsProvider {
bool lazy_require_input(StringRef identifier) override;
bool lazy_output_is_required(StringRef identifier) const override;
+
+ void set_default_remaining_outputs() override;
};
class GeometryNodesEvaluator {
@@ -433,7 +450,7 @@ class GeometryNodesEvaluator {
TaskPool *task_pool_ = nullptr;
GeometryNodesEvaluationParams &params_;
- const blender::nodes::DataTypeConversions &conversions_;
+ const blender::bke::DataTypeConversions &conversions_;
friend NodeParamsProvider;
@@ -441,7 +458,7 @@ class GeometryNodesEvaluator {
GeometryNodesEvaluator(GeometryNodesEvaluationParams &params)
: outer_allocator_(params.allocator),
params_(params),
- conversions_(blender::nodes::get_implicit_type_conversions())
+ conversions_(blender::bke::get_implicit_type_conversions())
{
}
@@ -640,7 +657,7 @@ class GeometryNodesEvaluator {
value.destruct();
continue;
}
- this->forward_output(socket, value);
+ this->forward_output(socket, value, nullptr);
}
}
@@ -649,7 +666,7 @@ class GeometryNodesEvaluator {
for (const DInputSocket &socket : params_.output_sockets) {
const DNode node = socket.node();
NodeState &node_state = this->get_node_state(node);
- this->with_locked_node(node, node_state, [&](LockedNode &locked_node) {
+ this->with_locked_node(node, node_state, nullptr, [&](LockedNode &locked_node) {
/* Setting an input as required will schedule any linked node. */
this->set_input_required(locked_node, socket);
});
@@ -657,7 +674,7 @@ class GeometryNodesEvaluator {
for (const DSocket socket : params_.force_compute_sockets) {
const DNode node = socket.node();
NodeState &node_state = this->get_node_state(node);
- this->with_locked_node(node, node_state, [&](LockedNode &locked_node) {
+ this->with_locked_node(node, node_state, nullptr, [&](LockedNode &locked_node) {
if (socket->is_input()) {
this->set_input_required(locked_node, DInputSocket(socket));
}
@@ -702,12 +719,24 @@ class GeometryNodesEvaluator {
{
void *user_data = BLI_task_pool_user_data(task_pool);
GeometryNodesEvaluator &evaluator = *(GeometryNodesEvaluator *)user_data;
- const NodeWithState *node_with_state = (const NodeWithState *)task_data;
-
- evaluator.node_task_run(node_with_state->node, *node_with_state->state);
+ const NodeWithState *root_node_with_state = (const NodeWithState *)task_data;
+
+ /* First, the node provided by the task pool is executed. During the execution other nodes
+ * might be scheduled. One of those nodes is not added to the task pool but is executed in the
+ * loop below directly. This has two main benefits:
+ * - Fewer round trips through the task pool which add threading overhead.
+ * - Helps with cpu cache efficiency, because a thread is more likely to process data that it
+ * has processed shortly before.
+ */
+ DNode next_node_to_run = root_node_with_state->node;
+ while (next_node_to_run) {
+ NodeTaskRunState run_state;
+ evaluator.node_task_run(next_node_to_run, &run_state);
+ next_node_to_run = run_state.next_node_to_run;
+ }
}
- void node_task_run(const DNode node, NodeState &node_state)
+ void node_task_run(const DNode node, NodeTaskRunState *run_state)
{
/* These nodes are sometimes scheduled. We could also check for them in other places, but
* it's the easiest to do it here. */
@@ -715,21 +744,25 @@ class GeometryNodesEvaluator {
return;
}
- const bool do_execute_node = this->node_task_preprocessing(node, node_state);
+ NodeState &node_state = *node_states_.lookup_key_as(node).state;
+
+ const bool do_execute_node = this->node_task_preprocessing(node, node_state, run_state);
/* Only execute the node if all prerequisites are met. There has to be an output that is
* required and all required inputs have to be provided already. */
if (do_execute_node) {
- this->execute_node(node, node_state);
+ this->execute_node(node, node_state, run_state);
}
- this->node_task_postprocessing(node, node_state, do_execute_node);
+ this->node_task_postprocessing(node, node_state, do_execute_node, run_state);
}
- bool node_task_preprocessing(const DNode node, NodeState &node_state)
+ bool node_task_preprocessing(const DNode node,
+ NodeState &node_state,
+ NodeTaskRunState *run_state)
{
bool do_execute_node = false;
- this->with_locked_node(node, node_state, [&](LockedNode &locked_node) {
+ this->with_locked_node(node, node_state, run_state, [&](LockedNode &locked_node) {
BLI_assert(node_state.schedule_state == NodeScheduleState::Scheduled);
node_state.schedule_state = NodeScheduleState::Running;
@@ -888,7 +921,7 @@ class GeometryNodesEvaluator {
* Actually execute the node. All the required inputs are available and at least one output is
* required.
*/
- void execute_node(const DNode node, NodeState &node_state)
+ void execute_node(const DNode node, NodeState &node_state, NodeTaskRunState *run_state)
{
const bNode &bnode = *node->bnode();
@@ -902,40 +935,49 @@ class GeometryNodesEvaluator {
/* Use the geometry node execute callback if it exists. */
if (bnode.typeinfo->geometry_node_execute != nullptr) {
- this->execute_geometry_node(node, node_state);
+ this->execute_geometry_node(node, node_state, run_state);
return;
}
/* Use the multi-function implementation if it exists. */
const nodes::NodeMultiFunctions::Item &fn_item = params_.mf_by_node->try_get(node);
if (fn_item.fn != nullptr) {
- this->execute_multi_function_node(node, fn_item, node_state);
+ this->execute_multi_function_node(node, fn_item, node_state, run_state);
return;
}
- this->execute_unknown_node(node, node_state);
+ this->execute_unknown_node(node, node_state, run_state);
}
- void execute_geometry_node(const DNode node, NodeState &node_state)
+ void execute_geometry_node(const DNode node, NodeState &node_state, NodeTaskRunState *run_state)
{
const bNode &bnode = *node->bnode();
- NodeParamsProvider params_provider{*this, node, node_state};
+ NodeParamsProvider params_provider{*this, node, node_state, run_state};
GeoNodeExecParams params{params_provider};
if (node->idname().find("Legacy") != StringRef::not_found) {
params.error_message_add(geo_log::NodeWarningType::Legacy,
TIP_("Legacy node will be removed before Blender 4.0"));
}
+ using Clock = std::chrono::steady_clock;
+ Clock::time_point begin = Clock::now();
bnode.typeinfo->geometry_node_execute(params);
+ Clock::time_point end = Clock::now();
+ const std::chrono::microseconds duration =
+ std::chrono::duration_cast<std::chrono::microseconds>(end - begin);
+ if (params_.geo_logger != nullptr) {
+ params_.geo_logger->local().log_execution_time(node, duration);
+ }
}
void execute_multi_function_node(const DNode node,
const nodes::NodeMultiFunctions::Item &fn_item,
- NodeState &node_state)
+ NodeState &node_state,
+ NodeTaskRunState *run_state)
{
if (node->idname().find("Legacy") != StringRef::not_found) {
/* Create geometry nodes params just for creating an error message. */
- NodeParamsProvider params_provider{*this, node, node_state};
+ NodeParamsProvider params_provider{*this, node, node_state, run_state};
GeoNodeExecParams params{params_provider};
params.error_message_add(geo_log::NodeWarningType::Legacy,
TIP_("Legacy node will be removed before Blender 4.0"));
@@ -943,8 +985,9 @@ class GeometryNodesEvaluator {
LinearAllocator<> &allocator = local_allocators_.local();
- /* Prepare the inputs for the multi function. */
- Vector<GField> input_fields;
+ bool any_input_is_field = false;
+ Vector<const void *, 16> input_values;
+ Vector<const ValueOrFieldCPPType *, 16> input_types;
for (const int i : node->inputs().index_range()) {
const InputSocketRef &socket_ref = node->input(i);
if (!socket_ref.is_available()) {
@@ -955,7 +998,38 @@ class GeometryNodesEvaluator {
BLI_assert(input_state.was_ready_for_execution);
SingleInputValue &single_value = *input_state.value.single;
BLI_assert(single_value.value != nullptr);
- input_fields.append(std::move(*(GField *)single_value.value));
+ const ValueOrFieldCPPType &field_cpp_type = static_cast<const ValueOrFieldCPPType &>(
+ *input_state.type);
+ input_values.append(single_value.value);
+ input_types.append(&field_cpp_type);
+ if (field_cpp_type.is_field(single_value.value)) {
+ any_input_is_field = true;
+ }
+ }
+
+ if (any_input_is_field) {
+ this->execute_multi_function_node__field(
+ node, fn_item, node_state, allocator, input_values, input_types, run_state);
+ }
+ else {
+ this->execute_multi_function_node__value(
+ node, *fn_item.fn, node_state, allocator, input_values, input_types, run_state);
+ }
+ }
+
+ void execute_multi_function_node__field(const DNode node,
+ const nodes::NodeMultiFunctions::Item &fn_item,
+ NodeState &node_state,
+ LinearAllocator<> &allocator,
+ Span<const void *> input_values,
+ Span<const ValueOrFieldCPPType *> input_types,
+ NodeTaskRunState *run_state)
+ {
+ Vector<GField> input_fields;
+ for (const int i : input_values.index_range()) {
+ const void *input_value_or_field = input_values[i];
+ const ValueOrFieldCPPType &field_cpp_type = *input_types[i];
+ input_fields.append(field_cpp_type.as_field(input_value_or_field));
}
std::shared_ptr<fn::FieldOperation> operation;
@@ -966,7 +1040,6 @@ class GeometryNodesEvaluator {
operation = std::make_shared<fn::FieldOperation>(*fn_item.fn, std::move(input_fields));
}
- /* Forward outputs. */
int output_index = 0;
for (const int i : node->outputs().index_range()) {
const OutputSocketRef &socket_ref = node->output(i);
@@ -975,17 +1048,70 @@ class GeometryNodesEvaluator {
}
OutputState &output_state = node_state.outputs[i];
const DOutputSocket socket{node.context(), &socket_ref};
- const CPPType *cpp_type = get_socket_cpp_type(socket_ref);
+ const ValueOrFieldCPPType *cpp_type = static_cast<const ValueOrFieldCPPType *>(
+ get_socket_cpp_type(socket_ref));
GField new_field{operation, output_index};
- new_field = fn::make_field_constant_if_possible(std::move(new_field));
- GField &field_to_forward = *allocator.construct<GField>(std::move(new_field)).release();
- this->forward_output(socket, {cpp_type, &field_to_forward});
+ void *buffer = allocator.allocate(cpp_type->size(), cpp_type->alignment());
+ cpp_type->construct_from_field(buffer, std::move(new_field));
+ this->forward_output(socket, {cpp_type, buffer}, run_state);
output_state.has_been_computed = true;
output_index++;
}
}
- void execute_unknown_node(const DNode node, NodeState &node_state)
+ void execute_multi_function_node__value(const DNode node,
+ const MultiFunction &fn,
+ NodeState &node_state,
+ LinearAllocator<> &allocator,
+ Span<const void *> input_values,
+ Span<const ValueOrFieldCPPType *> input_types,
+ NodeTaskRunState *run_state)
+ {
+ MFParamsBuilder params{fn, 1};
+ for (const int i : input_values.index_range()) {
+ const void *input_value_or_field = input_values[i];
+ const ValueOrFieldCPPType &field_cpp_type = *input_types[i];
+ const CPPType &base_type = field_cpp_type.base_type();
+ const void *input_value = field_cpp_type.get_value_ptr(input_value_or_field);
+ params.add_readonly_single_input(GVArray::ForSingleRef(base_type, 1, input_value));
+ }
+
+ Vector<GMutablePointer, 16> output_buffers;
+ for (const int i : node->outputs().index_range()) {
+ const DOutputSocket socket = node.output(i);
+ if (!socket->is_available()) {
+ output_buffers.append({});
+ continue;
+ }
+ const ValueOrFieldCPPType *value_or_field_type = static_cast<const ValueOrFieldCPPType *>(
+ get_socket_cpp_type(socket));
+ const CPPType &base_type = value_or_field_type->base_type();
+ void *value_or_field_buffer = allocator.allocate(value_or_field_type->size(),
+ value_or_field_type->alignment());
+ value_or_field_type->default_construct(value_or_field_buffer);
+ void *value_buffer = value_or_field_type->get_value_ptr(value_or_field_buffer);
+ base_type.destruct(value_buffer);
+ params.add_uninitialized_single_output(GMutableSpan{base_type, value_buffer, 1});
+ output_buffers.append({value_or_field_type, value_or_field_buffer});
+ }
+
+ MFContextBuilder context;
+ fn.call(IndexRange(1), params, context);
+
+ for (const int i : output_buffers.index_range()) {
+ GMutablePointer buffer = output_buffers[i];
+ if (buffer.get() == nullptr) {
+ continue;
+ }
+ const DOutputSocket socket = node.output(i);
+ this->forward_output(socket, buffer, run_state);
+
+ OutputState &output_state = node_state.outputs[i];
+ output_state.has_been_computed = true;
+ }
+ }
+
+ void execute_unknown_node(const DNode node, NodeState &node_state, NodeTaskRunState *run_state)
{
LinearAllocator<> &allocator = local_allocators_.local();
for (const OutputSocketRef *socket : node->outputs()) {
@@ -1002,13 +1128,16 @@ class GeometryNodesEvaluator {
output_state.has_been_computed = true;
void *buffer = allocator.allocate(type->size(), type->alignment());
this->construct_default_value(*type, buffer);
- this->forward_output({node.context(), socket}, {*type, buffer});
+ this->forward_output({node.context(), socket}, {*type, buffer}, run_state);
}
}
- void node_task_postprocessing(const DNode node, NodeState &node_state, bool was_executed)
+ void node_task_postprocessing(const DNode node,
+ NodeState &node_state,
+ bool was_executed,
+ NodeTaskRunState *run_state)
{
- this->with_locked_node(node, node_state, [&](LockedNode &locked_node) {
+ this->with_locked_node(node, node_state, run_state, [&](LockedNode &locked_node) {
const bool node_has_finished = this->finish_node_if_possible(locked_node);
const bool reschedule_requested = node_state.schedule_state ==
NodeScheduleState::RunningAndRescheduled;
@@ -1089,10 +1218,9 @@ class GeometryNodesEvaluator {
/**
* Load the required input from the socket or trigger nodes to the left to compute the value.
- * When this function is called, the node will always be executed again eventually (either
- * immediately, or when all required inputs have been computed by other nodes).
+ * \return True when the node will be triggered by another node again when the value is computed.
*/
- void set_input_required(LockedNode &locked_node, const DInputSocket input_socket)
+ bool set_input_required(LockedNode &locked_node, const DInputSocket input_socket)
{
BLI_assert(locked_node.node == input_socket.node());
InputState &input_state = locked_node.node_state.inputs[input_socket->index()];
@@ -1100,19 +1228,16 @@ class GeometryNodesEvaluator {
/* Value set as unused cannot become used again. */
BLI_assert(input_state.usage != ValueUsage::Unused);
- if (input_state.usage == ValueUsage::Required) {
- /* The value is already required, but the node might expect to be evaluated again. */
- this->schedule_node(locked_node);
- /* Returning here also ensure that the code below is executed at most once per input. */
- return;
+ if (input_state.was_ready_for_execution) {
+ return false;
}
- input_state.usage = ValueUsage::Required;
- if (input_state.was_ready_for_execution) {
- /* The value was already ready, but the node might expect to be evaluated again. */
- this->schedule_node(locked_node);
- return;
+ if (input_state.usage == ValueUsage::Required) {
+ /* If the input was not ready for execution but is required, the node will be triggered again
+ * once the input has been computed. */
+ return true;
}
+ input_state.usage = ValueUsage::Required;
/* Count how many values still have to be added to this input until it is "complete". */
int missing_values = 0;
@@ -1127,9 +1252,7 @@ class GeometryNodesEvaluator {
}
}
if (missing_values == 0) {
- /* The input is fully available already, but the node might expect to be evaluated again. */
- this->schedule_node(locked_node);
- return;
+ return false;
}
/* Increase the total number of missing required inputs. This ensures that the node will be
* scheduled correctly when all inputs have been provided. */
@@ -1144,30 +1267,28 @@ class GeometryNodesEvaluator {
/* If there are no origin sockets, just load the value from the socket directly. */
this->load_unlinked_input_value(locked_node, input_socket, input_state, input_socket);
locked_node.node_state.missing_required_inputs -= 1;
- this->schedule_node(locked_node);
- return;
+ return false;
}
- bool will_be_triggered_by_other_node = false;
+ bool requested_from_other_node = false;
for (const DSocket &origin_socket : origin_sockets) {
if (origin_socket->is_input()) {
/* Load the value directly from the origin socket. In most cases this is an unlinked
* group input. */
this->load_unlinked_input_value(locked_node, input_socket, input_state, origin_socket);
locked_node.node_state.missing_required_inputs -= 1;
- this->schedule_node(locked_node);
}
else {
/* The value has not been computed yet, so when it will be forwarded by another node, this
* node will be triggered. */
- will_be_triggered_by_other_node = true;
-
+ requested_from_other_node = true;
locked_node.delayed_required_outputs.append(DOutputSocket(origin_socket));
}
}
/* If this node will be triggered by another node, we don't have to schedule it now. */
- if (!will_be_triggered_by_other_node) {
- this->schedule_node(locked_node);
+ if (requested_from_other_node) {
+ return true;
}
+ return false;
}
void set_input_unused(LockedNode &locked_node, const DInputSocket socket)
@@ -1203,13 +1324,13 @@ class GeometryNodesEvaluator {
});
}
- void send_output_required_notification(const DOutputSocket socket)
+ void send_output_required_notification(const DOutputSocket socket, NodeTaskRunState *run_state)
{
const DNode node = socket.node();
NodeState &node_state = this->get_node_state(node);
OutputState &output_state = node_state.outputs[socket->index()];
- this->with_locked_node(node, node_state, [&](LockedNode &locked_node) {
+ this->with_locked_node(node, node_state, run_state, [&](LockedNode &locked_node) {
if (output_state.output_usage == ValueUsage::Required) {
/* Output is marked as required already. So the node is scheduled already. */
return;
@@ -1221,13 +1342,13 @@ class GeometryNodesEvaluator {
});
}
- void send_output_unused_notification(const DOutputSocket socket)
+ void send_output_unused_notification(const DOutputSocket socket, NodeTaskRunState *run_state)
{
const DNode node = socket.node();
NodeState &node_state = this->get_node_state(node);
OutputState &output_state = node_state.outputs[socket->index()];
- this->with_locked_node(node, node_state, [&](LockedNode &locked_node) {
+ this->with_locked_node(node, node_state, run_state, [&](LockedNode &locked_node) {
output_state.potential_users -= 1;
if (output_state.potential_users == 0) {
/* The socket might be required even though the output is not used by other sockets. That
@@ -1253,8 +1374,11 @@ class GeometryNodesEvaluator {
/**
* Moves a newly computed value from an output socket to all the inputs that might need it.
+ * Takes ownership of the value and destructs if it is unused.
*/
- void forward_output(const DOutputSocket from_socket, GMutablePointer value_to_forward)
+ void forward_output(const DOutputSocket from_socket,
+ GMutablePointer value_to_forward,
+ NodeTaskRunState *run_state)
{
BLI_assert(value_to_forward.get() != nullptr);
@@ -1307,12 +1431,12 @@ class GeometryNodesEvaluator {
}
else {
/* The value has been converted. */
- this->add_value_to_input_socket(to_socket, from_socket, current_value);
+ this->add_value_to_input_socket(to_socket, from_socket, current_value, run_state);
}
});
this->log_socket_value(log_original_value_sockets, value_to_forward);
this->forward_to_sockets_with_same_type(
- allocator, forward_original_value_sockets, value_to_forward, from_socket);
+ allocator, forward_original_value_sockets, value_to_forward, from_socket, run_state);
}
bool should_forward_to_socket(const DInputSocket socket)
@@ -1334,7 +1458,8 @@ class GeometryNodesEvaluator {
void forward_to_sockets_with_same_type(LinearAllocator<> &allocator,
Span<DInputSocket> to_sockets,
GMutablePointer value_to_forward,
- const DOutputSocket from_socket)
+ const DOutputSocket from_socket,
+ NodeTaskRunState *run_state)
{
if (to_sockets.is_empty()) {
/* Value is not used anymore, so it can be destructed. */
@@ -1343,7 +1468,7 @@ class GeometryNodesEvaluator {
else if (to_sockets.size() == 1) {
/* Value is only used by one input socket, no need to copy it. */
const DInputSocket to_socket = to_sockets[0];
- this->add_value_to_input_socket(to_socket, from_socket, value_to_forward);
+ this->add_value_to_input_socket(to_socket, from_socket, value_to_forward, run_state);
}
else {
/* Multiple inputs use the value, make a copy for every input except for one. */
@@ -1353,17 +1478,18 @@ class GeometryNodesEvaluator {
for (const DInputSocket &to_socket : to_sockets.drop_front(1)) {
void *buffer = allocator.allocate(type.size(), type.alignment());
type.copy_construct(value_to_forward.get(), buffer);
- this->add_value_to_input_socket(to_socket, from_socket, {type, buffer});
+ this->add_value_to_input_socket(to_socket, from_socket, {type, buffer}, run_state);
}
/* Forward the original value to one of the targets. */
const DInputSocket to_socket = to_sockets[0];
- this->add_value_to_input_socket(to_socket, from_socket, value_to_forward);
+ this->add_value_to_input_socket(to_socket, from_socket, value_to_forward, run_state);
}
}
void add_value_to_input_socket(const DInputSocket socket,
const DOutputSocket origin,
- GMutablePointer value)
+ GMutablePointer value,
+ NodeTaskRunState *run_state)
{
BLI_assert(socket->is_available());
@@ -1371,7 +1497,7 @@ class GeometryNodesEvaluator {
NodeState &node_state = this->get_node_state(node);
InputState &input_state = node_state.inputs[socket->index()];
- this->with_locked_node(node, node_state, [&](LockedNode &locked_node) {
+ this->with_locked_node(node, node_state, run_state, [&](LockedNode &locked_node) {
if (socket->is_multi_input_socket()) {
/* Add a new value to the multi-input. */
MultiInputValue &multi_value = *input_state.value.multi;
@@ -1398,6 +1524,14 @@ class GeometryNodesEvaluator {
});
}
+ /**
+ * Loads the value of a socket that is not computed by another node. Note that the socket may
+ * still be linked to e.g. a Group Input node, but the socket on the outside is not connected to
+ * anything.
+ *
+ * \param input_socket: The socket of the node that wants to use the value.
+ * \param origin_socket: The socket that we want to load the value from.
+ */
void load_unlinked_input_value(LockedNode &locked_node,
const DInputSocket input_socket,
InputState &input_state,
@@ -1417,7 +1551,15 @@ class GeometryNodesEvaluator {
else {
SingleInputValue &single_value = *input_state.value.single;
single_value.value = value.get();
- this->log_socket_value({input_socket}, value);
+ Vector<DSocket> sockets_to_log_to = {input_socket};
+ if (origin_socket != input_socket) {
+ /* This might log the socket value for the #origin_socket more than once, but this is
+ * handled by the logging system gracefully. */
+ sockets_to_log_to.append(origin_socket);
+ }
+ /* TODO: Log to the intermediate sockets between the group input and where the value is
+ * actually used as well. */
+ this->log_socket_value(sockets_to_log_to, value);
}
}
@@ -1466,19 +1608,28 @@ class GeometryNodesEvaluator {
from_type.copy_construct(from_value, to_value);
return;
}
-
- const FieldCPPType *from_field_type = dynamic_cast<const FieldCPPType *>(&from_type);
- const FieldCPPType *to_field_type = dynamic_cast<const FieldCPPType *>(&to_type);
+ const ValueOrFieldCPPType *from_field_type = dynamic_cast<const ValueOrFieldCPPType *>(
+ &from_type);
+ const ValueOrFieldCPPType *to_field_type = dynamic_cast<const ValueOrFieldCPPType *>(&to_type);
if (from_field_type != nullptr && to_field_type != nullptr) {
- const CPPType &from_base_type = from_field_type->field_type();
- const CPPType &to_base_type = to_field_type->field_type();
+ const CPPType &from_base_type = from_field_type->base_type();
+ const CPPType &to_base_type = to_field_type->base_type();
if (conversions_.is_convertible(from_base_type, to_base_type)) {
- const MultiFunction &fn = *conversions_.get_conversion_multi_function(
- MFDataType::ForSingle(from_base_type), MFDataType::ForSingle(to_base_type));
- const GField &from_field = *(const GField *)from_value;
- auto operation = std::make_shared<fn::FieldOperation>(fn, Vector<GField>{from_field});
- new (to_value) GField(std::move(operation), 0);
+ if (from_field_type->is_field(from_value)) {
+ const GField &from_field = *from_field_type->get_field_ptr(from_value);
+ const MultiFunction &fn = *conversions_.get_conversion_multi_function(
+ MFDataType::ForSingle(from_base_type), MFDataType::ForSingle(to_base_type));
+ auto operation = std::make_shared<fn::FieldOperation>(fn, Vector<GField>{from_field});
+ to_field_type->construct_from_field(to_value, GField(std::move(operation), 0));
+ }
+ else {
+ to_field_type->default_construct(to_value);
+ const void *from_value_ptr = from_field_type->get_value_ptr(from_value);
+ void *to_value_ptr = to_field_type->get_value_ptr(to_value);
+ conversions_.get_conversion_functions(from_base_type, to_base_type)
+ ->convert_single_to_initialized(from_value_ptr, to_value_ptr);
+ }
return;
}
}
@@ -1494,14 +1645,6 @@ class GeometryNodesEvaluator {
void construct_default_value(const CPPType &type, void *r_value)
{
- if (const FieldCPPType *field_cpp_type = dynamic_cast<const FieldCPPType *>(&type)) {
- const CPPType &base_type = field_cpp_type->field_type();
- auto constant_fn = std::make_unique<fn::CustomMF_GenericConstant>(
- base_type, base_type.default_value(), false);
- auto operation = std::make_shared<fn::FieldOperation>(std::move(constant_fn));
- new (r_value) GField(std::move(operation), 0);
- return;
- }
type.copy_construct(type.default_value(), r_value);
}
@@ -1533,10 +1676,21 @@ class GeometryNodesEvaluator {
params_.geo_logger->local().log_value_for_sockets(sockets, value);
}
+ void log_debug_message(DNode node, std::string message)
+ {
+ if (params_.geo_logger == nullptr) {
+ return;
+ }
+ params_.geo_logger->local().log_debug_message(node, std::move(message));
+ }
+
/* In most cases when `NodeState` is accessed, the node has to be locked first to avoid race
* conditions. */
template<typename Function>
- void with_locked_node(const DNode node, NodeState &node_state, const Function &function)
+ void with_locked_node(const DNode node,
+ NodeState &node_state,
+ NodeTaskRunState *run_state,
+ const Function &function)
{
LockedNode locked_node{node, node_state};
@@ -1549,21 +1703,32 @@ class GeometryNodesEvaluator {
/* Then send notifications to the other nodes after the node state is unlocked. This avoids
* locking two nodes at the same time on this thread and helps to prevent deadlocks. */
for (const DOutputSocket &socket : locked_node.delayed_required_outputs) {
- this->send_output_required_notification(socket);
+ this->send_output_required_notification(socket, run_state);
}
for (const DOutputSocket &socket : locked_node.delayed_unused_outputs) {
- this->send_output_unused_notification(socket);
- }
- for (const DNode &node : locked_node.delayed_scheduled_nodes) {
- this->add_node_to_task_pool(node);
+ this->send_output_unused_notification(socket, run_state);
+ }
+ for (const DNode &node_to_schedule : locked_node.delayed_scheduled_nodes) {
+ if (run_state != nullptr && !run_state->next_node_to_run) {
+ /* Execute the node on the same thread after the current node finished. */
+ /* Currently, this assumes that it is always best to run the first node that is scheduled
+ * on the same thread. That is usually correct, because the geometry socket which carries
+ * the most data usually comes first in nodes. */
+ run_state->next_node_to_run = node_to_schedule;
+ }
+ else {
+ /* Push the node to the task pool so that another thread can start working on it. */
+ this->add_node_to_task_pool(node_to_schedule);
+ }
}
}
};
NodeParamsProvider::NodeParamsProvider(GeometryNodesEvaluator &evaluator,
DNode dnode,
- NodeState &node_state)
- : evaluator_(evaluator), node_state_(node_state)
+ NodeState &node_state,
+ NodeTaskRunState *run_state)
+ : evaluator_(evaluator), node_state_(node_state), run_state_(run_state)
{
this->dnode = dnode;
this->self_object = evaluator.params_.self_object;
@@ -1671,7 +1836,7 @@ void NodeParamsProvider::set_output(StringRef identifier, GMutablePointer value)
OutputState &output_state = node_state_.outputs[socket->index()];
BLI_assert(!output_state.has_been_computed);
- evaluator_.forward_output(socket, value);
+ evaluator_.forward_output(socket, value, run_state_);
output_state.has_been_computed = true;
}
@@ -1685,8 +1850,12 @@ bool NodeParamsProvider::lazy_require_input(StringRef identifier)
if (input_state.was_ready_for_execution) {
return false;
}
- evaluator_.with_locked_node(this->dnode, node_state_, [&](LockedNode &locked_node) {
- evaluator_.set_input_required(locked_node, socket);
+ evaluator_.with_locked_node(this->dnode, node_state_, run_state_, [&](LockedNode &locked_node) {
+ if (!evaluator_.set_input_required(locked_node, socket)) {
+ /* Schedule the currently executed node again because the value is available now but was not
+ * ready for the current execution. */
+ evaluator_.schedule_node(locked_node);
+ }
});
return true;
}
@@ -1696,7 +1865,7 @@ void NodeParamsProvider::set_input_unused(StringRef identifier)
const DInputSocket socket = this->dnode.input_by_identifier(identifier);
BLI_assert(socket);
- evaluator_.with_locked_node(this->dnode, node_state_, [&](LockedNode &locked_node) {
+ evaluator_.with_locked_node(this->dnode, node_state_, run_state_, [&](LockedNode &locked_node) {
evaluator_.set_input_unused(locked_node, socket);
});
}
@@ -1726,6 +1895,29 @@ bool NodeParamsProvider::lazy_output_is_required(StringRef identifier) const
return output_state.output_usage_for_execution == ValueUsage::Required;
}
+void NodeParamsProvider::set_default_remaining_outputs()
+{
+ LinearAllocator<> &allocator = evaluator_.local_allocators_.local();
+
+ for (const int i : this->dnode->outputs().index_range()) {
+ OutputState &output_state = node_state_.outputs[i];
+ if (output_state.has_been_computed) {
+ continue;
+ }
+ if (output_state.output_usage_for_execution == ValueUsage::Unused) {
+ continue;
+ }
+
+ const DOutputSocket socket = this->dnode.output(i);
+ const CPPType *type = get_socket_cpp_type(socket);
+ BLI_assert(type != nullptr);
+ void *buffer = allocator.allocate(type->size(), type->alignment());
+ type->copy_construct(type->default_value(), buffer);
+ evaluator_.forward_output(socket, {type, buffer}, run_state_);
+ output_state.has_been_computed = true;
+ }
+}
+
void evaluate_geometry_nodes(GeometryNodesEvaluationParams &params)
{
GeometryNodesEvaluator evaluator{params};
diff --git a/source/blender/modifiers/intern/MOD_solidify_extrude.c b/source/blender/modifiers/intern/MOD_solidify_extrude.c
index 54a508ff5e2..20d65b9d9f8 100644
--- a/source/blender/modifiers/intern/MOD_solidify_extrude.c
+++ b/source/blender/modifiers/intern/MOD_solidify_extrude.c
@@ -183,6 +183,7 @@ static void mesh_calc_hq_normal(Mesh *mesh, float (*poly_nors)[3], float (*r_ver
/* -------------------------------------------------------------------- */
/** \name Main Solidify Function
* \{ */
+
/* NOLINTNEXTLINE: readability-function-size */
Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
diff --git a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c
index d4aaefcfe05..997f5943060 100644
--- a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c
+++ b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c
@@ -74,6 +74,7 @@ static float angle_signed_on_axis_normalized_v3v3_v3(const float n[3],
static float clamp_nonzero(const float value, const float epsilon)
{
BLI_assert(!(epsilon < 0.0f));
+ /* Return closest value with `abs(value) >= epsilon`. */
if (value < 0.0f) {
return min_ff(value, -epsilon);
}
@@ -171,15 +172,22 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
float(*poly_nors)[3] = NULL;
+ /* #ofs_front and #ofs_back are the offset from the original
+ * surface along the normal, where #oft_front is along the positive
+ * and #oft_back is along the negative normal. */
const float ofs_front = (smd->offset_fac + 1.0f) * 0.5f * smd->offset;
const float ofs_back = ofs_front - smd->offset * smd->offset_fac;
- const float ofs_front_clamped = clamp_nonzero(smd->offset > 0 ? ofs_front : ofs_back, 1e-5f);
- const float ofs_back_clamped = clamp_nonzero(smd->offset > 0 ? ofs_back : ofs_front, 1e-5f);
+ /* #ofs_front_clamped and #ofs_back_clamped are the same as
+ * #ofs_front and #ofs_back, but never zero. */
+ const float ofs_front_clamped = clamp_nonzero(ofs_front, 1e-5f);
+ const float ofs_back_clamped = clamp_nonzero(ofs_back, 1e-5f);
const float offset_fac_vg = smd->offset_fac_vg;
const float offset_fac_vg_inv = 1.0f - smd->offset_fac_vg;
const float offset = fabsf(smd->offset) * smd->offset_clamp;
const bool do_angle_clamp = smd->flag & MOD_SOLIDIFY_OFFSET_ANGLE_CLAMP;
- const bool do_flip = (smd->flag & MOD_SOLIDIFY_FLIP) != 0;
+ /* #do_flip, flips the normals of the result. This is inverted if negative thickness
+ * is used, since simple solidify with negative thickness keeps the faces facing outside. */
+ const bool do_flip = ((smd->flag & MOD_SOLIDIFY_FLIP) != 0) == (smd->offset > 0);
const bool do_rim = smd->flag & MOD_SOLIDIFY_RIM;
const bool do_shell = ((smd->flag & MOD_SOLIDIFY_RIM) && (smd->flag & MOD_SOLIDIFY_NOSHELL)) ==
0;
diff --git a/source/blender/modifiers/intern/MOD_ui_common.c b/source/blender/modifiers/intern/MOD_ui_common.c
index 9937a2342c3..fc1f6d33b25 100644
--- a/source/blender/modifiers/intern/MOD_ui_common.c
+++ b/source/blender/modifiers/intern/MOD_ui_common.c
@@ -100,9 +100,6 @@ static void set_modifier_expand_flag(const bContext *UNUSED(C), Panel *panel, sh
/** \name Modifier Panel Layouts
* \{ */
-/**
- * Draw modifier error message.
- */
void modifier_panel_end(uiLayout *layout, PointerRNA *ptr)
{
ModifierData *md = ptr->data;
@@ -132,14 +129,11 @@ PointerRNA *modifier_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_
uiBlock *block = uiLayoutGetBlock(panel->layout);
UI_block_lock_set(block, ID_IS_LINKED((Object *)ptr->owner_id), ERROR_LIBDATA_MESSAGE);
- uiLayoutSetContextPointer(panel->layout, "modifier", ptr);
+ UI_panel_context_pointer_set(panel, "modifier", ptr);
return ptr;
}
-/**
- * Helper function for modifier layouts to draw vertex group settings.
- */
void modifier_vgroup_ui(uiLayout *layout,
PointerRNA *ptr,
PointerRNA *ob_ptr,
@@ -304,7 +298,7 @@ static void modifier_panel_header(const bContext *C, Panel *panel)
ModifierData *md = (ModifierData *)ptr->data;
Object *ob = (Object *)ptr->owner_id;
- uiLayoutSetContextPointer(panel->layout, "modifier", ptr);
+ UI_panel_context_pointer_set(panel, "modifier", ptr);
const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
Scene *scene = CTX_data_scene(C);
@@ -429,9 +423,6 @@ static void modifier_panel_header(const bContext *C, Panel *panel)
/** \name Modifier Registration Helpers
* \{ */
-/**
- * Create a panel in the context's region
- */
PanelType *modifier_panel_register(ARegionType *region_type, ModifierType type, PanelDrawFn draw)
{
PanelType *panel_type = MEM_callocN(sizeof(PanelType), __func__);
@@ -458,12 +449,6 @@ PanelType *modifier_panel_register(ARegionType *region_type, ModifierType type,
return panel_type;
}
-/**
- * Add a child panel to the parent.
- *
- * \note To create the panel type's idname, it appends the \a name argument to the \a parent's
- * idname.
- */
PanelType *modifier_subpanel_register(ARegionType *region_type,
const char *name,
const char *label,
diff --git a/source/blender/modifiers/intern/MOD_ui_common.h b/source/blender/modifiers/intern/MOD_ui_common.h
index e7f801049b8..9662b181013 100644
--- a/source/blender/modifiers/intern/MOD_ui_common.h
+++ b/source/blender/modifiers/intern/MOD_ui_common.h
@@ -37,6 +37,9 @@ typedef void (*PanelDrawFn)(const bContext *, struct Panel *);
void modifier_panel_buttons(const struct bContext *C, struct Panel *panel);
+/**
+ * Helper function for modifier layouts to draw vertex group settings.
+ */
void modifier_vgroup_ui(struct uiLayout *layout,
struct PointerRNA *ptr,
struct PointerRNA *ob_ptr,
@@ -44,15 +47,27 @@ void modifier_vgroup_ui(struct uiLayout *layout,
const char *invert_vgroup_prop,
const char *text);
+/**
+ * Draw modifier error message.
+ */
void modifier_panel_end(struct uiLayout *layout, PointerRNA *ptr);
struct PointerRNA *modifier_panel_get_property_pointers(struct Panel *panel,
struct PointerRNA *r_ob_ptr);
+/**
+ * Create a panel in the context's region
+ */
struct PanelType *modifier_panel_register(struct ARegionType *region_type,
ModifierType type,
PanelDrawFn draw);
+/**
+ * Add a child panel to the parent.
+ *
+ * \note To create the panel type's idname, it appends the \a name argument to the \a parent's
+ * idname.
+ */
struct PanelType *modifier_subpanel_register(struct ARegionType *region_type,
const char *name,
const char *label,
diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c
index d57e92b4b35..16ef65f7838 100644
--- a/source/blender/modifiers/intern/MOD_util.c
+++ b/source/blender/modifiers/intern/MOD_util.c
@@ -72,7 +72,6 @@ void MOD_init_texture(MappingInfoModifierData *dmd, const ModifierEvalContext *c
}
/* TODO: to be renamed to get_texture_coords once we are done with moving modifiers to Mesh. */
-/** \param cos: may be NULL, in which case we use directly mesh vertices' coordinates. */
void MOD_get_texture_coords(MappingInfoModifierData *dmd,
const ModifierEvalContext *UNUSED(ctx),
Object *ob,
@@ -182,7 +181,6 @@ void MOD_previous_vcos_store(ModifierData *md, const float (*vert_coords)[3])
/* lattice/mesh modifier too */
}
-/* returns a mesh if mesh == NULL, for deforming modifiers that need it */
Mesh *MOD_deform_mesh_eval_get(Object *ob,
struct BMEditMesh *em,
Mesh *mesh,
@@ -219,8 +217,7 @@ Mesh *MOD_deform_mesh_eval_get(Object *ob,
}
if (use_orco) {
- CustomData_add_layer(
- &mesh->vdata, CD_ORCO, CD_ASSIGN, BKE_mesh_orco_verts_get(ob), mesh->totvert);
+ BKE_mesh_orco_ensure(ob, mesh);
}
}
else if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF)) {
@@ -289,7 +286,6 @@ void MOD_depsgraph_update_object_bone_relation(struct DepsNodeHandle *node,
}
}
-/* only called by BKE_modifier.h/modifier.c */
void modifier_type_init(ModifierTypeInfo *types[])
{
#define INIT_TYPE(typeName) (types[eModifierType_##typeName] = &modifierType_##typeName)
diff --git a/source/blender/modifiers/intern/MOD_util.h b/source/blender/modifiers/intern/MOD_util.h
index a3db848874e..a6fc2749e71 100644
--- a/source/blender/modifiers/intern/MOD_util.h
+++ b/source/blender/modifiers/intern/MOD_util.h
@@ -32,6 +32,9 @@ struct ModifierEvalContext;
struct Object;
void MOD_init_texture(struct MappingInfoModifierData *dmd, const struct ModifierEvalContext *ctx);
+/**
+ * \param cos: may be NULL, in which case we use directly mesh vertices' coordinates.
+ */
void MOD_get_texture_coords(struct MappingInfoModifierData *dmd,
const struct ModifierEvalContext *ctx,
struct Object *ob,
@@ -41,6 +44,9 @@ void MOD_get_texture_coords(struct MappingInfoModifierData *dmd,
void MOD_previous_vcos_store(struct ModifierData *md, const float (*vert_coords)[3]);
+/**
+ * \returns a mesh if mesh == NULL, for deforming modifiers that need it.
+ */
struct Mesh *MOD_deform_mesh_eval_get(struct Object *ob,
struct BMEditMesh *em,
struct Mesh *mesh,
diff --git a/source/blender/modifiers/intern/MOD_weightvg_util.c b/source/blender/modifiers/intern/MOD_weightvg_util.c
index e403051d1be..cd9e5162527 100644
--- a/source/blender/modifiers/intern/MOD_weightvg_util.c
+++ b/source/blender/modifiers/intern/MOD_weightvg_util.c
@@ -57,12 +57,6 @@
#include "MOD_weightvg_util.h"
#include "RE_texture.h" /* Texture masking. */
-/* Maps new_w weights in place, using either one of the predefined functions, or a custom curve.
- * Return values are in new_w.
- * If indices is not NULL, it must be a table of same length as org_w and new_w,
- * mapping to the real vertex index (in case the weight tables do not cover the whole vertices...).
- * cmap might be NULL, in which case curve mapping mode will return unmodified data.
- */
void weightvg_do_map(
int num, float *new_w, short falloff_type, const bool do_invert, CurveMapping *cmap, RNG *rng)
{
@@ -125,13 +119,6 @@ void weightvg_do_map(
}
}
-/* Applies new_w weights to org_w ones, using either a texture, vgroup or constant value as factor.
- * Return values are in org_w.
- * If indices is not NULL, it must be a table of same length as org_w and new_w,
- * mapping to the real vertex index (in case the weight tables do not cover the whole vertices...).
- * XXX The standard "factor" value is assumed in [0.0, 1.0] range.
- * Else, weird results might appear.
- */
void weightvg_do_mask(const ModifierEvalContext *ctx,
const int num,
const int *indices,
@@ -267,12 +254,6 @@ void weightvg_do_mask(const ModifierEvalContext *ctx,
}
}
-/* Applies weights to given vgroup (defgroup), and optionally add/remove vertices from the group.
- * If dws is not NULL, it must be an array of MDeformWeight pointers of same length as weights (and
- * defgrp_idx can then have any value).
- * If indices is not NULL, it must be an array of same length as weights, mapping to the real
- * vertex index (in case the weight array does not cover the whole vertices...).
- */
void weightvg_update_vg(MDeformVert *dvert,
int defgrp_idx,
MDeformWeight **dws,
@@ -340,8 +321,6 @@ void weightvg_update_vg(MDeformVert *dvert,
}
}
-/* Common vertex weight mask interface elements for the modifier panels.
- */
void weightvg_ui_common(const bContext *C, PointerRNA *ob_ptr, PointerRNA *ptr, uiLayout *layout)
{
PointerRNA mask_texture_ptr = RNA_pointer_get(ptr, "mask_texture");
diff --git a/source/blender/modifiers/intern/MOD_weightvg_util.h b/source/blender/modifiers/intern/MOD_weightvg_util.h
index 796603289ca..00aecd7342c 100644
--- a/source/blender/modifiers/intern/MOD_weightvg_util.h
+++ b/source/blender/modifiers/intern/MOD_weightvg_util.h
@@ -46,13 +46,21 @@ struct uiLayout;
* Util functions. *
**************************************/
-/* We cannot divide by zero (what a surprise...).
- * So if -MOD_WEIGHTVGROUP_DIVMODE_ZEROFLOOR < weightf < MOD_WEIGHTVGROUP_DIVMODE_ZEROFLOOR,
+/**
+ * We cannot divide by zero (what a surprise...).
+ * So if `-MOD_WEIGHTVGROUP_DIVMODE_ZEROFLOOR < weightf < MOD_WEIGHTVGROUP_DIVMODE_ZEROFLOOR`,
* we clamp weightf to this value (or its negative version).
* Also used to avoid null power factor.
*/
#define MOD_WVG_ZEROFLOOR 1.0e-32f
+/**
+ * Maps new_w weights in place, using either one of the predefined functions, or a custom curve.
+ * Return values are in new_w.
+ * If indices is not NULL, it must be a table of same length as org_w and new_w,
+ * mapping to the real vertex index (in case the weight tables do not cover the whole vertices...).
+ * cmap might be NULL, in which case curve mapping mode will return unmodified data.
+ */
void weightvg_do_map(int num,
float *new_w,
short falloff_type,
@@ -60,6 +68,14 @@ void weightvg_do_map(int num,
struct CurveMapping *cmap,
struct RNG *rng);
+/**
+ * Applies new_w weights to org_w ones, using either a texture, vgroup or constant value as factor.
+ * Return values are in org_w.
+ * If indices is not NULL, it must be a table of same length as org_w and new_w,
+ * mapping to the real vertex index (in case the weight tables do not cover the whole vertices...).
+ * XXX The standard "factor" value is assumed in [0.0, 1.0] range.
+ * Else, weird results might appear.
+ */
void weightvg_do_mask(const ModifierEvalContext *ctx,
const int num,
const int *indices,
@@ -78,6 +94,13 @@ void weightvg_do_mask(const ModifierEvalContext *ctx,
const char *tex_uvlayer_name,
const bool invert_vgroup_mask);
+/**
+ * Applies weights to given vgroup (defgroup), and optionally add/remove vertices from the group.
+ * If dws is not NULL, it must be an array of #MDeformWeight pointers of same length as weights
+ * (and defgrp_idx can then have any value).
+ * If indices is not NULL, it must be an array of same length as weights, mapping to the real
+ * vertex index (in case the weight array does not cover the whole vertices...).
+ */
void weightvg_update_vg(struct MDeformVert *dvert,
int defgrp_idx,
struct MDeformWeight **dws,
@@ -90,4 +113,7 @@ void weightvg_update_vg(struct MDeformVert *dvert,
const float rem_thresh,
const bool do_normalize);
+/**
+ * Common vertex weight mask interface elements for the modifier panels.
+ */
void weightvg_ui_common(const bContext *C, PointerRNA *ob_ptr, PointerRNA *ptr, uiLayout *layout);
diff --git a/source/blender/modifiers/intern/MOD_weld.c b/source/blender/modifiers/intern/MOD_weld.c
index 503297d5985..f842bef3298 100644
--- a/source/blender/modifiers/intern/MOD_weld.c
+++ b/source/blender/modifiers/intern/MOD_weld.c
@@ -363,7 +363,9 @@ static void weld_assert_poly_len(const WeldPoly *wp, const WeldLoop *wloop)
uint max_len = wp->loop_end - wp->loop_start + 1;
BLI_assert(len <= max_len);
}
-#endif
+
+#endif /* USE_WELD_DEBUG */
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index e256ebcff56..5f61d13a3af 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -19,6 +19,7 @@
# ***** END GPL LICENSE BLOCK *****
add_subdirectory(geometry)
+add_subdirectory(shader)
set(INC
.
@@ -44,7 +45,6 @@ set(INC
../windowmanager
../../../intern/glew-mx
../../../intern/guardedalloc
- ../../../intern/sky/include
)
@@ -141,7 +141,7 @@ set(SRC
function/nodes/node_fn_align_euler_to_vector.cc
function/nodes/node_fn_boolean_math.cc
- function/nodes/node_fn_float_compare.cc
+ function/nodes/node_fn_compare.cc
function/nodes/node_fn_float_to_int.cc
function/nodes/node_fn_input_bool.cc
function/nodes/node_fn_input_color.cc
@@ -157,99 +157,6 @@ set(SRC
function/nodes/node_fn_value_to_string.cc
function/node_function_util.cc
- shader/nodes/node_shader_add_shader.c
- shader/nodes/node_shader_ambient_occlusion.c
- shader/nodes/node_shader_attribute.c
- shader/nodes/node_shader_background.c
- shader/nodes/node_shader_bevel.c
- shader/nodes/node_shader_blackbody.c
- shader/nodes/node_shader_brightness.c
- shader/nodes/node_shader_bsdf_anisotropic.c
- shader/nodes/node_shader_bsdf_diffuse.c
- shader/nodes/node_shader_bsdf_glass.c
- shader/nodes/node_shader_bsdf_glossy.c
- shader/nodes/node_shader_bsdf_hair.c
- shader/nodes/node_shader_bsdf_hair_principled.c
- shader/nodes/node_shader_bsdf_principled.c
- shader/nodes/node_shader_bsdf_refraction.c
- shader/nodes/node_shader_bsdf_toon.c
- shader/nodes/node_shader_bsdf_translucent.c
- shader/nodes/node_shader_bsdf_transparent.c
- shader/nodes/node_shader_bsdf_velvet.c
- shader/nodes/node_shader_bump.c
- shader/nodes/node_shader_camera.c
- shader/nodes/node_shader_clamp.cc
- shader/nodes/node_shader_common.c
- shader/nodes/node_shader_curves.cc
- shader/nodes/node_shader_displacement.c
- shader/nodes/node_shader_eevee_specular.c
- shader/nodes/node_shader_emission.c
- shader/nodes/node_shader_fresnel.c
- shader/nodes/node_shader_gamma.c
- shader/nodes/node_shader_geometry.c
- shader/nodes/node_shader_hair_info.c
- shader/nodes/node_shader_holdout.c
- shader/nodes/node_shader_hueSatVal.c
- shader/nodes/node_shader_ies_light.c
- shader/nodes/node_shader_invert.c
- shader/nodes/node_shader_layer_weight.c
- shader/nodes/node_shader_light_falloff.c
- shader/nodes/node_shader_light_path.c
- shader/nodes/node_shader_map_range.cc
- shader/nodes/node_shader_mapping.c
- shader/nodes/node_shader_math.cc
- shader/nodes/node_shader_mixRgb.cc
- shader/nodes/node_shader_mix_shader.c
- shader/nodes/node_shader_normal.c
- shader/nodes/node_shader_normal_map.c
- shader/nodes/node_shader_object_info.c
- shader/nodes/node_shader_output_aov.c
- shader/nodes/node_shader_output_light.c
- shader/nodes/node_shader_output_linestyle.c
- shader/nodes/node_shader_output_material.c
- shader/nodes/node_shader_output_world.c
- shader/nodes/node_shader_particle_info.c
- shader/nodes/node_shader_rgb.c
- shader/nodes/node_shader_script.c
- shader/nodes/node_shader_sepcombHSV.c
- shader/nodes/node_shader_sepcombRGB.cc
- shader/nodes/node_shader_sepcombXYZ.cc
- shader/nodes/node_shader_shaderToRgb.c
- shader/nodes/node_shader_squeeze.c
- shader/nodes/node_shader_subsurface_scattering.c
- shader/nodes/node_shader_tangent.c
- shader/nodes/node_shader_tex_brick.cc
- shader/nodes/node_shader_tex_checker.cc
- shader/nodes/node_shader_tex_coord.c
- shader/nodes/node_shader_tex_environment.c
- shader/nodes/node_shader_tex_gradient.cc
- shader/nodes/node_shader_tex_image.cc
- shader/nodes/node_shader_tex_magic.cc
- shader/nodes/node_shader_tex_musgrave.cc
- shader/nodes/node_shader_tex_noise.cc
- shader/nodes/node_shader_tex_pointdensity.c
- shader/nodes/node_shader_tex_sky.c
- shader/nodes/node_shader_tex_voronoi.cc
- shader/nodes/node_shader_tex_wave.cc
- shader/nodes/node_shader_tex_white_noise.cc
- shader/nodes/node_shader_uvAlongStroke.c
- shader/nodes/node_shader_uvmap.c
- shader/nodes/node_shader_valToRgb.cc
- shader/nodes/node_shader_value.cc
- shader/nodes/node_shader_vectTransform.c
- shader/nodes/node_shader_vector_displacement.c
- shader/nodes/node_shader_vector_math.cc
- shader/nodes/node_shader_vector_rotate.cc
- shader/nodes/node_shader_vertex_color.c
- shader/nodes/node_shader_volume_absorption.c
- shader/nodes/node_shader_volume_info.c
- shader/nodes/node_shader_volume_principled.c
- shader/nodes/node_shader_volume_scatter.c
- shader/nodes/node_shader_wavelength.c
- shader/nodes/node_shader_wireframe.c
- shader/node_shader_tree.c
- shader/node_shader_util.c
-
texture/nodes/node_texture_at.c
texture/nodes/node_texture_bricks.c
texture/nodes/node_texture_checker.c
@@ -277,7 +184,6 @@ set(SRC
texture/node_texture_util.c
intern/derived_node_tree.cc
- intern/extern_implementations.cc
intern/geometry_nodes_eval_log.cc
intern/math_functions.cc
intern/node_common.cc
@@ -287,13 +193,12 @@ set(SRC
intern/node_multi_function.cc
intern/node_socket.cc
intern/node_socket_declarations.cc
+ intern/socket_search_link.cc
intern/node_tree_ref.cc
intern/node_util.c
- intern/type_conversions.cc
composite/node_composite_util.hh
function/node_function_util.hh
- shader/node_shader_util.h
texture/node_texture_util.h
NOD_common.h
@@ -310,10 +215,10 @@ set(SRC
NOD_shader.h
NOD_socket.h
NOD_socket_declarations.hh
+ NOD_socket_search_link.hh
NOD_socket_declarations_geometry.hh
NOD_static_types.h
NOD_texture.h
- NOD_type_conversions.hh
intern/node_common.h
intern/node_exec.h
intern/node_util.h
@@ -322,8 +227,8 @@ set(SRC
set(LIB
bf_bmesh
bf_functions
- bf_intern_sky
bf_nodes_geometry
+ bf_nodes_shader
)
if(WITH_BULLET)
diff --git a/source/blender/nodes/NOD_common.h b/source/blender/nodes/NOD_common.h
index fa979bb4799..e488352170b 100644
--- a/source/blender/nodes/NOD_common.h
+++ b/source/blender/nodes/NOD_common.h
@@ -35,9 +35,11 @@ void register_node_type_reroute(void);
void register_node_type_group_input(void);
void register_node_type_group_output(void);
-/* internal functions for editor */
+/* Internal functions for editor. */
+
struct bNodeSocket *node_group_find_input_socket(struct bNode *groupnode, const char *identifier);
struct bNodeSocket *node_group_find_output_socket(struct bNode *groupnode, const char *identifier);
+/** Make sure all group node in ntree, which use ngroup, are sync'd. */
void node_group_update(struct bNodeTree *ntree, struct bNode *node);
struct bNodeSocket *node_group_input_find_socket(struct bNode *node, const char *identifier);
diff --git a/source/blender/nodes/NOD_derived_node_tree.hh b/source/blender/nodes/NOD_derived_node_tree.hh
index 895f7ef6d5b..dc619deb5d2 100644
--- a/source/blender/nodes/NOD_derived_node_tree.hh
+++ b/source/blender/nodes/NOD_derived_node_tree.hh
@@ -72,8 +72,10 @@ class DTreeContext {
bool is_root() const;
};
-/* A (nullable) reference to a node and the context it is in. It is unique within an entire nested
- * node group hierarchy. This type is small and can be passed around by value. */
+/**
+ * A (nullable) reference to a node and the context it is in. It is unique within an entire nested
+ * node group hierarchy. This type is small and can be passed around by value.
+ */
class DNode {
private:
const DTreeContext *context_ = nullptr;
@@ -100,11 +102,13 @@ class DNode {
DOutputSocket output_by_identifier(StringRef identifier) const;
};
-/* A (nullable) reference to a socket and the context it is in. It is unique within an entire
+/**
+ * A (nullable) reference to a socket and the context it is in. It is unique within an entire
* nested node group hierarchy. This type is small and can be passed around by value.
*
* A #DSocket can represent an input or an output socket. If the type of a socket is known at
- * compile time is preferable to use #DInputSocket or #DOutputSocket instead. */
+ * compile time is preferable to use #DInputSocket or #DOutputSocket instead.
+ */
class DSocket {
protected:
const DTreeContext *context_ = nullptr;
@@ -129,7 +133,7 @@ class DSocket {
DNode node() const;
};
-/* A (nullable) reference to an input socket and the context it is in. */
+/** A (nullable) reference to an input socket and the context it is in. */
class DInputSocket : public DSocket {
public:
DInputSocket() = default;
@@ -142,10 +146,15 @@ class DInputSocket : public DSocket {
DOutputSocket get_corresponding_group_node_output() const;
Vector<DOutputSocket, 4> get_corresponding_group_input_sockets() const;
+ /**
+ * Call `origin_fn` for every "real" origin socket. "Real" means that reroutes, muted nodes
+ * and node groups are handled by this function. Origin sockets are ones where a node gets its
+ * inputs from.
+ */
void foreach_origin_socket(FunctionRef<void(DSocket)> origin_fn) const;
};
-/* A (nullable) reference to an output socket and the context it is in. */
+/** A (nullable) reference to an output socket and the context it is in. */
class DOutputSocket : public DSocket {
public:
DOutputSocket() = default;
@@ -166,6 +175,11 @@ class DOutputSocket : public DSocket {
using ForeachTargetSocketFn =
FunctionRef<void(DInputSocket, const TargetSocketPathInfo &path_info)>;
+ /**
+ * Calls `target_fn` for every "real" target socket. "Real" means that reroutes, muted nodes
+ * and node groups are handled by this function. Target sockets are on the nodes that use the
+ * value from this socket.
+ */
void foreach_target_socket(ForeachTargetSocketFn target_fn) const;
private:
@@ -180,16 +194,27 @@ class DerivedNodeTree {
VectorSet<const NodeTreeRef *> used_node_tree_refs_;
public:
+ /**
+ * Construct a new derived node tree for a given root node tree. The generated derived node tree
+ * does not own the used node tree refs (so that those can be used by others as well). The caller
+ * has to make sure that the node tree refs added to #node_tree_refs live at least as long as the
+ * derived node tree.
+ */
DerivedNodeTree(bNodeTree &btree, NodeTreeRefMap &node_tree_refs);
~DerivedNodeTree();
const DTreeContext &root_context() const;
Span<const NodeTreeRef *> used_node_tree_refs() const;
+ /**
+ * \return True when there is a link cycle. Unavailable sockets are ignored.
+ */
bool has_link_cycles() const;
bool has_undefined_nodes_or_sockets() const;
+ /** Calls the given callback on all nodes in the (possibly nested) derived node tree. */
void foreach_node(FunctionRef<void(DNode)> callback) const;
+ /** Generates a graph in dot format. The generated graph has all node groups inlined. */
std::string to_dot() const;
private:
@@ -246,6 +271,7 @@ inline bool DTreeContext::is_root() const
{
return parent_context_ == nullptr;
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -312,6 +338,7 @@ inline DOutputSocket DNode::output_by_identifier(StringRef identifier) const
{
return {context_, &node_ref_->output_by_identifier(identifier)};
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -374,6 +401,7 @@ inline DNode DSocket::node() const
BLI_assert(socket_ref_ != nullptr);
return {context_, &socket_ref_->node()};
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -399,6 +427,7 @@ inline const InputSocketRef *DInputSocket::operator->() const
{
return (const InputSocketRef *)socket_ref_;
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -424,6 +453,7 @@ inline const OutputSocketRef *DOutputSocket::operator->() const
{
return (const OutputSocketRef *)socket_ref_;
}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/nodes/NOD_function.h b/source/blender/nodes/NOD_function.h
index 81f0667fe1c..be3998a916c 100644
--- a/source/blender/nodes/NOD_function.h
+++ b/source/blender/nodes/NOD_function.h
@@ -24,7 +24,7 @@ void register_node_type_fn_legacy_random_float(void);
void register_node_type_fn_align_euler_to_vector(void);
void register_node_type_fn_boolean_math(void);
-void register_node_type_fn_float_compare(void);
+void register_node_type_fn_compare(void);
void register_node_type_fn_float_to_int(void);
void register_node_type_fn_input_bool(void);
void register_node_type_fn_input_color(void);
diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h
index ea3458af065..a0b8e237f19 100644
--- a/source/blender/nodes/NOD_geometry.h
+++ b/source/blender/nodes/NOD_geometry.h
@@ -16,12 +16,12 @@
#pragma once
+#include "BKE_node.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "BKE_node.h"
-
extern struct bNodeTreeType *ntreeType_Geometry;
void register_node_tree_type_geo(void);
@@ -57,6 +57,7 @@ void register_node_type_geo_attribute_combine_xyz(void);
void register_node_type_geo_attribute_compare(void);
void register_node_type_geo_attribute_convert(void);
void register_node_type_geo_attribute_curve_map(void);
+void register_node_type_geo_attribute_domain_size(void);
void register_node_type_geo_attribute_fill(void);
void register_node_type_geo_attribute_map_range(void);
void register_node_type_geo_attribute_math(void);
@@ -75,7 +76,6 @@ void register_node_type_geo_curve_fill(void);
void register_node_type_geo_curve_fillet(void);
void register_node_type_geo_curve_handle_type_selection(void);
void register_node_type_geo_curve_length(void);
-void register_node_type_geo_curve_parameter(void);
void register_node_type_geo_curve_primitive_bezier_segment(void);
void register_node_type_geo_curve_primitive_circle(void);
void register_node_type_geo_curve_primitive_line(void);
@@ -88,13 +88,16 @@ void register_node_type_geo_curve_reverse(void);
void register_node_type_geo_curve_sample(void);
void register_node_type_geo_curve_set_handles(void);
void register_node_type_geo_curve_spline_type(void);
+void register_node_type_geo_curve_spline_parameter(void);
void register_node_type_geo_curve_subdivide(void);
void register_node_type_geo_curve_to_mesh(void);
void register_node_type_geo_curve_to_points(void);
void register_node_type_geo_curve_trim(void);
void register_node_type_geo_delete_geometry(void);
void register_node_type_geo_distribute_points_on_faces(void);
+void register_node_type_geo_dual_mesh(void);
void register_node_type_geo_edge_split(void);
+void register_node_type_geo_geometry_to_instance(void);
void register_node_type_geo_image_texture(void);
void register_node_type_geo_input_curve_handles(void);
void register_node_type_geo_input_curve_tilt(void);
@@ -102,9 +105,16 @@ void register_node_type_geo_input_id(void);
void register_node_type_geo_input_index(void);
void register_node_type_geo_input_material_index(void);
void register_node_type_geo_input_material(void);
+void register_node_type_geo_input_mesh_edge_neighbors(void);
+void register_node_type_geo_input_mesh_edge_vertices(void);
+void register_node_type_geo_input_mesh_face_area(void);
+void register_node_type_geo_input_mesh_face_neighbors(void);
+void register_node_type_geo_input_mesh_island(void);
+void register_node_type_geo_input_mesh_vertex_neighbors(void);
void register_node_type_geo_input_normal(void);
void register_node_type_geo_input_position(void);
void register_node_type_geo_input_radius(void);
+void register_node_type_geo_input_scene_time(void);
void register_node_type_geo_input_shade_smooth(void);
void register_node_type_geo_input_spline_cyclic(void);
void register_node_type_geo_input_spline_length(void);
diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh
index 700f32ee414..f225b3b94b2 100644
--- a/source/blender/nodes/NOD_geometry_exec.hh
+++ b/source/blender/nodes/NOD_geometry_exec.hh
@@ -28,6 +28,8 @@
#include "NOD_derived_node_tree.hh"
#include "NOD_geometry_nodes_eval_log.hh"
+#include "GEO_realize_instances.hh"
+
struct Depsgraph;
struct ModifierData;
@@ -36,8 +38,8 @@ namespace blender::nodes {
using bke::AnonymousAttributeFieldInput;
using bke::AttributeFieldInput;
using bke::AttributeIDRef;
-using bke::geometry_set_realize_instances;
using bke::GeometryComponentFieldContext;
+using bke::GeometryFieldInput;
using bke::OutputAttribute;
using bke::OutputAttribute_Typed;
using bke::ReadAttributeLookup;
@@ -59,6 +61,7 @@ using fn::GVArray;
using fn::GVArray_GSpan;
using fn::GVMutableArray;
using fn::GVMutableArray_GSpan;
+using fn::ValueOrField;
using geometry_nodes_eval_log::NodeWarningType;
/**
@@ -117,6 +120,8 @@ class GeoNodeExecParamsProvider {
virtual bool output_is_required(StringRef identifier) const = 0;
virtual bool lazy_require_input(StringRef identifier) = 0;
virtual bool lazy_output_is_required(StringRef identifier) const = 0;
+
+ virtual void set_default_remaining_outputs() = 0;
};
class GeoNodeExecParams {
@@ -129,7 +134,7 @@ class GeoNodeExecParams {
}
template<typename T>
- static inline constexpr bool is_stored_as_field_v = std::is_same_v<T, float> ||
+ static inline constexpr bool is_field_base_type_v = std::is_same_v<T, float> ||
std::is_same_v<T, int> ||
std::is_same_v<T, bool> ||
std::is_same_v<T, ColorGeometry4f> ||
@@ -157,9 +162,15 @@ class GeoNodeExecParams {
*/
template<typename T> T extract_input(StringRef identifier)
{
- if constexpr (is_stored_as_field_v<T>) {
- Field<T> field = this->extract_input<Field<T>>(identifier);
- return fn::evaluate_constant_field(field);
+ if constexpr (is_field_base_type_v<T>) {
+ ValueOrField<T> value_or_field = this->extract_input<ValueOrField<T>>(identifier);
+ return value_or_field.as_value();
+ }
+ else if constexpr (fn::is_field_v<T>) {
+ using BaseType = typename T::base_type;
+ ValueOrField<BaseType> value_or_field = this->extract_input<ValueOrField<BaseType>>(
+ identifier);
+ return value_or_field.as_field();
}
else {
#ifdef DEBUG
@@ -186,9 +197,9 @@ class GeoNodeExecParams {
Vector<GMutablePointer> gvalues = provider_->extract_multi_input(identifier);
Vector<T> values;
for (GMutablePointer gvalue : gvalues) {
- if constexpr (is_stored_as_field_v<T>) {
- const Field<T> field = gvalue.relocate_out<Field<T>>();
- values.append(fn::evaluate_constant_field(field));
+ if constexpr (is_field_base_type_v<T>) {
+ const ValueOrField<T> value_or_field = gvalue.relocate_out<ValueOrField<T>>();
+ values.append(value_or_field.as_value());
}
else {
values.append(gvalue.relocate_out<T>());
@@ -200,11 +211,16 @@ class GeoNodeExecParams {
/**
* Get the input value for the input socket with the given identifier.
*/
- template<typename T> const T get_input(StringRef identifier) const
+ template<typename T> T get_input(StringRef identifier) const
{
- if constexpr (is_stored_as_field_v<T>) {
- const Field<T> &field = this->get_input<Field<T>>(identifier);
- return fn::evaluate_constant_field(field);
+ if constexpr (is_field_base_type_v<T>) {
+ ValueOrField<T> value_or_field = this->get_input<ValueOrField<T>>(identifier);
+ return value_or_field.as_value();
+ }
+ else if constexpr (fn::is_field_v<T>) {
+ using BaseType = typename T::base_type;
+ ValueOrField<BaseType> value_or_field = this->get_input<ValueOrField<BaseType>>(identifier);
+ return value_or_field.as_field();
}
else {
#ifdef DEBUG
@@ -226,9 +242,12 @@ class GeoNodeExecParams {
template<typename T> void set_output(StringRef identifier, T &&value)
{
using StoredT = std::decay_t<T>;
- if constexpr (is_stored_as_field_v<StoredT>) {
- this->set_output<Field<StoredT>>(identifier,
- fn::make_constant_field<StoredT>(std::forward<T>(value)));
+ if constexpr (is_field_base_type_v<StoredT>) {
+ this->set_output(identifier, ValueOrField<StoredT>(std::forward<T>(value)));
+ }
+ else if constexpr (fn::is_field_v<StoredT>) {
+ using BaseType = typename StoredT::base_type;
+ this->set_output(identifier, ValueOrField<BaseType>(std::forward<T>(value)));
}
else {
const CPPType &type = CPPType::get<StoredT>();
@@ -336,12 +355,19 @@ class GeoNodeExecParams {
const GeometryComponent &component,
const CustomDataType default_type) const;
+ /**
+ * If any of the corresponding input sockets are attributes instead of single values,
+ * use the highest priority attribute domain from among them.
+ * Otherwise return the default domain.
+ */
AttributeDomain get_highest_priority_input_domain(Span<std::string> names,
const GeometryComponent &component,
const AttributeDomain default_domain) const;
std::string attribute_producer_name() const;
+ void set_default_remaining_outputs();
+
private:
/* Utilities for detecting common errors at when using this class. */
void check_input_access(StringRef identifier, const CPPType *requested_type = nullptr) const;
diff --git a/source/blender/nodes/NOD_geometry_nodes_eval_log.hh b/source/blender/nodes/NOD_geometry_nodes_eval_log.hh
index 2a118057a03..ac2c29b4ec2 100644
--- a/source/blender/nodes/NOD_geometry_nodes_eval_log.hh
+++ b/source/blender/nodes/NOD_geometry_nodes_eval_log.hh
@@ -41,6 +41,8 @@
#include "NOD_derived_node_tree.hh"
+#include <chrono>
+
struct SpaceNode;
struct SpaceSpreadsheet;
@@ -169,6 +171,16 @@ struct NodeWithWarning {
NodeWarning warning;
};
+struct NodeWithExecutionTime {
+ DNode node;
+ std::chrono::microseconds exec_time;
+};
+
+struct NodeWithDebugMessage {
+ DNode node;
+ std::string message;
+};
+
/** The same value can be referenced by multiple sockets when they are linked. */
struct ValueOfSockets {
Span<DSocket> sockets;
@@ -189,6 +201,8 @@ class LocalGeoLogger {
std::unique_ptr<LinearAllocator<>> allocator_;
Vector<ValueOfSockets> values_;
Vector<NodeWithWarning> node_warnings_;
+ Vector<NodeWithExecutionTime> node_exec_times_;
+ Vector<NodeWithDebugMessage> node_debug_messages_;
friend ModifierLog;
@@ -201,6 +215,12 @@ class LocalGeoLogger {
void log_value_for_sockets(Span<DSocket> sockets, GPointer value);
void log_multi_value_socket(DSocket socket, Span<GPointer> values);
void log_node_warning(DNode node, NodeWarningType type, std::string message);
+ void log_execution_time(DNode node, std::chrono::microseconds exec_time);
+ /**
+ * Log a message that will be displayed in the node editor next to the node.
+ * This should only be used for debugging purposes and not to display information to users.
+ */
+ void log_debug_message(DNode node, std::string message);
};
/** The root logger class. */
@@ -274,12 +294,15 @@ class NodeLog {
Vector<SocketLog> input_logs_;
Vector<SocketLog> output_logs_;
Vector<NodeWarning, 0> warnings_;
+ Vector<std::string, 0> debug_messages_;
+ std::chrono::microseconds exec_time_;
friend ModifierLog;
public:
const SocketLog *lookup_socket_log(eNodeSocketInOut in_out, int index) const;
const SocketLog *lookup_socket_log(const bNode &node, const bNodeSocket &socket) const;
+ void execution_time(std::chrono::microseconds exec_time);
Span<SocketLog> input_logs() const
{
@@ -296,6 +319,16 @@ class NodeLog {
return warnings_;
}
+ Span<std::string> debug_messages() const
+ {
+ return debug_messages_;
+ }
+
+ std::chrono::microseconds execution_time() const
+ {
+ return exec_time_;
+ }
+
Vector<const GeometryAttributeInfo *> lookup_available_attributes() const;
};
diff --git a/source/blender/nodes/NOD_math_functions.hh b/source/blender/nodes/NOD_math_functions.hh
index 86ff8cab3e9..54abc754346 100644
--- a/source/blender/nodes/NOD_math_functions.hh
+++ b/source/blender/nodes/NOD_math_functions.hh
@@ -204,7 +204,7 @@ inline bool try_dispatch_float_math_fl_fl_fl_to_fl(const int operation, Callback
* This is similar to try_dispatch_float_math_fl_to_fl, just with a different callback signature.
*/
template<typename Callback>
-inline bool try_dispatch_float_math_fl_fl_to_bool(const FloatCompareOperation operation,
+inline bool try_dispatch_float_math_fl_fl_to_bool(const NodeCompareOperation operation,
Callback &&callback)
{
const FloatMathOperationInfo *info = get_float_compare_operation_info(operation);
@@ -219,13 +219,13 @@ inline bool try_dispatch_float_math_fl_fl_to_bool(const FloatCompareOperation op
};
switch (operation) {
- case NODE_FLOAT_COMPARE_LESS_THAN:
+ case NODE_COMPARE_LESS_THAN:
return dispatch([](float a, float b) { return a < b; });
- case NODE_FLOAT_COMPARE_LESS_EQUAL:
+ case NODE_COMPARE_LESS_EQUAL:
return dispatch([](float a, float b) { return a <= b; });
- case NODE_FLOAT_COMPARE_GREATER_THAN:
+ case NODE_COMPARE_GREATER_THAN:
return dispatch([](float a, float b) { return a > b; });
- case NODE_FLOAT_COMPARE_GREATER_EQUAL:
+ case NODE_COMPARE_GREATER_EQUAL:
return dispatch([](float a, float b) { return a >= b; });
default:
return false;
diff --git a/source/blender/nodes/NOD_node_declaration.hh b/source/blender/nodes/NOD_node_declaration.hh
index 9b99026d6a7..af2130ec452 100644
--- a/source/blender/nodes/NOD_node_declaration.hh
+++ b/source/blender/nodes/NOD_node_declaration.hh
@@ -16,6 +16,7 @@
#pragma once
+#include <functional>
#include <type_traits>
#include "BLI_string_ref.hh"
@@ -23,6 +24,8 @@
#include "DNA_node_types.h"
+struct bNode;
+
namespace blender::nodes {
class NodeDeclarationBuilder;
@@ -84,8 +87,12 @@ class SocketDeclaration {
std::string name_;
std::string identifier_;
std::string description_;
+ /** Defined by whether the socket is part of the node's input or
+ * output socket declaration list. Included here for convenience. */
+ eNodeSocketInOut in_out_;
bool hide_label_ = false;
bool hide_value_ = false;
+ bool compact_ = false;
bool is_multi_input_ = false;
bool no_mute_links_ = false;
bool is_attribute_name_ = false;
@@ -94,19 +101,36 @@ class SocketDeclaration {
InputSocketFieldType input_field_type_ = InputSocketFieldType::None;
OutputFieldDependency output_field_dependency_;
+ /** Utility method to make the socket available if there is a straightforward way to do so. */
+ std::function<void(bNode &)> make_available_fn_;
+
friend NodeDeclarationBuilder;
template<typename SocketDecl> friend class SocketDeclarationBuilder;
public:
virtual ~SocketDeclaration() = default;
- virtual bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const = 0;
+ virtual bNodeSocket &build(bNodeTree &ntree, bNode &node) const = 0;
virtual bool matches(const bNodeSocket &socket) const = 0;
virtual bNodeSocket &update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const;
+ /**
+ * Determine if a new socket described by this declaration could have a valid connection
+ * the other socket.
+ */
+ virtual bool can_connect(const bNodeSocket &socket) const = 0;
+
+ /**
+ * Change the node such that the socket will become visible. The node type's update method
+ * should be called afterwards.
+ * \note Note that this is not necessarily implemented for all node types.
+ */
+ void make_available(bNode &node) const;
+
StringRefNull name() const;
StringRefNull description() const;
StringRefNull identifier() const;
+ eNodeSocketInOut in_out() const;
bool is_attribute_name() const;
bool is_default_link_socket() const;
@@ -215,6 +239,18 @@ class SocketDeclarationBuilder : public BaseSocketDeclarationBuilder {
std::move(input_dependencies));
return *(Self *)this;
}
+
+ /**
+ * Pass a function that sets properties on the node required to make the corresponding socket
+ * available, if it is not available on the default state of the node. The function is allowed to
+ * make other sockets unavailable, since it is meant to be called when the node is first added.
+ * The node type's update function is called afterwards.
+ */
+ Self &make_available(std::function<void(bNode &)> fn)
+ {
+ decl_->make_available_fn_ = std::move(fn);
+ return *(Self *)this;
+ }
};
using SocketDeclarationPtr = std::unique_ptr<SocketDeclaration>;
@@ -232,6 +268,7 @@ class NodeDeclaration {
Span<SocketDeclarationPtr> inputs() const;
Span<SocketDeclarationPtr> outputs() const;
+ Span<SocketDeclarationPtr> sockets(eNodeSocketInOut in_out) const;
bool is_function_node() const
{
@@ -267,7 +304,7 @@ class NodeDeclarationBuilder {
template<typename DeclType>
typename DeclType::Builder &add_socket(StringRef name,
StringRef identifier,
- Vector<SocketDeclarationPtr> &r_decls);
+ eNodeSocketInOut in_out);
};
/* -------------------------------------------------------------------- */
@@ -360,6 +397,11 @@ inline StringRefNull SocketDeclaration::identifier() const
return identifier_;
}
+inline eNodeSocketInOut SocketDeclaration::in_out() const
+{
+ return in_out_;
+}
+
inline StringRefNull SocketDeclaration::description() const
{
return description_;
@@ -385,6 +427,13 @@ inline const OutputFieldDependency &SocketDeclaration::output_field_dependency()
return output_field_dependency_;
}
+inline void SocketDeclaration::make_available(bNode &node) const
+{
+ if (make_available_fn_) {
+ make_available_fn_(node);
+ }
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -400,28 +449,34 @@ template<typename DeclType>
inline typename DeclType::Builder &NodeDeclarationBuilder::add_input(StringRef name,
StringRef identifier)
{
- return this->add_socket<DeclType>(name, identifier, declaration_.inputs_);
+ return this->add_socket<DeclType>(name, identifier, SOCK_IN);
}
template<typename DeclType>
inline typename DeclType::Builder &NodeDeclarationBuilder::add_output(StringRef name,
StringRef identifier)
{
- return this->add_socket<DeclType>(name, identifier, declaration_.outputs_);
+ return this->add_socket<DeclType>(name, identifier, SOCK_OUT);
}
template<typename DeclType>
-inline typename DeclType::Builder &NodeDeclarationBuilder::add_socket(
- StringRef name, StringRef identifier, Vector<SocketDeclarationPtr> &r_decls)
+inline typename DeclType::Builder &NodeDeclarationBuilder::add_socket(StringRef name,
+ StringRef identifier,
+ eNodeSocketInOut in_out)
{
static_assert(std::is_base_of_v<SocketDeclaration, DeclType>);
using Builder = typename DeclType::Builder;
+
+ Vector<SocketDeclarationPtr> &declarations = in_out == SOCK_IN ? declaration_.inputs_ :
+ declaration_.outputs_;
+
std::unique_ptr<DeclType> socket_decl = std::make_unique<DeclType>();
std::unique_ptr<Builder> socket_decl_builder = std::make_unique<Builder>();
socket_decl_builder->decl_ = &*socket_decl;
socket_decl->name_ = name;
socket_decl->identifier_ = identifier.is_empty() ? name : identifier;
- r_decls.append(std::move(socket_decl));
+ socket_decl->in_out_ = in_out;
+ declarations.append(std::move(socket_decl));
Builder &socket_decl_builder_ref = *socket_decl_builder;
builders_.append(std::move(socket_decl_builder));
return socket_decl_builder_ref;
@@ -443,6 +498,14 @@ inline Span<SocketDeclarationPtr> NodeDeclaration::outputs() const
return outputs_;
}
+inline Span<SocketDeclarationPtr> NodeDeclaration::sockets(eNodeSocketInOut in_out) const
+{
+ if (in_out == SOCK_IN) {
+ return inputs_;
+ }
+ return outputs_;
+}
+
/** \} */
} // namespace blender::nodes
diff --git a/source/blender/nodes/NOD_node_tree_ref.hh b/source/blender/nodes/NOD_node_tree_ref.hh
index 26a5dc9d60f..65789069231 100644
--- a/source/blender/nodes/NOD_node_tree_ref.hh
+++ b/source/blender/nodes/NOD_node_tree_ref.hh
@@ -279,6 +279,9 @@ class NodeTreeRef : NonCopyable, NonMovable {
const NodeRef *find_node(const bNode &bnode) const;
+ /**
+ * \return True when there is a link cycle. Unavailable sockets are ignored.
+ */
bool has_link_cycles() const;
bool has_undefined_nodes_or_sockets() const;
@@ -297,6 +300,10 @@ class NodeTreeRef : NonCopyable, NonMovable {
bool has_cycle = false;
};
+ /**
+ * Sort nodes topologically from left to right or right to left.
+ * In the future the result if this could be cached on #NodeTreeRef.
+ */
ToposortResult toposort(ToposortDirection direction) const;
bNodeTree *btree() const;
diff --git a/source/blender/nodes/NOD_socket_declarations.hh b/source/blender/nodes/NOD_socket_declarations.hh
index f7aea212f73..3fb21a4263d 100644
--- a/source/blender/nodes/NOD_socket_declarations.hh
+++ b/source/blender/nodes/NOD_socket_declarations.hh
@@ -39,9 +39,10 @@ class Float : public SocketDeclaration {
public:
using Builder = FloatBuilder;
- bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const override;
+ bNodeSocket &build(bNodeTree &ntree, bNode &node) const override;
bool matches(const bNodeSocket &socket) const override;
bNodeSocket &update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const override;
+ bool can_connect(const bNodeSocket &socket) const override;
};
class FloatBuilder : public SocketDeclarationBuilder<Float> {
@@ -66,9 +67,10 @@ class Int : public SocketDeclaration {
public:
using Builder = IntBuilder;
- bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const override;
+ bNodeSocket &build(bNodeTree &ntree, bNode &node) const override;
bool matches(const bNodeSocket &socket) const override;
bNodeSocket &update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const override;
+ bool can_connect(const bNodeSocket &socket) const override;
};
class IntBuilder : public SocketDeclarationBuilder<Int> {
@@ -93,9 +95,10 @@ class Vector : public SocketDeclaration {
public:
using Builder = VectorBuilder;
- bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const override;
+ bNodeSocket &build(bNodeTree &ntree, bNode &node) const override;
bool matches(const bNodeSocket &socket) const override;
bNodeSocket &update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const override;
+ bool can_connect(const bNodeSocket &socket) const override;
};
class VectorBuilder : public SocketDeclarationBuilder<Vector> {
@@ -104,6 +107,7 @@ class VectorBuilder : public SocketDeclarationBuilder<Vector> {
VectorBuilder &subtype(PropertySubType subtype);
VectorBuilder &min(const float min);
VectorBuilder &max(const float max);
+ VectorBuilder &compact();
};
class BoolBuilder;
@@ -116,8 +120,9 @@ class Bool : public SocketDeclaration {
public:
using Builder = BoolBuilder;
- bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const override;
+ bNodeSocket &build(bNodeTree &ntree, bNode &node) const override;
bool matches(const bNodeSocket &socket) const override;
+ bool can_connect(const bNodeSocket &socket) const override;
};
class BoolBuilder : public SocketDeclarationBuilder<Bool> {
@@ -136,8 +141,9 @@ class Color : public SocketDeclaration {
public:
using Builder = ColorBuilder;
- bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const override;
+ bNodeSocket &build(bNodeTree &ntree, bNode &node) const override;
bool matches(const bNodeSocket &socket) const override;
+ bool can_connect(const bNodeSocket &socket) const override;
};
class ColorBuilder : public SocketDeclarationBuilder<Color> {
@@ -156,8 +162,9 @@ class String : public SocketDeclaration {
public:
using Builder = StringBuilder;
- bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const override;
+ bNodeSocket &build(bNodeTree &ntree, bNode &node) const override;
bool matches(const bNodeSocket &socket) const override;
+ bool can_connect(const bNodeSocket &socket) const override;
};
class StringBuilder : public SocketDeclarationBuilder<String> {
@@ -172,9 +179,10 @@ class IDSocketDeclaration : public SocketDeclaration {
public:
IDSocketDeclaration(const char *idname);
- bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const override;
+ bNodeSocket &build(bNodeTree &ntree, bNode &node) const override;
bool matches(const bNodeSocket &socket) const override;
bNodeSocket &update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const override;
+ bool can_connect(const bNodeSocket &socket) const override;
};
class Object : public IDSocketDeclaration {
@@ -212,6 +220,23 @@ class Image : public IDSocketDeclaration {
Image();
};
+class ShaderBuilder;
+
+class Shader : public SocketDeclaration {
+ private:
+ friend ShaderBuilder;
+
+ public:
+ using Builder = ShaderBuilder;
+
+ bNodeSocket &build(bNodeTree &ntree, bNode &node) const override;
+ bool matches(const bNodeSocket &socket) const override;
+ bool can_connect(const bNodeSocket &socket) const;
+};
+
+class ShaderBuilder : public SocketDeclarationBuilder<Shader> {
+};
+
/* -------------------------------------------------------------------- */
/** \name #FloatBuilder Inline Methods
* \{ */
@@ -300,6 +325,12 @@ inline VectorBuilder &VectorBuilder::max(const float max)
return *this;
}
+inline VectorBuilder &VectorBuilder::compact()
+{
+ decl_->compact_ = true;
+ return *this;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -369,26 +400,3 @@ inline Image::Image() : IDSocketDeclaration("NodeSocketImage")
/** \} */
} // namespace blender::nodes::decl
-
-/* -------------------------------------------------------------------- */
-/** \name External Template Instantiations
- *
- * Defined in `intern/extern_implementations.cc`.
- * \{ */
-
-namespace blender::nodes {
-#define MAKE_EXTERN_SOCKET_DECLARATION(TYPE) \
- extern template class SocketDeclarationBuilder<TYPE>; \
- extern template TYPE::Builder &NodeDeclarationBuilder::add_input<TYPE>(StringRef, StringRef); \
- extern template TYPE::Builder &NodeDeclarationBuilder::add_output<TYPE>(StringRef, StringRef);
-
-MAKE_EXTERN_SOCKET_DECLARATION(decl::Float)
-MAKE_EXTERN_SOCKET_DECLARATION(decl::Int)
-MAKE_EXTERN_SOCKET_DECLARATION(decl::Vector)
-MAKE_EXTERN_SOCKET_DECLARATION(decl::Bool)
-MAKE_EXTERN_SOCKET_DECLARATION(decl::Color)
-MAKE_EXTERN_SOCKET_DECLARATION(decl::String)
-
-} // namespace blender::nodes
-
-/** \} */
diff --git a/source/blender/nodes/NOD_socket_declarations_geometry.hh b/source/blender/nodes/NOD_socket_declarations_geometry.hh
index 1531f82d67d..0ce07da22ff 100644
--- a/source/blender/nodes/NOD_socket_declarations_geometry.hh
+++ b/source/blender/nodes/NOD_socket_declarations_geometry.hh
@@ -35,8 +35,9 @@ class Geometry : public SocketDeclaration {
public:
using Builder = GeometryBuilder;
- bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const override;
+ bNodeSocket &build(bNodeTree &ntree, bNode &node) const override;
bool matches(const bNodeSocket &socket) const override;
+ bool can_connect(const bNodeSocket &socket) const override;
Span<GeometryComponentType> supported_types() const;
bool only_realized_data() const;
@@ -52,7 +53,3 @@ class GeometryBuilder : public SocketDeclarationBuilder<Geometry> {
};
} // namespace blender::nodes::decl
-
-namespace blender::nodes {
-MAKE_EXTERN_SOCKET_DECLARATION(decl::Geometry)
-}
diff --git a/source/blender/nodes/NOD_socket_search_link.hh b/source/blender/nodes/NOD_socket_search_link.hh
new file mode 100644
index 00000000000..b7594561dc4
--- /dev/null
+++ b/source/blender/nodes/NOD_socket_search_link.hh
@@ -0,0 +1,151 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <functional>
+
+#include "BLI_string_ref.hh"
+#include "BLI_vector.hh"
+
+#include "DNA_node_types.h" /* Necessary for eNodeSocketInOut. */
+
+#include "NOD_node_declaration.hh"
+
+struct bContext;
+
+namespace blender::nodes {
+
+/**
+ * Parameters for the operation operation of adding a node after the link drag search menu closes.
+ */
+class LinkSearchOpParams {
+ private:
+ /**
+ * Keep track of the nodes added by the callback, so they can be selected or moved afterwards.
+ */
+ Vector<bNode *> &added_nodes_;
+
+ public:
+ const bContext &C;
+ bNodeTree &node_tree;
+ /**
+ * The node that contains the #socket.
+ */
+ bNode &node;
+ /**
+ * The existing socket to connect any added nodes to. Might be an input or output socket.
+ */
+ bNodeSocket &socket;
+
+ LinkSearchOpParams(const bContext &C,
+ bNodeTree &node_tree,
+ bNode &node,
+ bNodeSocket &socket,
+ Vector<bNode *> &added_nodes)
+ : added_nodes_(added_nodes), C(C), node_tree(node_tree), node(node), socket(socket)
+ {
+ }
+
+ bNode &add_node(StringRef idname);
+ bNode &add_node(const bNodeType &type);
+ /**
+ * Find a socket with the given name (correctly checks for inputs and outputs)
+ * and connect it to the socket the link drag started from (#socket).
+ */
+ void connect_available_socket(bNode &new_node, StringRef socket_name);
+ /**
+ * Like #connect_available_socket, but also calls the node's update function.
+ */
+ void update_and_connect_available_socket(bNode &new_node, StringRef socket_name);
+};
+
+struct SocketLinkOperation {
+ using LinkSocketFn = std::function<void(LinkSearchOpParams &link_params)>;
+
+ std::string name;
+ LinkSocketFn fn;
+ int weight = 0;
+};
+
+class GatherLinkSearchOpParams {
+ /** The current node type. */
+ const bNodeType &node_type_;
+
+ const bNodeTree &node_tree_;
+
+ const bNodeSocket &other_socket_;
+
+ /* The operations currently being built. Owned by the caller. */
+ Vector<SocketLinkOperation> &items_;
+
+ public:
+ GatherLinkSearchOpParams(const bNodeType &node_type,
+ const bNodeTree &node_tree,
+ const bNodeSocket &other_socket,
+ Vector<SocketLinkOperation> &items)
+ : node_type_(node_type), node_tree_(node_tree), other_socket_(other_socket), items_(items)
+ {
+ }
+
+ /**
+ * The node on the other side of the dragged link.
+ */
+ const bNodeSocket &other_socket() const;
+
+ /**
+ * The node tree the user is editing when the search menu is created.
+ */
+ const bNodeTree &node_tree() const;
+
+ /**
+ * The type of the node in the current callback.
+ */
+ const bNodeType &node_type() const;
+
+ /**
+ * Whether to list the input or output sockets of the node.
+ */
+ eNodeSocketInOut in_out() const;
+
+ /**
+ * \param weight: Used to customize the order when multiple search items match.
+ *
+ * \warning When creating lambdas for the #fn argument, be careful not to capture this class
+ * itself, since it is temporary. That is why we tend to use the same variable name for this
+ * class (`params`) that we do for the argument to `LinkSocketFn`.
+ */
+ void add_item(std::string socket_name, SocketLinkOperation::LinkSocketFn fn, int weight = 0);
+};
+
+/**
+ * This callback can be used for a node type when a few things are true about its inputs.
+ * To avoid creating more boilerplate, it is the default callback for node types.
+ * - Either all declared sockets are visible in the default state of the node, *OR* the node's
+ * type's declaration has been extended with #make_available functions for those sockets.
+ *
+ * If a node type does not meet these criteria, the function will do nothing in a release build.
+ * In a debug build, an assert will most likely be hit.
+ *
+ * \note For nodes with the deprecated #bNodeSocketTemplate instead of a declaration,
+ * these criteria do not apply and the function just tries its best without asserting.
+ */
+void search_link_ops_for_basic_node(GatherLinkSearchOpParams &params);
+
+void search_link_ops_for_declarations(GatherLinkSearchOpParams &params,
+ Span<SocketDeclarationPtr> declarations);
+
+} // namespace blender::nodes
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 20ad4d359f1..84bc7bf0ceb 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -267,7 +267,7 @@ DefNode(FunctionNode, FN_NODE_LEGACY_RANDOM_FLOAT, 0, "LEGACY_RANDOM_FLOAT", Leg
DefNode(FunctionNode, FN_NODE_ALIGN_EULER_TO_VECTOR, def_fn_align_euler_to_vector, "ALIGN_EULER_TO_VECTOR", AlignEulerToVector, "Align Euler To Vector", "")
DefNode(FunctionNode, FN_NODE_BOOLEAN_MATH, def_boolean_math, "BOOLEAN_MATH", BooleanMath, "Boolean Math", "")
-DefNode(FunctionNode, FN_NODE_COMPARE_FLOATS, def_float_compare, "COMPARE_FLOATS", CompareFloats, "Compare Floats", "")
+DefNode(FunctionNode, FN_NODE_COMPARE, def_compare, "COMPARE", Compare, "Compare", "")
DefNode(FunctionNode, FN_NODE_FLOAT_TO_INT, def_float_to_int, "FLOAT_TO_INT", FloatToInt, "Float to Integer", "")
DefNode(FunctionNode, FN_NODE_INPUT_BOOL, def_fn_input_bool, "INPUT_BOOL", InputBool, "Boolean", "")
DefNode(FunctionNode, FN_NODE_INPUT_COLOR, def_fn_input_color, "INPUT_COLOR", InputColor, "Color", "")
@@ -325,6 +325,7 @@ DefNode(GeometryNode, GEO_NODE_LEGACY_VOLUME_TO_MESH, def_geo_volume_to_mesh, "L
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_REMOVE, 0, "ATTRIBUTE_REMOVE", AttributeRemove, "Attribute Remove", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_STATISTIC, def_geo_attribute_statistic, "ATTRIBUTE_STATISTIC", AttributeStatistic, "Attribute Statistic", "")
+DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_DOMAIN_SIZE, def_geo_attribute_domain_size, "ATTRIBUTE_DOMAIN_SIZE", AttributeDomainSize, "Domain Size", "")
DefNode(GeometryNode, GEO_NODE_BOUNDING_BOX, 0, "BOUNDING_BOX", BoundBox, "Bounding Box", "")
DefNode(GeometryNode, GEO_NODE_CAPTURE_ATTRIBUTE, def_geo_attribute_capture, "CAPTURE_ATTRIBUTE", CaptureAttribute, "Capture Attribute", "")
DefNode(GeometryNode, GEO_NODE_COLLECTION_INFO, def_geo_collection_info, "COLLECTION_INFO", CollectionInfo, "Collection Info", "")
@@ -332,7 +333,7 @@ DefNode(GeometryNode, GEO_NODE_CONVEX_HULL, 0, "CONVEX_HULL", ConvexHull, "Conve
DefNode(GeometryNode, GEO_NODE_CURVE_ENDPOINT_SELECTION, 0, "CURVE_ENDPOINT_SELECTION", CurveEndpointSelection, "Endpoint Selection", "")
DefNode(GeometryNode, GEO_NODE_CURVE_HANDLE_TYPE_SELECTION, def_geo_curve_handle_type_selection, "CURVE_HANDLE_TYPE_SELECTION", CurveHandleTypeSelection, "Handle Type Selection", "")
DefNode(GeometryNode, GEO_NODE_CURVE_LENGTH, 0, "CURVE_LENGTH", CurveLength, "Curve Length", "")
-DefNode(GeometryNode, GEO_NODE_CURVE_PARAMETER, 0, "CURVE_PARAMETER", CurveParameter, "Curve Parameter", "")
+DefNode(GeometryNode, GEO_NODE_CURVE_SPLINE_PARAMETER, 0, "SPLINE_PARAMETER", SplineParameter, "Spline Parameter", "")
DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT, def_geo_curve_primitive_bezier_segment, "CURVE_PRIMITIVE_BEZIER_SEGMENT", CurvePrimitiveBezierSegment, "Bezier Segment", "")
DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_CIRCLE, def_geo_curve_primitive_circle, "CURVE_PRIMITIVE_CIRCLE", CurvePrimitiveCircle, "Curve Circle", "")
DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_LINE, def_geo_curve_primitive_line, "CURVE_PRIMITIVE_LINE", CurvePrimitiveLine, "Curve Line", "")
@@ -346,8 +347,10 @@ DefNode(GeometryNode, GEO_NODE_CURVE_TO_MESH, 0, "CURVE_TO_MESH", CurveToMesh, "
DefNode(GeometryNode, GEO_NODE_CURVE_TO_POINTS, def_geo_curve_to_points, "CURVE_TO_POINTS", CurveToPoints, "Curve to Points", "")
DefNode(GeometryNode, GEO_NODE_DELETE_GEOMETRY, def_geo_delete_geometry, "DELETE_GEOMETRY", DeleteGeometry, "Delete Geometry", "")
DefNode(GeometryNode, GEO_NODE_DISTRIBUTE_POINTS_ON_FACES, def_geo_distribute_points_on_faces, "DISTRIBUTE_POINTS_ON_FACES", DistributePointsOnFaces, "Distribute Points on Faces", "")
+DefNode(GeometryNode, GEO_NODE_DUAL_MESH, 0, "DUAL_MESH", DualMesh, "Dual Mesh", "")
DefNode(GeometryNode, GEO_NODE_FILL_CURVE, def_geo_curve_fill, "FILL_CURVE", FillCurve, "Fill Curve", "")
DefNode(GeometryNode, GEO_NODE_FILLET_CURVE, def_geo_curve_fillet, "FILLET_CURVE", FilletCurve, "Fillet Curve", "")
+DefNode(GeometryNode, GEO_NODE_GEOMETRY_TO_INSTANCE, 0, "GEOMETRY_TO_INSTANCE", GeometryToInstance, "Geometry to Instance", "")
DefNode(GeometryNode, GEO_NODE_IMAGE_TEXTURE, def_geo_image_texture, "IMAGE_TEXTURE", ImageTexture, "Image Texture", "")
DefNode(GeometryNode, GEO_NODE_INPUT_CURVE_HANDLES, 0, "INPUT_CURVE_HANDLES", InputCurveHandlePositions, "Curve Handle Positions", "")
DefNode(GeometryNode, GEO_NODE_INPUT_CURVE_TILT, 0, "INPUT_CURVE_TILT", InputCurveTilt, "Curve Tilt", "")
@@ -355,9 +358,16 @@ DefNode(GeometryNode, GEO_NODE_INPUT_ID, 0, "INPUT_ID", InputID, "ID", "")
DefNode(GeometryNode, GEO_NODE_INPUT_INDEX, 0, "INDEX", InputIndex, "Index", "")
DefNode(GeometryNode, GEO_NODE_INPUT_MATERIAL_INDEX, 0, "INPUT_MATERIAL_INDEX", InputMaterialIndex, "Material Index", "")
DefNode(GeometryNode, GEO_NODE_INPUT_MATERIAL, def_geo_input_material, "INPUT_MATERIAL", InputMaterial, "Material", "")
+DefNode(GeometryNode, GEO_NODE_INPUT_MESH_EDGE_NEIGHBORS, 0, "MESH_EDGE_NEIGHBORS", InputMeshEdgeNeighbors, "Edge Neighbors", "")
+DefNode(GeometryNode, GEO_NODE_INPUT_MESH_EDGE_VERTICES, 0, "MESH_EDGE_VERTICES", InputMeshEdgeVertices, "Edge Vertices", "")
+DefNode(GeometryNode, GEO_NODE_INPUT_MESH_FACE_AREA, 0, "MESH_FACE_AREA", InputMeshFaceArea, "Face Area", "")
+DefNode(GeometryNode, GEO_NODE_INPUT_MESH_FACE_NEIGHBORS, 0, "MESH_FACE_NEIGHBORS", InputMeshFaceNeighbors, "Face Neighbors", "")
+DefNode(GeometryNode, GEO_NODE_INPUT_MESH_ISLAND, 0, "MESH_ISLAND", InputMeshIsland, "Mesh Island", "")
+DefNode(GeometryNode, GEO_NODE_INPUT_MESH_VERTEX_NEIGHBORS, 0, "MESH_VERTEX_NEIGHBORS", InputMeshVertexNeighbors, "Vertex Neighbors", "")
DefNode(GeometryNode, GEO_NODE_INPUT_NORMAL, 0, "INPUT_NORMAL", InputNormal, "Normal", "")
DefNode(GeometryNode, GEO_NODE_INPUT_POSITION, 0, "POSITION", InputPosition, "Position", "")
DefNode(GeometryNode, GEO_NODE_INPUT_RADIUS, 0, "INPUT_RADIUS", InputRadius, "Radius", "")
+DefNode(GeometryNode, GEO_NODE_INPUT_SCENE_TIME, 0, "INPUT_SCENE_TIME", InputSceneTime, "Scene Time", "")
DefNode(GeometryNode, GEO_NODE_INPUT_SHADE_SMOOTH, 0, "INPUT_SHADE_SMOOTH", InputShadeSmooth, "Is Shade Smooth", "")
DefNode(GeometryNode, GEO_NODE_INPUT_SPLINE_CYCLIC, 0, "INPUT_SPLINE_CYCLIC", InputSplineCyclic, "Is Spline Cyclic", "")
DefNode(GeometryNode, GEO_NODE_INPUT_SPLINE_LENGTH, 0, "SPLINE_LENGTH", SplineLength, "Spline Length", "")
@@ -384,7 +394,7 @@ DefNode(GeometryNode, GEO_NODE_POINTS_TO_VERTICES, 0, "POINTS_TO_VERTICES", Poin
DefNode(GeometryNode, GEO_NODE_POINTS_TO_VOLUME, def_geo_points_to_volume, "POINTS_TO_VOLUME", PointsToVolume, "Points to Volume", "")
DefNode(GeometryNode, GEO_NODE_PROXIMITY, def_geo_proximity, "PROXIMITY", Proximity, "Geometry Proximity", "")
DefNode(GeometryNode, GEO_NODE_RAYCAST, def_geo_raycast, "RAYCAST", Raycast, "Raycast", "")
-DefNode(GeometryNode, GEO_NODE_REALIZE_INSTANCES, 0, "REALIZE_INSTANCES", RealizeInstances, "Realize Instances", "")
+DefNode(GeometryNode, GEO_NODE_REALIZE_INSTANCES, def_geo_realize_instances, "REALIZE_INSTANCES", RealizeInstances, "Realize Instances", "")
DefNode(GeometryNode, GEO_NODE_REPLACE_MATERIAL, 0, "REPLACE_MATERIAL", ReplaceMaterial, "Replace Material", "")
DefNode(GeometryNode, GEO_NODE_RESAMPLE_CURVE, def_geo_curve_resample, "RESAMPLE_CURVE", ResampleCurve, "Resample Curve", "")
DefNode(GeometryNode, GEO_NODE_REVERSE_CURVE, 0, "REVERSE_CURVE", ReverseCurve, "Reverse Curve", "")
diff --git a/source/blender/nodes/composite/node_composite_tree.cc b/source/blender/nodes/composite/node_composite_tree.cc
index a596a85b748..1326c9edab1 100644
--- a/source/blender/nodes/composite/node_composite_tree.cc
+++ b/source/blender/nodes/composite/node_composite_tree.cc
@@ -212,7 +212,7 @@ static bool composite_node_tree_socket_type_valid(bNodeTreeType *UNUSED(ntreetyp
bNodeTreeType *ntreeType_Composite;
-void register_node_tree_type_cmp(void)
+void register_node_tree_type_cmp()
{
bNodeTreeType *tt = ntreeType_Composite = (bNodeTreeType *)MEM_callocN(
sizeof(bNodeTreeType), "compositor node tree type");
@@ -259,16 +259,6 @@ void ntreeCompositExecTree(Scene *scene,
/* *********************************************** */
-/**
- * Update the outputs of the render layer nodes.
- * Since the outputs depend on the render engine, this part is a bit complex:
- * - #ntreeCompositUpdateRLayers is called and loops over all render layer nodes.
- * - Each render layer node calls the update function of the
- * render engine that's used for its scene.
- * - The render engine calls RE_engine_register_pass for each pass.
- * - #RE_engine_register_pass calls #ntreeCompositRegisterPass,
- * which calls #node_cmp_rlayers_register_pass for every render layer node.
- */
void ntreeCompositUpdateRLayers(bNodeTree *ntree)
{
if (ntree == nullptr) {
@@ -299,8 +289,6 @@ void ntreeCompositRegisterPass(bNodeTree *ntree,
}
}
-/* called from render pipeline, to tag render input and output */
-/* need to do all scenes, to prevent errors when you re-render 1 scene */
void ntreeCompositTagRender(Scene *scene)
{
/* XXX Think using G_MAIN here is valid, since you want to update current file's scene nodes,
diff --git a/source/blender/nodes/composite/node_composite_util.cc b/source/blender/nodes/composite/node_composite_util.cc
index 21269b92e65..1262dfad11f 100644
--- a/source/blender/nodes/composite/node_composite_util.cc
+++ b/source/blender/nodes/composite/node_composite_util.cc
@@ -21,6 +21,8 @@
* \ingroup nodes
*/
+#include "NOD_socket_search_link.hh"
+
#include "node_composite_util.hh"
bool cmp_node_poll_default(bNodeType *UNUSED(ntype),
@@ -28,7 +30,7 @@ bool cmp_node_poll_default(bNodeType *UNUSED(ntype),
const char **r_disabled_hint)
{
if (!STREQ(ntree->idname, "CompositorNodeTree")) {
- *r_disabled_hint = "Not a compositor node tree";
+ *r_disabled_hint = TIP_("Not a compositor node tree");
return false;
}
return true;
@@ -52,4 +54,5 @@ void cmp_node_type_base(bNodeType *ntype, int type, const char *name, short ncla
ntype->poll = cmp_node_poll_default;
ntype->updatefunc = cmp_node_update_default;
ntype->insert_link = node_insert_link_default;
+ ntype->gather_link_search_ops = blender::nodes::search_link_ops_for_basic_node;
}
diff --git a/source/blender/nodes/composite/node_composite_util.hh b/source/blender/nodes/composite/node_composite_util.hh
index 6fd82ffc93f..04708d0d854 100644
--- a/source/blender/nodes/composite/node_composite_util.hh
+++ b/source/blender/nodes/composite/node_composite_util.hh
@@ -27,9 +27,6 @@
#include "DNA_movieclip_types.h"
#include "DNA_node_types.h"
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
-
#include "BLT_translation.h"
#include "BKE_colorband.h"
@@ -45,8 +42,8 @@
#include "RE_pipeline.h"
-/* only for forward declarations */
#include "NOD_composite.h"
+#include "NOD_socket.h"
#include "NOD_socket_declarations.hh"
#define CMP_SCALE_MAX 12000
diff --git a/source/blender/nodes/composite/nodes/node_composite_alphaOver.cc b/source/blender/nodes/composite/nodes/node_composite_alphaOver.cc
index b6f64ed00c7..5e6d59edfd5 100644
--- a/source/blender/nodes/composite/nodes/node_composite_alphaOver.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_alphaOver.cc
@@ -21,32 +21,46 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** ALPHAOVER ******************** */
-static bNodeSocketTemplate cmp_node_alphaover_in[] = {
- {SOCK_FLOAT, N_("Fac"), 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_alphaover_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void cmp_node_alphaover_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Fac")).default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Color>(N_("Image"), "Image_001").default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
static void node_alphaover_init(bNodeTree *UNUSED(ntree), bNode *node)
{
node->storage = MEM_callocN(sizeof(NodeTwoFloats), "NodeTwoFloats");
}
-void register_node_type_cmp_alphaover(void)
+static void node_composit_buts_alphaover(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "use_premultiply", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "premul", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_alphaover()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_ALPHAOVER, "Alpha Over", NODE_CLASS_OP_COLOR, 0);
- node_type_socket_templates(&ntype, cmp_node_alphaover_in, cmp_node_alphaover_out);
+ ntype.declare = blender::nodes::cmp_node_alphaover_declare;
+ ntype.draw_buttons = node_composit_buts_alphaover;
node_type_init(&ntype, node_alphaover_init);
node_type_storage(
&ntype, "NodeTwoFloats", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_antialiasing.cc b/source/blender/nodes/composite/nodes/node_composite_antialiasing.cc
index 23e63b9a53b..02b2652ed6a 100644
--- a/source/blender/nodes/composite/nodes/node_composite_antialiasing.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_antialiasing.cc
@@ -23,14 +23,22 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Anti-Aliasing (SMAA 1x) ******************** */
-static bNodeSocketTemplate cmp_node_antialiasing_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, {-1, ""}};
+namespace blender::nodes {
-static bNodeSocketTemplate cmp_node_antialiasing_out[] = {{SOCK_RGBA, N_("Image")}, {-1, ""}};
+static void cmp_node_antialiasing_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
static void node_composit_init_antialiasing(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -44,13 +52,25 @@ static void node_composit_init_antialiasing(bNodeTree *UNUSED(ntree), bNode *nod
node->storage = data;
}
-void register_node_type_cmp_antialiasing(void)
+static void node_composit_buts_antialiasing(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, false);
+
+ uiItemR(col, ptr, "threshold", 0, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "contrast_limit", 0, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "corner_rounding", 0, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_antialiasing()
{
static bNodeType ntype;
cmp_node_type_base(
&ntype, CMP_NODE_ANTIALIASING, "Anti-Aliasing", NODE_CLASS_OP_FILTER, NODE_PREVIEW);
- node_type_socket_templates(&ntype, cmp_node_antialiasing_in, cmp_node_antialiasing_out);
+ ntype.declare = blender::nodes::cmp_node_antialiasing_declare;
+ ntype.draw_buttons = node_composit_buts_antialiasing;
node_type_size(&ntype, 170, 140, 200);
node_type_init(&ntype, node_composit_init_antialiasing);
node_type_storage(
diff --git a/source/blender/nodes/composite/nodes/node_composite_bilateralblur.cc b/source/blender/nodes/composite/nodes/node_composite_bilateralblur.cc
index 3e724d17a10..3f107a13a44 100644
--- a/source/blender/nodes/composite/nodes/node_composite_bilateralblur.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_bilateralblur.cc
@@ -21,18 +21,23 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** BILATERALBLUR ******************** */
-static bNodeSocketTemplate cmp_node_bilateralblur_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_RGBA, N_("Determinator"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""}};
-static bNodeSocketTemplate cmp_node_bilateralblur_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void cmp_node_bilateralblur_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Color>(N_("Determinator")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
static void node_composit_init_bilateralblur(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -44,12 +49,25 @@ static void node_composit_init_bilateralblur(bNodeTree *UNUSED(ntree), bNode *no
nbbd->sigma_space = 5.0;
}
-void register_node_type_cmp_bilateralblur(void)
+static void node_composit_buts_bilateralblur(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "iterations", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "sigma_color", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "sigma_space", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_bilateralblur()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_BILATERALBLUR, "Bilateral Blur", NODE_CLASS_OP_FILTER, 0);
- node_type_socket_templates(&ntype, cmp_node_bilateralblur_in, cmp_node_bilateralblur_out);
+ ntype.declare = blender::nodes::cmp_node_bilateralblur_declare;
+ ntype.draw_buttons = node_composit_buts_bilateralblur;
node_type_init(&ntype, node_composit_init_bilateralblur);
node_type_storage(
&ntype, "NodeBilateralBlurData", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_blur.cc b/source/blender/nodes/composite/nodes/node_composite_blur.cc
index c5c0c21929e..bcc8c786ae5 100644
--- a/source/blender/nodes/composite/nodes/node_composite_blur.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_blur.cc
@@ -22,14 +22,25 @@
* \ingroup cmpnodes
*/
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** BLUR ******************** */
-static bNodeSocketTemplate cmp_node_blur_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_FLOAT, N_("Size"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE},
- {-1, ""}};
-static bNodeSocketTemplate cmp_node_blur_out[] = {{SOCK_RGBA, N_("Image")}, {-1, ""}};
+
+namespace blender::nodes {
+
+static void cmp_node_blur_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Size")).default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
static void node_composit_init_blur(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -38,12 +49,54 @@ static void node_composit_init_blur(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = data;
}
-void register_node_type_cmp_blur(void)
+static void node_composit_buts_blur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col, *row;
+
+ col = uiLayoutColumn(layout, false);
+ const int filter = RNA_enum_get(ptr, "filter_type");
+ const int reference = RNA_boolean_get(ptr, "use_variable_size");
+
+ uiItemR(col, ptr, "filter_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ if (filter != R_FILTER_FAST_GAUSS) {
+ uiItemR(col, ptr, "use_variable_size", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ if (!reference) {
+ uiItemR(col, ptr, "use_bokeh", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+ uiItemR(col, ptr, "use_gamma_correction", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+
+ uiItemR(col, ptr, "use_relative", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, 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_SPLIT_EMPTY_NAME | UI_ITEM_R_EXPAND,
+ nullptr,
+ ICON_NONE);
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "factor_x", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("X"), ICON_NONE);
+ uiItemR(col, ptr, "factor_y", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Y"), ICON_NONE);
+ }
+ else {
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "size_x", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("X"), ICON_NONE);
+ uiItemR(col, ptr, "size_y", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Y"), ICON_NONE);
+ }
+ uiItemR(col, ptr, "use_extended_bounds", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_blur()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_BLUR, "Blur", NODE_CLASS_OP_FILTER, NODE_PREVIEW);
- node_type_socket_templates(&ntype, cmp_node_blur_in, cmp_node_blur_out);
+ ntype.declare = blender::nodes::cmp_node_blur_declare;
+ ntype.draw_buttons = node_composit_buts_blur;
node_type_init(&ntype, node_composit_init_blur);
node_type_storage(
&ntype, "NodeBlurData", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc b/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc
index f130a642e20..d0659f6a51e 100644
--- a/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc
@@ -22,18 +22,25 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "../node_composite_util.hh"
/* **************** BLUR ******************** */
-static bNodeSocketTemplate cmp_node_bokehblur_in[] = {
- {SOCK_RGBA, N_("Image"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {SOCK_RGBA, N_("Bokeh"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Size"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 10.0f},
- {SOCK_FLOAT, N_("Bounding box"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f},
- {-1, ""}};
-static bNodeSocketTemplate cmp_node_bokehblur_out[] = {
- {SOCK_RGBA, N_("Image"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, {-1, ""}};
+namespace blender::nodes {
+
+static void cmp_node_bokehblur_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_input<decl::Color>(N_("Bokeh")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Size")).default_value(1.0f).min(0.0f).max(10.0f);
+ b.add_input<decl::Float>(N_("Bounding box")).default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
static void node_composit_init_bokehblur(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -41,12 +48,21 @@ static void node_composit_init_bokehblur(bNodeTree *UNUSED(ntree), bNode *node)
node->custom4 = 16.0f;
}
-void register_node_type_cmp_bokehblur(void)
+static void node_composit_buts_bokehblur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "use_variable_size", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ // uiItemR(layout, ptr, "f_stop", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); /* UNUSED */
+ uiItemR(layout, ptr, "blur_max", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "use_extended_bounds", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_bokehblur()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_BOKEHBLUR, "Bokeh Blur", NODE_CLASS_OP_FILTER, 0);
- node_type_socket_templates(&ntype, cmp_node_bokehblur_in, cmp_node_bokehblur_out);
+ ntype.declare = blender::nodes::cmp_node_bokehblur_declare;
+ ntype.draw_buttons = node_composit_buts_bokehblur;
node_type_init(&ntype, node_composit_init_bokehblur);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_bokehimage.cc b/source/blender/nodes/composite/nodes/node_composite_bokehimage.cc
index 3f8a7606d94..8817a07a422 100644
--- a/source/blender/nodes/composite/nodes/node_composite_bokehimage.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_bokehimage.cc
@@ -21,6 +21,9 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "../node_composite_util.hh"
/* **************** Bokeh image Tools ******************** */
@@ -45,12 +48,28 @@ static void node_composit_init_bokehimage(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = data;
}
-void register_node_type_cmp_bokehimage(void)
+static void node_composit_buts_bokehimage(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "flaps", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "angle", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(
+ layout, ptr, "rounding", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ uiItemR(layout,
+ ptr,
+ "catadioptric",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(layout, ptr, "shift", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_bokehimage()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_BOKEHIMAGE, "Bokeh Image", NODE_CLASS_INPUT, NODE_PREVIEW);
ntype.declare = blender::nodes::cmp_node_bokehimage_declare;
+ ntype.draw_buttons = node_composit_buts_bokehimage;
node_type_init(&ntype, node_composit_init_bokehimage);
node_type_storage(
&ntype, "NodeBokehImage", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_boxmask.cc b/source/blender/nodes/composite/nodes/node_composite_boxmask.cc
index cdf96065f97..40859922154 100644
--- a/source/blender/nodes/composite/nodes/node_composite_boxmask.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_boxmask.cc
@@ -21,16 +21,23 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "../node_composite_util.hh"
/* **************** SCALAR MATH ******************** */
-static bNodeSocketTemplate cmp_node_boxmask_in[] = {
- {SOCK_FLOAT, N_("Mask"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Value"), 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
- {-1, ""}};
-static bNodeSocketTemplate cmp_node_boxmask_out[] = {
- {SOCK_FLOAT, N_("Mask"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, {-1, ""}};
+namespace blender::nodes {
+
+static void cmp_node_boxmask_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Mask")).default_value(0.0f).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("Value")).default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_output<decl::Float>(N_("Mask"));
+}
+
+} // namespace blender::nodes
static void node_composit_init_boxmask(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -43,12 +50,29 @@ static void node_composit_init_boxmask(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = data;
}
-void register_node_type_cmp_boxmask(void)
+static void node_composit_buts_boxmask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *row;
+
+ row = uiLayoutRow(layout, true);
+ uiItemR(row, ptr, "x", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(row, ptr, "y", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ row = uiLayoutRow(layout, true);
+ uiItemR(row, ptr, "width", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ uiItemR(row, ptr, "height", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+
+ uiItemR(layout, ptr, "rotation", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "mask_type", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_boxmask()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_MASK_BOX, "Box Mask", NODE_CLASS_MATTE, 0);
- node_type_socket_templates(&ntype, cmp_node_boxmask_in, cmp_node_boxmask_out);
+ ntype.declare = blender::nodes::cmp_node_boxmask_declare;
+ ntype.draw_buttons = node_composit_buts_boxmask;
node_type_init(&ntype, node_composit_init_boxmask);
node_type_storage(&ntype, "NodeBoxMask", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_brightness.cc b/source/blender/nodes/composite/nodes/node_composite_brightness.cc
index 028afad3cf8..ca03a9b4fbf 100644
--- a/source/blender/nodes/composite/nodes/node_composite_brightness.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_brightness.cc
@@ -21,6 +21,9 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Bright and Contrast ******************** */
@@ -42,12 +45,20 @@ static void node_composit_init_brightcontrast(bNodeTree *UNUSED(ntree), bNode *n
node->custom1 = 1;
}
-void register_node_type_cmp_brightcontrast(void)
+static void node_composit_buts_brightcontrast(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "use_premultiply", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_brightcontrast()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_BRIGHTCONTRAST, "Bright/Contrast", NODE_CLASS_OP_COLOR, 0);
ntype.declare = blender::nodes::cmp_node_brightcontrast_declare;
+ ntype.draw_buttons = node_composit_buts_brightcontrast;
node_type_init(&ntype, node_composit_init_brightcontrast);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_channelMatte.cc b/source/blender/nodes/composite/nodes/node_composite_channelMatte.cc
index e211bc45b17..1b4be78c71b 100644
--- a/source/blender/nodes/composite/nodes/node_composite_channelMatte.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_channelMatte.cc
@@ -21,19 +21,25 @@
* \ingroup cmpnodes
*/
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* ******************* Channel Matte Node ********************************* */
-static bNodeSocketTemplate cmp_node_channel_matte_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_channel_matte_out[] = {
- {SOCK_RGBA, N_("Image")},
- {SOCK_FLOAT, N_("Matte")},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void cmp_node_channel_matte_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+ b.add_output<decl::Float>(N_("Matte"));
+}
+
+} // namespace blender::nodes
static void node_composit_init_channel_matte(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -50,13 +56,55 @@ static void node_composit_init_channel_matte(bNodeTree *UNUSED(ntree), bNode *no
node->custom2 = 2; /* Green Channel. */
}
-void register_node_type_cmp_channel_matte(void)
+static void node_composit_buts_channel_matte(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiLayout *col, *row;
+
+ uiItemL(layout, IFACE_("Color Space:"), ICON_NONE);
+ row = uiLayoutRow(layout, false);
+ uiItemR(
+ row, ptr, "color_space", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_EXPAND, nullptr, 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_SPLIT_EMPTY_NAME | UI_ITEM_R_EXPAND,
+ nullptr,
+ ICON_NONE);
+
+ col = uiLayoutColumn(layout, false);
+
+ uiItemR(col, ptr, "limit_method", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, 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_SPLIT_EMPTY_NAME | UI_ITEM_R_EXPAND,
+ nullptr,
+ ICON_NONE);
+ }
+
+ uiItemR(
+ col, ptr, "limit_max", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ uiItemR(
+ col, ptr, "limit_min", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_channel_matte()
{
static bNodeType ntype;
cmp_node_type_base(
&ntype, CMP_NODE_CHANNEL_MATTE, "Channel Key", NODE_CLASS_MATTE, NODE_PREVIEW);
- node_type_socket_templates(&ntype, cmp_node_channel_matte_in, cmp_node_channel_matte_out);
+ ntype.declare = blender::nodes::cmp_node_channel_matte_declare;
+ ntype.draw_buttons = node_composit_buts_channel_matte;
node_type_init(&ntype, node_composit_init_channel_matte);
node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_chromaMatte.cc b/source/blender/nodes/composite/nodes/node_composite_chromaMatte.cc
index 990778160df..a7e3a1c148f 100644
--- a/source/blender/nodes/composite/nodes/node_composite_chromaMatte.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_chromaMatte.cc
@@ -21,20 +21,24 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* ******************* Chroma Key ********************************************************** */
-static bNodeSocketTemplate cmp_node_chroma_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_RGBA, N_("Key Color"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
-
-static bNodeSocketTemplate cmp_node_chroma_out[] = {
- {SOCK_RGBA, N_("Image")},
- {SOCK_FLOAT, N_("Matte")},
- {-1, ""},
-};
+
+namespace blender::nodes {
+
+static void cmp_node_chroma_matte_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Color>(N_("Key Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+ b.add_output<decl::Float>(N_("Matte"));
+}
+
+} // namespace blender::nodes
static void node_composit_init_chroma_matte(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -47,12 +51,29 @@ static void node_composit_init_chroma_matte(bNodeTree *UNUSED(ntree), bNode *nod
c->fstrength = 1.0f;
}
-void register_node_type_cmp_chroma_matte(void)
+static void node_composit_buts_chroma_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, false);
+ uiItemR(col, ptr, "tolerance", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "threshold", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ col = uiLayoutColumn(layout, true);
+ /* Removed for now. */
+ // uiItemR(col, ptr, "lift", UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "gain", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ /* Removed for now. */
+ // uiItemR(col, ptr, "shadow_adjust", UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_chroma_matte()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_CHROMA_MATTE, "Chroma Key", NODE_CLASS_MATTE, NODE_PREVIEW);
- node_type_socket_templates(&ntype, cmp_node_chroma_in, cmp_node_chroma_out);
+ ntype.declare = blender::nodes::cmp_node_chroma_matte_declare;
+ ntype.draw_buttons = node_composit_buts_chroma_matte;
node_type_init(&ntype, node_composit_init_chroma_matte);
node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_colorMatte.cc b/source/blender/nodes/composite/nodes/node_composite_colorMatte.cc
index fc9a0075b14..367b046f3f6 100644
--- a/source/blender/nodes/composite/nodes/node_composite_colorMatte.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_colorMatte.cc
@@ -21,20 +21,24 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
-/* ******************* Color Key ********************************************************** */
-static bNodeSocketTemplate cmp_node_color_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_RGBA, N_("Key Color"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
+/* ******************* Color Matte ********************************************************** */
+
+namespace blender::nodes {
+
+static void cmp_node_color_matte_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Color>(N_("Key Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+ b.add_output<decl::Float>(N_("Matte"));
+}
-static bNodeSocketTemplate cmp_node_color_out[] = {
- {SOCK_RGBA, N_("Image")},
- {SOCK_FLOAT, N_("Matte")},
- {-1, ""},
-};
+} // namespace blender::nodes
static void node_composit_init_color_matte(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -47,12 +51,30 @@ static void node_composit_init_color_matte(bNodeTree *UNUSED(ntree), bNode *node
c->fstrength = 1.0f;
}
-void register_node_type_cmp_color_matte(void)
+static void node_composit_buts_color_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(
+ col, ptr, "color_hue", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ uiItemR(col,
+ ptr,
+ "color_saturation",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(
+ col, ptr, "color_value", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_color_matte()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_COLOR_MATTE, "Color Key", NODE_CLASS_MATTE, NODE_PREVIEW);
- node_type_socket_templates(&ntype, cmp_node_color_in, cmp_node_color_out);
+ ntype.declare = blender::nodes::cmp_node_color_matte_declare;
+ ntype.draw_buttons = node_composit_buts_color_matte;
node_type_init(&ntype, node_composit_init_color_matte);
node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_colorSpill.cc b/source/blender/nodes/composite/nodes/node_composite_colorSpill.cc
index 7bdc2e8289e..e136041cf6e 100644
--- a/source/blender/nodes/composite/nodes/node_composite_colorSpill.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_colorSpill.cc
@@ -21,19 +21,25 @@
* \ingroup cmpnodes
*/
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* ******************* Color Spill Suppression ********************************* */
-static bNodeSocketTemplate cmp_node_color_spill_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_FLOAT, N_("Fac"), 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_FACTOR},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_color_spill_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void cmp_node_color_spill_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Fac")).default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
static void node_composit_init_color_spill(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -46,12 +52,59 @@ static void node_composit_init_color_spill(bNodeTree *UNUSED(ntree), bNode *node
ncs->unspill = 0; /* do not use unspill */
}
-void register_node_type_cmp_color_spill(void)
+static void node_composit_buts_color_spill(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *row, *col;
+
+ uiItemL(layout, IFACE_("Despill Channel:"), ICON_NONE);
+ row = uiLayoutRow(layout, false);
+ uiItemR(row, ptr, "channel", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
+
+ col = uiLayoutColumn(layout, false);
+ uiItemR(col, ptr, "limit_method", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, 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_SPLIT_EMPTY_NAME | UI_ITEM_R_EXPAND,
+ nullptr,
+ ICON_NONE);
+ }
+
+ uiItemR(col, ptr, "ratio", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "use_unspill", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ if (RNA_boolean_get(ptr, "use_unspill") == true) {
+ uiItemR(col,
+ ptr,
+ "unspill_red",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(col,
+ ptr,
+ "unspill_green",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(col,
+ ptr,
+ "unspill_blue",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ }
+}
+
+void register_node_type_cmp_color_spill()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_COLOR_SPILL, "Color Spill", NODE_CLASS_MATTE, 0);
- node_type_socket_templates(&ntype, cmp_node_color_spill_in, cmp_node_color_spill_out);
+ ntype.declare = blender::nodes::cmp_node_color_spill_declare;
+ ntype.draw_buttons = node_composit_buts_color_spill;
node_type_init(&ntype, node_composit_init_color_spill);
node_type_storage(
&ntype, "NodeColorspill", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_colorbalance.cc b/source/blender/nodes/composite/nodes/node_composite_colorbalance.cc
index ef8af5f81a6..a35b3d813e6 100644
--- a/source/blender/nodes/composite/nodes/node_composite_colorbalance.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_colorbalance.cc
@@ -21,6 +21,11 @@
* \ingroup cmpnodes
*/
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* ******************* Color Balance ********************************* */
@@ -39,8 +44,7 @@ static void cmp_node_colorbalance_declare(NodeDeclarationBuilder &b)
/* Sync functions update formula parameters for other modes, such that the result is comparable.
* Note that the results are not exactly the same due to differences in color handling
* (sRGB conversion happens for LGG),
- * but this keeps settings comparable.
- */
+ * but this keeps settings comparable. */
void ntreeCompositColorBalanceSyncFromLGG(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -80,12 +84,88 @@ static void node_composit_init_colorbalance(bNodeTree *UNUSED(ntree), bNode *nod
node->storage = n;
}
-void register_node_type_cmp_colorbalance(void)
+static void node_composit_buts_colorbalance(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *split, *col, *row;
+
+ uiItemR(layout, ptr, "correction_method", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ if (RNA_enum_get(ptr, "correction_method") == 0) {
+
+ split = uiLayoutSplit(layout, 0.0f, false);
+ col = uiLayoutColumn(split, false);
+ uiTemplateColorPicker(col, ptr, "lift", true, true, false, true);
+ row = uiLayoutRow(col, false);
+ uiItemR(row, ptr, "lift", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ col = uiLayoutColumn(split, false);
+ uiTemplateColorPicker(col, ptr, "gamma", true, true, true, true);
+ row = uiLayoutRow(col, false);
+ uiItemR(row, ptr, "gamma", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ col = uiLayoutColumn(split, false);
+ uiTemplateColorPicker(col, ptr, "gain", true, true, true, true);
+ row = uiLayoutRow(col, false);
+ uiItemR(row, ptr, "gain", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+ else {
+
+ split = uiLayoutSplit(layout, 0.0f, false);
+ col = uiLayoutColumn(split, false);
+ uiTemplateColorPicker(col, ptr, "offset", true, true, false, true);
+ row = uiLayoutRow(col, false);
+ uiItemR(row, ptr, "offset", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "offset_basis", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ col = uiLayoutColumn(split, false);
+ uiTemplateColorPicker(col, ptr, "power", true, true, false, true);
+ row = uiLayoutRow(col, false);
+ uiItemR(row, ptr, "power", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ col = uiLayoutColumn(split, false);
+ uiTemplateColorPicker(col, ptr, "slope", true, true, false, true);
+ row = uiLayoutRow(col, false);
+ uiItemR(row, ptr, "slope", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+}
+
+static void node_composit_buts_colorbalance_ex(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "correction_method", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ if (RNA_enum_get(ptr, "correction_method") == 0) {
+
+ uiTemplateColorPicker(layout, ptr, "lift", true, true, false, true);
+ uiItemR(layout, ptr, "lift", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ uiTemplateColorPicker(layout, ptr, "gamma", true, true, true, true);
+ uiItemR(layout, ptr, "gamma", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ uiTemplateColorPicker(layout, ptr, "gain", true, true, true, true);
+ uiItemR(layout, ptr, "gain", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+ else {
+ uiTemplateColorPicker(layout, ptr, "offset", true, true, false, true);
+ uiItemR(layout, ptr, "offset", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ uiTemplateColorPicker(layout, ptr, "power", true, true, false, true);
+ uiItemR(layout, ptr, "power", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ uiTemplateColorPicker(layout, ptr, "slope", true, true, false, true);
+ uiItemR(layout, ptr, "slope", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+}
+
+void register_node_type_cmp_colorbalance()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_COLORBALANCE, "Color Balance", NODE_CLASS_OP_COLOR, 0);
ntype.declare = blender::nodes::cmp_node_colorbalance_declare;
+ ntype.draw_buttons = node_composit_buts_colorbalance;
+ ntype.draw_buttons_ex = node_composit_buts_colorbalance_ex;
node_type_size(&ntype, 400, 200, 400);
node_type_init(&ntype, node_composit_init_colorbalance);
node_type_storage(
diff --git a/source/blender/nodes/composite/nodes/node_composite_colorcorrection.cc b/source/blender/nodes/composite/nodes/node_composite_colorcorrection.cc
index 095fbef826a..e3bba3b6c4f 100644
--- a/source/blender/nodes/composite/nodes/node_composite_colorcorrection.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_colorcorrection.cc
@@ -21,6 +21,9 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* ******************* Color Correction ********************************* */
@@ -66,12 +69,230 @@ static void node_composit_init_colorcorrection(bNodeTree *UNUSED(ntree), bNode *
node->storage = n;
}
-void register_node_type_cmp_colorcorrection(void)
+static void node_composit_buts_colorcorrection(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiLayout *row;
+
+ row = uiLayoutRow(layout, false);
+ uiItemR(row, ptr, "red", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(row, ptr, "green", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(row, ptr, "blue", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ row = uiLayoutRow(layout, false);
+ uiItemL(row, "", ICON_NONE);
+ uiItemL(row, IFACE_("Saturation"), ICON_NONE);
+ uiItemL(row, IFACE_("Contrast"), ICON_NONE);
+ uiItemL(row, IFACE_("Gamma"), ICON_NONE);
+ uiItemL(row, IFACE_("Gain"), ICON_NONE);
+ uiItemL(row, IFACE_("Lift"), ICON_NONE);
+
+ row = uiLayoutRow(layout, false);
+ uiItemL(row, IFACE_("Master"), ICON_NONE);
+ uiItemR(
+ row, ptr, "master_saturation", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(
+ row, ptr, "master_contrast", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "master_gamma", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "master_gain", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "master_lift", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE);
+
+ row = uiLayoutRow(layout, false);
+ uiItemL(row, IFACE_("Highlights"), ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "highlights_saturation",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ "",
+ ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "highlights_contrast",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ "",
+ ICON_NONE);
+ uiItemR(
+ row, ptr, "highlights_gamma", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(
+ row, ptr, "highlights_gain", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(
+ row, ptr, "highlights_lift", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE);
+
+ row = uiLayoutRow(layout, false);
+ uiItemL(row, IFACE_("Midtones"), ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "midtones_saturation",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ "",
+ ICON_NONE);
+ uiItemR(
+ row, ptr, "midtones_contrast", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(
+ row, ptr, "midtones_gamma", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "midtones_gain", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "midtones_lift", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE);
+
+ row = uiLayoutRow(layout, false);
+ uiItemL(row, IFACE_("Shadows"), ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "shadows_saturation",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ "",
+ ICON_NONE);
+ uiItemR(
+ row, ptr, "shadows_contrast", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "shadows_gamma", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "shadows_gain", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "shadows_lift", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE);
+
+ row = uiLayoutRow(layout, false);
+ uiItemR(row,
+ ptr,
+ "midtones_start",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(
+ row, ptr, "midtones_end", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+}
+
+static void node_composit_buts_colorcorrection_ex(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiLayout *row;
+
+ row = uiLayoutRow(layout, false);
+ uiItemR(row, ptr, "red", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(row, ptr, "green", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(row, ptr, "blue", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ row = layout;
+ uiItemL(row, IFACE_("Saturation"), ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "master_saturation",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "highlights_saturation",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "midtones_saturation",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "shadows_saturation",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+
+ uiItemL(row, IFACE_("Contrast"), ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "master_contrast",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "highlights_contrast",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "midtones_contrast",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "shadows_contrast",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+
+ uiItemL(row, IFACE_("Gamma"), ICON_NONE);
+ uiItemR(
+ row, ptr, "master_gamma", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "highlights_gamma",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "midtones_gamma",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "shadows_gamma",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+
+ uiItemL(row, IFACE_("Gain"), ICON_NONE);
+ uiItemR(
+ row, ptr, "master_gain", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "highlights_gain",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "midtones_gain",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(
+ row, ptr, "shadows_gain", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+
+ uiItemL(row, IFACE_("Lift"), ICON_NONE);
+ uiItemR(
+ row, ptr, "master_lift", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "highlights_lift",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "midtones_lift",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(
+ row, ptr, "shadows_lift", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+
+ row = uiLayoutRow(layout, false);
+ uiItemR(row, ptr, "midtones_start", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(row, ptr, "midtones_end", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_colorcorrection()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_COLORCORRECTION, "Color Correction", NODE_CLASS_OP_COLOR, 0);
ntype.declare = blender::nodes::cmp_node_colorcorrection_declare;
+ ntype.draw_buttons = node_composit_buts_colorcorrection;
+ ntype.draw_buttons_ex = node_composit_buts_colorcorrection_ex;
node_type_size(&ntype, 400, 200, 600);
node_type_init(&ntype, node_composit_init_colorcorrection);
node_type_storage(
diff --git a/source/blender/nodes/composite/nodes/node_composite_common.cc b/source/blender/nodes/composite/nodes/node_composite_common.cc
index 6432a89ffa0..aa81cecc3e2 100644
--- a/source/blender/nodes/composite/nodes/node_composite_common.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_common.cc
@@ -32,14 +32,13 @@
#include "RNA_access.h"
-void register_node_type_cmp_group(void)
+void register_node_type_cmp_group()
{
static bNodeType ntype;
/* NOTE: Cannot use sh_node_type_base for node group, because it would map the node type
* to the shared NODE_GROUP integer type id. */
- node_type_base_custom(
- &ntype, "CompositorNodeGroup", "Group", NODE_CLASS_GROUP, NODE_CONST_OUTPUT);
+ node_type_base_custom(&ntype, "CompositorNodeGroup", "Group", NODE_CLASS_GROUP, 0);
ntype.type = NODE_GROUP;
ntype.poll = cmp_node_poll_default;
ntype.poll_instance = node_group_poll_instance;
@@ -50,7 +49,7 @@ void register_node_type_cmp_group(void)
node_type_socket_templates(&ntype, nullptr, nullptr);
node_type_size(&ntype, 140, 60, 400);
- node_type_label(&ntype, node_group_label);
+ ntype.labelfunc = node_group_label;
node_type_group_update(&ntype, node_group_update);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_composite.cc b/source/blender/nodes/composite/nodes/node_composite_composite.cc
index a1a49133a3a..547e5123579 100644
--- a/source/blender/nodes/composite/nodes/node_composite_composite.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_composite.cc
@@ -21,6 +21,9 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** COMPOSITE ******************** */
@@ -36,13 +39,18 @@ static void cmp_node_composite_declare(NodeDeclarationBuilder &b)
} // namespace blender::nodes
-void register_node_type_cmp_composite(void)
+static void node_composit_buts_composite(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "use_alpha", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_composite()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_COMPOSITE, "Composite", NODE_CLASS_OUTPUT, NODE_PREVIEW);
ntype.declare = blender::nodes::cmp_node_composite_declare;
-
+ ntype.draw_buttons = node_composit_buts_composite;
ntype.no_muting = true;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_cornerpin.cc b/source/blender/nodes/composite/nodes/node_composite_cornerpin.cc
index b5ca1fb015e..2e7a87a576d 100644
--- a/source/blender/nodes/composite/nodes/node_composite_cornerpin.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_cornerpin.cc
@@ -23,27 +23,39 @@
#include "node_composite_util.hh"
-static bNodeSocketTemplate inputs[] = {
- {SOCK_RGBA, N_("Image"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {SOCK_VECTOR, N_("Upper Left"), 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {SOCK_VECTOR, N_("Upper Right"), 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {SOCK_VECTOR, N_("Lower Left"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {SOCK_VECTOR, N_("Lower Right"), 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {-1, ""},
-};
-
-static bNodeSocketTemplate outputs[] = {
- {SOCK_RGBA, N_("Image")},
- {SOCK_FLOAT, N_("Plane")},
- {-1, ""},
-};
-
-void register_node_type_cmp_cornerpin(void)
+namespace blender::nodes {
+
+static void cmp_node_cornerpin_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Vector>(N_("Upper Left"))
+ .default_value({0.0f, 1.0f, 0.0f})
+ .min(0.0f)
+ .max(1.0f);
+ b.add_input<decl::Vector>(N_("Upper Right"))
+ .default_value({1.0f, 1.0f, 0.0f})
+ .min(0.0f)
+ .max(1.0f);
+ b.add_input<decl::Vector>(N_("Lower Left"))
+ .default_value({0.0f, 0.0f, 0.0f})
+ .min(0.0f)
+ .max(1.0f);
+ b.add_input<decl::Vector>(N_("Lower Right"))
+ .default_value({1.0f, 0.0f, 0.0f})
+ .min(0.0f)
+ .max(1.0f);
+ b.add_output<decl::Color>(N_("Image"));
+ b.add_output<decl::Float>(N_("Plane"));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_cmp_cornerpin()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_CORNERPIN, "Corner Pin", NODE_CLASS_DISTORT, 0);
- node_type_socket_templates(&ntype, inputs, outputs);
+ ntype.declare = blender::nodes::cmp_node_cornerpin_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_crop.cc b/source/blender/nodes/composite/nodes/node_composite_crop.cc
index f07dba8a74b..fa33caa4c0e 100644
--- a/source/blender/nodes/composite/nodes/node_composite_crop.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_crop.cc
@@ -21,18 +21,24 @@
* \ingroup cmpnodes
*/
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Crop ******************** */
-static bNodeSocketTemplate cmp_node_crop_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_crop_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void cmp_node_crop_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
static void node_composit_init_crop(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -44,12 +50,35 @@ static void node_composit_init_crop(bNodeTree *UNUSED(ntree), bNode *node)
nxy->y2 = 0;
}
-void register_node_type_cmp_crop(void)
+static void node_composit_buts_crop(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ uiItemR(layout, ptr, "use_crop_size", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "relative", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ col = uiLayoutColumn(layout, true);
+ if (RNA_boolean_get(ptr, "relative")) {
+ uiItemR(col, ptr, "rel_min_x", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Left"), ICON_NONE);
+ uiItemR(col, ptr, "rel_max_x", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Right"), ICON_NONE);
+ uiItemR(col, ptr, "rel_min_y", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Up"), ICON_NONE);
+ uiItemR(col, ptr, "rel_max_y", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Down"), ICON_NONE);
+ }
+ else {
+ uiItemR(col, ptr, "min_x", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Left"), ICON_NONE);
+ uiItemR(col, ptr, "max_x", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Right"), ICON_NONE);
+ uiItemR(col, ptr, "min_y", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Up"), ICON_NONE);
+ uiItemR(col, ptr, "max_y", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Down"), ICON_NONE);
+ }
+}
+
+void register_node_type_cmp_crop()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_CROP, "Crop", NODE_CLASS_DISTORT, 0);
- node_type_socket_templates(&ntype, cmp_node_crop_in, cmp_node_crop_out);
+ ntype.declare = blender::nodes::cmp_node_crop_declare;
+ ntype.draw_buttons = node_composit_buts_crop;
node_type_init(&ntype, node_composit_init_crop);
node_type_storage(&ntype, "NodeTwoXYs", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc
index 6657267b016..65b1f6799d7 100644
--- a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc
@@ -38,8 +38,10 @@
#include <optional>
+/* -------------------------------------------------------------------- */
/** \name Cryptomatte
* \{ */
+
static blender::bke::cryptomatte::CryptomatteSessionPtr cryptomatte_init_from_node_render(
const bNode &node, const bool use_meta_data)
{
@@ -297,16 +299,16 @@ static bool node_poll_cryptomatte(bNodeType *UNUSED(ntype),
}
if (scene == nullptr) {
- *r_disabled_hint =
- "The node tree must be the compositing node tree of any scene in the file";
+ *r_disabled_hint = TIP_(
+ "The node tree must be the compositing node tree of any scene in the file");
}
return scene != nullptr;
}
- *r_disabled_hint = "Not a compositor node tree";
+ *r_disabled_hint = TIP_("Not a compositor node tree");
return false;
}
-void register_node_type_cmp_cryptomatte(void)
+void register_node_type_cmp_cryptomatte()
{
static bNodeType ntype;
@@ -322,8 +324,10 @@ void register_node_type_cmp_cryptomatte(void)
/** \} */
+/* -------------------------------------------------------------------- */
/** \name Cryptomatte Legacy
* \{ */
+
static void node_init_cryptomatte_legacy(bNodeTree *ntree, bNode *node)
{
node_init_cryptomatte(ntree, node);
@@ -361,7 +365,7 @@ int ntreeCompositCryptomatteRemoveSocket(bNodeTree *ntree, bNode *node)
return 1;
}
-void register_node_type_cmp_cryptomatte_legacy(void)
+void register_node_type_cmp_cryptomatte_legacy()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/composite/nodes/node_composite_curves.cc b/source/blender/nodes/composite/nodes/node_composite_curves.cc
index 5f99bb57768..518b57dc405 100644
--- a/source/blender/nodes/composite/nodes/node_composite_curves.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_curves.cc
@@ -21,6 +21,9 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** CURVE Time ******************** */
@@ -42,7 +45,7 @@ static void node_composit_init_curves_time(bNodeTree *UNUSED(ntree), bNode *node
node->storage = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
}
-void register_node_type_cmp_curve_time(void)
+void register_node_type_cmp_curve_time()
{
static bNodeType ntype;
@@ -56,27 +59,34 @@ void register_node_type_cmp_curve_time(void)
}
/* **************** CURVE VEC ******************** */
-static bNodeSocketTemplate cmp_node_curve_vec_in[] = {
- {SOCK_VECTOR, N_("Vector"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_curve_vec_out[] = {
- {SOCK_VECTOR, N_("Vector")},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void cmp_node_curve_vec_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Vector>(N_("Vector")).default_value({0.0f, 0.0f, 0.0f}).min(-1.0f).max(1.0f);
+ b.add_output<decl::Vector>(N_("Vector"));
+}
+
+} // namespace blender::nodes
static void node_composit_init_curve_vec(bNodeTree *UNUSED(ntree), bNode *node)
{
node->storage = BKE_curvemapping_add(3, -1.0f, -1.0f, 1.0f, 1.0f);
}
-void register_node_type_cmp_curve_vec(void)
+static void node_buts_curvevec(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiTemplateCurveMapping(layout, ptr, "mapping", 'v', false, false, false, false);
+}
+
+void register_node_type_cmp_curve_vec()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_CURVE_VEC, "Vector Curves", NODE_CLASS_OP_VECTOR, 0);
- node_type_socket_templates(&ntype, cmp_node_curve_vec_in, cmp_node_curve_vec_out);
+ ntype.declare = blender::nodes::cmp_node_curve_vec_declare;
+ ntype.draw_buttons = node_buts_curvevec;
node_type_size(&ntype, 200, 140, 320);
node_type_init(&ntype, node_composit_init_curve_vec);
node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves);
@@ -105,7 +115,7 @@ static void node_composit_init_curve_rgb(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = BKE_curvemapping_add(4, 0.0f, 0.0f, 1.0f, 1.0f);
}
-void register_node_type_cmp_curve_rgb(void)
+void register_node_type_cmp_curve_rgb()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/composite/nodes/node_composite_defocus.cc b/source/blender/nodes/composite/nodes/node_composite_defocus.cc
index 1103aff4366..0ee8a8da1e8 100644
--- a/source/blender/nodes/composite/nodes/node_composite_defocus.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_defocus.cc
@@ -21,20 +21,27 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.hh"
-
#include <climits>
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_composite_util.hh"
+
/* ************ Defocus Node ****************** */
-static bNodeSocketTemplate cmp_node_defocus_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_FLOAT, N_("Z"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_defocus_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+
+namespace blender::nodes {
+
+static void cmp_node_defocus_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Z")).default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
static void node_composit_init_defocus(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -53,12 +60,52 @@ static void node_composit_init_defocus(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = nbd;
}
-void register_node_type_cmp_defocus(void)
+static void node_composit_buts_defocus(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ uiLayout *sub, *col;
+
+ col = uiLayoutColumn(layout, false);
+ uiItemL(col, IFACE_("Bokeh Type:"), ICON_NONE);
+ uiItemR(col, ptr, "bokeh", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ uiItemR(col, ptr, "angle", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ uiItemR(layout, ptr, "use_gamma_correction", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ col = uiLayoutColumn(layout, false);
+ uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_zbuffer") == true);
+ uiItemR(col, ptr, "f_stop", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ uiItemR(layout, ptr, "blur_max", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "threshold", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ col = uiLayoutColumn(layout, false);
+ uiItemR(col, ptr, "use_preview", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ uiTemplateID(layout,
+ C,
+ ptr,
+ "scene",
+ nullptr,
+ nullptr,
+ nullptr,
+ UI_TEMPLATE_ID_FILTER_ALL,
+ false,
+ nullptr);
+
+ col = uiLayoutColumn(layout, false);
+ uiItemR(col, ptr, "use_zbuffer", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ sub = uiLayoutColumn(col, false);
+ uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_zbuffer") == false);
+ uiItemR(sub, ptr, "z_scale", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_defocus()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_DEFOCUS, "Defocus", NODE_CLASS_OP_FILTER, 0);
- node_type_socket_templates(&ntype, cmp_node_defocus_in, cmp_node_defocus_out);
+ ntype.declare = blender::nodes::cmp_node_defocus_declare;
+ ntype.draw_buttons = node_composit_buts_defocus;
node_type_init(&ntype, node_composit_init_defocus);
node_type_storage(&ntype, "NodeDefocus", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_denoise.cc b/source/blender/nodes/composite/nodes/node_composite_denoise.cc
index ec085794462..f1e5388a7a3 100644
--- a/source/blender/nodes/composite/nodes/node_composite_denoise.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_denoise.cc
@@ -23,14 +23,26 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
-static bNodeSocketTemplate cmp_node_denoise_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f},
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {SOCK_RGBA, N_("Albedo"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {-1, ""}};
-static bNodeSocketTemplate cmp_node_denoise_out[] = {{SOCK_RGBA, N_("Image")}, {-1, ""}};
+namespace blender::nodes {
+
+static void cmp_node_denoise_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Vector>(N_("Normal"))
+ .default_value({0.0f, 0.0f, 0.0f})
+ .min(-1.0f)
+ .max(1.0f)
+ .hide_value();
+ b.add_input<decl::Color>(N_("Albedo")).default_value({1.0f, 1.0f, 1.0f, 1.0f}).hide_value();
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
static void node_composit_init_denonise(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -40,12 +52,31 @@ static void node_composit_init_denonise(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = ndg;
}
-void register_node_type_cmp_denoise(void)
+static void node_composit_buts_denoise(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+#ifndef WITH_OPENIMAGEDENOISE
+ uiItemL(layout, IFACE_("Disabled, built without OpenImageDenoise"), ICON_ERROR);
+#else
+ /* Always supported through Accelerate framework BNNS on macOS. */
+# ifndef __APPLE__
+ if (!BLI_cpu_support_sse41()) {
+ uiItemL(layout, IFACE_("Disabled, CPU with SSE4.1 is required"), ICON_ERROR);
+ }
+# endif
+#endif
+
+ uiItemL(layout, IFACE_("Prefilter:"), ICON_NONE);
+ uiItemR(layout, ptr, "prefilter", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "use_hdr", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_denoise()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_DENOISE, "Denoise", NODE_CLASS_OP_FILTER, 0);
- node_type_socket_templates(&ntype, cmp_node_denoise_in, cmp_node_denoise_out);
+ ntype.declare = blender::nodes::cmp_node_denoise_declare;
+ ntype.draw_buttons = node_composit_buts_denoise;
node_type_init(&ntype, node_composit_init_denonise);
node_type_storage(&ntype, "NodeDenoise", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_despeckle.cc b/source/blender/nodes/composite/nodes/node_composite_despeckle.cc
index 52d91dabeb1..411bad14f25 100644
--- a/source/blender/nodes/composite/nodes/node_composite_despeckle.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_despeckle.cc
@@ -21,18 +21,23 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** FILTER ******************** */
-static bNodeSocketTemplate cmp_node_despeckle_in[] = {
- {SOCK_FLOAT, N_("Fac"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_despeckle_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+
+namespace blender::nodes {
+
+static void cmp_node_despeckle_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Fac")).default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
static void node_composit_init_despeckle(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -40,12 +45,22 @@ static void node_composit_init_despeckle(bNodeTree *UNUSED(ntree), bNode *node)
node->custom4 = 0.5f;
}
-void register_node_type_cmp_despeckle(void)
+static void node_composit_buts_despeckle(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, false);
+ uiItemR(col, ptr, "threshold", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "threshold_neighbor", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_despeckle()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_DESPECKLE, "Despeckle", NODE_CLASS_OP_FILTER, NODE_PREVIEW);
- node_type_socket_templates(&ntype, cmp_node_despeckle_in, cmp_node_despeckle_out);
+ ntype.declare = blender::nodes::cmp_node_despeckle_declare;
+ ntype.draw_buttons = node_composit_buts_despeckle;
node_type_init(&ntype, node_composit_init_despeckle);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_diffMatte.cc b/source/blender/nodes/composite/nodes/node_composite_diffMatte.cc
index 1e1a48381b7..a9e3258c8fb 100644
--- a/source/blender/nodes/composite/nodes/node_composite_diffMatte.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_diffMatte.cc
@@ -21,20 +21,24 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* ******************* channel Difference Matte ********************************* */
-static bNodeSocketTemplate cmp_node_diff_matte_in[] = {
- {SOCK_RGBA, N_("Image 1"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_RGBA, N_("Image 2"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
-
-static bNodeSocketTemplate cmp_node_diff_matte_out[] = {
- {SOCK_RGBA, N_("Image")},
- {SOCK_FLOAT, N_("Matte")},
- {-1, ""},
-};
+
+namespace blender::nodes {
+
+static void cmp_node_diff_matte_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image 1")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Color>(N_("Image 2")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+ b.add_output<decl::Color>(N_("Matte"));
+}
+
+} // namespace blender::nodes
static void node_composit_init_diff_matte(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -44,13 +48,24 @@ static void node_composit_init_diff_matte(bNodeTree *UNUSED(ntree), bNode *node)
c->t2 = 0.1f;
}
-void register_node_type_cmp_diff_matte(void)
+static void node_composit_buts_diff_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(
+ col, ptr, "tolerance", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "falloff", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_diff_matte()
{
static bNodeType ntype;
cmp_node_type_base(
&ntype, CMP_NODE_DIFF_MATTE, "Difference Key", NODE_CLASS_MATTE, NODE_PREVIEW);
- node_type_socket_templates(&ntype, cmp_node_diff_matte_in, cmp_node_diff_matte_out);
+ ntype.declare = blender::nodes::cmp_node_diff_matte_declare;
+ ntype.draw_buttons = node_composit_buts_diff_matte;
node_type_init(&ntype, node_composit_init_diff_matte);
node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_dilate.cc b/source/blender/nodes/composite/nodes/node_composite_dilate.cc
index 57884a299da..1af2bb0433b 100644
--- a/source/blender/nodes/composite/nodes/node_composite_dilate.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_dilate.cc
@@ -21,13 +21,24 @@
* \ingroup cmpnodes
*/
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Dilate/Erode ******************** */
-static bNodeSocketTemplate cmp_node_dilateerode_in[] = {
- {SOCK_FLOAT, N_("Mask"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE}, {-1, ""}};
-static bNodeSocketTemplate cmp_node_dilateerode_out[] = {{SOCK_FLOAT, N_("Mask")}, {-1, ""}};
+namespace blender::nodes {
+
+static void cmp_node_dilate_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Mask")).default_value(0.0f).min(0.0f).max(1.0f);
+ b.add_output<decl::Float>(N_("Mask"));
+}
+
+} // namespace blender::nodes
static void node_composit_init_dilateerode(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -37,12 +48,27 @@ static void node_composit_init_dilateerode(bNodeTree *UNUSED(ntree), bNode *node
node->storage = data;
}
-void register_node_type_cmp_dilateerode(void)
+static void node_composit_buts_dilateerode(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "mode", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "distance", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ switch (RNA_enum_get(ptr, "mode")) {
+ case CMP_NODE_DILATEERODE_DISTANCE_THRESH:
+ uiItemR(layout, ptr, "edge", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ break;
+ case CMP_NODE_DILATEERODE_DISTANCE_FEATHER:
+ uiItemR(layout, ptr, "falloff", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ break;
+ }
+}
+
+void register_node_type_cmp_dilateerode()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_DILATEERODE, "Dilate/Erode", NODE_CLASS_OP_FILTER, 0);
- node_type_socket_templates(&ntype, cmp_node_dilateerode_in, cmp_node_dilateerode_out);
+ ntype.draw_buttons = node_composit_buts_dilateerode;
+ ntype.declare = blender::nodes::cmp_node_dilate_declare;
node_type_init(&ntype, node_composit_init_dilateerode);
node_type_storage(
&ntype, "NodeDilateErode", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_directionalblur.cc b/source/blender/nodes/composite/nodes/node_composite_directionalblur.cc
index d9f82ba5009..36b130d55a4 100644
--- a/source/blender/nodes/composite/nodes/node_composite_directionalblur.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_directionalblur.cc
@@ -21,12 +21,20 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
-static bNodeSocketTemplate cmp_node_dblur_in[] = {{SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""}};
+namespace blender::nodes {
+
+static void cmp_node_directional_blur_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+}
-static bNodeSocketTemplate cmp_node_dblur_out[] = {{SOCK_RGBA, N_("Image")}, {-1, ""}};
+} // namespace blender::nodes
static void node_composit_init_dblur(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -37,12 +45,37 @@ static void node_composit_init_dblur(bNodeTree *UNUSED(ntree), bNode *node)
ndbd->center_y = 0.5;
}
-void register_node_type_cmp_dblur(void)
+static void node_composit_buts_dblur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ uiItemR(layout, ptr, "iterations", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "use_wrap", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ col = uiLayoutColumn(layout, true);
+ uiItemL(col, IFACE_("Center:"), ICON_NONE);
+ uiItemR(col, ptr, "center_x", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("X"), ICON_NONE);
+ uiItemR(col, ptr, "center_y", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Y"), ICON_NONE);
+
+ uiItemS(layout);
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "distance", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "angle", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ uiItemS(layout);
+
+ uiItemR(layout, ptr, "spin", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "zoom", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_dblur()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_DBLUR, "Directional Blur", NODE_CLASS_OP_FILTER, 0);
- node_type_socket_templates(&ntype, cmp_node_dblur_in, cmp_node_dblur_out);
+ ntype.declare = blender::nodes::cmp_node_directional_blur_declare;
+ ntype.draw_buttons = node_composit_buts_dblur;
node_type_init(&ntype, node_composit_init_dblur);
node_type_storage(
&ntype, "NodeDBlurData", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_displace.cc b/source/blender/nodes/composite/nodes/node_composite_displace.cc
index b1ed7f05794..0137c1f7da8 100644
--- a/source/blender/nodes/composite/nodes/node_composite_displace.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_displace.cc
@@ -25,24 +25,29 @@
/* **************** Displace ******************** */
-static bNodeSocketTemplate cmp_node_displace_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_VECTOR, N_("Vector"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_TRANSLATION},
- {SOCK_FLOAT, N_("X Scale"), 0.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f, PROP_NONE},
- {SOCK_FLOAT, N_("Y Scale"), 0.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f, PROP_NONE},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_displace_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
-
-void register_node_type_cmp_displace(void)
+namespace blender::nodes {
+
+static void cmp_node_displace_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Vector>(N_("Vector"))
+ .default_value({1.0f, 1.0f, 1.0f})
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_TRANSLATION);
+ b.add_input<decl::Float>(N_("X Scale")).default_value(0.0f).min(-1000.0f).max(1000.0f);
+ b.add_input<decl::Float>(N_("Y Scale")).default_value(0.0f).min(-1000.0f).max(1000.0f);
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_cmp_displace()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_DISPLACE, "Displace", NODE_CLASS_DISTORT, 0);
- node_type_socket_templates(&ntype, cmp_node_displace_in, cmp_node_displace_out);
+ ntype.declare = blender::nodes::cmp_node_displace_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_distanceMatte.cc b/source/blender/nodes/composite/nodes/node_composite_distanceMatte.cc
index 3f8767ecd08..47a48ed141e 100644
--- a/source/blender/nodes/composite/nodes/node_composite_distanceMatte.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_distanceMatte.cc
@@ -21,20 +21,24 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* ******************* channel Distance Matte ********************************* */
-static bNodeSocketTemplate cmp_node_distance_matte_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_RGBA, N_("Key Color"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
-
-static bNodeSocketTemplate cmp_node_distance_matte_out[] = {
- {SOCK_RGBA, N_("Image")},
- {SOCK_FLOAT, N_("Matte")},
- {-1, ""},
-};
+
+namespace blender::nodes {
+
+static void cmp_node_distance_matte_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Color>(N_("Key Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+ b.add_output<decl::Float>(N_("Matte"));
+}
+
+} // namespace blender::nodes
static void node_composit_init_distance_matte(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -45,12 +49,30 @@ static void node_composit_init_distance_matte(bNodeTree *UNUSED(ntree), bNode *n
c->t2 = 0.1f;
}
-void register_node_type_cmp_distance_matte(void)
+static void node_composit_buts_distance_matte(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiLayout *col, *row;
+
+ col = uiLayoutColumn(layout, true);
+
+ uiItemL(layout, IFACE_("Color Space:"), ICON_NONE);
+ row = uiLayoutRow(layout, false);
+ uiItemR(row, ptr, "channel", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
+
+ uiItemR(
+ col, ptr, "tolerance", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "falloff", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_distance_matte()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_DIST_MATTE, "Distance Key", NODE_CLASS_MATTE, NODE_PREVIEW);
- node_type_socket_templates(&ntype, cmp_node_distance_matte_in, cmp_node_distance_matte_out);
+ ntype.declare = blender::nodes::cmp_node_distance_matte_declare;
+ ntype.draw_buttons = node_composit_buts_distance_matte;
node_type_init(&ntype, node_composit_init_distance_matte);
node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_doubleEdgeMask.cc b/source/blender/nodes/composite/nodes/node_composite_doubleEdgeMask.cc
index 7c9a48efc2d..4fde539e6fb 100644
--- a/source/blender/nodes/composite/nodes/node_composite_doubleEdgeMask.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_doubleEdgeMask.cc
@@ -20,31 +20,46 @@
/** \file
* \ingroup cmpnodes
*/
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
+
/* **************** Double Edge Mask ******************** */
-static bNodeSocketTemplate cmp_node_doubleedgemask_in[] = {
- /* Inner mask socket definition. */
- {SOCK_FLOAT, "Inner Mask", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- /* Outer mask socket definition. */
- {SOCK_FLOAT, "Outer Mask", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- /* Input socket array terminator. */
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_doubleedgemask_out[] = {
- /* Output socket definition. */
- {SOCK_FLOAT, "Mask"},
- /* Output socket array terminator. */
- {-1, ""},
-};
-
-void register_node_type_cmp_doubleedgemask(void)
+namespace blender::nodes {
+
+static void cmp_node_double_edge_mask_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Inner Mask")).default_value(0.8f).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("Outer Mask")).default_value(0.8f).min(0.0f).max(1.0f);
+ b.add_output<decl::Float>(N_("Mask"));
+}
+
+} // namespace blender::nodes
+
+static void node_composit_buts_double_edge_mask(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, false);
+
+ uiItemL(col, IFACE_("Inner Edge:"), ICON_NONE);
+ uiItemR(col, ptr, "inner_mode", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ uiItemL(col, IFACE_("Buffer Edge:"), ICON_NONE);
+ uiItemR(col, ptr, "edge_mode", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
+
+void register_node_type_cmp_doubleedgemask()
{
static bNodeType ntype; /* Allocate a node type data structure. */
cmp_node_type_base(&ntype, CMP_NODE_DOUBLEEDGEMASK, "Double Edge Mask", NODE_CLASS_MATTE, 0);
- node_type_socket_templates(&ntype, cmp_node_doubleedgemask_in, cmp_node_doubleedgemask_out);
- node_type_socket_templates(&ntype, cmp_node_doubleedgemask_in, cmp_node_doubleedgemask_out);
+ ntype.declare = blender::nodes::cmp_node_double_edge_mask_declare;
+ ntype.draw_buttons = node_composit_buts_double_edge_mask;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_ellipsemask.cc b/source/blender/nodes/composite/nodes/node_composite_ellipsemask.cc
index 67196fb0d35..8eb89e53790 100644
--- a/source/blender/nodes/composite/nodes/node_composite_ellipsemask.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_ellipsemask.cc
@@ -21,16 +21,23 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "../node_composite_util.hh"
/* **************** SCALAR MATH ******************** */
-static bNodeSocketTemplate cmp_node_ellipsemask_in[] = {
- {SOCK_FLOAT, N_("Mask"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Value"), 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
- {-1, ""}};
-static bNodeSocketTemplate cmp_node_ellipsemask_out[] = {
- {SOCK_FLOAT, N_("Mask"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, {-1, ""}};
+namespace blender::nodes {
+
+static void cmp_node_ellipsemask_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Mask")).default_value(0.0f).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("Value")).default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_output<decl::Float>(N_("Mask"));
+}
+
+} // namespace blender::nodes
static void node_composit_init_ellipsemask(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -44,12 +51,27 @@ static void node_composit_init_ellipsemask(bNodeTree *UNUSED(ntree), bNode *node
node->storage = data;
}
-void register_node_type_cmp_ellipsemask(void)
+static void node_composit_buts_ellipsemask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *row;
+ row = uiLayoutRow(layout, true);
+ uiItemR(row, ptr, "x", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(row, ptr, "y", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ row = uiLayoutRow(layout, true);
+ uiItemR(row, ptr, "width", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ uiItemR(row, ptr, "height", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+
+ uiItemR(layout, ptr, "rotation", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "mask_type", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_ellipsemask()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_MASK_ELLIPSE, "Ellipse Mask", NODE_CLASS_MATTE, 0);
- node_type_socket_templates(&ntype, cmp_node_ellipsemask_in, cmp_node_ellipsemask_out);
+ ntype.declare = blender::nodes::cmp_node_ellipsemask_declare;
+ ntype.draw_buttons = node_composit_buts_ellipsemask;
node_type_size(&ntype, 260, 110, 320);
node_type_init(&ntype, node_composit_init_ellipsemask);
node_type_storage(
diff --git a/source/blender/nodes/composite/nodes/node_composite_exposure.cc b/source/blender/nodes/composite/nodes/node_composite_exposure.cc
index c1e64065f7e..b696db41a3c 100644
--- a/source/blender/nodes/composite/nodes/node_composite_exposure.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_exposure.cc
@@ -36,7 +36,7 @@ static void cmp_node_exposure_declare(NodeDeclarationBuilder &b)
} // namespace blender::nodes
-void register_node_type_cmp_exposure(void)
+void register_node_type_cmp_exposure()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/composite/nodes/node_composite_filter.cc b/source/blender/nodes/composite/nodes/node_composite_filter.cc
index f07619877f4..3671d502539 100644
--- a/source/blender/nodes/composite/nodes/node_composite_filter.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_filter.cc
@@ -21,26 +21,37 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** FILTER ******************** */
-static bNodeSocketTemplate cmp_node_filter_in[] = {
- {SOCK_FLOAT, N_("Fac"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_filter_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
-
-void register_node_type_cmp_filter(void)
+
+namespace blender::nodes {
+
+static void cmp_node_filter_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Fac")).default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
+
+static void node_composit_buts_filter(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "filter_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
+
+void register_node_type_cmp_filter()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_FILTER, "Filter", NODE_CLASS_OP_FILTER, NODE_PREVIEW);
- node_type_socket_templates(&ntype, cmp_node_filter_in, cmp_node_filter_out);
- node_type_label(&ntype, node_filter_label);
+ ntype.declare = blender::nodes::cmp_node_filter_declare;
+ ntype.draw_buttons = node_composit_buts_filter;
+ ntype.labelfunc = node_filter_label;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_flip.cc b/source/blender/nodes/composite/nodes/node_composite_flip.cc
index 42aa3141f5c..38bc0f8b855 100644
--- a/source/blender/nodes/composite/nodes/node_composite_flip.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_flip.cc
@@ -21,25 +21,35 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Flip ******************** */
-static bNodeSocketTemplate cmp_node_flip_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_flip_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void cmp_node_flip_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
+
+static void node_composit_buts_flip(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "axis", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
-void register_node_type_cmp_flip(void)
+void register_node_type_cmp_flip()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_FLIP, "Flip", NODE_CLASS_DISTORT, 0);
- node_type_socket_templates(&ntype, cmp_node_flip_in, cmp_node_flip_out);
+ ntype.declare = blender::nodes::cmp_node_flip_declare;
+ ntype.draw_buttons = node_composit_buts_flip;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_gamma.cc b/source/blender/nodes/composite/nodes/node_composite_gamma.cc
index 74152a27485..438770865ae 100644
--- a/source/blender/nodes/composite/nodes/node_composite_gamma.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_gamma.cc
@@ -40,7 +40,7 @@ static void cmp_node_gamma_declare(NodeDeclarationBuilder &b)
} // namespace blender::nodes
-void register_node_type_cmp_gamma(void)
+void register_node_type_cmp_gamma()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/composite/nodes/node_composite_glare.cc b/source/blender/nodes/composite/nodes/node_composite_glare.cc
index 8a2fd1e1584..adaf22395c3 100644
--- a/source/blender/nodes/composite/nodes/node_composite_glare.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_glare.cc
@@ -21,16 +21,22 @@
* \ingroup cmpnodes
*/
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
-static bNodeSocketTemplate cmp_node_glare_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_glare_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void cmp_node_glare_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
static void node_composit_init_glare(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -49,12 +55,51 @@ static void node_composit_init_glare(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = ndg;
}
-void register_node_type_cmp_glare(void)
+static void node_composit_buts_glare(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "glare_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ uiItemR(layout, ptr, "quality", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+
+ if (RNA_enum_get(ptr, "glare_type") != 1) {
+ uiItemR(layout, ptr, "iterations", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ if (RNA_enum_get(ptr, "glare_type") != 0) {
+ uiItemR(layout,
+ ptr,
+ "color_modulation",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ }
+ }
+
+ uiItemR(layout, ptr, "mix", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "threshold", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ if (RNA_enum_get(ptr, "glare_type") == 2) {
+ uiItemR(layout, ptr, "streaks", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "angle_offset", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+ if (RNA_enum_get(ptr, "glare_type") == 0 || RNA_enum_get(ptr, "glare_type") == 2) {
+ uiItemR(
+ layout, ptr, "fade", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+
+ if (RNA_enum_get(ptr, "glare_type") == 0) {
+ uiItemR(layout, ptr, "use_rotate_45", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+ }
+ if (RNA_enum_get(ptr, "glare_type") == 1) {
+ uiItemR(layout, ptr, "size", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+}
+
+void register_node_type_cmp_glare()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_GLARE, "Glare", NODE_CLASS_OP_FILTER, 0);
- node_type_socket_templates(&ntype, cmp_node_glare_in, cmp_node_glare_out);
+ ntype.declare = blender::nodes::cmp_node_glare_declare;
+ ntype.draw_buttons = node_composit_buts_glare;
node_type_init(&ntype, node_composit_init_glare);
node_type_storage(&ntype, "NodeGlare", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_hueSatVal.cc b/source/blender/nodes/composite/nodes/node_composite_hueSatVal.cc
index 21430035465..47fbaa4d384 100644
--- a/source/blender/nodes/composite/nodes/node_composite_hueSatVal.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_hueSatVal.cc
@@ -47,7 +47,7 @@ static void cmp_node_huesatval_declare(NodeDeclarationBuilder &b)
} // namespace blender::nodes
-void register_node_type_cmp_hue_sat(void)
+void register_node_type_cmp_hue_sat()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/composite/nodes/node_composite_huecorrect.cc b/source/blender/nodes/composite/nodes/node_composite_huecorrect.cc
index 83743bbed18..e78ba0c7f9c 100644
--- a/source/blender/nodes/composite/nodes/node_composite_huecorrect.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_huecorrect.cc
@@ -51,7 +51,7 @@ static void node_composit_init_huecorrect(bNodeTree *UNUSED(ntree), bNode *node)
cumapping->cur = 1;
}
-void register_node_type_cmp_huecorrect(void)
+void register_node_type_cmp_huecorrect()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/composite/nodes/node_composite_idMask.cc b/source/blender/nodes/composite/nodes/node_composite_idMask.cc
index 5121370567c..f5b8cb6c567 100644
--- a/source/blender/nodes/composite/nodes/node_composite_idMask.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_idMask.cc
@@ -21,6 +21,9 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** ID Mask ******************** */
@@ -35,12 +38,19 @@ static void cmp_node_idmask_declare(NodeDeclarationBuilder &b)
} // namespace blender::nodes
-void register_node_type_cmp_idmask(void)
+static void node_composit_buts_id_mask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "index", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "use_antialiasing", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_idmask()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_ID_MASK, "ID Mask", NODE_CLASS_CONVERTER, 0);
ntype.declare = blender::nodes::cmp_node_idmask_declare;
+ ntype.draw_buttons = node_composit_buts_id_mask;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_image.cc b/source/blender/nodes/composite/nodes/node_composite_image.cc
index 40d4d4563c9..8e3cc9bcd95 100644
--- a/source/blender/nodes/composite/nodes/node_composite_image.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_image.cc
@@ -26,16 +26,21 @@
#include "BLI_linklist.h"
#include "BLI_utildefines.h"
-#include "DNA_scene_types.h"
-
-#include "RE_engine.h"
-
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_scene.h"
+#include "DNA_scene_types.h"
+
+#include "RE_engine.h"
+
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
/* **************** IMAGE (and RenderResult, multilayer image) ******************** */
static bNodeSocketTemplate cmp_node_rlayers_out[] = {
@@ -443,7 +448,7 @@ static void node_composit_copy_image(bNodeTree *UNUSED(dest_ntree),
}
}
-void register_node_type_cmp_image(void)
+void register_node_type_cmp_image()
{
static bNodeType ntype;
@@ -451,7 +456,7 @@ void register_node_type_cmp_image(void)
node_type_init(&ntype, node_composit_init_image);
node_type_storage(&ntype, "ImageUser", node_composit_free_image, node_composit_copy_image);
node_type_update(&ntype, cmp_node_image_update);
- node_type_label(&ntype, node_image_label);
+ ntype.labelfunc = node_image_label;
nodeRegisterType(&ntype);
}
@@ -499,7 +504,7 @@ static bool node_composit_poll_rlayers(bNodeType *UNUSED(ntype),
const char **r_disabled_hint)
{
if (!STREQ(ntree->idname, "CompositorNodeTree")) {
- *r_disabled_hint = "Not a compositor node tree";
+ *r_disabled_hint = TIP_("Not a compositor node tree");
return false;
}
@@ -516,7 +521,8 @@ static bool node_composit_poll_rlayers(bNodeType *UNUSED(ntype),
}
if (scene == nullptr) {
- *r_disabled_hint = "The node tree must be the compositing node tree of any scene in the file";
+ *r_disabled_hint = TIP_(
+ "The node tree must be the compositing node tree of any scene in the file");
return false;
}
return true;
@@ -554,12 +560,56 @@ static void cmp_node_rlayers_update(bNodeTree *ntree, bNode *node)
cmp_node_update_default(ntree, node);
}
-void register_node_type_cmp_rlayers(void)
+static void node_composit_buts_viewlayers(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ bNode *node = (bNode *)ptr->data;
+ uiLayout *col, *row;
+
+ uiTemplateID(layout,
+ C,
+ ptr,
+ "scene",
+ nullptr,
+ nullptr,
+ nullptr,
+ UI_TEMPLATE_ID_FILTER_ALL,
+ false,
+ nullptr);
+
+ if (!node->id) {
+ return;
+ }
+
+ col = uiLayoutColumn(layout, false);
+ row = uiLayoutRow(col, true);
+ uiItemR(row, ptr, "layer", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+
+ PropertyRNA *prop = RNA_struct_find_property(ptr, "layer");
+ const char *layer_name;
+ if (!(RNA_property_enum_identifier(
+ C, ptr, prop, RNA_property_enum_get(ptr, prop), &layer_name))) {
+ return;
+ }
+
+ PointerRNA scn_ptr;
+ char scene_name[MAX_ID_NAME - 2];
+ scn_ptr = RNA_pointer_get(ptr, "scene");
+ RNA_string_get(&scn_ptr, "name", scene_name);
+
+ PointerRNA op_ptr;
+ uiItemFullO(
+ row, "RENDER_OT_render", "", ICON_RENDER_STILL, nullptr, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
+ RNA_string_set(&op_ptr, "layer", layer_name);
+ RNA_string_set(&op_ptr, "scene", scene_name);
+}
+
+void register_node_type_cmp_rlayers()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_R_LAYERS, "Render Layers", NODE_CLASS_INPUT, NODE_PREVIEW);
node_type_socket_templates(&ntype, nullptr, cmp_node_rlayers_out);
+ ntype.draw_buttons = node_composit_buts_viewlayers;
ntype.initfunc_api = node_composit_init_rlayers;
ntype.poll = node_composit_poll_rlayers;
node_type_storage(&ntype, nullptr, node_composit_free_rlayers, node_composit_copy_rlayers);
diff --git a/source/blender/nodes/composite/nodes/node_composite_inpaint.cc b/source/blender/nodes/composite/nodes/node_composite_inpaint.cc
index d0ff97a2ca0..976b1cd5a15 100644
--- a/source/blender/nodes/composite/nodes/node_composite_inpaint.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_inpaint.cc
@@ -21,20 +21,35 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Inpaint/ ******************** */
-static bNodeSocketTemplate cmp_node_inpaint_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, {-1, ""}};
-static bNodeSocketTemplate cmp_node_inpaint_out[] = {{SOCK_RGBA, N_("Image")}, {-1, ""}};
+namespace blender::nodes {
+
+static void cmp_node_inpaint_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
+
+static void node_composit_buts_inpaint(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "distance", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
-void register_node_type_cmp_inpaint(void)
+void register_node_type_cmp_inpaint()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_INPAINT, "Inpaint", NODE_CLASS_OP_FILTER, 0);
- node_type_socket_templates(&ntype, cmp_node_inpaint_in, cmp_node_inpaint_out);
+ ntype.declare = blender::nodes::cmp_node_inpaint_declare;
+ ntype.draw_buttons = node_composit_buts_inpaint;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_invert.cc b/source/blender/nodes/composite/nodes/node_composite_invert.cc
index dabf0452628..2243608d5c3 100644
--- a/source/blender/nodes/composite/nodes/node_composite_invert.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_invert.cc
@@ -21,6 +21,9 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** INVERT ******************** */
@@ -41,13 +44,23 @@ static void node_composit_init_invert(bNodeTree *UNUSED(ntree), bNode *node)
node->custom1 |= CMP_CHAN_RGB;
}
+static void node_composit_buts_invert(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, false);
+ uiItemR(col, ptr, "invert_rgb", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "invert_alpha", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
/* custom1 = mix type */
-void register_node_type_cmp_invert(void)
+void register_node_type_cmp_invert()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_INVERT, "Invert", NODE_CLASS_OP_COLOR, 0);
ntype.declare = blender::nodes::cmp_node_invert_declare;
+ ntype.draw_buttons = node_composit_buts_invert;
node_type_init(&ntype, node_composit_init_invert);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_keying.cc b/source/blender/nodes/composite/nodes/node_composite_keying.cc
index d5547161069..de1da3289f9 100644
--- a/source/blender/nodes/composite/nodes/node_composite_keying.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_keying.cc
@@ -21,30 +21,33 @@
* \ingroup cmpnodes
*/
+#include "BLI_math_base.h"
+
#include "BLT_translation.h"
#include "DNA_movieclip_types.h"
-#include "BLI_math_base.h"
+#include "UI_interface.h"
+#include "UI_resources.h"
#include "node_composite_util.hh"
-/* **************** Translate ******************** */
+/* **************** Keying ******************** */
-static bNodeSocketTemplate cmp_node_keying_in[] = {
- {SOCK_RGBA, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {SOCK_RGBA, "Key Color", 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_FLOAT, "Garbage Matte", 0.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_FLOAT, "Core Matte", 0.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void cmp_node_keying_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_input<decl::Color>(N_("Key Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Garbage Matte")).hide_value();
+ b.add_input<decl::Float>(N_("Core Matte")).hide_value();
+ b.add_output<decl::Color>(N_("Image"));
+ b.add_output<decl::Float>(N_("Matte"));
+ b.add_output<decl::Float>(N_("Edges"));
+}
-static bNodeSocketTemplate cmp_node_keying_out[] = {
- {SOCK_RGBA, "Image"},
- {SOCK_FLOAT, "Matte"},
- {SOCK_FLOAT, "Edges"},
- {-1, ""},
-};
+} // namespace blender::nodes
static void node_composit_init_keying(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -60,12 +63,31 @@ static void node_composit_init_keying(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = data;
}
-void register_node_type_cmp_keying(void)
+static void node_composit_buts_keying(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ /* bNode *node = (bNode*)ptr->data; */ /* UNUSED */
+
+ uiItemR(layout, ptr, "blur_pre", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "screen_balance", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "despill_factor", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "despill_balance", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "edge_kernel_radius", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "edge_kernel_tolerance", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "clip_black", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "clip_white", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "dilate_distance", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "feather_falloff", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "feather_distance", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "blur_post", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_keying()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_KEYING, "Keying", NODE_CLASS_MATTE, 0);
- node_type_socket_templates(&ntype, cmp_node_keying_in, cmp_node_keying_out);
+ ntype.declare = blender::nodes::cmp_node_keying_declare;
+ ntype.draw_buttons = node_composit_buts_keying;
node_type_init(&ntype, node_composit_init_keying);
node_type_storage(
&ntype, "NodeKeyingData", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_keyingscreen.cc b/source/blender/nodes/composite/nodes/node_composite_keyingscreen.cc
index c976a92b92d..d90fbe05211 100644
--- a/source/blender/nodes/composite/nodes/node_composite_keyingscreen.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_keyingscreen.cc
@@ -26,14 +26,23 @@
#include "BLI_math_base.h"
#include "BLI_math_color.h"
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
-/* **************** Translate ******************** */
+/* **************** Keying Screen ******************** */
-static bNodeSocketTemplate cmp_node_keyingscreen_out[] = {
- {SOCK_RGBA, "Screen"},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void cmp_node_keyingscreen_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Color>(N_("Screen"));
+}
+
+} // namespace blender::nodes
static void node_composit_init_keyingscreen(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -42,12 +51,40 @@ static void node_composit_init_keyingscreen(bNodeTree *UNUSED(ntree), bNode *nod
node->storage = data;
}
-void register_node_type_cmp_keyingscreen(void)
+static void node_composit_buts_keyingscreen(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ bNode *node = (bNode *)ptr->data;
+
+ uiTemplateID(layout,
+ C,
+ ptr,
+ "clip",
+ nullptr,
+ nullptr,
+ nullptr,
+ UI_TEMPLATE_ID_FILTER_ALL,
+ false,
+ nullptr);
+
+ if (node->id) {
+ MovieClip *clip = (MovieClip *)node->id;
+ uiLayout *col;
+ PointerRNA tracking_ptr;
+
+ RNA_pointer_create(&clip->id, &RNA_MovieTracking, &clip->tracking, &tracking_ptr);
+
+ col = uiLayoutColumn(layout, true);
+ uiItemPointerR(col, ptr, "tracking_object", &tracking_ptr, "objects", "", ICON_OBJECT_DATA);
+ }
+}
+
+void register_node_type_cmp_keyingscreen()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_KEYINGSCREEN, "Keying Screen", NODE_CLASS_MATTE, 0);
- node_type_socket_templates(&ntype, nullptr, cmp_node_keyingscreen_out);
+ ntype.declare = blender::nodes::cmp_node_keyingscreen_declare;
+ ntype.draw_buttons = node_composit_buts_keyingscreen;
node_type_init(&ntype, node_composit_init_keyingscreen);
node_type_storage(
&ntype, "NodeKeyingScreenData", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_lensdist.cc b/source/blender/nodes/composite/nodes/node_composite_lensdist.cc
index 2a8dc035792..11ee0cf0aa3 100644
--- a/source/blender/nodes/composite/nodes/node_composite_lensdist.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_lensdist.cc
@@ -21,18 +21,24 @@
* \ingroup cmpnodes
*/
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
-static bNodeSocketTemplate cmp_node_lensdist_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_FLOAT, N_("Distort"), 0.0f, 0.0f, 0.0f, 0.0f, -0.999f, 1.0f, PROP_NONE},
- {SOCK_FLOAT, N_("Dispersion"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_lensdist_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void cmp_node_lensdist_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Distort")).default_value(0.0f).min(-0.999f).max(1.0f);
+ b.add_input<decl::Float>(N_("Dispersion")).default_value(0.0f).min(0.0f).max(1.0f);
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
static void node_composit_init_lensdist(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -41,12 +47,26 @@ static void node_composit_init_lensdist(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = nld;
}
-void register_node_type_cmp_lensdist(void)
+static void node_composit_buts_lensdist(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, false);
+ uiItemR(col, ptr, "use_projector", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ col = uiLayoutColumn(col, false);
+ uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_projector") == false);
+ uiItemR(col, ptr, "use_jitter", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "use_fit", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_lensdist()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_LENSDIST, "Lens Distortion", NODE_CLASS_DISTORT, 0);
- node_type_socket_templates(&ntype, cmp_node_lensdist_in, cmp_node_lensdist_out);
+ ntype.declare = blender::nodes::cmp_node_lensdist_declare;
+ ntype.draw_buttons = node_composit_buts_lensdist;
node_type_init(&ntype, node_composit_init_lensdist);
node_type_storage(
&ntype, "NodeLensDist", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_levels.cc b/source/blender/nodes/composite/nodes/node_composite_levels.cc
index 54064f24e0d..891f79f9bf9 100644
--- a/source/blender/nodes/composite/nodes/node_composite_levels.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_levels.cc
@@ -21,6 +21,9 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** LEVELS ******************** */
@@ -41,12 +44,18 @@ static void node_composit_init_view_levels(bNodeTree *UNUSED(ntree), bNode *node
node->custom1 = 1; /* All channels. */
}
-void register_node_type_cmp_view_levels(void)
+static void node_composit_buts_view_levels(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "channel", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
+
+void register_node_type_cmp_view_levels()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_VIEW_LEVELS, "Levels", NODE_CLASS_OUTPUT, NODE_PREVIEW);
ntype.declare = blender::nodes::cmp_node_levels_declare;
+ ntype.draw_buttons = node_composit_buts_view_levels;
node_type_init(&ntype, node_composit_init_view_levels);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_lummaMatte.cc b/source/blender/nodes/composite/nodes/node_composite_lummaMatte.cc
index 600406d22b9..f5193bd5df2 100644
--- a/source/blender/nodes/composite/nodes/node_composite_lummaMatte.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_lummaMatte.cc
@@ -21,19 +21,23 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* ******************* Luma Matte Node ********************************* */
-static bNodeSocketTemplate cmp_node_luma_matte_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_luma_matte_out[] = {
- {SOCK_RGBA, N_("Image")},
- {SOCK_FLOAT, N_("Matte")},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void cmp_node_luma_matte_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+ b.add_output<decl::Float>(N_("Matte"));
+}
+
+} // namespace blender::nodes
static void node_composit_init_luma_matte(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -43,12 +47,24 @@ static void node_composit_init_luma_matte(bNodeTree *UNUSED(ntree), bNode *node)
c->t2 = 0.0f;
}
-void register_node_type_cmp_luma_matte(void)
+static void node_composit_buts_luma_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(
+ col, ptr, "limit_max", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ uiItemR(
+ col, ptr, "limit_min", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_luma_matte()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_LUMA_MATTE, "Luminance Key", NODE_CLASS_MATTE, NODE_PREVIEW);
- node_type_socket_templates(&ntype, cmp_node_luma_matte_in, cmp_node_luma_matte_out);
+ ntype.declare = blender::nodes::cmp_node_luma_matte_declare;
+ ntype.draw_buttons = node_composit_buts_luma_matte;
node_type_init(&ntype, node_composit_init_luma_matte);
node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_mapRange.cc b/source/blender/nodes/composite/nodes/node_composite_mapRange.cc
index 808ad538e55..1ae80f68dfd 100644
--- a/source/blender/nodes/composite/nodes/node_composite_mapRange.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_mapRange.cc
@@ -21,28 +21,42 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
-/* **************** MAP VALUE ******************** */
-static bNodeSocketTemplate cmp_node_map_range_in[] = {
- {SOCK_FLOAT, N_("Value"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {SOCK_FLOAT, N_("From Min"), 0.0f, 1.0f, 1.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
- {SOCK_FLOAT, N_("From Max"), 1.0f, 1.0f, 1.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
- {SOCK_FLOAT, N_("To Min"), 0.0f, 1.0f, 1.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
- {SOCK_FLOAT, N_("To Max"), 1.0f, 1.0f, 1.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_map_range_out[] = {
- {SOCK_FLOAT, N_("Value")},
- {-1, ""},
-};
-
-void register_node_type_cmp_map_range(void)
+/* **************** Map Range ******************** */
+
+namespace blender::nodes {
+
+static void cmp_node_map_range_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Value")).default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("From Min")).default_value(0.0f).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>(N_("From Max")).default_value(0.0f).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>(N_("To Min")).default_value(0.0f).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>(N_("To Max")).default_value(0.0f).min(-10000.0f).max(10000.0f);
+ b.add_output<decl::Float>(N_("Value"));
+}
+
+} // namespace blender::nodes
+
+static void node_composit_buts_map_range(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "use_clamp", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_map_range()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_MAP_RANGE, "Map Range", NODE_CLASS_OP_VECTOR, 0);
- node_type_socket_templates(&ntype, cmp_node_map_range_in, cmp_node_map_range_out);
+ ntype.declare = blender::nodes::cmp_node_map_range_declare;
+ ntype.draw_buttons = node_composit_buts_map_range;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_mapUV.cc b/source/blender/nodes/composite/nodes/node_composite_mapUV.cc
index 99032bd042e..71446e3a3c4 100644
--- a/source/blender/nodes/composite/nodes/node_composite_mapUV.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_mapUV.cc
@@ -21,26 +21,36 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Map UV ******************** */
-static bNodeSocketTemplate cmp_node_mapuv_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_VECTOR, N_("UV"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_mapuv_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
-
-void register_node_type_cmp_mapuv(void)
+namespace blender::nodes {
+
+static void cmp_node_map_uv_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Vector>(N_("UV")).default_value({1.0f, 0.0f, 0.0f}).min(0.0f).max(1.0f);
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
+
+static void node_composit_buts_map_uv(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "alpha", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_mapuv()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_MAP_UV, "Map UV", NODE_CLASS_DISTORT, 0);
- node_type_socket_templates(&ntype, cmp_node_mapuv_in, cmp_node_mapuv_out);
+ ntype.declare = blender::nodes::cmp_node_map_uv_declare;
+ ntype.draw_buttons = node_composit_buts_map_uv;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_mapValue.cc b/source/blender/nodes/composite/nodes/node_composite_mapValue.cc
index 25c00c2ba13..4bd9124fa68 100644
--- a/source/blender/nodes/composite/nodes/node_composite_mapValue.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_mapValue.cc
@@ -21,29 +21,58 @@
* \ingroup cmpnodes
*/
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** MAP VALUE ******************** */
-static bNodeSocketTemplate cmp_node_map_value_in[] = {
- {SOCK_FLOAT, N_("Value"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_map_value_out[] = {
- {SOCK_FLOAT, N_("Value")},
- {-1, ""},
-};
+
+namespace blender::nodes {
+
+static void cmp_node_map_value_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Value")).default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_output<decl::Float>(N_("Value"));
+}
+
+} // namespace blender::nodes
static void node_composit_init_map_value(bNodeTree *UNUSED(ntree), bNode *node)
{
node->storage = BKE_texture_mapping_add(TEXMAP_TYPE_POINT);
}
-void register_node_type_cmp_map_value(void)
+static void node_composit_buts_map_value(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *sub, *col;
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "offset", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "size", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "use_min", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ sub = uiLayoutColumn(col, false);
+ uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_min"));
+ uiItemR(sub, ptr, "min", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "use_max", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ sub = uiLayoutColumn(col, false);
+ uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_max"));
+ uiItemR(sub, ptr, "max", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
+
+void register_node_type_cmp_map_value()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_MAP_VALUE, "Map Value", NODE_CLASS_OP_VECTOR, 0);
- node_type_socket_templates(&ntype, cmp_node_map_value_in, cmp_node_map_value_out);
+ ntype.declare = blender::nodes::cmp_node_map_value_declare;
+ ntype.draw_buttons = node_composit_buts_map_value;
node_type_init(&ntype, node_composit_init_map_value);
node_type_storage(&ntype, "TexMapping", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_mask.cc b/source/blender/nodes/composite/nodes/node_composite_mask.cc
index 6428fadaa5f..8cbf526a289 100644
--- a/source/blender/nodes/composite/nodes/node_composite_mask.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_mask.cc
@@ -23,6 +23,9 @@
#include "DNA_mask_types.h"
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Mask ******************** */
@@ -46,7 +49,10 @@ static void node_composit_init_mask(bNodeTree *UNUSED(ntree), bNode *node)
node->custom3 = 0.5f; /* shutter */
}
-static void node_mask_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
+static void node_mask_label(const bNodeTree *UNUSED(ntree),
+ const bNode *node,
+ char *label,
+ int maxlen)
{
if (node->id != nullptr) {
BLI_strncpy(label, node->id->name + 2, maxlen);
@@ -56,14 +62,45 @@ static void node_mask_label(bNodeTree *UNUSED(ntree), bNode *node, char *label,
}
}
-void register_node_type_cmp_mask(void)
+static void node_composit_buts_mask(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ bNode *node = (bNode *)ptr->data;
+
+ uiTemplateID(layout,
+ C,
+ ptr,
+ "mask",
+ nullptr,
+ nullptr,
+ nullptr,
+ UI_TEMPLATE_ID_FILTER_ALL,
+ false,
+ nullptr);
+ uiItemR(layout, ptr, "use_feather", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ uiItemR(layout, ptr, "size_source", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+
+ if (node->custom1 & (CMP_NODEFLAG_MASK_FIXED | CMP_NODEFLAG_MASK_FIXED_SCENE)) {
+ uiItemR(layout, ptr, "size_x", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "size_y", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+
+ uiItemR(layout, ptr, "use_motion_blur", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ if (node->custom1 & CMP_NODEFLAG_MASK_MOTION_BLUR) {
+ uiItemR(layout, ptr, "motion_blur_samples", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "motion_blur_shutter", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+}
+
+void register_node_type_cmp_mask()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_MASK, "Mask", NODE_CLASS_INPUT, 0);
ntype.declare = blender::nodes::cmp_node_mask_declare;
+ ntype.draw_buttons = node_composit_buts_mask;
node_type_init(&ntype, node_composit_init_mask);
- node_type_label(&ntype, node_mask_label);
+ ntype.labelfunc = node_mask_label;
node_type_storage(&ntype, "NodeMask", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_math.cc b/source/blender/nodes/composite/nodes/node_composite_math.cc
index ecddcc2ad32..b34cfab5eb5 100644
--- a/source/blender/nodes/composite/nodes/node_composite_math.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_math.cc
@@ -24,21 +24,32 @@
#include "node_composite_util.hh"
/* **************** SCALAR MATH ******************** */
-static bNodeSocketTemplate cmp_node_math_in[] = {
- {SOCK_FLOAT, N_("Value"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
- {SOCK_FLOAT, N_("Value"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
- {SOCK_FLOAT, N_("Value"), 0.0f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
- {-1, ""}};
-static bNodeSocketTemplate cmp_node_math_out[] = {{SOCK_FLOAT, N_("Value")}, {-1, ""}};
+namespace blender::nodes {
-void register_node_type_cmp_math(void)
+static void cmp_node_math_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Value")).default_value(0.5f).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>(N_("Value"), "Value_001")
+ .default_value(0.5f)
+ .min(-10000.0f)
+ .max(10000.0f);
+ b.add_input<decl::Float>(N_("Value"), "Value_002")
+ .default_value(0.5f)
+ .min(-10000.0f)
+ .max(10000.0f);
+ b.add_output<decl::Float>(N_("Value"));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_cmp_math()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_MATH, "Math", NODE_CLASS_CONVERTER, 0);
- node_type_socket_templates(&ntype, cmp_node_math_in, cmp_node_math_out);
- node_type_label(&ntype, node_math_label);
+ ntype.declare = blender::nodes::cmp_node_math_declare;
+ ntype.labelfunc = node_math_label;
node_type_update(&ntype, node_math_update);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_mixrgb.cc b/source/blender/nodes/composite/nodes/node_composite_mixrgb.cc
index 557116f5b7a..4432b031ee7 100644
--- a/source/blender/nodes/composite/nodes/node_composite_mixrgb.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_mixrgb.cc
@@ -25,25 +25,26 @@
/* **************** MIX RGB ******************** */
-static bNodeSocketTemplate cmp_node_mix_rgb_in[] = {
- {SOCK_FLOAT, N_("Fac"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_mix_rgb_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void cmp_node_mixrgb_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Fac")).default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Color>(N_("Image"), "Image_001").default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
/* custom1 = mix type */
-void register_node_type_cmp_mix_rgb(void)
+void register_node_type_cmp_mix_rgb()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR, NODE_PREVIEW);
- node_type_socket_templates(&ntype, cmp_node_mix_rgb_in, cmp_node_mix_rgb_out);
- node_type_label(&ntype, node_blend_label);
+ ntype.declare = blender::nodes::cmp_node_mixrgb_declare;
+ ntype.labelfunc = node_blend_label;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_movieclip.cc b/source/blender/nodes/composite/nodes/node_composite_movieclip.cc
index 5d63a1b8002..47a2c89a2f9 100644
--- a/source/blender/nodes/composite/nodes/node_composite_movieclip.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_movieclip.cc
@@ -21,11 +21,16 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.hh"
-
#include "BKE_context.h"
#include "BKE_lib_id.h"
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_composite_util.hh"
+
namespace blender::nodes {
static void cmp_node_movieclip_declare(NodeDeclarationBuilder &b)
@@ -53,12 +58,53 @@ static void init(const bContext *C, PointerRNA *ptr)
user->framenr = 1;
}
-void register_node_type_cmp_movieclip(void)
+static void node_composit_buts_movieclip(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ uiTemplateID(layout,
+ C,
+ ptr,
+ "clip",
+ nullptr,
+ "CLIP_OT_open",
+ nullptr,
+ UI_TEMPLATE_ID_FILTER_ALL,
+ false,
+ nullptr);
+}
+
+static void node_composit_buts_movieclip_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ bNode *node = (bNode *)ptr->data;
+ PointerRNA clipptr;
+
+ uiTemplateID(layout,
+ C,
+ ptr,
+ "clip",
+ nullptr,
+ "CLIP_OT_open",
+ nullptr,
+ UI_TEMPLATE_ID_FILTER_ALL,
+ false,
+ nullptr);
+
+ if (!node->id) {
+ return;
+ }
+
+ clipptr = RNA_pointer_get(ptr, "clip");
+
+ uiTemplateColorspaceSettings(layout, &clipptr, "colorspace_settings");
+}
+
+void register_node_type_cmp_movieclip()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_MOVIECLIP, "Movie Clip", NODE_CLASS_INPUT, NODE_PREVIEW);
ntype.declare = blender::nodes::cmp_node_movieclip_declare;
+ ntype.draw_buttons = node_composit_buts_movieclip;
+ ntype.draw_buttons_ex = node_composit_buts_movieclip_ex;
ntype.initfunc_api = init;
node_type_storage(
&ntype, "MovieClipUser", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_moviedistortion.cc b/source/blender/nodes/composite/nodes/node_composite_moviedistortion.cc
index 2bac30cc152..e7d9cac7c1a 100644
--- a/source/blender/nodes/composite/nodes/node_composite_moviedistortion.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_moviedistortion.cc
@@ -21,24 +21,27 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.hh"
-
#include "BKE_context.h"
#include "BKE_lib_id.h"
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_composite_util.hh"
+
/* **************** Translate ******************** */
-static bNodeSocketTemplate cmp_node_moviedistortion_in[] = {
- {SOCK_RGBA, N_("Image"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void cmp_node_moviedistortion_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+}
-static bNodeSocketTemplate cmp_node_moviedistortion_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+} // namespace blender::nodes
-static void label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
+static void label(const bNodeTree *UNUSED(ntree), const bNode *node, char *label, int maxlen)
{
if (node->custom1 == 0) {
BLI_strncpy(label, IFACE_("Undistortion"), maxlen);
@@ -73,14 +76,36 @@ static void storage_copy(bNodeTree *UNUSED(dest_ntree), bNode *dest_node, const
}
}
-void register_node_type_cmp_moviedistortion(void)
+static void node_composit_buts_moviedistortion(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ bNode *node = (bNode *)ptr->data;
+
+ uiTemplateID(layout,
+ C,
+ ptr,
+ "clip",
+ nullptr,
+ "CLIP_OT_open",
+ nullptr,
+ UI_TEMPLATE_ID_FILTER_ALL,
+ false,
+ nullptr);
+
+ if (!node->id) {
+ return;
+ }
+
+ uiItemR(layout, ptr, "distortion_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
+
+void register_node_type_cmp_moviedistortion()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_MOVIEDISTORTION, "Movie Distortion", NODE_CLASS_DISTORT, 0);
- node_type_socket_templates(&ntype, cmp_node_moviedistortion_in, cmp_node_moviedistortion_out);
- node_type_label(&ntype, label);
-
+ ntype.declare = blender::nodes::cmp_node_moviedistortion_declare;
+ ntype.draw_buttons = node_composit_buts_moviedistortion;
+ ntype.labelfunc = label;
ntype.initfunc_api = init;
node_type_storage(&ntype, nullptr, storage_free, storage_copy);
diff --git a/source/blender/nodes/composite/nodes/node_composite_normal.cc b/source/blender/nodes/composite/nodes/node_composite_normal.cc
index 7531025daa5..b541761a8cc 100644
--- a/source/blender/nodes/composite/nodes/node_composite_normal.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_normal.cc
@@ -24,23 +24,28 @@
#include "node_composite_util.hh"
/* **************** NORMAL ******************** */
-static bNodeSocketTemplate cmp_node_normal_in[] = {
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 1.0f, 0.0f, -1.0f, 1.0f, PROP_DIRECTION},
- {-1, ""},
-};
-
-static bNodeSocketTemplate cmp_node_normal_out[] = {
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 1.0f, 0.0f, -1.0f, 1.0f, PROP_DIRECTION},
- {SOCK_FLOAT, N_("Dot")},
- {-1, ""},
-};
-
-void register_node_type_cmp_normal(void)
+
+namespace blender::nodes {
+
+static void cmp_node_normal_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Vector>(N_("Normal"))
+ .default_value({1.0f, 1.0f, 1.0f})
+ .min(-1.0f)
+ .max(1.0f)
+ .subtype(PROP_DIRECTION);
+ b.add_output<decl::Vector>(N_("Normal"));
+ b.add_output<decl::Float>(N_("Dot"));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_cmp_normal()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_NORMAL, "Normal", NODE_CLASS_OP_VECTOR, 0);
- node_type_socket_templates(&ntype, cmp_node_normal_in, cmp_node_normal_out);
+ ntype.declare = blender::nodes::cmp_node_normal_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_normalize.cc b/source/blender/nodes/composite/nodes/node_composite_normalize.cc
index 7cc54e4eed6..dd3939fa6e2 100644
--- a/source/blender/nodes/composite/nodes/node_composite_normalize.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_normalize.cc
@@ -24,16 +24,23 @@
#include "node_composite_util.hh"
/* **************** NORMALIZE single channel, useful for Z buffer ******************** */
-static bNodeSocketTemplate cmp_node_normalize_in[] = {
- {SOCK_FLOAT, N_("Value"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE}, {-1, ""}};
-static bNodeSocketTemplate cmp_node_normalize_out[] = {{SOCK_FLOAT, N_("Value")}, {-1, ""}};
-void register_node_type_cmp_normalize(void)
+namespace blender::nodes {
+
+static void cmp_node_normalize_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Value")).default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_output<decl::Float>(N_("Value"));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_cmp_normalize()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_NORMALIZE, "Normalize", NODE_CLASS_OP_VECTOR, 0);
- node_type_socket_templates(&ntype, cmp_node_normalize_in, cmp_node_normalize_out);
+ ntype.declare = blender::nodes::cmp_node_normalize_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_outputFile.cc b/source/blender/nodes/composite/nodes/node_composite_outputFile.cc
index a372d2f7419..79074375a23 100644
--- a/source/blender/nodes/composite/nodes/node_composite_outputFile.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_outputFile.cc
@@ -21,14 +21,21 @@
* \ingroup cmpnodes
*/
+#include <cstring>
+
+#include "BLI_string_utf8.h"
#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
-#include <cstring>
#include "BKE_context.h"
#include "RNA_access.h"
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "WM_api.h"
+
#include "node_composite_util.hh"
#include "intern/openexr/openexr_multi.h"
@@ -275,12 +282,169 @@ static void update_output_file(bNodeTree *ntree, bNode *node)
}
}
-void register_node_type_cmp_output_file(void)
+static void node_composit_buts_file_output(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ PointerRNA imfptr = RNA_pointer_get(ptr, "format");
+ const bool multilayer = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_MULTILAYER;
+
+ if (multilayer) {
+ uiItemL(layout, IFACE_("Path:"), ICON_NONE);
+ }
+ else {
+ uiItemL(layout, IFACE_("Base Path:"), ICON_NONE);
+ }
+ uiItemR(layout, ptr, "base_path", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
+
+static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ Scene *scene = CTX_data_scene(C);
+ PointerRNA imfptr = RNA_pointer_get(ptr, "format");
+ PointerRNA active_input_ptr, op_ptr;
+ uiLayout *row, *col;
+ const bool multilayer = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_MULTILAYER;
+ const bool is_exr = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_OPENEXR;
+ const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
+
+ node_composit_buts_file_output(layout, C, ptr);
+ uiTemplateImageSettings(layout, &imfptr, false);
+
+ /* disable stereo output for multilayer, too much work for something that no one will use */
+ /* if someone asks for that we can implement it */
+ if (is_multiview) {
+ uiTemplateImageFormatViews(layout, &imfptr, nullptr);
+ }
+
+ uiItemS(layout);
+
+ uiItemO(layout, IFACE_("Add Input"), ICON_ADD, "NODE_OT_output_file_add_socket");
+
+ row = uiLayoutRow(layout, false);
+ col = uiLayoutColumn(row, true);
+
+ const int active_index = RNA_int_get(ptr, "active_input_index");
+ /* using different collection properties if multilayer format is enabled */
+ if (multilayer) {
+ uiTemplateList(col,
+ C,
+ "UI_UL_list",
+ "file_output_node",
+ ptr,
+ "layer_slots",
+ ptr,
+ "active_input_index",
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ UI_TEMPLATE_LIST_FLAG_NONE);
+ RNA_property_collection_lookup_int(
+ ptr, RNA_struct_find_property(ptr, "layer_slots"), active_index, &active_input_ptr);
+ }
+ else {
+ uiTemplateList(col,
+ C,
+ "UI_UL_list",
+ "file_output_node",
+ ptr,
+ "file_slots",
+ ptr,
+ "active_input_index",
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ UI_TEMPLATE_LIST_FLAG_NONE);
+ RNA_property_collection_lookup_int(
+ ptr, RNA_struct_find_property(ptr, "file_slots"), active_index, &active_input_ptr);
+ }
+ /* XXX collection lookup does not return the ID part of the pointer,
+ * setting this manually here */
+ active_input_ptr.owner_id = ptr->owner_id;
+
+ col = uiLayoutColumn(row, true);
+ wmOperatorType *ot = WM_operatortype_find("NODE_OT_output_file_move_active_socket", false);
+ uiItemFullO_ptr(col, ot, "", ICON_TRIA_UP, nullptr, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
+ RNA_enum_set(&op_ptr, "direction", 1);
+ uiItemFullO_ptr(col, ot, "", ICON_TRIA_DOWN, nullptr, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
+ RNA_enum_set(&op_ptr, "direction", 2);
+
+ if (active_input_ptr.data) {
+ if (multilayer) {
+ col = uiLayoutColumn(layout, true);
+
+ uiItemL(col, IFACE_("Layer:"), ICON_NONE);
+ row = uiLayoutRow(col, false);
+ uiItemR(row, &active_input_ptr, "name", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ uiItemFullO(row,
+ "NODE_OT_output_file_remove_active_socket",
+ "",
+ ICON_X,
+ nullptr,
+ WM_OP_EXEC_DEFAULT,
+ UI_ITEM_R_ICON_ONLY,
+ nullptr);
+ }
+ else {
+ col = uiLayoutColumn(layout, true);
+
+ uiItemL(col, IFACE_("File Subpath:"), ICON_NONE);
+ row = uiLayoutRow(col, false);
+ uiItemR(row, &active_input_ptr, "path", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ uiItemFullO(row,
+ "NODE_OT_output_file_remove_active_socket",
+ "",
+ ICON_X,
+ nullptr,
+ WM_OP_EXEC_DEFAULT,
+ UI_ITEM_R_ICON_ONLY,
+ nullptr);
+
+ /* format details for individual files */
+ imfptr = RNA_pointer_get(&active_input_ptr, "format");
+
+ col = uiLayoutColumn(layout, true);
+ uiItemL(col, IFACE_("Format:"), ICON_NONE);
+ uiItemR(col,
+ &active_input_ptr,
+ "use_node_format",
+ UI_ITEM_R_SPLIT_EMPTY_NAME,
+ nullptr,
+ ICON_NONE);
+
+ const bool is_socket_exr = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_OPENEXR;
+ const bool use_node_format = RNA_boolean_get(&active_input_ptr, "use_node_format");
+
+ if ((!is_exr && use_node_format) || (!is_socket_exr && !use_node_format)) {
+ uiItemR(col,
+ &active_input_ptr,
+ "save_as_render",
+ UI_ITEM_R_SPLIT_EMPTY_NAME,
+ nullptr,
+ ICON_NONE);
+ }
+
+ col = uiLayoutColumn(layout, false);
+ uiLayoutSetActive(col, use_node_format == false);
+ uiTemplateImageSettings(col, &imfptr, false);
+
+ if (is_multiview) {
+ uiTemplateImageFormatViews(layout, &imfptr, nullptr);
+ }
+ }
+ }
+}
+
+void register_node_type_cmp_output_file()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_OUTPUT_FILE, "File Output", NODE_CLASS_OUTPUT, NODE_PREVIEW);
node_type_socket_templates(&ntype, nullptr, nullptr);
+ ntype.draw_buttons = node_composit_buts_file_output;
+ ntype.draw_buttons_ex = node_composit_buts_file_output_ex;
ntype.initfunc_api = init_output_file;
node_type_storage(&ntype, "NodeImageMultiFile", free_output_file, copy_output_file);
node_type_update(&ntype, update_output_file);
diff --git a/source/blender/nodes/composite/nodes/node_composite_pixelate.cc b/source/blender/nodes/composite/nodes/node_composite_pixelate.cc
index 19975c21a0b..3679aada759 100644
--- a/source/blender/nodes/composite/nodes/node_composite_pixelate.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_pixelate.cc
@@ -25,16 +25,22 @@
/* **************** Pixelate ******************** */
-static bNodeSocketTemplate cmp_node_pixelate_in[] = {
- {SOCK_RGBA, N_("Color"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE}, {-1, ""}};
-static bNodeSocketTemplate cmp_node_pixelate_out[] = {{SOCK_RGBA, N_("Color")}, {-1, ""}};
+namespace blender::nodes {
-void register_node_type_cmp_pixelate(void)
+static void cmp_node_pixelate_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color"));
+ b.add_output<decl::Color>(N_("Color"));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_cmp_pixelate()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_PIXELATE, "Pixelate", NODE_CLASS_OP_FILTER, 0);
- node_type_socket_templates(&ntype, cmp_node_pixelate_in, cmp_node_pixelate_out);
+ ntype.declare = blender::nodes::cmp_node_pixelate_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_planetrackdeform.cc b/source/blender/nodes/composite/nodes/node_composite_planetrackdeform.cc
index e122b710b7b..d9d362f5175 100644
--- a/source/blender/nodes/composite/nodes/node_composite_planetrackdeform.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_planetrackdeform.cc
@@ -21,16 +21,23 @@
* \ingroup cmpnodes
*/
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
-static bNodeSocketTemplate cmp_node_planetrackdeform_in[] = {
- {SOCK_RGBA, N_("Image"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE}, {-1, ""}};
+namespace blender::nodes {
+
+static void cmp_node_planetrackdeform_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image"));
+ b.add_output<decl::Color>(N_("Image"));
+ b.add_output<decl::Float>(N_("Plane"));
+}
-static bNodeSocketTemplate cmp_node_planetrackdeform_out[] = {
- {SOCK_RGBA, N_("Image")},
- {SOCK_FLOAT, N_("Plane")},
- {-1, ""},
-};
+} // namespace blender::nodes
static void init(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -41,13 +48,63 @@ static void init(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = data;
}
-void register_node_type_cmp_planetrackdeform(void)
+static void node_composit_buts_planetrackdeform(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ bNode *node = (bNode *)ptr->data;
+ NodePlaneTrackDeformData *data = (NodePlaneTrackDeformData *)node->storage;
+
+ uiTemplateID(layout,
+ C,
+ ptr,
+ "clip",
+ nullptr,
+ "CLIP_OT_open",
+ nullptr,
+ UI_TEMPLATE_ID_FILTER_ALL,
+ false,
+ nullptr);
+
+ if (node->id) {
+ MovieClip *clip = (MovieClip *)node->id;
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingObject *object;
+ uiLayout *col;
+ PointerRNA tracking_ptr;
+
+ RNA_pointer_create(&clip->id, &RNA_MovieTracking, tracking, &tracking_ptr);
+
+ col = uiLayoutColumn(layout, false);
+ uiItemPointerR(col, ptr, "tracking_object", &tracking_ptr, "objects", "", ICON_OBJECT_DATA);
+
+ object = BKE_tracking_object_get_named(tracking, data->tracking_object);
+ if (object) {
+ PointerRNA object_ptr;
+
+ RNA_pointer_create(&clip->id, &RNA_MovieTrackingObject, object, &object_ptr);
+
+ uiItemPointerR(
+ col, ptr, "plane_track_name", &object_ptr, "plane_tracks", "", ICON_ANIM_DATA);
+ }
+ else {
+ uiItemR(layout, ptr, "plane_track_name", 0, "", ICON_ANIM_DATA);
+ }
+ }
+
+ uiItemR(layout, ptr, "use_motion_blur", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ if (data->flag & CMP_NODEFLAG_PLANETRACKDEFORM_MOTION_BLUR) {
+ uiItemR(layout, ptr, "motion_blur_samples", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "motion_blur_shutter", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+}
+
+void register_node_type_cmp_planetrackdeform()
{
static bNodeType ntype;
cmp_node_type_base(
&ntype, CMP_NODE_PLANETRACKDEFORM, "Plane Track Deform", NODE_CLASS_DISTORT, 0);
- node_type_socket_templates(&ntype, cmp_node_planetrackdeform_in, cmp_node_planetrackdeform_out);
+ ntype.declare = blender::nodes::cmp_node_planetrackdeform_declare;
+ ntype.draw_buttons = node_composit_buts_planetrackdeform;
node_type_init(&ntype, init);
node_type_storage(
&ntype, "NodePlaneTrackDeformData", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_posterize.cc b/source/blender/nodes/composite/nodes/node_composite_posterize.cc
index 45a98e68b4b..8437c72e76c 100644
--- a/source/blender/nodes/composite/nodes/node_composite_posterize.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_posterize.cc
@@ -25,22 +25,23 @@
/* **************** Posterize ******************** */
-static bNodeSocketTemplate cmp_node_posterize_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_FLOAT, N_("Steps"), 8.0f, 8.0f, 8.0f, 8.0f, 2.0f, 1024.0f, PROP_NONE},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_posterize_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
-
-void register_node_type_cmp_posterize(void)
+namespace blender::nodes {
+
+static void cmp_node_posterize_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Steps")).default_value(8.0f).min(2.0f).max(1024.0f);
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_cmp_posterize()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_POSTERIZE, "Posterize", NODE_CLASS_OP_COLOR, 0);
- node_type_socket_templates(&ntype, cmp_node_posterize_in, cmp_node_posterize_out);
+ ntype.declare = blender::nodes::cmp_node_posterize_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_premulkey.cc b/source/blender/nodes/composite/nodes/node_composite_premulkey.cc
index 49068429a8d..a70adf68692 100644
--- a/source/blender/nodes/composite/nodes/node_composite_premulkey.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_premulkey.cc
@@ -21,6 +21,9 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Premul and Key Alpha Convert ******************** */
@@ -35,12 +38,18 @@ static void cmp_node_premulkey_declare(NodeDeclarationBuilder &b)
} // namespace blender::nodes
-void register_node_type_cmp_premulkey(void)
+static void node_composit_buts_premulkey(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "mapping", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
+
+void register_node_type_cmp_premulkey()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_PREMULKEY, "Alpha Convert", NODE_CLASS_CONVERTER, 0);
ntype.declare = blender::nodes::cmp_node_premulkey_declare;
+ ntype.draw_buttons = node_composit_buts_premulkey;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_rgb.cc b/source/blender/nodes/composite/nodes/node_composite_rgb.cc
index abe69d6a756..54f152d1cd0 100644
--- a/source/blender/nodes/composite/nodes/node_composite_rgb.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_rgb.cc
@@ -34,7 +34,7 @@ static void cmp_node_rgb_declare(NodeDeclarationBuilder &b)
} // namespace blender::nodes
-void register_node_type_cmp_rgb(void)
+void register_node_type_cmp_rgb()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/composite/nodes/node_composite_rotate.cc b/source/blender/nodes/composite/nodes/node_composite_rotate.cc
index d28b35ec9fb..cc1589a47ca 100644
--- a/source/blender/nodes/composite/nodes/node_composite_rotate.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_rotate.cc
@@ -21,31 +21,45 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Rotate ******************** */
-static bNodeSocketTemplate cmp_node_rotate_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_FLOAT, N_("Degr"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f, PROP_ANGLE},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_rotate_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void cmp_node_rotate_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Degr"))
+ .default_value(0.0f)
+ .min(-10000.0f)
+ .max(10000.0f)
+ .subtype(PROP_ANGLE);
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
static void node_composit_init_rotate(bNodeTree *UNUSED(ntree), bNode *node)
{
node->custom1 = 1; /* Bilinear Filter. */
}
-void register_node_type_cmp_rotate(void)
+static void node_composit_buts_rotate(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "filter_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
+
+void register_node_type_cmp_rotate()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_ROTATE, "Rotate", NODE_CLASS_DISTORT, 0);
- node_type_socket_templates(&ntype, cmp_node_rotate_in, cmp_node_rotate_out);
+ ntype.declare = blender::nodes::cmp_node_rotate_declare;
+ ntype.draw_buttons = node_composit_buts_rotate;
node_type_init(&ntype, node_composit_init_rotate);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_scale.cc b/source/blender/nodes/composite/nodes/node_composite_scale.cc
index 284d16b9b0d..98c9f6619f4 100644
--- a/source/blender/nodes/composite/nodes/node_composite_scale.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_scale.cc
@@ -21,16 +21,26 @@
* \ingroup cmpnodes
*/
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Scale ******************** */
-static bNodeSocketTemplate cmp_node_scale_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_FLOAT, N_("X"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0001f, CMP_SCALE_MAX, PROP_NONE},
- {SOCK_FLOAT, N_("Y"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0001f, CMP_SCALE_MAX, PROP_NONE},
- {-1, ""}};
-static bNodeSocketTemplate cmp_node_scale_out[] = {{SOCK_RGBA, N_("Image")}, {-1, ""}};
+namespace blender::nodes {
+
+static void cmp_node_scale_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("X")).default_value(1.0f).min(0.0001f).max(CMP_SCALE_MAX);
+ b.add_input<decl::Float>(N_("Y")).default_value(1.0f).min(0.0001f).max(CMP_SCALE_MAX);
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
static void node_composite_update_scale(bNodeTree *ntree, bNode *node)
{
@@ -45,12 +55,31 @@ static void node_composite_update_scale(bNodeTree *ntree, bNode *node)
}
}
-void register_node_type_cmp_scale(void)
+static void node_composit_buts_scale(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "space", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+
+ if (RNA_enum_get(ptr, "space") == CMP_SCALE_RENDERPERCENT) {
+ uiLayout *row;
+ uiItemR(layout,
+ ptr,
+ "frame_method",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_EXPAND,
+ nullptr,
+ ICON_NONE);
+ row = uiLayoutRow(layout, true);
+ uiItemR(row, ptr, "offset_x", UI_ITEM_R_SPLIT_EMPTY_NAME, "X", ICON_NONE);
+ uiItemR(row, ptr, "offset_y", UI_ITEM_R_SPLIT_EMPTY_NAME, "Y", ICON_NONE);
+ }
+}
+
+void register_node_type_cmp_scale()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_SCALE, "Scale", NODE_CLASS_DISTORT, 0);
- node_type_socket_templates(&ntype, cmp_node_scale_in, cmp_node_scale_out);
+ ntype.declare = blender::nodes::cmp_node_scale_declare;
+ ntype.draw_buttons = node_composit_buts_scale;
node_type_update(&ntype, node_composite_update_scale);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.cc b/source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.cc
index 83c54069658..9eafc0e3594 100644
--- a/source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.cc
@@ -38,7 +38,7 @@ static void cmp_node_sephsva_declare(NodeDeclarationBuilder &b)
} // namespace blender::nodes
-void register_node_type_cmp_sephsva(void)
+void register_node_type_cmp_sephsva()
{
static bNodeType ntype;
@@ -62,7 +62,7 @@ static void cmp_node_combhsva_declare(NodeDeclarationBuilder &b)
} // namespace blender::nodes
-void register_node_type_cmp_combhsva(void)
+void register_node_type_cmp_combhsva()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.cc b/source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.cc
index 049e798af0a..e81ea6f31be 100644
--- a/source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.cc
@@ -37,7 +37,7 @@ static void cmp_node_seprgba_declare(NodeDeclarationBuilder &b)
} // namespace blender::nodes
-void register_node_type_cmp_seprgba(void)
+void register_node_type_cmp_seprgba()
{
static bNodeType ntype;
@@ -62,7 +62,7 @@ static void cmp_node_combrgba_declare(NodeDeclarationBuilder &b)
} // namespace blender::nodes
-void register_node_type_cmp_combrgba(void)
+void register_node_type_cmp_combrgba()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.cc b/source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.cc
index eaf6ba5e9b2..15c8efc2ef8 100644
--- a/source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.cc
@@ -43,7 +43,7 @@ static void node_composit_init_mode_sepycca(bNodeTree *UNUSED(ntree), bNode *nod
node->custom1 = 1; /* BLI_YCC_ITU_BT709 */
}
-void register_node_type_cmp_sepycca(void)
+void register_node_type_cmp_sepycca()
{
static bNodeType ntype;
@@ -74,7 +74,7 @@ static void node_composit_init_mode_combycca(bNodeTree *UNUSED(ntree), bNode *no
node->custom1 = 1; /* BLI_YCC_ITU_BT709 */
}
-void register_node_type_cmp_combycca(void)
+void register_node_type_cmp_combycca()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.cc b/source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.cc
index bc7710122d1..4d4b01c2fb3 100644
--- a/source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.cc
@@ -38,7 +38,7 @@ static void cmp_node_sepyuva_declare(NodeDeclarationBuilder &b)
} // namespace blender::nodes
-void register_node_type_cmp_sepyuva(void)
+void register_node_type_cmp_sepyuva()
{
static bNodeType ntype;
@@ -63,7 +63,7 @@ static void cmp_node_combyuva_declare(NodeDeclarationBuilder &b)
} // namespace blender::nodes
-void register_node_type_cmp_combyuva(void)
+void register_node_type_cmp_combyuva()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/composite/nodes/node_composite_setalpha.cc b/source/blender/nodes/composite/nodes/node_composite_setalpha.cc
index f59ba76f0c5..3e66f884efd 100644
--- a/source/blender/nodes/composite/nodes/node_composite_setalpha.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_setalpha.cc
@@ -21,6 +21,9 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** SET ALPHA ******************** */
@@ -43,12 +46,18 @@ static void node_composit_init_setalpha(bNodeTree *UNUSED(ntree), bNode *node)
settings->mode = CMP_NODE_SETALPHA_MODE_APPLY;
}
-void register_node_type_cmp_setalpha(void)
+static void node_composit_buts_set_alpha(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "mode", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_setalpha()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_SETALPHA, "Set Alpha", NODE_CLASS_CONVERTER, 0);
ntype.declare = blender::nodes::cmp_node_setalpha_declare;
+ ntype.draw_buttons = node_composit_buts_set_alpha;
node_type_init(&ntype, node_composit_init_setalpha);
node_type_storage(
&ntype, "NodeSetAlpha", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_splitViewer.cc b/source/blender/nodes/composite/nodes/node_composite_splitViewer.cc
index c0403a041db..63772a52840 100644
--- a/source/blender/nodes/composite/nodes/node_composite_splitViewer.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_splitViewer.cc
@@ -21,17 +21,25 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.hh"
-
#include "BKE_global.h"
#include "BKE_image.h"
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_composite_util.hh"
+
/* **************** SPLIT VIEWER ******************** */
-static bNodeSocketTemplate cmp_node_splitviewer_in[] = {
- {SOCK_RGBA, N_("Image"), 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_RGBA, N_("Image"), 0.0f, 0.0f, 0.0f, 1.0f},
- {-1, ""},
-};
+
+namespace blender::nodes {
+
+static void cmp_node_split_viewer_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image"));
+ b.add_input<decl::Color>(N_("Image"), "Image_001");
+}
+
+} // namespace blender::nodes
static void node_composit_init_splitviewer(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -43,13 +51,24 @@ static void node_composit_init_splitviewer(bNodeTree *UNUSED(ntree), bNode *node
node->id = (ID *)BKE_image_ensure_viewer(G.main, IMA_TYPE_COMPOSITE, "Viewer Node");
}
-void register_node_type_cmp_splitviewer(void)
+static void node_composit_buts_splitviewer(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *row, *col;
+
+ col = uiLayoutColumn(layout, false);
+ row = uiLayoutRow(col, false);
+ uiItemR(row, ptr, "axis", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "factor", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_splitviewer()
{
static bNodeType ntype;
cmp_node_type_base(
&ntype, CMP_NODE_SPLITVIEWER, "Split Viewer", NODE_CLASS_OUTPUT, NODE_PREVIEW);
- node_type_socket_templates(&ntype, cmp_node_splitviewer_in, nullptr);
+ ntype.declare = blender::nodes::cmp_node_split_viewer_declare;
+ ntype.draw_buttons = node_composit_buts_splitviewer;
node_type_init(&ntype, node_composit_init_splitviewer);
node_type_storage(&ntype, "ImageUser", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_stabilize2d.cc b/source/blender/nodes/composite/nodes/node_composite_stabilize2d.cc
index e5ce2e8ceb9..de6cc21ccd5 100644
--- a/source/blender/nodes/composite/nodes/node_composite_stabilize2d.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_stabilize2d.cc
@@ -21,22 +21,25 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.hh"
+#include "UI_interface.h"
+#include "UI_resources.h"
#include "BKE_context.h"
#include "BKE_lib_id.h"
-/* **************** Translate ******************** */
+#include "node_composite_util.hh"
-static bNodeSocketTemplate cmp_node_stabilize2d_in[] = {
- {SOCK_RGBA, N_("Image"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {-1, ""},
-};
+/* **************** Stabilize 2D ******************** */
-static bNodeSocketTemplate cmp_node_stabilize2d_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void cmp_node_stabilize2d_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
static void init(const bContext *C, PointerRNA *ptr)
{
@@ -50,12 +53,36 @@ static void init(const bContext *C, PointerRNA *ptr)
node->custom1 = 1;
}
-void register_node_type_cmp_stabilize2d(void)
+static void node_composit_buts_stabilize2d(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ bNode *node = (bNode *)ptr->data;
+
+ uiTemplateID(layout,
+ C,
+ ptr,
+ "clip",
+ nullptr,
+ "CLIP_OT_open",
+ nullptr,
+ UI_TEMPLATE_ID_FILTER_ALL,
+ false,
+ nullptr);
+
+ if (!node->id) {
+ return;
+ }
+
+ uiItemR(layout, ptr, "filter_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ uiItemR(layout, ptr, "invert", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_stabilize2d()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_STABILIZE2D, "Stabilize 2D", NODE_CLASS_DISTORT, 0);
- node_type_socket_templates(&ntype, cmp_node_stabilize2d_in, cmp_node_stabilize2d_out);
+ ntype.declare = blender::nodes::cmp_node_stabilize2d_declare;
+ ntype.draw_buttons = node_composit_buts_stabilize2d;
ntype.initfunc_api = init;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_sunbeams.cc b/source/blender/nodes/composite/nodes/node_composite_sunbeams.cc
index 73907d2e27f..f5d69c7d17b 100644
--- a/source/blender/nodes/composite/nodes/node_composite_sunbeams.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_sunbeams.cc
@@ -21,16 +21,20 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
-static bNodeSocketTemplate inputs[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
-static bNodeSocketTemplate outputs[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void cmp_node_sunbeams_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
static void init(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -41,12 +45,24 @@ static void init(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = data;
}
-void register_node_type_cmp_sunbeams(void)
+static void node_composit_buts_sunbeams(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "source", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_EXPAND, "", ICON_NONE);
+ uiItemR(layout,
+ ptr,
+ "ray_length",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+}
+
+void register_node_type_cmp_sunbeams()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_SUNBEAMS, "Sun Beams", NODE_CLASS_OP_FILTER, 0);
- node_type_socket_templates(&ntype, inputs, outputs);
+ ntype.declare = blender::nodes::cmp_node_sunbeams_declare;
+ ntype.draw_buttons = node_composit_buts_sunbeams;
node_type_init(&ntype, init);
node_type_storage(
&ntype, "NodeSunBeams", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_switch.cc b/source/blender/nodes/composite/nodes/node_composite_switch.cc
index 71226a6da0b..d13bcc28d10 100644
--- a/source/blender/nodes/composite/nodes/node_composite_switch.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_switch.cc
@@ -21,27 +21,37 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "../node_composite_util.hh"
-/* **************** MIX RGB ******************** */
-static bNodeSocketTemplate cmp_node_switch_in[] = {
- {SOCK_RGBA, N_("Off"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {SOCK_RGBA, N_("On"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {-1, ""},
-};
+/* **************** Switch ******************** */
+
+namespace blender::nodes {
+
+static void cmp_node_switch_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Off")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_input<decl::Color>(N_("On")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
-static bNodeSocketTemplate cmp_node_switch_out[] = {
- {SOCK_RGBA, N_("Image"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
- {-1, ""},
-};
+static void node_composit_buts_switch(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "check", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
/* custom1 = mix type */
-void register_node_type_cmp_switch(void)
+void register_node_type_cmp_switch()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_SWITCH, "Switch", NODE_CLASS_LAYOUT, 0);
- node_type_socket_templates(&ntype, cmp_node_switch_in, cmp_node_switch_out);
+ ntype.declare = blender::nodes::cmp_node_switch_declare;
+ ntype.draw_buttons = node_composit_buts_switch;
node_type_size_preset(&ntype, NODE_SIZE_SMALL);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_switchview.cc b/source/blender/nodes/composite/nodes/node_composite_switchview.cc
index a61712f7f8d..159d66fc6cc 100644
--- a/source/blender/nodes/composite/nodes/node_composite_switchview.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_switchview.cc
@@ -25,9 +25,13 @@
#include "BKE_context.h"
#include "BKE_lib_id.h"
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "../node_composite_util.hh"
/* **************** SWITCH VIEW ******************** */
+
static bNodeSocketTemplate cmp_node_switch_view_out[] = {
{SOCK_RGBA, N_("Image"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
{-1, ""},
@@ -137,13 +141,27 @@ static void init_switch_view(const bContext *C, PointerRNA *ptr)
cmp_node_switch_view_sanitycheck(ntree, node);
}
-void register_node_type_cmp_switch_view(void)
+static void node_composit_buts_switch_view_ex(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *UNUSED(ptr))
+{
+ uiItemFullO(layout,
+ "NODE_OT_switch_view_update",
+ "Update Views",
+ ICON_FILE_REFRESH,
+ nullptr,
+ WM_OP_INVOKE_DEFAULT,
+ 0,
+ nullptr);
+}
+
+void register_node_type_cmp_switch_view()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_SWITCH_VIEW, "Switch View", NODE_CLASS_CONVERTER, 0);
node_type_socket_templates(&ntype, nullptr, cmp_node_switch_view_out);
-
+ ntype.draw_buttons_ex = node_composit_buts_switch_view_ex;
ntype.initfunc_api = init_switch_view;
node_type_update(&ntype, cmp_node_switch_view_update);
diff --git a/source/blender/nodes/composite/nodes/node_composite_texture.cc b/source/blender/nodes/composite/nodes/node_composite_texture.cc
index 55ae6a4185e..5e5fca755b2 100644
--- a/source/blender/nodes/composite/nodes/node_composite_texture.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_texture.cc
@@ -41,7 +41,7 @@ static void cmp_node_texture_declare(NodeDeclarationBuilder &b)
} // namespace blender::nodes
-void register_node_type_cmp_texture(void)
+void register_node_type_cmp_texture()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/composite/nodes/node_composite_tonemap.cc b/source/blender/nodes/composite/nodes/node_composite_tonemap.cc
index 33d6f98201c..c6015eda08c 100644
--- a/source/blender/nodes/composite/nodes/node_composite_tonemap.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_tonemap.cc
@@ -21,6 +21,11 @@
* \ingroup cmpnodes
*/
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
namespace blender::nodes {
@@ -49,12 +54,35 @@ static void node_composit_init_tonemap(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = ntm;
}
-void register_node_type_cmp_tonemap(void)
+static void node_composit_buts_tonemap(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, false);
+ uiItemR(col, ptr, "tonemap_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ if (RNA_enum_get(ptr, "tonemap_type") == 0) {
+ uiItemR(col, ptr, "key", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "offset", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "gamma", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+ else {
+ uiItemR(col, ptr, "intensity", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(
+ col, ptr, "contrast", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ uiItemR(
+ col, ptr, "adaptation", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ uiItemR(
+ col, ptr, "correction", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ }
+}
+
+void register_node_type_cmp_tonemap()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_TONEMAP, "Tonemap", NODE_CLASS_OP_COLOR, 0);
ntype.declare = blender::nodes::cmp_node_tonemap_declare;
+ ntype.draw_buttons = node_composit_buts_tonemap;
node_type_init(&ntype, node_composit_init_tonemap);
node_type_storage(&ntype, "NodeTonemap", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_trackpos.cc b/source/blender/nodes/composite/nodes/node_composite_trackpos.cc
index 537f7e661db..3be52820f15 100644
--- a/source/blender/nodes/composite/nodes/node_composite_trackpos.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_trackpos.cc
@@ -21,6 +21,11 @@
* \ingroup cmpnodes
*/
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
namespace blender::nodes {
@@ -42,12 +47,61 @@ static void init(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = data;
}
-void register_node_type_cmp_trackpos(void)
+static void node_composit_buts_trackpos(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ bNode *node = (bNode *)ptr->data;
+
+ uiTemplateID(layout,
+ C,
+ ptr,
+ "clip",
+ nullptr,
+ "CLIP_OT_open",
+ nullptr,
+ UI_TEMPLATE_ID_FILTER_ALL,
+ false,
+ nullptr);
+
+ if (node->id) {
+ MovieClip *clip = (MovieClip *)node->id;
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingObject *object;
+ uiLayout *col;
+ PointerRNA tracking_ptr;
+ NodeTrackPosData *data = (NodeTrackPosData *)node->storage;
+
+ RNA_pointer_create(&clip->id, &RNA_MovieTracking, tracking, &tracking_ptr);
+
+ col = uiLayoutColumn(layout, false);
+ uiItemPointerR(col, ptr, "tracking_object", &tracking_ptr, "objects", "", ICON_OBJECT_DATA);
+
+ object = BKE_tracking_object_get_named(tracking, data->tracking_object);
+ if (object) {
+ PointerRNA object_ptr;
+
+ RNA_pointer_create(&clip->id, &RNA_MovieTrackingObject, object, &object_ptr);
+
+ uiItemPointerR(col, ptr, "track_name", &object_ptr, "tracks", "", ICON_ANIM_DATA);
+ }
+ else {
+ uiItemR(layout, ptr, "track_name", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_ANIM_DATA);
+ }
+
+ uiItemR(layout, ptr, "position", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ if (ELEM(node->custom1, CMP_TRACKPOS_RELATIVE_FRAME, CMP_TRACKPOS_ABSOLUTE_FRAME)) {
+ uiItemR(layout, ptr, "frame_relative", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+ }
+}
+
+void register_node_type_cmp_trackpos()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_TRACKPOS, "Track Position", NODE_CLASS_INPUT, 0);
ntype.declare = blender::nodes::cmp_node_trackpos_declare;
+ ntype.draw_buttons = node_composit_buts_trackpos;
node_type_init(&ntype, init);
node_type_storage(
&ntype, "NodeTrackPosData", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_transform.cc b/source/blender/nodes/composite/nodes/node_composite_transform.cc
index 1695101cdbf..ad1cc4cd308 100644
--- a/source/blender/nodes/composite/nodes/node_composite_transform.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_transform.cc
@@ -21,30 +21,43 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Transform ******************** */
-static bNodeSocketTemplate cmp_node_transform_in[] = {
- {SOCK_RGBA, N_("Image"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("X"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f},
- {SOCK_FLOAT, N_("Y"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f},
- {SOCK_FLOAT, N_("Angle"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f, PROP_ANGLE},
- {SOCK_FLOAT, N_("Scale"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0001f, CMP_SCALE_MAX},
- {-1, ""},
-};
-
-static bNodeSocketTemplate cmp_node_transform_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
-
-void register_node_type_cmp_transform(void)
+namespace blender::nodes {
+
+static void cmp_node_transform_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_input<decl::Float>(N_("X")).default_value(0.0f).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>(N_("Y")).default_value(0.0f).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>(N_("Angle"))
+ .default_value(0.0f)
+ .min(-10000.0f)
+ .max(10000.0f)
+ .subtype(PROP_ANGLE);
+ b.add_input<decl::Float>(N_("Scale")).default_value(1.0f).min(0.0001f).max(CMP_SCALE_MAX);
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
+
+static void node_composit_buts_transform(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "filter_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
+
+void register_node_type_cmp_transform()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_TRANSFORM, "Transform", NODE_CLASS_DISTORT, 0);
- node_type_socket_templates(&ntype, cmp_node_transform_in, cmp_node_transform_out);
+ ntype.declare = blender::nodes::cmp_node_transform_declare;
+ ntype.draw_buttons = node_composit_buts_transform;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_translate.cc b/source/blender/nodes/composite/nodes/node_composite_translate.cc
index 0ee8a41a5ea..ce29cc55ca2 100644
--- a/source/blender/nodes/composite/nodes/node_composite_translate.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_translate.cc
@@ -21,20 +21,24 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
-/* **************** Translate ******************** */
+/* **************** Translate ******************** */
+
+namespace blender::nodes {
+
+static void cmp_node_translate_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("X")).default_value(0.0f).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>(N_("Y")).default_value(0.0f).min(-10000.0f).max(10000.0f);
+ b.add_output<decl::Color>(N_("Image"));
+}
-static bNodeSocketTemplate cmp_node_translate_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_FLOAT, N_("X"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f, PROP_NONE},
- {SOCK_FLOAT, N_("Y"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f, PROP_NONE},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_translate_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+} // namespace blender::nodes
static void node_composit_init_translate(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -43,12 +47,19 @@ static void node_composit_init_translate(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = data;
}
-void register_node_type_cmp_translate(void)
+static void node_composit_buts_translate(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "use_relative", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "wrap_axis", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_translate()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_TRANSLATE, "Translate", NODE_CLASS_DISTORT, 0);
- node_type_socket_templates(&ntype, cmp_node_translate_in, cmp_node_translate_out);
+ ntype.declare = blender::nodes::cmp_node_translate_declare;
+ ntype.draw_buttons = node_composit_buts_translate;
node_type_init(&ntype, node_composit_init_translate);
node_type_storage(
&ntype, "NodeTranslateData", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_valToRgb.cc b/source/blender/nodes/composite/nodes/node_composite_valToRgb.cc
index a0ab056e657..dca6c9c141c 100644
--- a/source/blender/nodes/composite/nodes/node_composite_valToRgb.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_valToRgb.cc
@@ -41,7 +41,7 @@ static void node_composit_init_valtorgb(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = BKE_colorband_add(true);
}
-void register_node_type_cmp_valtorgb(void)
+void register_node_type_cmp_valtorgb()
{
static bNodeType ntype;
@@ -66,7 +66,7 @@ static void cmp_node_rgbtobw_declare(NodeDeclarationBuilder &b)
} // namespace blender::nodes
-void register_node_type_cmp_rgbtobw(void)
+void register_node_type_cmp_rgbtobw()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/composite/nodes/node_composite_value.cc b/source/blender/nodes/composite/nodes/node_composite_value.cc
index 51214d23472..d2274d2d82a 100644
--- a/source/blender/nodes/composite/nodes/node_composite_value.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_value.cc
@@ -34,7 +34,7 @@ static void cmp_node_value_declare(NodeDeclarationBuilder &b)
} // namespace blender::nodes
-void register_node_type_cmp_value(void)
+void register_node_type_cmp_value()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/composite/nodes/node_composite_vecBlur.cc b/source/blender/nodes/composite/nodes/node_composite_vecBlur.cc
index ce6ba659609..c4bea269670 100644
--- a/source/blender/nodes/composite/nodes/node_composite_vecBlur.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_vecBlur.cc
@@ -21,15 +21,28 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** VECTOR BLUR ******************** */
-static bNodeSocketTemplate cmp_node_vecblur_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_FLOAT, N_("Z"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE},
- {SOCK_VECTOR, N_("Speed"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_VELOCITY},
- {-1, ""}};
-static bNodeSocketTemplate cmp_node_vecblur_out[] = {{SOCK_RGBA, N_("Image")}, {-1, ""}};
+
+namespace blender::nodes {
+
+static void cmp_node_vec_blur_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Z")).default_value(0.0f).min(0.0f).max(1.0f);
+ b.add_input<decl::Vector>(N_("Speed"))
+ .default_value({0.0f, 0.0f, 0.0f})
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_VELOCITY);
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
static void node_composit_init_vecblur(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -39,13 +52,30 @@ static void node_composit_init_vecblur(bNodeTree *UNUSED(ntree), bNode *node)
nbd->fac = 1.0f;
}
+static void node_composit_buts_vecblur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, false);
+ uiItemR(col, ptr, "samples", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "factor", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Blur"), ICON_NONE);
+
+ col = uiLayoutColumn(layout, true);
+ uiItemL(col, IFACE_("Speed:"), ICON_NONE);
+ uiItemR(col, ptr, "speed_min", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Min"), ICON_NONE);
+ uiItemR(col, ptr, "speed_max", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Max"), ICON_NONE);
+
+ uiItemR(layout, ptr, "use_curved", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
/* custom1: iterations, custom2: max_speed (0 = no_limit). */
-void register_node_type_cmp_vecblur(void)
+void register_node_type_cmp_vecblur()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_VECBLUR, "Vector Blur", NODE_CLASS_OP_FILTER, 0);
- node_type_socket_templates(&ntype, cmp_node_vecblur_in, cmp_node_vecblur_out);
+ ntype.declare = blender::nodes::cmp_node_vec_blur_declare;
+ ntype.draw_buttons = node_composit_buts_vecblur;
node_type_init(&ntype, node_composit_init_vecblur);
node_type_storage(
&ntype, "NodeBlurData", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_viewer.cc b/source/blender/nodes/composite/nodes/node_composite_viewer.cc
index 90f9882099b..fcebda3b8a4 100644
--- a/source/blender/nodes/composite/nodes/node_composite_viewer.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_viewer.cc
@@ -21,11 +21,16 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.hh"
-
#include "BKE_global.h"
#include "BKE_image.h"
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_composite_util.hh"
+
/* **************** VIEWER ******************** */
namespace blender::nodes {
@@ -50,12 +55,32 @@ static void node_composit_init_viewer(bNodeTree *UNUSED(ntree), bNode *node)
node->id = (ID *)BKE_image_ensure_viewer(G.main, IMA_TYPE_COMPOSITE, "Viewer Node");
}
-void register_node_type_cmp_viewer(void)
+static void node_composit_buts_viewer(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "use_alpha", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+static void node_composit_buts_viewer_ex(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ uiItemR(layout, ptr, "use_alpha", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "tile_order", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ if (RNA_enum_get(ptr, "tile_order") == 0) {
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "center_x", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "center_y", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+}
+
+void register_node_type_cmp_viewer()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_VIEWER, "Viewer", NODE_CLASS_OUTPUT, NODE_PREVIEW);
ntype.declare = blender::nodes::cmp_node_viewer_declare;
+ ntype.draw_buttons = node_composit_buts_viewer;
+ ntype.draw_buttons_ex = node_composit_buts_viewer_ex;
node_type_init(&ntype, node_composit_init_viewer);
node_type_storage(&ntype, "ImageUser", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_zcombine.cc b/source/blender/nodes/composite/nodes/node_composite_zcombine.cc
index 990f9fcd366..dd6872e4dd9 100644
--- a/source/blender/nodes/composite/nodes/node_composite_zcombine.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_zcombine.cc
@@ -21,29 +21,43 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Z COMBINE ******************** */
-/* lazy coder NOTE: node->custom2 is abused to send signal. */
-static bNodeSocketTemplate cmp_node_zcombine_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_FLOAT, N_("Z"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 10000.0f, PROP_NONE},
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_FLOAT, N_("Z"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 10000.0f, PROP_NONE},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_zcombine_out[] = {
- {SOCK_RGBA, N_("Image")},
- {SOCK_FLOAT, N_("Z")},
- {-1, ""},
-};
-
-void register_node_type_cmp_zcombine(void)
+
+namespace blender::nodes {
+
+static void cmp_node_zcombine_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Z")).default_value(1.0f).min(0.f).max(10000.0f);
+ b.add_input<decl::Color>(N_("Image"), "Image_001").default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Z"), "Z_001").default_value(1.0f).min(0.f).max(10000.0f);
+ b.add_output<decl::Color>(N_("Image"));
+ b.add_output<decl::Float>(N_("Z"));
+}
+
+} // namespace blender::nodes
+
+static void node_composit_buts_zcombine(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "use_alpha", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "use_antialias_z", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_zcombine()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_ZCOMBINE, "Z Combine", NODE_CLASS_OP_COLOR, 0);
- node_type_socket_templates(&ntype, cmp_node_zcombine_in, cmp_node_zcombine_out);
+ ntype.declare = blender::nodes::cmp_node_zcombine_declare;
+ ntype.draw_buttons = node_composit_buts_zcombine;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/function/node_function_util.cc b/source/blender/nodes/function/node_function_util.cc
index a1493d51a11..83f5b571695 100644
--- a/source/blender/nodes/function/node_function_util.cc
+++ b/source/blender/nodes/function/node_function_util.cc
@@ -17,13 +17,15 @@
#include "node_function_util.hh"
#include "node_util.h"
+#include "NOD_socket_search_link.hh"
+
static bool fn_node_poll_default(bNodeType *UNUSED(ntype),
bNodeTree *ntree,
const char **r_disabled_hint)
{
/* Function nodes are only supported in simulation node trees so far. */
if (!STREQ(ntree->idname, "GeometryNodeTree")) {
- *r_disabled_hint = "Not a geometry node tree";
+ *r_disabled_hint = TIP_("Not a geometry node tree");
return false;
}
return true;
@@ -34,4 +36,5 @@ void fn_node_type_base(bNodeType *ntype, int type, const char *name, short nclas
node_type_base(ntype, type, name, nclass, flag);
ntype->poll = fn_node_poll_default;
ntype->insert_link = node_insert_link_default;
+ ntype->gather_link_search_ops = blender::nodes::search_link_ops_for_basic_node;
}
diff --git a/source/blender/nodes/function/nodes/node_fn_boolean_math.cc b/source/blender/nodes/function/nodes/node_fn_boolean_math.cc
index ed03cc0025d..4b59b49c632 100644
--- a/source/blender/nodes/function/nodes/node_fn_boolean_math.cc
+++ b/source/blender/nodes/function/nodes/node_fn_boolean_math.cc
@@ -47,7 +47,10 @@ static void node_boolean_math_update(bNodeTree *ntree, bNode *node)
ntree, sockB, ELEM(node->custom1, NODE_BOOLEAN_MATH_AND, NODE_BOOLEAN_MATH_OR));
}
-static void node_boolean_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
+static void node_boolean_math_label(const bNodeTree *UNUSED(ntree),
+ const bNode *node,
+ char *label,
+ int maxlen)
{
const char *name;
bool enum_label = RNA_enum_name(rna_enum_node_boolean_math_items, node->custom1, &name);
@@ -92,7 +95,7 @@ void register_node_type_fn_boolean_math()
fn_node_type_base(&ntype, FN_NODE_BOOLEAN_MATH, "Boolean Math", NODE_CLASS_CONVERTER, 0);
ntype.declare = blender::nodes::fn_node_boolean_math_declare;
- node_type_label(&ntype, blender::nodes::node_boolean_math_label);
+ ntype.labelfunc = blender::nodes::node_boolean_math_label;
node_type_update(&ntype, blender::nodes::node_boolean_math_update);
ntype.build_multi_function = blender::nodes::fn_node_boolean_math_build_multi_function;
ntype.draw_buttons = blender::nodes::fn_node_boolean_math_layout;
diff --git a/source/blender/nodes/function/nodes/node_fn_compare.cc b/source/blender/nodes/function/nodes/node_fn_compare.cc
new file mode 100644
index 00000000000..e773563ca5f
--- /dev/null
+++ b/source/blender/nodes/function/nodes/node_fn_compare.cc
@@ -0,0 +1,540 @@
+/*
+ * 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 <cmath>
+
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "RNA_enum_types.h"
+
+#include "node_function_util.hh"
+
+#include "NOD_socket_search_link.hh"
+
+namespace blender::nodes::node_fn_compare_cc {
+
+NODE_STORAGE_FUNCS(NodeFunctionCompare)
+
+static void fn_node_compare_declare(NodeDeclarationBuilder &b)
+{
+ b.is_function_node();
+ b.add_input<decl::Float>(N_("A")).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>(N_("B")).min(-10000.0f).max(10000.0f);
+
+ b.add_input<decl::Int>(N_("A"), "A_INT");
+ b.add_input<decl::Int>(N_("B"), "B_INT");
+
+ b.add_input<decl::Vector>(N_("A"), "A_VEC3");
+ b.add_input<decl::Vector>(N_("B"), "B_VEC3");
+
+ b.add_input<decl::Color>(N_("A"), "A_COL");
+ b.add_input<decl::Color>(N_("B"), "B_COL");
+
+ b.add_input<decl::String>(N_("A"), "A_STR");
+ b.add_input<decl::String>(N_("B"), "B_STR");
+
+ b.add_input<decl::Float>(N_("C")).default_value(0.9f);
+ b.add_input<decl::Float>(N_("Angle")).default_value(0.0872665f).subtype(PROP_ANGLE);
+ b.add_input<decl::Float>(N_("Epsilon")).default_value(0.001).min(-10000.0f).max(10000.0f);
+
+ b.add_output<decl::Bool>(N_("Result"));
+};
+
+static void geo_node_compare_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ const NodeFunctionCompare &data = node_storage(*static_cast<const bNode *>(ptr->data));
+ uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
+ if (data.data_type == SOCK_VECTOR) {
+ uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
+ }
+ uiItemR(layout, ptr, "operation", 0, "", ICON_NONE);
+}
+
+static void node_compare_update(bNodeTree *ntree, bNode *node)
+{
+ NodeFunctionCompare *data = (NodeFunctionCompare *)node->storage;
+
+ bNodeSocket *sock_comp = (bNodeSocket *)BLI_findlink(&node->inputs, 10);
+ bNodeSocket *sock_angle = (bNodeSocket *)BLI_findlink(&node->inputs, 11);
+ bNodeSocket *sock_epsilon = (bNodeSocket *)BLI_findlink(&node->inputs, 12);
+
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
+ nodeSetSocketAvailability(ntree, socket, socket->type == (eNodeSocketDatatype)data->data_type);
+ }
+
+ nodeSetSocketAvailability(ntree,
+ sock_epsilon,
+ ELEM(data->operation, NODE_COMPARE_EQUAL, NODE_COMPARE_NOT_EQUAL) &&
+ !ELEM(data->data_type, SOCK_INT, SOCK_STRING));
+
+ nodeSetSocketAvailability(ntree,
+ sock_comp,
+ ELEM(data->mode, NODE_COMPARE_MODE_DOT_PRODUCT) &&
+ data->data_type == SOCK_VECTOR);
+
+ nodeSetSocketAvailability(ntree,
+ sock_angle,
+ ELEM(data->mode, NODE_COMPARE_MODE_DIRECTION) &&
+ data->data_type == SOCK_VECTOR);
+}
+
+static void node_compare_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeFunctionCompare *data = (NodeFunctionCompare *)MEM_callocN(sizeof(NodeFunctionCompare),
+ __func__);
+ data->operation = NODE_COMPARE_GREATER_THAN;
+ data->data_type = SOCK_FLOAT;
+ data->mode = NODE_COMPARE_MODE_ELEMENT;
+ node->storage = data;
+}
+
+class SocketSearchOp {
+ public:
+ std::string socket_name;
+ eNodeSocketDatatype data_type;
+ NodeCompareOperation operation;
+ NodeCompareMode mode = NODE_COMPARE_MODE_ELEMENT;
+ void operator()(LinkSearchOpParams &params)
+ {
+ bNode &node = params.add_node("FunctionNodeCompare");
+ node_storage(node).data_type = data_type;
+ node_storage(node).operation = operation;
+ node_storage(node).mode = mode;
+ params.update_and_connect_available_socket(node, socket_name);
+ }
+};
+
+static void node_compare_gather_link_searches(GatherLinkSearchOpParams &params)
+{
+ const NodeDeclaration &declaration = *params.node_type().fixed_declaration;
+ if (params.in_out() == SOCK_OUT) {
+ search_link_ops_for_declarations(params, declaration.outputs());
+ return;
+ }
+
+ const eNodeSocketDatatype type = static_cast<eNodeSocketDatatype>(params.other_socket().type);
+
+ if (ELEM(type, SOCK_FLOAT, SOCK_BOOLEAN, SOCK_RGBA, SOCK_VECTOR, SOCK_INT)) {
+ params.add_item(IFACE_("A"), SocketSearchOp{"A", type, NODE_COMPARE_GREATER_THAN});
+ params.add_item(IFACE_("B"), SocketSearchOp{"B", type, NODE_COMPARE_GREATER_THAN});
+ params.add_item(
+ IFACE_("C"),
+ SocketSearchOp{
+ "C", SOCK_VECTOR, NODE_COMPARE_GREATER_THAN, NODE_COMPARE_MODE_DOT_PRODUCT});
+ params.add_item(
+ IFACE_("Angle"),
+ SocketSearchOp{
+ "Angle", SOCK_VECTOR, NODE_COMPARE_GREATER_THAN, NODE_COMPARE_MODE_DIRECTION});
+ }
+ else if (type == SOCK_STRING) {
+ params.add_item(IFACE_("A"), SocketSearchOp{"A", type, NODE_COMPARE_EQUAL});
+ params.add_item(IFACE_("B"), SocketSearchOp{"B", type, NODE_COMPARE_EQUAL});
+ }
+}
+
+static void node_compare_label(const bNodeTree *UNUSED(ntree),
+ const bNode *node,
+ char *label,
+ int maxlen)
+{
+ const NodeFunctionCompare *data = (NodeFunctionCompare *)node->storage;
+ const char *name;
+ bool enum_label = RNA_enum_name(rna_enum_node_compare_operation_items, data->operation, &name);
+ if (!enum_label) {
+ name = "Unknown";
+ }
+ BLI_strncpy(label, IFACE_(name), maxlen);
+}
+
+static float component_average(float3 a)
+{
+ return (a.x + a.y + a.z) / 3.0f;
+}
+
+static const fn::MultiFunction *get_multi_function(bNode &node)
+{
+ const NodeFunctionCompare *data = (NodeFunctionCompare *)node.storage;
+
+ switch (data->data_type) {
+ case SOCK_FLOAT:
+ switch (data->operation) {
+ case NODE_COMPARE_LESS_THAN: {
+ static fn::CustomMF_SI_SI_SO<float, float, bool> fn{
+ "Less Than", [](float a, float b) { return a < b; }};
+ return &fn;
+ }
+ case NODE_COMPARE_LESS_EQUAL: {
+ static fn::CustomMF_SI_SI_SO<float, float, bool> fn{
+ "Less Equal", [](float a, float b) { return a <= b; }};
+ return &fn;
+ }
+ case NODE_COMPARE_GREATER_THAN: {
+ static fn::CustomMF_SI_SI_SO<float, float, bool> fn{
+ "Greater Than", [](float a, float b) { return a > b; }};
+ return &fn;
+ }
+ case NODE_COMPARE_GREATER_EQUAL: {
+ static fn::CustomMF_SI_SI_SO<float, float, bool> fn{
+ "Greater Equal", [](float a, float b) { return a >= b; }};
+ return &fn;
+ }
+ case NODE_COMPARE_EQUAL: {
+ static fn::CustomMF_SI_SI_SI_SO<float, float, float, bool> fn{
+ "Equal", [](float a, float b, float epsilon) { return std::abs(a - b) <= epsilon; }};
+ return &fn;
+ }
+ case NODE_COMPARE_NOT_EQUAL:
+ static fn::CustomMF_SI_SI_SI_SO<float, float, float, bool> fn{
+ "Not Equal",
+ [](float a, float b, float epsilon) { return std::abs(a - b) > epsilon; }};
+ return &fn;
+ }
+ break;
+ case SOCK_INT:
+ switch (data->operation) {
+ case NODE_COMPARE_LESS_THAN: {
+ static fn::CustomMF_SI_SI_SO<int, int, bool> fn{"Less Than",
+ [](int a, int b) { return a < b; }};
+ return &fn;
+ }
+ case NODE_COMPARE_LESS_EQUAL: {
+ static fn::CustomMF_SI_SI_SO<int, int, bool> fn{"Less Equal",
+ [](int a, int b) { return a <= b; }};
+ return &fn;
+ }
+ case NODE_COMPARE_GREATER_THAN: {
+ static fn::CustomMF_SI_SI_SO<int, int, bool> fn{"Greater Than",
+ [](int a, int b) { return a > b; }};
+ return &fn;
+ }
+ case NODE_COMPARE_GREATER_EQUAL: {
+ static fn::CustomMF_SI_SI_SO<int, int, bool> fn{"Greater Equal",
+ [](int a, int b) { return a >= b; }};
+ return &fn;
+ }
+ case NODE_COMPARE_EQUAL: {
+ static fn::CustomMF_SI_SI_SO<int, int, bool> fn{"Equal",
+ [](int a, int b) { return a == b; }};
+ return &fn;
+ }
+ case NODE_COMPARE_NOT_EQUAL: {
+ static fn::CustomMF_SI_SI_SO<int, int, bool> fn{"Not Equal",
+ [](int a, int b) { return a != b; }};
+ return &fn;
+ }
+ }
+ break;
+ case SOCK_VECTOR:
+ switch (data->operation) {
+ case NODE_COMPARE_LESS_THAN:
+ switch (data->mode) {
+ case NODE_COMPARE_MODE_AVERAGE: {
+ static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{
+ "Less Than - Average",
+ [](float3 a, float3 b) { return component_average(a) < component_average(b); }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_DOT_PRODUCT: {
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
+ "Less Than - Dot Product",
+ [](float3 a, float3 b, float comp) { return float3::dot(a, b) < comp; }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_DIRECTION: {
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
+ "Less Than - Direction",
+ [](float3 a, float3 b, float angle) { return angle_v3v3(a, b) < angle; }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_ELEMENT: {
+ static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{
+ "Less Than - Element-wise",
+ [](float3 a, float3 b) { return a.x < b.x && a.y < b.y && a.z < b.z; }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_LENGTH: {
+ static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{
+ "Less Than - Length",
+ [](float3 a, float3 b) { return a.length() < b.length(); }};
+ return &fn;
+ }
+ }
+ break;
+ case NODE_COMPARE_LESS_EQUAL:
+ switch (data->mode) {
+ case NODE_COMPARE_MODE_AVERAGE: {
+ static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{
+ "Less Equal - Average",
+ [](float3 a, float3 b) { return component_average(a) <= component_average(b); }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_DOT_PRODUCT: {
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
+ "Less Equal - Dot Product",
+ [](float3 a, float3 b, float comp) { return float3::dot(a, b) <= comp; }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_DIRECTION: {
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
+ "Less Equal - Direction",
+ [](float3 a, float3 b, float angle) { return angle_v3v3(a, b) <= angle; }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_ELEMENT: {
+ static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{
+ "Less Equal - Element-wise",
+ [](float3 a, float3 b) { return a.x <= b.x && a.y <= b.y && a.z <= b.z; }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_LENGTH: {
+ static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{
+ "Less Equal - Length",
+ [](float3 a, float3 b) { return a.length() <= b.length(); }};
+ return &fn;
+ }
+ }
+ break;
+ case NODE_COMPARE_GREATER_THAN:
+ switch (data->mode) {
+ case NODE_COMPARE_MODE_AVERAGE: {
+ static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{
+ "Greater Than - Average",
+ [](float3 a, float3 b) { return component_average(a) > component_average(b); }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_DOT_PRODUCT: {
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
+ "Greater Than - Dot Product",
+ [](float3 a, float3 b, float comp) { return float3::dot(a, b) > comp; }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_DIRECTION: {
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
+ "Greater Than - Direction",
+ [](float3 a, float3 b, float angle) { return angle_v3v3(a, b) > angle; }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_ELEMENT: {
+ static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{
+ "Greater Than - Element-wise",
+ [](float3 a, float3 b) { return a.x > b.x && a.y > b.y && a.z > b.z; }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_LENGTH: {
+ static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{
+ "Greater Than - Length",
+ [](float3 a, float3 b) { return a.length() > b.length(); }};
+ return &fn;
+ }
+ }
+ break;
+ case NODE_COMPARE_GREATER_EQUAL:
+ switch (data->mode) {
+ case NODE_COMPARE_MODE_AVERAGE: {
+ static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{
+ "Greater Equal - Average",
+ [](float3 a, float3 b) { return component_average(a) >= component_average(b); }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_DOT_PRODUCT: {
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
+ "Greater Equal - Dot Product",
+ [](float3 a, float3 b, float comp) { return float3::dot(a, b) >= comp; }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_DIRECTION: {
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
+ "Greater Equal - Direction",
+ [](float3 a, float3 b, float angle) { return angle_v3v3(a, b) >= angle; }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_ELEMENT: {
+ static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{
+ "Greater Equal - Element-wise",
+ [](float3 a, float3 b) { return a.x >= b.x && a.y >= b.y && a.z >= b.z; }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_LENGTH: {
+ static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{
+ "Greater Equal - Length",
+ [](float3 a, float3 b) { return a.length() >= b.length(); }};
+ return &fn;
+ }
+ }
+ break;
+ case NODE_COMPARE_EQUAL:
+ switch (data->mode) {
+ case NODE_COMPARE_MODE_AVERAGE: {
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
+ "Equal - Average", [](float3 a, float3 b, float epsilon) {
+ return abs(component_average(a) - component_average(b)) <= epsilon;
+ }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_DOT_PRODUCT: {
+ static fn::CustomMF_SI_SI_SI_SI_SO<float3, float3, float, float, bool> fn{
+ "Equal - Dot Product", [](float3 a, float3 b, float comp, float epsilon) {
+ return abs(float3::dot(a, b) - comp) <= epsilon;
+ }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_DIRECTION: {
+ static fn::CustomMF_SI_SI_SI_SI_SO<float3, float3, float, float, bool> fn{
+ "Equal - Direction", [](float3 a, float3 b, float angle, float epsilon) {
+ return abs(angle_v3v3(a, b) - angle) <= epsilon;
+ }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_ELEMENT: {
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
+ "Equal - Element-wise", [](float3 a, float3 b, float epsilon) {
+ return abs(a.x - b.x) <= epsilon && abs(a.y - b.y) <= epsilon &&
+ abs(a.z - b.z) <= epsilon;
+ }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_LENGTH: {
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
+ "Equal - Length", [](float3 a, float3 b, float epsilon) {
+ return abs(a.length() - b.length()) <= epsilon;
+ }};
+ return &fn;
+ }
+ }
+ break;
+ case NODE_COMPARE_NOT_EQUAL:
+ switch (data->mode) {
+ case NODE_COMPARE_MODE_AVERAGE: {
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
+ "Not Equal - Average", [](float3 a, float3 b, float epsilon) {
+ return abs(component_average(a) - component_average(b)) > epsilon;
+ }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_DOT_PRODUCT: {
+ static fn::CustomMF_SI_SI_SI_SI_SO<float3, float3, float, float, bool> fn{
+ "Not Equal - Dot Product", [](float3 a, float3 b, float comp, float epsilon) {
+ return abs(float3::dot(a, b) - comp) >= epsilon;
+ }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_DIRECTION: {
+ static fn::CustomMF_SI_SI_SI_SI_SO<float3, float3, float, float, bool> fn{
+ "Not Equal - Direction", [](float3 a, float3 b, float angle, float epsilon) {
+ return abs(angle_v3v3(a, b) - angle) > epsilon;
+ }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_ELEMENT: {
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
+ "Not Equal - Element-wise", [](float3 a, float3 b, float epsilon) {
+ return abs(a.x - b.x) > epsilon && abs(a.y - b.y) > epsilon &&
+ abs(a.z - b.z) > epsilon;
+ }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_LENGTH: {
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
+ "Not Equal - Length", [](float3 a, float3 b, float epsilon) {
+ return abs(a.length() - b.length()) > epsilon;
+ }};
+ return &fn;
+ }
+ }
+ break;
+ }
+ break;
+ case SOCK_RGBA:
+ switch (data->operation) {
+ case NODE_COMPARE_EQUAL: {
+ static fn::CustomMF_SI_SI_SI_SO<ColorGeometry4f, ColorGeometry4f, float, bool> fn{
+ "Equal", [](ColorGeometry4f a, ColorGeometry4f b, float epsilon) {
+ return abs(a.r - b.r) <= epsilon && abs(a.g - b.g) <= epsilon &&
+ abs(a.b - b.b) <= epsilon;
+ }};
+ return &fn;
+ }
+ case NODE_COMPARE_NOT_EQUAL: {
+ static fn::CustomMF_SI_SI_SI_SO<ColorGeometry4f, ColorGeometry4f, float, bool> fn{
+ "Not Equal", [](ColorGeometry4f a, ColorGeometry4f b, float epsilon) {
+ return abs(a.r - b.r) > epsilon && abs(a.g - b.g) > epsilon &&
+ abs(a.b - b.b) > epsilon;
+ }};
+ return &fn;
+ }
+ case NODE_COMPARE_COLOR_BRIGHTER: {
+ static fn::CustomMF_SI_SI_SO<ColorGeometry4f, ColorGeometry4f, bool> fn{
+ "Brighter", [](ColorGeometry4f a, ColorGeometry4f b) {
+ return rgb_to_grayscale(a) > rgb_to_grayscale(b);
+ }};
+ return &fn;
+ }
+ case NODE_COMPARE_COLOR_DARKER: {
+ static fn::CustomMF_SI_SI_SO<ColorGeometry4f, ColorGeometry4f, bool> fn{
+ "Darker", [](ColorGeometry4f a, ColorGeometry4f b) {
+ return rgb_to_grayscale(a) < rgb_to_grayscale(b);
+ }};
+ return &fn;
+ }
+ }
+ break;
+ case SOCK_STRING:
+ switch (data->operation) {
+ case NODE_COMPARE_EQUAL: {
+ static fn::CustomMF_SI_SI_SO<std::string, std::string, bool> fn{
+ "Equal", [](std::string a, std::string b) { return a == b; }};
+ return &fn;
+ }
+ case NODE_COMPARE_NOT_EQUAL: {
+ static fn::CustomMF_SI_SI_SO<std::string, std::string, bool> fn{
+ "Not Equal", [](std::string a, std::string b) { return a != b; }};
+ return &fn;
+ }
+ }
+ break;
+ }
+ return nullptr;
+}
+
+static void fn_node_compare_build_multi_function(NodeMultiFunctionBuilder &builder)
+{
+ const fn::MultiFunction *fn = get_multi_function(builder.node());
+ builder.set_matching_fn(fn);
+}
+
+} // namespace blender::nodes::node_fn_compare_cc
+
+void register_node_type_fn_compare()
+{
+ namespace file_ns = blender::nodes::node_fn_compare_cc;
+
+ static bNodeType ntype;
+ fn_node_type_base(&ntype, FN_NODE_COMPARE, "Compare", NODE_CLASS_CONVERTER, 0);
+ ntype.declare = file_ns::fn_node_compare_declare;
+ ntype.labelfunc = file_ns::node_compare_label;
+ node_type_update(&ntype, file_ns::node_compare_update);
+ node_type_init(&ntype, file_ns::node_compare_init);
+ node_type_storage(
+ &ntype, "NodeFunctionCompare", node_free_standard_storage, node_copy_standard_storage);
+ ntype.build_multi_function = file_ns::fn_node_compare_build_multi_function;
+ ntype.draw_buttons = file_ns::geo_node_compare_layout;
+ ntype.gather_link_search_ops = file_ns::node_compare_gather_link_searches;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/function/nodes/node_fn_float_compare.cc b/source/blender/nodes/function/nodes/node_fn_float_compare.cc
deleted file mode 100644
index b31611a1df2..00000000000
--- a/source/blender/nodes/function/nodes/node_fn_float_compare.cc
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#include <cmath>
-
-#include "BLI_listbase.h"
-#include "BLI_string.h"
-
-#include "RNA_enum_types.h"
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-#include "node_function_util.hh"
-
-namespace blender::nodes {
-
-static void fn_node_float_compare_declare(NodeDeclarationBuilder &b)
-{
- b.is_function_node();
- b.add_input<decl::Float>(N_("A")).min(-10000.0f).max(10000.0f);
- b.add_input<decl::Float>(N_("B")).min(-10000.0f).max(10000.0f);
- b.add_input<decl::Float>(N_("Epsilon")).default_value(0.001f).min(-10000.0f).max(10000.0f);
- b.add_output<decl::Bool>(N_("Result"));
-};
-
-static void geo_node_float_compare_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "operation", 0, "", ICON_NONE);
-}
-
-static void node_float_compare_update(bNodeTree *ntree, bNode *node)
-{
- bNodeSocket *sockEpsilon = (bNodeSocket *)BLI_findlink(&node->inputs, 2);
-
- nodeSetSocketAvailability(
- ntree,
- sockEpsilon,
- ELEM(node->custom1, NODE_FLOAT_COMPARE_EQUAL, NODE_FLOAT_COMPARE_NOT_EQUAL));
-}
-
-static void node_float_compare_label(bNodeTree *UNUSED(ntree),
- bNode *node,
- char *label,
- int maxlen)
-{
- const char *name;
- bool enum_label = RNA_enum_name(rna_enum_node_float_compare_items, node->custom1, &name);
- if (!enum_label) {
- name = "Unknown";
- }
- BLI_strncpy(label, IFACE_(name), maxlen);
-}
-
-static const fn::MultiFunction *get_multi_function(bNode &node)
-{
- static fn::CustomMF_SI_SI_SO<float, float, bool> less_than_fn{
- "Less Than", [](float a, float b) { return a < b; }};
- static fn::CustomMF_SI_SI_SO<float, float, bool> less_equal_fn{
- "Less Equal", [](float a, float b) { return a <= b; }};
- static fn::CustomMF_SI_SI_SO<float, float, bool> greater_than_fn{
- "Greater Than", [](float a, float b) { return a > b; }};
- static fn::CustomMF_SI_SI_SO<float, float, bool> greater_equal_fn{
- "Greater Equal", [](float a, float b) { return a >= b; }};
- static fn::CustomMF_SI_SI_SI_SO<float, float, float, bool> equal_fn{
- "Equal", [](float a, float b, float epsilon) { return std::abs(a - b) <= epsilon; }};
- static fn::CustomMF_SI_SI_SI_SO<float, float, float, bool> not_equal_fn{
- "Not Equal", [](float a, float b, float epsilon) { return std::abs(a - b) > epsilon; }};
-
- switch (node.custom1) {
- case NODE_FLOAT_COMPARE_LESS_THAN:
- return &less_than_fn;
- case NODE_FLOAT_COMPARE_LESS_EQUAL:
- return &less_equal_fn;
- case NODE_FLOAT_COMPARE_GREATER_THAN:
- return &greater_than_fn;
- case NODE_FLOAT_COMPARE_GREATER_EQUAL:
- return &greater_equal_fn;
- case NODE_FLOAT_COMPARE_EQUAL:
- return &equal_fn;
- case NODE_FLOAT_COMPARE_NOT_EQUAL:
- return &not_equal_fn;
- }
-
- BLI_assert_unreachable();
- return nullptr;
-}
-
-static void fn_node_float_compare_build_multi_function(NodeMultiFunctionBuilder &builder)
-{
- const fn::MultiFunction *fn = get_multi_function(builder.node());
- builder.set_matching_fn(fn);
-}
-
-} // namespace blender::nodes
-
-void register_node_type_fn_float_compare()
-{
- static bNodeType ntype;
-
- fn_node_type_base(&ntype, FN_NODE_COMPARE_FLOATS, "Compare Floats", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::fn_node_float_compare_declare;
- node_type_label(&ntype, blender::nodes::node_float_compare_label);
- node_type_update(&ntype, blender::nodes::node_float_compare_update);
- ntype.build_multi_function = blender::nodes::fn_node_float_compare_build_multi_function;
- ntype.draw_buttons = blender::nodes::geo_node_float_compare_layout;
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/function/nodes/node_fn_float_to_int.cc b/source/blender/nodes/function/nodes/node_fn_float_to_int.cc
index e6ec925f945..21f6734e4aa 100644
--- a/source/blender/nodes/function/nodes/node_fn_float_to_int.cc
+++ b/source/blender/nodes/function/nodes/node_fn_float_to_int.cc
@@ -39,7 +39,10 @@ static void fn_node_float_to_int_layout(uiLayout *layout, bContext *UNUSED(C), P
uiItemR(layout, ptr, "rounding_mode", 0, "", ICON_NONE);
}
-static void node_float_to_int_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
+static void node_float_to_int_label(const bNodeTree *UNUSED(ntree),
+ const bNode *node,
+ char *label,
+ int maxlen)
{
const char *name;
bool enum_label = RNA_enum_name(rna_enum_node_float_to_int_items, node->custom1, &name);
@@ -86,7 +89,7 @@ void register_node_type_fn_float_to_int()
fn_node_type_base(&ntype, FN_NODE_FLOAT_TO_INT, "Float to Integer", NODE_CLASS_CONVERTER, 0);
ntype.declare = blender::nodes::fn_node_float_to_int_declare;
- node_type_label(&ntype, blender::nodes::node_float_to_int_label);
+ ntype.labelfunc = blender::nodes::node_float_to_int_label;
ntype.build_multi_function = blender::nodes::fn_node_float_to_int_build_multi_function;
ntype.draw_buttons = blender::nodes::fn_node_float_to_int_layout;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/function/nodes/node_fn_random_value.cc b/source/blender/nodes/function/nodes/node_fn_random_value.cc
index 9720a39b740..b053482c99d 100644
--- a/source/blender/nodes/function/nodes/node_fn_random_value.cc
+++ b/source/blender/nodes/function/nodes/node_fn_random_value.cc
@@ -19,11 +19,15 @@
#include "node_function_util.hh"
+#include "NOD_socket_search_link.hh"
+
#include "UI_interface.h"
#include "UI_resources.h"
namespace blender::nodes {
+NODE_STORAGE_FUNCS(NodeRandomValue)
+
static void fn_node_random_value_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Vector>(N_("Min")).supports_field();
@@ -41,7 +45,8 @@ static void fn_node_random_value_declare(NodeDeclarationBuilder &b)
.max(1.0f)
.default_value(0.5f)
.subtype(PROP_FACTOR)
- .supports_field();
+ .supports_field()
+ .make_available([](bNode &node) { node_storage(node).data_type = CD_PROP_BOOL; });
b.add_input<decl::Int>(N_("ID")).implicit_field();
b.add_input<decl::Int>(N_("Seed")).default_value(0).min(-10000).max(10000).supports_field();
@@ -65,7 +70,7 @@ static void fn_node_random_value_init(bNodeTree *UNUSED(tree), bNode *node)
static void fn_node_random_value_update(bNodeTree *ntree, bNode *node)
{
- const NodeRandomValue &storage = *(const NodeRandomValue *)node->storage;
+ const NodeRandomValue &storage = node_storage(*node);
const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
bNodeSocket *sock_min_vector = (bNodeSocket *)node->inputs.first;
@@ -95,6 +100,55 @@ static void fn_node_random_value_update(bNodeTree *ntree, bNode *node)
nodeSetSocketAvailability(ntree, sock_out_bool, data_type == CD_PROP_BOOL);
}
+static std::optional<CustomDataType> node_type_from_other_socket(const bNodeSocket &socket)
+{
+ switch (socket.type) {
+ case SOCK_FLOAT:
+ return CD_PROP_FLOAT;
+ case SOCK_BOOLEAN:
+ return CD_PROP_BOOL;
+ case SOCK_INT:
+ return CD_PROP_INT32;
+ case SOCK_VECTOR:
+ return CD_PROP_FLOAT3;
+ case SOCK_RGBA:
+ return CD_PROP_COLOR;
+ default:
+ return {};
+ }
+}
+
+static void fn_node_random_value_gather_link_search(GatherLinkSearchOpParams &params)
+{
+ const NodeDeclaration &declaration = *params.node_type().fixed_declaration;
+ const std::optional<CustomDataType> type = node_type_from_other_socket(params.other_socket());
+ if (!type) {
+ return;
+ }
+ if (params.in_out() == SOCK_IN) {
+ if (ELEM(*type, CD_PROP_INT32, CD_PROP_FLOAT3, CD_PROP_FLOAT)) {
+ params.add_item(IFACE_("Min"), [type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("FunctionNodeRandomValue");
+ node_storage(node).data_type = *type;
+ params.update_and_connect_available_socket(node, "Min");
+ });
+ params.add_item(IFACE_("Max"), [type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("FunctionNodeRandomValue");
+ node_storage(node).data_type = *type;
+ params.update_and_connect_available_socket(node, "Max");
+ });
+ }
+ search_link_ops_for_declarations(params, declaration.inputs().take_back(3));
+ }
+ else {
+ params.add_item(IFACE_("Value"), [type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("FunctionNodeRandomValue");
+ node_storage(node).data_type = *type;
+ params.update_and_connect_available_socket(node, "Value");
+ });
+ }
+}
+
class RandomVectorFunction : public fn::MultiFunction {
public:
RandomVectorFunction()
@@ -203,14 +257,16 @@ class RandomIntFunction : public fn::MultiFunction {
const VArray<int> &seeds = params.readonly_single_input<int>(3, "Seed");
MutableSpan<int> values = params.uninitialized_single_output<int>(4, "Value");
+ /* Add one to the maximum and use floor to produce an even
+ * distribution for the first and last values (See T93591). */
for (int64_t i : mask) {
const float min_value = min_values[i];
- const float max_value = max_values[i];
+ const float max_value = max_values[i] + 1.0f;
const int seed = seeds[i];
const int id = ids[i];
const float value = noise::hash_to_float(id, seed);
- values[i] = round_fl_to_int(value * (max_value - min_value) + min_value);
+ values[i] = floor(value * (max_value - min_value) + min_value);
}
}
};
@@ -251,7 +307,7 @@ class RandomBoolFunction : public fn::MultiFunction {
static void fn_node_random_value_build_multi_function(NodeMultiFunctionBuilder &builder)
{
- const NodeRandomValue &storage = *(const NodeRandomValue *)builder.node().storage;
+ const NodeRandomValue &storage = node_storage(builder.node());
const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
switch (data_type) {
@@ -293,6 +349,7 @@ void register_node_type_fn_random_value()
ntype.draw_buttons = blender::nodes::fn_node_random_value_layout;
ntype.declare = blender::nodes::fn_node_random_value_declare;
ntype.build_multi_function = blender::nodes::fn_node_random_value_build_multi_function;
+ ntype.gather_link_search_ops = blender::nodes::fn_node_random_value_gather_link_search;
node_type_storage(
&ntype, "NodeRandomValue", node_free_standard_storage, node_copy_standard_storage);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/CMakeLists.txt b/source/blender/nodes/geometry/CMakeLists.txt
index 5ee26260790..f9a64381981 100644
--- a/source/blender/nodes/geometry/CMakeLists.txt
+++ b/source/blender/nodes/geometry/CMakeLists.txt
@@ -39,48 +39,49 @@ set(INC
set(SRC
- nodes/legacy/node_geo_align_rotation_to_vector.cc
- nodes/legacy/node_geo_attribute_clamp.cc
- nodes/legacy/node_geo_attribute_color_ramp.cc
- nodes/legacy/node_geo_attribute_combine_xyz.cc
- nodes/legacy/node_geo_attribute_compare.cc
- nodes/legacy/node_geo_attribute_convert.cc
- nodes/legacy/node_geo_attribute_curve_map.cc
- nodes/legacy/node_geo_attribute_fill.cc
- nodes/legacy/node_geo_attribute_map_range.cc
- nodes/legacy/node_geo_attribute_math.cc
- nodes/legacy/node_geo_attribute_mix.cc
- nodes/legacy/node_geo_attribute_proximity.cc
- nodes/legacy/node_geo_attribute_randomize.cc
- nodes/legacy/node_geo_attribute_sample_texture.cc
- nodes/legacy/node_geo_attribute_separate_xyz.cc
- nodes/legacy/node_geo_attribute_transfer.cc
- nodes/legacy/node_geo_attribute_vector_math.cc
- nodes/legacy/node_geo_attribute_vector_rotate.cc
- nodes/legacy/node_geo_curve_endpoints.cc
- nodes/legacy/node_geo_curve_reverse.cc
- nodes/legacy/node_geo_curve_select_by_handle_type.cc
- nodes/legacy/node_geo_curve_set_handles.cc
- nodes/legacy/node_geo_curve_spline_type.cc
- nodes/legacy/node_geo_curve_subdivide.cc
- nodes/legacy/node_geo_curve_to_points.cc
- nodes/legacy/node_geo_delete_geometry.cc
- nodes/legacy/node_geo_edge_split.cc
- nodes/legacy/node_geo_material_assign.cc
- nodes/legacy/node_geo_mesh_to_curve.cc
- nodes/legacy/node_geo_point_distribute.cc
- nodes/legacy/node_geo_point_instance.cc
- nodes/legacy/node_geo_point_rotate.cc
- nodes/legacy/node_geo_point_scale.cc
- nodes/legacy/node_geo_point_separate.cc
- nodes/legacy/node_geo_point_translate.cc
- nodes/legacy/node_geo_points_to_volume.cc
- nodes/legacy/node_geo_raycast.cc
- nodes/legacy/node_geo_select_by_material.cc
- nodes/legacy/node_geo_subdivision_surface.cc
- nodes/legacy/node_geo_volume_to_mesh.cc
+ nodes/legacy/node_geo_legacy_align_rotation_to_vector.cc
+ nodes/legacy/node_geo_legacy_attribute_clamp.cc
+ nodes/legacy/node_geo_legacy_attribute_color_ramp.cc
+ nodes/legacy/node_geo_legacy_attribute_combine_xyz.cc
+ nodes/legacy/node_geo_legacy_attribute_compare.cc
+ nodes/legacy/node_geo_legacy_attribute_convert.cc
+ nodes/legacy/node_geo_legacy_attribute_curve_map.cc
+ nodes/legacy/node_geo_legacy_attribute_fill.cc
+ nodes/legacy/node_geo_legacy_attribute_map_range.cc
+ nodes/legacy/node_geo_legacy_attribute_math.cc
+ nodes/legacy/node_geo_legacy_attribute_mix.cc
+ nodes/legacy/node_geo_legacy_attribute_proximity.cc
+ nodes/legacy/node_geo_legacy_attribute_randomize.cc
+ nodes/legacy/node_geo_legacy_attribute_sample_texture.cc
+ nodes/legacy/node_geo_legacy_attribute_separate_xyz.cc
+ nodes/legacy/node_geo_legacy_attribute_transfer.cc
+ nodes/legacy/node_geo_legacy_attribute_vector_math.cc
+ nodes/legacy/node_geo_legacy_attribute_vector_rotate.cc
+ nodes/legacy/node_geo_legacy_curve_endpoints.cc
+ nodes/legacy/node_geo_legacy_curve_reverse.cc
+ nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc
+ nodes/legacy/node_geo_legacy_curve_set_handles.cc
+ nodes/legacy/node_geo_legacy_curve_spline_type.cc
+ nodes/legacy/node_geo_legacy_curve_subdivide.cc
+ nodes/legacy/node_geo_legacy_curve_to_points.cc
+ nodes/legacy/node_geo_legacy_delete_geometry.cc
+ nodes/legacy/node_geo_legacy_edge_split.cc
+ nodes/legacy/node_geo_legacy_material_assign.cc
+ nodes/legacy/node_geo_legacy_mesh_to_curve.cc
+ nodes/legacy/node_geo_legacy_point_distribute.cc
+ nodes/legacy/node_geo_legacy_point_instance.cc
+ nodes/legacy/node_geo_legacy_point_rotate.cc
+ nodes/legacy/node_geo_legacy_point_scale.cc
+ nodes/legacy/node_geo_legacy_point_separate.cc
+ nodes/legacy/node_geo_legacy_point_translate.cc
+ nodes/legacy/node_geo_legacy_points_to_volume.cc
+ nodes/legacy/node_geo_legacy_raycast.cc
+ nodes/legacy/node_geo_legacy_select_by_material.cc
+ nodes/legacy/node_geo_legacy_subdivision_surface.cc
+ nodes/legacy/node_geo_legacy_volume_to_mesh.cc
nodes/node_geo_attribute_capture.cc
+ nodes/node_geo_attribute_domain_size.cc
nodes/node_geo_attribute_remove.cc
nodes/node_geo_attribute_statistic.cc
nodes/node_geo_boolean.cc
@@ -93,7 +94,6 @@ set(SRC
nodes/node_geo_curve_fillet.cc
nodes/node_geo_curve_handle_type_selection.cc
nodes/node_geo_curve_length.cc
- nodes/node_geo_curve_parameter.cc
nodes/node_geo_curve_primitive_bezier_segment.cc
nodes/node_geo_curve_primitive_circle.cc
nodes/node_geo_curve_primitive_line.cc
@@ -106,13 +106,16 @@ set(SRC
nodes/node_geo_curve_sample.cc
nodes/node_geo_curve_set_handles.cc
nodes/node_geo_curve_spline_type.cc
+ nodes/node_geo_curve_spline_parameter.cc
nodes/node_geo_curve_subdivide.cc
nodes/node_geo_curve_to_mesh.cc
nodes/node_geo_curve_to_points.cc
nodes/node_geo_curve_trim.cc
nodes/node_geo_delete_geometry.cc
nodes/node_geo_distribute_points_on_faces.cc
+ nodes/node_geo_dual_mesh.cc
nodes/node_geo_edge_split.cc
+ nodes/node_geo_geometry_to_instance.cc
nodes/node_geo_image_texture.cc
nodes/node_geo_input_curve_handles.cc
nodes/node_geo_input_curve_tilt.cc
@@ -120,9 +123,16 @@ set(SRC
nodes/node_geo_input_index.cc
nodes/node_geo_input_material_index.cc
nodes/node_geo_input_material.cc
+ nodes/node_geo_input_mesh_edge_neighbors.cc
+ nodes/node_geo_input_mesh_edge_vertices.cc
+ nodes/node_geo_input_mesh_face_area.cc
+ nodes/node_geo_input_mesh_face_neighbors.cc
+ nodes/node_geo_input_mesh_island.cc
+ nodes/node_geo_input_mesh_vertex_neighbors.cc
nodes/node_geo_input_normal.cc
nodes/node_geo_input_position.cc
nodes/node_geo_input_radius.cc
+ nodes/node_geo_input_scene_time.cc
nodes/node_geo_input_shade_smooth.cc
nodes/node_geo_input_spline_cyclic.cc
nodes/node_geo_input_spline_length.cc
@@ -265,3 +275,8 @@ if(WITH_OPENVDB)
endif()
blender_add_lib(bf_nodes_geometry "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
+
+if(WITH_UNITY_BUILD)
+ set_target_properties(bf_nodes_geometry PROPERTIES UNITY_BUILD ON)
+ set_target_properties(bf_nodes_geometry PROPERTIES UNITY_BUILD_BATCH_SIZE 10)
+endif()
diff --git a/source/blender/nodes/geometry/node_geometry_tree.cc b/source/blender/nodes/geometry/node_geometry_tree.cc
index 9747bb63773..89ab4d9961e 100644
--- a/source/blender/nodes/geometry/node_geometry_tree.cc
+++ b/source/blender/nodes/geometry/node_geometry_tree.cc
@@ -84,15 +84,16 @@ static void foreach_nodeclass(Scene *UNUSED(scene), void *calldata, bNodeClassCa
func(calldata, NODE_CLASS_LAYOUT, N_("Layout"));
}
-static bool geometry_node_tree_validate_link(bNodeTree *UNUSED(ntree), bNodeLink *link)
+static bool geometry_node_tree_validate_link(eNodeSocketDatatype type_a,
+ eNodeSocketDatatype type_b)
{
/* Geometry, string, object, material, texture and collection sockets can only be connected to
* themselves. The other types can be converted between each other. */
- if (ELEM(link->fromsock->type, SOCK_FLOAT, SOCK_VECTOR, SOCK_RGBA, SOCK_BOOLEAN, SOCK_INT) &&
- ELEM(link->tosock->type, SOCK_FLOAT, SOCK_VECTOR, SOCK_RGBA, SOCK_BOOLEAN, SOCK_INT)) {
+ if (ELEM(type_a, SOCK_FLOAT, SOCK_VECTOR, SOCK_RGBA, SOCK_BOOLEAN, SOCK_INT) &&
+ ELEM(type_b, SOCK_FLOAT, SOCK_VECTOR, SOCK_RGBA, SOCK_BOOLEAN, SOCK_INT)) {
return true;
}
- return (link->tosock->type == link->fromsock->type);
+ return type_a == type_b;
}
static bool geometry_node_tree_socket_type_valid(bNodeTreeType *UNUSED(ntreetype),
@@ -113,7 +114,7 @@ static bool geometry_node_tree_socket_type_valid(bNodeTreeType *UNUSED(ntreetype
SOCK_MATERIAL);
}
-void register_node_tree_type_geo(void)
+void register_node_tree_type_geo()
{
bNodeTreeType *tt = ntreeType_Geometry = static_cast<bNodeTreeType *>(
MEM_callocN(sizeof(bNodeTreeType), "geometry node tree type"));
diff --git a/source/blender/nodes/geometry/node_geometry_util.cc b/source/blender/nodes/geometry/node_geometry_util.cc
index 5c1d507041c..49991a40c1b 100644
--- a/source/blender/nodes/geometry/node_geometry_util.cc
+++ b/source/blender/nodes/geometry/node_geometry_util.cc
@@ -24,17 +24,12 @@
#include "BKE_mesh_runtime.h"
#include "BKE_pointcloud.h"
+#include "NOD_socket_search_link.hh"
+
namespace blender::nodes {
using bke::GeometryInstanceGroup;
-/**
- * Update the availability of a group of input sockets with the same name,
- * used for switching between attribute inputs or single values.
- *
- * \param mode: Controls which socket of the group to make available.
- * \param name_is_available: If false, make all sockets with this name unavailable.
- */
void update_attribute_input_socket_availabilities(bNodeTree &ntree,
bNode &node,
const StringRef name,
@@ -56,6 +51,31 @@ void update_attribute_input_socket_availabilities(bNodeTree &ntree,
}
}
+std::optional<CustomDataType> node_data_type_to_custom_data_type(const eNodeSocketDatatype type)
+{
+ switch (type) {
+ case SOCK_FLOAT:
+ return CD_PROP_FLOAT;
+ case SOCK_VECTOR:
+ return CD_PROP_FLOAT3;
+ case SOCK_RGBA:
+ return CD_PROP_COLOR;
+ case SOCK_BOOLEAN:
+ return CD_PROP_BOOL;
+ case SOCK_INT:
+ return CD_PROP_INT32;
+ case SOCK_STRING:
+ return CD_PROP_STRING;
+ default:
+ return {};
+ }
+}
+
+std::optional<CustomDataType> node_socket_to_custom_data_type(const bNodeSocket &socket)
+{
+ return node_data_type_to_custom_data_type(static_cast<eNodeSocketDatatype>(socket.type));
+}
+
} // namespace blender::nodes
bool geo_node_poll_default(bNodeType *UNUSED(ntype),
@@ -63,7 +83,7 @@ bool geo_node_poll_default(bNodeType *UNUSED(ntype),
const char **r_disabled_hint)
{
if (!STREQ(ntree->idname, "GeometryNodeTree")) {
- *r_disabled_hint = "Not a geometry node tree";
+ *r_disabled_hint = TIP_("Not a geometry node tree");
return false;
}
return true;
@@ -74,4 +94,5 @@ void geo_node_type_base(bNodeType *ntype, int type, const char *name, short ncla
node_type_base(ntype, type, name, nclass, flag);
ntype->poll = geo_node_poll_default;
ntype->insert_link = node_insert_link_default;
+ ntype->gather_link_search_ops = blender::nodes::search_link_ops_for_basic_node;
}
diff --git a/source/blender/nodes/geometry/node_geometry_util.hh b/source/blender/nodes/geometry/node_geometry_util.hh
index 79fe2ffc42b..3376b75d05b 100644
--- a/source/blender/nodes/geometry/node_geometry_util.hh
+++ b/source/blender/nodes/geometry/node_geometry_util.hh
@@ -43,6 +43,13 @@ bool geo_node_poll_default(struct bNodeType *ntype,
const char **r_disabled_hint);
namespace blender::nodes {
+/**
+ * Update the availability of a group of input sockets with the same name,
+ * used for switching between attribute inputs or single values.
+ *
+ * \param mode: Controls which socket of the group to make available.
+ * \param name_is_available: If false, make all sockets with this name unavailable.
+ */
void update_attribute_input_socket_availabilities(bNodeTree &ntree,
bNode &node,
const StringRef name,
@@ -126,4 +133,7 @@ void curve_create_default_rotation_attribute(Span<float3> tangents,
Span<float3> normals,
MutableSpan<float3> rotations);
+std::optional<CustomDataType> node_data_type_to_custom_data_type(eNodeSocketDatatype type);
+std::optional<CustomDataType> node_socket_to_custom_data_type(const bNodeSocket &socket);
+
} // namespace blender::nodes
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_align_rotation_to_vector.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_align_rotation_to_vector.cc
index dc7c251d034..4366c6f9234 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_align_rotation_to_vector.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_align_rotation_to_vector.cc
@@ -22,9 +22,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_align_rotation_to_vector_cc {
-static void geo_node_align_rotation_to_vector_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::String>(N_("Factor"));
@@ -40,9 +40,7 @@ static void geo_node_align_rotation_to_vector_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_align_rotation_to_vector_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "axis", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
uiLayoutSetPropSep(layout, true);
@@ -53,7 +51,7 @@ static void geo_node_align_rotation_to_vector_layout(uiLayout *layout,
uiItemR(col, ptr, "input_type_vector", 0, IFACE_("Vector"), ICON_NONE);
}
-static void geo_node_align_rotation_to_vector_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeGeometryAlignRotationToVector *node_storage = (NodeGeometryAlignRotationToVector *)
MEM_callocN(sizeof(NodeGeometryAlignRotationToVector), __func__);
@@ -65,7 +63,7 @@ static void geo_node_align_rotation_to_vector_init(bNodeTree *UNUSED(ntree), bNo
node->storage = node_storage;
}
-static void geo_node_align_rotation_to_vector_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
NodeGeometryAlignRotationToVector *node_storage = (NodeGeometryAlignRotationToVector *)
node->storage;
@@ -199,11 +197,11 @@ static void align_rotations_on_component(GeometryComponent &component,
rotations.save();
}
-static void geo_node_align_rotation_to_vector_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
align_rotations_on_component(geometry_set.get_component_for_write<MeshComponent>(), params);
@@ -219,10 +217,12 @@ static void geo_node_align_rotation_to_vector_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_align_rotation_to_vector_cc
void register_node_type_geo_align_rotation_to_vector()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_align_rotation_to_vector_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype,
@@ -230,14 +230,14 @@ void register_node_type_geo_align_rotation_to_vector()
"Align Rotation to Vector",
NODE_CLASS_GEOMETRY,
0);
- node_type_init(&ntype, blender::nodes::geo_node_align_rotation_to_vector_init);
- node_type_update(&ntype, blender::nodes::geo_node_align_rotation_to_vector_update);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(&ntype,
"NodeGeometryAlignRotationToVector",
node_free_standard_storage,
node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_align_rotation_to_vector_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_align_rotation_to_vector_exec;
- ntype.draw_buttons = blender::nodes::geo_node_align_rotation_to_vector_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_clamp.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_clamp.cc
index a11a1bd3825..7435152a966 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_clamp.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_clamp.cc
@@ -20,9 +20,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_attribute_clamp_cc {
-static void geo_node_attribute_clamp_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::String>(N_("Attribute"));
@@ -38,13 +38,13 @@ static void geo_node_attribute_clamp_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_attribute_clamp_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
uiItemR(layout, ptr, "operation", 0, "", ICON_NONE);
}
-static void geo_node_attribute_clamp_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeAttributeClamp *data = (NodeAttributeClamp *)MEM_callocN(sizeof(NodeAttributeClamp),
__func__);
@@ -53,7 +53,7 @@ static void geo_node_attribute_clamp_init(bNodeTree *UNUSED(tree), bNode *node)
node->storage = data;
}
-static void geo_node_attribute_clamp_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
bNodeSocket *sock_min_vector = (bNodeSocket *)BLI_findlink(&node->inputs, 3);
bNodeSocket *sock_max_vector = sock_min_vector->next;
@@ -243,11 +243,11 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam
attribute_result.save();
}
-static void geo_node_attribute_clamp_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
clamp_attribute(geometry_set.get_component_for_write<MeshComponent>(), params);
@@ -262,19 +262,21 @@ static void geo_node_attribute_clamp_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_clamp_cc
void register_node_type_geo_attribute_clamp()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_clamp_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_ATTRIBUTE_CLAMP, "Attribute Clamp", NODE_CLASS_ATTRIBUTE, 0);
- node_type_init(&ntype, blender::nodes::geo_node_attribute_clamp_init);
- node_type_update(&ntype, blender::nodes::geo_node_attribute_clamp_update);
- ntype.declare = blender::nodes::geo_node_attribute_clamp_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_clamp_exec;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_clamp_layout;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
node_type_storage(
&ntype, "NodeAttributeClamp", node_free_standard_storage, node_copy_standard_storage);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_color_ramp.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_color_ramp.cc
index 061f5f3d7ee..4efdf786e4e 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_color_ramp.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_color_ramp.cc
@@ -23,9 +23,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_attributes_color_ramp_cc {
-static void geo_node_attribute_color_ramp_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::String>(N_("Attribute"));
@@ -33,14 +33,12 @@ static void geo_node_attribute_color_ramp_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_attribute_color_ramp_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiTemplateColorRamp(layout, ptr, "color_ramp", false);
}
-static void geo_node_attribute_color_ramp_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeAttributeColorRamp *node_storage = (NodeAttributeColorRamp *)MEM_callocN(
sizeof(NodeAttributeColorRamp), __func__);
@@ -100,11 +98,11 @@ static void execute_on_component(const GeoNodeExecParams &params, GeometryCompon
attribute_result.save();
}
-static void geo_node_attribute_color_ramp_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
execute_on_component(params, geometry_set.get_component_for_write<MeshComponent>());
@@ -119,10 +117,12 @@ static void geo_node_attribute_color_ramp_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attributes_color_ramp_cc
void register_node_type_geo_attribute_color_ramp()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attributes_color_ramp_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype,
@@ -132,10 +132,10 @@ void register_node_type_geo_attribute_color_ramp()
0);
node_type_storage(
&ntype, "NodeAttributeColorRamp", node_free_standard_storage, node_copy_standard_storage);
- node_type_init(&ntype, blender::nodes::geo_node_attribute_color_ramp_init);
+ node_type_init(&ntype, file_ns::node_init);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
- ntype.declare = blender::nodes::geo_node_attribute_color_ramp_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_color_ramp_exec;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_color_ramp_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_combine_xyz.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_combine_xyz.cc
index a610356955b..7ba64c8db2b 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_combine_xyz.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_combine_xyz.cc
@@ -19,9 +19,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_attribute_combine_xyz_cc {
-static void geo_node_attribute_combine_xyz_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::String>(N_("X"));
@@ -34,9 +34,7 @@ static void geo_node_attribute_combine_xyz_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_attribute_combine_xyz_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
@@ -46,7 +44,7 @@ static void geo_node_attribute_combine_xyz_layout(uiLayout *layout,
uiItemR(col, ptr, "input_type_z", 0, IFACE_("Z"), ICON_NONE);
}
-static void geo_node_attribute_combine_xyz_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeAttributeCombineXYZ *data = (NodeAttributeCombineXYZ *)MEM_callocN(
sizeof(NodeAttributeCombineXYZ), __func__);
@@ -57,7 +55,7 @@ static void geo_node_attribute_combine_xyz_init(bNodeTree *UNUSED(tree), bNode *
node->storage = data;
}
-static void geo_node_attribute_combine_xyz_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
NodeAttributeCombineXYZ *node_storage = (NodeAttributeCombineXYZ *)node->storage;
update_attribute_input_socket_availabilities(
@@ -111,11 +109,11 @@ static void combine_attributes(GeometryComponent &component, const GeoNodeExecPa
attribute_result.save();
}
-static void geo_node_attribute_combine_xyz_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
combine_attributes(geometry_set.get_component_for_write<MeshComponent>(), params);
@@ -130,10 +128,12 @@ static void geo_node_attribute_combine_xyz_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_combine_xyz_cc
void register_node_type_geo_attribute_combine_xyz()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_combine_xyz_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype,
@@ -141,13 +141,13 @@ void register_node_type_geo_attribute_combine_xyz()
"Attribute Combine XYZ",
NODE_CLASS_ATTRIBUTE,
0);
- node_type_init(&ntype, blender::nodes::geo_node_attribute_combine_xyz_init);
- node_type_update(&ntype, blender::nodes::geo_node_attribute_combine_xyz_update);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(
&ntype, "NodeAttributeCombineXYZ", node_free_standard_storage, node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_attribute_combine_xyz_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_combine_xyz_exec;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_combine_xyz_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_compare.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_compare.cc
index a4ffe884999..8aa1adb0cf3 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_compare.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_compare.cc
@@ -21,9 +21,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_attribute_compare_cc {
-static void geo_node_attribute_compare_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::String>(N_("A"));
@@ -39,9 +39,7 @@ static void geo_node_attribute_compare_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_attribute_compare_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "operation", 0, "", ICON_NONE);
uiLayoutSetPropSep(layout, true);
@@ -50,11 +48,11 @@ static void geo_node_attribute_compare_layout(uiLayout *layout,
uiItemR(layout, ptr, "input_type_b", 0, IFACE_("B"), ICON_NONE);
}
-static void geo_node_attribute_compare_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeAttributeCompare *data = (NodeAttributeCompare *)MEM_callocN(sizeof(NodeAttributeCompare),
__func__);
- data->operation = NODE_FLOAT_COMPARE_GREATER_THAN;
+ data->operation = NODE_COMPARE_GREATER_THAN;
data->input_type_a = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
data->input_type_b = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
node->storage = data;
@@ -62,10 +60,10 @@ static void geo_node_attribute_compare_init(bNodeTree *UNUSED(tree), bNode *node
static bool operation_tests_equality(const NodeAttributeCompare &node_storage)
{
- return ELEM(node_storage.operation, NODE_FLOAT_COMPARE_EQUAL, NODE_FLOAT_COMPARE_NOT_EQUAL);
+ return ELEM(node_storage.operation, NODE_COMPARE_EQUAL, NODE_COMPARE_NOT_EQUAL);
}
-static void geo_node_attribute_compare_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
NodeAttributeCompare *node_storage = (NodeAttributeCompare *)node->storage;
update_attribute_input_socket_availabilities(
@@ -79,7 +77,7 @@ static void geo_node_attribute_compare_update(bNodeTree *ntree, bNode *node)
static void do_math_operation(const VArray<float> &input_a,
const VArray<float> &input_b,
- const FloatCompareOperation operation,
+ const NodeCompareOperation operation,
MutableSpan<bool> span_result)
{
const int size = input_a.size();
@@ -243,7 +241,7 @@ static void attribute_compare_calc(GeometryComponent &component, const GeoNodeEx
{
const bNode &node = params.node();
NodeAttributeCompare *node_storage = (NodeAttributeCompare *)node.storage;
- const FloatCompareOperation operation = static_cast<FloatCompareOperation>(
+ const NodeCompareOperation operation = static_cast<NodeCompareOperation>(
node_storage->operation);
const std::string result_name = params.get_input<std::string>("Result");
@@ -273,7 +271,7 @@ static void attribute_compare_calc(GeometryComponent &component, const GeoNodeEx
* conversions and float comparison. In other words, the comparison is not element-wise. */
if (operation_tests_equality(*node_storage)) {
const float threshold = params.get_input<float>("Threshold");
- if (operation == NODE_FLOAT_COMPARE_EQUAL) {
+ if (operation == NODE_COMPARE_EQUAL) {
if (input_data_type == CD_PROP_FLOAT) {
do_equal_operation_float(
attribute_a.typed<float>(), attribute_b.typed<float>(), threshold, result_span);
@@ -293,7 +291,7 @@ static void attribute_compare_calc(GeometryComponent &component, const GeoNodeEx
attribute_a.typed<bool>(), attribute_b.typed<bool>(), threshold, result_span);
}
}
- else if (operation == NODE_FLOAT_COMPARE_NOT_EQUAL) {
+ else if (operation == NODE_COMPARE_NOT_EQUAL) {
if (input_data_type == CD_PROP_FLOAT) {
do_not_equal_operation_float(
attribute_a.typed<float>(), attribute_b.typed<float>(), threshold, result_span);
@@ -322,11 +320,11 @@ static void attribute_compare_calc(GeometryComponent &component, const GeoNodeEx
attribute_result.save();
}
-static void geo_node_attribute_compare_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
attribute_compare_calc(geometry_set.get_component_for_write<MeshComponent>(), params);
@@ -341,20 +339,22 @@ static void geo_node_attribute_compare_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_compare_cc
void register_node_type_geo_attribute_compare()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_compare_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_ATTRIBUTE_COMPARE, "Attribute Compare", NODE_CLASS_ATTRIBUTE, 0);
- ntype.declare = blender::nodes::geo_node_attribute_compare_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_compare_exec;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_compare_layout;
- node_type_update(&ntype, blender::nodes::geo_node_attribute_compare_update);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(
&ntype, "NodeAttributeCompare", node_free_standard_storage, node_copy_standard_storage);
- node_type_init(&ntype, blender::nodes::geo_node_attribute_compare_init);
+ node_type_init(&ntype, file_ns::node_init);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_convert.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_convert.cc
index 13ba8d13618..28c133871f7 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_convert.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_convert.cc
@@ -19,9 +19,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_attribute_convert_cc {
-static void geo_node_attribute_convert_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::String>(N_("Attribute"));
@@ -29,9 +29,7 @@ static void geo_node_attribute_convert_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_attribute_convert_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
@@ -39,7 +37,7 @@ static void geo_node_attribute_convert_layout(uiLayout *layout,
uiItemR(layout, ptr, "data_type", 0, IFACE_("Type"), ICON_NONE);
}
-static void geo_node_attribute_convert_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeAttributeConvert *data = (NodeAttributeConvert *)MEM_callocN(sizeof(NodeAttributeConvert),
__func__);
@@ -130,11 +128,11 @@ static void attribute_convert_calc(GeometryComponent &component,
result_attribute.save();
}
-static void geo_node_attribute_convert_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
const std::string result_name = params.extract_input<std::string>("Result");
const std::string source_name = params.extract_input<std::string>("Attribute");
@@ -143,7 +141,7 @@ static void geo_node_attribute_convert_exec(GeoNodeExecParams params)
const AttributeDomain domain = static_cast<AttributeDomain>(node_storage.domain);
if (result_name.empty()) {
- params.set_output("Geometry", geometry_set);
+ params.set_default_remaining_outputs();
return;
}
@@ -175,18 +173,20 @@ static void geo_node_attribute_convert_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_convert_cc
void register_node_type_geo_attribute_convert()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_convert_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_ATTRIBUTE_CONVERT, "Attribute Convert", NODE_CLASS_ATTRIBUTE, 0);
- ntype.declare = blender::nodes::geo_node_attribute_convert_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_convert_exec;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_convert_layout;
- node_type_init(&ntype, blender::nodes::geo_node_attribute_convert_init);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(
&ntype, "NodeAttributeConvert", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_curve_map.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_curve_map.cc
index af56df0dc3f..0a7b5dd8463 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_curve_map.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_curve_map.cc
@@ -24,9 +24,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_attribute_curve_map_cc {
-static void geo_node_attribute_curve_map_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::String>(N_("Attribute"));
@@ -34,9 +34,7 @@ static void geo_node_attribute_curve_map_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_attribute_curve_map_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
bNode *node = (bNode *)ptr->data;
@@ -54,7 +52,7 @@ static void geo_node_attribute_curve_map_layout(uiLayout *layout,
}
}
-static void geo_node_attribute_curve_map_free_storage(bNode *node)
+static void node_free_storage(bNode *node)
{
if (node->storage) {
NodeAttributeCurveMap *data = (NodeAttributeCurveMap *)node->storage;
@@ -64,9 +62,9 @@ static void geo_node_attribute_curve_map_free_storage(bNode *node)
}
}
-static void geo_node_attribute_curve_map_copy_storage(bNodeTree *UNUSED(dest_ntree),
- bNode *dest_node,
- const bNode *src_node)
+static void node_copy_storage(bNodeTree *UNUSED(dest_ntree),
+ bNode *dest_node,
+ const bNode *src_node)
{
dest_node->storage = MEM_dupallocN(src_node->storage);
NodeAttributeCurveMap *src_data = (NodeAttributeCurveMap *)src_node->storage;
@@ -75,7 +73,7 @@ static void geo_node_attribute_curve_map_copy_storage(bNodeTree *UNUSED(dest_ntr
dest_data->curve_rgb = BKE_curvemapping_copy(src_data->curve_rgb);
}
-static void geo_node_attribute_curve_map_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeAttributeCurveMap *data = (NodeAttributeCurveMap *)MEM_callocN(sizeof(NodeAttributeCurveMap),
__func__);
@@ -87,7 +85,7 @@ static void geo_node_attribute_curve_map_init(bNodeTree *UNUSED(ntree), bNode *n
node->storage = data;
}
-static void geo_node_attribute_curve_map_update(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_update(bNodeTree *UNUSED(ntree), bNode *node)
{
/* Set the active curve when data type is changed. */
NodeAttributeCurveMap *data = (NodeAttributeCurveMap *)node->storage;
@@ -179,7 +177,7 @@ static void execute_on_component(const GeoNodeExecParams &params, GeometryCompon
attribute_result.save();
}
-static void geo_node_attribute_curve_map_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
const bNode &bnode = params.node();
NodeAttributeCurveMap *data = (NodeAttributeCurveMap *)bnode.storage;
@@ -188,7 +186,7 @@ static void geo_node_attribute_curve_map_exec(GeoNodeExecParams params)
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
execute_on_component(params, geometry_set.get_component_for_write<MeshComponent>());
@@ -203,23 +201,23 @@ static void geo_node_attribute_curve_map_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_curve_map_cc
void register_node_type_geo_attribute_curve_map()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_curve_map_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_ATTRIBUTE_CURVE_MAP, "Attribute Curve Map", NODE_CLASS_ATTRIBUTE, 0);
- node_type_update(&ntype, blender::nodes::geo_node_attribute_curve_map_update);
- node_type_init(&ntype, blender::nodes::geo_node_attribute_curve_map_init);
+ node_type_update(&ntype, file_ns::node_update);
+ node_type_init(&ntype, file_ns::node_init);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
- node_type_storage(&ntype,
- "NodeAttributeCurveMap",
- blender::nodes::geo_node_attribute_curve_map_free_storage,
- blender::nodes::geo_node_attribute_curve_map_copy_storage);
- ntype.declare = blender::nodes::geo_node_attribute_curve_map_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_curve_map_exec;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_curve_map_layout;
+ node_type_storage(
+ &ntype, "NodeAttributeCurveMap", file_ns::node_free_storage, file_ns::node_copy_storage);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_fill.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_fill.cc
index a1b537e9657..a05bcf1bed8 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_fill.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_fill.cc
@@ -19,9 +19,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_attribute_fill_cc {
-static void geo_node_attribute_fill_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::String>(N_("Attribute")).is_attribute_name();
@@ -33,7 +33,7 @@ static void geo_node_attribute_fill_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_attribute_fill_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
@@ -41,13 +41,13 @@ static void geo_node_attribute_fill_layout(uiLayout *layout, bContext *UNUSED(C)
uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
}
-static void geo_node_attribute_fill_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
node->custom1 = CD_PROP_FLOAT;
node->custom2 = ATTR_DOMAIN_AUTO;
}
-static void geo_node_attribute_fill_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
bNodeSocket *socket_value_vector = (bNodeSocket *)BLI_findlink(&node->inputs, 2);
bNodeSocket *socket_value_float = socket_value_vector->next;
@@ -127,11 +127,11 @@ static void fill_attribute(GeometryComponent &component, const GeoNodeExecParams
attribute.save();
}
-static void geo_node_attribute_fill_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
fill_attribute(geometry_set.get_component_for_write<MeshComponent>(), params);
@@ -146,18 +146,20 @@ static void geo_node_attribute_fill_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_fill_cc
void register_node_type_geo_attribute_fill()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_fill_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_ATTRIBUTE_FILL, "Attribute Fill", NODE_CLASS_ATTRIBUTE, 0);
- node_type_init(&ntype, blender::nodes::geo_node_attribute_fill_init);
- node_type_update(&ntype, blender::nodes::geo_node_attribute_fill_update);
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_fill_exec;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_fill_layout;
- ntype.declare = blender::nodes::geo_node_attribute_fill_declare;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_map_range.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_map_range.cc
index 2c70157d586..8ebcf34ad0b 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_map_range.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_map_range.cc
@@ -22,9 +22,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_attribute_map_range_cc {
-static void geo_node_attribute_map_range_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::String>(N_("Attribute"));
@@ -49,7 +49,7 @@ static void fn_attribute_map_range_layout(uiLayout *layout, bContext *UNUSED(C),
uiItemR(layout, ptr, "interpolation_type", 0, "", ICON_NONE);
}
-static void geo_node_attribute_map_range_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeAttributeMapRange *data = (NodeAttributeMapRange *)MEM_callocN(sizeof(NodeAttributeMapRange),
__func__);
@@ -58,7 +58,7 @@ static void geo_node_attribute_map_range_init(bNodeTree *UNUSED(ntree), bNode *n
node->storage = data;
}
-static void geo_node_attribute_map_range_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
NodeAttributeMapRange &node_storage = *(NodeAttributeMapRange *)node->storage;
@@ -399,7 +399,7 @@ static void map_range_attribute(GeometryComponent &component, const GeoNodeExecP
attribute_result.save();
}
-static void geo_node_attribute_map_range_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
@@ -416,20 +416,22 @@ static void geo_node_attribute_map_range_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_map_range_cc
void register_node_type_geo_attribute_map_range()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_map_range_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_ATTRIBUTE_MAP_RANGE, "Attribute Map Range", NODE_CLASS_ATTRIBUTE, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_map_range_exec;
- node_type_init(&ntype, blender::nodes::geo_node_attribute_map_range_init);
- node_type_update(&ntype, blender::nodes::geo_node_attribute_map_range_update);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(
&ntype, "NodeAttributeMapRange", node_free_standard_storage, node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_attribute_map_range_declare;
- ntype.draw_buttons = blender::nodes::fn_attribute_map_range_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::fn_attribute_map_range_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_math.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_math.cc
index 193db7355f9..e0a829b4100 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_math.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_math.cc
@@ -25,9 +25,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_attribute_math_cc {
-static void geo_node_attribute_math_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::String>(N_("A"));
@@ -100,7 +100,7 @@ static bool operation_use_input_b(const NodeMathOperation operation)
return false;
}
-static void geo_node_attribute_math_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
bNode *node = (bNode *)ptr->data;
NodeAttributeMath *node_storage = (NodeAttributeMath *)node->storage;
@@ -119,7 +119,7 @@ static void geo_node_attribute_math_layout(uiLayout *layout, bContext *UNUSED(C)
}
}
-static void geo_node_attribute_math_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeAttributeMath *data = (NodeAttributeMath *)MEM_callocN(sizeof(NodeAttributeMath), __func__);
@@ -130,7 +130,10 @@ static void geo_node_attribute_math_init(bNodeTree *UNUSED(tree), bNode *node)
node->storage = data;
}
-static void geo_node_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
+static void geo_node_math_label(const bNodeTree *UNUSED(ntree),
+ const bNode *node,
+ char *label,
+ int maxlen)
{
NodeAttributeMath &node_storage = *(NodeAttributeMath *)node->storage;
const char *name;
@@ -141,7 +144,7 @@ static void geo_node_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *lab
BLI_strncpy(label, IFACE_(name), maxlen);
}
-static void geo_node_attribute_math_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
NodeAttributeMath &node_storage = *(NodeAttributeMath *)node->storage;
NodeMathOperation operation = static_cast<NodeMathOperation>(node_storage.operation);
@@ -278,11 +281,11 @@ static void attribute_math_calc(GeometryComponent &component, const GeoNodeExecP
attribute_result.save();
}
-static void geo_node_attribute_math_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
attribute_math_calc(geometry_set.get_component_for_write<MeshComponent>(), params);
@@ -297,20 +300,22 @@ static void geo_node_attribute_math_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_math_cc
void register_node_type_geo_attribute_math()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_math_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_ATTRIBUTE_MATH, "Attribute Math", NODE_CLASS_ATTRIBUTE, 0);
- ntype.declare = blender::nodes::geo_node_attribute_math_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_math_exec;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_math_layout;
- node_type_label(&ntype, blender::nodes::geo_node_math_label);
- node_type_update(&ntype, blender::nodes::geo_node_attribute_math_update);
- node_type_init(&ntype, blender::nodes::geo_node_attribute_math_init);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.labelfunc = file_ns::geo_node_math_label;
+ node_type_update(&ntype, file_ns::node_update);
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(
&ntype, "NodeAttributeMath", node_free_standard_storage, node_copy_standard_storage);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_mix.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_mix.cc
index 6c7f2313633..4a110e9690a 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_mix.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_mix.cc
@@ -25,9 +25,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_attribute_mix_cc {
-static void geo_node_mix_attribute_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::String>(N_("Factor"));
@@ -48,7 +48,7 @@ static void geo_node_mix_attribute_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_attribute_mix_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
@@ -59,7 +59,7 @@ static void geo_node_attribute_mix_layout(uiLayout *layout, bContext *UNUSED(C),
uiItemR(col, ptr, "input_type_b", 0, IFACE_("B"), ICON_NONE);
}
-static void geo_node_attribute_mix_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeAttributeMix *data = (NodeAttributeMix *)MEM_callocN(sizeof(NodeAttributeMix),
"attribute mix node");
@@ -70,7 +70,7 @@ static void geo_node_attribute_mix_init(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = data;
}
-static void geo_node_attribute_mix_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
NodeAttributeMix *node_storage = (NodeAttributeMix *)node->storage;
update_attribute_input_socket_availabilities(
@@ -222,11 +222,11 @@ static void attribute_mix_calc(GeometryComponent &component, const GeoNodeExecPa
attribute_result.save();
}
-static void geo_node_attribute_mix_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
attribute_mix_calc(geometry_set.get_component_for_write<MeshComponent>(), params);
@@ -241,19 +241,21 @@ static void geo_node_attribute_mix_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_mix_cc
void register_node_type_geo_attribute_mix()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_mix_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_ATTRIBUTE_MIX, "Attribute Mix", NODE_CLASS_ATTRIBUTE, 0);
- node_type_init(&ntype, blender::nodes::geo_node_attribute_mix_init);
- node_type_update(&ntype, blender::nodes::geo_node_attribute_mix_update);
- ntype.declare = blender::nodes::geo_node_mix_attribute_declare;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_mix_layout;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_layout;
node_type_storage(
&ntype, "NodeAttributeMix", node_free_standard_storage, node_copy_standard_storage);
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_mix_exec;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_proximity.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_proximity.cc
index 0122f9b7598..080bf38a740 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_proximity.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_proximity.cc
@@ -26,9 +26,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_attribute_proximity_cc {
-static void geo_node_attribute_proximity_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::Geometry>(N_("Target"));
@@ -37,14 +37,12 @@ static void geo_node_attribute_proximity_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_attribute_proximity_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "target_geometry_element", 0, "", ICON_NONE);
}
-static void geo_attribute_proximity_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeGeometryAttributeProximity *node_storage = (NodeGeometryAttributeProximity *)MEM_callocN(
sizeof(NodeGeometryAttributeProximity), __func__);
@@ -203,16 +201,16 @@ static void attribute_calc_proximity(GeometryComponent &component,
}
}
-static void geo_node_attribute_proximity_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
GeometrySet geometry_set_target = params.extract_input<GeometrySet>("Target");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
/* This isn't required. This node should be rewritten to handle instances
* for the target geometry set. However, the generic BVH API complicates this. */
- geometry_set_target = geometry_set_realize_instances(geometry_set_target);
+ geometry_set_target = geometry::realize_instances_legacy(geometry_set_target);
if (geometry_set.has<MeshComponent>()) {
attribute_calc_proximity(
@@ -230,22 +228,24 @@ static void geo_node_attribute_proximity_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_proximity_cc
void register_node_type_geo_legacy_attribute_proximity()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_proximity_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_ATTRIBUTE_PROXIMITY, "Attribute Proximity", NODE_CLASS_ATTRIBUTE, 0);
- node_type_init(&ntype, blender::nodes::geo_attribute_proximity_init);
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(&ntype,
"NodeGeometryAttributeProximity",
node_free_standard_storage,
node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_attribute_proximity_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_proximity_exec;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_proximity_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_randomize.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_randomize.cc
index f8d9dcdaf87..ab2bc7b379c 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_randomize.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_randomize.cc
@@ -25,7 +25,41 @@
namespace blender::nodes {
-static void geo_node_legacy_attribute_randomize_declare(NodeDeclarationBuilder &b)
+Array<uint32_t> get_geometry_element_ids_as_uints(const GeometryComponent &component,
+ const AttributeDomain domain)
+{
+ const int domain_size = component.attribute_domain_size(domain);
+
+ /* Hash the reserved name attribute "id" as a (hopefully) stable seed for each point. */
+ GVArray hash_attribute = component.attribute_try_get_for_read("id", domain);
+ Array<uint32_t> hashes(domain_size);
+ if (hash_attribute) {
+ BLI_assert(hashes.size() == hash_attribute.size());
+ const CPPType &cpp_type = hash_attribute.type();
+ BLI_assert(cpp_type.is_hashable());
+ GVArray_GSpan items{hash_attribute};
+ threading::parallel_for(hashes.index_range(), 512, [&](IndexRange range) {
+ for (const int i : range) {
+ hashes[i] = cpp_type.hash(items[i]);
+ }
+ });
+ }
+ else {
+ /* If there is no "id" attribute for per-point variation, just create it here. */
+ RandomNumberGenerator rng(0);
+ for (const int i : hashes.index_range()) {
+ hashes[i] = rng.get_uint32();
+ }
+ }
+
+ return hashes;
+}
+
+} // namespace blender::nodes
+
+namespace blender::nodes::node_geo_legacy_attribute_randomize_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::String>(N_("Attribute"));
@@ -39,15 +73,13 @@ static void geo_node_legacy_attribute_randomize_declare(NodeDeclarationBuilder &
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_legacy_attribute_random_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
uiItemR(layout, ptr, "operation", 0, "", ICON_NONE);
}
-static void geo_node_legacy_attribute_randomize_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeAttributeRandomize *data = (NodeAttributeRandomize *)MEM_callocN(
sizeof(NodeAttributeRandomize), __func__);
@@ -57,7 +89,7 @@ static void geo_node_legacy_attribute_randomize_init(bNodeTree *UNUSED(tree), bN
node->storage = data;
}
-static void geo_node_legacy_attribute_randomize_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
bNodeSocket *sock_min_vector = (bNodeSocket *)BLI_findlink(&node->inputs, 2);
bNodeSocket *sock_max_vector = sock_min_vector->next;
@@ -174,36 +206,6 @@ static void randomize_attribute_bool(MutableSpan<bool> span,
});
}
-Array<uint32_t> get_geometry_element_ids_as_uints(const GeometryComponent &component,
- const AttributeDomain domain)
-{
- const int domain_size = component.attribute_domain_size(domain);
-
- /* Hash the reserved name attribute "id" as a (hopefully) stable seed for each point. */
- GVArray hash_attribute = component.attribute_try_get_for_read("id", domain);
- Array<uint32_t> hashes(domain_size);
- if (hash_attribute) {
- BLI_assert(hashes.size() == hash_attribute.size());
- const CPPType &cpp_type = hash_attribute.type();
- BLI_assert(cpp_type.is_hashable());
- GVArray_GSpan items{hash_attribute};
- threading::parallel_for(hashes.index_range(), 512, [&](IndexRange range) {
- for (const int i : range) {
- hashes[i] = cpp_type.hash(items[i]);
- }
- });
- }
- else {
- /* If there is no "id" attribute for per-point variation, just create it here. */
- RandomNumberGenerator rng(0);
- for (const int i : hashes.index_range()) {
- hashes[i] = rng.get_uint32();
- }
- }
-
- return hashes;
-}
-
static AttributeDomain get_result_domain(const GeometryComponent &component,
const GeoNodeExecParams &params,
const StringRef name)
@@ -280,12 +282,12 @@ static void randomize_attribute_on_component(GeometryComponent &component,
attribute.save();
}
-static void geo_node_legacy_random_attribute_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
const std::string attribute_name = params.get_input<std::string>("Attribute");
if (attribute_name.empty()) {
- params.set_output("Geometry", geometry_set);
+ params.set_default_remaining_outputs();
return;
}
const int seed = params.get_input<int>("Seed");
@@ -294,7 +296,7 @@ static void geo_node_legacy_random_attribute_exec(GeoNodeExecParams params)
const GeometryNodeAttributeRandomizeMode operation =
static_cast<GeometryNodeAttributeRandomizeMode>(storage.operation);
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
randomize_attribute_on_component(geometry_set.get_component_for_write<MeshComponent>(),
@@ -324,20 +326,22 @@ static void geo_node_legacy_random_attribute_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_randomize_cc
void register_node_type_geo_legacy_attribute_randomize()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_randomize_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_ATTRIBUTE_RANDOMIZE, "Attribute Randomize", NODE_CLASS_ATTRIBUTE, 0);
- node_type_init(&ntype, blender::nodes::geo_node_legacy_attribute_randomize_init);
- node_type_update(&ntype, blender::nodes::geo_node_legacy_attribute_randomize_update);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
- ntype.declare = blender::nodes::geo_node_legacy_attribute_randomize_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_legacy_random_attribute_exec;
- ntype.draw_buttons = blender::nodes::geo_node_legacy_attribute_random_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
node_type_storage(
&ntype, "NodeAttributeRandomize", node_free_standard_storage, node_copy_standard_storage);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_sample_texture.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_sample_texture.cc
index 9748ca3f2ad..bc18cb32e73 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_sample_texture.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_sample_texture.cc
@@ -28,9 +28,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_attribute_sample_texture_cc {
-static void geo_node_attribute_sample_texture_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::Texture>(N_("Texture")).hide_label();
@@ -100,11 +100,11 @@ static void execute_on_component(GeometryComponent &component, const GeoNodeExec
attribute_out.save();
}
-static void geo_node_attribute_sample_texture_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
execute_on_component(geometry_set.get_component_for_write<MeshComponent>(), params);
@@ -119,10 +119,12 @@ static void geo_node_attribute_sample_texture_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_sample_texture_cc
void register_node_type_geo_sample_texture()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_sample_texture_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype,
@@ -131,7 +133,7 @@ void register_node_type_geo_sample_texture()
NODE_CLASS_ATTRIBUTE,
0);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
- ntype.declare = blender::nodes::geo_node_attribute_sample_texture_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_sample_texture_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_separate_xyz.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_separate_xyz.cc
index bfc69780bf6..c5aac118baf 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_separate_xyz.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_separate_xyz.cc
@@ -19,9 +19,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_attribute_separate_xyz_cc {
-static void geo_node_attribute_separate_xyz_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::String>(N_("Vector"));
@@ -32,16 +32,14 @@ static void geo_node_attribute_separate_xyz_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_attribute_separate_xyz_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
uiItemR(layout, ptr, "input_type", 0, IFACE_("Type"), ICON_NONE);
}
-static void geo_node_attribute_separate_xyz_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeAttributeSeparateXYZ *data = (NodeAttributeSeparateXYZ *)MEM_callocN(
sizeof(NodeAttributeSeparateXYZ), __func__);
@@ -49,7 +47,7 @@ static void geo_node_attribute_separate_xyz_init(bNodeTree *UNUSED(tree), bNode
node->storage = data;
}
-static void geo_node_attribute_separate_xyz_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
NodeAttributeSeparateXYZ *node_storage = (NodeAttributeSeparateXYZ *)node->storage;
update_attribute_input_socket_availabilities(
@@ -132,11 +130,11 @@ static void separate_attribute(GeometryComponent &component, const GeoNodeExecPa
}
}
-static void geo_node_attribute_separate_xyz_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
separate_attribute(geometry_set.get_component_for_write<MeshComponent>(), params);
@@ -151,10 +149,12 @@ static void geo_node_attribute_separate_xyz_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_separate_xyz_cc
void register_node_type_geo_attribute_separate_xyz()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_separate_xyz_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype,
@@ -162,12 +162,12 @@ void register_node_type_geo_attribute_separate_xyz()
"Attribute Separate XYZ",
NODE_CLASS_ATTRIBUTE,
0);
- ntype.declare = blender::nodes::geo_node_attribute_separate_xyz_declare;
- node_type_init(&ntype, blender::nodes::geo_node_attribute_separate_xyz_init);
- node_type_update(&ntype, blender::nodes::geo_node_attribute_separate_xyz_update);
+ ntype.declare = file_ns::node_declare;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(
&ntype, "NodeAttributeSeparateXYZ", node_free_standard_storage, node_copy_standard_storage);
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_separate_xyz_exec;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_separate_xyz_layout;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_transfer.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_transfer.cc
index b8827f82efc..686edc80f62 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_transfer.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_transfer.cc
@@ -29,9 +29,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_attribute_transfer_cc {
-static void geo_node_attribute_transfer_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::Geometry>(N_("Source Geometry"));
@@ -40,9 +40,7 @@ static void geo_node_attribute_transfer_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_attribute_transfer_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
@@ -50,7 +48,7 @@ static void geo_node_attribute_transfer_layout(uiLayout *layout,
uiItemR(layout, ptr, "mapping", 0, IFACE_("Mapping"), ICON_NONE);
}
-static void geo_node_attribute_transfer_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryAttributeTransfer *data = (NodeGeometryAttributeTransfer *)MEM_callocN(
sizeof(NodeGeometryAttributeTransfer), __func__);
@@ -405,7 +403,7 @@ static void transfer_attribute_nearest(const GeometrySet &src_geometry,
data_type);
for (const int i : IndexRange(tot_samples)) {
if (pointcloud_distances_sq[i] < mesh_distances_sq[i]) {
- /* Point-cloud point is closer. */
+ /* Point cloud point is closer. */
const int index = pointcloud_indices[i];
pointcloud_src_attribute.varray.get(index, buffer);
dst_attribute->set_by_relocate(i, buffer);
@@ -477,7 +475,7 @@ static void transfer_attribute(const GeoNodeExecParams &params,
}
}
-static void geo_node_attribute_transfer_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet dst_geometry_set = params.extract_input<GeometrySet>("Geometry");
GeometrySet src_geometry_set = params.extract_input<GeometrySet>("Source Geometry");
@@ -485,12 +483,12 @@ static void geo_node_attribute_transfer_exec(GeoNodeExecParams params)
const std::string dst_attribute_name = params.extract_input<std::string>("Destination");
if (src_attribute_name.empty() || dst_attribute_name.empty()) {
- params.set_output("Geometry", dst_geometry_set);
+ params.set_default_remaining_outputs();
return;
}
- dst_geometry_set = bke::geometry_set_realize_instances(dst_geometry_set);
- src_geometry_set = bke::geometry_set_realize_instances(src_geometry_set);
+ dst_geometry_set = geometry::realize_instances_legacy(dst_geometry_set);
+ src_geometry_set = geometry::realize_instances_legacy(src_geometry_set);
if (dst_geometry_set.has<MeshComponent>()) {
transfer_attribute(params,
@@ -510,21 +508,23 @@ static void geo_node_attribute_transfer_exec(GeoNodeExecParams params)
params.set_output("Geometry", dst_geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_transfer_cc
void register_node_type_geo_legacy_attribute_transfer()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_transfer_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_ATTRIBUTE_TRANSFER, "Attribute Transfer", NODE_CLASS_ATTRIBUTE, 0);
- node_type_init(&ntype, blender::nodes::geo_node_attribute_transfer_init);
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(&ntype,
"NodeGeometryAttributeTransfer",
node_free_standard_storage,
node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_attribute_transfer_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_transfer_exec;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_transfer_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_math.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_math.cc
index e7fdd0f2eef..68051e81f57 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_math.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_math.cc
@@ -26,9 +26,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_attribute_vector_math_cc {
-static void geo_node_attribute_vector_math_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::String>(N_("A"));
@@ -66,9 +66,7 @@ static bool operation_use_input_c(const NodeVectorMathOperation operation)
NODE_VECTOR_MATH_MULTIPLY_ADD);
}
-static void geo_node_attribute_vector_math_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
bNode *node = (bNode *)ptr->data;
const NodeAttributeVectorMath &node_storage = *(NodeAttributeVectorMath *)node->storage;
@@ -103,7 +101,7 @@ static CustomDataType operation_get_read_type_c(const NodeVectorMathOperation op
return CD_PROP_FLOAT3;
}
-static void geo_node_attribute_vector_math_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeAttributeVectorMath *data = (NodeAttributeVectorMath *)MEM_callocN(
sizeof(NodeAttributeVectorMath), __func__);
@@ -152,8 +150,8 @@ static CustomDataType operation_get_result_type(const NodeVectorMathOperation op
return CD_PROP_FLOAT3;
}
-static void geo_node_vector_math_label(bNodeTree *UNUSED(ntree),
- bNode *node,
+static void geo_node_vector_math_label(const bNodeTree *UNUSED(ntree),
+ const bNode *node,
char *label,
int maxlen)
{
@@ -166,7 +164,7 @@ static void geo_node_vector_math_label(bNodeTree *UNUSED(ntree),
BLI_snprintf(label, maxlen, IFACE_("Vector %s"), IFACE_(name));
}
-static void geo_node_attribute_vector_math_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
const NodeAttributeVectorMath *node_storage = (NodeAttributeVectorMath *)node->storage;
const NodeVectorMathOperation operation = (const NodeVectorMathOperation)node_storage->operation;
@@ -531,11 +529,11 @@ static void attribute_vector_math_calc(GeometryComponent &component,
attribute_result.save();
}
-static void geo_node_attribute_vector_math_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
attribute_vector_math_calc(geometry_set.get_component_for_write<MeshComponent>(), params);
@@ -551,10 +549,12 @@ static void geo_node_attribute_vector_math_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_vector_math_cc
void register_node_type_geo_attribute_vector_math()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_vector_math_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype,
@@ -562,12 +562,12 @@ void register_node_type_geo_attribute_vector_math()
"Attribute Vector Math",
NODE_CLASS_ATTRIBUTE,
0);
- ntype.declare = blender::nodes::geo_node_attribute_vector_math_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_vector_math_exec;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_vector_math_layout;
- node_type_label(&ntype, blender::nodes::geo_node_vector_math_label);
- node_type_update(&ntype, blender::nodes::geo_node_attribute_vector_math_update);
- node_type_init(&ntype, blender::nodes::geo_node_attribute_vector_math_init);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.labelfunc = file_ns::geo_node_vector_math_label;
+ node_type_update(&ntype, file_ns::node_update);
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(
&ntype, "NodeAttributeVectorMath", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_rotate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_rotate.cc
index a6cd24ed72d..1ef50e69775 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_rotate.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_rotate.cc
@@ -21,9 +21,9 @@
#include "UI_interface.h"
#include "UI_resources.h"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_attribute_vector_rotate_cc {
-static void geo_node_attribute_vector_rotate_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::String>(N_("Vector"));
@@ -42,9 +42,7 @@ static void geo_node_attribute_vector_rotate_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_attribute_vector_rotate_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
bNode *node = (bNode *)ptr->data;
const NodeAttributeVectorRotate &node_storage = *(NodeAttributeVectorRotate *)node->storage;
@@ -70,7 +68,7 @@ static void geo_node_attribute_vector_rotate_layout(uiLayout *layout,
}
}
-static void geo_node_attribute_vector_rotate_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
const NodeAttributeVectorRotate *node_storage = (NodeAttributeVectorRotate *)node->storage;
const GeometryNodeAttributeVectorRotateMode mode = (const GeometryNodeAttributeVectorRotateMode)
@@ -112,7 +110,7 @@ static float3 vector_rotate_around_axis(const float3 vector,
return result + center;
}
-static void geo_node_attribute_vector_rotate_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeAttributeVectorRotate *node_storage = (NodeAttributeVectorRotate *)MEM_callocN(
sizeof(NodeAttributeVectorRotate), __func__);
@@ -309,11 +307,11 @@ static void execute_on_component(const GeoNodeExecParams &params, GeometryCompon
attribute_result.save();
}
-static void geo_node_attribute_vector_rotate_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
execute_on_component(params, geometry_set.get_component_for_write<MeshComponent>());
@@ -328,10 +326,12 @@ static void geo_node_attribute_vector_rotate_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_vector_rotate_cc
void register_node_type_geo_attribute_vector_rotate()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_vector_rotate_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype,
@@ -339,13 +339,13 @@ void register_node_type_geo_attribute_vector_rotate()
"Attribute Vector Rotate",
NODE_CLASS_ATTRIBUTE,
0);
- node_type_update(&ntype, blender::nodes::geo_node_attribute_vector_rotate_update);
- node_type_init(&ntype, blender::nodes::geo_node_attribute_vector_rotate_init);
+ node_type_update(&ntype, file_ns::node_update);
+ node_type_init(&ntype, file_ns::node_init);
node_type_size(&ntype, 165, 100, 600);
node_type_storage(
&ntype, "NodeAttributeVectorRotate", node_free_standard_storage, node_copy_standard_storage);
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_vector_rotate_exec;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_vector_rotate_layout;
- ntype.declare = blender::nodes::geo_node_attribute_vector_rotate_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_endpoints.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_endpoints.cc
index 67c8200a9c2..e61dee4bee1 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_endpoints.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_endpoints.cc
@@ -25,9 +25,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_curve_endpoints_cc {
-static void geo_node_curve_endpoints_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_output<decl::Geometry>(N_("Start Points"));
@@ -145,15 +145,14 @@ static void copy_endpoint_attributes(Span<SplinePtr> splines,
});
}
-static void geo_node_curve_endpoints_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = bke::geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (!geometry_set.has_curve()) {
- params.set_output("Start Points", GeometrySet());
- params.set_output("End Points", GeometrySet());
+ params.set_default_remaining_outputs();
return;
}
@@ -168,8 +167,7 @@ static void geo_node_curve_endpoints_exec(GeoNodeExecParams params)
const int total_size = offsets.size();
if (total_size == 0) {
- params.set_output("Start Points", GeometrySet());
- params.set_output("End Points", GeometrySet());
+ params.set_default_remaining_outputs();
return;
}
@@ -206,16 +204,18 @@ static void geo_node_curve_endpoints_exec(GeoNodeExecParams params)
params.set_output("End Points", std::move(end_result));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_curve_endpoints_cc
void register_node_type_geo_legacy_curve_endpoints()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_curve_endpoints_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_CURVE_ENDPOINTS, "Curve Endpoints", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_curve_endpoints_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_endpoints_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_reverse.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_reverse.cc
index bc4612e2b8b..7c550495b41 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_reverse.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_reverse.cc
@@ -20,19 +20,19 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_curve_reverse_cc {
-static void geo_node_curve_reverse_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Curve"));
b.add_input<decl::String>(N_("Selection"));
b.add_output<decl::Geometry>(N_("Curve"));
}
-static void geo_node_curve_reverse_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
- geometry_set = bke::geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (!geometry_set.has_curve()) {
params.set_output("Curve", geometry_set);
return;
@@ -58,14 +58,16 @@ static void geo_node_curve_reverse_exec(GeoNodeExecParams params)
params.set_output("Curve", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_curve_reverse_cc
void register_node_type_geo_legacy_curve_reverse()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_curve_reverse_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_CURVE_REVERSE, "Curve Reverse", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_curve_reverse_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_reverse_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_select_by_handle_type.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc
index 40d827ae141..c702e9ff686 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_select_by_handle_type.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc
@@ -23,24 +23,22 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_curve_select_by_handle_type_cc {
-static void geo_node_select_by_handle_type_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::String>(N_("Selection"));
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_curve_select_by_handle_type_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
uiItemR(layout, ptr, "handle_type", 0, "", ICON_NONE);
}
-static void geo_node_curve_select_by_handle_type_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryCurveSelectHandles *data = (NodeGeometryCurveSelectHandles *)MEM_callocN(
sizeof(NodeGeometryCurveSelectHandles), __func__);
@@ -94,7 +92,7 @@ static void select_curve_by_handle_type(const CurveEval &curve,
});
}
-static void geo_node_select_by_handle_type_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
const NodeGeometryCurveSelectHandles *storage =
(const NodeGeometryCurveSelectHandles *)params.node().storage;
@@ -103,7 +101,7 @@ static void geo_node_select_by_handle_type_exec(GeoNodeExecParams params)
const GeometryNodeCurveHandleMode mode = (GeometryNodeCurveHandleMode)storage->mode;
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = bke::geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
CurveComponent &curve_component = geometry_set.get_component_for_write<CurveComponent>();
const CurveEval *curve = curve_component.get_for_read();
@@ -121,10 +119,12 @@ static void geo_node_select_by_handle_type_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_curve_select_by_handle_type_cc
void register_node_type_geo_legacy_select_by_handle_type()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_curve_select_by_handle_type_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype,
@@ -132,14 +132,14 @@ void register_node_type_geo_legacy_select_by_handle_type()
"Select by Handle Type",
NODE_CLASS_GEOMETRY,
0);
- ntype.declare = blender::nodes::geo_node_select_by_handle_type_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_select_by_handle_type_exec;
- node_type_init(&ntype, blender::nodes::geo_node_curve_select_by_handle_type_init);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(&ntype,
"NodeGeometryCurveSelectHandles",
node_free_standard_storage,
node_copy_standard_storage);
- ntype.draw_buttons = blender::nodes::geo_node_curve_select_by_handle_type_layout;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_set_handles.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc
index b92db315d94..1e476d01148 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_set_handles.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc
@@ -21,24 +21,22 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_curve_set_handles_cc {
-static void geo_node_curve_set_handles_decalre(NodeDeclarationBuilder &b)
+static void node_decalre(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Curve"));
b.add_input<decl::String>(N_("Selection"));
b.add_output<decl::Geometry>(N_("Curve"));
}
-static void geo_node_curve_set_handles_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
uiItemR(layout, ptr, "handle_type", 0, "", ICON_NONE);
}
-static void geo_node_curve_set_handles_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryCurveSetHandles *data = (NodeGeometryCurveSetHandles *)MEM_callocN(
sizeof(NodeGeometryCurveSetHandles), __func__);
@@ -64,7 +62,7 @@ static BezierSpline::HandleType handle_type_from_input_type(GeometryNodeCurveHan
return BezierSpline::HandleType::Auto;
}
-static void geo_node_curve_set_handles_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
const NodeGeometryCurveSetHandles *node_storage =
(NodeGeometryCurveSetHandles *)params.node().storage;
@@ -72,7 +70,7 @@ static void geo_node_curve_set_handles_exec(GeoNodeExecParams params)
const GeometryNodeCurveHandleMode mode = (GeometryNodeCurveHandleMode)node_storage->mode;
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
- geometry_set = bke::geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (!geometry_set.has_curve()) {
params.set_output("Curve", geometry_set);
return;
@@ -124,21 +122,23 @@ static void geo_node_curve_set_handles_exec(GeoNodeExecParams params)
params.set_output("Curve", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_curve_set_handles_cc
void register_node_type_geo_legacy_curve_set_handles()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_curve_set_handles_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_CURVE_SET_HANDLES, "Set Handle Type", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_curve_set_handles_decalre;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_set_handles_exec;
- node_type_init(&ntype, blender::nodes::geo_node_curve_set_handles_init);
+ ntype.declare = file_ns::node_decalre;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(&ntype,
"NodeGeometryCurveSetHandles",
node_free_standard_storage,
node_copy_standard_storage);
- ntype.draw_buttons = blender::nodes::geo_node_curve_set_handles_layout;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_spline_type.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc
index 36d4519cac3..f3599f4328f 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_spline_type.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc
@@ -23,23 +23,21 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_curve_spline_type_cc {
-static void geo_node_legacy_curve_spline_type_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Curve"));
b.add_input<decl::String>(N_("Selection"));
b.add_output<decl::Geometry>(N_("Curve"));
}
-static void geo_node_legacy_curve_spline_type_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "spline_type", 0, "", ICON_NONE);
}
-static void geo_node_legacy_curve_spline_type_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryCurveSplineType *data = (NodeGeometryCurveSplineType *)MEM_callocN(
sizeof(NodeGeometryCurveSplineType), __func__);
@@ -238,14 +236,14 @@ static SplinePtr convert_to_nurbs(const Spline &input)
return {};
}
-static void geo_node_legacy_curve_spline_type_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
const NodeGeometryCurveSplineType *storage =
(const NodeGeometryCurveSplineType *)params.node().storage;
const GeometryNodeSplineType output_type = (const GeometryNodeSplineType)storage->spline_type;
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
- geometry_set = bke::geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (!geometry_set.has_curve()) {
params.set_output("Curve", geometry_set);
return;
@@ -282,21 +280,23 @@ static void geo_node_legacy_curve_spline_type_exec(GeoNodeExecParams params)
params.set_output("Curve", GeometrySet::create_with_curve(new_curve.release()));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_curve_spline_type_cc
void register_node_type_geo_legacy_curve_spline_type()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_curve_spline_type_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_CURVE_SPLINE_TYPE, "Set Spline Type", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_legacy_curve_spline_type_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_legacy_curve_spline_type_exec;
- node_type_init(&ntype, blender::nodes::geo_node_legacy_curve_spline_type_init);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(&ntype,
"NodeGeometryCurveSplineType",
node_free_standard_storage,
node_copy_standard_storage);
- ntype.draw_buttons = blender::nodes::geo_node_legacy_curve_spline_type_layout;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_subdivide.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc
index 603547a8e69..9878402dd35 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_subdivide.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc
@@ -25,9 +25,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_curve_subdivide_cc {
-static void geo_node_curve_subdivide_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::String>(N_("Cuts"));
@@ -35,14 +35,14 @@ static void geo_node_curve_subdivide_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_curve_subdivide_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
uiItemR(layout, ptr, "cuts_type", 0, IFACE_("Cuts"), ICON_NONE);
}
-static void geo_node_curve_subdivide_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryCurveSubdivide *data = (NodeGeometryCurveSubdivide *)MEM_callocN(
sizeof(NodeGeometryCurveSubdivide), __func__);
@@ -51,7 +51,7 @@ static void geo_node_curve_subdivide_init(bNodeTree *UNUSED(tree), bNode *node)
node->storage = data;
}
-static void geo_node_curve_subdivide_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
NodeGeometryPointTranslate &node_storage = *(NodeGeometryPointTranslate *)node->storage;
@@ -347,11 +347,11 @@ static std::unique_ptr<CurveEval> subdivide_curve(const CurveEval &input_curve,
return output_curve;
}
-static void geo_node_subdivide_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = bke::geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (!geometry_set.has_curve()) {
params.set_output("Geometry", geometry_set);
@@ -370,22 +370,24 @@ static void geo_node_subdivide_exec(GeoNodeExecParams params)
params.set_output("Geometry", GeometrySet::create_with_curve(output_curve.release()));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_curve_subdivide_cc
void register_node_type_geo_legacy_curve_subdivide()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_curve_subdivide_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_CURVE_SUBDIVIDE, "Curve Subdivide", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_curve_subdivide_declare;
- ntype.draw_buttons = blender::nodes::geo_node_curve_subdivide_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_layout;
node_type_storage(&ntype,
"NodeGeometryCurveSubdivide",
node_free_standard_storage,
node_copy_standard_storage);
- node_type_init(&ntype, blender::nodes::geo_node_curve_subdivide_init);
- node_type_update(&ntype, blender::nodes::geo_node_curve_subdivide_update);
- ntype.geometry_node_execute = blender::nodes::geo_node_subdivide_exec;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_to_points.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc
index ab51258cc69..3bd03f3cee0 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_to_points.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc
@@ -28,7 +28,59 @@
namespace blender::nodes {
-static void geo_node_curve_to_points_declare(NodeDeclarationBuilder &b)
+static GMutableSpan create_attribute_and_retrieve_span(PointCloudComponent &points,
+ const AttributeIDRef &attribute_id,
+ const CustomDataType data_type)
+{
+ points.attribute_try_create(attribute_id, ATTR_DOMAIN_POINT, data_type, AttributeInitDefault());
+ WriteAttributeLookup attribute = points.attribute_try_get_for_write(attribute_id);
+ BLI_assert(attribute);
+ return attribute.varray.get_internal_span();
+}
+
+template<typename T>
+static MutableSpan<T> create_attribute_and_retrieve_span(PointCloudComponent &points,
+ const AttributeIDRef &attribute_id)
+{
+ GMutableSpan attribute = create_attribute_and_retrieve_span(
+ points, attribute_id, bke::cpp_type_to_custom_data_type(CPPType::get<T>()));
+ return attribute.typed<T>();
+}
+
+CurveToPointsResults curve_to_points_create_result_attributes(PointCloudComponent &points,
+ const CurveEval &curve)
+{
+ CurveToPointsResults attributes;
+
+ attributes.result_size = points.attribute_domain_size(ATTR_DOMAIN_POINT);
+
+ attributes.positions = create_attribute_and_retrieve_span<float3>(points, "position");
+ attributes.radii = create_attribute_and_retrieve_span<float>(points, "radius");
+ attributes.tilts = create_attribute_and_retrieve_span<float>(points, "tilt");
+
+ /* Because of the invariants of the curve component, we use the attributes of the
+ * first spline as a representative for the attribute meta data all splines. */
+ curve.splines().first()->attributes.foreach_attribute(
+ [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
+ attributes.point_attributes.add_new(
+ attribute_id,
+ create_attribute_and_retrieve_span(points, attribute_id, meta_data.data_type));
+ return true;
+ },
+ ATTR_DOMAIN_POINT);
+
+ attributes.tangents = create_attribute_and_retrieve_span<float3>(points, "tangent");
+ attributes.normals = create_attribute_and_retrieve_span<float3>(points, "normal");
+ attributes.rotations = create_attribute_and_retrieve_span<float3>(points, "rotation");
+
+ return attributes;
+}
+
+} // namespace blender::nodes
+
+namespace blender::nodes::node_geo_legacy_curve_to_points_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::Int>(N_("Count")).default_value(10).min(2).max(100000);
@@ -36,12 +88,12 @@ static void geo_node_curve_to_points_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_curve_to_points_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
}
-static void geo_node_curve_to_points_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryCurveToPoints *data = (NodeGeometryCurveToPoints *)MEM_callocN(
sizeof(NodeGeometryCurveToPoints), __func__);
@@ -50,7 +102,7 @@ static void geo_node_curve_to_points_init(bNodeTree *UNUSED(tree), bNode *node)
node->storage = data;
}
-static void geo_node_curve_to_points_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
NodeGeometryCurveToPoints &node_storage = *(NodeGeometryCurveToPoints *)node->storage;
const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)node_storage.mode;
@@ -114,54 +166,6 @@ static Array<int> calculate_spline_point_offsets(GeoNodeExecParams &params,
return {0};
}
-static GMutableSpan create_attribute_and_retrieve_span(PointCloudComponent &points,
- const AttributeIDRef &attribute_id,
- const CustomDataType data_type)
-{
- points.attribute_try_create(attribute_id, ATTR_DOMAIN_POINT, data_type, AttributeInitDefault());
- WriteAttributeLookup attribute = points.attribute_try_get_for_write(attribute_id);
- BLI_assert(attribute);
- return attribute.varray.get_internal_span();
-}
-
-template<typename T>
-static MutableSpan<T> create_attribute_and_retrieve_span(PointCloudComponent &points,
- const AttributeIDRef &attribute_id)
-{
- GMutableSpan attribute = create_attribute_and_retrieve_span(
- points, attribute_id, bke::cpp_type_to_custom_data_type(CPPType::get<T>()));
- return attribute.typed<T>();
-}
-
-CurveToPointsResults curve_to_points_create_result_attributes(PointCloudComponent &points,
- const CurveEval &curve)
-{
- CurveToPointsResults attributes;
-
- attributes.result_size = points.attribute_domain_size(ATTR_DOMAIN_POINT);
-
- attributes.positions = create_attribute_and_retrieve_span<float3>(points, "position");
- attributes.radii = create_attribute_and_retrieve_span<float>(points, "radius");
- attributes.tilts = create_attribute_and_retrieve_span<float>(points, "tilt");
-
- /* Because of the invariants of the curve component, we use the attributes of the
- * first spline as a representative for the attribute meta data all splines. */
- curve.splines().first()->attributes.foreach_attribute(
- [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
- attributes.point_attributes.add_new(
- attribute_id,
- create_attribute_and_retrieve_span(points, attribute_id, meta_data.data_type));
- return true;
- },
- ATTR_DOMAIN_POINT);
-
- attributes.tangents = create_attribute_and_retrieve_span<float3>(points, "tangent");
- attributes.normals = create_attribute_and_retrieve_span<float3>(points, "normal");
- attributes.rotations = create_attribute_and_retrieve_span<float3>(points, "rotation");
-
- return attributes;
-}
-
/**
* TODO: For non-poly splines, this has double copies that could be avoided as part
* of a general look at optimizing uses of #Spline::interpolate_to_evaluated.
@@ -286,13 +290,13 @@ static void copy_spline_domain_attributes(const CurveComponent &curve_component,
});
}
-static void geo_node_curve_to_points_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
NodeGeometryCurveToPoints &node_storage = *(NodeGeometryCurveToPoints *)params.node().storage;
const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)node_storage.mode;
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = bke::geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (!geometry_set.has_curve()) {
params.set_output("Geometry", GeometrySet());
@@ -340,21 +344,23 @@ static void geo_node_curve_to_points_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(result));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_curve_to_points_cc
void register_node_type_geo_legacy_curve_to_points()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_curve_to_points_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_CURVE_TO_POINTS, "Curve to Points", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_curve_to_points_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_to_points_exec;
- ntype.draw_buttons = blender::nodes::geo_node_curve_to_points_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
node_type_storage(
&ntype, "NodeGeometryCurveToPoints", node_free_standard_storage, node_copy_standard_storage);
- node_type_init(&ntype, blender::nodes::geo_node_curve_to_points_init);
- node_type_update(&ntype, blender::nodes::geo_node_curve_to_points_update);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_delete_geometry.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_delete_geometry.cc
index f62a22d7934..abd75e710ae 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_delete_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_delete_geometry.cc
@@ -29,23 +29,23 @@
using blender::bke::CustomDataAttributes;
/* Code from the mask modifier in MOD_mask.cc. */
-extern void copy_masked_vertices_to_new_mesh(const Mesh &src_mesh,
- Mesh &dst_mesh,
- blender::Span<int> vertex_map);
-extern void copy_masked_edges_to_new_mesh(const Mesh &src_mesh,
- Mesh &dst_mesh,
- blender::Span<int> vertex_map,
- blender::Span<int> edge_map);
-extern void copy_masked_polys_to_new_mesh(const Mesh &src_mesh,
- Mesh &dst_mesh,
- blender::Span<int> vertex_map,
- blender::Span<int> edge_map,
- blender::Span<int> masked_poly_indices,
- blender::Span<int> new_loop_starts);
-
-namespace blender::nodes {
-
-static void geo_node_delete_geometry_declare(NodeDeclarationBuilder &b)
+void copy_masked_vertices_to_new_mesh(const Mesh &src_mesh,
+ Mesh &dst_mesh,
+ blender::Span<int> vertex_map);
+void copy_masked_edges_to_new_mesh(const Mesh &src_mesh,
+ Mesh &dst_mesh,
+ blender::Span<int> vertex_map,
+ blender::Span<int> edge_map);
+void copy_masked_polys_to_new_mesh(const Mesh &src_mesh,
+ Mesh &dst_mesh,
+ blender::Span<int> vertex_map,
+ blender::Span<int> edge_map,
+ blender::Span<int> masked_poly_indices,
+ blender::Span<int> new_loop_starts);
+
+namespace blender::nodes::node_geo_legacy_delete_geometry_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::String>(N_("Selection"));
@@ -627,10 +627,10 @@ static void delete_mesh_selection(MeshComponent &component,
component.replace(mesh_out);
}
-static void geo_node_delete_geometry_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = bke::geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
const bool invert = params.extract_input<bool>("Invert");
const std::string selection_name = params.extract_input<std::string>("Selection");
@@ -662,16 +662,18 @@ static void geo_node_delete_geometry_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(out_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_delete_geometry_cc
void register_node_type_geo_legacy_delete_geometry()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_delete_geometry_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_DELETE_GEOMETRY, "Delete Geometry", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_delete_geometry_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_delete_geometry_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_edge_split.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_edge_split.cc
index 8f2bf05d2b4..c046fda4686 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_edge_split.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_edge_split.cc
@@ -22,9 +22,9 @@ extern "C" {
Mesh *doEdgeSplit(const Mesh *mesh, EdgeSplitModifierData *emd);
}
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_edge_split_cc {
-static void geo_node_edge_split_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::Bool>(N_("Edge Angle")).default_value(true);
@@ -37,11 +37,11 @@ static void geo_node_edge_split_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_edge_split_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (!geometry_set.has_mesh()) {
params.set_output("Geometry", std::move(geometry_set));
@@ -76,14 +76,16 @@ static void geo_node_edge_split_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_edge_split_cc
void register_node_type_geo_legacy_edge_split()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_edge_split_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_LEGACY_EDGE_SPLIT, "Edge Split", NODE_CLASS_GEOMETRY, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_edge_split_exec;
- ntype.declare = blender::nodes::geo_node_edge_split_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_material_assign.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_material_assign.cc
index 58374679a95..88e8374f5d6 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_material_assign.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_material_assign.cc
@@ -24,9 +24,9 @@
#include "BKE_material.h"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_material_assign_cc {
-static void geo_node_legacy_material_assign_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::Material>(N_("Material")).hide_label(true);
@@ -59,14 +59,14 @@ static void assign_material_to_faces(Mesh &mesh, const VArray<bool> &face_mask,
}
}
-static void geo_node_legacy_material_assign_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Material *material = params.extract_input<Material *>("Material");
const std::string mask_name = params.extract_input<std::string>("Selection");
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
@@ -81,15 +81,17 @@ static void geo_node_legacy_material_assign_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_material_assign_cc
void register_node_type_geo_legacy_material_assign()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_material_assign_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_MATERIAL_ASSIGN, "Material Assign", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_legacy_material_assign_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_legacy_material_assign_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_mesh_to_curve.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc
index 321de24a3dc..2ff7410f3f6 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_mesh_to_curve.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc
@@ -18,23 +18,23 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_mesh_to_curve_cc {
-static void geo_node_legacy_mesh_to_curve_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Mesh"));
b.add_input<decl::String>(N_("Selection"));
b.add_output<decl::Geometry>(N_("Curve"));
}
-static void geo_node_legacy_mesh_to_curve_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
- geometry_set = bke::geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (!geometry_set.has_mesh()) {
- params.set_output("Curve", GeometrySet());
+ params.set_default_remaining_outputs();
return;
}
@@ -55,7 +55,7 @@ static void geo_node_legacy_mesh_to_curve_exec(GeoNodeExecParams params)
}
if (selected_edge_indices.size() == 0) {
- params.set_output("Curve", GeometrySet());
+ params.set_default_remaining_outputs();
return;
}
@@ -65,15 +65,17 @@ static void geo_node_legacy_mesh_to_curve_exec(GeoNodeExecParams params)
params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_mesh_to_curve_cc
void register_node_type_geo_legacy_mesh_to_curve()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_mesh_to_curve_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_MESH_TO_CURVE, "Mesh to Curve", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_legacy_mesh_to_curve_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_legacy_mesh_to_curve_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_distribute.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_distribute.cc
index 4e13a490d89..2451a7447ec 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_distribute.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_distribute.cc
@@ -36,11 +36,11 @@
#include "node_geometry_util.hh"
-using blender::bke::GeometryInstanceGroup;
+namespace blender::nodes::node_geo_legacy_point_distribute_cc {
-namespace blender::nodes {
+using blender::bke::GeometryInstanceGroup;
-static void geo_node_point_distribute_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::Float>(N_("Distance Min")).min(0.0f).max(100000.0f).subtype(PROP_DISTANCE);
@@ -54,9 +54,7 @@ static void geo_node_point_distribute_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_point_distribute_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "distribute_method", 0, "", ICON_NONE);
}
@@ -541,7 +539,7 @@ static void distribute_points_poisson_disk(Span<GeometryInstanceGroup> set_group
}
}
-static void geo_node_point_distribute_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
@@ -554,14 +552,14 @@ static void geo_node_point_distribute_exec(GeoNodeExecParams params)
"Density Attribute");
if (density <= 0.0f) {
- params.set_output("Geometry", GeometrySet());
+ params.set_default_remaining_outputs();
return;
}
Vector<GeometryInstanceGroup> set_groups;
geometry_set_gather_instances(geometry_set, set_groups);
if (set_groups.is_empty()) {
- params.set_output("Geometry", GeometrySet());
+ params.set_default_remaining_outputs();
return;
}
@@ -575,7 +573,7 @@ static void geo_node_point_distribute_exec(GeoNodeExecParams params)
if (set_groups.is_empty()) {
params.error_message_add(NodeWarningType::Error, TIP_("Input geometry must contain a mesh"));
- params.set_output("Geometry", GeometrySet());
+ params.set_default_remaining_outputs();
return;
}
@@ -625,7 +623,7 @@ static void geo_node_point_distribute_exec(GeoNodeExecParams params)
}
if (final_points_len == 0) {
- params.set_output("Geometry", GeometrySet());
+ params.set_default_remaining_outputs();
return;
}
@@ -655,17 +653,19 @@ static void geo_node_point_distribute_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set_out));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_point_distribute_cc
void register_node_type_geo_point_distribute()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_point_distribute_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_POINT_DISTRIBUTE, "Point Distribute", NODE_CLASS_GEOMETRY, 0);
- node_type_update(&ntype, blender::nodes::node_point_distribute_update);
- ntype.declare = blender::nodes::geo_node_point_distribute_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_point_distribute_exec;
- ntype.draw_buttons = blender::nodes::geo_node_point_distribute_layout;
+ node_type_update(&ntype, file_ns::node_point_distribute_update);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_instance.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_instance.cc
index 713971941ea..8915a58feb1 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_instance.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_instance.cc
@@ -24,9 +24,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_point_instance_cc {
-static void geo_node_point_instance_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::Object>(N_("Object")).hide_label();
@@ -36,7 +36,7 @@ static void geo_node_point_instance_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_point_instance_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "instance_type", 0, "", ICON_NONE);
if (RNA_enum_get(ptr, "instance_type") == GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION) {
@@ -44,7 +44,7 @@ static void geo_node_point_instance_layout(uiLayout *layout, bContext *UNUSED(C)
}
}
-static void geo_node_point_instance_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryPointInstance *data = (NodeGeometryPointInstance *)MEM_callocN(
sizeof(NodeGeometryPointInstance), __func__);
@@ -53,7 +53,7 @@ static void geo_node_point_instance_init(bNodeTree *UNUSED(tree), bNode *node)
node->storage = data;
}
-static void geo_node_point_instance_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
bNodeSocket *object_socket = (bNodeSocket *)BLI_findlink(&node->inputs, 1);
bNodeSocket *collection_socket = object_socket->next;
@@ -173,6 +173,9 @@ static void add_instances_from_component(InstancesComponent &instances,
const AttributeDomain domain = ATTR_DOMAIN_POINT;
const int domain_size = src_geometry.attribute_domain_size(domain);
+ if (domain_size == 0) {
+ return;
+ }
VArray<float3> positions = src_geometry.attribute_get_for_read<float3>(
"position", domain, {0, 0, 0});
@@ -186,7 +189,9 @@ static void add_instances_from_component(InstancesComponent &instances,
instances.resize(start_len + domain_size);
MutableSpan<int> handles = instances.instance_reference_handles().slice(start_len, domain_size);
MutableSpan<float4x4> transforms = instances.instance_transforms().slice(start_len, domain_size);
- MutableSpan<int> instance_ids = instances.instance_ids_ensure().slice(start_len, domain_size);
+ OutputAttribute_Typed<int> instance_id_attribute =
+ instances.attribute_try_get_for_output_only<int>("id", ATTR_DOMAIN_INSTANCE);
+ MutableSpan<int> instance_ids = instance_id_attribute.as_span();
/* Skip all of the randomness handling if there is only a single possible instance
* (anything except for collection mode with "Whole Collection" turned off). */
@@ -213,16 +218,18 @@ static void add_instances_from_component(InstancesComponent &instances,
}
});
}
+
+ instance_id_attribute.save();
}
-static void geo_node_point_instance_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
GeometrySet geometry_set_out;
/* TODO: This node should be able to instance on the input instances component
* rather than making the entire input geometry set real. */
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
const Vector<InstanceReference> possible_references = get_instance_references(params);
if (possible_references.is_empty()) {
@@ -255,20 +262,22 @@ static void geo_node_point_instance_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set_out));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_point_instance_cc
void register_node_type_geo_point_instance()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_point_instance_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_POINT_INSTANCE, "Point Instance", NODE_CLASS_GEOMETRY, 0);
- node_type_init(&ntype, blender::nodes::geo_node_point_instance_init);
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(
&ntype, "NodeGeometryPointInstance", node_free_standard_storage, node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_point_instance_declare;
- ntype.draw_buttons = blender::nodes::geo_node_point_instance_layout;
- node_type_update(&ntype, blender::nodes::geo_node_point_instance_update);
- ntype.geometry_node_execute = blender::nodes::geo_node_point_instance_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_layout;
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_rotate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_rotate.cc
index ab1d68bfe4f..a0a7674797a 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_rotate.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_rotate.cc
@@ -21,9 +21,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_point_rotate_cc {
-static void geo_node_point_rotate_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::String>(N_("Axis"));
@@ -37,7 +37,7 @@ static void geo_node_point_rotate_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_point_rotate_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
NodeGeometryRotatePoints *storage = (NodeGeometryRotatePoints *)((bNode *)ptr->data)->storage;
@@ -57,7 +57,7 @@ static void geo_node_point_rotate_layout(uiLayout *layout, bContext *UNUSED(C),
}
}
-static void geo_node_point_rotate_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeGeometryRotatePoints *node_storage = (NodeGeometryRotatePoints *)MEM_callocN(
sizeof(NodeGeometryRotatePoints), __func__);
@@ -71,7 +71,7 @@ static void geo_node_point_rotate_init(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = node_storage;
}
-static void geo_node_point_rotate_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
NodeGeometryRotatePoints *node_storage = (NodeGeometryRotatePoints *)node->storage;
update_attribute_input_socket_availabilities(
@@ -199,11 +199,11 @@ static void point_rotate_on_component(GeometryComponent &component,
rotation_attribute.save();
}
-static void geo_node_point_rotate_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
point_rotate_on_component(geometry_set.get_component_for_write<MeshComponent>(), params);
@@ -218,19 +218,21 @@ static void geo_node_point_rotate_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_point_rotate_cc
void register_node_type_geo_point_rotate()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_point_rotate_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_LEGACY_POINT_ROTATE, "Point Rotate", NODE_CLASS_GEOMETRY, 0);
- node_type_init(&ntype, blender::nodes::geo_node_point_rotate_init);
- node_type_update(&ntype, blender::nodes::geo_node_point_rotate_update);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(
&ntype, "NodeGeometryRotatePoints", node_free_standard_storage, node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_point_rotate_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_point_rotate_exec;
- ntype.draw_buttons = blender::nodes::geo_node_point_rotate_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_scale.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_scale.cc
index 8d6345ce6b1..d38df124979 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_scale.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_scale.cc
@@ -21,9 +21,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_point_scale_cc {
-static void geo_node_point_scale_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::String>(N_("Factor"));
@@ -34,14 +34,14 @@ static void geo_node_point_scale_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_point_scale_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
uiItemR(layout, ptr, "input_type", 0, IFACE_("Type"), ICON_NONE);
}
-static void geo_node_point_scale_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryPointScale *data = (NodeGeometryPointScale *)MEM_callocN(
sizeof(NodeGeometryPointScale), __func__);
@@ -50,7 +50,7 @@ static void geo_node_point_scale_init(bNodeTree *UNUSED(tree), bNode *node)
node->storage = data;
}
-static void geo_node_point_scale_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
NodeGeometryPointScale &node_storage = *(NodeGeometryPointScale *)node->storage;
@@ -101,11 +101,11 @@ static void execute_on_component(GeoNodeExecParams params, GeometryComponent &co
scale_attribute.save();
}
-static void geo_node_point_scale_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
execute_on_component(params, geometry_set.get_component_for_write<MeshComponent>());
@@ -120,20 +120,22 @@ static void geo_node_point_scale_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_point_scale_cc
void register_node_type_geo_point_scale()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_point_scale_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_LEGACY_POINT_SCALE, "Point Scale", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_point_scale_declare;
- node_type_init(&ntype, blender::nodes::geo_node_point_scale_init);
- node_type_update(&ntype, blender::nodes::geo_node_point_scale_update);
+ ntype.declare = file_ns::node_declare;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(
&ntype, "NodeGeometryPointScale", node_free_standard_storage, node_copy_standard_storage);
- ntype.geometry_node_execute = blender::nodes::geo_node_point_scale_exec;
- ntype.draw_buttons = blender::nodes::geo_node_point_scale_layout;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_separate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_separate.cc
index 3539fe2de64..9260928b311 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_separate.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_separate.cc
@@ -25,14 +25,6 @@
namespace blender::nodes {
-static void geo_node_point_instance_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Geometry>(N_("Geometry"));
- b.add_input<decl::String>(N_("Mask"));
- b.add_output<decl::Geometry>(N_("Geometry 1"));
- b.add_output<decl::Geometry>(N_("Geometry 2"));
-}
-
template<typename T>
static void copy_data_based_on_mask(Span<T> data,
Span<bool> masks,
@@ -78,6 +70,18 @@ void copy_point_attributes_based_on_mask(const GeometryComponent &in_component,
}
}
+} // namespace blender::nodes
+
+namespace blender::nodes::node_geo_legacy_point_separate_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("Mask"));
+ b.add_output<decl::Geometry>(N_("Geometry 1"));
+ b.add_output<decl::Geometry>(N_("Geometry 2"));
+}
+
static void create_component_points(GeometryComponent &component, const int total)
{
switch (component.type()) {
@@ -133,7 +137,7 @@ static GeometrySet separate_geometry_set(const GeometrySet &set_in,
return set_out;
}
-static void geo_node_point_separate_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
bool wait_for_inputs = false;
wait_for_inputs |= params.lazy_require_input("Geometry");
@@ -146,7 +150,7 @@ static void geo_node_point_separate_exec(GeoNodeExecParams params)
/* TODO: This is not necessary-- the input geometry set can be read only,
* but it must be rewritten to handle instance groups. */
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (params.lazy_output_is_required("Geometry 1")) {
params.set_output("Geometry 1",
@@ -158,16 +162,18 @@ static void geo_node_point_separate_exec(GeoNodeExecParams params)
}
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_point_separate_cc
void register_node_type_geo_point_separate()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_point_separate_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_POINT_SEPARATE, "Point Separate", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_point_instance_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_point_separate_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.geometry_node_execute_supports_laziness = true;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_translate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_translate.cc
index 3b2959beb86..c70478182ec 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_translate.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_translate.cc
@@ -19,9 +19,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_point_translate_cc {
-static void geo_node_point_translate_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::String>(N_("Translation"));
@@ -29,7 +29,7 @@ static void geo_node_point_translate_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_point_translate_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
@@ -53,11 +53,11 @@ static void execute_on_component(GeoNodeExecParams params, GeometryComponent &co
position_attribute.save();
}
-static void geo_node_point_translate_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
execute_on_component(params, geometry_set.get_component_for_write<MeshComponent>());
@@ -72,7 +72,7 @@ static void geo_node_point_translate_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
}
-static void geo_node_point_translate_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryPointTranslate *data = (NodeGeometryPointTranslate *)MEM_callocN(
sizeof(NodeGeometryPointTranslate), __func__);
@@ -81,7 +81,7 @@ static void geo_node_point_translate_init(bNodeTree *UNUSED(tree), bNode *node)
node->storage = data;
}
-static void geo_node_point_translate_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
NodeGeometryPointTranslate &node_storage = *(NodeGeometryPointTranslate *)node->storage;
@@ -89,22 +89,24 @@ static void geo_node_point_translate_update(bNodeTree *ntree, bNode *node)
*ntree, *node, "Translation", (GeometryNodeAttributeInputMode)node_storage.input_type);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_point_translate_cc
void register_node_type_geo_point_translate()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_point_translate_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_POINT_TRANSLATE, "Point Translate", NODE_CLASS_GEOMETRY, 0);
- node_type_init(&ntype, blender::nodes::geo_node_point_translate_init);
- node_type_update(&ntype, blender::nodes::geo_node_point_translate_update);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(&ntype,
"NodeGeometryPointTranslate",
node_free_standard_storage,
node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_point_translate_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_point_translate_exec;
- ntype.draw_buttons = blender::nodes::geo_node_point_translate_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_points_to_volume.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_points_to_volume.cc
index d465a9ab1a8..ec1ab67b530 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_points_to_volume.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_points_to_volume.cc
@@ -28,9 +28,9 @@
#include "UI_interface.h"
#include "UI_resources.h"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_points_to_volume_cc {
-static void geo_node_points_to_volume_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::Float>(N_("Density")).default_value(1.0f).min(0.0f);
@@ -41,9 +41,7 @@ static void geo_node_points_to_volume_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_points_to_volume_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
@@ -51,7 +49,7 @@ static void geo_node_points_to_volume_layout(uiLayout *layout,
uiItemR(layout, ptr, "input_type_radius", 0, IFACE_("Radius"), ICON_NONE);
}
-static void geo_node_points_to_volume_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeGeometryPointsToVolume *data = (NodeGeometryPointsToVolume *)MEM_callocN(
sizeof(NodeGeometryPointsToVolume), __func__);
@@ -65,7 +63,7 @@ static void geo_node_points_to_volume_init(bNodeTree *UNUSED(ntree), bNode *node
STRNCPY(radius_attribute_socket_value->value, "radius");
}
-static void geo_node_points_to_volume_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
NodeGeometryPointsToVolume *data = (NodeGeometryPointsToVolume *)node->storage;
bNodeSocket *voxel_size_socket = nodeFindSocket(node, SOCK_IN, "Voxel Size");
@@ -244,13 +242,13 @@ static void initialize_volume_component_from_points(const GeometrySet &geometry_
}
#endif
-static void geo_node_points_to_volume_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set_in = params.extract_input<GeometrySet>("Geometry");
GeometrySet geometry_set_out;
/* TODO: Read-only access to instances should be supported here, for now they are made real. */
- geometry_set_in = geometry_set_realize_instances(geometry_set_in);
+ geometry_set_in = geometry::realize_instances_legacy(geometry_set_in);
#ifdef WITH_OPENVDB
initialize_volume_component_from_points(geometry_set_in, geometry_set_out, params);
@@ -259,10 +257,12 @@ static void geo_node_points_to_volume_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set_out));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_points_to_volume_cc
void register_node_type_geo_legacy_points_to_volume()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_points_to_volume_cc;
+
static bNodeType ntype;
geo_node_type_base(
@@ -272,10 +272,10 @@ void register_node_type_geo_legacy_points_to_volume()
node_free_standard_storage,
node_copy_standard_storage);
node_type_size(&ntype, 170, 120, 700);
- node_type_init(&ntype, blender::nodes::geo_node_points_to_volume_init);
- node_type_update(&ntype, blender::nodes::geo_node_points_to_volume_update);
- ntype.declare = blender::nodes::geo_node_points_to_volume_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_points_to_volume_exec;
- ntype.draw_buttons = blender::nodes::geo_node_points_to_volume_layout;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_raycast.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_raycast.cc
index 5aa683ca232..599ffd617a5 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_raycast.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_raycast.cc
@@ -24,9 +24,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_raycast_cc {
-static void geo_node_raycast_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::Geometry>(N_("Target Geometry"));
@@ -47,7 +47,7 @@ static void geo_node_raycast_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_raycast_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
@@ -56,7 +56,7 @@ static void geo_node_raycast_layout(uiLayout *layout, bContext *UNUSED(C), Point
uiItemR(layout, ptr, "input_type_ray_length", 0, IFACE_("Ray Length"), ICON_NONE);
}
-static void geo_node_raycast_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryRaycast *data = (NodeGeometryRaycast *)MEM_callocN(sizeof(NodeGeometryRaycast),
__func__);
@@ -65,7 +65,7 @@ static void geo_node_raycast_init(bNodeTree *UNUSED(tree), bNode *node)
node->storage = data;
}
-static void geo_node_raycast_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
NodeGeometryRaycast *node_storage = (NodeGeometryRaycast *)node->storage;
update_attribute_input_socket_availabilities(
@@ -272,7 +272,7 @@ static void raycast_from_points(const GeoNodeExecParams &params,
}
}
-static void geo_node_raycast_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
GeometrySet target_geometry_set = params.extract_input<GeometrySet>("Target Geometry");
@@ -285,8 +285,8 @@ static void geo_node_raycast_exec(GeoNodeExecParams params)
const Array<std::string> hit_names = {params.extract_input<std::string>("Target Attribute")};
const Array<std::string> hit_output_names = {params.extract_input<std::string>("Hit Attribute")};
- geometry_set = bke::geometry_set_realize_instances(geometry_set);
- target_geometry_set = bke::geometry_set_realize_instances(target_geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
+ target_geometry_set = geometry::realize_instances_legacy(target_geometry_set);
static const Array<GeometryComponentType> types = {
GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE};
@@ -307,20 +307,22 @@ static void geo_node_raycast_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_raycast_cc
void register_node_type_geo_legacy_raycast()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_raycast_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_LEGACY_RAYCAST, "Raycast", NODE_CLASS_GEOMETRY, 0);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
- node_type_init(&ntype, blender::nodes::geo_node_raycast_init);
- node_type_update(&ntype, blender::nodes::geo_node_raycast_update);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(
&ntype, "NodeGeometryRaycast", node_free_standard_storage, node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_raycast_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_raycast_exec;
- ntype.draw_buttons = blender::nodes::geo_node_raycast_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_select_by_material.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_select_by_material.cc
index a8d6f33a5fd..b61ba5ff67e 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_select_by_material.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_select_by_material.cc
@@ -26,9 +26,9 @@
#include "BKE_material.h"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_select_by_material_cc {
-static void geo_node_legacy_select_by_material_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::Material>(N_("Material")).hide_label();
@@ -54,13 +54,13 @@ static void select_mesh_by_material(const Mesh &mesh,
});
}
-static void geo_node_legacy_select_by_material_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Material *material = params.extract_input<Material *>("Material");
const std::string selection_name = params.extract_input<std::string>("Selection");
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
@@ -78,15 +78,17 @@ static void geo_node_legacy_select_by_material_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_select_by_material_cc
void register_node_type_geo_legacy_select_by_material()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_select_by_material_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_SELECT_BY_MATERIAL, "Select by Material", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_legacy_select_by_material_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_legacy_select_by_material_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_subdivision_surface.cc
index 295cd05fd01..819ffb2c20c 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_subdivision_surface.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_subdivision_surface.cc
@@ -23,9 +23,9 @@
#include "UI_resources.h"
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_subdivision_surface_cc {
-static void geo_node_subdivision_surface_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::Int>(N_("Level")).default_value(1).min(0).max(6);
@@ -33,9 +33,7 @@ static void geo_node_subdivision_surface_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_subdivision_surface_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
#ifdef WITH_OPENSUBDIV
uiLayoutSetPropSep(layout, true);
@@ -47,7 +45,7 @@ static void geo_node_subdivision_surface_layout(uiLayout *layout,
#endif
}
-static void geo_node_subdivision_surface_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeGeometrySubdivisionSurface *data = (NodeGeometrySubdivisionSurface *)MEM_callocN(
sizeof(NodeGeometrySubdivisionSurface), __func__);
@@ -56,11 +54,11 @@ static void geo_node_subdivision_surface_init(bNodeTree *UNUSED(ntree), bNode *n
node->storage = data;
}
-static void geo_node_subdivision_surface_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (!geometry_set.has_mesh()) {
params.set_output("Geometry", geometry_set);
@@ -126,18 +124,20 @@ static void geo_node_subdivision_surface_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_subdivision_surface_cc
void register_node_type_geo_legacy_subdivision_surface()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_subdivision_surface_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_SUBDIVISION_SURFACE, "Subdivision Surface", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_subdivision_surface_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_subdivision_surface_exec;
- ntype.draw_buttons = blender::nodes::geo_node_subdivision_surface_layout;
- node_type_init(&ntype, blender::nodes::geo_node_subdivision_surface_init);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ node_type_init(&ntype, file_ns::node_init);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
node_type_storage(&ntype,
"NodeGeometrySubdivisionSurface",
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_volume_to_mesh.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_volume_to_mesh.cc
index 6a52b943967..acff0be7126 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_volume_to_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_volume_to_mesh.cc
@@ -35,9 +35,9 @@
#include "UI_interface.h"
#include "UI_resources.h"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_volume_to_mesh_cc {
-static void geo_node_volume_to_mesh_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::String>(N_("Density"));
@@ -48,14 +48,14 @@ static void geo_node_volume_to_mesh_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_volume_to_mesh_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
uiItemR(layout, ptr, "resolution_mode", 0, IFACE_("Resolution"), ICON_NONE);
}
-static void geo_node_volume_to_mesh_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeGeometryVolumeToMesh *data = (NodeGeometryVolumeToMesh *)MEM_callocN(
sizeof(NodeGeometryVolumeToMesh), __func__);
@@ -68,7 +68,7 @@ static void geo_node_volume_to_mesh_init(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = data;
}
-static void geo_node_volume_to_mesh_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
NodeGeometryVolumeToMesh *data = (NodeGeometryVolumeToMesh *)node->storage;
@@ -140,7 +140,7 @@ static void create_mesh_from_volume(GeometrySet &geometry_set_in,
#endif /* WITH_OPENVDB */
-static void geo_node_volume_to_mesh_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set_in = params.extract_input<GeometrySet>("Geometry");
GeometrySet geometry_set_out;
@@ -155,21 +155,23 @@ static void geo_node_volume_to_mesh_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set_out);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_volume_to_mesh_cc
void register_node_type_geo_legacy_volume_to_mesh()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_volume_to_mesh_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_VOLUME_TO_MESH, "Volume to Mesh", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_volume_to_mesh_declare;
+ ntype.declare = file_ns::node_declare;
node_type_storage(
&ntype, "NodeGeometryVolumeToMesh", node_free_standard_storage, node_copy_standard_storage);
node_type_size(&ntype, 170, 120, 700);
- node_type_init(&ntype, blender::nodes::geo_node_volume_to_mesh_init);
- node_type_update(&ntype, blender::nodes::geo_node_volume_to_mesh_update);
- ntype.geometry_node_execute = blender::nodes::geo_node_volume_to_mesh_exec;
- ntype.draw_buttons = blender::nodes::geo_node_volume_to_mesh_layout;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc
index 19deb761948..be0baa706af 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc
@@ -19,11 +19,15 @@
#include "BKE_attribute_math.hh"
+#include "NOD_socket_search_link.hh"
+
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_attribute_capture_cc {
+
+NODE_STORAGE_FUNCS(NodeGeometryAttributeCapture)
-static void geo_node_attribute_capture_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::Vector>(N_("Value")).supports_field();
@@ -40,9 +44,7 @@ static void geo_node_attribute_capture_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Int>(N_("Attribute"), "Attribute_004").field_source();
}
-static void geo_node_attribute_capture_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
@@ -50,7 +52,7 @@ static void geo_node_attribute_capture_layout(uiLayout *layout,
uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
}
-static void geo_node_attribute_capture_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryAttributeCapture *data = (NodeGeometryAttributeCapture *)MEM_callocN(
sizeof(NodeGeometryAttributeCapture), __func__);
@@ -60,10 +62,9 @@ static void geo_node_attribute_capture_init(bNodeTree *UNUSED(tree), bNode *node
node->storage = data;
}
-static void geo_node_attribute_capture_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
- const NodeGeometryAttributeCapture &storage = *(const NodeGeometryAttributeCapture *)
- node->storage;
+ const NodeGeometryAttributeCapture &storage = node_storage(*node);
const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
bNodeSocket *socket_value_geometry = (bNodeSocket *)node->inputs.first;
@@ -93,6 +94,33 @@ static void geo_node_attribute_capture_update(bNodeTree *ntree, bNode *node)
nodeSetSocketAvailability(ntree, out_socket_value_int32, data_type == CD_PROP_INT32);
}
+static void node_gather_link_searches(GatherLinkSearchOpParams &params)
+{
+ const NodeDeclaration &declaration = *params.node_type().fixed_declaration;
+ search_link_ops_for_declarations(params, declaration.inputs().take_front(1));
+ search_link_ops_for_declarations(params, declaration.outputs().take_front(1));
+
+ const bNodeType &node_type = params.node_type();
+ const std::optional<CustomDataType> type = node_data_type_to_custom_data_type(
+ (eNodeSocketDatatype)params.other_socket().type);
+ if (type && *type != CD_PROP_STRING) {
+ if (params.in_out() == SOCK_OUT) {
+ params.add_item(IFACE_("Attribute"), [node_type, type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node(node_type);
+ node_storage(node).data_type = *type;
+ params.update_and_connect_available_socket(node, "Attribute");
+ });
+ }
+ else {
+ params.add_item(IFACE_("Value"), [node_type, type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node(node_type);
+ node_storage(node).data_type = *type;
+ params.update_and_connect_available_socket(node, "Value");
+ });
+ }
+ }
+}
+
static void try_capture_field_on_geometry(GeometryComponent &component,
const AttributeIDRef &attribute_id,
const AttributeDomain domain,
@@ -113,13 +141,11 @@ static void try_capture_field_on_geometry(GeometryComponent &component,
output_attribute.save();
}
-static void geo_node_attribute_capture_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- const bNode &node = params.node();
- const NodeGeometryAttributeCapture &storage = *(const NodeGeometryAttributeCapture *)
- node.storage;
+ const NodeGeometryAttributeCapture &storage = node_storage(params.node());
const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain);
@@ -147,16 +173,27 @@ static void geo_node_attribute_capture_exec(GeoNodeExecParams params)
WeakAnonymousAttributeID anonymous_id{"Attribute"};
const CPPType &type = field.cpp_type();
- static const Array<GeometryComponentType> types = {
- GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE};
- geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- for (const GeometryComponentType type : types) {
- if (geometry_set.has(type)) {
- GeometryComponent &component = geometry_set.get_component_for_write(type);
- try_capture_field_on_geometry(component, anonymous_id.get(), domain, field);
- }
+ /* Run on the instances component separately to only affect the top level of instances. */
+ if (domain == ATTR_DOMAIN_INSTANCE) {
+ if (geometry_set.has_instances()) {
+ GeometryComponent &component = geometry_set.get_component_for_write(
+ GEO_COMPONENT_TYPE_INSTANCES);
+ try_capture_field_on_geometry(component, anonymous_id.get(), domain, field);
}
- });
+ }
+ else {
+ static const Array<GeometryComponentType> types = {
+ GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE};
+
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ for (const GeometryComponentType type : types) {
+ if (geometry_set.has(type)) {
+ GeometryComponent &component = geometry_set.get_component_for_write(type);
+ try_capture_field_on_geometry(component, anonymous_id.get(), domain, field);
+ }
+ }
+ });
+ }
GField output_field{std::make_shared<bke::AnonymousAttributeFieldInput>(
std::move(anonymous_id), type, params.attribute_producer_name())};
@@ -189,10 +226,12 @@ static void geo_node_attribute_capture_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_attribute_capture_cc
void register_node_type_geo_attribute_capture()
{
+ namespace file_ns = blender::nodes::node_geo_attribute_capture_cc;
+
static bNodeType ntype;
geo_node_type_base(
@@ -201,10 +240,11 @@ void register_node_type_geo_attribute_capture()
"NodeGeometryAttributeCapture",
node_free_standard_storage,
node_copy_standard_storage);
- node_type_init(&ntype, blender::nodes::geo_node_attribute_capture_init);
- node_type_update(&ntype, blender::nodes::geo_node_attribute_capture_update);
- ntype.declare = blender::nodes::geo_node_attribute_capture_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_capture_exec;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_capture_layout;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.gather_link_search_ops = file_ns::node_gather_link_searches;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc
new file mode 100644
index 00000000000..d6662e4e637
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc
@@ -0,0 +1,155 @@
+/*
+ * 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 "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_attribute_domain_size_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>("Geometry");
+ b.add_output<decl::Int>("Point Count").make_available([](bNode &node) {
+ node.custom1 = GEO_COMPONENT_TYPE_MESH;
+ });
+ b.add_output<decl::Int>("Edge Count").make_available([](bNode &node) {
+ node.custom1 = GEO_COMPONENT_TYPE_MESH;
+ });
+ b.add_output<decl::Int>("Face Count").make_available([](bNode &node) {
+ node.custom1 = GEO_COMPONENT_TYPE_MESH;
+ });
+ b.add_output<decl::Int>("Face Corner Count").make_available([](bNode &node) {
+ node.custom1 = GEO_COMPONENT_TYPE_MESH;
+ });
+ b.add_output<decl::Int>("Spline Count").make_available([](bNode &node) {
+ node.custom1 = GEO_COMPONENT_TYPE_CURVE;
+ });
+ b.add_output<decl::Int>("Instance Count").make_available([](bNode &node) {
+ node.custom1 = GEO_COMPONENT_TYPE_INSTANCES;
+ });
+}
+
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "component", 0, "", ICON_NONE);
+}
+
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ node->custom1 = GEO_COMPONENT_TYPE_MESH;
+}
+
+static void node_update(bNodeTree *ntree, bNode *node)
+{
+ bNodeSocket *point_socket = (bNodeSocket *)node->outputs.first;
+ bNodeSocket *edge_socket = point_socket->next;
+ bNodeSocket *face_socket = edge_socket->next;
+ bNodeSocket *face_corner_socket = face_socket->next;
+ bNodeSocket *spline_socket = face_corner_socket->next;
+ bNodeSocket *instances_socket = spline_socket->next;
+
+ nodeSetSocketAvailability(ntree,
+ point_socket,
+ ELEM(node->custom1,
+ GEO_COMPONENT_TYPE_MESH,
+ GEO_COMPONENT_TYPE_CURVE,
+ GEO_COMPONENT_TYPE_POINT_CLOUD));
+ nodeSetSocketAvailability(ntree, edge_socket, node->custom1 == GEO_COMPONENT_TYPE_MESH);
+ nodeSetSocketAvailability(ntree, face_socket, node->custom1 == GEO_COMPONENT_TYPE_MESH);
+ nodeSetSocketAvailability(ntree, face_corner_socket, node->custom1 == GEO_COMPONENT_TYPE_MESH);
+ nodeSetSocketAvailability(ntree, spline_socket, node->custom1 == GEO_COMPONENT_TYPE_CURVE);
+ nodeSetSocketAvailability(
+ ntree, instances_socket, node->custom1 == GEO_COMPONENT_TYPE_INSTANCES);
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ GeometryComponentType component = (GeometryComponentType)params.node().custom1;
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+
+ switch (component) {
+ case GEO_COMPONENT_TYPE_MESH: {
+ if (geometry_set.has_mesh()) {
+ const MeshComponent *component = geometry_set.get_component_for_read<MeshComponent>();
+ params.set_output("Point Count", component->attribute_domain_size(ATTR_DOMAIN_POINT));
+ params.set_output("Edge Count", component->attribute_domain_size(ATTR_DOMAIN_EDGE));
+ params.set_output("Face Count", component->attribute_domain_size(ATTR_DOMAIN_FACE));
+ params.set_output("Face Corner Count",
+ component->attribute_domain_size(ATTR_DOMAIN_CORNER));
+ }
+ else {
+ params.set_default_remaining_outputs();
+ }
+ break;
+ }
+ case GEO_COMPONENT_TYPE_CURVE: {
+ if (geometry_set.has_curve()) {
+ const CurveComponent *component = geometry_set.get_component_for_read<CurveComponent>();
+ params.set_output("Point Count", component->attribute_domain_size(ATTR_DOMAIN_POINT));
+ params.set_output("Spline Count", component->attribute_domain_size(ATTR_DOMAIN_CURVE));
+ }
+ else {
+ params.set_default_remaining_outputs();
+ }
+ break;
+ }
+ case GEO_COMPONENT_TYPE_POINT_CLOUD: {
+ if (geometry_set.has_pointcloud()) {
+ const PointCloudComponent *component =
+ geometry_set.get_component_for_read<PointCloudComponent>();
+ params.set_output("Point Count", component->attribute_domain_size(ATTR_DOMAIN_POINT));
+ }
+ else {
+ params.set_default_remaining_outputs();
+ }
+ break;
+ }
+ case GEO_COMPONENT_TYPE_INSTANCES: {
+ if (geometry_set.has_instances()) {
+ const InstancesComponent *component =
+ geometry_set.get_component_for_read<InstancesComponent>();
+ params.set_output("Instance Count",
+ component->attribute_domain_size(ATTR_DOMAIN_INSTANCE));
+ }
+ else {
+ params.set_default_remaining_outputs();
+ }
+ break;
+ }
+ default:
+ BLI_assert_unreachable();
+ }
+}
+
+} // namespace blender::nodes::node_geo_attribute_domain_size_cc
+
+void register_node_type_geo_attribute_domain_size()
+{
+ namespace file_ns = blender::nodes::node_geo_attribute_domain_size_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(
+ &ntype, GEO_NODE_ATTRIBUTE_DOMAIN_SIZE, "Domain Size", NODE_CLASS_ATTRIBUTE, 0);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_layout;
+ node_type_init(&ntype, file_ns::node_init);
+ ntype.updatefunc = file_ns::node_update;
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc
index f80b8ccc971..6f26b2c756b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc
@@ -16,9 +16,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_attribute_remove_cc {
-static void geo_node_attribute_remove_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::String>(N_("Attribute")).multi_input();
@@ -42,7 +42,7 @@ static void remove_attribute(GeometryComponent &component,
}
}
-static void geo_node_attribute_remove_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
Vector<std::string> attribute_names = params.extract_multi_input<std::string>("Attribute");
@@ -66,15 +66,17 @@ static void geo_node_attribute_remove_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_attribute_remove_cc
void register_node_type_geo_attribute_remove()
{
+ namespace file_ns = blender::nodes::node_geo_attribute_remove_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_ATTRIBUTE_REMOVE, "Attribute Remove", NODE_CLASS_ATTRIBUTE, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_remove_exec;
- ntype.declare = blender::nodes::geo_node_attribute_remove_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc
index d9513332078..b79125d43d1 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc
@@ -22,13 +22,16 @@
#include "BLI_math_base_safe.h"
+#include "NOD_socket_search_link.hh"
+
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_attribute_statistic_cc {
-static void geo_node_attribute_statistic_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).supports_field().hide_value();
b.add_input<decl::Float>(N_("Attribute")).hide_value().supports_field();
b.add_input<decl::Vector>(N_("Attribute"), "Attribute_001").hide_value().supports_field();
@@ -51,24 +54,23 @@ static void geo_node_attribute_statistic_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Vector>(N_("Variance"), "Variance_001");
}
-static void geo_node_attribute_statistic_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
uiItemR(layout, ptr, "domain", 0, "", ICON_NONE);
}
-static void geo_node_attribute_statistic_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
node->custom1 = CD_PROP_FLOAT;
node->custom2 = ATTR_DOMAIN_POINT;
}
-static void geo_node_attribute_statistic_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
bNodeSocket *socket_geo = (bNodeSocket *)node->inputs.first;
- bNodeSocket *socket_float_attr = socket_geo->next;
+ bNodeSocket *socket_selection = socket_geo->next;
+ bNodeSocket *socket_float_attr = socket_selection->next;
bNodeSocket *socket_float3_attr = socket_float_attr->next;
bNodeSocket *socket_float_mean = (bNodeSocket *)node->outputs.first;
@@ -112,6 +114,54 @@ static void geo_node_attribute_statistic_update(bNodeTree *ntree, bNode *node)
nodeSetSocketAvailability(ntree, socket_vector_variance, data_type == CD_PROP_FLOAT3);
}
+static std::optional<CustomDataType> node_type_from_other_socket(const bNodeSocket &socket)
+{
+ switch (socket.type) {
+ case SOCK_FLOAT:
+ case SOCK_BOOLEAN:
+ case SOCK_INT:
+ return CD_PROP_FLOAT;
+ case SOCK_VECTOR:
+ case SOCK_RGBA:
+ return CD_PROP_FLOAT3;
+ default:
+ return {};
+ }
+}
+
+static void node_gather_link_searches(GatherLinkSearchOpParams &params)
+{
+ const bNodeType &node_type = params.node_type();
+ const std::optional<CustomDataType> type = node_type_from_other_socket(params.other_socket());
+ if (params.in_out() == SOCK_IN) {
+ if (params.other_socket().type == SOCK_GEOMETRY) {
+ params.add_item(IFACE_("Geometry"), [node_type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node(node_type);
+ params.connect_available_socket(node, "Geometry");
+ });
+ }
+ if (type) {
+ params.add_item(IFACE_("Attribute"), [&](LinkSearchOpParams &params) {
+ bNode &node = params.add_node(node_type);
+ node.custom1 = *type;
+ params.update_and_connect_available_socket(node, "Attribute");
+ });
+ }
+ }
+ else if (type) {
+ /* Only use the first 8 declarations since we set the type automatically. */
+ const NodeDeclaration &declaration = *params.node_type().fixed_declaration;
+ for (const SocketDeclarationPtr &socket_decl : declaration.outputs().take_front(8)) {
+ StringRefNull name = socket_decl->name();
+ params.add_item(IFACE_(name.c_str()), [node_type, name, type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node(node_type);
+ node.custom1 = *type;
+ params.update_and_connect_available_socket(node, name);
+ });
+ }
+ }
+}
+
template<typename T> static T compute_sum(const Span<T> data)
{
return std::accumulate(data.begin(), data.end(), T());
@@ -146,65 +196,40 @@ static float median_of_sorted_span(const Span<float> data)
}
return median;
}
-static void set_empty(CustomDataType data_type, GeoNodeExecParams &params)
-{
- if (data_type == CD_PROP_FLOAT) {
- params.set_output("Mean", 0.0f);
- params.set_output("Median", 0.0f);
- params.set_output("Sum", 0.0f);
- params.set_output("Min", 0.0f);
- params.set_output("Max", 0.0f);
- params.set_output("Range", 0.0f);
- params.set_output("Standard Deviation", 0.0f);
- params.set_output("Variance", 0.0f);
- }
- else if (data_type == CD_PROP_FLOAT3) {
- params.set_output("Mean_001", float3{0.0f, 0.0f, 0.0f});
- params.set_output("Median_001", float3{0.0f, 0.0f, 0.0f});
- params.set_output("Sum_001", float3{0.0f, 0.0f, 0.0f});
- params.set_output("Min_001", float3{0.0f, 0.0f, 0.0f});
- params.set_output("Max_001", float3{0.0f, 0.0f, 0.0f});
- params.set_output("Range_001", float3{0.0f, 0.0f, 0.0f});
- params.set_output("Standard Deviation_001", float3{0.0f, 0.0f, 0.0f});
- params.set_output("Variance_001", float3{0.0f, 0.0f, 0.0f});
- }
-}
-static void geo_node_attribute_statistic_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.get_input<GeometrySet>("Geometry");
-
const bNode &node = params.node();
const CustomDataType data_type = static_cast<CustomDataType>(node.custom1);
const AttributeDomain domain = static_cast<AttributeDomain>(node.custom2);
-
- int64_t total_size = 0;
Vector<const GeometryComponent *> components = geometry_set.get_components_for_read();
- for (const GeometryComponent *component : components) {
- if (component->attribute_domain_supported(domain)) {
- total_size += component->attribute_domain_size(domain);
- }
- }
- if (total_size == 0) {
- set_empty(data_type, params);
- return;
- }
+ const Field<bool> selection_field = params.get_input<Field<bool>>("Selection");
switch (data_type) {
case CD_PROP_FLOAT: {
const Field<float> input_field = params.get_input<Field<float>>("Attribute");
- Array<float> data = Array<float>(total_size);
- int offset = 0;
+ Vector<float> data;
for (const GeometryComponent *component : components) {
if (component->attribute_domain_supported(domain)) {
GeometryComponentFieldContext field_context{*component, domain};
const int domain_size = component->attribute_domain_size(domain);
+
fn::FieldEvaluator data_evaluator{field_context, domain_size};
- MutableSpan<float> component_result = data.as_mutable_span().slice(offset, domain_size);
- data_evaluator.add_with_destination(input_field, component_result);
+ data_evaluator.add(input_field);
+ data_evaluator.set_selection(selection_field);
data_evaluator.evaluate();
- offset += domain_size;
+ const VArray<float> &component_data = data_evaluator.get_evaluated<float>(0);
+ const IndexMask selection = data_evaluator.get_evaluated_selection_as_mask();
+
+ const int next_data_index = data.size();
+ data.resize(next_data_index + selection.size());
+ MutableSpan<float> selected_data = data.as_mutable_span().slice(next_data_index,
+ selection.size());
+ for (const int i : selection.index_range()) {
+ selected_data[i] = component_data[selection[i]];
+ }
}
}
@@ -225,7 +250,7 @@ static void geo_node_attribute_statistic_exec(GeoNodeExecParams params)
const bool variance_required = params.output_is_required("Standard Deviation") ||
params.output_is_required("Variance");
- if (total_size != 0) {
+ if (data.size() != 0) {
if (sort_required) {
std::sort(data.begin(), data.end());
median = median_of_sorted_span(data);
@@ -236,7 +261,7 @@ static void geo_node_attribute_statistic_exec(GeoNodeExecParams params)
}
if (sum_required || variance_required) {
sum = compute_sum<float>(data);
- mean = sum / total_size;
+ mean = sum / data.size();
if (variance_required) {
variance = compute_variance(data, mean);
@@ -263,18 +288,26 @@ static void geo_node_attribute_statistic_exec(GeoNodeExecParams params)
}
case CD_PROP_FLOAT3: {
const Field<float3> input_field = params.get_input<Field<float3>>("Attribute_001");
-
- Array<float3> data = Array<float3>(total_size);
- int offset = 0;
+ Vector<float3> data;
for (const GeometryComponent *component : components) {
if (component->attribute_domain_supported(domain)) {
GeometryComponentFieldContext field_context{*component, domain};
const int domain_size = component->attribute_domain_size(domain);
+
fn::FieldEvaluator data_evaluator{field_context, domain_size};
- MutableSpan<float3> component_result = data.as_mutable_span().slice(offset, domain_size);
- data_evaluator.add_with_destination(input_field, component_result);
+ data_evaluator.add(input_field);
+ data_evaluator.set_selection(selection_field);
data_evaluator.evaluate();
- offset += domain_size;
+ const VArray<float3> &component_data = data_evaluator.get_evaluated<float3>(0);
+ const IndexMask selection = data_evaluator.get_evaluated_selection_as_mask();
+
+ const int next_data_index = data.size();
+ data.resize(data.size() + selection.size());
+ MutableSpan<float3> selected_data = data.as_mutable_span().slice(next_data_index,
+ selection.size());
+ for (const int i : selection.index_range()) {
+ selected_data[i] = component_data[selection[i]];
+ }
}
}
@@ -299,9 +332,9 @@ static void geo_node_attribute_statistic_exec(GeoNodeExecParams params)
Array<float> data_y;
Array<float> data_z;
if (sort_required || variance_required) {
- data_x.reinitialize(total_size);
- data_y.reinitialize(total_size);
- data_z.reinitialize(total_size);
+ data_x.reinitialize(data.size());
+ data_y.reinitialize(data.size());
+ data_z.reinitialize(data.size());
for (const int i : data.index_range()) {
data_x[i] = data[i].x;
data_y[i] = data[i].y;
@@ -309,7 +342,7 @@ static void geo_node_attribute_statistic_exec(GeoNodeExecParams params)
}
}
- if (total_size != 0) {
+ if (data.size() != 0) {
if (sort_required) {
std::sort(data_x.begin(), data_x.end());
std::sort(data_y.begin(), data_y.end());
@@ -326,7 +359,7 @@ static void geo_node_attribute_statistic_exec(GeoNodeExecParams params)
}
if (sum_required || variance_required) {
sum = compute_sum(data.as_span());
- mean = sum / total_size;
+ mean = sum / data.size();
if (variance_required) {
const float x_variance = compute_variance(data_x, mean.x);
@@ -360,19 +393,22 @@ static void geo_node_attribute_statistic_exec(GeoNodeExecParams params)
}
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_attribute_statistic_cc
void register_node_type_geo_attribute_statistic()
{
+ namespace file_ns = blender::nodes::node_geo_attribute_statistic_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_ATTRIBUTE_STATISTIC, "Attribute Statistic", NODE_CLASS_ATTRIBUTE, 0);
- ntype.declare = blender::nodes::geo_node_attribute_statistic_declare;
- node_type_init(&ntype, blender::nodes::geo_node_attribute_statistic_init);
- node_type_update(&ntype, blender::nodes::geo_node_attribute_statistic_update);
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_statistic_exec;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_statistic_layout;
+ ntype.declare = file_ns::node_declare;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.gather_link_search_ops = file_ns::node_gather_link_searches;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
index dba051fe13d..0947632cc09 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
@@ -23,9 +23,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_boolean_cc {
-static void geo_node_boolean_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Mesh 1"))
.only_realized_data()
@@ -36,12 +36,12 @@ static void geo_node_boolean_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Mesh"));
}
-static void geo_node_boolean_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "operation", 0, "", ICON_NONE);
}
-static void geo_node_boolean_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
GeometryNodeBooleanOperation operation = (GeometryNodeBooleanOperation)node->custom1;
@@ -63,12 +63,12 @@ static void geo_node_boolean_update(bNodeTree *ntree, bNode *node)
}
}
-static void geo_node_boolean_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
node->custom1 = GEO_NODE_BOOLEAN_DIFFERENCE;
}
-static void geo_node_boolean_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometryNodeBooleanOperation operation = (GeometryNodeBooleanOperation)params.node().custom1;
const bool use_self = params.get_input<bool>("Self Intersection");
@@ -119,17 +119,19 @@ static void geo_node_boolean_exec(GeoNodeExecParams params)
params.set_output("Mesh", GeometrySet::create_with_mesh(result));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_boolean_cc
void register_node_type_geo_boolean()
{
+ namespace file_ns = blender::nodes::node_geo_boolean_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_MESH_BOOLEAN, "Mesh Boolean", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_boolean_declare;
- ntype.draw_buttons = blender::nodes::geo_node_boolean_layout;
- ntype.updatefunc = blender::nodes::geo_node_boolean_update;
- node_type_init(&ntype, blender::nodes::geo_node_boolean_init);
- ntype.geometry_node_execute = blender::nodes::geo_node_boolean_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.updatefunc = file_ns::node_update;
+ node_type_init(&ntype, file_ns::node_init);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc b/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc
index e7c9715934a..da1f9a00c69 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc
@@ -16,9 +16,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_bounding_box_cc {
-static void geo_node_bounding_box_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_output<decl::Geometry>(N_("Bounding Box"));
@@ -26,7 +26,7 @@ static void geo_node_bounding_box_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Vector>(N_("Max"));
}
-static void geo_node_bounding_box_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
@@ -78,14 +78,16 @@ static void geo_node_bounding_box_exec(GeoNodeExecParams params)
}
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_bounding_box_cc
void register_node_type_geo_bounding_box()
{
+ namespace file_ns = blender::nodes::node_geo_bounding_box_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_BOUNDING_BOX, "Bounding Box", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_bounding_box_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_bounding_box_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc b/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc
index 503711fedfe..6b8c895879d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc
@@ -27,9 +27,11 @@
#include <algorithm>
-namespace blender::nodes {
+namespace blender::nodes::node_geo_collection_info_cc {
-static void geo_node_collection_info_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryCollectionInfo)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Collection>(N_("Collection")).hide_label();
b.add_input<decl::Bool>(N_("Separate Children"))
@@ -42,12 +44,12 @@ static void geo_node_collection_info_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_collection_info_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "transform_space", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
}
-static void geo_node_collection_info_node_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryCollectionInfo *data = (NodeGeometryCollectionInfo *)MEM_callocN(
sizeof(NodeGeometryCollectionInfo), __func__);
@@ -61,14 +63,12 @@ struct InstanceListEntry {
float4x4 transform;
};
-static void geo_node_collection_info_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Collection *collection = params.get_input<Collection *>("Collection");
- GeometrySet geometry_set_out;
-
if (collection == nullptr) {
- params.set_output("Geometry", geometry_set_out);
+ params.set_default_remaining_outputs();
return;
}
const Object *self_object = params.self_object();
@@ -76,15 +76,15 @@ static void geo_node_collection_info_exec(GeoNodeExecParams params)
(Object *)self_object);
if (is_recursive) {
params.error_message_add(NodeWarningType::Error, "Collection contains current object");
- params.set_output("Geometry", geometry_set_out);
+ params.set_default_remaining_outputs();
return;
}
- const bNode &bnode = params.node();
- NodeGeometryCollectionInfo *node_storage = (NodeGeometryCollectionInfo *)bnode.storage;
- const bool use_relative_transform = (node_storage->transform_space ==
+ const NodeGeometryCollectionInfo &storage = node_storage(params.node());
+ const bool use_relative_transform = (storage.transform_space ==
GEO_NODE_TRANSFORM_SPACE_RELATIVE);
+ GeometrySet geometry_set_out;
InstancesComponent &instances = geometry_set_out.get_component_for_write<InstancesComponent>();
const bool separate_children = params.get_input<bool>("Separate Children");
@@ -155,20 +155,22 @@ static void geo_node_collection_info_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set_out);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_collection_info_cc
void register_node_type_geo_collection_info()
{
+ namespace file_ns = blender::nodes::node_geo_collection_info_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_COLLECTION_INFO, "Collection Info", NODE_CLASS_INPUT, 0);
- ntype.declare = blender::nodes::geo_node_collection_info_declare;
- node_type_init(&ntype, blender::nodes::geo_node_collection_info_node_init);
+ ntype.declare = file_ns::node_declare;
+ node_type_init(&ntype, file_ns::node_node_init);
node_type_storage(&ntype,
"NodeGeometryCollectionInfo",
node_free_standard_storage,
node_copy_standard_storage);
- ntype.geometry_node_execute = blender::nodes::geo_node_collection_info_exec;
- ntype.draw_buttons = blender::nodes::geo_node_collection_info_layout;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_common.cc b/source/blender/nodes/geometry/nodes/node_geo_common.cc
index 9ebbdd349de..64b7a80bdb4 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_common.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_common.cc
@@ -22,7 +22,7 @@
#include "node_common.h"
#include "node_geometry_util.hh"
-void register_node_type_geo_group(void)
+void register_node_type_geo_group()
{
static bNodeType ntype;
@@ -37,7 +37,7 @@ void register_node_type_geo_group(void)
node_type_socket_templates(&ntype, nullptr, nullptr);
node_type_size(&ntype, 140, 60, 400);
- node_type_label(&ntype, node_group_label);
+ ntype.labelfunc = node_group_label;
node_type_group_update(&ntype, node_group_update);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc
index 221fb421ab4..56c1e95bd70 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc
@@ -28,9 +28,9 @@
# include "RBI_hull_api.h"
#endif
-namespace blender::nodes {
+namespace blender::nodes::node_geo_convex_hull_cc {
-static void geo_node_convex_hull_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_output<decl::Geometry>(N_("Convex Hull"));
@@ -296,7 +296,7 @@ static Mesh *convex_hull_from_instances(const GeometrySet &geometry_set)
#endif /* WITH_BULLET */
-static void geo_node_convex_hull_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
@@ -312,18 +312,20 @@ static void geo_node_convex_hull_exec(GeoNodeExecParams params)
#else
params.error_message_add(NodeWarningType::Error,
TIP_("Disabled, Blender was compiled without Bullet"));
- params.set_output("Convex Hull", geometry_set);
+ params.set_default_remaining_outputs();
#endif /* WITH_BULLET */
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_convex_hull_cc
void register_node_type_geo_convex_hull()
{
+ namespace file_ns = blender::nodes::node_geo_convex_hull_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_CONVEX_HULL, "Convex Hull", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_convex_hull_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_convex_hull_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc
index c41b76412e9..fc407414667 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc
@@ -21,9 +21,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_endpoint_select_cc {
-static void geo_node_curve_endpoint_selection_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Int>(N_("Start Size"))
.min(0)
@@ -51,69 +51,61 @@ static void select_by_spline(const int start, const int end, MutableSpan<bool> r
r_selection.slice(size - end_use, end_use).fill(true);
}
-class EndpointFieldInput final : public fn::FieldInput {
+class EndpointFieldInput final : public GeometryFieldInput {
Field<int> start_size_;
Field<int> end_size_;
public:
EndpointFieldInput(Field<int> start_size, Field<int> end_size)
- : FieldInput(CPPType::get<bool>(), "Endpoint Selection node"),
+ : GeometryFieldInput(CPPType::get<bool>(), "Endpoint Selection node"),
start_size_(start_size),
end_size_(end_size)
{
category_ = Category::Generated;
}
- GVArray get_varray_for_context(const fn::FieldContext &context,
- IndexMask UNUSED(mask),
- ResourceScope &UNUSED(scope)) const final
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
{
- if (const GeometryComponentFieldContext *geometry_context =
- dynamic_cast<const GeometryComponentFieldContext *>(&context)) {
+ if (component.type() != GEO_COMPONENT_TYPE_CURVE || domain != ATTR_DOMAIN_POINT) {
+ return nullptr;
+ }
- const GeometryComponent &component = geometry_context->geometry_component();
- const AttributeDomain domain = geometry_context->domain();
- if (component.type() != GEO_COMPONENT_TYPE_CURVE || domain != ATTR_DOMAIN_POINT) {
- return nullptr;
- }
+ const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
+ const CurveEval *curve = curve_component.get_for_read();
- const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
- const CurveEval *curve = curve_component.get_for_read();
+ Array<int> control_point_offsets = curve->control_point_offsets();
- Array<int> control_point_offsets = curve->control_point_offsets();
+ if (curve == nullptr || control_point_offsets.last() == 0) {
+ return nullptr;
+ }
- if (curve == nullptr || control_point_offsets.last() == 0) {
- return nullptr;
+ GeometryComponentFieldContext size_context{curve_component, ATTR_DOMAIN_CURVE};
+ fn::FieldEvaluator evaluator{size_context, curve->splines().size()};
+ evaluator.add(start_size_);
+ evaluator.add(end_size_);
+ evaluator.evaluate();
+ const VArray<int> &start_size = evaluator.get_evaluated<int>(0);
+ const VArray<int> &end_size = evaluator.get_evaluated<int>(1);
+
+ const int point_size = control_point_offsets.last();
+ Array<bool> selection(point_size, false);
+ int current_point = 0;
+ MutableSpan<bool> selection_span = selection.as_mutable_span();
+ for (int i : IndexRange(curve->splines().size())) {
+ const SplinePtr &spline = curve->splines()[i];
+ if (start_size[i] <= 0 && end_size[i] <= 0) {
+ selection_span.slice(current_point, spline->size()).fill(false);
}
-
- GeometryComponentFieldContext size_context{curve_component, ATTR_DOMAIN_CURVE};
- fn::FieldEvaluator evaluator{size_context, curve->splines().size()};
- evaluator.add(start_size_);
- evaluator.add(end_size_);
- evaluator.evaluate();
- const VArray<int> &start_size = evaluator.get_evaluated<int>(0);
- const VArray<int> &end_size = evaluator.get_evaluated<int>(1);
-
- const int point_size = control_point_offsets.last();
- Array<bool> selection(point_size, false);
- int current_point = 0;
- MutableSpan<bool> selection_span = selection.as_mutable_span();
- for (int i : IndexRange(curve->splines().size())) {
- const SplinePtr &spline = curve->splines()[i];
- if (start_size[i] <= 0 && end_size[i] <= 0) {
- selection_span.slice(current_point, spline->size()).fill(false);
- }
- else {
- int start_use = std::max(start_size[i], 0);
- int end_use = std::max(end_size[i], 0);
- select_by_spline(
- start_use, end_use, selection_span.slice(current_point, spline->size()));
- }
- current_point += spline->size();
+ else {
+ int start_use = std::max(start_size[i], 0);
+ int end_use = std::max(end_size[i], 0);
+ select_by_spline(start_use, end_use, selection_span.slice(current_point, spline->size()));
}
- return VArray<bool>::ForContainer(std::move(selection));
+ current_point += spline->size();
}
- return {};
+ return VArray<bool>::ForContainer(std::move(selection));
};
uint64_t hash() const override
@@ -131,23 +123,25 @@ class EndpointFieldInput final : public fn::FieldInput {
}
};
-static void geo_node_curve_endpoint_selection_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Field<int> start_size = params.extract_input<Field<int>>("Start Size");
Field<int> end_size = params.extract_input<Field<int>>("End Size");
Field<bool> selection_field{std::make_shared<EndpointFieldInput>(start_size, end_size)};
params.set_output("Selection", std::move(selection_field));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_endpoint_select_cc
void register_node_type_geo_curve_endpoint_selection()
{
+ namespace file_ns = blender::nodes::node_geo_curve_endpoint_select_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_CURVE_ENDPOINT_SELECTION, "Endpoint Selection", NODE_CLASS_INPUT, 0);
- ntype.declare = blender::nodes::geo_node_curve_endpoint_selection_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_endpoint_selection_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc
index 219effadec4..3aabf8e21eb 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc
@@ -31,20 +31,22 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_fill_cc {
-static void geo_node_curve_fill_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryCurveFill)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
b.add_output<decl::Geometry>(N_("Mesh"));
}
-static void geo_node_curve_fill_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
}
-static void geo_node_curve_fill_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeGeometryCurveFill *data = (NodeGeometryCurveFill *)MEM_callocN(sizeof(NodeGeometryCurveFill),
__func__);
@@ -147,11 +149,11 @@ static void curve_fill_calculate(GeometrySet &geometry_set, const GeometryNodeCu
geometry_set.replace_curve(nullptr);
}
-static void geo_node_curve_fill_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
- const NodeGeometryCurveFill &storage = *(const NodeGeometryCurveFill *)params.node().storage;
+ const NodeGeometryCurveFill &storage = node_storage(params.node());
const GeometryNodeCurveFillMode mode = (GeometryNodeCurveFillMode)storage.mode;
geometry_set.modify_geometry_sets(
@@ -160,19 +162,21 @@ static void geo_node_curve_fill_exec(GeoNodeExecParams params)
params.set_output("Mesh", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_fill_cc
void register_node_type_geo_curve_fill()
{
+ namespace file_ns = blender::nodes::node_geo_curve_fill_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_FILL_CURVE, "Fill Curve", NODE_CLASS_GEOMETRY, 0);
- node_type_init(&ntype, blender::nodes::geo_node_curve_fill_init);
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(
&ntype, "NodeGeometryCurveFill", node_free_standard_storage, node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_curve_fill_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_fill_exec;
- ntype.draw_buttons = blender::nodes::geo_node_curve_fill_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc
index a320f35c539..a438c1d6086 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc
@@ -25,12 +25,19 @@
#include "BKE_spline.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_fillet_cc {
-static void geo_node_curve_fillet_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryCurveFillet)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
- b.add_input<decl::Int>(N_("Count")).default_value(1).min(1).max(1000).supports_field();
+ b.add_input<decl::Int>(N_("Count"))
+ .default_value(1)
+ .min(1)
+ .max(1000)
+ .supports_field()
+ .make_available([](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_FILLET_POLY; });
b.add_input<decl::Float>(N_("Radius"))
.min(0.0f)
.max(FLT_MAX)
@@ -41,12 +48,12 @@ static void geo_node_curve_fillet_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Curve"));
}
-static void geo_node_curve_fillet_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
}
-static void geo_node_curve_fillet_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryCurveFillet *data = (NodeGeometryCurveFillet *)MEM_callocN(
sizeof(NodeGeometryCurveFillet), __func__);
@@ -76,10 +83,10 @@ struct FilletData {
Array<int> counts;
};
-static void geo_node_curve_fillet_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
- NodeGeometryCurveFillet &node_storage = *(NodeGeometryCurveFillet *)node->storage;
- const GeometryNodeCurveFilletMode mode = (GeometryNodeCurveFilletMode)node_storage.mode;
+ const NodeGeometryCurveFillet &storage = node_storage(*node);
+ const GeometryNodeCurveFilletMode mode = (GeometryNodeCurveFilletMode)storage.mode;
bNodeSocket *poly_socket = ((bNodeSocket *)node->inputs.first)->next;
@@ -332,14 +339,17 @@ static void copy_common_attributes_by_mapping(const Spline &src,
copy_attribute_by_mapping(src.radii(), dst.radii(), mapping);
copy_attribute_by_mapping(src.tilts(), dst.tilts(), mapping);
- dst.attributes.reallocate(1);
src.attributes.foreach_attribute(
[&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
std::optional<GSpan> src_attribute = src.attributes.get_for_read(attribute_id);
if (dst.attributes.create(attribute_id, meta_data.data_type)) {
std::optional<GMutableSpan> dst_attribute = dst.attributes.get_for_write(attribute_id);
if (dst_attribute) {
- src_attribute->type().copy_assign(src_attribute->data(), dst_attribute->data());
+ attribute_math::convert_to_static_type(dst_attribute->type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ copy_attribute_by_mapping(
+ src_attribute->typed<T>(), dst_attribute->typed<T>(), mapping);
+ });
return true;
}
}
@@ -607,12 +617,12 @@ static void calculate_curve_fillet(GeometrySet &geometry_set,
geometry_set.replace_curve(output_curve.release());
}
-static void geo_node_fillet_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
- NodeGeometryCurveFillet &node_storage = *(NodeGeometryCurveFillet *)params.node().storage;
- const GeometryNodeCurveFilletMode mode = (GeometryNodeCurveFilletMode)node_storage.mode;
+ const NodeGeometryCurveFillet &storage = node_storage(params.node());
+ const GeometryNodeCurveFilletMode mode = (GeometryNodeCurveFilletMode)storage.mode;
Field<float> radius_field = params.extract_input<Field<float>>("Radius");
const bool limit_radius = params.extract_input<bool>("Limit Radius");
@@ -629,19 +639,21 @@ static void geo_node_fillet_exec(GeoNodeExecParams params)
params.set_output("Curve", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_fillet_cc
void register_node_type_geo_curve_fillet()
{
+ namespace file_ns = blender::nodes::node_geo_curve_fillet_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_FILLET_CURVE, "Fillet Curve", NODE_CLASS_GEOMETRY, 0);
- ntype.draw_buttons = blender::nodes::geo_node_curve_fillet_layout;
+ ntype.draw_buttons = file_ns::node_layout;
node_type_storage(
&ntype, "NodeGeometryCurveFillet", node_free_standard_storage, node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_curve_fillet_declare;
- node_type_init(&ntype, blender::nodes::geo_node_curve_fillet_init);
- node_type_update(&ntype, blender::nodes::geo_node_curve_fillet_update);
- ntype.geometry_node_execute = blender::nodes::geo_node_fillet_exec;
+ ntype.declare = file_ns::node_declare;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc
index 5fb17270301..381bb0fc1d0 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc
@@ -21,22 +21,22 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_handle_type_selection_cc {
-static void geo_node_curve_handle_type_selection_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryCurveSelectHandles)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Bool>(N_("Selection")).field_source();
}
-static void geo_node_curve_handle_type_selection_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
uiItemR(layout, ptr, "handle_type", 0, "", ICON_NONE);
}
-static void geo_node_curve_handle_type_selection_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryCurveSelectHandles *data = (NodeGeometryCurveSelectHandles *)MEM_callocN(
sizeof(NodeGeometryCurveSelectHandles), __func__);
@@ -85,44 +85,40 @@ static void select_by_handle_type(const CurveEval &curve,
}
}
-class HandleTypeFieldInput final : public fn::FieldInput {
+class HandleTypeFieldInput final : public GeometryFieldInput {
BezierSpline::HandleType type_;
GeometryNodeCurveHandleMode mode_;
public:
HandleTypeFieldInput(BezierSpline::HandleType type, GeometryNodeCurveHandleMode mode)
- : FieldInput(CPPType::get<bool>(), "Handle Type Selection node"), type_(type), mode_(mode)
+ : GeometryFieldInput(CPPType::get<bool>(), "Handle Type Selection node"),
+ type_(type),
+ mode_(mode)
{
category_ = Category::Generated;
}
- GVArray get_varray_for_context(const fn::FieldContext &context,
- IndexMask mask,
- ResourceScope &UNUSED(scope)) const final
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask mask) const final
{
- if (const GeometryComponentFieldContext *geometry_context =
- dynamic_cast<const GeometryComponentFieldContext *>(&context)) {
-
- const GeometryComponent &component = geometry_context->geometry_component();
- const AttributeDomain domain = geometry_context->domain();
- if (component.type() != GEO_COMPONENT_TYPE_CURVE) {
- return {};
- }
+ if (component.type() != GEO_COMPONENT_TYPE_CURVE) {
+ return {};
+ }
- const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
- const CurveEval *curve = curve_component.get_for_read();
- if (curve == nullptr) {
- return {};
- }
+ const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
+ const CurveEval *curve = curve_component.get_for_read();
+ if (curve == nullptr) {
+ return {};
+ }
- if (domain == ATTR_DOMAIN_POINT) {
- Array<bool> selection(mask.min_array_size());
- select_by_handle_type(*curve, type_, mode_, selection);
- return VArray<bool>::ForContainer(std::move(selection));
- }
+ if (domain == ATTR_DOMAIN_POINT) {
+ Array<bool> selection(mask.min_array_size());
+ select_by_handle_type(*curve, type_, mode_, selection);
+ return VArray<bool>::ForContainer(std::move(selection));
}
return {};
- };
+ }
uint64_t hash() const override
{
@@ -140,34 +136,35 @@ class HandleTypeFieldInput final : public fn::FieldInput {
}
};
-static void geo_node_curve_handle_type_selection_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
- const NodeGeometryCurveSelectHandles *storage =
- (const NodeGeometryCurveSelectHandles *)params.node().storage;
+ const NodeGeometryCurveSelectHandles &storage = node_storage(params.node());
const BezierSpline::HandleType handle_type = handle_type_from_input_type(
- (GeometryNodeCurveHandleType)storage->handle_type);
- const GeometryNodeCurveHandleMode mode = (GeometryNodeCurveHandleMode)storage->mode;
+ (GeometryNodeCurveHandleType)storage.handle_type);
+ const GeometryNodeCurveHandleMode mode = (GeometryNodeCurveHandleMode)storage.mode;
Field<bool> selection_field{std::make_shared<HandleTypeFieldInput>(handle_type, mode)};
params.set_output("Selection", std::move(selection_field));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_handle_type_selection_cc
void register_node_type_geo_curve_handle_type_selection()
{
+ namespace file_ns = blender::nodes::node_geo_curve_handle_type_selection_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_CURVE_HANDLE_TYPE_SELECTION, "Handle Type Selection", NODE_CLASS_INPUT, 0);
- ntype.declare = blender::nodes::geo_node_curve_handle_type_selection_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_handle_type_selection_exec;
- node_type_init(&ntype, blender::nodes::geo_node_curve_handle_type_selection_init);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(&ntype,
"NodeGeometryCurveSelectHandles",
node_free_standard_storage,
node_copy_standard_storage);
- ntype.draw_buttons = blender::nodes::geo_node_curve_handle_type_selection_layout;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc
index 0d0dc0ec89c..73ad8a8cf65 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc
@@ -17,19 +17,19 @@
#include "BKE_spline.hh"
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_length_cc {
-static void geo_node_curve_length_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
b.add_output<decl::Float>(N_("Length"));
}
-static void geo_node_curve_length_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet curve_set = params.extract_input<GeometrySet>("Curve");
if (!curve_set.has_curve()) {
- params.set_output("Length", 0.0f);
+ params.set_default_remaining_outputs();
return;
}
const CurveEval &curve = *curve_set.get_curve_for_read();
@@ -40,14 +40,16 @@ static void geo_node_curve_length_exec(GeoNodeExecParams params)
params.set_output("Length", length);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_length_cc
void register_node_type_geo_curve_length()
{
+ namespace file_ns = blender::nodes::node_geo_curve_length_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_CURVE_LENGTH, "Curve Length", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_curve_length_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_length_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc
index 673a5095044..4299b5cc022 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc
@@ -21,9 +21,11 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_primitive_bezier_segment_cc {
-static void geo_node_curve_primitive_bezier_segment_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryCurvePrimitiveBezierSegment)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Int>(N_("Resolution"))
.default_value(16)
@@ -53,14 +55,12 @@ static void geo_node_curve_primitive_bezier_segment_declare(NodeDeclarationBuild
b.add_output<decl::Geometry>(N_("Curve"));
}
-static void geo_node_curve_primitive_bezier_segment_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
}
-static void geo_node_curve_primitive_bezier_segment_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryCurvePrimitiveBezierSegment *data = (NodeGeometryCurvePrimitiveBezierSegment *)
MEM_callocN(sizeof(NodeGeometryCurvePrimitiveBezierSegment), __func__);
@@ -120,12 +120,11 @@ static std::unique_ptr<CurveEval> create_bezier_segment_curve(
return curve;
}
-static void geo_node_curve_primitive_bezier_segment_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
- const NodeGeometryCurvePrimitiveBezierSegment *node_storage =
- (NodeGeometryCurvePrimitiveBezierSegment *)params.node().storage;
+ const NodeGeometryCurvePrimitiveBezierSegment &storage = node_storage(params.node());
const GeometryNodeCurvePrimitiveBezierSegmentMode mode =
- (const GeometryNodeCurvePrimitiveBezierSegmentMode)node_storage->mode;
+ (const GeometryNodeCurvePrimitiveBezierSegmentMode)storage.mode;
std::unique_ptr<CurveEval> curve = create_bezier_segment_curve(
params.extract_input<float3>("Start"),
@@ -137,20 +136,22 @@ static void geo_node_curve_primitive_bezier_segment_exec(GeoNodeExecParams param
params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_primitive_bezier_segment_cc
void register_node_type_geo_curve_primitive_bezier_segment()
{
+ namespace file_ns = blender::nodes::node_geo_curve_primitive_bezier_segment_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT, "Bezier Segment", NODE_CLASS_GEOMETRY, 0);
- node_type_init(&ntype, blender::nodes::geo_node_curve_primitive_bezier_segment_init);
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(&ntype,
"NodeGeometryCurvePrimitiveBezierSegment",
node_free_standard_storage,
node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_curve_primitive_bezier_segment_declare;
- ntype.draw_buttons = blender::nodes::geo_node_curve_primitive_bezier_segment_layout;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_primitive_bezier_segment_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc
index 5d8beb9c9d8..70abf4c64a7 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc
@@ -21,9 +21,11 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_primitive_circle_cc {
-static void geo_node_curve_primitive_circle_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryCurvePrimitiveCircle)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Int>(N_("Resolution"))
.default_value(32)
@@ -54,17 +56,17 @@ static void geo_node_curve_primitive_circle_declare(NodeDeclarationBuilder &b)
.subtype(PROP_DISTANCE)
.description(N_("Distance of the points from the origin"));
b.add_output<decl::Geometry>(N_("Curve"));
- b.add_output<decl::Vector>(N_("Center"));
+ b.add_output<decl::Vector>(N_("Center")).make_available([](bNode &node) {
+ node_storage(node).mode = GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS;
+ });
}
-static void geo_node_curve_primitive_circle_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
}
-static void geo_node_curve_primitive_circle_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryCurvePrimitiveCircle *data = (NodeGeometryCurvePrimitiveCircle *)MEM_callocN(
sizeof(NodeGeometryCurvePrimitiveCircle), __func__);
@@ -73,12 +75,11 @@ static void geo_node_curve_primitive_circle_init(bNodeTree *UNUSED(tree), bNode
node->storage = data;
}
-static void geo_node_curve_primitive_circle_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
- const NodeGeometryCurvePrimitiveCircle *node_storage = (NodeGeometryCurvePrimitiveCircle *)
- node->storage;
- const GeometryNodeCurvePrimitiveCircleMode mode = (const GeometryNodeCurvePrimitiveCircleMode)
- node_storage->mode;
+ const NodeGeometryCurvePrimitiveCircle &storage = node_storage(*node);
+ const GeometryNodeCurvePrimitiveCircleMode mode = (GeometryNodeCurvePrimitiveCircleMode)
+ storage.mode;
bNodeSocket *start_socket = ((bNodeSocket *)node->inputs.first)->next;
bNodeSocket *middle_socket = start_socket->next;
@@ -195,13 +196,11 @@ static std::unique_ptr<CurveEval> create_radius_circle_curve(const int resolutio
return curve;
}
-static void geo_node_curve_primitive_circle_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
- const NodeGeometryCurvePrimitiveCircle *node_storage =
- (NodeGeometryCurvePrimitiveCircle *)params.node().storage;
-
+ const NodeGeometryCurvePrimitiveCircle &storage = node_storage(params.node());
const GeometryNodeCurvePrimitiveCircleMode mode = (GeometryNodeCurvePrimitiveCircleMode)
- node_storage->mode;
+ storage.mode;
std::unique_ptr<CurveEval> curve;
if (mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS) {
@@ -222,26 +221,28 @@ static void geo_node_curve_primitive_circle_exec(GeoNodeExecParams params)
params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
}
else {
- params.set_output("Curve", GeometrySet());
+ params.set_default_remaining_outputs();
}
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_primitive_circle_cc
void register_node_type_geo_curve_primitive_circle()
{
+ namespace file_ns = blender::nodes::node_geo_curve_primitive_circle_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_CURVE_PRIMITIVE_CIRCLE, "Curve Circle", NODE_CLASS_GEOMETRY, 0);
- node_type_init(&ntype, blender::nodes::geo_node_curve_primitive_circle_init);
- node_type_update(&ntype, blender::nodes::geo_node_curve_primitive_circle_update);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(&ntype,
"NodeGeometryCurvePrimitiveCircle",
node_free_standard_storage,
node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_curve_primitive_circle_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_primitive_circle_exec;
- ntype.draw_buttons = blender::nodes::geo_node_curve_primitive_circle_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc
index 238fc77e1cc..6d71c97b15a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc
@@ -21,9 +21,11 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_primitive_line_cc {
-static void geo_node_curve_primitive_line_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryCurvePrimitiveLine)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Vector>(N_("Start"))
.subtype(PROP_TRANSLATION)
@@ -43,14 +45,12 @@ static void geo_node_curve_primitive_line_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Curve"));
}
-static void geo_node_curve_primitive_line_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
}
-static void geo_node_curve_primitive_line_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryCurvePrimitiveLine *data = (NodeGeometryCurvePrimitiveLine *)MEM_callocN(
sizeof(NodeGeometryCurvePrimitiveLine), __func__);
@@ -59,12 +59,10 @@ static void geo_node_curve_primitive_line_init(bNodeTree *UNUSED(tree), bNode *n
node->storage = data;
}
-static void geo_node_curve_primitive_line_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
- const NodeGeometryCurvePrimitiveLine *node_storage = (NodeGeometryCurvePrimitiveLine *)
- node->storage;
- const GeometryNodeCurvePrimitiveLineMode mode = (const GeometryNodeCurvePrimitiveLineMode)
- node_storage->mode;
+ const NodeGeometryCurvePrimitiveLine &storage = node_storage(*node);
+ const GeometryNodeCurvePrimitiveLineMode mode = (GeometryNodeCurvePrimitiveLineMode)storage.mode;
bNodeSocket *p2_socket = ((bNodeSocket *)node->inputs.first)->next;
bNodeSocket *direction_socket = p2_socket->next;
@@ -112,13 +110,10 @@ static std::unique_ptr<CurveEval> create_direction_line_curve(const float3 start
return curve;
}
-static void geo_node_curve_primitive_line_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
-
- const NodeGeometryCurvePrimitiveLine *node_storage =
- (NodeGeometryCurvePrimitiveLine *)params.node().storage;
-
- GeometryNodeCurvePrimitiveLineMode mode = (GeometryNodeCurvePrimitiveLineMode)node_storage->mode;
+ const NodeGeometryCurvePrimitiveLine &storage = node_storage(params.node());
+ const GeometryNodeCurvePrimitiveLineMode mode = (GeometryNodeCurvePrimitiveLineMode)storage.mode;
std::unique_ptr<CurveEval> curve;
if (mode == GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_POINTS) {
@@ -134,20 +129,22 @@ static void geo_node_curve_primitive_line_exec(GeoNodeExecParams params)
params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_primitive_line_cc
void register_node_type_geo_curve_primitive_line()
{
+ namespace file_ns = blender::nodes::node_geo_curve_primitive_line_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_LINE, "Curve Line", NODE_CLASS_GEOMETRY, 0);
- node_type_init(&ntype, blender::nodes::geo_node_curve_primitive_line_init);
- node_type_update(&ntype, blender::nodes::geo_node_curve_primitive_line_update);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(&ntype,
"NodeGeometryCurvePrimitiveLine",
node_free_standard_storage,
node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_curve_primitive_line_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_primitive_line_exec;
- ntype.draw_buttons = blender::nodes::geo_node_curve_primitive_line_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc
index 27bf4a310df..92a9b1b4966 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc
@@ -17,9 +17,9 @@
#include "BKE_spline.hh"
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_primitive_quadratic_bezier_cc {
-static void geo_node_curve_primitive_quadratic_bezier_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Int>(N_("Resolution"))
.default_value(16)
@@ -64,7 +64,7 @@ static std::unique_ptr<CurveEval> create_quadratic_bezier_curve(const float3 p1,
return curve;
}
-static void geo_node_curve_primitive_quadratic_bezier_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
std::unique_ptr<CurveEval> curve = create_quadratic_bezier_curve(
params.extract_input<float3>("Start"),
@@ -74,17 +74,19 @@ static void geo_node_curve_primitive_quadratic_bezier_exec(GeoNodeExecParams par
params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_primitive_quadratic_bezier_cc
void register_node_type_geo_curve_primitive_quadratic_bezier()
{
+ namespace file_ns = blender::nodes::node_geo_curve_primitive_quadratic_bezier_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype,
GEO_NODE_CURVE_PRIMITIVE_QUADRATIC_BEZIER,
"Quadratic Bezier",
NODE_CLASS_GEOMETRY,
0);
- ntype.declare = blender::nodes::geo_node_curve_primitive_quadratic_bezier_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_primitive_quadratic_bezier_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc
index 114ae441d99..ff6294b9b6b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc
@@ -17,11 +17,16 @@
#include "BKE_spline.hh"
#include "UI_interface.h"
#include "UI_resources.h"
+
+#include "NOD_socket_search_link.hh"
+
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_primitive_quadrilaterial_cc {
+
+NODE_STORAGE_FUNCS(NodeGeometryCurvePrimitiveQuad)
-static void geo_node_curve_primitive_quadrilateral_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Float>(N_("Width"))
.default_value(2.0f)
@@ -77,14 +82,12 @@ static void geo_node_curve_primitive_quadrilateral_declare(NodeDeclarationBuilde
b.add_output<decl::Geometry>(N_("Curve"));
}
-static void geo_node_curve_primitive_quadrilateral_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
}
-static void geo_node_curve_primitive_quadrilateral_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryCurvePrimitiveQuad *data = (NodeGeometryCurvePrimitiveQuad *)MEM_callocN(
sizeof(NodeGeometryCurvePrimitiveQuad), __func__);
@@ -92,11 +95,11 @@ static void geo_node_curve_primitive_quadrilateral_init(bNodeTree *UNUSED(tree),
node->storage = data;
}
-static void geo_node_curve_primitive_quadrilateral_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
- NodeGeometryCurvePrimitiveQuad &node_storage = *(NodeGeometryCurvePrimitiveQuad *)node->storage;
+ const NodeGeometryCurvePrimitiveQuad &storage = node_storage(*node);
GeometryNodeCurvePrimitiveQuadMode mode = static_cast<GeometryNodeCurvePrimitiveQuadMode>(
- node_storage.mode);
+ storage.mode);
bNodeSocket *width = ((bNodeSocket *)node->inputs.first);
bNodeSocket *height = width->next;
@@ -142,6 +145,41 @@ static void geo_node_curve_primitive_quadrilateral_update(bNodeTree *ntree, bNod
}
}
+class SocketSearchOp {
+ public:
+ std::string socket_name;
+ GeometryNodeCurvePrimitiveQuadMode quad_mode;
+ void operator()(LinkSearchOpParams &params)
+ {
+ bNode &node = params.add_node("GeometryNodeCurvePrimitiveQuadrilateral");
+ node_storage(node).mode = quad_mode;
+ params.update_and_connect_available_socket(node, socket_name);
+ }
+};
+
+static void node_gather_link_searches(GatherLinkSearchOpParams &params)
+{
+ const NodeDeclaration &declaration = *params.node_type().fixed_declaration;
+ if (params.in_out() == SOCK_OUT) {
+ search_link_ops_for_declarations(params, declaration.outputs());
+ }
+ else if (params.node_tree().typeinfo->validate_link(
+ static_cast<eNodeSocketDatatype>(params.other_socket().type), SOCK_FLOAT)) {
+ params.add_item(IFACE_("Width"),
+ SocketSearchOp{"Width", GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_RECTANGLE});
+ params.add_item(IFACE_("Height"),
+ SocketSearchOp{"Height", GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_RECTANGLE});
+ params.add_item(IFACE_("Bottom Width"),
+ SocketSearchOp{"Bottom Width", GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_TRAPEZOID});
+ params.add_item(IFACE_("Top Width"),
+ SocketSearchOp{"Top Width", GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_TRAPEZOID});
+ params.add_item(IFACE_("Offset"),
+ SocketSearchOp{"Offset", GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_PARALLELOGRAM});
+ params.add_item(IFACE_("Point 1"),
+ SocketSearchOp{"Point 1", GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_POINTS});
+ }
+}
+
static void create_rectangle_curve(MutableSpan<float3> positions,
const float height,
const float width)
@@ -197,12 +235,10 @@ static void create_kite_curve(MutableSpan<float3> positions,
positions[3] = float3(-width / 2.0f, 0, 0);
}
-static void geo_node_curve_primitive_quadrilateral_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
- const NodeGeometryCurvePrimitiveQuad &node_storage =
- *(NodeGeometryCurvePrimitiveQuad *)(params.node()).storage;
- const GeometryNodeCurvePrimitiveQuadMode mode = static_cast<GeometryNodeCurvePrimitiveQuadMode>(
- node_storage.mode);
+ const NodeGeometryCurvePrimitiveQuad &storage = node_storage(params.node());
+ const GeometryNodeCurvePrimitiveQuadMode mode = (GeometryNodeCurvePrimitiveQuadMode)storage.mode;
std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>();
std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
@@ -246,7 +282,7 @@ static void geo_node_curve_primitive_quadrilateral_exec(GeoNodeExecParams params
params.extract_input<float3>("Point 4"));
break;
default:
- params.set_output("Curve", GeometrySet());
+ params.set_default_remaining_outputs();
return;
}
@@ -255,21 +291,24 @@ static void geo_node_curve_primitive_quadrilateral_exec(GeoNodeExecParams params
params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_primitive_quadrilaterial_cc
void register_node_type_geo_curve_primitive_quadrilateral()
{
+ namespace file_ns = blender::nodes::node_geo_curve_primitive_quadrilaterial_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_CURVE_PRIMITIVE_QUADRILATERAL, "Quadrilateral", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_curve_primitive_quadrilateral_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_primitive_quadrilateral_exec;
- ntype.draw_buttons = blender::nodes::geo_node_curve_primitive_quadrilateral_layout;
- node_type_update(&ntype, blender::nodes::geo_node_curve_primitive_quadrilateral_update);
- node_type_init(&ntype, blender::nodes::geo_node_curve_primitive_quadrilateral_init);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ node_type_update(&ntype, file_ns::node_update);
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(&ntype,
"NodeGeometryCurvePrimitiveQuad",
node_free_standard_storage,
node_copy_standard_storage);
+ ntype.gather_link_search_ops = file_ns::node_gather_link_searches;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc
index 1384165e520..d5ae3551904 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc
@@ -18,9 +18,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_primitive_spiral_cc {
-static void geo_node_curve_primitive_spiral_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Int>(N_("Resolution"))
.default_value(32)
@@ -81,11 +81,11 @@ static std::unique_ptr<CurveEval> create_spiral_curve(const float rotations,
return curve;
}
-static void geo_node_curve_primitive_spiral_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
const float rotations = std::max(params.extract_input<float>("Rotations"), 0.0f);
if (rotations == 0.0f) {
- params.set_output("Curve", GeometrySet());
+ params.set_default_remaining_outputs();
return;
}
@@ -99,14 +99,16 @@ static void geo_node_curve_primitive_spiral_exec(GeoNodeExecParams params)
params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_primitive_spiral_cc
void register_node_type_geo_curve_primitive_spiral()
{
+ namespace file_ns = blender::nodes::node_geo_curve_primitive_spiral_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_SPIRAL, "Spiral", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_curve_primitive_spiral_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_primitive_spiral_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc
index 9004681c246..731be0f0f49 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc
@@ -18,9 +18,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_primitive_star_cc {
-static void geo_node_curve_primitive_star_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Int>(N_("Points"))
.default_value(8)
@@ -85,7 +85,7 @@ static void create_selection_output(CurveComponent &component,
attribute.save();
}
-static void geo_node_curve_primitive_star_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
std::unique_ptr<CurveEval> curve = create_star_curve(
std::max(params.extract_input<float>("Inner Radius"), 0.0f),
@@ -103,13 +103,15 @@ static void geo_node_curve_primitive_star_exec(GeoNodeExecParams params)
}
params.set_output("Curve", std::move(output));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_primitive_star_cc
void register_node_type_geo_curve_primitive_star()
{
+ namespace file_ns = blender::nodes::node_geo_curve_primitive_star_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_STAR, "Star", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_curve_primitive_star_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_primitive_star_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
index f72978bae50..7e465714265 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
@@ -26,9 +26,11 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_resample_cc {
-static void geo_node_curve_resample_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryCurveResample)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
b.add_input<decl::Bool>(N_("Selection")).default_value(true).supports_field().hide_value();
@@ -41,12 +43,12 @@ static void geo_node_curve_resample_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Curve"));
}
-static void geo_node_curve_resample_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
}
-static void geo_node_curve_resample_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryCurveResample *data = (NodeGeometryCurveResample *)MEM_callocN(
sizeof(NodeGeometryCurveResample), __func__);
@@ -55,10 +57,10 @@ static void geo_node_curve_resample_init(bNodeTree *UNUSED(tree), bNode *node)
node->storage = data;
}
-static void geo_node_curve_resample_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
- NodeGeometryCurveResample &node_storage = *(NodeGeometryCurveResample *)node->storage;
- const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)node_storage.mode;
+ const NodeGeometryCurveResample &storage = node_storage(*node);
+ const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)storage.mode;
bNodeSocket *count_socket = ((bNodeSocket *)node->inputs.first)->next->next;
bNodeSocket *length_socket = count_socket->next;
@@ -189,7 +191,7 @@ static std::unique_ptr<CurveEval> resample_curve(const CurveComponent *component
threading::parallel_for(input_splines.index_range(), 128, [&](IndexRange range) {
for (const int i : range) {
BLI_assert(mode_param.count);
- if (selections[i]) {
+ if (selections[i] && input_splines[i]->evaluated_points_size() > 0) {
output_splines[i] = resample_spline(*input_splines[i], std::max(cuts[i], 1));
}
else {
@@ -208,7 +210,7 @@ static std::unique_ptr<CurveEval> resample_curve(const CurveComponent *component
threading::parallel_for(input_splines.index_range(), 128, [&](IndexRange range) {
for (const int i : range) {
- if (selections[i]) {
+ if (selections[i] && input_splines[i]->evaluated_points_size() > 0) {
/* Don't allow asymptotic count increase for low resolution values. */
const float divide_length = std::max(lengths[i], 0.0001f);
const float spline_length = input_splines[i]->length();
@@ -229,7 +231,7 @@ static std::unique_ptr<CurveEval> resample_curve(const CurveComponent *component
threading::parallel_for(input_splines.index_range(), 128, [&](IndexRange range) {
for (const int i : range) {
- if (selections[i]) {
+ if (selections[i] && input_splines[i]->evaluated_points_size() > 0) {
output_splines[i] = resample_spline_evaluated(*input_splines[i]);
}
else {
@@ -255,12 +257,12 @@ static void geometry_set_curve_resample(GeometrySet &geometry_set,
geometry_set.replace_curve(output_curve.release());
}
-static void geo_node_resample_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
- NodeGeometryCurveResample &node_storage = *(NodeGeometryCurveResample *)params.node().storage;
- const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)node_storage.mode;
+ const NodeGeometryCurveResample &storage = node_storage(params.node());
+ const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)storage.mode;
SampleModeParam mode_param;
mode_param.mode = mode;
@@ -269,7 +271,7 @@ static void geo_node_resample_exec(GeoNodeExecParams params)
if (mode == GEO_NODE_CURVE_RESAMPLE_COUNT) {
Field<int> count = params.extract_input<Field<int>>("Count");
if (count < 1) {
- params.set_output("Curve", GeometrySet());
+ params.set_default_remaining_outputs();
return;
}
mode_param.count.emplace(count);
@@ -285,19 +287,21 @@ static void geo_node_resample_exec(GeoNodeExecParams params)
params.set_output("Curve", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_resample_cc
void register_node_type_geo_curve_resample()
{
+ namespace file_ns = blender::nodes::node_geo_curve_resample_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_RESAMPLE_CURVE, "Resample Curve", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_curve_resample_declare;
- ntype.draw_buttons = blender::nodes::geo_node_curve_resample_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_layout;
node_type_storage(
&ntype, "NodeGeometryCurveResample", node_free_standard_storage, node_copy_standard_storage);
- node_type_init(&ntype, blender::nodes::geo_node_curve_resample_init);
- node_type_update(&ntype, blender::nodes::geo_node_curve_resample_update);
- ntype.geometry_node_execute = blender::nodes::geo_node_resample_exec;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc
index b1dc45a426a..d07e89ec7f2 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc
@@ -20,16 +20,16 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_reverse_cc {
-static void geo_node_curve_reverse_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
b.add_output<decl::Geometry>(N_("Curve"));
}
-static void geo_node_curve_reverse_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
@@ -60,13 +60,15 @@ static void geo_node_curve_reverse_exec(GeoNodeExecParams params)
params.set_output("Curve", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_reverse_cc
void register_node_type_geo_curve_reverse()
{
+ namespace file_ns = blender::nodes::node_geo_curve_reverse_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_REVERSE_CURVE, "Reverse Curve", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_curve_reverse_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_reverse_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc
index 8f42aacab43..eff760266f5 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc
@@ -23,27 +23,37 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_sample_cc {
-static void geo_node_curve_sample_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryCurveSample)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Curve"))
.only_realized_data()
.supported_type(GEO_COMPONENT_TYPE_CURVE);
- b.add_input<decl::Float>(N_("Factor")).min(0.0f).max(1.0f).subtype(PROP_FACTOR).supports_field();
- b.add_input<decl::Float>(N_("Length")).min(0.0f).subtype(PROP_DISTANCE).supports_field();
-
+ b.add_input<decl::Float>(N_("Factor"))
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR)
+ .supports_field()
+ .make_available([](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_SAMPLE_FACTOR; });
+ b.add_input<decl::Float>(N_("Length"))
+ .min(0.0f)
+ .subtype(PROP_DISTANCE)
+ .supports_field()
+ .make_available([](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_SAMPLE_LENGTH; });
b.add_output<decl::Vector>(N_("Position")).dependent_field();
b.add_output<decl::Vector>(N_("Tangent")).dependent_field();
b.add_output<decl::Vector>(N_("Normal")).dependent_field();
}
-static void geo_node_curve_sample_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
}
-static void geo_node_curve_sample_type_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_type_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryCurveSample *data = (NodeGeometryCurveSample *)MEM_callocN(
sizeof(NodeGeometryCurveSample), __func__);
@@ -51,10 +61,10 @@ static void geo_node_curve_sample_type_init(bNodeTree *UNUSED(tree), bNode *node
node->storage = data;
}
-static void geo_node_curve_sample_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
- const NodeGeometryCurveSample &node_storage = *(NodeGeometryCurveSample *)node->storage;
- const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)node_storage.mode;
+ const NodeGeometryCurveSample &storage = node_storage(*node);
+ const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)storage.mode;
bNodeSocket *factor = ((bNodeSocket *)node->inputs.first)->next;
bNodeSocket *length = factor->next;
@@ -200,8 +210,8 @@ class SampleCurveFunction : public fn::MultiFunction {
static Field<float> get_length_input_field(const GeoNodeExecParams &params,
const float curve_total_length)
{
- const NodeGeometryCurveSample &node_storage = *(NodeGeometryCurveSample *)params.node().storage;
- const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)node_storage.mode;
+ const NodeGeometryCurveSample &storage = node_storage(params.node());
+ const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)storage.mode;
if (mode == GEO_NODE_CURVE_SAMPLE_LENGTH) {
/* Just make sure the length is in bounds of the curve. */
@@ -229,34 +239,32 @@ static Field<float> get_length_input_field(const GeoNodeExecParams &params,
return Field<float>(std::move(process_op), 0);
}
-static void geo_node_curve_sample_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
- auto return_default = [&]() {
- params.set_output("Position", fn::make_constant_field<float3>({0.0f, 0.0f, 0.0f}));
- params.set_output("Tangent", fn::make_constant_field<float3>({0.0f, 0.0f, 0.0f}));
- params.set_output("Normal", fn::make_constant_field<float3>({0.0f, 0.0f, 0.0f}));
- };
-
const CurveComponent *component = geometry_set.get_component_for_read<CurveComponent>();
if (component == nullptr) {
- return return_default();
+ params.set_default_remaining_outputs();
+ return;
}
const CurveEval *curve = component->get_for_read();
if (curve == nullptr) {
- return return_default();
+ params.set_default_remaining_outputs();
+ return;
}
if (curve->splines().is_empty()) {
- return return_default();
+ params.set_default_remaining_outputs();
+ return;
}
Array<float> spline_lengths = curve->accumulated_spline_lengths();
const float total_length = spline_lengths.last();
if (total_length == 0.0f) {
- return return_default();
+ params.set_default_remaining_outputs();
+ return;
}
Field<float> length_field = get_length_input_field(params, total_length);
@@ -271,20 +279,22 @@ static void geo_node_curve_sample_exec(GeoNodeExecParams params)
params.set_output("Normal", Field<float3>(sample_op, 2));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_sample_cc
void register_node_type_geo_curve_sample()
{
+ namespace file_ns = blender::nodes::node_geo_curve_sample_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_SAMPLE_CURVE, " Sample Curve", NODE_CLASS_GEOMETRY, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_sample_exec;
- ntype.declare = blender::nodes::geo_node_curve_sample_declare;
- node_type_init(&ntype, blender::nodes::geo_node_curve_sample_type_init);
- node_type_update(&ntype, blender::nodes::geo_node_curve_sample_update);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ node_type_init(&ntype, file_ns::node_type_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(
&ntype, "NodeGeometryCurveSample", node_free_standard_storage, node_copy_standard_storage);
- ntype.draw_buttons = blender::nodes::geo_node_curve_sample_layout;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc
index 8b0a6ca840c..8c0827570c6 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc
@@ -21,24 +21,24 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_set_handles_cc {
-static void geo_node_curve_set_handles_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryCurveSetHandles)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
b.add_output<decl::Geometry>(N_("Curve"));
}
-static void geo_node_curve_set_handles_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
uiItemR(layout, ptr, "handle_type", 0, "", ICON_NONE);
}
-static void geo_node_curve_set_handles_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryCurveSetHandles *data = (NodeGeometryCurveSetHandles *)MEM_callocN(
sizeof(NodeGeometryCurveSetHandles), __func__);
@@ -64,12 +64,11 @@ static BezierSpline::HandleType handle_type_from_input_type(GeometryNodeCurveHan
return BezierSpline::HandleType::Auto;
}
-static void geo_node_curve_set_handles_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
- const NodeGeometryCurveSetHandles *node_storage =
- (NodeGeometryCurveSetHandles *)params.node().storage;
- const GeometryNodeCurveHandleType type = (GeometryNodeCurveHandleType)node_storage->handle_type;
- const GeometryNodeCurveHandleMode mode = (GeometryNodeCurveHandleMode)node_storage->mode;
+ const NodeGeometryCurveSetHandles &storage = node_storage(params.node());
+ const GeometryNodeCurveHandleType type = (GeometryNodeCurveHandleType)storage.handle_type;
+ const GeometryNodeCurveHandleMode mode = (GeometryNodeCurveHandleMode)storage.mode;
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
@@ -130,21 +129,23 @@ static void geo_node_curve_set_handles_exec(GeoNodeExecParams params)
}
params.set_output("Curve", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_set_handles_cc
void register_node_type_geo_curve_set_handles()
{
+ namespace file_ns = blender::nodes::node_geo_curve_set_handles_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_CURVE_SET_HANDLES, "Set Handle Type", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_curve_set_handles_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_set_handles_exec;
- node_type_init(&ntype, blender::nodes::geo_node_curve_set_handles_init);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(&ntype,
"NodeGeometryCurveSetHandles",
node_free_standard_storage,
node_copy_standard_storage);
- ntype.draw_buttons = blender::nodes::geo_node_curve_set_handles_layout;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_parameter.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc
index 63518b38090..de352d217ed 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_parameter.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc
@@ -20,9 +20,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_spline_parameter_cc {
-static void geo_node_curve_parameter_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Float>(N_("Factor"))
.field_source()
@@ -34,6 +34,9 @@ static void geo_node_curve_parameter_declare(NodeDeclarationBuilder &b)
.description(
N_("For points, the distance along the control point's spline, For splines, the "
"distance along the entire curve"));
+ b.add_output<decl::Int>(N_("Index"))
+ .field_source()
+ .description(N_("Each control point's index on its spline"));
}
/**
@@ -182,29 +185,39 @@ static VArray<float> construct_curve_length_varray(const CurveEval &curve,
return {};
}
-class CurveParameterFieldInput final : public fn::FieldInput {
+static VArray<int> construct_index_on_spline_varray(const CurveEval &curve,
+ const IndexMask UNUSED(mask),
+ const AttributeDomain domain)
+{
+ if (domain == ATTR_DOMAIN_POINT) {
+ Array<int> output(curve.total_control_point_size());
+ int output_index = 0;
+ for (int spline_index : curve.splines().index_range()) {
+ for (int point_index : IndexRange(curve.splines()[spline_index]->size())) {
+ output[output_index++] = point_index;
+ }
+ }
+ return VArray<int>::ForContainer(std::move(output));
+ }
+ return {};
+}
+
+class CurveParameterFieldInput final : public GeometryFieldInput {
public:
- CurveParameterFieldInput() : fn::FieldInput(CPPType::get<float>(), "Curve Parameter node")
+ CurveParameterFieldInput() : GeometryFieldInput(CPPType::get<float>(), "Curve Parameter node")
{
category_ = Category::Generated;
}
- GVArray get_varray_for_context(const fn::FieldContext &context,
- IndexMask mask,
- ResourceScope &UNUSED(scope)) const final
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask mask) const final
{
- if (const GeometryComponentFieldContext *geometry_context =
- dynamic_cast<const GeometryComponentFieldContext *>(&context)) {
-
- const GeometryComponent &component = geometry_context->geometry_component();
- const AttributeDomain domain = geometry_context->domain();
-
- if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
- const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
- const CurveEval *curve = curve_component.get_for_read();
- if (curve) {
- return construct_curve_parameter_varray(*curve, mask, domain);
- }
+ if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
+ const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
+ const CurveEval *curve = curve_component.get_for_read();
+ if (curve) {
+ return construct_curve_parameter_varray(*curve, mask, domain);
}
}
return {};
@@ -222,28 +235,22 @@ class CurveParameterFieldInput final : public fn::FieldInput {
}
};
-class CurveLengthFieldInput final : public fn::FieldInput {
+class CurveLengthFieldInput final : public GeometryFieldInput {
public:
- CurveLengthFieldInput() : fn::FieldInput(CPPType::get<float>(), "Curve Length node")
+ CurveLengthFieldInput() : GeometryFieldInput(CPPType::get<float>(), "Curve Length node")
{
category_ = Category::Generated;
}
- GVArray get_varray_for_context(const fn::FieldContext &context,
- IndexMask mask,
- ResourceScope &UNUSED(scope)) const final
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask mask) const final
{
- if (const GeometryComponentFieldContext *geometry_context =
- dynamic_cast<const GeometryComponentFieldContext *>(&context)) {
-
- const GeometryComponent &component = geometry_context->geometry_component();
- const AttributeDomain domain = geometry_context->domain();
- if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
- const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
- const CurveEval *curve = curve_component.get_for_read();
- if (curve) {
- return construct_curve_length_varray(*curve, mask, domain);
- }
+ if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
+ const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
+ const CurveEval *curve = curve_component.get_for_read();
+ if (curve) {
+ return construct_curve_length_varray(*curve, mask, domain);
}
}
return {};
@@ -261,21 +268,59 @@ class CurveLengthFieldInput final : public fn::FieldInput {
}
};
-static void geo_node_curve_parameter_exec(GeoNodeExecParams params)
+class IndexOnSplineFieldInput final : public GeometryFieldInput {
+ public:
+ IndexOnSplineFieldInput() : GeometryFieldInput(CPPType::get<int>(), "Spline Index")
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask mask) const final
+ {
+ if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
+ const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
+ const CurveEval *curve = curve_component.get_for_read();
+ if (curve) {
+ return construct_index_on_spline_varray(*curve, mask, domain);
+ }
+ }
+ return {};
+ }
+
+ uint64_t hash() const override
+ {
+ /* Some random constant hash. */
+ return 4536246522;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ return dynamic_cast<const IndexOnSplineFieldInput *>(&other) != nullptr;
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
{
Field<float> parameter_field{std::make_shared<CurveParameterFieldInput>()};
Field<float> length_field{std::make_shared<CurveLengthFieldInput>()};
+ Field<int> index_on_spline_field{std::make_shared<IndexOnSplineFieldInput>()};
params.set_output("Factor", std::move(parameter_field));
params.set_output("Length", std::move(length_field));
+ params.set_output("Index", std::move(index_on_spline_field));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_spline_parameter_cc
-void register_node_type_geo_curve_parameter()
+void register_node_type_geo_curve_spline_parameter()
{
+ namespace file_ns = blender::nodes::node_geo_curve_spline_parameter_cc;
+
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_CURVE_PARAMETER, "Curve Parameter", NODE_CLASS_INPUT, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_parameter_exec;
- ntype.declare = blender::nodes::geo_node_curve_parameter_declare;
+ geo_node_type_base(
+ &ntype, GEO_NODE_CURVE_SPLINE_PARAMETER, "Spline Parameter", NODE_CLASS_INPUT, 0);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc
index ae4453929ac..eef8c1b0db5 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc
@@ -23,23 +23,23 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_spline_type_cc {
-static void geo_node_curve_spline_type_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryCurveSplineType)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
b.add_output<decl::Geometry>(N_("Curve"));
}
-static void geo_node_curve_spline_type_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "spline_type", 0, "", ICON_NONE);
}
-static void geo_node_curve_spline_type_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryCurveSplineType *data = (NodeGeometryCurveSplineType *)MEM_callocN(
sizeof(NodeGeometryCurveSplineType), __func__);
@@ -238,11 +238,10 @@ static SplinePtr convert_to_nurbs(const Spline &input)
return {};
}
-static void geo_node_curve_spline_type_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
- const NodeGeometryCurveSplineType *storage =
- (const NodeGeometryCurveSplineType *)params.node().storage;
- const GeometryNodeSplineType output_type = (const GeometryNodeSplineType)storage->spline_type;
+ const NodeGeometryCurveSplineType &storage = node_storage(params.node());
+ const GeometryNodeSplineType output_type = (const GeometryNodeSplineType)storage.spline_type;
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
@@ -263,24 +262,28 @@ static void geo_node_curve_spline_type_exec(GeoNodeExecParams params)
const VArray<bool> &selection = selection_evaluator.get_evaluated<bool>(0);
std::unique_ptr<CurveEval> new_curve = std::make_unique<CurveEval>();
- for (const int i : curve.splines().index_range()) {
- if (selection[i]) {
- switch (output_type) {
- case GEO_NODE_SPLINE_TYPE_POLY:
- new_curve->add_spline(convert_to_poly_spline(*curve.splines()[i]));
- break;
- case GEO_NODE_SPLINE_TYPE_BEZIER:
- new_curve->add_spline(convert_to_bezier(*curve.splines()[i], params));
- break;
- case GEO_NODE_SPLINE_TYPE_NURBS:
- new_curve->add_spline(convert_to_nurbs(*curve.splines()[i]));
- break;
+ new_curve->resize(curve.splines().size());
+
+ threading::parallel_for(curve.splines().index_range(), 512, [&](IndexRange range) {
+ for (const int i : range) {
+ if (selection[i]) {
+ switch (output_type) {
+ case GEO_NODE_SPLINE_TYPE_POLY:
+ new_curve->splines()[i] = convert_to_poly_spline(*curve.splines()[i]);
+ break;
+ case GEO_NODE_SPLINE_TYPE_BEZIER:
+ new_curve->splines()[i] = convert_to_bezier(*curve.splines()[i], params);
+ break;
+ case GEO_NODE_SPLINE_TYPE_NURBS:
+ new_curve->splines()[i] = convert_to_nurbs(*curve.splines()[i]);
+ break;
+ }
+ }
+ else {
+ new_curve->splines()[i] = curve.splines()[i]->copy();
}
}
- else {
- new_curve->add_spline(curve.splines()[i]->copy());
- }
- }
+ });
new_curve->attributes = curve.attributes;
geometry_set.replace_curve(new_curve.release());
});
@@ -288,21 +291,23 @@ static void geo_node_curve_spline_type_exec(GeoNodeExecParams params)
params.set_output("Curve", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_spline_type_cc
void register_node_type_geo_curve_spline_type()
{
+ namespace file_ns = blender::nodes::node_geo_curve_spline_type_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_CURVE_SPLINE_TYPE, "Set Spline Type", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_curve_spline_type_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_spline_type_exec;
- node_type_init(&ntype, blender::nodes::geo_node_curve_spline_type_init);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(&ntype,
"NodeGeometryCurveSplineType",
node_free_standard_storage,
node_copy_standard_storage);
- ntype.draw_buttons = blender::nodes::geo_node_curve_spline_type_layout;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc
index 7c4c17e69e0..6de188fc1c4 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc
@@ -25,9 +25,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_subdivide_cc {
-static void geo_node_curve_subdivide_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
b.add_input<decl::Int>(N_("Cuts")).default_value(1).min(0).max(1000).supports_field();
@@ -322,7 +322,7 @@ static std::unique_ptr<CurveEval> subdivide_curve(const CurveEval &input_curve,
return output_curve;
}
-static void geo_node_subdivide_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
Field<int> cuts_field = params.extract_input<Field<int>>("Cuts");
@@ -351,14 +351,16 @@ static void geo_node_subdivide_exec(GeoNodeExecParams params)
params.set_output("Curve", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_subdivide_cc
void register_node_type_geo_curve_subdivide()
{
+ namespace file_ns = blender::nodes::node_geo_curve_subdivide_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_SUBDIVIDE_CURVE, "Subdivide Curve", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_curve_subdivide_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_subdivide_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc
index 1977b465de4..ff3e85cb6b7 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc
@@ -23,9 +23,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_to_mesh_cc {
-static void geo_node_curve_to_mesh_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
b.add_input<decl::Geometry>(N_("Profile Curve"))
@@ -54,7 +54,7 @@ static void geometry_set_curve_to_mesh(GeometrySet &geometry_set,
}
}
-static void geo_node_curve_to_mesh_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet curve_set = params.extract_input<GeometrySet>("Curve");
GeometrySet profile_set = params.extract_input<GeometrySet>("Profile Curve");
@@ -72,14 +72,16 @@ static void geo_node_curve_to_mesh_exec(GeoNodeExecParams params)
params.set_output("Mesh", std::move(curve_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_to_mesh_cc
void register_node_type_geo_curve_to_mesh()
{
+ namespace file_ns = blender::nodes::node_geo_curve_to_mesh_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_CURVE_TO_MESH, "Curve to Mesh", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_curve_to_mesh_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_to_mesh_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc
index b9f129a5f75..0e9425246cb 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc
@@ -27,24 +27,50 @@
#include "node_geometry_util.hh"
namespace blender::nodes {
+void curve_create_default_rotation_attribute(Span<float3> tangents,
+ Span<float3> normals,
+ MutableSpan<float3> rotations)
+{
+ threading::parallel_for(IndexRange(rotations.size()), 512, [&](IndexRange range) {
+ for (const int i : range) {
+ rotations[i] =
+ float4x4::from_normalized_axis_data({0, 0, 0}, normals[i], tangents[i]).to_euler();
+ }
+ });
+}
+} // namespace blender::nodes
+
+namespace blender::nodes::node_geo_curve_to_points_cc {
+
+NODE_STORAGE_FUNCS(NodeGeometryCurveToPoints)
-static void geo_node_curve_to_points_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
- b.add_input<decl::Int>(N_("Count")).default_value(10).min(2).max(100000);
- b.add_input<decl::Float>(N_("Length")).default_value(0.1f).min(0.001f).subtype(PROP_DISTANCE);
+ b.add_input<decl::Int>(N_("Count"))
+ .default_value(10)
+ .min(2)
+ .max(100000)
+ .make_available(
+ [](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_RESAMPLE_COUNT; });
+ b.add_input<decl::Float>(N_("Length"))
+ .default_value(0.1f)
+ .min(0.001f)
+ .subtype(PROP_DISTANCE)
+ .make_available(
+ [](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_RESAMPLE_LENGTH; });
b.add_output<decl::Geometry>(N_("Points"));
b.add_output<decl::Vector>(N_("Tangent")).field_source();
b.add_output<decl::Vector>(N_("Normal")).field_source();
b.add_output<decl::Vector>(N_("Rotation")).field_source();
}
-static void geo_node_curve_to_points_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
}
-static void geo_node_curve_to_points_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryCurveToPoints *data = (NodeGeometryCurveToPoints *)MEM_callocN(
sizeof(NodeGeometryCurveToPoints), __func__);
@@ -53,10 +79,10 @@ static void geo_node_curve_to_points_init(bNodeTree *UNUSED(tree), bNode *node)
node->storage = data;
}
-static void geo_node_curve_to_points_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
- NodeGeometryCurveToPoints &node_storage = *(NodeGeometryCurveToPoints *)node->storage;
- const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)node_storage.mode;
+ const NodeGeometryCurveToPoints &storage = node_storage(*node);
+ const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)storage.mode;
bNodeSocket *count_socket = ((bNodeSocket *)node->inputs.first)->next;
bNodeSocket *length_socket = count_socket->next;
@@ -78,9 +104,14 @@ static Array<int> calculate_spline_point_offsets(GeoNodeExecParams &params,
return {0};
}
Array<int> offsets(size + 1);
- for (const int i : offsets.index_range()) {
- offsets[i] = count * i;
+ int offset = 0;
+ for (const int i : IndexRange(size)) {
+ offsets[i] = offset;
+ if (splines[i]->evaluated_points_size() > 0) {
+ offset += count;
+ }
}
+ offsets.last() = offset;
return offsets;
}
case GEO_NODE_CURVE_RESAMPLE_LENGTH: {
@@ -90,7 +121,9 @@ static Array<int> calculate_spline_point_offsets(GeoNodeExecParams &params,
int offset = 0;
for (const int i : IndexRange(size)) {
offsets[i] = offset;
- offset += splines[i]->length() / resolution + 1;
+ if (splines[i]->evaluated_points_size() > 0) {
+ offset += splines[i]->length() / resolution + 1;
+ }
}
offsets.last() = offset;
return offsets;
@@ -289,22 +322,10 @@ static void copy_spline_domain_attributes(const CurveEval &curve,
ATTR_DOMAIN_CURVE);
}
-void curve_create_default_rotation_attribute(Span<float3> tangents,
- Span<float3> normals,
- MutableSpan<float3> rotations)
+static void node_geo_exec(GeoNodeExecParams params)
{
- threading::parallel_for(IndexRange(rotations.size()), 512, [&](IndexRange range) {
- for (const int i : range) {
- rotations[i] =
- float4x4::from_normalized_axis_data({0, 0, 0}, normals[i], tangents[i]).to_euler();
- }
- });
-}
-
-static void geo_node_curve_to_points_exec(GeoNodeExecParams params)
-{
- NodeGeometryCurveToPoints &node_storage = *(NodeGeometryCurveToPoints *)params.node().storage;
- const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)node_storage.mode;
+ const NodeGeometryCurveToPoints &storage = node_storage(params.node());
+ const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)storage.mode;
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
AnonymousAttributeIDs attribute_outputs;
@@ -374,20 +395,21 @@ static void geo_node_curve_to_points_exec(GeoNodeExecParams params)
}
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_to_points_cc
void register_node_type_geo_curve_to_points()
{
+ namespace file_ns = blender::nodes::node_geo_curve_to_points_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_CURVE_TO_POINTS, "Curve to Points", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_curve_to_points_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_to_points_exec;
- ntype.draw_buttons = blender::nodes::geo_node_curve_to_points_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
node_type_storage(
&ntype, "NodeGeometryCurveToPoints", node_free_standard_storage, node_copy_standard_storage);
- node_type_init(&ntype, blender::nodes::geo_node_curve_to_points_init);
- node_type_update(&ntype, blender::nodes::geo_node_curve_to_points_update);
-
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
index b281876d314..746392a66cc 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
@@ -20,40 +20,52 @@
#include "UI_interface.h"
#include "UI_resources.h"
+#include "NOD_socket_search_link.hh"
+
#include "node_geometry_util.hh"
+namespace blender::nodes::node_geo_curve_trim_cc {
+
using blender::attribute_math::mix2;
-namespace blender::nodes {
+NODE_STORAGE_FUNCS(NodeGeometryCurveTrim)
-static void geo_node_curve_trim_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
- b.add_input<decl::Float>(N_("Start")).min(0.0f).max(1.0f).subtype(PROP_FACTOR).supports_field();
+ b.add_input<decl::Float>(N_("Start"))
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR)
+ .make_available([](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_SAMPLE_FACTOR; })
+ .supports_field();
b.add_input<decl::Float>(N_("End"))
.min(0.0f)
.max(1.0f)
.default_value(1.0f)
.subtype(PROP_FACTOR)
+ .make_available([](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_SAMPLE_FACTOR; })
.supports_field();
b.add_input<decl::Float>(N_("Start"), "Start_001")
.min(0.0f)
.subtype(PROP_DISTANCE)
+ .make_available([](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_SAMPLE_LENGTH; })
.supports_field();
b.add_input<decl::Float>(N_("End"), "End_001")
.min(0.0f)
.default_value(1.0f)
.subtype(PROP_DISTANCE)
+ .make_available([](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_SAMPLE_LENGTH; })
.supports_field();
b.add_output<decl::Geometry>(N_("Curve"));
}
-static void geo_node_curve_trim_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
}
-static void geo_node_curve_trim_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryCurveTrim *data = (NodeGeometryCurveTrim *)MEM_callocN(sizeof(NodeGeometryCurveTrim),
__func__);
@@ -62,10 +74,10 @@ static void geo_node_curve_trim_init(bNodeTree *UNUSED(tree), bNode *node)
node->storage = data;
}
-static void geo_node_curve_trim_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
- const NodeGeometryCurveTrim &node_storage = *(NodeGeometryCurveTrim *)node->storage;
- const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)node_storage.mode;
+ const NodeGeometryCurveTrim &storage = node_storage(*node);
+ const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)storage.mode;
bNodeSocket *start_fac = ((bNodeSocket *)node->inputs.first)->next;
bNodeSocket *end_fac = start_fac->next;
@@ -78,6 +90,38 @@ static void geo_node_curve_trim_update(bNodeTree *ntree, bNode *node)
nodeSetSocketAvailability(ntree, end_len, mode == GEO_NODE_CURVE_SAMPLE_LENGTH);
}
+class SocketSearchOp {
+ public:
+ StringRef socket_name;
+ GeometryNodeCurveSampleMode mode;
+ void operator()(LinkSearchOpParams &params)
+ {
+ bNode &node = params.add_node("GeometryNodeTrimCurve");
+ node_storage(node).mode = mode;
+ params.update_and_connect_available_socket(node, socket_name);
+ }
+};
+
+static void node_gather_link_searches(GatherLinkSearchOpParams &params)
+{
+ const NodeDeclaration &declaration = *params.node_type().fixed_declaration;
+
+ search_link_ops_for_declarations(params, declaration.outputs());
+ search_link_ops_for_declarations(params, declaration.inputs().take_front(1));
+
+ if (params.in_out() == SOCK_IN) {
+ if (params.node_tree().typeinfo->validate_link(
+ static_cast<eNodeSocketDatatype>(params.other_socket().type), SOCK_FLOAT)) {
+ params.add_item(IFACE_("Start (Factor)"),
+ SocketSearchOp{"Start", GEO_NODE_CURVE_SAMPLE_FACTOR});
+ params.add_item(IFACE_("End (Factor)"), SocketSearchOp{"End", GEO_NODE_CURVE_SAMPLE_FACTOR});
+ params.add_item(IFACE_("Start (Length)"),
+ SocketSearchOp{"Start", GEO_NODE_CURVE_SAMPLE_LENGTH});
+ params.add_item(IFACE_("End (Length)"), SocketSearchOp{"End", GEO_NODE_CURVE_SAMPLE_LENGTH});
+ }
+ }
+}
+
struct TrimLocation {
/* Control point index at the start side of the trim location. */
int left_index;
@@ -532,10 +576,10 @@ static void geometry_set_curve_trim(GeometrySet &geometry_set,
});
}
-static void geo_node_curve_trim_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
- const NodeGeometryCurveTrim &node_storage = *(NodeGeometryCurveTrim *)params.node().storage;
- const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)node_storage.mode;
+ const NodeGeometryCurveTrim &storage = node_storage(params.node());
+ const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)storage.mode;
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
@@ -557,18 +601,21 @@ static void geo_node_curve_trim_exec(GeoNodeExecParams params)
params.set_output("Curve", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_trim_cc
void register_node_type_geo_curve_trim()
{
+ namespace file_ns = blender::nodes::node_geo_curve_trim_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_TRIM_CURVE, "Trim Curve", NODE_CLASS_GEOMETRY, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_trim_exec;
- ntype.draw_buttons = blender::nodes::geo_node_curve_trim_layout;
- ntype.declare = blender::nodes::geo_node_curve_trim_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.declare = file_ns::node_declare;
node_type_storage(
&ntype, "NodeGeometryCurveTrim", node_free_standard_storage, node_copy_standard_storage);
- node_type_init(&ntype, blender::nodes::geo_node_curve_trim_init);
- node_type_update(&ntype, blender::nodes::geo_node_curve_trim_update);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.gather_link_search_ops = file_ns::node_gather_link_searches;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
index d07644f8403..1de809b30e4 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
@@ -29,63 +29,26 @@
#include "node_geometry_util.hh"
-using blender::bke::CustomDataAttributes;
-
-/* Code from the mask modifier in MOD_mask.cc. */
-extern void copy_masked_vertices_to_new_mesh(const Mesh &src_mesh,
- Mesh &dst_mesh,
- blender::Span<int> vertex_map);
-extern void copy_masked_edges_to_new_mesh(const Mesh &src_mesh,
- Mesh &dst_mesh,
- blender::Span<int> vertex_map,
- blender::Span<int> edge_map);
-extern void copy_masked_polys_to_new_mesh(const Mesh &src_mesh,
- Mesh &dst_mesh,
- blender::Span<int> vertex_map,
- blender::Span<int> edge_map,
- blender::Span<int> masked_poly_indices,
- blender::Span<int> new_loop_starts);
-
namespace blender::nodes {
-static void geo_node_delete_geometry_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Geometry>(N_("Geometry"));
- b.add_input<decl::Bool>(N_("Selection"))
- .default_value(true)
- .hide_value()
- .supports_field()
- .description(N_("The parts of the geometry to be deleted"));
- b.add_output<decl::Geometry>(N_("Geometry"));
-}
+using blender::bke::CustomDataAttributes;
-static void geo_node_delete_geometry_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+template<typename T>
+static void copy_data_based_on_mask(Span<T> data, MutableSpan<T> r_data, IndexMask mask)
{
- const bNode *node = static_cast<bNode *>(ptr->data);
- const NodeGeometryDeleteGeometry &storage = *(const NodeGeometryDeleteGeometry *)node->storage;
- const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain);
-
- uiItemR(layout, ptr, "domain", 0, "", ICON_NONE);
- /* Only show the mode when it is relevant. */
- if (ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE, ATTR_DOMAIN_FACE)) {
- uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
+ for (const int i_out : mask.index_range()) {
+ r_data[i_out] = data[mask[i_out]];
}
}
-static void geo_node_delete_geometry_init(bNodeTree *UNUSED(tree), bNode *node)
-{
- NodeGeometryDeleteGeometry *data = (NodeGeometryDeleteGeometry *)MEM_callocN(
- sizeof(NodeGeometryDeleteGeometry), __func__);
- data->domain = ATTR_DOMAIN_POINT;
- data->mode = GEO_NODE_DELETE_GEOMETRY_MODE_ALL;
-
- node->storage = data;
-}
-
-template<typename T> static void copy_data(Span<T> data, MutableSpan<T> r_data, IndexMask mask)
+template<typename T>
+static void copy_data_based_on_map(Span<T> src, MutableSpan<T> dst, Span<int> index_map)
{
- for (const int i_out : mask.index_range()) {
- r_data[i_out] = data[mask[i_out]];
+ for (const int i_src : index_map.index_range()) {
+ const int i_dst = index_map[i_src];
+ if (i_dst != -1) {
+ dst[i_dst] = src[i_src];
+ }
}
}
@@ -102,23 +65,6 @@ static IndexMask index_mask_indices(Span<bool> mask, const bool invert, Vector<i
return IndexMask(indices);
}
-/** Utility function for making an IndexMask from an array of integers, where the negative integers
- * are seen as false. The indices vector should live at least as long as the returned IndexMask.
- */
-static IndexMask index_mask_indices(Span<int> mask,
- const int num_indices,
- Vector<int64_t> &indices)
-{
- indices.clear();
- indices.reserve(num_indices);
- for (const int i : mask.index_range()) {
- if (mask[i] >= 0) {
- indices.append_unchecked(i);
- }
- }
- return IndexMask(indices);
-}
-
/**
* Copies the attributes with a domain in `domains` to `result_component`.
*/
@@ -191,12 +137,87 @@ static void copy_attributes_based_on_mask(const Map<AttributeIDRef, AttributeKin
using T = decltype(dummy);
VArray_Span<T> span{attribute.varray.typed<T>()};
MutableSpan<T> out_span = result_attribute.as_span<T>();
- copy_data(span, out_span, mask);
+ copy_data_based_on_mask(span, out_span, mask);
});
result_attribute.save();
}
}
+static void copy_attributes_based_on_map(const Map<AttributeIDRef, AttributeKind> &attributes,
+ const GeometryComponent &in_component,
+ GeometryComponent &result_component,
+ const AttributeDomain domain,
+ const Span<int> index_map)
+{
+ for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
+ const AttributeIDRef attribute_id = entry.key;
+ ReadAttributeLookup attribute = in_component.attribute_try_get_for_read(attribute_id);
+ if (!attribute) {
+ continue;
+ }
+
+ /* Only copy if it is on a domain we want. */
+ if (domain != attribute.domain) {
+ continue;
+ }
+ const CustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type());
+
+ OutputAttribute result_attribute = result_component.attribute_try_get_for_output_only(
+ attribute_id, attribute.domain, data_type);
+
+ if (!result_attribute) {
+ continue;
+ }
+
+ attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ VArray_Span<T> span{attribute.varray.typed<T>()};
+ MutableSpan<T> out_span = result_attribute.as_span<T>();
+ copy_data_based_on_map(span, out_span, index_map);
+ });
+ result_attribute.save();
+ }
+}
+
+static void copy_face_corner_attributes(const Map<AttributeIDRef, AttributeKind> &attributes,
+ const GeometryComponent &in_component,
+ GeometryComponent &out_component,
+ const int num_selected_loops,
+ const Span<int> selected_poly_indices,
+ const Mesh &mesh_in)
+{
+ Vector<int64_t> indices;
+ indices.reserve(num_selected_loops);
+ for (const int src_poly_index : selected_poly_indices) {
+ const MPoly &src_poly = mesh_in.mpoly[src_poly_index];
+ const int src_loop_start = src_poly.loopstart;
+ const int tot_loop = src_poly.totloop;
+ for (const int i : IndexRange(tot_loop)) {
+ indices.append_unchecked(src_loop_start + i);
+ }
+ }
+ copy_attributes_based_on_mask(
+ attributes, in_component, out_component, ATTR_DOMAIN_CORNER, IndexMask(indices));
+}
+
+static void copy_masked_vertices_to_new_mesh(const Mesh &src_mesh,
+ Mesh &dst_mesh,
+ Span<int> vertex_map)
+{
+ BLI_assert(src_mesh.totvert == vertex_map.size());
+ for (const int i_src : vertex_map.index_range()) {
+ const int i_dst = vertex_map[i_src];
+ if (i_dst == -1) {
+ continue;
+ }
+
+ const MVert &v_src = src_mesh.mvert[i_src];
+ MVert &v_dst = dst_mesh.mvert[i_dst];
+
+ v_dst = v_src;
+ }
+}
+
static void copy_masked_edges_to_new_mesh(const Mesh &src_mesh, Mesh &dst_mesh, Span<int> edge_map)
{
BLI_assert(src_mesh.totedge == edge_map.size());
@@ -215,6 +236,28 @@ static void copy_masked_edges_to_new_mesh(const Mesh &src_mesh, Mesh &dst_mesh,
}
}
+static void copy_masked_edges_to_new_mesh(const Mesh &src_mesh,
+ Mesh &dst_mesh,
+ Span<int> vertex_map,
+ Span<int> edge_map)
+{
+ BLI_assert(src_mesh.totvert == vertex_map.size());
+ BLI_assert(src_mesh.totedge == edge_map.size());
+ for (const int i_src : IndexRange(src_mesh.totedge)) {
+ const int i_dst = edge_map[i_src];
+ if (i_dst == -1) {
+ continue;
+ }
+
+ const MEdge &e_src = src_mesh.medge[i_src];
+ MEdge &e_dst = dst_mesh.medge[i_dst];
+
+ e_dst = e_src;
+ e_dst.v1 = vertex_map[e_src.v1];
+ e_dst.v2 = vertex_map[e_src.v2];
+ }
+}
+
/* Faces and edges changed but vertices are the same. */
static void copy_masked_polys_to_new_mesh(const Mesh &src_mesh,
Mesh &dst_mesh,
@@ -268,29 +311,56 @@ static void copy_masked_polys_to_new_mesh(const Mesh &src_mesh,
}
}
+static void copy_masked_polys_to_new_mesh(const Mesh &src_mesh,
+ Mesh &dst_mesh,
+ Span<int> vertex_map,
+ Span<int> edge_map,
+ Span<int> masked_poly_indices,
+ Span<int> new_loop_starts)
+{
+ for (const int i_dst : masked_poly_indices.index_range()) {
+ const int i_src = masked_poly_indices[i_dst];
+
+ const MPoly &mp_src = src_mesh.mpoly[i_src];
+ MPoly &mp_dst = dst_mesh.mpoly[i_dst];
+ const int i_ml_src = mp_src.loopstart;
+ const int i_ml_dst = new_loop_starts[i_dst];
+
+ const MLoop *ml_src = src_mesh.mloop + i_ml_src;
+ MLoop *ml_dst = dst_mesh.mloop + i_ml_dst;
+
+ mp_dst = mp_src;
+ mp_dst.loopstart = i_ml_dst;
+ for (int i : IndexRange(mp_src.totloop)) {
+ ml_dst[i].v = vertex_map[ml_src[i].v];
+ ml_dst[i].e = edge_map[ml_src[i].e];
+ }
+ }
+}
+
static void spline_copy_builtin_attributes(const Spline &spline,
Spline &r_spline,
const IndexMask mask)
{
- copy_data(spline.positions(), r_spline.positions(), mask);
- copy_data(spline.radii(), r_spline.radii(), mask);
- copy_data(spline.tilts(), r_spline.tilts(), mask);
+ copy_data_based_on_mask(spline.positions(), r_spline.positions(), mask);
+ copy_data_based_on_mask(spline.radii(), r_spline.radii(), mask);
+ copy_data_based_on_mask(spline.tilts(), r_spline.tilts(), mask);
switch (spline.type()) {
case Spline::Type::Poly:
break;
case Spline::Type::Bezier: {
const BezierSpline &src = static_cast<const BezierSpline &>(spline);
BezierSpline &dst = static_cast<BezierSpline &>(r_spline);
- copy_data(src.handle_positions_left(), dst.handle_positions_left(), mask);
- copy_data(src.handle_positions_right(), dst.handle_positions_right(), mask);
- copy_data(src.handle_types_left(), dst.handle_types_left(), mask);
- copy_data(src.handle_types_right(), dst.handle_types_right(), mask);
+ copy_data_based_on_mask(src.handle_positions_left(), dst.handle_positions_left(), mask);
+ copy_data_based_on_mask(src.handle_positions_right(), dst.handle_positions_right(), mask);
+ copy_data_based_on_mask(src.handle_types_left(), dst.handle_types_left(), mask);
+ copy_data_based_on_mask(src.handle_types_right(), dst.handle_types_right(), mask);
break;
}
case Spline::Type::NURBS: {
const NURBSpline &src = static_cast<const NURBSpline &>(spline);
NURBSpline &dst = static_cast<NURBSpline &>(r_spline);
- copy_data(src.weights(), dst.weights(), mask);
+ copy_data_based_on_mask(src.weights(), dst.weights(), mask);
break;
}
}
@@ -316,7 +386,7 @@ static void copy_dynamic_attributes(const CustomDataAttributes &src,
attribute_math::convert_to_static_type(new_attribute->type(), [&](auto dummy) {
using T = decltype(dummy);
- copy_data(src_attribute->typed<T>(), new_attribute->typed<T>(), mask);
+ copy_data_based_on_mask(src_attribute->typed<T>(), new_attribute->typed<T>(), mask);
});
return true;
},
@@ -986,6 +1056,23 @@ static void do_mesh_separation(GeometrySet &geometry_set,
copy_masked_edges_to_new_mesh(mesh_in, *mesh_out, vertex_map, edge_map);
copy_masked_polys_to_new_mesh(
mesh_in, *mesh_out, vertex_map, edge_map, selected_poly_indices, new_loop_starts);
+
+ /* Copy attributes. */
+ copy_attributes_based_on_map(
+ attributes, in_component, out_component, ATTR_DOMAIN_POINT, vertex_map);
+ copy_attributes_based_on_map(
+ attributes, in_component, out_component, ATTR_DOMAIN_EDGE, edge_map);
+ copy_attributes_based_on_mask(attributes,
+ in_component,
+ out_component,
+ ATTR_DOMAIN_FACE,
+ IndexMask(Vector<int64_t>(selected_poly_indices.as_span())));
+ copy_face_corner_attributes(attributes,
+ in_component,
+ out_component,
+ num_selected_loops,
+ selected_poly_indices,
+ mesh_in);
break;
}
case GEO_NODE_DELETE_GEOMETRY_MODE_EDGE_FACE: {
@@ -1041,22 +1128,25 @@ static void do_mesh_separation(GeometrySet &geometry_set,
/* Copy the selected parts of the mesh over to the new mesh. */
memcpy(mesh_out->mvert, mesh_in.mvert, mesh_in.totvert * sizeof(MVert));
- copy_attributes(attributes, in_component, out_component, {ATTR_DOMAIN_POINT});
copy_masked_edges_to_new_mesh(mesh_in, *mesh_out, edge_map);
copy_masked_polys_to_new_mesh(
mesh_in, *mesh_out, edge_map, selected_poly_indices, new_loop_starts);
- Vector<int64_t> indices;
+
+ /* Copy attributes. */
+ copy_attributes(attributes, in_component, out_component, {ATTR_DOMAIN_POINT});
+ copy_attributes_based_on_map(
+ attributes, in_component, out_component, ATTR_DOMAIN_EDGE, edge_map);
copy_attributes_based_on_mask(attributes,
in_component,
out_component,
- ATTR_DOMAIN_EDGE,
- index_mask_indices(edge_map, num_selected_edges, indices));
- copy_attributes_based_on_mask(
- attributes,
- in_component,
- out_component,
- ATTR_DOMAIN_FACE,
- index_mask_indices(selected_poly_indices, num_selected_polys, indices));
+ ATTR_DOMAIN_FACE,
+ IndexMask(Vector<int64_t>(selected_poly_indices.as_span())));
+ copy_face_corner_attributes(attributes,
+ in_component,
+ out_component,
+ num_selected_loops,
+ selected_poly_indices,
+ mesh_in);
break;
}
case GEO_NODE_DELETE_GEOMETRY_MODE_ONLY_FACE: {
@@ -1100,14 +1190,22 @@ static void do_mesh_separation(GeometrySet &geometry_set,
/* Copy the selected parts of the mesh over to the new mesh. */
memcpy(mesh_out->mvert, mesh_in.mvert, mesh_in.totvert * sizeof(MVert));
memcpy(mesh_out->medge, mesh_in.medge, mesh_in.totedge * sizeof(MEdge));
+ copy_masked_polys_to_new_mesh(mesh_in, *mesh_out, selected_poly_indices, new_loop_starts);
+
+ /* Copy attributes. */
copy_attributes(
attributes, in_component, out_component, {ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE});
- copy_masked_polys_to_new_mesh(mesh_in, *mesh_out, selected_poly_indices, new_loop_starts);
- Vector<int64_t> indices;
- const IndexMask mask = index_mask_indices(
- selected_poly_indices, num_selected_polys, indices);
- copy_attributes_based_on_mask(
- attributes, in_component, out_component, ATTR_DOMAIN_FACE, mask);
+ copy_attributes_based_on_mask(attributes,
+ in_component,
+ out_component,
+ ATTR_DOMAIN_FACE,
+ IndexMask(Vector<int64_t>(selected_poly_indices.as_span())));
+ copy_face_corner_attributes(attributes,
+ in_component,
+ out_component,
+ num_selected_loops,
+ selected_poly_indices,
+ mesh_in);
break;
}
}
@@ -1177,17 +1275,55 @@ void separate_geometry(GeometrySet &geometry_set,
r_is_error = !some_valid_domain && geometry_set.has_realized_data();
}
-static void geo_node_delete_geometry_exec(GeoNodeExecParams params)
+} // namespace blender::nodes
+
+namespace blender::nodes::node_geo_delete_geometry_cc {
+
+NODE_STORAGE_FUNCS(NodeGeometryDeleteGeometry)
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Bool>(N_("Selection"))
+ .default_value(true)
+ .hide_value()
+ .supports_field()
+ .description(N_("The parts of the geometry to be deleted"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
+}
+
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ const bNode *node = static_cast<bNode *>(ptr->data);
+ const NodeGeometryDeleteGeometry &storage = node_storage(*node);
+ const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain);
+
+ uiItemR(layout, ptr, "domain", 0, "", ICON_NONE);
+ /* Only show the mode when it is relevant. */
+ if (ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE, ATTR_DOMAIN_FACE)) {
+ uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
+ }
+}
+
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeGeometryDeleteGeometry *data = (NodeGeometryDeleteGeometry *)MEM_callocN(
+ sizeof(NodeGeometryDeleteGeometry), __func__);
+ data->domain = ATTR_DOMAIN_POINT;
+ data->mode = GEO_NODE_DELETE_GEOMETRY_MODE_ALL;
+
+ node->storage = data;
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
const Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
- const bNode &node = params.node();
- const NodeGeometryDeleteGeometry &storage = *(const NodeGeometryDeleteGeometry *)node.storage;
+ const NodeGeometryDeleteGeometry &storage = node_storage(params.node());
const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain);
- const GeometryNodeDeleteGeometryMode mode = static_cast<GeometryNodeDeleteGeometryMode>(
- storage.mode);
+ const GeometryNodeDeleteGeometryMode mode = (GeometryNodeDeleteGeometryMode)storage.mode;
bool all_is_error = false;
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
@@ -1204,10 +1340,12 @@ static void geo_node_delete_geometry_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_delete_geometry_cc
void register_node_type_geo_delete_geometry()
{
+ namespace file_ns = blender::nodes::node_geo_delete_geometry_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_DELETE_GEOMETRY, "Delete Geometry", NODE_CLASS_GEOMETRY, 0);
@@ -1217,10 +1355,10 @@ void register_node_type_geo_delete_geometry()
node_free_standard_storage,
node_copy_standard_storage);
- node_type_init(&ntype, blender::nodes::geo_node_delete_geometry_init);
+ node_type_init(&ntype, file_ns::node_init);
- ntype.declare = blender::nodes::geo_node_delete_geometry_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_delete_geometry_exec;
- ntype.draw_buttons = blender::nodes::geo_node_delete_geometry_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc
index b2c76b76590..3537b62c76e 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc
@@ -36,11 +36,9 @@
#include "node_geometry_util.hh"
-using blender::bke::GeometryInstanceGroup;
+namespace blender::nodes::node_geo_distribute_points_on_faces_cc {
-namespace blender::nodes {
-
-static void geo_node_point_distribute_points_on_faces_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH);
b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
@@ -60,9 +58,7 @@ static void geo_node_point_distribute_points_on_faces_declare(NodeDeclarationBui
b.add_output<decl::Vector>(N_("Rotation")).subtype(PROP_EULER).field_source();
}
-static void geo_node_point_distribute_points_on_faces_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "distribute_method", 0, "", ICON_NONE);
}
@@ -403,16 +399,12 @@ static Array<float> calc_full_density_factors_with_selection(const MeshComponent
GeometryComponentFieldContext field_context{component, attribute_domain};
const int domain_size = component.attribute_domain_size(attribute_domain);
- fn::FieldEvaluator selection_evaluator{field_context, domain_size};
- selection_evaluator.add(selection_field);
- selection_evaluator.evaluate();
- const IndexMask selection_mask = selection_evaluator.get_evaluated_as_mask(0);
-
Array<float> densities(domain_size, 0.0f);
- fn::FieldEvaluator density_evaluator{field_context, &selection_mask};
- density_evaluator.add_with_destination(density_field, densities.as_mutable_span());
- density_evaluator.evaluate();
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.set_selection(selection_field);
+ evaluator.add_with_destination(density_field, densities.as_mutable_span());
+ evaluator.evaluate();
return densities;
}
@@ -528,7 +520,7 @@ static void point_distribution_calculate(GeometrySet &geometry_set,
mesh_component, point_component, bary_coords, looptri_indices, attribute_outputs);
}
-static void geo_node_point_distribute_points_on_faces_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
@@ -570,10 +562,12 @@ static void geo_node_point_distribute_points_on_faces_exec(GeoNodeExecParams par
}
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_distribute_points_on_faces_cc
void register_node_type_geo_distribute_points_on_faces()
{
+ namespace file_ns = blender::nodes::node_geo_distribute_points_on_faces_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype,
@@ -581,10 +575,10 @@ void register_node_type_geo_distribute_points_on_faces()
"Distribute Points on Faces",
NODE_CLASS_GEOMETRY,
0);
- node_type_update(&ntype, blender::nodes::node_point_distribute_points_on_faces_update);
+ node_type_update(&ntype, file_ns::node_point_distribute_points_on_faces_update);
node_type_size(&ntype, 170, 100, 320);
- ntype.declare = blender::nodes::geo_node_point_distribute_points_on_faces_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_point_distribute_points_on_faces_exec;
- ntype.draw_buttons = blender::nodes::geo_node_point_distribute_points_on_faces_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc
new file mode 100644
index 00000000000..a3bbeca7af3
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc
@@ -0,0 +1,847 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "BLI_task.hh"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_attribute_math.hh"
+#include "BKE_mesh.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_dual_mesh_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>("Mesh").supported_type(GEO_COMPONENT_TYPE_MESH);
+ b.add_input<decl::Bool>("Keep Boundaries")
+ .default_value(false)
+ .description(
+ "Keep non-manifold boundaries of the input mesh in place by avoiding the dual "
+ "transformation there");
+ b.add_output<decl::Geometry>("Dual Mesh");
+}
+
+enum class EdgeType : int8_t {
+ Loose = 0, /* No polygons connected to it. */
+ Boundary = 1, /* An edge connected to exactly one polygon. */
+ Normal = 2, /* A normal edge (connected to two polygons). */
+ NonManifold = 3, /* An edge connected to more than two polygons. */
+};
+
+static EdgeType get_edge_type_with_added_neighbor(EdgeType old_type)
+{
+ switch (old_type) {
+ case EdgeType::Loose:
+ return EdgeType::Boundary;
+ case EdgeType::Boundary:
+ return EdgeType::Normal;
+ case EdgeType::Normal:
+ case EdgeType::NonManifold:
+ return EdgeType::NonManifold;
+ }
+ BLI_assert_unreachable();
+ return EdgeType::Loose;
+}
+
+enum class VertexType : int8_t {
+ Loose = 0, /* Either no edges connected or only loose edges connected. */
+ Normal = 1, /* A normal vertex. */
+ Boundary = 2, /* A vertex on a boundary edge. */
+ NonManifold = 3, /* A vertex on a non-manifold edge. */
+};
+
+static VertexType get_vertex_type_with_added_neighbor(VertexType old_type)
+{
+ switch (old_type) {
+ case VertexType::Loose:
+ return VertexType::Normal;
+ case VertexType::Normal:
+ return VertexType::Boundary;
+ case VertexType::Boundary:
+ case VertexType::NonManifold:
+ return VertexType::NonManifold;
+ }
+ BLI_assert_unreachable();
+ return VertexType::Loose;
+}
+
+/* Copy only where vertex_types is 'normal'. If keep boundaries is selected, also copy from
+ * boundary vertices. */
+template<typename T>
+static void copy_data_based_on_vertex_types(Span<T> data,
+ MutableSpan<T> r_data,
+ const Span<VertexType> vertex_types,
+ const bool keep_boundaries)
+{
+ if (keep_boundaries) {
+ int out_i = 0;
+ for (const int i : data.index_range()) {
+ if (ELEM(vertex_types[i], VertexType::Normal, VertexType::Boundary)) {
+ r_data[out_i] = data[i];
+ out_i++;
+ }
+ }
+ }
+ else {
+ int out_i = 0;
+ for (const int i : data.index_range()) {
+ if (vertex_types[i] == VertexType::Normal) {
+ r_data[out_i] = data[i];
+ out_i++;
+ }
+ }
+ }
+}
+
+template<typename T>
+static void copy_data_based_on_pairs(Span<T> data,
+ MutableSpan<T> r_data,
+ const Span<std::pair<int, int>> new_to_old_map)
+{
+ for (const std::pair<int, int> &pair : new_to_old_map) {
+ r_data[pair.first] = data[pair.second];
+ }
+}
+
+/* Copy using the map. */
+template<typename T>
+static void copy_data_based_on_new_to_old_map(Span<T> data,
+ MutableSpan<T> r_data,
+ const Span<int> new_to_old_map)
+{
+ for (const int i : r_data.index_range()) {
+ const int old_i = new_to_old_map[i];
+ r_data[i] = data[old_i];
+ }
+}
+
+/**
+ * Transfers the attributes from the original mesh to the new mesh using the following logic:
+ * - If the attribute was on the face domain it is now on the point domain, and this is true
+ * for all faces, so we can just copy these.
+ * - If the attribute was on the vertex domain there are three cases:
+ * - It was a 'bad' vertex so it is not in the dual mesh, and we can just ignore it
+ * - It was a normal vertex so it has a corresponding face in the dual mesh to which we can
+ * transfer.
+ * - It was a boundary vertex so it has a corresponding face, if keep_boundaries is true.
+ * Otherwise we can just ignore it.
+ * - If the attribute was on the edge domain we lookup for the new edges which edge it originated
+ * from using `new_to_old_edges_map`. We have to do it in this reverse order, because there can
+ * be more edges in the new mesh if keep boundaries is on.
+ * - We do the same thing for face corners as we do for edges.
+ *
+ * Some of the vertices (on the boundary) in the dual mesh don't come from faces, but from edges or
+ * vertices. For these the `boundary_vertex_to_relevant_face_map` is used, which maps them to the
+ * closest face.
+ */
+static void transfer_attributes(
+ const Map<AttributeIDRef, AttributeKind> &attributes,
+ const Span<VertexType> vertex_types,
+ const bool keep_boundaries,
+ const Span<int> new_to_old_edges_map,
+ const Span<int> new_to_old_face_corners_map,
+ const Span<std::pair<int, int>> boundary_vertex_to_relevant_face_map,
+ const GeometryComponent &src_component,
+ GeometryComponent &dst_component)
+{
+ for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
+ const AttributeIDRef attribute_id = entry.key;
+ ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read(attribute_id);
+ if (!src_attribute) {
+ continue;
+ }
+
+ AttributeDomain out_domain;
+ if (src_attribute.domain == ATTR_DOMAIN_FACE) {
+ out_domain = ATTR_DOMAIN_POINT;
+ }
+ else if (src_attribute.domain == ATTR_DOMAIN_POINT) {
+ out_domain = ATTR_DOMAIN_FACE;
+ }
+ else {
+ /* Edges and Face Corners. */
+ out_domain = src_attribute.domain;
+ }
+ const CustomDataType data_type = bke::cpp_type_to_custom_data_type(
+ src_attribute.varray.type());
+ OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
+ attribute_id, out_domain, data_type);
+
+ if (!dst_attribute) {
+ continue;
+ }
+
+ attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ VArray_Span<T> span{src_attribute.varray.typed<T>()};
+ MutableSpan<T> dst_span = dst_attribute.as_span<T>();
+ if (src_attribute.domain == ATTR_DOMAIN_FACE) {
+ dst_span.take_front(span.size()).copy_from(span);
+ if (keep_boundaries) {
+ copy_data_based_on_pairs(span, dst_span, boundary_vertex_to_relevant_face_map);
+ }
+ }
+ else if (src_attribute.domain == ATTR_DOMAIN_POINT) {
+ copy_data_based_on_vertex_types(span, dst_span, vertex_types, keep_boundaries);
+ }
+ else if (src_attribute.domain == ATTR_DOMAIN_EDGE) {
+ copy_data_based_on_new_to_old_map(span, dst_span, new_to_old_edges_map);
+ }
+ else {
+ copy_data_based_on_new_to_old_map(span, dst_span, new_to_old_face_corners_map);
+ }
+ });
+ dst_attribute.save();
+ }
+}
+
+/**
+ * Calculates the boundaries of the mesh. Boundary polygons are not computed since we don't need
+ * them later on. We use the following definitions:
+ * - An edge is on a boundary if it is connected to only one polygon.
+ * - A vertex is on a boundary if it is on an edge on a boundary.
+ */
+static void calc_boundaries(const Mesh &mesh,
+ MutableSpan<VertexType> r_vertex_types,
+ MutableSpan<EdgeType> r_edge_types)
+{
+ BLI_assert(r_vertex_types.size() == mesh.totvert);
+ BLI_assert(r_edge_types.size() == mesh.totedge);
+ r_vertex_types.fill(VertexType::Loose);
+ r_edge_types.fill(EdgeType::Loose);
+
+ /* Add up the number of polys connected to each edge. */
+ for (const int i : IndexRange(mesh.totpoly)) {
+ const MPoly &poly = mesh.mpoly[i];
+ for (const MLoop &loop : Span<MLoop>(&mesh.mloop[poly.loopstart], poly.totloop)) {
+ r_edge_types[loop.e] = get_edge_type_with_added_neighbor(r_edge_types[loop.e]);
+ }
+ }
+
+ /* Update vertices. */
+ for (const int i : IndexRange(mesh.totedge)) {
+ const EdgeType edge_type = r_edge_types[i];
+ if (edge_type == EdgeType::Loose) {
+ continue;
+ }
+ const MEdge &edge = mesh.medge[i];
+ if (edge_type == EdgeType::Boundary) {
+ r_vertex_types[edge.v1] = get_vertex_type_with_added_neighbor(r_vertex_types[edge.v1]);
+ r_vertex_types[edge.v2] = get_vertex_type_with_added_neighbor(r_vertex_types[edge.v2]);
+ }
+ else if (edge_type >= EdgeType::NonManifold) {
+ r_vertex_types[edge.v1] = VertexType::NonManifold;
+ r_vertex_types[edge.v2] = VertexType::NonManifold;
+ }
+ }
+
+ /* Normal verts are on a normal edge, and not on boundary edges or non-manifold edges. */
+ for (const int i : IndexRange(mesh.totedge)) {
+ const EdgeType edge_type = r_edge_types[i];
+ if (edge_type == EdgeType::Normal) {
+ const MEdge &edge = mesh.medge[i];
+ if (r_vertex_types[edge.v1] == VertexType::Loose) {
+ r_vertex_types[edge.v1] = VertexType::Normal;
+ }
+ if (r_vertex_types[edge.v2] == VertexType::Loose) {
+ r_vertex_types[edge.v2] = VertexType::Normal;
+ }
+ }
+ }
+}
+
+/**
+ * Stores the indices of the polygons connected to each vertex.
+ */
+static void create_vertex_poly_map(const Mesh &mesh,
+ MutableSpan<Vector<int>> r_vertex_poly_indices)
+{
+ for (const int i : IndexRange(mesh.totpoly)) {
+ const MPoly &poly = mesh.mpoly[i];
+ for (const MLoop &loop : Span<MLoop>(&mesh.mloop[poly.loopstart], poly.totloop)) {
+ r_vertex_poly_indices[loop.v].append(i);
+ }
+ }
+}
+
+/**
+ * Sorts the polygons connected to the given vertex based on polygon adjacency. The ordering is
+ * so such that the normals point in the same way as the original mesh. If the vertex is a
+ * boundary vertex, the first and last polygon have a boundary edge connected to the vertex. The
+ * `r_shared_edges` array at index i is set to the index of the shared edge between the i-th and
+ * `(i+1)-th` sorted polygon. Similarly the `r_sorted_corners` array at index i is set to the
+ * corner in the i-th sorted polygon.
+ *
+ * How the faces are sorted (see diagrams below):
+ * (For this explanation we'll assume all faces are oriented clockwise)
+ * (The vertex whose connected polygons we need to sort is "v0")
+ *
+ * \code{.unparsed}
+ * Normal case: Boundary Vertex case:
+ * v1 ----- v2 ----- v3 | | |
+ * | f3 | f0 | v2 ---- v4 --------- v3---
+ * | | | | / ,-' |
+ * v8 ----- v0 ----- v4 | f0 / f1 ,-' |
+ * | f2 | f1 | | / ,-' |
+ * | | | | / ,-' |
+ * v7 ----- v6 ----- v5 | / ,-' f2 |
+ * | /,-' |
+ * v0 ------------------ v1---
+ * \endcode
+ *
+ * - First we get the two corners of each face that have an edge which contains v0. A corner is
+ * simply a vertex followed by an edge. In this case for the face "f0" for example, we'd end up
+ * with the corners (v: v4, e: v4<->v0) and (v: v0, e: v0<->v2). Note that if the face was
+ * oriented counter-clockwise we'd end up with the corners (v: v0, e: v0<->v4) and (v: v2, e:
+ * v0<->v2) instead.
+ * - Then we need to choose one polygon as our first. If "v0" is not on a boundary we can just
+ * choose any polygon. If it is on a boundary some more care needs to be taken. Here we need to
+ * pick a polygon which lies on the boundary (in the diagram either f0 or f2). To choose between
+ * the two we need the next step.
+ * - In the normal case we use this polygon to set `shared_edge_i` which indicates the index of the
+ * shared edge between this polygon and the next one. There are two possible choices: v0<->v4 and
+ * v2<->v0. To choose we look at the corners. Since the edge v0<->v2 lies on the corner which has
+ * v0, we set `shared_edge_i` to the other edge (v0<->v4), such that the next face will be "f1"
+ * which is the next face in clockwise order.
+ * - In the boundary vertex case, we do something similar, but we are also forced to choose the
+ * edge which is not on the boundary. If this doesn't line up with orientation of the polygon, we
+ * know we'll need to choose the other boundary polygon as our first polygon. If the orientations
+ * don't line up there as well, it means that the mesh normals are not consistent, and we just
+ * have to force an orientation for ourselves. (Imagine if f0 is oriented counter-clockwise and
+ * f2 is oriented clockwise for example)
+ * - Next comes a loop where we look at the other faces and find the one which has the shared
+ * edge. Then we set the next shared edge to the other edge on the polygon connected to "v0", and
+ * continue. Because of the way we've chosen the first shared edge the order of the faces will
+ * have the same orientation as that of the first polygon.
+ * (In this case we'd have f0 -> f1 -> f2 -> f3 which also goes around clockwise).
+ * - Every time we determine a shared edge, we can also add a corner to `r_sorted_corners`. This
+ * will simply be the corner which doesn't contain the shared edge.
+ * - Finally if we are in the normal case we also need to add the last "shared edge" to close the
+ * loop.
+ */
+static void sort_vertex_polys(const Mesh &mesh,
+ const int vertex_index,
+ const bool boundary_vertex,
+ const Span<EdgeType> edge_types,
+ MutableSpan<int> connected_polygons,
+ MutableSpan<int> r_shared_edges,
+ MutableSpan<int> r_sorted_corners)
+{
+ if (connected_polygons.size() <= 2 && (!boundary_vertex || connected_polygons.size() == 0)) {
+ return;
+ }
+
+ /* For each polygon store the two corners whose edge contains the vertex. */
+ Array<std::pair<int, int>> poly_vertex_corners(connected_polygons.size());
+ for (const int i : connected_polygons.index_range()) {
+ const MPoly &poly = mesh.mpoly[connected_polygons[i]];
+ bool first_edge_done = false;
+ for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
+ const MLoop &loop = mesh.mloop[loop_index];
+ if (mesh.medge[loop.e].v1 == vertex_index || mesh.medge[loop.e].v2 == vertex_index) {
+ if (!first_edge_done) {
+ poly_vertex_corners[i].first = loop_index;
+ first_edge_done = true;
+ }
+ else {
+ poly_vertex_corners[i].second = loop_index;
+ break;
+ }
+ }
+ }
+ }
+
+ int shared_edge_i = -1;
+ /* Determine first polygon and orientation. For now the orientation of the whole loop depends
+ * on the one polygon we chose as first. It's probably not worth it to check every polygon in
+ * the loop to determine the 'average' orientation. */
+ if (boundary_vertex) {
+ /* Our first polygon needs to be one which has a boundary edge. */
+ for (const int i : connected_polygons.index_range()) {
+ const MLoop &first_loop = mesh.mloop[poly_vertex_corners[i].first];
+ const MLoop &second_loop = mesh.mloop[poly_vertex_corners[i].second];
+ if (edge_types[first_loop.e] == EdgeType::Boundary && first_loop.v == vertex_index) {
+ shared_edge_i = second_loop.e;
+ r_sorted_corners[0] = poly_vertex_corners[i].first;
+ std::swap(connected_polygons[i], connected_polygons[0]);
+ std::swap(poly_vertex_corners[i], poly_vertex_corners[0]);
+ break;
+ }
+ if (edge_types[second_loop.e] == EdgeType::Boundary && second_loop.v == vertex_index) {
+ shared_edge_i = first_loop.e;
+ r_sorted_corners[0] = poly_vertex_corners[i].second;
+ std::swap(connected_polygons[i], connected_polygons[0]);
+ std::swap(poly_vertex_corners[i], poly_vertex_corners[0]);
+ break;
+ }
+ }
+ if (shared_edge_i == -1) {
+ /* The rotation is inconsistent between the two polygons on the boundary. Just choose one
+ * of the polygon's orientation. */
+ for (const int i : connected_polygons.index_range()) {
+ const MLoop &first_loop = mesh.mloop[poly_vertex_corners[i].first];
+ const MLoop &second_loop = mesh.mloop[poly_vertex_corners[i].second];
+ if (edge_types[first_loop.e] == EdgeType::Boundary) {
+ shared_edge_i = second_loop.e;
+ r_sorted_corners[0] = poly_vertex_corners[i].first;
+ std::swap(connected_polygons[i], connected_polygons[0]);
+ std::swap(poly_vertex_corners[i], poly_vertex_corners[0]);
+ break;
+ }
+ if (edge_types[second_loop.e] == EdgeType::Boundary) {
+ shared_edge_i = first_loop.e;
+ r_sorted_corners[0] = poly_vertex_corners[i].second;
+ std::swap(connected_polygons[i], connected_polygons[0]);
+ std::swap(poly_vertex_corners[i], poly_vertex_corners[0]);
+ break;
+ }
+ }
+ }
+ }
+ else {
+ /* Any polygon can be the first. Just need to check the orientation.*/
+ const MLoop &first_loop = mesh.mloop[poly_vertex_corners[0].first];
+ const MLoop &second_loop = mesh.mloop[poly_vertex_corners[0].second];
+ if (first_loop.v == vertex_index) {
+ shared_edge_i = second_loop.e;
+ r_sorted_corners[0] = poly_vertex_corners[0].first;
+ }
+ else {
+ r_sorted_corners[0] = poly_vertex_corners[0].second;
+ shared_edge_i = first_loop.e;
+ }
+ }
+ BLI_assert(shared_edge_i != -1);
+
+ for (const int i : IndexRange(connected_polygons.size() - 1)) {
+ r_shared_edges[i] = shared_edge_i;
+
+ /* Look at the other polys to see if it has this shared edge. */
+ int j = i + 1;
+ for (; j < connected_polygons.size(); ++j) {
+ const MLoop &first_loop = mesh.mloop[poly_vertex_corners[j].first];
+ const MLoop &second_loop = mesh.mloop[poly_vertex_corners[j].second];
+ if (first_loop.e == shared_edge_i) {
+ r_sorted_corners[i + 1] = poly_vertex_corners[j].first;
+ shared_edge_i = second_loop.e;
+ break;
+ }
+ if (second_loop.e == shared_edge_i) {
+ r_sorted_corners[i + 1] = poly_vertex_corners[j].second;
+ shared_edge_i = first_loop.e;
+ break;
+ }
+ }
+
+ BLI_assert(j != connected_polygons.size());
+
+ std::swap(connected_polygons[i + 1], connected_polygons[j]);
+ std::swap(poly_vertex_corners[i + 1], poly_vertex_corners[j]);
+ }
+
+ if (!boundary_vertex) {
+ /* Shared edge between first and last polygon. */
+ r_shared_edges.last() = shared_edge_i;
+ }
+}
+
+/**
+ * Get the edge on the poly that contains the given vertex and is a boundary edge.
+ */
+static void boundary_edge_on_poly(const MPoly &poly,
+ const Mesh &mesh,
+ const int vertex_index,
+ const Span<EdgeType> edge_types,
+ int &r_edge)
+{
+ for (const MLoop &loop : Span<MLoop>(&mesh.mloop[poly.loopstart], poly.totloop)) {
+ if (edge_types[loop.e] == EdgeType::Boundary) {
+ const MEdge &edge = mesh.medge[loop.e];
+ if (edge.v1 == vertex_index || edge.v2 == vertex_index) {
+ r_edge = loop.e;
+ return;
+ }
+ }
+ }
+}
+
+/**
+ * Get the two edges on the poly that contain the given vertex and are boundary edges. The
+ * orientation of the poly is taken into account.
+ */
+static void boundary_edges_on_poly(const MPoly &poly,
+ const Mesh &mesh,
+ const int vertex_index,
+ const Span<EdgeType> edge_types,
+ int &r_edge1,
+ int &r_edge2)
+{
+ bool edge1_done = false;
+ /* This is set to true if the order in which we encounter the two edges is inconsistent with the
+ * orientation of the polygon. */
+ bool needs_swap = false;
+ for (const MLoop &loop : Span<MLoop>(&mesh.mloop[poly.loopstart], poly.totloop)) {
+ if (edge_types[loop.e] == EdgeType::Boundary) {
+ const MEdge &edge = mesh.medge[loop.e];
+ if (edge.v1 == vertex_index || edge.v2 == vertex_index) {
+ if (edge1_done) {
+ if (needs_swap) {
+ r_edge2 = r_edge1;
+ r_edge1 = loop.e;
+ }
+ else {
+ r_edge2 = loop.e;
+ }
+ return;
+ }
+ r_edge1 = loop.e;
+ edge1_done = true;
+ if (loop.v == vertex_index) {
+ needs_swap = true;
+ }
+ }
+ }
+ }
+}
+
+static void add_edge(const Mesh &mesh,
+ const int old_edge_i,
+ const int v1,
+ const int v2,
+ Vector<int> &new_to_old_edges_map,
+ Vector<MEdge> &new_edges,
+ Vector<int> &loop_edges)
+{
+ MEdge new_edge = MEdge(mesh.medge[old_edge_i]);
+ new_edge.v1 = v1;
+ new_edge.v2 = v2;
+ const int new_edge_i = new_edges.size();
+ new_to_old_edges_map.append(old_edge_i);
+ new_edges.append(new_edge);
+ loop_edges.append(new_edge_i);
+}
+
+/**
+ * Calculate the barycentric dual of a mesh. The dual is only "dual" in terms of connectivity,
+ * i.e. applying the function twice will give the same vertices, edges, and faces, but not the
+ * same positions. When the option "Keep Boundaries" is selected the connectivity is no
+ * longer dual.
+ *
+ * For the dual mesh of a manifold input mesh:
+ * - The vertices are at the centers of the faces of the input mesh.
+ * - The edges connect the two vertices created from the two faces next to the edge in the input
+ * mesh.
+ * - The faces are at the vertices of the input mesh.
+ *
+ * Some special cases are needed for boundaries and non-manifold geometry.
+ */
+static void calc_dual_mesh(GeometrySet &geometry_set,
+ const MeshComponent &in_component,
+ const bool keep_boundaries)
+{
+ const Mesh &mesh_in = *in_component.get_for_read();
+
+ Map<AttributeIDRef, AttributeKind> attributes;
+ geometry_set.gather_attributes_for_propagation(
+ {GEO_COMPONENT_TYPE_MESH}, GEO_COMPONENT_TYPE_MESH, false, attributes);
+
+ Array<VertexType> vertex_types(mesh_in.totvert);
+ Array<EdgeType> edge_types(mesh_in.totedge);
+ calc_boundaries(mesh_in, vertex_types, edge_types);
+ Array<Vector<int>> vertex_poly_indices(mesh_in.totvert);
+ Array<Array<int>> vertex_shared_edges(mesh_in.totvert);
+ Array<Array<int>> vertex_corners(mesh_in.totvert);
+ create_vertex_poly_map(mesh_in, vertex_poly_indices);
+ threading::parallel_for(vertex_poly_indices.index_range(), 512, [&](IndexRange range) {
+ for (const int i : range) {
+ if (vertex_types[i] == VertexType::Loose || vertex_types[i] >= VertexType::NonManifold ||
+ (!keep_boundaries && vertex_types[i] == VertexType::Boundary)) {
+ /* Bad vertex that we can't work with. */
+ continue;
+ }
+ MutableSpan<int> loop_indices = vertex_poly_indices[i];
+ Array<int> sorted_corners(loop_indices.size());
+ if (vertex_types[i] == VertexType::Normal) {
+ Array<int> shared_edges(loop_indices.size());
+ sort_vertex_polys(
+ mesh_in, i, false, edge_types, loop_indices, shared_edges, sorted_corners);
+ vertex_shared_edges[i] = shared_edges;
+ }
+ else {
+ Array<int> shared_edges(loop_indices.size() - 1);
+ sort_vertex_polys(
+ mesh_in, i, true, edge_types, loop_indices, shared_edges, sorted_corners);
+ vertex_shared_edges[i] = shared_edges;
+ }
+ vertex_corners[i] = sorted_corners;
+ }
+ });
+
+ Vector<float3> vertex_positions(mesh_in.totpoly);
+ for (const int i : IndexRange(mesh_in.totpoly)) {
+ const MPoly poly = mesh_in.mpoly[i];
+ BKE_mesh_calc_poly_center(
+ &poly, &mesh_in.mloop[poly.loopstart], mesh_in.mvert, vertex_positions[i]);
+ }
+
+ Array<int> boundary_edge_midpoint_index;
+ if (keep_boundaries) {
+ /* Only initialize when we actually need it. */
+ boundary_edge_midpoint_index.reinitialize(mesh_in.totedge);
+ /* We need to add vertices at the centers of boundary edges. */
+ for (const int i : IndexRange(mesh_in.totedge)) {
+ if (edge_types[i] == EdgeType::Boundary) {
+ float3 mid;
+ const MEdge &edge = mesh_in.medge[i];
+ mid_v3_v3v3(mid, mesh_in.mvert[edge.v1].co, mesh_in.mvert[edge.v2].co);
+ boundary_edge_midpoint_index[i] = vertex_positions.size();
+ vertex_positions.append(mid);
+ }
+ }
+ }
+
+ Vector<int> loop_lengths;
+ Vector<int> loops;
+ Vector<int> loop_edges;
+ Vector<MEdge> new_edges;
+ /* These are used to transfer attributes. */
+ Vector<int> new_to_old_face_corners_map;
+ Vector<int> new_to_old_edges_map;
+ /* Stores the index of the vertex in the dual and the face it should get the attribute from. */
+ Vector<std::pair<int, int>> boundary_vertex_to_relevant_face_map;
+ /* Since each edge in the dual (except the ones created with keep boundaries) comes from
+ * exactly one edge in the original, we can use this array to keep track of whether it still
+ * needs to be created or not. If it's not -1 it gives the index in `new_edges` of the dual
+ * edge. The edges coming from preserving the boundaries only get added once anyway, so we
+ * don't need a hashmap for that. */
+ Array<int> old_to_new_edges_map(mesh_in.totedge);
+ old_to_new_edges_map.fill(-1);
+ for (const int i : IndexRange(mesh_in.totvert)) {
+ if (vertex_types[i] == VertexType::Loose || vertex_types[i] >= VertexType::NonManifold ||
+ (!keep_boundaries && vertex_types[i] == VertexType::Boundary)) {
+ /* Bad vertex that we can't work with. */
+ continue;
+ }
+
+ Vector<int> loop_indices = vertex_poly_indices[i];
+ Span<int> shared_edges = vertex_shared_edges[i];
+ Span<int> sorted_corners = vertex_corners[i];
+ if (vertex_types[i] == VertexType::Normal) {
+ if (loop_indices.size() <= 2) {
+ /* We can't make a polygon from 2 vertices. */
+ continue;
+ }
+
+ /* Add edges in the loop. */
+ for (const int i : shared_edges.index_range()) {
+ const int old_edge_i = shared_edges[i];
+ if (old_to_new_edges_map[old_edge_i] == -1) {
+ /* This edge has not been created yet. */
+ MEdge new_edge = MEdge(mesh_in.medge[old_edge_i]);
+ new_edge.v1 = loop_indices[i];
+ new_edge.v2 = loop_indices[(i + 1) % loop_indices.size()];
+ new_to_old_edges_map.append(old_edge_i);
+ old_to_new_edges_map[old_edge_i] = new_edges.size();
+ new_edges.append(new_edge);
+ }
+ loop_edges.append(old_to_new_edges_map[old_edge_i]);
+ }
+
+ new_to_old_face_corners_map.extend(sorted_corners);
+ }
+ else {
+ /**
+ * The code handles boundary vertices like the vertex marked "V" in the diagram below.
+ * The first thing that happens is ordering the faces f1,f2 and f3 (stored in
+ * loop_indices), together with their shared edges e3 and e4 (which get stored in
+ * shared_edges). The ordering could end up being clockwise or counterclockwise, for this
+ * we'll assume that the ordering f1->f2->f3 is chosen. After that we add the edges in
+ * between the polygons, in this case the edges f1--f2, and f2--f3. Now we need to merge
+ * these with the boundary edges e1 and e2. To do this we create an edge from f3 to the
+ * midpoint of e2 (computed in a previous step), from this midpoint to V, from V to the
+ * midpoint of e1 and from the midpoint of e1 to f1.
+ *
+ * \code{.unparsed}
+ * | | | | | |
+ * v2 ---- v3 --------- v4--- v2 ---- v3 -------- v4---
+ * | f3 / ,-' | | / ,-'|
+ * | / f2 ,-' | | / ,-' |
+ * e2 | /e3 ,-' e4 | ====> M1-f3-/--f2-.,-' |
+ * | / ,-' | ====> | / ,-'\ |
+ * | / ,-' f1 | | / ,-' f1 |
+ * | /,-' | | /,-' | |
+ * V-------------------- v5--- V------------M2----- v5---
+ * \endcode
+ */
+
+ /* Add the edges in between the polys. */
+ for (const int i : shared_edges.index_range()) {
+ const int old_edge_i = shared_edges[i];
+ if (old_to_new_edges_map[old_edge_i] == -1) {
+ /* This edge has not been created yet. */
+ MEdge new_edge = MEdge(mesh_in.medge[old_edge_i]);
+ new_edge.v1 = loop_indices[i];
+ new_edge.v2 = loop_indices[i + 1];
+ new_to_old_edges_map.append(old_edge_i);
+ old_to_new_edges_map[old_edge_i] = new_edges.size();
+ new_edges.append(new_edge);
+ }
+ loop_edges.append(old_to_new_edges_map[old_edge_i]);
+ }
+
+ new_to_old_face_corners_map.extend(sorted_corners);
+
+ /* Add the vertex and the midpoints of the two boundary edges to the loop. */
+
+ /* Get the boundary edges. */
+ int edge1;
+ int edge2;
+ if (loop_indices.size() >= 2) {
+ /* The first boundary edge is at the end of the chain of polygons. */
+ boundary_edge_on_poly(mesh_in.mpoly[loop_indices.last()], mesh_in, i, edge_types, edge1);
+ boundary_edge_on_poly(mesh_in.mpoly[loop_indices.first()], mesh_in, i, edge_types, edge2);
+ }
+ else {
+ /* If there is only one polygon both edges are in that polygon. */
+ boundary_edges_on_poly(
+ mesh_in.mpoly[loop_indices[0]], mesh_in, i, edge_types, edge1, edge2);
+ }
+
+ const int last_face_center = loop_indices.last();
+ loop_indices.append(boundary_edge_midpoint_index[edge1]);
+ new_to_old_face_corners_map.append(sorted_corners.last());
+ const int first_midpoint = loop_indices.last();
+ if (old_to_new_edges_map[edge1] == -1) {
+ add_edge(mesh_in,
+ edge1,
+ last_face_center,
+ first_midpoint,
+ new_to_old_edges_map,
+ new_edges,
+ loop_edges);
+ old_to_new_edges_map[edge1] = new_edges.size() - 1;
+ boundary_vertex_to_relevant_face_map.append(std::pair(first_midpoint, last_face_center));
+ }
+ else {
+ loop_edges.append(old_to_new_edges_map[edge1]);
+ }
+ loop_indices.append(vertex_positions.size());
+ /* This is sort of arbitrary, but interpolating would be a lot harder to do. */
+ new_to_old_face_corners_map.append(sorted_corners.first());
+ boundary_vertex_to_relevant_face_map.append(
+ std::pair(loop_indices.last(), last_face_center));
+ vertex_positions.append(mesh_in.mvert[i].co);
+ const int boundary_vertex = loop_indices.last();
+ add_edge(mesh_in,
+ edge1,
+ first_midpoint,
+ boundary_vertex,
+ new_to_old_edges_map,
+ new_edges,
+ loop_edges);
+
+ loop_indices.append(boundary_edge_midpoint_index[edge2]);
+ new_to_old_face_corners_map.append(sorted_corners.first());
+ const int second_midpoint = loop_indices.last();
+ add_edge(mesh_in,
+ edge2,
+ boundary_vertex,
+ second_midpoint,
+ new_to_old_edges_map,
+ new_edges,
+ loop_edges);
+
+ if (old_to_new_edges_map[edge2] == -1) {
+ const int first_face_center = loop_indices.first();
+ add_edge(mesh_in,
+ edge2,
+ second_midpoint,
+ first_face_center,
+ new_to_old_edges_map,
+ new_edges,
+ loop_edges);
+ old_to_new_edges_map[edge2] = new_edges.size() - 1;
+ boundary_vertex_to_relevant_face_map.append(std::pair(second_midpoint, first_face_center));
+ }
+ else {
+ loop_edges.append(old_to_new_edges_map[edge2]);
+ }
+ }
+
+ loop_lengths.append(loop_indices.size());
+ for (const int j : loop_indices) {
+ loops.append(j);
+ }
+ }
+ Mesh *mesh_out = BKE_mesh_new_nomain(
+ vertex_positions.size(), new_edges.size(), 0, loops.size(), loop_lengths.size());
+ MeshComponent out_component;
+ out_component.replace(mesh_out, GeometryOwnershipType::Editable);
+ transfer_attributes(attributes,
+ vertex_types,
+ keep_boundaries,
+ new_to_old_edges_map,
+ new_to_old_face_corners_map,
+ boundary_vertex_to_relevant_face_map,
+ in_component,
+ out_component);
+
+ int loop_start = 0;
+ for (const int i : IndexRange(mesh_out->totpoly)) {
+ mesh_out->mpoly[i].loopstart = loop_start;
+ mesh_out->mpoly[i].totloop = loop_lengths[i];
+ loop_start += loop_lengths[i];
+ }
+ for (const int i : IndexRange(mesh_out->totloop)) {
+ mesh_out->mloop[i].v = loops[i];
+ mesh_out->mloop[i].e = loop_edges[i];
+ }
+ for (const int i : IndexRange(mesh_out->totvert)) {
+ copy_v3_v3(mesh_out->mvert[i].co, vertex_positions[i]);
+ }
+ memcpy(mesh_out->medge, new_edges.data(), sizeof(MEdge) * new_edges.size());
+ BKE_mesh_normals_tag_dirty(mesh_out);
+ geometry_set.replace_mesh(mesh_out);
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
+ const bool keep_boundaries = params.extract_input<bool>("Keep Boundaries");
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ if (geometry_set.has_mesh()) {
+ const MeshComponent &component = *geometry_set.get_component_for_read<MeshComponent>();
+ calc_dual_mesh(geometry_set, component, keep_boundaries);
+ }
+ });
+ params.set_output("Dual Mesh", std::move(geometry_set));
+}
+
+} // namespace blender::nodes::node_geo_dual_mesh_cc
+
+void register_node_type_geo_dual_mesh()
+{
+ namespace file_ns = blender::nodes::node_geo_dual_mesh_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(&ntype, GEO_NODE_DUAL_MESH, "Dual Mesh", NODE_CLASS_GEOMETRY, 0);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc b/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc
index ca6254be182..d23a18ba37b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc
@@ -22,9 +22,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_edge_split_cc {
-static void geo_node_edge_split_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH);
b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
@@ -57,7 +57,7 @@ static Mesh *mesh_edge_split(const Mesh &mesh, const IndexMask selection)
return result;
}
-static void geo_node_edge_split_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
@@ -82,14 +82,16 @@ static void geo_node_edge_split_exec(GeoNodeExecParams params)
params.set_output("Mesh", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_edge_split_cc
void register_node_type_geo_edge_split()
{
+ namespace file_ns = blender::nodes::node_geo_edge_split_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_SPLIT_EDGES, "Split Edges", NODE_CLASS_GEOMETRY, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_edge_split_exec;
- ntype.declare = blender::nodes::geo_node_edge_split_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_geometry_to_instance.cc b/source/blender/nodes/geometry/nodes/node_geo_geometry_to_instance.cc
new file mode 100644
index 00000000000..7faf104737f
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_geometry_to_instance.cc
@@ -0,0 +1,55 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_geometry_to_instance_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Geometry")).multi_input();
+ b.add_output<decl::Geometry>(N_("Instances"));
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ Vector<GeometrySet> geometries = params.extract_multi_input<GeometrySet>("Geometry");
+ GeometrySet instances_geometry;
+ InstancesComponent &instances_component =
+ instances_geometry.get_component_for_write<InstancesComponent>();
+ for (GeometrySet &geometry : geometries) {
+ geometry.ensure_owns_direct_data();
+ const int handle = instances_component.add_reference(std::move(geometry));
+ instances_component.add_instance(handle, float4x4::identity());
+ }
+ params.set_output("Instances", std::move(instances_geometry));
+}
+
+} // namespace blender::nodes::node_geo_geometry_to_instance_cc
+
+void register_node_type_geo_geometry_to_instance()
+{
+ namespace file_ns = blender::nodes::node_geo_geometry_to_instance_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(
+ &ntype, GEO_NODE_GEOMETRY_TO_INSTANCE, "Geometry to Instance", NODE_CLASS_GEOMETRY, 0);
+ node_type_size(&ntype, 160, 100, 300);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc b/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc
index 7bbe0716f78..0003f15854d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc
@@ -32,9 +32,11 @@
#include "UI_interface.h"
#include "UI_resources.h"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_image_texture_cc {
-static void geo_node_image_texture_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryImageTexture)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Image>(N_("Image")).hide_label();
b.add_input<decl::Vector>(N_("Vector"))
@@ -45,13 +47,13 @@ static void geo_node_image_texture_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Float>(N_("Alpha")).no_muted_links().dependent_field();
}
-static void geo_node_image_texture_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "interpolation", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
uiItemR(layout, ptr, "extension", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
}
-static void geo_node_image_texture_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeGeometryImageTexture *tex = (NodeGeometryImageTexture *)MEM_callocN(
sizeof(NodeGeometryImageTexture), __func__);
@@ -370,20 +372,15 @@ class ImageFieldsFunction : public fn::MultiFunction {
}
};
-static void geo_node_image_texture_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
- auto return_default = [&]() {
- params.set_output("Color", ColorGeometry4f(0.0f, 0.0f, 0.0f, 1.0f));
- params.set_output("Alpha", 1.0f);
- };
-
Image *image = params.get_input<Image *>("Image");
if (image == nullptr) {
- return return_default();
+ params.set_default_remaining_outputs();
+ return;
}
- const bNode &node = params.node();
- NodeGeometryImageTexture *data = (NodeGeometryImageTexture *)node.storage;
+ const NodeGeometryImageTexture &storage = node_storage(params.node());
ImageUser image_user;
BKE_imageuser_default(&image_user);
@@ -395,10 +392,11 @@ static void geo_node_image_texture_exec(GeoNodeExecParams params)
std::unique_ptr<ImageFieldsFunction> image_fn;
try {
image_fn = std::make_unique<ImageFieldsFunction>(
- data->interpolation, data->extension, *image, image_user);
+ storage.interpolation, storage.extension, *image, image_user);
}
catch (const std::runtime_error &) {
- return return_default();
+ params.set_default_remaining_outputs();
+ return;
}
Field<float3> vector_field = params.extract_input<Field<float3>>("Vector");
@@ -410,20 +408,22 @@ static void geo_node_image_texture_exec(GeoNodeExecParams params)
params.set_output("Alpha", Field<float>(image_op, 1));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_image_texture_cc
-void register_node_type_geo_image_texture(void)
+void register_node_type_geo_image_texture()
{
+ namespace file_ns = blender::nodes::node_geo_image_texture_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_IMAGE_TEXTURE, "Image Texture", NODE_CLASS_TEXTURE, 0);
- ntype.declare = blender::nodes::geo_node_image_texture_declare;
- ntype.draw_buttons = blender::nodes::geo_node_image_texture_layout;
- node_type_init(&ntype, blender::nodes::geo_node_image_texture_init);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_layout;
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(
&ntype, "NodeGeometryImageTexture", node_free_standard_storage, node_copy_standard_storage);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
- ntype.geometry_node_execute = blender::nodes::geo_node_image_texture_exec;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc
index b8df545d073..dae8fda2099 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc
@@ -16,15 +16,15 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_input_curve_handles_cc {
-static void geo_node_input_curve_handles_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Vector>(N_("Left")).field_source();
b.add_output<decl::Vector>(N_("Right")).field_source();
}
-static void geo_node_input_curve_handles_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Field<float3> left_field = AttributeFieldInput::Create<float3>("handle_left");
Field<float3> right_field = AttributeFieldInput::Create<float3>("handle_right");
@@ -32,15 +32,17 @@ static void geo_node_input_curve_handles_exec(GeoNodeExecParams params)
params.set_output("Right", std::move(right_field));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_input_curve_handles_cc
void register_node_type_geo_input_curve_handles()
{
+ namespace file_ns = blender::nodes::node_geo_input_curve_handles_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_INPUT_CURVE_HANDLES, "Curve Handle Positions", NODE_CLASS_INPUT, 0);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- ntype.geometry_node_execute = blender::nodes::geo_node_input_curve_handles_exec;
- ntype.declare = blender::nodes::geo_node_input_curve_handles_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_curve_tilt.cc b/source/blender/nodes/geometry/nodes/node_geo_input_curve_tilt.cc
index f32db3842db..5ba85b6f34e 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_curve_tilt.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_curve_tilt.cc
@@ -16,27 +16,29 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_input_curve_tilt_cc {
-static void geo_node_input_curve_tilt_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Float>(N_("Tilt")).field_source();
}
-static void geo_node_input_curve_tilt_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Field<float> tilt_field = AttributeFieldInput::Create<float>("tilt");
params.set_output("Tilt", std::move(tilt_field));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_input_curve_tilt_cc
void register_node_type_geo_input_curve_tilt()
{
+ namespace file_ns = blender::nodes::node_geo_input_curve_tilt_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_INPUT_CURVE_TILT, "Curve Tilt", NODE_CLASS_INPUT, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_input_curve_tilt_exec;
- ntype.declare = blender::nodes::geo_node_input_curve_tilt_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_id.cc b/source/blender/nodes/geometry/nodes/node_geo_input_id.cc
index 37d5bac0325..d2e103a093a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_id.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_id.cc
@@ -16,27 +16,29 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_input_id_cc {
-static void geo_node_input_id_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Int>(N_("ID")).field_source();
}
-static void geo_node_input_id_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Field<int> position_field{std::make_shared<bke::IDAttributeFieldInput>()};
params.set_output("ID", std::move(position_field));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_input_id_cc
void register_node_type_geo_input_id()
{
+ namespace file_ns = blender::nodes::node_geo_input_id_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_INPUT_ID, "ID", NODE_CLASS_INPUT, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_input_id_exec;
- ntype.declare = blender::nodes::geo_node_input_id_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_index.cc b/source/blender/nodes/geometry/nodes/node_geo_input_index.cc
index 6200ac5e7a8..74cddfc6a4a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_index.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_index.cc
@@ -16,27 +16,29 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_input_index_cc {
-static void geo_node_input_index_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Int>(N_("Index")).field_source();
}
-static void geo_node_input_index_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Field<int> index_field{std::make_shared<fn::IndexFieldInput>()};
params.set_output("Index", std::move(index_field));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_input_index_cc
void register_node_type_geo_input_index()
{
+ namespace file_ns = blender::nodes::node_geo_input_index_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_INPUT_INDEX, "Index", NODE_CLASS_INPUT, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_input_index_exec;
- ntype.declare = blender::nodes::geo_node_input_index_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_material.cc b/source/blender/nodes/geometry/nodes/node_geo_input_material.cc
index fc41188dee5..1b6e3c8fc68 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_material.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_material.cc
@@ -19,33 +19,35 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_input_material_cc {
-static void geo_node_input_material_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Material>(N_("Material"));
}
-static void geo_node_input_material_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "material", 0, "", ICON_NONE);
}
-static void geo_node_input_material_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Material *material = (Material *)params.node().id;
params.set_output("Material", material);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_input_material_cc
void register_node_type_geo_input_material()
{
+ namespace file_ns = blender::nodes::node_geo_input_material_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_INPUT_MATERIAL, "Material", NODE_CLASS_INPUT, 0);
- ntype.draw_buttons = blender::nodes::geo_node_input_material_layout;
- ntype.declare = blender::nodes::geo_node_input_material_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_input_material_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_material_index.cc b/source/blender/nodes/geometry/nodes/node_geo_input_material_index.cc
index 5d5d9e40032..4df218eb669 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_material_index.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_material_index.cc
@@ -16,27 +16,29 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_input_material_index_cc {
-static void geo_node_input_material_index_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Int>(N_("Material Index")).field_source();
}
-static void geo_node_input_material_index_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Field<int> material_index_field = AttributeFieldInput::Create<int>("material_index");
params.set_output("Material Index", std::move(material_index_field));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_input_material_index_cc
void register_node_type_geo_input_material_index()
{
+ namespace file_ns = blender::nodes::node_geo_input_material_index_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_INPUT_MATERIAL_INDEX, "Material Index", NODE_CLASS_INPUT, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_input_material_index_exec;
- ntype.declare = blender::nodes::geo_node_input_material_index_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc
new file mode 100644
index 00000000000..ede87252312
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc
@@ -0,0 +1,93 @@
+/*
+ * 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 "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_mesh.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_input_mesh_edge_neighbors_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Int>(N_("Face Count"))
+ .field_source()
+ .description(N_("Number of faces that contain the edge"));
+}
+
+class EdgeNeighborCountFieldInput final : public GeometryFieldInput {
+ public:
+ EdgeNeighborCountFieldInput()
+ : GeometryFieldInput(CPPType::get<int>(), "Edge Neighbor Count Field")
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
+ {
+ if (component.type() == GEO_COMPONENT_TYPE_MESH) {
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ const Mesh *mesh = mesh_component.get_for_read();
+ if (mesh == nullptr) {
+ return {};
+ }
+
+ Array<int> face_count(mesh->totedge, 0);
+ for (const int i : IndexRange(mesh->totloop)) {
+ face_count[mesh->mloop[i].e]++;
+ }
+
+ return mesh_component.attribute_try_adapt_domain<int>(
+ VArray<int>::ForContainer(std::move(face_count)), ATTR_DOMAIN_EDGE, domain);
+ }
+ return {};
+ }
+
+ uint64_t hash() const override
+ {
+ /* Some random constant hash. */
+ return 985671075;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ return dynamic_cast<const EdgeNeighborCountFieldInput *>(&other) != nullptr;
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ Field<int> neighbor_count_field{std::make_shared<EdgeNeighborCountFieldInput>()};
+ params.set_output("Face Count", std::move(neighbor_count_field));
+}
+
+} // namespace blender::nodes::node_geo_input_mesh_edge_neighbors_cc
+
+void register_node_type_geo_input_mesh_edge_neighbors()
+{
+ namespace file_ns = blender::nodes::node_geo_input_mesh_edge_neighbors_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(
+ &ntype, GEO_NODE_INPUT_MESH_EDGE_NEIGHBORS, "Edge Neighbors", NODE_CLASS_INPUT, 0);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc
new file mode 100644
index 00000000000..473bef63e92
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc
@@ -0,0 +1,188 @@
+/*
+ * 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 "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_mesh.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_input_mesh_edge_vertices_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Int>(N_("Vertex Index 1"))
+ .field_source()
+ .description(N_("The index of the first vertex in the edge"));
+ b.add_output<decl::Int>(N_("Vertex Index 2"))
+ .field_source()
+ .description(N_("The index of the second vertex in the edge"));
+ b.add_output<decl::Vector>(N_("Position 1"))
+ .field_source()
+ .description(N_("The position of the first vertex in the edge"));
+ b.add_output<decl::Vector>(N_("Position 2"))
+ .field_source()
+ .description(N_("The position of the second vertex in the edge"));
+}
+
+enum VertexNumber { VERTEX_ONE, VERTEX_TWO };
+
+static VArray<int> construct_edge_vertices_gvarray(const MeshComponent &component,
+ const VertexNumber vertex,
+ const AttributeDomain domain)
+{
+ const Mesh *mesh = component.get_for_read();
+ if (mesh == nullptr) {
+ return {};
+ }
+ if (domain == ATTR_DOMAIN_EDGE) {
+
+ if (vertex == VERTEX_ONE) {
+ return VArray<int>::ForFunc(mesh->totpoly,
+ [mesh](const int i) -> int { return mesh->medge[i].v1; });
+ }
+ return VArray<int>::ForFunc(mesh->totpoly,
+ [mesh](const int i) -> int { return mesh->medge[i].v2; });
+ }
+ return {};
+}
+
+class EdgeVerticesFieldInput final : public GeometryFieldInput {
+ private:
+ VertexNumber vertex_;
+
+ public:
+ EdgeVerticesFieldInput(VertexNumber vertex)
+ : GeometryFieldInput(CPPType::get<int>(), "Edge Vertices Field"), vertex_(vertex)
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
+ {
+ if (component.type() == GEO_COMPONENT_TYPE_MESH) {
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ return construct_edge_vertices_gvarray(mesh_component, vertex_, domain);
+ }
+ return {};
+ }
+
+ uint64_t hash() const override
+ {
+ return vertex_ == VERTEX_ONE ? 23847562893465 : 92384598734567;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ if (const EdgeVerticesFieldInput *other_field = dynamic_cast<const EdgeVerticesFieldInput *>(
+ &other)) {
+ return vertex_ == other_field->vertex_;
+ }
+ return false;
+ }
+};
+
+static VArray<float3> construct_edge_positions_gvarray(const MeshComponent &component,
+ const VertexNumber vertex,
+ const AttributeDomain domain)
+{
+ const Mesh *mesh = component.get_for_read();
+ if (mesh == nullptr) {
+ return {};
+ }
+
+ if (vertex == VERTEX_ONE) {
+ return component.attribute_try_adapt_domain<float3>(
+ VArray<float3>::ForFunc(
+ mesh->totedge,
+ [mesh](const int i) { return float3(mesh->mvert[mesh->medge[i].v1].co); }),
+ ATTR_DOMAIN_EDGE,
+ domain);
+ }
+ return component.attribute_try_adapt_domain<float3>(
+ VArray<float3>::ForFunc(
+ mesh->totedge,
+ [mesh](const int i) { return float3(mesh->mvert[mesh->medge[i].v2].co); }),
+ ATTR_DOMAIN_EDGE,
+ domain);
+}
+
+class EdgePositionFieldInput final : public GeometryFieldInput {
+ private:
+ VertexNumber vertex_;
+
+ public:
+ EdgePositionFieldInput(VertexNumber vertex)
+ : GeometryFieldInput(CPPType::get<float3>(), "Edge Position Field"), vertex_(vertex)
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
+ {
+ if (component.type() == GEO_COMPONENT_TYPE_MESH) {
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ return construct_edge_positions_gvarray(mesh_component, vertex_, domain);
+ }
+ return {};
+ }
+
+ uint64_t hash() const override
+ {
+ return vertex_ == VERTEX_ONE ? 987456978362 : 374587679866;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ if (const EdgePositionFieldInput *other_field = dynamic_cast<const EdgePositionFieldInput *>(
+ &other)) {
+ return vertex_ == other_field->vertex_;
+ }
+ return false;
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ Field<int> vertex_field_1{std::make_shared<EdgeVerticesFieldInput>(VERTEX_ONE)};
+ Field<int> vertex_field_2{std::make_shared<EdgeVerticesFieldInput>(VERTEX_TWO)};
+ Field<float3> position_field_1{std::make_shared<EdgePositionFieldInput>(VERTEX_ONE)};
+ Field<float3> position_field_2{std::make_shared<EdgePositionFieldInput>(VERTEX_TWO)};
+
+ params.set_output("Vertex Index 1", std::move(vertex_field_1));
+ params.set_output("Vertex Index 2", std::move(vertex_field_2));
+ params.set_output("Position 1", std::move(position_field_1));
+ params.set_output("Position 2", std::move(position_field_2));
+}
+
+} // namespace blender::nodes::node_geo_input_mesh_edge_vertices_cc
+
+void register_node_type_geo_input_mesh_edge_vertices()
+{
+ namespace file_ns = blender::nodes::node_geo_input_mesh_edge_vertices_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(
+ &ntype, GEO_NODE_INPUT_MESH_EDGE_VERTICES, "Edge Vertices", NODE_CLASS_INPUT, 0);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc
new file mode 100644
index 00000000000..538b9e9682d
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc
@@ -0,0 +1,96 @@
+/*
+ * 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 "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_mesh.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_input_mesh_face_area_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Float>(N_("Area"))
+ .field_source()
+ .description(N_("The surface area of each of the mesh's faces"));
+}
+
+static VArray<float> construct_face_area_gvarray(const MeshComponent &component,
+ const AttributeDomain domain)
+{
+ const Mesh *mesh = component.get_for_read();
+ if (mesh == nullptr) {
+ return {};
+ }
+
+ auto area_fn = [mesh](const int i) -> float {
+ const MPoly *mp = &mesh->mpoly[i];
+ return BKE_mesh_calc_poly_area(mp, &mesh->mloop[mp->loopstart], mesh->mvert);
+ };
+
+ return component.attribute_try_adapt_domain<float>(
+ VArray<float>::ForFunc(mesh->totpoly, area_fn), ATTR_DOMAIN_FACE, domain);
+}
+
+class FaceAreaFieldInput final : public GeometryFieldInput {
+ public:
+ FaceAreaFieldInput() : GeometryFieldInput(CPPType::get<float>(), "Face Area Field")
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
+ {
+ if (component.type() == GEO_COMPONENT_TYPE_MESH) {
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ return construct_face_area_gvarray(mesh_component, domain);
+ }
+ return {};
+ }
+
+ uint64_t hash() const override
+ {
+ /* Some random constant hash. */
+ return 1346334523;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ return dynamic_cast<const FaceAreaFieldInput *>(&other) != nullptr;
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ params.set_output("Area", Field<float>(std::make_shared<FaceAreaFieldInput>()));
+}
+
+} // namespace blender::nodes::node_geo_input_mesh_face_area_cc
+
+void register_node_type_geo_input_mesh_face_area()
+{
+ namespace file_ns = blender::nodes::node_geo_input_mesh_face_area_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_MESH_FACE_AREA, "Face Area", NODE_CLASS_INPUT, 0);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc
new file mode 100644
index 00000000000..80bb25dc7ca
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc
@@ -0,0 +1,158 @@
+/*
+ * 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 "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_mesh.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_input_mesh_face_neighbors_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Int>(N_("Vertex Count"))
+ .field_source()
+ .description(N_("Number of edges or points in the face"));
+ b.add_output<decl::Int>(N_("Face Count"))
+ .field_source()
+ .description(N_("Number of faces which share an edge with the face"));
+}
+
+static VArray<int> construct_neighbor_count_gvarray(const MeshComponent &component,
+ const AttributeDomain domain)
+{
+ const Mesh *mesh = component.get_for_read();
+ if (mesh == nullptr) {
+ return {};
+ }
+
+ Array<int> edge_count(mesh->totedge, 0);
+ for (const int i : IndexRange(mesh->totloop)) {
+ edge_count[mesh->mloop[i].e]++;
+ }
+
+ Array<int> poly_count(mesh->totpoly, 0);
+ for (const int poly_num : IndexRange(mesh->totpoly)) {
+ MPoly &poly = mesh->mpoly[poly_num];
+ for (const int loop_num : IndexRange(poly.loopstart, poly.totloop)) {
+ poly_count[poly_num] += edge_count[mesh->mloop[loop_num].e] - 1;
+ }
+ }
+
+ return component.attribute_try_adapt_domain<int>(
+ VArray<int>::ForContainer(std::move(poly_count)), ATTR_DOMAIN_FACE, domain);
+}
+
+class FaceNeighborCountFieldInput final : public GeometryFieldInput {
+ public:
+ FaceNeighborCountFieldInput()
+ : GeometryFieldInput(CPPType::get<int>(), "Face Neighbor Count Field")
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
+ {
+ if (component.type() == GEO_COMPONENT_TYPE_MESH) {
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ return construct_neighbor_count_gvarray(mesh_component, domain);
+ }
+ return {};
+ }
+
+ uint64_t hash() const override
+ {
+ /* Some random constant hash. */
+ return 823543774;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ return dynamic_cast<const FaceNeighborCountFieldInput *>(&other) != nullptr;
+ }
+};
+
+static VArray<int> construct_vertex_count_gvarray(const MeshComponent &component,
+ const AttributeDomain domain)
+{
+ const Mesh *mesh = component.get_for_read();
+ if (mesh == nullptr) {
+ return {};
+ }
+
+ return component.attribute_try_adapt_domain<int>(
+ VArray<int>::ForFunc(mesh->totpoly,
+ [mesh](const int i) -> float { return mesh->mpoly[i].totloop; }),
+ ATTR_DOMAIN_FACE,
+ domain);
+}
+
+class FaceVertexCountFieldInput final : public GeometryFieldInput {
+ public:
+ FaceVertexCountFieldInput() : GeometryFieldInput(CPPType::get<int>(), "Vertex Count Field")
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
+ {
+ if (component.type() == GEO_COMPONENT_TYPE_MESH) {
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ return construct_vertex_count_gvarray(mesh_component, domain);
+ }
+ return {};
+ }
+
+ uint64_t hash() const override
+ {
+ /* Some random constant hash. */
+ return 236235463634;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ return dynamic_cast<const FaceVertexCountFieldInput *>(&other) != nullptr;
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ Field<int> vertex_count_field{std::make_shared<FaceVertexCountFieldInput>()};
+ Field<int> neighbor_count_field{std::make_shared<FaceNeighborCountFieldInput>()};
+ params.set_output("Vertex Count", std::move(vertex_count_field));
+ params.set_output("Face Count", std::move(neighbor_count_field));
+}
+
+} // namespace blender::nodes::node_geo_input_mesh_face_neighbors_cc
+
+void register_node_type_geo_input_mesh_face_neighbors()
+{
+ namespace file_ns = blender::nodes::node_geo_input_mesh_face_neighbors_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(
+ &ntype, GEO_NODE_INPUT_MESH_FACE_NEIGHBORS, "Face Neighbors", NODE_CLASS_INPUT, 0);
+ node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc
new file mode 100644
index 00000000000..3c713ef6ca9
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc
@@ -0,0 +1,101 @@
+/*
+ * 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 "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_mesh.h"
+
+#include "BLI_disjoint_set.hh"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_input_mesh_island_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Int>(N_("Index"))
+ .field_source()
+ .description(N_("Island indices are based on the order of the lowest-numbered vertex "
+ "contained in each island"));
+}
+
+class IslandFieldInput final : public GeometryFieldInput {
+ public:
+ IslandFieldInput() : GeometryFieldInput(CPPType::get<int>(), "Island Index")
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
+ {
+ if (component.type() != GEO_COMPONENT_TYPE_MESH) {
+ return {};
+ }
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ const Mesh *mesh = mesh_component.get_for_read();
+ if (mesh == nullptr) {
+ return {};
+ }
+
+ DisjointSet islands(mesh->totvert);
+ for (const int i : IndexRange(mesh->totedge)) {
+ islands.join(mesh->medge[i].v1, mesh->medge[i].v2);
+ }
+
+ Array<int> output(mesh->totvert);
+ VectorSet<int> ordered_roots;
+ for (const int i : IndexRange(mesh->totvert)) {
+ const int64_t root = islands.find_root(i);
+ output[i] = ordered_roots.index_of_or_add(root);
+ }
+
+ return mesh_component.attribute_try_adapt_domain<int>(
+ VArray<int>::ForContainer(std::move(output)), ATTR_DOMAIN_POINT, domain);
+ }
+
+ uint64_t hash() const override
+ {
+ /* Some random constant hash. */
+ return 635467354;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ return dynamic_cast<const IslandFieldInput *>(&other) != nullptr;
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ Field<int> island_field{std::make_shared<IslandFieldInput>()};
+ params.set_output("Index", std::move(island_field));
+}
+
+} // namespace blender::nodes::node_geo_input_mesh_island_cc
+
+void register_node_type_geo_input_mesh_island()
+{
+ namespace file_ns = blender::nodes::node_geo_input_mesh_island_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_MESH_ISLAND, "Mesh Island", NODE_CLASS_INPUT, 0);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc
new file mode 100644
index 00000000000..05140c92205
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc
@@ -0,0 +1,155 @@
+/*
+ * 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 "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_mesh.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_input_mesh_vertex_neighbors_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Int>(N_("Vertex Count"))
+ .field_source()
+ .description(N_("Vertex count and edge count are equal"));
+ b.add_output<decl::Int>(N_("Face Count"))
+ .field_source()
+ .description(N_("Number of faces that contain the vertex"));
+}
+
+static VArray<int> construct_vertex_count_gvarray(const MeshComponent &component,
+ const AttributeDomain domain)
+{
+ const Mesh *mesh = component.get_for_read();
+ if (mesh == nullptr) {
+ return {};
+ }
+
+ if (domain == ATTR_DOMAIN_POINT) {
+ Array<int> vertices(mesh->totvert, 0);
+ for (const int i : IndexRange(mesh->totedge)) {
+ vertices[mesh->medge[i].v1]++;
+ vertices[mesh->medge[i].v2]++;
+ }
+ return VArray<int>::ForContainer(std::move(vertices));
+ }
+ return {};
+}
+
+class VertexCountFieldInput final : public GeometryFieldInput {
+ public:
+ VertexCountFieldInput() : GeometryFieldInput(CPPType::get<int>(), "Vertex Count Field")
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
+ {
+ if (component.type() == GEO_COMPONENT_TYPE_MESH) {
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ return construct_vertex_count_gvarray(mesh_component, domain);
+ }
+ return {};
+ }
+
+ uint64_t hash() const override
+ {
+ /* Some random constant hash. */
+ return 23574528465;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ return dynamic_cast<const VertexCountFieldInput *>(&other) != nullptr;
+ }
+};
+
+static VArray<int> construct_face_count_gvarray(const MeshComponent &component,
+ const AttributeDomain domain)
+{
+ const Mesh *mesh = component.get_for_read();
+ if (mesh == nullptr) {
+ return {};
+ }
+
+ if (domain == ATTR_DOMAIN_POINT) {
+ Array<int> vertices(mesh->totvert, 0);
+ for (const int i : IndexRange(mesh->totloop)) {
+ int vertex = mesh->mloop[i].v;
+ vertices[vertex]++;
+ }
+ return VArray<int>::ForContainer(std::move(vertices));
+ }
+ return {};
+}
+
+class VertexFaceCountFieldInput final : public GeometryFieldInput {
+ public:
+ VertexFaceCountFieldInput() : GeometryFieldInput(CPPType::get<int>(), "Vertex Face Count Field")
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
+ {
+ if (component.type() == GEO_COMPONENT_TYPE_MESH) {
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ return construct_face_count_gvarray(mesh_component, domain);
+ }
+ return {};
+ }
+
+ uint64_t hash() const override
+ {
+ /* Some random constant hash. */
+ return 3462374322;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ return dynamic_cast<const VertexFaceCountFieldInput *>(&other) != nullptr;
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ Field<int> vertex_field{std::make_shared<VertexCountFieldInput>()};
+ Field<int> face_field{std::make_shared<VertexFaceCountFieldInput>()};
+
+ params.set_output("Vertex Count", std::move(vertex_field));
+ params.set_output("Face Count", std::move(face_field));
+}
+
+} // namespace blender::nodes::node_geo_input_mesh_vertex_neighbors_cc
+
+void register_node_type_geo_input_mesh_vertex_neighbors()
+{
+ namespace file_ns = blender::nodes::node_geo_input_mesh_vertex_neighbors_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(
+ &ntype, GEO_NODE_INPUT_MESH_VERTEX_NEIGHBORS, "Vertex Neighbors", NODE_CLASS_INPUT, 0);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc b/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc
index 6c95ad73bf7..1cc508d9d9d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc
@@ -24,9 +24,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_input_normal_cc {
-static void geo_node_input_normal_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Vector>(N_("Normal")).field_source();
}
@@ -93,8 +93,7 @@ static VArray<float3> mesh_vertex_normals(const Mesh &mesh,
static VArray<float3> construct_mesh_normals_gvarray(const MeshComponent &mesh_component,
const Mesh &mesh,
const IndexMask mask,
- const AttributeDomain domain,
- ResourceScope &UNUSED(scope))
+ const AttributeDomain domain)
{
Span<MVert> verts{mesh.mvert, mesh.totvert};
Span<MEdge> edges{mesh.medge, mesh.totedge};
@@ -199,8 +198,7 @@ static Array<float3> curve_normal_point_domain(const CurveEval &curve)
}
static VArray<float3> construct_curve_normal_gvarray(const CurveComponent &component,
- const AttributeDomain domain,
- ResourceScope &UNUSED(scope))
+ const AttributeDomain domain)
{
const CurveEval *curve = component.get_for_read();
if (curve == nullptr) {
@@ -231,36 +229,29 @@ static VArray<float3> construct_curve_normal_gvarray(const CurveComponent &compo
return nullptr;
}
-class NormalFieldInput final : public fn::FieldInput {
+class NormalFieldInput final : public GeometryFieldInput {
public:
- NormalFieldInput() : fn::FieldInput(CPPType::get<float3>(), "Normal node")
+ NormalFieldInput() : GeometryFieldInput(CPPType::get<float3>(), "Normal node")
{
category_ = Category::Generated;
}
- GVArray get_varray_for_context(const fn::FieldContext &context,
- IndexMask mask,
- ResourceScope &scope) const final
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask mask) const final
{
- if (const GeometryComponentFieldContext *geometry_context =
- dynamic_cast<const GeometryComponentFieldContext *>(&context)) {
-
- const GeometryComponent &component = geometry_context->geometry_component();
- const AttributeDomain domain = geometry_context->domain();
-
- if (component.type() == GEO_COMPONENT_TYPE_MESH) {
- const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
- const Mesh *mesh = mesh_component.get_for_read();
- if (mesh == nullptr) {
- return {};
- }
-
- return construct_mesh_normals_gvarray(mesh_component, *mesh, mask, domain, scope);
- }
- if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
- const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
- return construct_curve_normal_gvarray(curve_component, domain, scope);
+ if (component.type() == GEO_COMPONENT_TYPE_MESH) {
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ const Mesh *mesh = mesh_component.get_for_read();
+ if (mesh == nullptr) {
+ return {};
}
+
+ return construct_mesh_normals_gvarray(mesh_component, *mesh, mask, domain);
+ }
+ if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
+ const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
+ return construct_curve_normal_gvarray(curve_component, domain);
}
return {};
}
@@ -277,20 +268,22 @@ class NormalFieldInput final : public fn::FieldInput {
}
};
-static void geo_node_input_normal_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Field<float3> normal_field{std::make_shared<NormalFieldInput>()};
params.set_output("Normal", std::move(normal_field));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_input_normal_cc
void register_node_type_geo_input_normal()
{
+ namespace file_ns = blender::nodes::node_geo_input_normal_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_INPUT_NORMAL, "Normal", NODE_CLASS_INPUT, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_input_normal_exec;
- ntype.declare = blender::nodes::geo_node_input_normal_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_position.cc b/source/blender/nodes/geometry/nodes/node_geo_input_position.cc
index a8477d4bc4f..8322831a871 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_position.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_position.cc
@@ -16,27 +16,29 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_input_position_cc {
-static void geo_node_input_position_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Vector>(N_("Position")).field_source();
}
-static void geo_node_input_position_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Field<float3> position_field{AttributeFieldInput::Create<float3>("position")};
params.set_output("Position", std::move(position_field));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_input_position_cc
void register_node_type_geo_input_position()
{
+ namespace file_ns = blender::nodes::node_geo_input_position_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_INPUT_POSITION, "Position", NODE_CLASS_INPUT, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_input_position_exec;
- ntype.declare = blender::nodes::geo_node_input_position_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_radius.cc b/source/blender/nodes/geometry/nodes/node_geo_input_radius.cc
index 6d2c4c38cbe..26fb74f5a5b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_radius.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_radius.cc
@@ -16,27 +16,29 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_input_radius_cc {
-static void geo_node_input_radius_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Float>(N_("Radius")).default_value(1.0f).min(0.0f).field_source();
}
-static void geo_node_input_radius_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Field<float> radius_field = AttributeFieldInput::Create<float>("radius");
params.set_output("Radius", std::move(radius_field));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_input_radius_cc
void register_node_type_geo_input_radius()
{
+ namespace file_ns = blender::nodes::node_geo_input_radius_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_INPUT_RADIUS, "Radius", NODE_CLASS_INPUT, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_input_radius_exec;
- ntype.declare = blender::nodes::geo_node_input_radius_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_scene_time.cc b/source/blender/nodes/geometry/nodes/node_geo_input_scene_time.cc
new file mode 100644
index 00000000000..cfc1a81f7b9
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_scene_time.cc
@@ -0,0 +1,50 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "BKE_scene.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_input_scene_time_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Float>(N_("Seconds"));
+ b.add_output<decl::Float>(N_("Frame"));
+}
+
+static void node_exec(GeoNodeExecParams params)
+{
+ const Scene *scene = DEG_get_input_scene(params.depsgraph());
+ const float scene_ctime = BKE_scene_ctime_get(scene);
+ const double frame_rate = (((double)scene->r.frs_sec) / (double)scene->r.frs_sec_base);
+ params.set_output("Seconds", float(scene_ctime / frame_rate));
+ params.set_output("Frame", scene_ctime);
+}
+
+} // namespace blender::nodes::node_geo_input_scene_time_cc
+
+void register_node_type_geo_input_scene_time()
+{
+ static bNodeType ntype;
+ namespace file_ns = blender::nodes::node_geo_input_scene_time_cc;
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_SCENE_TIME, "Scene Time", NODE_CLASS_INPUT, 0);
+ ntype.geometry_node_execute = file_ns::node_exec;
+ ntype.declare = file_ns::node_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc b/source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc
index dcd14b1c054..3efe8577e51 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc
@@ -16,27 +16,29 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_input_shade_smooth_cc {
-static void geo_node_input_shade_smooth_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Bool>(N_("Smooth")).field_source();
}
-static void geo_node_input_shade_smooth_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Field<bool> shade_smooth_field = AttributeFieldInput::Create<bool>("shade_smooth");
params.set_output("Smooth", std::move(shade_smooth_field));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_input_shade_smooth_cc
void register_node_type_geo_input_shade_smooth()
{
+ namespace file_ns = blender::nodes::node_geo_input_shade_smooth_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_INPUT_SHADE_SMOOTH, "Is Shade Smooth", NODE_CLASS_INPUT, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_input_shade_smooth_exec;
- ntype.declare = blender::nodes::geo_node_input_shade_smooth_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_spline_cyclic.cc b/source/blender/nodes/geometry/nodes/node_geo_input_spline_cyclic.cc
index a8ee6dd8b12..5f833445a76 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_spline_cyclic.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_spline_cyclic.cc
@@ -16,28 +16,30 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_input_spline_cyclic_cc {
-static void geo_node_input_spline_cyclic_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Bool>(N_("Cyclic")).field_source();
}
-static void geo_node_input_spline_cyclic_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Field<bool> cyclic_field = AttributeFieldInput::Create<bool>("cyclic");
params.set_output("Cyclic", std::move(cyclic_field));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_input_spline_cyclic_cc
void register_node_type_geo_input_spline_cyclic()
{
+ namespace file_ns = blender::nodes::node_geo_input_spline_cyclic_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_INPUT_SPLINE_CYCLIC, "Is Spline Cyclic", NODE_CLASS_INPUT, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_input_spline_cyclic_exec;
- ntype.declare = blender::nodes::geo_node_input_spline_cyclic_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc b/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc
index a976e0b193f..810d6e2fddd 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc
@@ -18,16 +18,20 @@
#include "BKE_spline.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_input_spline_length_cc {
-static void geo_node_input_spline_length_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Float>(N_("Length")).field_source();
+ b.add_output<decl::Int>(N_("Point Count")).field_source();
}
+/* --------------------------------------------------------------------
+ * Spline Length
+ */
+
static VArray<float> construct_spline_length_gvarray(const CurveComponent &component,
- const AttributeDomain domain,
- ResourceScope &UNUSED(scope))
+ const AttributeDomain domain)
{
const CurveEval *curve = component.get_for_read();
if (curve == nullptr) {
@@ -46,29 +50,23 @@ static VArray<float> construct_spline_length_gvarray(const CurveComponent &compo
std::move(length), ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT);
}
- return nullptr;
+ return {};
}
-class SplineLengthFieldInput final : public fn::FieldInput {
+class SplineLengthFieldInput final : public GeometryFieldInput {
public:
- SplineLengthFieldInput() : fn::FieldInput(CPPType::get<float>(), "Spline Length node")
+ SplineLengthFieldInput() : GeometryFieldInput(CPPType::get<float>(), "Spline Length node")
{
category_ = Category::Generated;
}
- GVArray get_varray_for_context(const fn::FieldContext &context,
- IndexMask UNUSED(mask),
- ResourceScope &scope) const final
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
{
- if (const GeometryComponentFieldContext *geometry_context =
- dynamic_cast<const GeometryComponentFieldContext *>(&context)) {
-
- const GeometryComponent &component = geometry_context->geometry_component();
- const AttributeDomain domain = geometry_context->domain();
- if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
- const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
- return construct_spline_length_gvarray(curve_component, domain, scope);
- }
+ if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
+ const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
+ return construct_spline_length_gvarray(curve_component, domain);
}
return {};
}
@@ -85,20 +83,81 @@ class SplineLengthFieldInput final : public fn::FieldInput {
}
};
-static void geo_node_input_spline_length_exec(GeoNodeExecParams params)
+/* --------------------------------------------------------------------
+ * Spline Count
+ */
+
+static VArray<int> construct_spline_count_gvarray(const CurveComponent &component,
+ const AttributeDomain domain)
+{
+ const CurveEval *curve = component.get_for_read();
+ if (curve == nullptr) {
+ return {};
+ }
+
+ Span<SplinePtr> splines = curve->splines();
+ auto count_fn = [splines](int i) { return splines[i]->size(); };
+
+ if (domain == ATTR_DOMAIN_CURVE) {
+ return VArray<int>::ForFunc(splines.size(), count_fn);
+ }
+ if (domain == ATTR_DOMAIN_POINT) {
+ VArray<int> count = VArray<int>::ForFunc(splines.size(), count_fn);
+ return component.attribute_try_adapt_domain<int>(
+ std::move(count), ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT);
+ }
+
+ return {};
+}
+
+class SplineCountFieldInput final : public GeometryFieldInput {
+ public:
+ SplineCountFieldInput() : GeometryFieldInput(CPPType::get<int>(), "Spline Point Count")
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
+ {
+ if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
+ const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
+ return construct_spline_count_gvarray(curve_component, domain);
+ }
+ return {};
+ }
+
+ uint64_t hash() const override
+ {
+ /* Some random constant hash. */
+ return 456364322625;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ return dynamic_cast<const SplineCountFieldInput *>(&other) != nullptr;
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
{
- Field<float> length_field{std::make_shared<SplineLengthFieldInput>()};
- params.set_output("Length", std::move(length_field));
+ Field<float> spline_length_field{std::make_shared<SplineLengthFieldInput>()};
+ Field<int> spline_count_field{std::make_shared<SplineCountFieldInput>()};
+
+ params.set_output("Length", std::move(spline_length_field));
+ params.set_output("Point Count", std::move(spline_count_field));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_input_spline_length_cc
void register_node_type_geo_input_spline_length()
{
- static bNodeType ntype;
+ namespace file_ns = blender::nodes::node_geo_input_spline_length_cc;
+ static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_INPUT_SPLINE_LENGTH, "Spline Length", NODE_CLASS_INPUT, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_input_spline_length_exec;
- ntype.declare = blender::nodes::geo_node_input_spline_length_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_spline_resolution.cc b/source/blender/nodes/geometry/nodes/node_geo_input_spline_resolution.cc
index 75fb8a13d38..77b6e27e6a2 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_spline_resolution.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_spline_resolution.cc
@@ -16,28 +16,30 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_input_spline_resolution_cc {
-static void geo_node_input_spline_resolution_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Int>(N_("Resolution")).field_source();
}
-static void geo_node_input_spline_resolution_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Field<int> resolution_field = AttributeFieldInput::Create<int>("resolution");
params.set_output("Resolution", std::move(resolution_field));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_input_spline_resolution_cc
void register_node_type_geo_input_spline_resolution()
{
+ namespace file_ns = blender::nodes::node_geo_input_spline_resolution_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_INPUT_SPLINE_RESOLUTION, "Spline Resolution", NODE_CLASS_INPUT, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_input_spline_resolution_exec;
- ntype.declare = blender::nodes::geo_node_input_spline_resolution_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc b/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc
index 49885f29d44..86f882df3cd 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc
@@ -20,9 +20,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_input_tangent_cc {
-static void geo_node_input_tangent_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Vector>(N_("Tangent")).field_source();
}
@@ -85,8 +85,7 @@ static Array<float3> curve_tangent_point_domain(const CurveEval &curve)
}
static VArray<float3> construct_curve_tangent_gvarray(const CurveComponent &component,
- const AttributeDomain domain,
- ResourceScope &UNUSED(scope))
+ const AttributeDomain domain)
{
const CurveEval *curve = component.get_for_read();
if (curve == nullptr) {
@@ -118,27 +117,20 @@ static VArray<float3> construct_curve_tangent_gvarray(const CurveComponent &comp
return nullptr;
}
-class TangentFieldInput final : public fn::FieldInput {
+class TangentFieldInput final : public GeometryFieldInput {
public:
- TangentFieldInput() : fn::FieldInput(CPPType::get<float3>(), "Tangent node")
+ TangentFieldInput() : GeometryFieldInput(CPPType::get<float3>(), "Tangent node")
{
category_ = Category::Generated;
}
- GVArray get_varray_for_context(const fn::FieldContext &context,
- IndexMask UNUSED(mask),
- ResourceScope &scope) const final
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
{
- if (const GeometryComponentFieldContext *geometry_context =
- dynamic_cast<const GeometryComponentFieldContext *>(&context)) {
-
- const GeometryComponent &component = geometry_context->geometry_component();
- const AttributeDomain domain = geometry_context->domain();
-
- if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
- const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
- return construct_curve_tangent_gvarray(curve_component, domain, scope);
- }
+ if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
+ const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
+ return construct_curve_tangent_gvarray(curve_component, domain);
}
return {};
}
@@ -155,20 +147,22 @@ class TangentFieldInput final : public fn::FieldInput {
}
};
-static void geo_node_input_tangent_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Field<float3> tangent_field{std::make_shared<TangentFieldInput>()};
params.set_output("Tangent", std::move(tangent_field));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_input_tangent_cc
void register_node_type_geo_input_tangent()
{
+ namespace file_ns = blender::nodes::node_geo_input_tangent_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_INPUT_TANGENT, "Curve Tangent", NODE_CLASS_INPUT, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_input_tangent_exec;
- ntype.declare = blender::nodes::geo_node_input_tangent_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc b/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc
index 2a68030aba7..486f90760f5 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc
@@ -22,11 +22,13 @@
#include "UI_interface.h"
#include "UI_resources.h"
+#include "BKE_attribute_math.hh"
+
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_instance_on_points_cc {
-static void geo_node_instance_on_points_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Points")).description(N_("Points to instance on"));
b.add_input<decl::Bool>(N_("Selection")).default_value(true).supports_field().hide_value();
@@ -53,20 +55,34 @@ static void geo_node_instance_on_points_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Instances"));
}
-static void add_instances_from_component(InstancesComponent &dst_component,
- const GeometryComponent &src_component,
- const GeometrySet &instance,
- const GeoNodeExecParams &params)
+static void add_instances_from_component(
+ InstancesComponent &dst_component,
+ const GeometryComponent &src_component,
+ const GeometrySet &instance,
+ const GeoNodeExecParams &params,
+ const Map<AttributeIDRef, AttributeKind> &attributes_to_propagate)
{
const AttributeDomain domain = ATTR_DOMAIN_POINT;
const int domain_size = src_component.attribute_domain_size(domain);
+ VArray<bool> pick_instance;
+ VArray<int> indices;
+ VArray<float3> rotations;
+ VArray<float3> scales;
+
GeometryComponentFieldContext field_context{src_component, domain};
const Field<bool> selection_field = params.get_input<Field<bool>>("Selection");
- fn::FieldEvaluator selection_evaluator{field_context, domain_size};
- selection_evaluator.add(selection_field);
- selection_evaluator.evaluate();
- const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.set_selection(selection_field);
+ /* The evaluator could use the component's stable IDs as a destination directly, but only the
+ * selected indices should be copied. */
+ evaluator.add(params.get_input<Field<bool>>("Pick Instance"), &pick_instance);
+ evaluator.add(params.get_input<Field<int>>("Instance Index"), &indices);
+ evaluator.add(params.get_input<Field<float3>>("Rotation"), &rotations);
+ evaluator.add(params.get_input<Field<float3>>("Scale"), &scales);
+ evaluator.evaluate();
+
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
/* The initial size of the component might be non-zero when this function is called for multiple
* component types. */
@@ -79,19 +95,6 @@ static void add_instances_from_component(InstancesComponent &dst_component,
MutableSpan<float4x4> dst_transforms = dst_component.instance_transforms().slice(start_len,
select_len);
- FieldEvaluator field_evaluator{field_context, domain_size};
- VArray<bool> pick_instance;
- VArray<int> indices;
- VArray<float3> rotations;
- VArray<float3> scales;
- /* The evaluator could use the component's stable IDs as a destination directly, but only the
- * selected indices should be copied. */
- field_evaluator.add(params.get_input<Field<bool>>("Pick Instance"), &pick_instance);
- field_evaluator.add(params.get_input<Field<int>>("Instance Index"), &indices);
- field_evaluator.add(params.get_input<Field<float3>>("Rotation"), &rotations);
- field_evaluator.add(params.get_input<Field<float3>>("Scale"), &scales);
- field_evaluator.evaluate();
-
VArray<float3> positions = src_component.attribute_get_for_read<float3>(
"position", domain, {0, 0, 0});
@@ -154,17 +157,6 @@ static void add_instances_from_component(InstancesComponent &dst_component,
}
});
- VArray<int> ids = src_component
- .attribute_try_get_for_read("id", ATTR_DOMAIN_POINT, CD_PROP_INT32)
- .typed<int>();
- if (ids) {
- VArray_Span<int> ids_span{ids};
- MutableSpan<int> dst_ids = dst_component.instance_ids_ensure();
- for (const int64_t i : selection.index_range()) {
- dst_ids[i] = ids_span[selection[i]];
- }
- }
-
if (pick_instance.is_single()) {
if (pick_instance.get_internal_single()) {
if (instance.has_realized_data()) {
@@ -174,9 +166,40 @@ static void add_instances_from_component(InstancesComponent &dst_component,
}
}
}
+
+ bke::CustomDataAttributes &instance_attributes = dst_component.attributes();
+ for (const auto item : attributes_to_propagate.items()) {
+ const AttributeIDRef &attribute_id = item.key;
+ const AttributeKind attribute_kind = item.value;
+
+ const GVArray src_attribute = src_component.attribute_get_for_read(
+ attribute_id, ATTR_DOMAIN_POINT, attribute_kind.data_type);
+ BLI_assert(src_attribute);
+ std::optional<GMutableSpan> dst_attribute_opt = instance_attributes.get_for_write(
+ attribute_id);
+ if (!dst_attribute_opt) {
+ if (!instance_attributes.create(attribute_id, attribute_kind.data_type)) {
+ continue;
+ }
+ dst_attribute_opt = instance_attributes.get_for_write(attribute_id);
+ }
+ BLI_assert(dst_attribute_opt);
+ const GMutableSpan dst_attribute = dst_attribute_opt->slice(start_len, select_len);
+ threading::parallel_for(selection.index_range(), 1024, [&](IndexRange selection_range) {
+ attribute_math::convert_to_static_type(attribute_kind.data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ VArray<T> src = src_attribute.typed<T>();
+ MutableSpan<T> dst = dst_attribute.typed<T>();
+ for (const int range_i : selection_range) {
+ const int i = selection[range_i];
+ dst[range_i] = src[i];
+ }
+ });
+ });
+ }
}
-static void geo_node_instance_on_points_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Points");
GeometrySet instance = params.get_input<GeometrySet>("Instance");
@@ -185,23 +208,36 @@ static void geo_node_instance_on_points_exec(GeoNodeExecParams params)
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
+ Map<AttributeIDRef, AttributeKind> attributes_to_propagate;
+ geometry_set.gather_attributes_for_propagation(
+ {GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE},
+ GEO_COMPONENT_TYPE_INSTANCES,
+ false,
+ attributes_to_propagate);
+ attributes_to_propagate.remove("position");
+
if (geometry_set.has<MeshComponent>()) {
- add_instances_from_component(
- instances, *geometry_set.get_component_for_read<MeshComponent>(), instance, params);
- geometry_set.remove(GEO_COMPONENT_TYPE_MESH);
+ add_instances_from_component(instances,
+ *geometry_set.get_component_for_read<MeshComponent>(),
+ instance,
+ params,
+ attributes_to_propagate);
}
if (geometry_set.has<PointCloudComponent>()) {
add_instances_from_component(instances,
*geometry_set.get_component_for_read<PointCloudComponent>(),
instance,
- params);
- geometry_set.remove(GEO_COMPONENT_TYPE_POINT_CLOUD);
+ params,
+ attributes_to_propagate);
}
if (geometry_set.has<CurveComponent>()) {
- add_instances_from_component(
- instances, *geometry_set.get_component_for_read<CurveComponent>(), instance, params);
- geometry_set.remove(GEO_COMPONENT_TYPE_CURVE);
+ add_instances_from_component(instances,
+ *geometry_set.get_component_for_read<CurveComponent>(),
+ instance,
+ params,
+ attributes_to_propagate);
}
+ geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES});
});
/* Unused references may have been added above. Remove those now so that other nodes don't
@@ -214,15 +250,17 @@ static void geo_node_instance_on_points_exec(GeoNodeExecParams params)
params.set_output("Instances", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_instance_on_points_cc
void register_node_type_geo_instance_on_points()
{
+ namespace file_ns = blender::nodes::node_geo_instance_on_points_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_INSTANCE_ON_POINTS, "Instance on Points", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_instance_on_points_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_instance_on_points_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc
index c3955426e69..9942e388ba5 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc
@@ -14,14 +14,16 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#include "BKE_pointcloud.h"
#include "DNA_pointcloud_types.h"
+#include "BKE_attribute_math.hh"
+#include "BKE_pointcloud.h"
+
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_instances_to_points_cc {
-static void geo_node_instances_to_points_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Instances")).only_instances();
b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
@@ -51,14 +53,15 @@ static void convert_instances_to_points(GeometrySet &geometry_set,
{
const InstancesComponent &instances = *geometry_set.get_component_for_read<InstancesComponent>();
- const AttributeDomain attribute_domain = ATTR_DOMAIN_POINT;
- GeometryComponentFieldContext field_context{instances, attribute_domain};
- const int domain_size = instances.attribute_domain_size(attribute_domain);
+ GeometryComponentFieldContext field_context{instances, ATTR_DOMAIN_INSTANCE};
+ const int domain_size = instances.attribute_domain_size(ATTR_DOMAIN_INSTANCE);
- fn::FieldEvaluator selection_evaluator{field_context, domain_size};
- selection_evaluator.add(std::move(selection_field));
- selection_evaluator.evaluate();
- const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.set_selection(std::move(selection_field));
+ evaluator.add(std::move(position_field));
+ evaluator.add(std::move(radius_field));
+ evaluator.evaluate();
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
if (selection.is_empty()) {
return;
}
@@ -68,27 +71,40 @@ static void convert_instances_to_points(GeometrySet &geometry_set,
PointCloudComponent &points = geometry_set.get_component_for_write<PointCloudComponent>();
- fn::FieldEvaluator evaluator{field_context, &selection};
- evaluator.add(std::move(position_field));
- evaluator.add(std::move(radius_field));
- evaluator.evaluate();
const VArray<float3> &positions = evaluator.get_evaluated<float3>(0);
copy_attribute_to_points(positions, selection, {(float3 *)pointcloud->co, pointcloud->totpoint});
const VArray<float> &radii = evaluator.get_evaluated<float>(1);
copy_attribute_to_points(radii, selection, {pointcloud->radius, pointcloud->totpoint});
- if (!instances.instance_ids().is_empty()) {
- OutputAttribute_Typed<int> id_attribute = points.attribute_try_get_for_output<int>(
- "id", ATTR_DOMAIN_POINT, CD_PROP_INT32);
- MutableSpan<int> ids = id_attribute.as_span();
- for (const int i : selection.index_range()) {
- ids[i] = instances.instance_ids()[selection[i]];
- }
- id_attribute.save();
+ Map<AttributeIDRef, AttributeKind> attributes_to_propagate;
+ geometry_set.gather_attributes_for_propagation({GEO_COMPONENT_TYPE_INSTANCES},
+ GEO_COMPONENT_TYPE_POINT_CLOUD,
+ false,
+ attributes_to_propagate);
+ /* These two attributes are added by the implicit inputs above. */
+ attributes_to_propagate.remove("position");
+ attributes_to_propagate.remove("radius");
+
+ for (const auto item : attributes_to_propagate.items()) {
+ const AttributeIDRef &attribute_id = item.key;
+ const AttributeKind attribute_kind = item.value;
+
+ const GVArray src = instances.attribute_get_for_read(
+ attribute_id, ATTR_DOMAIN_INSTANCE, attribute_kind.data_type);
+ BLI_assert(src);
+ OutputAttribute dst = points.attribute_try_get_for_output_only(
+ attribute_id, ATTR_DOMAIN_POINT, attribute_kind.data_type);
+ BLI_assert(dst);
+
+ attribute_math::convert_to_static_type(attribute_kind.data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ copy_attribute_to_points(src.typed<T>(), selection, dst.as_span().typed<T>());
+ });
+ dst.save();
}
}
-static void geo_node_instances_to_points_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Instances");
@@ -101,19 +117,21 @@ static void geo_node_instances_to_points_exec(GeoNodeExecParams params)
params.set_output("Points", std::move(geometry_set));
}
else {
- params.set_output("Points", GeometrySet());
+ params.set_default_remaining_outputs();
}
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_instances_to_points_cc
void register_node_type_geo_instances_to_points()
{
+ namespace file_ns = blender::nodes::node_geo_instances_to_points_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_INSTANCES_TO_POINTS, "Instances to Points", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_instances_to_points_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_instances_to_points_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc b/source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc
index 8e0e98f7bd5..5925d440317 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc
@@ -18,14 +18,14 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_is_viewport_cc {
-static void geo_node_is_viewport_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Bool>(N_("Is Viewport"));
}
-static void geo_node_is_viewport_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
const Depsgraph *depsgraph = params.depsgraph();
const eEvaluationMode mode = DEG_get_mode(depsgraph);
@@ -34,14 +34,16 @@ static void geo_node_is_viewport_exec(GeoNodeExecParams params)
params.set_output("Is Viewport", is_viewport);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_is_viewport_cc
void register_node_type_geo_is_viewport()
{
+ namespace file_ns = blender::nodes::node_geo_is_viewport_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_IS_VIEWPORT, "Is Viewport", NODE_CLASS_INPUT, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_is_viewport_exec;
- ntype.declare = blender::nodes::geo_node_is_viewport_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
index fcdf7c2da01..bf7a9f49829 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
@@ -19,127 +19,23 @@
#include "BKE_mesh_runtime.h"
#include "BKE_pointcloud.h"
#include "BKE_spline.hh"
+#include "BKE_type_conversions.hh"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
-#include "NOD_type_conversions.hh"
+#include "GEO_realize_instances.hh"
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_join_geometry_cc {
-static void geo_node_join_geometry_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry")).multi_input();
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static Mesh *join_mesh_topology_and_builtin_attributes(Span<const MeshComponent *> src_components)
-{
- int totverts = 0;
- int totloops = 0;
- int totedges = 0;
- int totpolys = 0;
-
- int64_t cd_dirty_vert = 0;
- int64_t cd_dirty_poly = 0;
- int64_t cd_dirty_edge = 0;
- int64_t cd_dirty_loop = 0;
-
- VectorSet<Material *> materials;
-
- for (const MeshComponent *mesh_component : src_components) {
- const Mesh *mesh = mesh_component->get_for_read();
- totverts += mesh->totvert;
- totloops += mesh->totloop;
- totedges += mesh->totedge;
- totpolys += mesh->totpoly;
- cd_dirty_vert |= mesh->runtime.cd_dirty_vert;
- cd_dirty_poly |= mesh->runtime.cd_dirty_poly;
- cd_dirty_edge |= mesh->runtime.cd_dirty_edge;
- cd_dirty_loop |= mesh->runtime.cd_dirty_loop;
-
- for (const int slot_index : IndexRange(mesh->totcol)) {
- Material *material = mesh->mat[slot_index];
- materials.add(material);
- }
- }
-
- const Mesh *first_input_mesh = src_components[0]->get_for_read();
- Mesh *new_mesh = BKE_mesh_new_nomain(totverts, totedges, 0, totloops, totpolys);
- BKE_mesh_copy_parameters_for_eval(new_mesh, first_input_mesh);
-
- for (const int i : IndexRange(materials.size())) {
- Material *material = materials[i];
- BKE_id_material_eval_assign(&new_mesh->id, i + 1, material);
- }
-
- new_mesh->runtime.cd_dirty_vert = cd_dirty_vert;
- new_mesh->runtime.cd_dirty_poly = cd_dirty_poly;
- new_mesh->runtime.cd_dirty_edge = cd_dirty_edge;
- new_mesh->runtime.cd_dirty_loop = cd_dirty_loop;
-
- int vert_offset = 0;
- int loop_offset = 0;
- int edge_offset = 0;
- int poly_offset = 0;
- for (const MeshComponent *mesh_component : src_components) {
- const Mesh *mesh = mesh_component->get_for_read();
- if (mesh == nullptr) {
- continue;
- }
-
- Array<int> material_index_map(mesh->totcol);
- for (const int i : IndexRange(mesh->totcol)) {
- Material *material = mesh->mat[i];
- const int new_material_index = materials.index_of(material);
- material_index_map[i] = new_material_index;
- }
-
- for (const int i : IndexRange(mesh->totvert)) {
- const MVert &old_vert = mesh->mvert[i];
- MVert &new_vert = new_mesh->mvert[vert_offset + i];
- new_vert = old_vert;
- }
-
- for (const int i : IndexRange(mesh->totedge)) {
- const MEdge &old_edge = mesh->medge[i];
- MEdge &new_edge = new_mesh->medge[edge_offset + i];
- new_edge = old_edge;
- new_edge.v1 += vert_offset;
- new_edge.v2 += vert_offset;
- }
- for (const int i : IndexRange(mesh->totloop)) {
- const MLoop &old_loop = mesh->mloop[i];
- MLoop &new_loop = new_mesh->mloop[loop_offset + i];
- new_loop = old_loop;
- new_loop.v += vert_offset;
- new_loop.e += edge_offset;
- }
- for (const int i : IndexRange(mesh->totpoly)) {
- const MPoly &old_poly = mesh->mpoly[i];
- MPoly &new_poly = new_mesh->mpoly[poly_offset + i];
- new_poly = old_poly;
- new_poly.loopstart += loop_offset;
- if (old_poly.mat_nr >= 0 && old_poly.mat_nr < mesh->totcol) {
- new_poly.mat_nr = material_index_map[new_poly.mat_nr];
- }
- else {
- /* The material index was invalid before. */
- new_poly.mat_nr = 0;
- }
- }
-
- vert_offset += mesh->totvert;
- loop_offset += mesh->totloop;
- edge_offset += mesh->totedge;
- poly_offset += mesh->totpoly;
- }
-
- return new_mesh;
-}
-
template<typename Component>
static Array<const GeometryComponent *> to_base_components(Span<const Component *> components)
{
@@ -223,33 +119,6 @@ static void join_attributes(Span<const GeometryComponent *> src_components,
}
}
-static void join_components(Span<const MeshComponent *> src_components, GeometrySet &result)
-{
- Mesh *new_mesh = join_mesh_topology_and_builtin_attributes(src_components);
-
- MeshComponent &dst_component = result.get_component_for_write<MeshComponent>();
- dst_component.replace(new_mesh);
-
- /* Don't copy attributes that are stored directly in the mesh data structs. */
- join_attributes(to_base_components(src_components),
- dst_component,
- {"position", "material_index", "normal", "shade_smooth", "crease"});
-}
-
-static void join_components(Span<const PointCloudComponent *> src_components, GeometrySet &result)
-{
- int totpoints = 0;
- for (const PointCloudComponent *pointcloud_component : src_components) {
- totpoints += pointcloud_component->attribute_domain_size(ATTR_DOMAIN_POINT);
- }
-
- PointCloudComponent &dst_component = result.get_component_for_write<PointCloudComponent>();
- PointCloud *pointcloud = BKE_pointcloud_new_nomain(totpoints);
- dst_component.replace(pointcloud);
-
- join_attributes(to_base_components(src_components), dst_component);
-}
-
static void join_components(Span<const InstancesComponent *> src_components, GeometrySet &result)
{
InstancesComponent &dst_component = result.get_component_for_write<InstancesComponent>();
@@ -288,192 +157,6 @@ static void join_components(Span<const VolumeComponent *> src_components, Geomet
UNUSED_VARS(src_components, dst_component);
}
-/**
- * \note This takes advantage of the fact that creating attributes on joined curves never
- * changes a point attribute into a spline attribute; it is always the other way around.
- */
-static void ensure_control_point_attribute(const AttributeIDRef &attribute_id,
- const CustomDataType data_type,
- Span<CurveComponent *> src_components,
- CurveEval &result)
-{
- MutableSpan<SplinePtr> splines = result.splines();
- const CPPType &type = *bke::custom_data_type_to_cpp_type(data_type);
-
- /* In order to fill point attributes with spline domain attribute values where necessary, keep
- * track of the curve each spline came from while iterating over the splines in the result. */
- int src_component_index = 0;
- int spline_index_in_component = 0;
- const CurveEval *current_curve = src_components[src_component_index]->get_for_read();
-
- for (SplinePtr &spline : splines) {
- std::optional<GSpan> attribute = spline->attributes.get_for_read(attribute_id);
-
- if (attribute) {
- if (attribute->type() != type) {
- /* In this case, the attribute exists, but it has the wrong type. So create a buffer
- * for the converted values, do the conversion, and then replace the attribute. */
- void *converted_buffer = MEM_mallocN_aligned(
- spline->size() * type.size(), type.alignment(), __func__);
-
- const DataTypeConversions &conversions = blender::nodes::get_implicit_type_conversions();
- conversions.try_convert(GVArray::ForSpan(*attribute), type).materialize(converted_buffer);
-
- spline->attributes.remove(attribute_id);
- spline->attributes.create_by_move(attribute_id, data_type, converted_buffer);
- }
- }
- else {
- spline->attributes.create(attribute_id, data_type);
-
- if (current_curve->attributes.get_for_read(attribute_id)) {
- /* In this case the attribute did not exist, but there is a spline domain attribute
- * we can retrieve a value from, as a spline to point domain conversion. So fill the
- * new attribute with the value for this spline. */
- GVArray current_curve_attribute = current_curve->attributes.get_for_read(
- attribute_id, data_type, nullptr);
-
- BLI_assert(spline->attributes.get_for_read(attribute_id));
- std::optional<GMutableSpan> new_attribute = spline->attributes.get_for_write(attribute_id);
-
- BUFFER_FOR_CPP_TYPE_VALUE(type, buffer);
- current_curve_attribute.get(spline_index_in_component, buffer);
- type.fill_assign_n(buffer, new_attribute->data(), new_attribute->size());
- }
- }
-
- /* Move to the next spline and maybe the next input component. */
- spline_index_in_component++;
- if (spline != splines.last() && spline_index_in_component >= current_curve->splines().size()) {
- src_component_index++;
- spline_index_in_component = 0;
-
- current_curve = src_components[src_component_index]->get_for_read();
- }
- }
-}
-
-/**
- * Curve point domain attributes must be in the same order on every spline. The order might have
- * been different on separate instances, so ensure that all splines have the same order. Note that
- * because #Map is used, the order is not necessarily consistent every time, but it is the same for
- * every spline, and that's what matters.
- */
-static void sort_curve_point_attributes(const Map<AttributeIDRef, AttributeMetaData> &info,
- MutableSpan<SplinePtr> splines)
-{
- Vector<AttributeIDRef> new_order;
- for (Map<AttributeIDRef, AttributeMetaData>::Item item : info.items()) {
- if (item.value.domain == ATTR_DOMAIN_POINT) {
- /* Only sort attributes stored on splines. */
- new_order.append(item.key);
- }
- }
- for (SplinePtr &spline : splines) {
- spline->attributes.reorder(new_order);
- }
-}
-
-/**
- * Fill data for an attribute on the new curve based on all source curves.
- */
-static void ensure_spline_attribute(const AttributeIDRef &attribute_id,
- const CustomDataType data_type,
- Span<CurveComponent *> src_components,
- CurveEval &result)
-{
- const CPPType &type = *bke::custom_data_type_to_cpp_type(data_type);
-
- result.attributes.create(attribute_id, data_type);
- GMutableSpan result_attribute = *result.attributes.get_for_write(attribute_id);
-
- int offset = 0;
- for (const CurveComponent *component : src_components) {
- const CurveEval &curve = *component->get_for_read();
- const int size = curve.splines().size();
- if (size == 0) {
- continue;
- }
- GVArray read_attribute = curve.attributes.get_for_read(attribute_id, data_type, nullptr);
- GVArray_GSpan src_span{read_attribute};
-
- const void *src_buffer = src_span.data();
- type.copy_assign_n(src_buffer, result_attribute[offset], size);
-
- offset += size;
- }
-}
-
-/**
- * Special handling for copying spline attributes. This is necessary because we move the splines
- * out of the source components instead of copying them, meaning we can no longer access point
- * domain attributes on the source components.
- *
- * \warning Splines have been moved out of the source components at this point, so it
- * is important to only read curve-level data (spline domain attributes) from them.
- */
-static void join_curve_attributes(const Map<AttributeIDRef, AttributeMetaData> &info,
- Span<CurveComponent *> src_components,
- CurveEval &result)
-{
- for (const Map<AttributeIDRef, AttributeMetaData>::Item item : info.items()) {
- const AttributeIDRef attribute_id = item.key;
- const AttributeMetaData meta_data = item.value;
-
- if (meta_data.domain == ATTR_DOMAIN_CURVE) {
- ensure_spline_attribute(attribute_id, meta_data.data_type, src_components, result);
- }
- else {
- ensure_control_point_attribute(attribute_id, meta_data.data_type, src_components, result);
- }
- }
-
- sort_curve_point_attributes(info, result.splines());
-}
-
-static void join_curve_components(MutableSpan<GeometrySet> src_geometry_sets, GeometrySet &result)
-{
- Vector<CurveComponent *> src_components;
- for (GeometrySet &geometry_set : src_geometry_sets) {
- if (geometry_set.has_curve()) {
- /* Retrieving with write access seems counterintuitive, but it can allow avoiding a copy
- * in the case where the input spline has no other users, because the splines can be
- * moved from the source curve rather than copied from a read-only source. Retrieving
- * the curve for write will make a copy only when it has a user elsewhere. */
- CurveComponent &component = geometry_set.get_component_for_write<CurveComponent>();
- src_components.append(&component);
- }
- }
-
- if (src_components.size() == 0) {
- return;
- }
- if (src_components.size() == 1) {
- result.add(*src_components[0]);
- return;
- }
-
- /* Retrieve attribute info before moving the splines out of the input components. */
- const Map<AttributeIDRef, AttributeMetaData> info = get_final_attribute_info(
- {(const GeometryComponent **)src_components.data(), src_components.size()},
- {"position", "radius", "tilt", "handle_left", "handle_right", "cyclic", "resolution"});
-
- CurveComponent &dst_component = result.get_component_for_write<CurveComponent>();
- CurveEval *dst_curve = new CurveEval();
- for (CurveComponent *component : src_components) {
- CurveEval *src_curve = component->get_for_write();
- for (SplinePtr &spline : src_curve->splines()) {
- dst_curve->add_spline(std::move(spline));
- }
- }
- dst_curve->attributes.reallocate(dst_curve->splines().size());
-
- join_curve_attributes(info, src_components, *dst_curve);
- dst_curve->assert_valid_point_attributes();
-
- dst_component.replace(dst_curve);
-}
-
template<typename Component>
static void join_component_type(Span<GeometrySet> src_geometry_sets, GeometrySet &result)
{
@@ -492,10 +175,32 @@ static void join_component_type(Span<GeometrySet> src_geometry_sets, GeometrySet
result.add(*components[0]);
return;
}
- join_components(components, result);
+
+ GeometrySet instances_geometry_set;
+ InstancesComponent &instances =
+ instances_geometry_set.get_component_for_write<InstancesComponent>();
+
+ if constexpr (std::is_same_v<Component, InstancesComponent> ||
+ std::is_same_v<Component, VolumeComponent>) {
+ join_components(components, result);
+ }
+ else {
+ for (const Component *component : components) {
+ GeometrySet tmp_geo;
+ tmp_geo.add(*component);
+ const int handle = instances.add_reference(InstanceReference{tmp_geo});
+ instances.add_instance(handle, float4x4::identity());
+ }
+
+ geometry::RealizeInstancesOptions options;
+ options.keep_original_ids = true;
+ options.realize_instance_attributes = false;
+ GeometrySet joined_components = geometry::realize_instances(instances_geometry_set, options);
+ result.add(joined_components.get_component_for_write<Component>());
+ }
}
-static void geo_node_join_geometry_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Vector<GeometrySet> geometry_sets = params.extract_multi_input<GeometrySet>("Geometry");
@@ -504,18 +209,20 @@ static void geo_node_join_geometry_exec(GeoNodeExecParams params)
join_component_type<PointCloudComponent>(geometry_sets, geometry_set_result);
join_component_type<InstancesComponent>(geometry_sets, geometry_set_result);
join_component_type<VolumeComponent>(geometry_sets, geometry_set_result);
- join_curve_components(geometry_sets, geometry_set_result);
+ join_component_type<CurveComponent>(geometry_sets, geometry_set_result);
params.set_output("Geometry", std::move(geometry_set_result));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_join_geometry_cc
void register_node_type_geo_join_geometry()
{
+ namespace file_ns = blender::nodes::node_geo_join_geometry_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_JOIN_GEOMETRY, "Join Geometry", NODE_CLASS_GEOMETRY, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_join_geometry_exec;
- ntype.declare = blender::nodes::geo_node_join_geometry_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_material_replace.cc b/source/blender/nodes/geometry/nodes/node_geo_material_replace.cc
index e4a62bd5267..5a334126350 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_material_replace.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_material_replace.cc
@@ -24,9 +24,9 @@
#include "BKE_material.h"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_material_replace_cc {
-static void geo_node_material_replace_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry")).supported_type(GEO_COMPONENT_TYPE_MESH);
b.add_input<decl::Material>(N_("Old"));
@@ -34,7 +34,7 @@ static void geo_node_material_replace_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_material_replace_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Material *old_material = params.extract_input<Material *>("Old");
Material *new_material = params.extract_input<Material *>("New");
@@ -55,15 +55,17 @@ static void geo_node_material_replace_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_material_replace_cc
void register_node_type_geo_material_replace()
{
+ namespace file_ns = blender::nodes::node_geo_material_replace_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_REPLACE_MATERIAL, "Replace Material", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_material_replace_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_material_replace_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc
index 12ffa21762e..2aad68e7c25 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc
@@ -26,9 +26,9 @@
#include "BKE_material.h"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_material_selection_cc {
-static void geo_node_material_selection_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Material>(N_("Material")).hide_label(true);
b.add_output<decl::Bool>(N_("Selection")).field_source();
@@ -54,45 +54,40 @@ static void select_mesh_by_material(const Mesh &mesh,
});
}
-class MaterialSelectionFieldInput final : public fn::FieldInput {
+class MaterialSelectionFieldInput final : public GeometryFieldInput {
Material *material_;
public:
MaterialSelectionFieldInput(Material *material)
- : fn::FieldInput(CPPType::get<bool>(), "Material Selection node"), material_(material)
+ : GeometryFieldInput(CPPType::get<bool>(), "Material Selection node"), material_(material)
{
category_ = Category::Generated;
}
- GVArray get_varray_for_context(const fn::FieldContext &context,
- IndexMask mask,
- ResourceScope &UNUSED(scope)) const final
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask mask) const final
{
- if (const GeometryComponentFieldContext *geometry_context =
- dynamic_cast<const GeometryComponentFieldContext *>(&context)) {
- const GeometryComponent &component = geometry_context->geometry_component();
- const AttributeDomain domain = geometry_context->domain();
- if (component.type() != GEO_COMPONENT_TYPE_MESH) {
- return {};
- }
- const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
- const Mesh *mesh = mesh_component.get_for_read();
- if (mesh == nullptr) {
- return {};
- }
-
- if (domain == ATTR_DOMAIN_FACE) {
- Array<bool> selection(mask.min_array_size());
- select_mesh_by_material(*mesh, material_, mask, selection);
- return VArray<bool>::ForContainer(std::move(selection));
- }
-
- Array<bool> selection(mesh->totpoly);
- select_mesh_by_material(*mesh, material_, IndexMask(mesh->totpoly), selection);
- return mesh_component.attribute_try_adapt_domain<bool>(
- VArray<bool>::ForContainer(std::move(selection)), ATTR_DOMAIN_FACE, domain);
+ if (component.type() != GEO_COMPONENT_TYPE_MESH) {
+ return {};
+ }
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ const Mesh *mesh = mesh_component.get_for_read();
+ if (mesh == nullptr) {
+ return {};
+ }
+
+ if (domain == ATTR_DOMAIN_FACE) {
+ Array<bool> selection(mask.min_array_size());
+ select_mesh_by_material(*mesh, material_, mask, selection);
+ return VArray<bool>::ForContainer(std::move(selection));
}
+ Array<bool> selection(mesh->totpoly);
+ select_mesh_by_material(*mesh, material_, IndexMask(mesh->totpoly), selection);
+ return mesh_component.attribute_try_adapt_domain<bool>(
+ VArray<bool>::ForContainer(std::move(selection)), ATTR_DOMAIN_FACE, domain);
+
return nullptr;
}
@@ -111,22 +106,24 @@ class MaterialSelectionFieldInput final : public fn::FieldInput {
}
};
-static void geo_node_material_selection_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Material *material = params.extract_input<Material *>("Material");
Field<bool> material_field{std::make_shared<MaterialSelectionFieldInput>(material)};
params.set_output("Selection", std::move(material_field));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_material_selection_cc
void register_node_type_geo_material_selection()
{
+ namespace file_ns = blender::nodes::node_geo_material_selection_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_MATERIAL_SELECTION, "Material Selection", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_material_selection_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_material_selection_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc
index f1f95be107a..7a1cb8a62a3 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc
@@ -25,9 +25,11 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_mesh_primitive_circle_cc {
-static void geo_node_mesh_primitive_circle_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryMeshCircle)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Int>(N_("Vertices"))
.default_value(32)
@@ -41,16 +43,14 @@ static void geo_node_mesh_primitive_circle_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Mesh"));
}
-static void geo_node_mesh_primitive_circle_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
uiItemR(layout, ptr, "fill_type", 0, nullptr, ICON_NONE);
}
-static void geo_node_mesh_primitive_circle_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeGeometryMeshCircle *node_storage = (NodeGeometryMeshCircle *)MEM_callocN(
sizeof(NodeGeometryMeshCircle), __func__);
@@ -199,42 +199,41 @@ static Mesh *create_circle_mesh(const float radius,
return mesh;
}
-static void geo_node_mesh_primitive_circle_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
- const bNode &node = params.node();
- const NodeGeometryMeshCircle &storage = *(const NodeGeometryMeshCircle *)node.storage;
-
- const GeometryNodeMeshCircleFillType fill_type = (const GeometryNodeMeshCircleFillType)
- storage.fill_type;
+ const NodeGeometryMeshCircle &storage = node_storage(params.node());
+ const GeometryNodeMeshCircleFillType fill = (GeometryNodeMeshCircleFillType)storage.fill_type;
const float radius = params.extract_input<float>("Radius");
const int verts_num = params.extract_input<int>("Vertices");
if (verts_num < 3) {
params.error_message_add(NodeWarningType::Info, TIP_("Vertices must be at least 3"));
- params.set_output("Mesh", GeometrySet());
+ params.set_default_remaining_outputs();
return;
}
- Mesh *mesh = create_circle_mesh(radius, verts_num, fill_type);
+ Mesh *mesh = create_circle_mesh(radius, verts_num, fill);
BLI_assert(BKE_mesh_is_valid(mesh));
params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_mesh_primitive_circle_cc
void register_node_type_geo_mesh_primitive_circle()
{
+ namespace file_ns = blender::nodes::node_geo_mesh_primitive_circle_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_MESH_PRIMITIVE_CIRCLE, "Mesh Circle", NODE_CLASS_GEOMETRY, 0);
- node_type_init(&ntype, blender::nodes::geo_node_mesh_primitive_circle_init);
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(
&ntype, "NodeGeometryMeshCircle", node_free_standard_storage, node_copy_standard_storage);
- ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_circle_exec;
- ntype.draw_buttons = blender::nodes::geo_node_mesh_primitive_circle_layout;
- ntype.declare = blender::nodes::geo_node_mesh_primitive_circle_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
index fc93f6e72b5..70b093798f8 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
@@ -29,75 +29,6 @@
namespace blender::nodes {
-static void geo_node_mesh_primitive_cone_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Int>(N_("Vertices"))
- .default_value(32)
- .min(3)
- .max(512)
- .description(N_("Number of points on the circle at the top and bottom"));
- b.add_input<decl::Int>(N_("Side Segments"))
- .default_value(1)
- .min(1)
- .max(512)
- .description(N_("The number of edges running vertically along the side of the cone"));
- b.add_input<decl::Int>(N_("Fill Segments"))
- .default_value(1)
- .min(1)
- .max(512)
- .description(N_("Number of concentric rings used to fill the round face"));
- b.add_input<decl::Float>(N_("Radius Top"))
- .min(0.0f)
- .subtype(PROP_DISTANCE)
- .description(N_("Radius of the top circle of the cone"));
- b.add_input<decl::Float>(N_("Radius Bottom"))
- .default_value(1.0f)
- .min(0.0f)
- .subtype(PROP_DISTANCE)
- .description(N_("Radius of the bottom circle of the cone"));
- b.add_input<decl::Float>(N_("Depth"))
- .default_value(2.0f)
- .min(0.0f)
- .subtype(PROP_DISTANCE)
- .description(N_("Height of the generated cone"));
- b.add_output<decl::Geometry>(N_("Mesh"));
- b.add_output<decl::Bool>(N_("Top")).field_source();
- b.add_output<decl::Bool>(N_("Bottom")).field_source();
- b.add_output<decl::Bool>(N_("Side")).field_source();
-}
-
-static void geo_node_mesh_primitive_cone_init(bNodeTree *UNUSED(ntree), bNode *node)
-{
- NodeGeometryMeshCone *node_storage = (NodeGeometryMeshCone *)MEM_callocN(
- sizeof(NodeGeometryMeshCone), __func__);
-
- node_storage->fill_type = GEO_NODE_MESH_CIRCLE_FILL_NGON;
-
- node->storage = node_storage;
-}
-
-static void geo_node_mesh_primitive_cone_update(bNodeTree *ntree, bNode *node)
-{
- bNodeSocket *vertices_socket = (bNodeSocket *)node->inputs.first;
- bNodeSocket *rings_socket = vertices_socket->next;
- bNodeSocket *fill_subdiv_socket = rings_socket->next;
-
- const NodeGeometryMeshCone &storage = *(const NodeGeometryMeshCone *)node->storage;
- const GeometryNodeMeshCircleFillType fill_type =
- static_cast<const GeometryNodeMeshCircleFillType>(storage.fill_type);
- const bool has_fill = fill_type != GEO_NODE_MESH_CIRCLE_FILL_NONE;
- nodeSetSocketAvailability(ntree, fill_subdiv_socket, has_fill);
-}
-
-static void geo_node_mesh_primitive_cone_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
-{
- uiLayoutSetPropSep(layout, true);
- uiLayoutSetPropDecorate(layout, false);
- uiItemR(layout, ptr, "fill_type", 0, nullptr, ICON_NONE);
-}
-
struct ConeConfig {
float radius_top;
float radius_bottom;
@@ -794,37 +725,103 @@ Mesh *create_cylinder_or_cone_mesh(const float radius_top,
return mesh;
}
-static void geo_node_mesh_primitive_cone_exec(GeoNodeExecParams params)
+} // namespace blender::nodes
+
+namespace blender::nodes::node_geo_mesh_primitive_cone_cc {
+
+NODE_STORAGE_FUNCS(NodeGeometryMeshCone)
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Int>(N_("Vertices"))
+ .default_value(32)
+ .min(3)
+ .max(512)
+ .description(N_("Number of points on the circle at the top and bottom"));
+ b.add_input<decl::Int>(N_("Side Segments"))
+ .default_value(1)
+ .min(1)
+ .max(512)
+ .description(N_("The number of edges running vertically along the side of the cone"));
+ b.add_input<decl::Int>(N_("Fill Segments"))
+ .default_value(1)
+ .min(1)
+ .max(512)
+ .description(N_("Number of concentric rings used to fill the round face"));
+ b.add_input<decl::Float>(N_("Radius Top"))
+ .min(0.0f)
+ .subtype(PROP_DISTANCE)
+ .description(N_("Radius of the top circle of the cone"));
+ b.add_input<decl::Float>(N_("Radius Bottom"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .subtype(PROP_DISTANCE)
+ .description(N_("Radius of the bottom circle of the cone"));
+ b.add_input<decl::Float>(N_("Depth"))
+ .default_value(2.0f)
+ .min(0.0f)
+ .subtype(PROP_DISTANCE)
+ .description(N_("Height of the generated cone"));
+ b.add_output<decl::Geometry>(N_("Mesh"));
+ b.add_output<decl::Bool>(N_("Top")).field_source();
+ b.add_output<decl::Bool>(N_("Bottom")).field_source();
+ b.add_output<decl::Bool>(N_("Side")).field_source();
+}
+
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- const bNode &node = params.node();
- const NodeGeometryMeshCone &storage = *(const NodeGeometryMeshCone *)node.storage;
- const GeometryNodeMeshCircleFillType fill_type = (const GeometryNodeMeshCircleFillType)
- storage.fill_type;
-
- auto return_default = [&]() {
- params.set_output("Top", fn::make_constant_field<bool>(false));
- params.set_output("Bottom", fn::make_constant_field<bool>(false));
- params.set_output("Side", fn::make_constant_field<bool>(false));
- params.set_output("Mesh", GeometrySet());
- };
+ NodeGeometryMeshCone *node_storage = (NodeGeometryMeshCone *)MEM_callocN(
+ sizeof(NodeGeometryMeshCone), __func__);
+
+ node_storage->fill_type = GEO_NODE_MESH_CIRCLE_FILL_NGON;
+
+ node->storage = node_storage;
+}
+
+static void node_update(bNodeTree *ntree, bNode *node)
+{
+ bNodeSocket *vertices_socket = (bNodeSocket *)node->inputs.first;
+ bNodeSocket *rings_socket = vertices_socket->next;
+ bNodeSocket *fill_subdiv_socket = rings_socket->next;
+
+ const NodeGeometryMeshCone &storage = node_storage(*node);
+ const GeometryNodeMeshCircleFillType fill = (GeometryNodeMeshCircleFillType)storage.fill_type;
+ const bool has_fill = fill != GEO_NODE_MESH_CIRCLE_FILL_NONE;
+ nodeSetSocketAvailability(ntree, fill_subdiv_socket, has_fill);
+}
+
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
+ uiItemR(layout, ptr, "fill_type", 0, nullptr, ICON_NONE);
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ const NodeGeometryMeshCone &storage = node_storage(params.node());
+ const GeometryNodeMeshCircleFillType fill = (GeometryNodeMeshCircleFillType)storage.fill_type;
const int circle_segments = params.extract_input<int>("Vertices");
if (circle_segments < 3) {
params.error_message_add(NodeWarningType::Info, TIP_("Vertices must be at least 3"));
- return return_default();
+ params.set_default_remaining_outputs();
+ return;
}
const int side_segments = params.extract_input<int>("Side Segments");
if (side_segments < 1) {
params.error_message_add(NodeWarningType::Info, TIP_("Side Segments must be at least 1"));
- return return_default();
+ params.set_default_remaining_outputs();
+ return;
}
- const bool no_fill = fill_type == GEO_NODE_MESH_CIRCLE_FILL_NONE;
+ const bool no_fill = fill == GEO_NODE_MESH_CIRCLE_FILL_NONE;
const int fill_segments = no_fill ? 1 : params.extract_input<int>("Fill Segments");
if (fill_segments < 1) {
params.error_message_add(NodeWarningType::Info, TIP_("Fill Segments must be at least 1"));
- return return_default();
+ params.set_default_remaining_outputs();
+ return;
}
const float radius_top = params.extract_input<float>("Radius Top");
@@ -848,7 +845,7 @@ static void geo_node_mesh_primitive_cone_exec(GeoNodeExecParams params)
circle_segments,
side_segments,
fill_segments,
- fill_type,
+ fill,
attribute_outputs);
/* Transform the mesh so that the base of the cone is at the origin. */
@@ -874,19 +871,21 @@ static void geo_node_mesh_primitive_cone_exec(GeoNodeExecParams params)
params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_mesh_primitive_cone_cc
void register_node_type_geo_mesh_primitive_cone()
{
+ namespace file_ns = blender::nodes::node_geo_mesh_primitive_cone_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CONE, "Cone", NODE_CLASS_GEOMETRY, 0);
- node_type_init(&ntype, blender::nodes::geo_node_mesh_primitive_cone_init);
- node_type_update(&ntype, blender::nodes::geo_node_mesh_primitive_cone_update);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(
&ntype, "NodeGeometryMeshCone", node_free_standard_storage, node_copy_standard_storage);
- ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_cone_exec;
- ntype.draw_buttons = blender::nodes::geo_node_mesh_primitive_cone_layout;
- ntype.declare = blender::nodes::geo_node_mesh_primitive_cone_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc
index b5903f7b71e..2542542c919 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc
@@ -24,31 +24,6 @@
namespace blender::nodes {
-static void geo_node_mesh_primitive_cube_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Vector>(N_("Size"))
- .default_value(float3(1))
- .min(0.0f)
- .subtype(PROP_TRANSLATION)
- .description(N_("Side length along each axis"));
- b.add_input<decl::Int>(N_("Vertices X"))
- .default_value(2)
- .min(2)
- .max(1000)
- .description(N_("Number of vertices for the X side of the shape"));
- b.add_input<decl::Int>(N_("Vertices Y"))
- .default_value(2)
- .min(2)
- .max(1000)
- .description(N_("Number of vertices for the Y side of the shape"));
- b.add_input<decl::Int>(N_("Vertices Z"))
- .default_value(2)
- .min(2)
- .max(1000)
- .description(N_("Number of vertices for the Z side of the shape"));
- b.add_output<decl::Geometry>(N_("Mesh"));
-}
-
struct CuboidConfig {
float3 size;
int verts_x;
@@ -102,23 +77,37 @@ static void calculate_vertices(const CuboidConfig &config, MutableSpan<MVert> ve
int vert_index = 0;
- /* Though looping over all possible coordinates inside the cube only to skip them may be slow,
- * the alternative is similar complexity to below in the poly index calculation. If this loop
- * becomes a problem in the future it could be optimized, though only after proper performance
- * testing. */
for (const int z : IndexRange(config.verts_z)) {
- for (const int y : IndexRange(config.verts_y)) {
- for (const int x : IndexRange(config.verts_x)) {
- /* Only plot vertices on the surface of the cuboid. */
- if (ELEM(z, 0, config.edges_z) || ELEM(x, 0, config.edges_x) ||
- ELEM(y, 0, config.edges_y)) {
-
+ if (ELEM(z, 0, config.edges_z)) {
+ /* Fill bottom and top. */
+ const float z_pos = z_bottom + z_delta * z;
+ for (const int y : IndexRange(config.verts_y)) {
+ const float y_pos = y_front + y_delta * y;
+ for (const int x : IndexRange(config.verts_x)) {
const float x_pos = x_left + x_delta * x;
+ copy_v3_v3(verts[vert_index++].co, float3(x_pos, y_pos, z_pos));
+ }
+ }
+ }
+ else {
+ for (const int y : IndexRange(config.verts_y)) {
+ if (ELEM(y, 0, config.edges_y)) {
+ /* Fill y-sides. */
const float y_pos = y_front + y_delta * y;
const float z_pos = z_bottom + z_delta * z;
- copy_v3_v3(verts[vert_index].co, float3(x_pos, y_pos, z_pos));
-
- vert_index++;
+ for (const int x : IndexRange(config.verts_x)) {
+ const float x_pos = x_left + x_delta * x;
+ copy_v3_v3(verts[vert_index++].co, float3(x_pos, y_pos, z_pos));
+ }
+ }
+ else {
+ /* Fill x-sides. */
+ const float x_pos = x_left;
+ const float y_pos = y_front + y_delta * y;
+ const float z_pos = z_bottom + z_delta * z;
+ copy_v3_v3(verts[vert_index++].co, float3(x_pos, y_pos, z_pos));
+ const float x_pos2 = x_left + x_delta * config.edges_x;
+ copy_v3_v3(verts[vert_index++].co, float3(x_pos2, y_pos, z_pos));
}
}
}
@@ -439,6 +428,35 @@ Mesh *create_cuboid_mesh(const float3 size,
return mesh;
}
+} // namespace blender::nodes
+
+namespace blender::nodes::node_geo_mesh_primitive_cube_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Vector>(N_("Size"))
+ .default_value(float3(1))
+ .min(0.0f)
+ .subtype(PROP_TRANSLATION)
+ .description(N_("Side length along each axis"));
+ b.add_input<decl::Int>(N_("Vertices X"))
+ .default_value(2)
+ .min(2)
+ .max(1000)
+ .description(N_("Number of vertices for the X side of the shape"));
+ b.add_input<decl::Int>(N_("Vertices Y"))
+ .default_value(2)
+ .min(2)
+ .max(1000)
+ .description(N_("Number of vertices for the Y side of the shape"));
+ b.add_input<decl::Int>(N_("Vertices Z"))
+ .default_value(2)
+ .min(2)
+ .max(1000)
+ .description(N_("Number of vertices for the Z side of the shape"));
+ b.add_output<decl::Geometry>(N_("Mesh"));
+}
+
static Mesh *create_cube_mesh(const float3 size,
const int verts_x,
const int verts_y,
@@ -484,7 +502,7 @@ static Mesh *create_cube_mesh(const float3 size,
return create_cuboid_mesh(size, verts_x, verts_y, verts_z);
}
-static void geo_node_mesh_primitive_cube_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
const float3 size = params.extract_input<float3>("Size");
const int verts_x = params.extract_input<int>("Vertices X");
@@ -492,7 +510,7 @@ static void geo_node_mesh_primitive_cube_exec(GeoNodeExecParams params)
const int verts_z = params.extract_input<int>("Vertices Z");
if (verts_x < 1 || verts_y < 1 || verts_z < 1) {
params.error_message_add(NodeWarningType::Info, TIP_("Vertices must be at least 1"));
- params.set_output("Mesh", GeometrySet());
+ params.set_default_remaining_outputs();
return;
}
@@ -501,14 +519,16 @@ static void geo_node_mesh_primitive_cube_exec(GeoNodeExecParams params)
params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_mesh_primitive_cube_cc
void register_node_type_geo_mesh_primitive_cube()
{
+ namespace file_ns = blender::nodes::node_geo_mesh_primitive_cube_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CUBE, "Cube", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_mesh_primitive_cube_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_cube_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc
index a2ac46190b3..b8d2ed3be92 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc
@@ -25,9 +25,11 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_mesh_primitive_cylinder_cc {
-static void geo_node_mesh_primitive_cylinder_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryMeshCylinder)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Int>(N_("Vertices"))
.default_value(32)
@@ -60,16 +62,14 @@ static void geo_node_mesh_primitive_cylinder_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Bool>(N_("Bottom")).field_source();
}
-static void geo_node_mesh_primitive_cylinder_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
uiItemR(layout, ptr, "fill_type", 0, nullptr, ICON_NONE);
}
-static void geo_node_mesh_primitive_cylinder_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeGeometryMeshCylinder *node_storage = (NodeGeometryMeshCylinder *)MEM_callocN(
sizeof(NodeGeometryMeshCylinder), __func__);
@@ -79,53 +79,45 @@ static void geo_node_mesh_primitive_cylinder_init(bNodeTree *UNUSED(ntree), bNod
node->storage = node_storage;
}
-static void geo_node_mesh_primitive_cylinder_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
bNodeSocket *vertices_socket = (bNodeSocket *)node->inputs.first;
bNodeSocket *rings_socket = vertices_socket->next;
bNodeSocket *fill_subdiv_socket = rings_socket->next;
- const NodeGeometryMeshCone &storage = *(const NodeGeometryMeshCone *)node->storage;
- const GeometryNodeMeshCircleFillType fill_type =
- static_cast<const GeometryNodeMeshCircleFillType>(storage.fill_type);
- const bool has_fill = fill_type != GEO_NODE_MESH_CIRCLE_FILL_NONE;
+ const NodeGeometryMeshCylinder &storage = node_storage(*node);
+ const GeometryNodeMeshCircleFillType fill = (GeometryNodeMeshCircleFillType)storage.fill_type;
+ const bool has_fill = fill != GEO_NODE_MESH_CIRCLE_FILL_NONE;
nodeSetSocketAvailability(ntree, fill_subdiv_socket, has_fill);
}
-static void geo_node_mesh_primitive_cylinder_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
- const bNode &node = params.node();
- const NodeGeometryMeshCylinder &storage = *(const NodeGeometryMeshCylinder *)node.storage;
-
- const GeometryNodeMeshCircleFillType fill_type = (const GeometryNodeMeshCircleFillType)
- storage.fill_type;
-
- auto return_default = [&]() {
- params.set_output("Top", fn::make_constant_field<bool>(false));
- params.set_output("Bottom", fn::make_constant_field<bool>(false));
- params.set_output("Side", fn::make_constant_field<bool>(false));
- params.set_output("Mesh", GeometrySet());
- };
+ const NodeGeometryMeshCylinder &storage = node_storage(params.node());
+ const GeometryNodeMeshCircleFillType fill = (GeometryNodeMeshCircleFillType)storage.fill_type;
const float radius = params.extract_input<float>("Radius");
const float depth = params.extract_input<float>("Depth");
const int circle_segments = params.extract_input<int>("Vertices");
if (circle_segments < 3) {
params.error_message_add(NodeWarningType::Info, TIP_("Vertices must be at least 3"));
- return return_default();
+ params.set_default_remaining_outputs();
+ return;
}
const int side_segments = params.extract_input<int>("Side Segments");
if (side_segments < 1) {
params.error_message_add(NodeWarningType::Info, TIP_("Side Segments must be at least 1"));
- return return_default();
+ params.set_default_remaining_outputs();
+ return;
}
- const bool no_fill = fill_type == GEO_NODE_MESH_CIRCLE_FILL_NONE;
+ const bool no_fill = fill == GEO_NODE_MESH_CIRCLE_FILL_NONE;
const int fill_segments = no_fill ? 1 : params.extract_input<int>("Fill Segments");
if (fill_segments < 1) {
params.error_message_add(NodeWarningType::Info, TIP_("Fill Segments must be at least 1"));
- return return_default();
+ params.set_default_remaining_outputs();
+ return;
}
ConeAttributeOutputs attribute_outputs;
@@ -146,7 +138,7 @@ static void geo_node_mesh_primitive_cylinder_exec(GeoNodeExecParams params)
circle_segments,
side_segments,
fill_segments,
- fill_type,
+ fill,
attribute_outputs);
if (attribute_outputs.top_id) {
@@ -169,18 +161,20 @@ static void geo_node_mesh_primitive_cylinder_exec(GeoNodeExecParams params)
params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_mesh_primitive_cylinder_cc
void register_node_type_geo_mesh_primitive_cylinder()
{
+ namespace file_ns = blender::nodes::node_geo_mesh_primitive_cylinder_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CYLINDER, "Cylinder", NODE_CLASS_GEOMETRY, 0);
- node_type_init(&ntype, blender::nodes::geo_node_mesh_primitive_cylinder_init);
- node_type_update(&ntype, blender::nodes::geo_node_mesh_primitive_cylinder_update);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(
&ntype, "NodeGeometryMeshCylinder", node_free_standard_storage, node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_mesh_primitive_cylinder_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_cylinder_exec;
- ntype.draw_buttons = blender::nodes::geo_node_mesh_primitive_cylinder_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc
index 73c679e18f8..77634a03af6 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc
@@ -27,31 +27,6 @@
namespace blender::nodes {
-static void geo_node_mesh_primitive_grid_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Float>(N_("Size X"))
- .default_value(1.0f)
- .min(0.0f)
- .subtype(PROP_DISTANCE)
- .description(N_("Side length of the plane in the X direction"));
- b.add_input<decl::Float>(N_("Size Y"))
- .default_value(1.0f)
- .min(0.0f)
- .subtype(PROP_DISTANCE)
- .description(N_("Side length of the plane in the Y direction"));
- b.add_input<decl::Int>(N_("Vertices X"))
- .default_value(3)
- .min(2)
- .max(1000)
- .description(N_("Number of vertices in the X direction"));
- b.add_input<decl::Int>(N_("Vertices Y"))
- .default_value(3)
- .min(2)
- .max(1000)
- .description(N_("Number of vertices in the Y direction"));
- b.add_output<decl::Geometry>(N_("Mesh"));
-}
-
static void calculate_uvs(
Mesh *mesh, Span<MVert> verts, Span<MLoop> loops, const float size_x, const float size_y)
{
@@ -169,14 +144,43 @@ Mesh *create_grid_mesh(const int verts_x,
return mesh;
}
-static void geo_node_mesh_primitive_grid_exec(GeoNodeExecParams params)
+} // namespace blender::nodes
+
+namespace blender::nodes::node_geo_mesh_primitive_grid_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Size X"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .subtype(PROP_DISTANCE)
+ .description(N_("Side length of the plane in the X direction"));
+ b.add_input<decl::Float>(N_("Size Y"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .subtype(PROP_DISTANCE)
+ .description(N_("Side length of the plane in the Y direction"));
+ b.add_input<decl::Int>(N_("Vertices X"))
+ .default_value(3)
+ .min(2)
+ .max(1000)
+ .description(N_("Number of vertices in the X direction"));
+ b.add_input<decl::Int>(N_("Vertices Y"))
+ .default_value(3)
+ .min(2)
+ .max(1000)
+ .description(N_("Number of vertices in the Y direction"));
+ b.add_output<decl::Geometry>(N_("Mesh"));
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
{
const float size_x = params.extract_input<float>("Size X");
const float size_y = params.extract_input<float>("Size Y");
const int verts_x = params.extract_input<int>("Vertices X");
const int verts_y = params.extract_input<int>("Vertices Y");
if (verts_x < 1 || verts_y < 1) {
- params.set_output("Mesh", GeometrySet());
+ params.set_default_remaining_outputs();
return;
}
@@ -187,14 +191,16 @@ static void geo_node_mesh_primitive_grid_exec(GeoNodeExecParams params)
params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_mesh_primitive_grid_cc
void register_node_type_geo_mesh_primitive_grid()
{
+ namespace file_ns = blender::nodes::node_geo_mesh_primitive_grid_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_GRID, "Grid", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_mesh_primitive_grid_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_grid_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc
index e4bf5e31dbf..5f483a95063 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc
@@ -24,9 +24,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_mesh_primitive_ico_sphere_cc {
-static void geo_node_mesh_primitive_ico_sphere_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Float>(N_("Radius"))
.default_value(1.0f)
@@ -69,7 +69,7 @@ static Mesh *create_ico_sphere_mesh(const int subdivisions, const float radius)
return mesh;
}
-static void geo_node_mesh_primitive_ico_sphere_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
const int subdivisions = std::min(params.extract_input<int>("Subdivisions"), 10);
const float radius = params.extract_input<float>("Radius");
@@ -78,15 +78,17 @@ static void geo_node_mesh_primitive_ico_sphere_exec(GeoNodeExecParams params)
params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_mesh_primitive_ico_sphere_cc
void register_node_type_geo_mesh_primitive_ico_sphere()
{
+ namespace file_ns = blender::nodes::node_geo_mesh_primitive_ico_sphere_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_MESH_PRIMITIVE_ICO_SPHERE, "Ico Sphere", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_mesh_primitive_ico_sphere_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_ico_sphere_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc
index 1a92be1c05d..9a87c040bdf 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc
@@ -23,11 +23,15 @@
#include "UI_interface.h"
#include "UI_resources.h"
+#include "NOD_socket_search_link.hh"
+
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_mesh_primitive_line_cc {
+
+NODE_STORAGE_FUNCS(NodeGeometryMeshLine)
-static void geo_node_mesh_primitive_line_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Int>(N_("Count"))
.default_value(10)
@@ -51,9 +55,7 @@ static void geo_node_mesh_primitive_line_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Mesh"));
}
-static void geo_node_mesh_primitive_line_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
@@ -63,7 +65,7 @@ static void geo_node_mesh_primitive_line_layout(uiLayout *layout,
}
}
-static void geo_node_mesh_primitive_line_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeGeometryMeshLine *node_storage = (NodeGeometryMeshLine *)MEM_callocN(
sizeof(NodeGeometryMeshLine), __func__);
@@ -74,16 +76,16 @@ static void geo_node_mesh_primitive_line_init(bNodeTree *UNUSED(ntree), bNode *n
node->storage = node_storage;
}
-static void geo_node_mesh_primitive_line_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
bNodeSocket *count_socket = (bNodeSocket *)node->inputs.first;
bNodeSocket *resolution_socket = count_socket->next;
bNodeSocket *start_socket = resolution_socket->next;
bNodeSocket *end_and_offset_socket = start_socket->next;
- const NodeGeometryMeshLine &storage = *(const NodeGeometryMeshLine *)node->storage;
- const GeometryNodeMeshLineMode mode = (const GeometryNodeMeshLineMode)storage.mode;
- const GeometryNodeMeshLineCountMode count_mode = (const GeometryNodeMeshLineCountMode)
+ const NodeGeometryMeshLine &storage = node_storage(*node);
+ const GeometryNodeMeshLineMode mode = (GeometryNodeMeshLineMode)storage.mode;
+ const GeometryNodeMeshLineCountMode count_mode = (GeometryNodeMeshLineCountMode)
storage.count_mode;
node_sock_label(end_and_offset_socket,
@@ -100,44 +102,48 @@ static void geo_node_mesh_primitive_line_update(bNodeTree *ntree, bNode *node)
count_mode == GEO_NODE_MESH_LINE_COUNT_TOTAL);
}
-static void fill_edge_data(MutableSpan<MEdge> edges)
+static void node_gather_link_searches(GatherLinkSearchOpParams &params)
{
- for (const int i : edges.index_range()) {
- edges[i].v1 = i;
- edges[i].v2 = i + 1;
- edges[i].flag |= ME_LOOSEEDGE;
+ const NodeDeclaration &declaration = *params.node_type().fixed_declaration;
+ if (params.in_out() == SOCK_OUT) {
+ search_link_ops_for_declarations(params, declaration.outputs());
+ return;
}
-}
-
-Mesh *create_line_mesh(const float3 start, const float3 delta, const int count)
-{
- if (count < 1) {
- return nullptr;
- }
-
- Mesh *mesh = BKE_mesh_new_nomain(count, count - 1, 0, 0, 0);
- BKE_id_material_eval_ensure_default_slot(&mesh->id);
- MutableSpan<MVert> verts{mesh->mvert, mesh->totvert};
- MutableSpan<MEdge> edges{mesh->medge, mesh->totedge};
-
- short normal[3];
- normal_float_to_short_v3(normal, delta.normalized());
-
- for (const int i : verts.index_range()) {
- copy_v3_v3(verts[i].co, start + delta * i);
- copy_v3_v3_short(verts[i].no, normal);
+ else if (params.node_tree().typeinfo->validate_link(
+ static_cast<eNodeSocketDatatype>(params.other_socket().type), SOCK_FLOAT)) {
+ params.add_item(IFACE_("Count"), [](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeMeshLine");
+ node_storage(node).mode = GEO_NODE_MESH_LINE_MODE_OFFSET;
+ params.connect_available_socket(node, "Count");
+ });
+ params.add_item(IFACE_("Resolution"), [](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeMeshLine");
+ node_storage(node).mode = GEO_NODE_MESH_LINE_MODE_OFFSET;
+ node_storage(node).count_mode = GEO_NODE_MESH_LINE_COUNT_RESOLUTION;
+ params.connect_available_socket(node, "Resolution");
+ });
+ params.add_item(IFACE_("Start Location"), [](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeMeshLine");
+ params.connect_available_socket(node, "Start Location");
+ });
+ params.add_item(IFACE_("Offset"), [](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeMeshLine");
+ params.connect_available_socket(node, "Offset");
+ });
+ /* The last socket is reused in end points mode. */
+ params.add_item(IFACE_("End Location"), [](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeMeshLine");
+ node_storage(node).mode = GEO_NODE_MESH_LINE_MODE_END_POINTS;
+ params.connect_available_socket(node, "Offset");
+ });
}
-
- fill_edge_data(edges);
-
- return mesh;
}
-static void geo_node_mesh_primitive_line_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
- const NodeGeometryMeshLine &storage = *(const NodeGeometryMeshLine *)params.node().storage;
- const GeometryNodeMeshLineMode mode = (const GeometryNodeMeshLineMode)storage.mode;
- const GeometryNodeMeshLineCountMode count_mode = (const GeometryNodeMeshLineCountMode)
+ const NodeGeometryMeshLine &storage = node_storage(params.node());
+ const GeometryNodeMeshLineMode mode = (GeometryNodeMeshLineMode)storage.mode;
+ const GeometryNodeMeshLineCountMode count_mode = (GeometryNodeMeshLineCountMode)
storage.count_mode;
Mesh *mesh = nullptr;
@@ -174,19 +180,59 @@ static void geo_node_mesh_primitive_line_exec(GeoNodeExecParams params)
params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
}
+} // namespace blender::nodes::node_geo_mesh_primitive_line_cc
+
+namespace blender::nodes {
+
+static void fill_edge_data(MutableSpan<MEdge> edges)
+{
+ for (const int i : edges.index_range()) {
+ edges[i].v1 = i;
+ edges[i].v2 = i + 1;
+ edges[i].flag |= ME_LOOSEEDGE;
+ }
+}
+
+Mesh *create_line_mesh(const float3 start, const float3 delta, const int count)
+{
+ if (count < 1) {
+ return nullptr;
+ }
+
+ Mesh *mesh = BKE_mesh_new_nomain(count, count - 1, 0, 0, 0);
+ BKE_id_material_eval_ensure_default_slot(&mesh->id);
+ MutableSpan<MVert> verts{mesh->mvert, mesh->totvert};
+ MutableSpan<MEdge> edges{mesh->medge, mesh->totedge};
+
+ short normal[3];
+ normal_float_to_short_v3(normal, delta.normalized());
+
+ for (const int i : verts.index_range()) {
+ copy_v3_v3(verts[i].co, start + delta * i);
+ copy_v3_v3_short(verts[i].no, normal);
+ }
+
+ fill_edge_data(edges);
+
+ return mesh;
+}
+
} // namespace blender::nodes
void register_node_type_geo_mesh_primitive_line()
{
+ namespace file_ns = blender::nodes::node_geo_mesh_primitive_line_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_LINE, "Mesh Line", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_mesh_primitive_line_declare;
- node_type_init(&ntype, blender::nodes::geo_node_mesh_primitive_line_init);
- node_type_update(&ntype, blender::nodes::geo_node_mesh_primitive_line_update);
+ ntype.declare = file_ns::node_declare;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(
&ntype, "NodeGeometryMeshLine", node_free_standard_storage, node_copy_standard_storage);
- ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_line_exec;
- ntype.draw_buttons = blender::nodes::geo_node_mesh_primitive_line_layout;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.gather_link_search_ops = file_ns::node_gather_link_searches;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
index 3197a94c27b..ce2e0923a30 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
@@ -25,9 +25,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_mesh_primitive_uv_sphere_cc {
-static void geo_node_mesh_primitive_uv_shpere_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Int>(N_("Segments"))
.default_value(32)
@@ -292,7 +292,7 @@ static Mesh *create_uv_sphere_mesh(const float radius, const int segments, const
return mesh;
}
-static void geo_node_mesh_primitive_uv_sphere_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
const int segments_num = params.extract_input<int>("Segments");
const int rings_num = params.extract_input<int>("Rings");
@@ -303,7 +303,7 @@ static void geo_node_mesh_primitive_uv_sphere_exec(GeoNodeExecParams params)
if (rings_num < 3) {
params.error_message_add(NodeWarningType::Info, TIP_("Rings must be at least 3"));
}
- params.set_output("Mesh", GeometrySet());
+ params.set_default_remaining_outputs();
return;
}
@@ -313,15 +313,17 @@ static void geo_node_mesh_primitive_uv_sphere_exec(GeoNodeExecParams params)
params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_mesh_primitive_uv_sphere_cc
void register_node_type_geo_mesh_primitive_uv_sphere()
{
+ namespace file_ns = blender::nodes::node_geo_mesh_primitive_uv_sphere_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_MESH_PRIMITIVE_UV_SPHERE, "UV Sphere", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_mesh_primitive_uv_shpere_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_uv_sphere_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc
index d99c0c851a8..1ec9808044f 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc
@@ -23,9 +23,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_mesh_subdivide_cc {
-static void geo_node_mesh_subdivide_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH);
b.add_input<decl::Int>(N_("Level")).default_value(1).min(0).max(6);
@@ -72,14 +72,14 @@ static void geometry_set_mesh_subdivide(GeometrySet &geometry_set, const int lev
BKE_subdiv_free(subdiv);
}
-static void geo_node_mesh_subdivide_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
#ifndef WITH_OPENSUBDIV
params.error_message_add(NodeWarningType::Error,
TIP_("Disabled, Blender was compiled without OpenSubdiv"));
- params.set_output("Mesh", std::move(geometry_set));
+ params.set_default_remaining_outputs();
return;
#endif
@@ -97,14 +97,16 @@ static void geo_node_mesh_subdivide_exec(GeoNodeExecParams params)
params.set_output("Mesh", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_mesh_subdivide_cc
void register_node_type_geo_mesh_subdivide()
{
+ namespace file_ns = blender::nodes::node_geo_mesh_subdivide_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_SUBDIVIDE_MESH, "Subdivide Mesh", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_mesh_subdivide_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_mesh_subdivide_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc
index 11865c635b8..90f0af75788 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc
@@ -18,16 +18,16 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_mesh_to_curve_cc {
-static void geo_node_legacy_mesh_to_curve_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH);
b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
b.add_output<decl::Geometry>(N_("Curve"));
}
-static void geo_node_legacy_mesh_to_curve_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
@@ -56,14 +56,16 @@ static void geo_node_legacy_mesh_to_curve_exec(GeoNodeExecParams params)
params.set_output("Curve", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_mesh_to_curve_cc
void register_node_type_geo_mesh_to_curve()
{
+ namespace file_ns = blender::nodes::node_geo_mesh_to_curve_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_MESH_TO_CURVE, "Mesh to Curve", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_legacy_mesh_to_curve_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_legacy_mesh_to_curve_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc
index a37e3e34777..77314341fec 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc
@@ -26,9 +26,11 @@
using blender::Array;
-namespace blender::nodes {
+namespace blender::nodes::node_geo_mesh_to_points_cc {
-static void geo_node_mesh_to_points_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryMeshToPoints)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH);
b.add_input<decl::Bool>(N_("Selection")).default_value(true).supports_field().hide_value();
@@ -41,12 +43,12 @@ static void geo_node_mesh_to_points_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Points"));
}
-static void geo_node_mesh_to_points_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
}
-static void geo_node_mesh_to_points_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryMeshToPoints *data = (NodeGeometryMeshToPoints *)MEM_callocN(
sizeof(NodeGeometryMeshToPoints), __func__);
@@ -81,10 +83,15 @@ static void geometry_set_mesh_to_points(GeometrySet &geometry_set,
geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES});
return;
}
- fn::FieldEvaluator selection_evaluator{field_context, domain_size};
- selection_evaluator.add(selection_field);
- selection_evaluator.evaluate();
- const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.set_selection(selection_field);
+ /* Evaluating directly into the point cloud doesn't work because we are not using the full
+ * "min_array_size" array but compressing the selected elements into the final array with no
+ * gaps. */
+ evaluator.add(position_field);
+ evaluator.add(radius_field);
+ evaluator.evaluate();
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
PointCloud *pointcloud = BKE_pointcloud_new_nomain(selection.size());
uninitialized_fill_n(pointcloud->radius, pointcloud->totpoint, 0.05f);
@@ -92,13 +99,6 @@ static void geometry_set_mesh_to_points(GeometrySet &geometry_set,
PointCloudComponent &point_component =
geometry_set.get_component_for_write<PointCloudComponent>();
- /* Evaluating directly into the point cloud doesn't work because we are not using the full
- * "min_array_size" array but compressing the selected elements into the final array with no
- * gaps. */
- fn::FieldEvaluator evaluator{field_context, &selection};
- evaluator.add(position_field);
- evaluator.add(radius_field);
- evaluator.evaluate();
copy_attribute_to_points(evaluator.get_evaluated<float3>(0),
selection,
{(float3 *)pointcloud->co, pointcloud->totpoint});
@@ -129,7 +129,7 @@ static void geometry_set_mesh_to_points(GeometrySet &geometry_set,
geometry_set.keep_only({GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_INSTANCES});
}
-static void geo_node_mesh_to_points_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
Field<float3> position = params.extract_input<Field<float3>>("Position");
@@ -144,8 +144,7 @@ static void geo_node_mesh_to_points_exec(GeoNodeExecParams params)
FieldOperation(max_zero_fn, {std::move(radius)}));
Field<float> positive_radius(std::move(max_zero_op), 0);
- const NodeGeometryMeshToPoints &storage =
- *(const NodeGeometryMeshToPoints *)params.node().storage;
+ const NodeGeometryMeshToPoints &storage = node_storage(params.node());
const GeometryNodeMeshToPointsMode mode = (GeometryNodeMeshToPointsMode)storage.mode;
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
@@ -172,17 +171,19 @@ static void geo_node_mesh_to_points_exec(GeoNodeExecParams params)
params.set_output("Points", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_mesh_to_points_cc
void register_node_type_geo_mesh_to_points()
{
+ namespace file_ns = blender::nodes::node_geo_mesh_to_points_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_MESH_TO_POINTS, "Mesh to Points", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_mesh_to_points_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_mesh_to_points_exec;
- node_type_init(&ntype, blender::nodes::geo_node_mesh_to_points_init);
- ntype.draw_buttons = blender::nodes::geo_node_mesh_to_points_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ node_type_init(&ntype, file_ns::node_init);
+ ntype.draw_buttons = file_ns::node_layout;
node_type_storage(
&ntype, "NodeGeometryMeshToPoints", node_free_standard_storage, node_copy_standard_storage);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_object_info.cc b/source/blender/nodes/geometry/nodes/node_geo_object_info.cc
index bb8e5f7e29b..38c3b9cbcd9 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_object_info.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_object_info.cc
@@ -21,9 +21,11 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_object_info_cc {
-static void geo_node_object_info_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryObjectInfo)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Object>(N_("Object")).hide_label();
b.add_input<decl::Bool>(N_("As Instance"))
@@ -35,31 +37,22 @@ static void geo_node_object_info_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_object_info_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "transform_space", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
}
-static void geo_node_object_info_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
- const bNode &bnode = params.node();
- NodeGeometryObjectInfo *node_storage = (NodeGeometryObjectInfo *)bnode.storage;
- const bool transform_space_relative = (node_storage->transform_space ==
+ const NodeGeometryObjectInfo &storage = node_storage(params.node());
+ const bool transform_space_relative = (storage.transform_space ==
GEO_NODE_TRANSFORM_SPACE_RELATIVE);
- auto default_transform = [&]() {
- params.set_output("Location", float3(0));
- params.set_output("Rotation", float3(0));
- params.set_output("Scale", float3(0));
- };
- auto default_geometry = [&]() { params.set_output("Geometry", GeometrySet()); };
-
Object *object = params.get_input<Object *>("Object");
const Object *self_object = params.self_object();
if (object == nullptr) {
- default_transform();
- default_geometry();
+ params.set_default_remaining_outputs();
return;
}
@@ -81,7 +74,7 @@ static void geo_node_object_info_exec(GeoNodeExecParams params)
if (object == self_object) {
params.error_message_add(NodeWarningType::Error,
TIP_("Geometry cannot be retrieved from the modifier object"));
- default_geometry();
+ params.set_default_remaining_outputs();
return;
}
@@ -107,7 +100,7 @@ static void geo_node_object_info_exec(GeoNodeExecParams params)
}
}
-static void geo_node_object_info_node_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryObjectInfo *data = (NodeGeometryObjectInfo *)MEM_callocN(
sizeof(NodeGeometryObjectInfo), __func__);
@@ -115,18 +108,20 @@ static void geo_node_object_info_node_init(bNodeTree *UNUSED(tree), bNode *node)
node->storage = data;
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_object_info_cc
void register_node_type_geo_object_info()
{
+ namespace file_ns = blender::nodes::node_geo_object_info_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_OBJECT_INFO, "Object Info", NODE_CLASS_INPUT, 0);
- node_type_init(&ntype, blender::nodes::geo_node_object_info_node_init);
+ node_type_init(&ntype, file_ns::node_node_init);
node_type_storage(
&ntype, "NodeGeometryObjectInfo", node_free_standard_storage, node_copy_standard_storage);
- ntype.geometry_node_execute = blender::nodes::geo_node_object_info_exec;
- ntype.draw_buttons = blender::nodes::geo_node_object_info_layout;
- ntype.declare = blender::nodes::geo_node_object_info_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc b/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc
index 5a6a3b25a45..5510773eabd 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc
@@ -21,11 +21,11 @@
#include "node_geometry_util.hh"
-using blender::Array;
+namespace blender::nodes::node_geo_points_to_vertices_cc {
-namespace blender::nodes {
+using blender::Array;
-static void geo_node_points_to_vertices_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Points")).supported_type(GEO_COMPONENT_TYPE_POINT_CLOUD);
b.add_input<decl::Bool>(N_("Selection")).default_value(true).supports_field().hide_value();
@@ -92,7 +92,7 @@ static void geometry_set_points_to_vertices(GeometrySet &geometry_set,
geometry_set.keep_only({GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_INSTANCES});
}
-static void geo_node_points_to_vertices_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Points");
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
@@ -104,15 +104,17 @@ static void geo_node_points_to_vertices_exec(GeoNodeExecParams params)
params.set_output("Mesh", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_points_to_vertices_cc
void register_node_type_geo_points_to_vertices()
{
+ namespace file_ns = blender::nodes::node_geo_points_to_vertices_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_POINTS_TO_VERTICES, "Points to Vertices", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_points_to_vertices_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_points_to_vertices_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc b/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc
index 31c16cb95e0..744cce6d445 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc
@@ -28,14 +28,27 @@
#include "UI_interface.h"
#include "UI_resources.h"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_points_to_volume_cc {
-static void geo_node_points_to_volume_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryPointsToVolume)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Points"));
b.add_input<decl::Float>(N_("Density")).default_value(1.0f).min(0.0f);
- b.add_input<decl::Float>(N_("Voxel Size")).default_value(0.3f).min(0.01f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>(N_("Voxel Amount")).default_value(64.0f).min(0.0f);
+ b.add_input<decl::Float>(N_("Voxel Size"))
+ .default_value(0.3f)
+ .min(0.01f)
+ .subtype(PROP_DISTANCE)
+ .make_available([](bNode &node) {
+ node_storage(node).resolution_mode = GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE;
+ });
+ b.add_input<decl::Float>(N_("Voxel Amount"))
+ .default_value(64.0f)
+ .min(0.0f)
+ .make_available([](bNode &node) {
+ node_storage(node).resolution_mode = GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT;
+ });
b.add_input<decl::Float>(N_("Radius"))
.default_value(0.5f)
.min(0.0f)
@@ -44,16 +57,14 @@ static void geo_node_points_to_volume_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Volume"));
}
-static void geo_node_points_to_volume_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
uiItemR(layout, ptr, "resolution_mode", 0, IFACE_("Resolution"), ICON_NONE);
}
-static void geo_node_points_to_volume_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeGeometryPointsToVolume *data = (NodeGeometryPointsToVolume *)MEM_callocN(
sizeof(NodeGeometryPointsToVolume), __func__);
@@ -61,18 +72,18 @@ static void geo_node_points_to_volume_init(bNodeTree *UNUSED(ntree), bNode *node
node->storage = data;
}
-static void geo_node_points_to_volume_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
- NodeGeometryPointsToVolume *data = (NodeGeometryPointsToVolume *)node->storage;
+ const NodeGeometryPointsToVolume &storage = node_storage(*node);
bNodeSocket *voxel_size_socket = nodeFindSocket(node, SOCK_IN, "Voxel Size");
bNodeSocket *voxel_amount_socket = nodeFindSocket(node, SOCK_IN, "Voxel Amount");
nodeSetSocketAvailability(ntree,
voxel_amount_socket,
- data->resolution_mode ==
+ storage.resolution_mode ==
GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT);
nodeSetSocketAvailability(ntree,
voxel_size_socket,
- data->resolution_mode ==
+ storage.resolution_mode ==
GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE);
}
@@ -136,8 +147,7 @@ static float compute_voxel_size(const GeoNodeExecParams &params,
Span<float3> positions,
const float radius)
{
- const NodeGeometryPointsToVolume &storage =
- *(const NodeGeometryPointsToVolume *)params.node().storage;
+ const NodeGeometryPointsToVolume &storage = node_storage(params.node());
if (storage.resolution_mode == GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE) {
return params.get_input<float>("Voxel Size");
@@ -236,7 +246,7 @@ static void initialize_volume_component_from_points(GeoNodeExecParams &params,
}
#endif
-static void geo_node_points_to_volume_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Points");
@@ -248,14 +258,16 @@ static void geo_node_points_to_volume_exec(GeoNodeExecParams params)
#else
params.error_message_add(NodeWarningType::Error,
TIP_("Disabled, Blender was compiled without OpenVDB"));
- params.set_output("Volume", GeometrySet());
+ params.set_default_remaining_outputs();
#endif
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_points_to_volume_cc
void register_node_type_geo_points_to_volume()
{
+ namespace file_ns = blender::nodes::node_geo_points_to_volume_cc;
+
static bNodeType ntype;
geo_node_type_base(
@@ -265,10 +277,10 @@ void register_node_type_geo_points_to_volume()
node_free_standard_storage,
node_copy_standard_storage);
node_type_size(&ntype, 170, 120, 700);
- node_type_init(&ntype, blender::nodes::geo_node_points_to_volume_init);
- node_type_update(&ntype, blender::nodes::geo_node_points_to_volume_update);
- ntype.declare = blender::nodes::geo_node_points_to_volume_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_points_to_volume_exec;
- ntype.draw_buttons = blender::nodes::geo_node_points_to_volume_layout;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_proximity.cc b/source/blender/nodes/geometry/nodes/node_geo_proximity.cc
index c05476b982b..aa3383e68be 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_proximity.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_proximity.cc
@@ -27,9 +27,11 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_proximity_cc {
-static void geo_node_proximity_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryProximity)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Target"))
.only_realized_data()
@@ -39,7 +41,7 @@ static void geo_node_proximity_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Float>(N_("Distance")).dependent_field();
}
-static void geo_node_proximity_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "target_element", 0, "", ICON_NONE);
}
@@ -206,21 +208,17 @@ class ProximityFunction : public fn::MultiFunction {
}
};
-static void geo_node_proximity_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set_target = params.extract_input<GeometrySet>("Target");
geometry_set_target.ensure_owns_direct_data();
- auto return_default = [&]() {
- params.set_output("Position", fn::make_constant_field<float3>({0.0f, 0.0f, 0.0f}));
- params.set_output("Distance", fn::make_constant_field<float>(0.0f));
- };
-
if (!geometry_set_target.has_mesh() && !geometry_set_target.has_pointcloud()) {
- return return_default();
+ params.set_default_remaining_outputs();
+ return;
}
- const NodeGeometryProximity &storage = *(const NodeGeometryProximity *)params.node().storage;
+ const NodeGeometryProximity &storage = node_storage(params.node());
Field<float3> position_field = params.extract_input<Field<float3>>("Source Position");
auto proximity_fn = std::make_unique<ProximityFunction>(
@@ -233,18 +231,20 @@ static void geo_node_proximity_exec(GeoNodeExecParams params)
params.set_output("Distance", Field<float>(proximity_op, 1));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_proximity_cc
void register_node_type_geo_proximity()
{
+ namespace file_ns = blender::nodes::node_geo_proximity_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_PROXIMITY, "Geometry Proximity", NODE_CLASS_GEOMETRY, 0);
- node_type_init(&ntype, blender::nodes::geo_proximity_init);
+ node_type_init(&ntype, file_ns::geo_proximity_init);
node_type_storage(
&ntype, "NodeGeometryProximity", node_free_standard_storage, node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_proximity_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_proximity_exec;
- ntype.draw_buttons = blender::nodes::geo_node_proximity_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_raycast.cc b/source/blender/nodes/geometry/nodes/node_geo_raycast.cc
index d422bf5a00a..d255fe482f6 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_raycast.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_raycast.cc
@@ -23,13 +23,17 @@
#include "UI_interface.h"
#include "UI_resources.h"
+#include "NOD_socket_search_link.hh"
+
#include "node_geometry_util.hh"
+namespace blender::nodes::node_geo_raycast_cc {
+
using namespace blender::bke::mesh_surface_sample;
-namespace blender::nodes {
+NODE_STORAGE_FUNCS(NodeGeometryRaycast)
-static void geo_node_raycast_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Target Geometry"))
.only_realized_data()
@@ -63,13 +67,13 @@ static void geo_node_raycast_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Int>(N_("Attribute"), "Attribute_004").dependent_field({1, 2, 3, 4, 5, 6});
}
-static void geo_node_raycast_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
uiItemR(layout, ptr, "mapping", 0, "", ICON_NONE);
}
-static void geo_node_raycast_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryRaycast *data = (NodeGeometryRaycast *)MEM_callocN(sizeof(NodeGeometryRaycast),
__func__);
@@ -78,10 +82,10 @@ static void geo_node_raycast_init(bNodeTree *UNUSED(tree), bNode *node)
node->storage = data;
}
-static void geo_node_raycast_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
- const NodeGeometryRaycast &data = *(const NodeGeometryRaycast *)node->storage;
- const CustomDataType data_type = static_cast<CustomDataType>(data.data_type);
+ const NodeGeometryRaycast &storage = node_storage(*node);
+ const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
bNodeSocket *socket_vector = (bNodeSocket *)BLI_findlink(&node->inputs, 1);
bNodeSocket *socket_float = socket_vector->next;
@@ -108,6 +112,25 @@ static void geo_node_raycast_update(bNodeTree *ntree, bNode *node)
nodeSetSocketAvailability(ntree, out_socket_int32, data_type == CD_PROP_INT32);
}
+static void node_gather_link_searches(GatherLinkSearchOpParams &params)
+{
+ const NodeDeclaration &declaration = *params.node_type().fixed_declaration;
+ search_link_ops_for_declarations(params, declaration.inputs().take_front(1));
+ search_link_ops_for_declarations(params, declaration.inputs().take_back(3));
+ search_link_ops_for_declarations(params, declaration.outputs().take_front(4));
+
+ const std::optional<CustomDataType> type = node_data_type_to_custom_data_type(
+ (eNodeSocketDatatype)params.other_socket().type);
+ if (type && *type != CD_PROP_STRING) {
+ /* The input and output sockets have the same name. */
+ params.add_item(IFACE_("Attribute"), [type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeRaycast");
+ node_storage(node).data_type = *type;
+ params.update_and_connect_available_socket(node, "Attribute");
+ });
+ }
+}
+
static eAttributeMapMode get_map_mode(GeometryNodeRaycastMapMode map_mode)
{
switch (map_mode) {
@@ -205,10 +228,10 @@ class RaycastFunction : public fn::MultiFunction {
std::unique_ptr<FieldEvaluator> target_evaluator_;
const GVArray *target_data_ = nullptr;
- /* Always evaluate the target domain data on the point domain. Eventually this could be
- * exposed as an option or determined automatically from the field inputs in order to avoid
- * losing information if the target field is on a different domain. */
- const AttributeDomain domain_ = ATTR_DOMAIN_POINT;
+ /* Always evaluate the target domain data on the face corner domain because it contains the most
+ * information. Eventually this could be exposed as an option or determined automatically from
+ * the field inputs for better performance. */
+ const AttributeDomain domain_ = ATTR_DOMAIN_CORNER;
fn::MFSignature signature_;
@@ -375,35 +398,27 @@ static void output_attribute_field(GeoNodeExecParams &params, GField field)
}
}
-static void geo_node_raycast_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet target = params.extract_input<GeometrySet>("Target Geometry");
- const NodeGeometryRaycast &data = *(const NodeGeometryRaycast *)params.node().storage;
- const GeometryNodeRaycastMapMode mapping = static_cast<GeometryNodeRaycastMapMode>(data.mapping);
- const CustomDataType data_type = static_cast<CustomDataType>(data.data_type);
-
- auto return_default = [&]() {
- params.set_output("Is Hit", fn::make_constant_field<bool>(false));
- params.set_output("Hit Position", fn::make_constant_field<float3>({0.0f, 0.0f, 0.0f}));
- params.set_output("Hit Normal", fn::make_constant_field<float3>({0.0f, 0.0f, 0.0f}));
- params.set_output("Hit Distance", fn::make_constant_field<float>(0.0f));
- attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
- using T = decltype(dummy);
- output_attribute_field(params, fn::make_constant_field<T>(T()));
- });
- };
+ const NodeGeometryRaycast &storage = node_storage(params.node());
+ const GeometryNodeRaycastMapMode mapping = (GeometryNodeRaycastMapMode)storage.mapping;
+ const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
if (target.is_empty()) {
- return return_default();
+ params.set_default_remaining_outputs();
+ return;
}
if (!target.has_mesh()) {
- return return_default();
+ params.set_default_remaining_outputs();
+ return;
}
if (target.get_mesh_for_read()->totpoly == 0) {
params.error_message_add(NodeWarningType::Error, TIP_("The target mesh must have faces"));
- return return_default();
+ params.set_default_remaining_outputs();
+ return;
}
GField field = get_input_attribute_field(params, data_type);
@@ -426,20 +441,23 @@ static void geo_node_raycast_exec(GeoNodeExecParams params)
}
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_raycast_cc
void register_node_type_geo_raycast()
{
+ namespace file_ns = blender::nodes::node_geo_raycast_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_RAYCAST, "Raycast", NODE_CLASS_GEOMETRY, 0);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, blender::nodes::geo_node_raycast_init);
- node_type_update(&ntype, blender::nodes::geo_node_raycast_update);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(
&ntype, "NodeGeometryRaycast", node_free_standard_storage, node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_raycast_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_raycast_exec;
- ntype.draw_buttons = blender::nodes::geo_node_raycast_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.gather_link_search_ops = file_ns::node_gather_link_searches;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc
index 6c51c1f738f..fad35389823 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc
@@ -16,33 +16,48 @@
#include "node_geometry_util.hh"
+#include "GEO_realize_instances.hh"
+
#include "UI_interface.h"
#include "UI_resources.h"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_realize_instances_cc {
-static void geo_node_realize_instances_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_realize_instances_exec(GeoNodeExecParams params)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "legacy_behavior", 0, nullptr, ICON_NONE);
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
{
+ const bool legacy_behavior = params.node().custom1 & GEO_NODE_REALIZE_INSTANCES_LEGACY_BEHAVIOR;
+
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = bke::geometry_set_realize_instances(geometry_set);
+ geometry::RealizeInstancesOptions options;
+ options.keep_original_ids = legacy_behavior;
+ options.realize_instance_attributes = !legacy_behavior;
+ geometry_set = geometry::realize_instances(geometry_set, options);
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_realize_instances_cc
void register_node_type_geo_realize_instances()
{
+ namespace file_ns = blender::nodes::node_geo_realize_instances_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_REALIZE_INSTANCES, "Realize Instances", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_realize_instances_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_realize_instances_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons_ex = file_ns::node_layout;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc
index c53eaa2ded9..335484c62b0 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc
@@ -18,9 +18,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_rotate_instances_cc {
-static void geo_node_rotate_instances_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Instances")).only_instances();
b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
@@ -35,19 +35,17 @@ static void rotate_instances(GeoNodeExecParams &params, InstancesComponent &inst
GeometryComponentFieldContext field_context{instances_component, ATTR_DOMAIN_INSTANCE};
const int domain_size = instances_component.instances_amount();
- fn::FieldEvaluator selection_evaluator{field_context, domain_size};
- selection_evaluator.add(params.extract_input<Field<bool>>("Selection"));
- selection_evaluator.evaluate();
- const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.set_selection(params.extract_input<Field<bool>>("Selection"));
+ evaluator.add(params.extract_input<Field<float3>>("Rotation"));
+ evaluator.add(params.extract_input<Field<float3>>("Pivot Point"));
+ evaluator.add(params.extract_input<Field<bool>>("Local Space"));
+ evaluator.evaluate();
- fn::FieldEvaluator transforms_evaluator{field_context, &selection};
- transforms_evaluator.add(params.extract_input<Field<float3>>("Rotation"));
- transforms_evaluator.add(params.extract_input<Field<float3>>("Pivot Point"));
- transforms_evaluator.add(params.extract_input<Field<bool>>("Local Space"));
- transforms_evaluator.evaluate();
- const VArray<float3> &rotations = transforms_evaluator.get_evaluated<float3>(0);
- const VArray<float3> &pivots = transforms_evaluator.get_evaluated<float3>(1);
- const VArray<bool> &local_spaces = transforms_evaluator.get_evaluated<bool>(2);
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
+ const VArray<float3> &rotations = evaluator.get_evaluated<float3>(0);
+ const VArray<float3> &pivots = evaluator.get_evaluated<float3>(1);
+ const VArray<bool> &local_spaces = evaluator.get_evaluated<bool>(2);
MutableSpan<float4x4> instance_transforms = instances_component.instance_transforms();
@@ -96,7 +94,7 @@ static void rotate_instances(GeoNodeExecParams &params, InstancesComponent &inst
});
}
-static void geo_node_rotate_instances_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Instances");
if (geometry_set.has_instances()) {
@@ -106,15 +104,17 @@ static void geo_node_rotate_instances_exec(GeoNodeExecParams params)
params.set_output("Instances", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_rotate_instances_cc
void register_node_type_geo_rotate_instances()
{
+ namespace file_ns = blender::nodes::node_geo_rotate_instances_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_ROTATE_INSTANCES, "Rotate Instances", NODE_CLASS_GEOMETRY, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_rotate_instances_exec;
- ntype.declare = blender::nodes::geo_node_rotate_instances_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc
index fa2501515a9..1779ac8bff7 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc
@@ -18,9 +18,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_scale_instances_cc {
-static void geo_node_scale_instances_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Instances")).only_instances();
b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
@@ -37,19 +37,17 @@ static void scale_instances(GeoNodeExecParams &params, InstancesComponent &insta
{
GeometryComponentFieldContext field_context{instances_component, ATTR_DOMAIN_INSTANCE};
- fn::FieldEvaluator selection_evaluator{field_context, instances_component.instances_amount()};
- selection_evaluator.add(params.extract_input<Field<bool>>("Selection"));
- selection_evaluator.evaluate();
- const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
+ fn::FieldEvaluator evaluator{field_context, instances_component.instances_amount()};
+ evaluator.set_selection(params.extract_input<Field<bool>>("Selection"));
+ evaluator.add(params.extract_input<Field<float3>>("Scale"));
+ evaluator.add(params.extract_input<Field<float3>>("Center"));
+ evaluator.add(params.extract_input<Field<bool>>("Local Space"));
+ evaluator.evaluate();
- fn::FieldEvaluator transforms_evaluator{field_context, &selection};
- transforms_evaluator.add(params.extract_input<Field<float3>>("Scale"));
- transforms_evaluator.add(params.extract_input<Field<float3>>("Center"));
- transforms_evaluator.add(params.extract_input<Field<bool>>("Local Space"));
- transforms_evaluator.evaluate();
- const VArray<float3> &scales = transforms_evaluator.get_evaluated<float3>(0);
- const VArray<float3> &pivots = transforms_evaluator.get_evaluated<float3>(1);
- const VArray<bool> &local_spaces = transforms_evaluator.get_evaluated<bool>(2);
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
+ const VArray<float3> &scales = evaluator.get_evaluated<float3>(0);
+ const VArray<float3> &pivots = evaluator.get_evaluated<float3>(1);
+ const VArray<bool> &local_spaces = evaluator.get_evaluated<bool>(2);
MutableSpan<float4x4> instance_transforms = instances_component.instance_transforms();
@@ -75,7 +73,7 @@ static void scale_instances(GeoNodeExecParams &params, InstancesComponent &insta
});
}
-static void geo_node_scale_instances_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Instances");
if (geometry_set.has_instances()) {
@@ -85,14 +83,16 @@ static void geo_node_scale_instances_exec(GeoNodeExecParams params)
params.set_output("Instances", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_scale_instances_cc
void register_node_type_geo_scale_instances()
{
+ namespace file_ns = blender::nodes::node_geo_scale_instances_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_SCALE_INSTANCES, "Scale Instances", NODE_CLASS_GEOMETRY, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_scale_instances_exec;
- ntype.declare = blender::nodes::geo_node_scale_instances_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_separate_components.cc b/source/blender/nodes/geometry/nodes/node_geo_separate_components.cc
index a16fb712b13..e4adfe6587d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_separate_components.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_separate_components.cc
@@ -16,9 +16,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_separate_components_cc {
-static void geo_node_join_geometry_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_output<decl::Geometry>(N_("Mesh"));
@@ -28,7 +28,7 @@ static void geo_node_join_geometry_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Instances"));
}
-static void geo_node_separate_components_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
@@ -61,15 +61,17 @@ static void geo_node_separate_components_exec(GeoNodeExecParams params)
params.set_output("Instances", instances);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_separate_components_cc
void register_node_type_geo_separate_components()
{
+ namespace file_ns = blender::nodes::node_geo_separate_components_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_SEPARATE_COMPONENTS, "Separate Components", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_join_geometry_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_separate_components_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc
index 28e214c0ccc..7f1cc1be421 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc
@@ -19,9 +19,11 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_separate_geometry_cc {
-static void geo_node_separate_geometry_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometrySeparateGeometry)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::Bool>(N_("Selection"))
@@ -35,14 +37,12 @@ static void geo_node_separate_geometry_declare(NodeDeclarationBuilder &b)
.description(N_("The parts of the geometry not in the selection"));
}
-static void geo_node_separate_geometry_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "domain", 0, "", ICON_NONE);
}
-static void geo_node_separate_geometry_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometrySeparateGeometry *data = (NodeGeometrySeparateGeometry *)MEM_callocN(
sizeof(NodeGeometrySeparateGeometry), __func__);
@@ -51,14 +51,13 @@ static void geo_node_separate_geometry_init(bNodeTree *UNUSED(tree), bNode *node
node->storage = data;
}
-static void geo_node_separate_geometry_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
const Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
- const bNode &node = params.node();
- const NodeGeometryDeleteGeometry &storage = *(const NodeGeometryDeleteGeometry *)node.storage;
+ const NodeGeometrySeparateGeometry &storage = node_storage(params.node());
const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain);
bool all_is_error = false;
@@ -95,10 +94,12 @@ static void geo_node_separate_geometry_exec(GeoNodeExecParams params)
}
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_separate_geometry_cc
void register_node_type_geo_separate_geometry()
{
+ namespace file_ns = blender::nodes::node_geo_separate_geometry_cc;
+
static bNodeType ntype;
geo_node_type_base(
@@ -109,10 +110,10 @@ void register_node_type_geo_separate_geometry()
node_free_standard_storage,
node_copy_standard_storage);
- node_type_init(&ntype, blender::nodes::geo_node_separate_geometry_init);
+ node_type_init(&ntype, file_ns::node_init);
- ntype.declare = blender::nodes::geo_node_separate_geometry_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_separate_geometry_exec;
- ntype.draw_buttons = blender::nodes::geo_node_separate_geometry_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc
index 30b445da58c..f98b4116526 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc
@@ -21,9 +21,11 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_set_curve_handles_cc {
-static void geo_node_set_curve_handles_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometrySetCurveHandlePositions)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
@@ -32,14 +34,12 @@ static void geo_node_set_curve_handles_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Curve"));
}
-static void geo_node_set_curve_handles_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
}
-static void geo_node_set_curve_handles_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometrySetCurveHandlePositions *data = (NodeGeometrySetCurveHandlePositions *)MEM_callocN(
sizeof(NodeGeometrySetCurveHandlePositions), __func__);
@@ -60,10 +60,12 @@ static void set_position_in_component(const GeometryNodeCurveHandleMode mode,
return;
}
- fn::FieldEvaluator selection_evaluator{field_context, domain_size};
- selection_evaluator.add(selection_field);
- selection_evaluator.evaluate();
- const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.set_selection(selection_field);
+ evaluator.add(position_field);
+ evaluator.add(offset_field);
+ evaluator.evaluate();
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
CurveComponent *curve_component = static_cast<CurveComponent *>(&component);
CurveEval *curve = curve_component->get_for_write();
@@ -77,7 +79,7 @@ static void set_position_in_component(const GeometryNodeCurveHandleMode mode,
if (spline->type() == Spline::Type::Bezier) {
BezierSpline &bezier = static_cast<BezierSpline &>(*spline);
for (int i : bezier.positions().index_range()) {
- if (selection[current_mask] == current_point) {
+ if (current_mask < selection.size() && selection[current_mask] == current_point) {
if (mode & GEO_NODE_CURVE_HANDLE_LEFT) {
if (bezier.handle_types_left()[i] == BezierSpline::HandleType::Vector) {
bezier.ensure_auto_handles();
@@ -105,7 +107,7 @@ static void set_position_in_component(const GeometryNodeCurveHandleMode mode,
}
else {
for (int UNUSED(i) : spline->positions().index_range()) {
- if (selection[current_mask] == current_point) {
+ if (current_mask < selection.size() && selection[current_mask] == current_point) {
current_mask++;
}
current_point++;
@@ -113,13 +115,8 @@ static void set_position_in_component(const GeometryNodeCurveHandleMode mode,
}
}
- fn::FieldEvaluator position_evaluator{field_context, &selection};
- position_evaluator.add(position_field);
- position_evaluator.add(offset_field);
- position_evaluator.evaluate();
-
- const VArray<float3> &positions_input = position_evaluator.get_evaluated<float3>(0);
- const VArray<float3> &offsets_input = position_evaluator.get_evaluated<float3>(1);
+ const VArray<float3> &positions_input = evaluator.get_evaluated<float3>(0);
+ const VArray<float3> &offsets_input = evaluator.get_evaluated<float3>(1);
OutputAttribute_Typed<float3> positions = component.attribute_try_get_for_output<float3>(
side, ATTR_DOMAIN_POINT, {0, 0, 0});
@@ -132,11 +129,10 @@ static void set_position_in_component(const GeometryNodeCurveHandleMode mode,
positions.save();
}
-static void geo_node_set_curve_handles_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
- const NodeGeometrySetCurveHandlePositions *node_storage =
- (NodeGeometrySetCurveHandlePositions *)params.node().storage;
- const GeometryNodeCurveHandleMode mode = (GeometryNodeCurveHandleMode)node_storage->mode;
+ const NodeGeometrySetCurveHandlePositions &storage = node_storage(params.node());
+ const GeometryNodeCurveHandleMode mode = (GeometryNodeCurveHandleMode)storage.mode;
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
@@ -162,22 +158,24 @@ static void geo_node_set_curve_handles_exec(GeoNodeExecParams params)
params.set_output("Curve", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_set_curve_handles_cc
void register_node_type_geo_set_curve_handles()
{
+ namespace file_ns = blender::nodes::node_geo_set_curve_handles_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_SET_CURVE_HANDLES, "Set Handle Positions", NODE_CLASS_GEOMETRY, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_set_curve_handles_exec;
- ntype.declare = blender::nodes::geo_node_set_curve_handles_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
ntype.minwidth = 100.0f;
- node_type_init(&ntype, blender::nodes::geo_node_set_curve_handles_init);
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(&ntype,
"NodeGeometrySetCurveHandlePositions",
node_free_standard_storage,
node_copy_standard_storage);
- ntype.draw_buttons = blender::nodes::geo_node_set_curve_handles_layout;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc b/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc
index e47ce7dea30..7d99f42c487 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc
@@ -16,9 +16,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_set_curve_radius_cc {
-static void geo_node_set_curve_radius_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
@@ -40,20 +40,18 @@ static void set_radius_in_component(GeometryComponent &component,
return;
}
- fn::FieldEvaluator selection_evaluator{field_context, domain_size};
- selection_evaluator.add(selection_field);
- selection_evaluator.evaluate();
- const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
-
OutputAttribute_Typed<float> radii = component.attribute_try_get_for_output_only<float>(
"radius", ATTR_DOMAIN_POINT);
- fn::FieldEvaluator radii_evaluator{field_context, &selection};
- radii_evaluator.add_with_destination(radius_field, radii.varray());
- radii_evaluator.evaluate();
+
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.set_selection(selection_field);
+ evaluator.add_with_destination(radius_field, radii.varray());
+ evaluator.evaluate();
+
radii.save();
}
-static void geo_node_set_curve_radius_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
@@ -69,15 +67,17 @@ static void geo_node_set_curve_radius_exec(GeoNodeExecParams params)
params.set_output("Curve", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_set_curve_radius_cc
void register_node_type_geo_set_curve_radius()
{
+ namespace file_ns = blender::nodes::node_geo_set_curve_radius_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_SET_CURVE_RADIUS, "Set Curve Radius", NODE_CLASS_GEOMETRY, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_set_curve_radius_exec;
- ntype.declare = blender::nodes::geo_node_set_curve_radius_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc b/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc
index a861c35f738..447310e1ad7 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc
@@ -16,9 +16,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_set_curve_tilt_cc {
-static void geo_node_set_curve_tilt_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
@@ -36,20 +36,18 @@ static void set_tilt_in_component(GeometryComponent &component,
return;
}
- fn::FieldEvaluator selection_evaluator{field_context, domain_size};
- selection_evaluator.add(selection_field);
- selection_evaluator.evaluate();
- const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
-
OutputAttribute_Typed<float> tilts = component.attribute_try_get_for_output_only<float>(
"tilt", ATTR_DOMAIN_POINT);
- fn::FieldEvaluator tilt_evaluator{field_context, &selection};
- tilt_evaluator.add_with_destination(tilt_field, tilts.varray());
- tilt_evaluator.evaluate();
+
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.set_selection(selection_field);
+ evaluator.add_with_destination(tilt_field, tilts.varray());
+ evaluator.evaluate();
+
tilts.save();
}
-static void geo_node_set_curve_tilt_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
@@ -65,14 +63,16 @@ static void geo_node_set_curve_tilt_exec(GeoNodeExecParams params)
params.set_output("Curve", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_set_curve_tilt_cc
void register_node_type_geo_set_curve_tilt()
{
+ namespace file_ns = blender::nodes::node_geo_set_curve_tilt_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_SET_CURVE_TILT, "Set Curve Tilt", NODE_CLASS_GEOMETRY, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_set_curve_tilt_exec;
- ntype.declare = blender::nodes::geo_node_set_curve_tilt_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_id.cc b/source/blender/nodes/geometry/nodes/node_geo_set_id.cc
index 77d8e786501..db4083acd4b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_id.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_id.cc
@@ -16,9 +16,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_set_id_cc {
-static void geo_node_set_id_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
@@ -36,26 +36,24 @@ static void set_id_in_component(GeometryComponent &component,
return;
}
- fn::FieldEvaluator selection_evaluator{field_context, domain_size};
- selection_evaluator.add(selection_field);
- selection_evaluator.evaluate();
- const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.set_selection(selection_field);
/* Since adding the ID attribute can change the result of the field evaluation (the random value
* node uses the index if the ID is unavailable), make sure that it isn't added before evaluating
* the field. However, as an optimization, use a faster code path when it already exists. */
- fn::FieldEvaluator id_evaluator{field_context, &selection};
if (component.attribute_exists("id")) {
OutputAttribute_Typed<int> id_attribute = component.attribute_try_get_for_output_only<int>(
"id", ATTR_DOMAIN_POINT);
- id_evaluator.add_with_destination(id_field, id_attribute.varray());
- id_evaluator.evaluate();
+ evaluator.add_with_destination(id_field, id_attribute.varray());
+ evaluator.evaluate();
id_attribute.save();
}
else {
- id_evaluator.add(id_field);
- id_evaluator.evaluate();
- const VArray<int> &result_ids = id_evaluator.get_evaluated<int>(0);
+ evaluator.add(id_field);
+ evaluator.evaluate();
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
+ const VArray<int> &result_ids = evaluator.get_evaluated<int>(0);
OutputAttribute_Typed<int> id_attribute = component.attribute_try_get_for_output_only<int>(
"id", ATTR_DOMAIN_POINT);
result_ids.materialize(selection, id_attribute.as_span());
@@ -63,7 +61,7 @@ static void set_id_in_component(GeometryComponent &component,
}
}
-static void geo_node_set_id_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
@@ -81,14 +79,16 @@ static void geo_node_set_id_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_set_id_cc
void register_node_type_geo_set_id()
{
+ namespace file_ns = blender::nodes::node_geo_set_id_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_SET_ID, "Set ID", NODE_CLASS_GEOMETRY, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_set_id_exec;
- ntype.declare = blender::nodes::geo_node_set_id_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_material.cc b/source/blender/nodes/geometry/nodes/node_geo_set_material.cc
index 3817de02a38..30510c3570c 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_material.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_material.cc
@@ -21,16 +21,18 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_pointcloud_types.h"
#include "DNA_volume_types.h"
#include "BKE_material.h"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_set_material_cc {
-static void geo_node_set_material_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"))
- .supported_type({GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_VOLUME});
+ .supported_type(
+ {GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_VOLUME, GEO_COMPONENT_TYPE_POINT_CLOUD});
b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
b.add_input<decl::Material>(N_("Material")).hide_label();
b.add_output<decl::Geometry>(N_("Geometry"));
@@ -59,58 +61,68 @@ static void assign_material_to_faces(Mesh &mesh, const IndexMask selection, Mate
}
}
-static void geo_node_set_material_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Material *material = params.extract_input<Material *>("Material");
const Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ /* Only add the warnings once, even if there are many unique instances. */
+ bool point_selection_warning = false;
bool volume_selection_warning = false;
+
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- if (geometry_set.has<MeshComponent>()) {
+ if (geometry_set.has_mesh()) {
MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
- Mesh *mesh = mesh_component.get_for_write();
- if (mesh != nullptr) {
- GeometryComponentFieldContext field_context{mesh_component, ATTR_DOMAIN_FACE};
+ Mesh &mesh = *mesh_component.get_for_write();
+ GeometryComponentFieldContext field_context{mesh_component, ATTR_DOMAIN_FACE};
- fn::FieldEvaluator selection_evaluator{field_context, mesh->totpoly};
- selection_evaluator.add(selection_field);
- selection_evaluator.evaluate();
- const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
+ fn::FieldEvaluator selection_evaluator{field_context, mesh.totpoly};
+ selection_evaluator.add(selection_field);
+ selection_evaluator.evaluate();
+ const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
- assign_material_to_faces(*mesh, selection, material);
- }
+ assign_material_to_faces(mesh, selection, material);
}
- if (geometry_set.has_volume()) {
- Volume &volume = *geometry_set.get_volume_for_write();
-
+ if (Volume *volume = geometry_set.get_volume_for_write()) {
+ BKE_id_material_eval_assign(&volume->id, 1, material);
if (selection_field.node().depends_on_input()) {
volume_selection_warning = true;
}
-
- BKE_id_material_eval_assign(&volume.id, 1, material);
+ }
+ if (PointCloud *pointcloud = geometry_set.get_pointcloud_for_write()) {
+ BKE_id_material_eval_assign(&pointcloud->id, 1, material);
+ if (selection_field.node().depends_on_input()) {
+ point_selection_warning = true;
+ }
}
});
if (volume_selection_warning) {
- /* Only add the warning once, even if there are many unique volume instances. */
params.error_message_add(
NodeWarningType::Info,
TIP_("Volumes only support a single material; selection input can not be a field"));
}
+ if (point_selection_warning) {
+ params.error_message_add(
+ NodeWarningType::Info,
+ TIP_("Point clouds only support a single material; selection input can not be a field"));
+ }
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_set_material_cc
void register_node_type_geo_set_material()
{
+ namespace file_ns = blender::nodes::node_geo_set_material_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_SET_MATERIAL, "Set Material", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_set_material_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_set_material_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc b/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc
index a8bb1bd8644..4451907132a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc
@@ -16,9 +16,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_set_material_index_cc {
-static void geo_node_set_material_index_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry")).supported_type(GEO_COMPONENT_TYPE_MESH);
b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
@@ -36,20 +36,17 @@ static void set_material_index_in_component(GeometryComponent &component,
return;
}
- fn::FieldEvaluator selection_evaluator{field_context, domain_size};
- selection_evaluator.add(selection_field);
- selection_evaluator.evaluate();
- const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
-
OutputAttribute_Typed<int> indices = component.attribute_try_get_for_output_only<int>(
"material_index", ATTR_DOMAIN_FACE);
- fn::FieldEvaluator material_evaluator{field_context, &selection};
- material_evaluator.add_with_destination(index_field, indices.varray());
- material_evaluator.evaluate();
+
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.set_selection(selection_field);
+ evaluator.add_with_destination(index_field, indices.varray());
+ evaluator.evaluate();
indices.save();
}
-static void geo_node_set_material_index_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
@@ -64,15 +61,17 @@ static void geo_node_set_material_index_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_set_material_index_cc
void register_node_type_geo_set_material_index()
{
+ namespace file_ns = blender::nodes::node_geo_set_material_index_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_SET_MATERIAL_INDEX, "Set Material Index", NODE_CLASS_GEOMETRY, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_set_material_index_exec;
- ntype.declare = blender::nodes::geo_node_set_material_index_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc b/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc
index 9ff299542b4..98adff7c939 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc
@@ -16,9 +16,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_set_point_radius_cc {
-static void geo_node_set_point_radius_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Points")).supported_type(GEO_COMPONENT_TYPE_POINT_CLOUD);
b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
@@ -40,20 +40,18 @@ static void set_radius_in_component(GeometryComponent &component,
return;
}
- fn::FieldEvaluator selection_evaluator{field_context, domain_size};
- selection_evaluator.add(selection_field);
- selection_evaluator.evaluate();
- const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
-
OutputAttribute_Typed<float> radii = component.attribute_try_get_for_output_only<float>(
"radius", ATTR_DOMAIN_POINT);
- fn::FieldEvaluator radii_evaluator{field_context, &selection};
- radii_evaluator.add_with_destination(radius_field, radii.varray());
- radii_evaluator.evaluate();
+
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.set_selection(selection_field);
+ evaluator.add_with_destination(radius_field, radii.varray());
+ evaluator.evaluate();
+
radii.save();
}
-static void geo_node_set_point_radius_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Points");
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
@@ -70,15 +68,17 @@ static void geo_node_set_point_radius_exec(GeoNodeExecParams params)
params.set_output("Points", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_set_point_radius_cc
void register_node_type_geo_set_point_radius()
{
+ namespace file_ns = blender::nodes::node_geo_set_point_radius_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_SET_POINT_RADIUS, "Set Point Radius", NODE_CLASS_GEOMETRY, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_set_point_radius_exec;
- ntype.declare = blender::nodes::geo_node_set_point_radius_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_position.cc b/source/blender/nodes/geometry/nodes/node_geo_set_position.cc
index 5fe9fb1b3d4..93073c2436d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_position.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_position.cc
@@ -16,11 +16,16 @@
#include "DEG_depsgraph_query.h"
+#include "BLI_task.hh"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_set_position_cc {
-static void geo_node_set_position_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
@@ -29,6 +34,77 @@ static void geo_node_set_position_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
+static void set_computed_position_and_offset(GeometryComponent &component,
+ const VArray<float3> &in_positions,
+ const VArray<float3> &in_offsets,
+ const AttributeDomain domain,
+ const IndexMask selection)
+{
+
+ OutputAttribute_Typed<float3> positions = component.attribute_try_get_for_output<float3>(
+ "position", domain, {0, 0, 0});
+
+ const int grain_size = 10000;
+
+ switch (component.type()) {
+ case GEO_COMPONENT_TYPE_MESH: {
+ Mesh *mesh = static_cast<MeshComponent &>(component).get_for_write();
+ MutableSpan<MVert> mverts{mesh->mvert, mesh->totvert};
+ if (in_positions.is_same(positions.varray())) {
+ devirtualize_varray(in_offsets, [&](const auto in_offsets) {
+ threading::parallel_for(
+ selection.index_range(), grain_size, [&](const IndexRange range) {
+ for (const int i : selection.slice(range)) {
+ const float3 offset = in_offsets[i];
+ add_v3_v3(mverts[i].co, offset);
+ }
+ });
+ });
+ }
+ else {
+ devirtualize_varray2(
+ in_positions, in_offsets, [&](const auto in_positions, const auto in_offsets) {
+ threading::parallel_for(
+ selection.index_range(), grain_size, [&](const IndexRange range) {
+ for (const int i : selection.slice(range)) {
+ const float3 new_position = in_positions[i] + in_offsets[i];
+ copy_v3_v3(mverts[i].co, new_position);
+ }
+ });
+ });
+ }
+ break;
+ }
+ default: {
+ MutableSpan<float3> out_positions_span = positions.as_span();
+ if (in_positions.is_same(positions.varray())) {
+ devirtualize_varray(in_offsets, [&](const auto in_offsets) {
+ threading::parallel_for(
+ selection.index_range(), grain_size, [&](const IndexRange range) {
+ for (const int i : selection.slice(range)) {
+ out_positions_span[i] += in_offsets[i];
+ }
+ });
+ });
+ }
+ else {
+ devirtualize_varray2(
+ in_positions, in_offsets, [&](const auto in_positions, const auto in_offsets) {
+ threading::parallel_for(
+ selection.index_range(), grain_size, [&](const IndexRange range) {
+ for (const int i : selection.slice(range)) {
+ out_positions_span[i] = in_positions[i] + in_offsets[i];
+ }
+ });
+ });
+ }
+ break;
+ }
+ }
+
+ positions.save();
+}
+
static void set_position_in_component(GeometryComponent &component,
const Field<bool> &selection_field,
const Field<float3> &position_field,
@@ -43,33 +119,19 @@ static void set_position_in_component(GeometryComponent &component,
return;
}
- fn::FieldEvaluator selection_evaluator{field_context, domain_size};
- selection_evaluator.add(selection_field);
- selection_evaluator.evaluate();
- const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
-
- fn::FieldEvaluator position_evaluator{field_context, &selection};
- position_evaluator.add(position_field);
- position_evaluator.add(offset_field);
- position_evaluator.evaluate();
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.set_selection(selection_field);
+ evaluator.add(position_field);
+ evaluator.add(offset_field);
+ evaluator.evaluate();
- /* TODO: We could have different code paths depending on whether the offset input is a single
- * value or not */
-
- const VArray<float3> &positions_input = position_evaluator.get_evaluated<float3>(0);
- const VArray<float3> &offsets_input = position_evaluator.get_evaluated<float3>(1);
-
- OutputAttribute_Typed<float3> positions = component.attribute_try_get_for_output<float3>(
- "position", domain, {0, 0, 0});
- MutableSpan<float3> position_mutable = positions.as_span();
-
- for (int i : selection) {
- position_mutable[i] = positions_input[i] + offsets_input[i];
- }
- positions.save();
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
+ const VArray<float3> &positions_input = evaluator.get_evaluated<float3>(0);
+ const VArray<float3> &offsets_input = evaluator.get_evaluated<float3>(1);
+ set_computed_position_and_offset(component, positions_input, offsets_input, domain, selection);
}
-static void geo_node_set_position_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry = params.extract_input<GeometrySet>("Geometry");
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
@@ -89,14 +151,16 @@ static void geo_node_set_position_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_set_position_cc
void register_node_type_geo_set_position()
{
+ namespace file_ns = blender::nodes::node_geo_set_position_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_SET_POSITION, "Set Position", NODE_CLASS_GEOMETRY, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_set_position_exec;
- ntype.declare = blender::nodes::geo_node_set_position_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc b/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc
index 06e25c2ed55..879a868cc0e 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc
@@ -16,9 +16,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_set_shade_smooth_cc {
-static void geo_node_set_shade_smooth_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry")).supported_type(GEO_COMPONENT_TYPE_MESH);
b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
@@ -36,20 +36,18 @@ static void set_smooth_in_component(GeometryComponent &component,
return;
}
- fn::FieldEvaluator selection_evaluator{field_context, domain_size};
- selection_evaluator.add(selection_field);
- selection_evaluator.evaluate();
- const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
-
OutputAttribute_Typed<bool> shades = component.attribute_try_get_for_output_only<bool>(
"shade_smooth", ATTR_DOMAIN_FACE);
- fn::FieldEvaluator shade_evaluator{field_context, &selection};
- shade_evaluator.add_with_destination(shade_field, shades.varray());
- shade_evaluator.evaluate();
+
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.set_selection(selection_field);
+ evaluator.add_with_destination(shade_field, shades.varray());
+ evaluator.evaluate();
+
shades.save();
}
-static void geo_node_set_shade_smooth_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
@@ -64,15 +62,17 @@ static void geo_node_set_shade_smooth_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_set_shade_smooth_cc
void register_node_type_geo_set_shade_smooth()
{
+ namespace file_ns = blender::nodes::node_geo_set_shade_smooth_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_SET_SHADE_SMOOTH, "Set Shade Smooth", NODE_CLASS_GEOMETRY, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_set_shade_smooth_exec;
- ntype.declare = blender::nodes::geo_node_set_shade_smooth_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc b/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc
index ec751ae1d2b..694491d7e6d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc
@@ -16,9 +16,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_set_spline_cyclic_cc {
-static void geo_node_set_spline_cyclic_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry")).supported_type(GEO_COMPONENT_TYPE_CURVE);
b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
@@ -36,20 +36,18 @@ static void set_cyclic_in_component(GeometryComponent &component,
return;
}
- fn::FieldEvaluator selection_evaluator{field_context, domain_size};
- selection_evaluator.add(selection_field);
- selection_evaluator.evaluate();
- const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
-
OutputAttribute_Typed<bool> cyclics = component.attribute_try_get_for_output_only<bool>(
"cyclic", ATTR_DOMAIN_CURVE);
- fn::FieldEvaluator cyclic_evaluator{field_context, &selection};
- cyclic_evaluator.add_with_destination(cyclic_field, cyclics.varray());
- cyclic_evaluator.evaluate();
+
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.set_selection(selection_field);
+ evaluator.add_with_destination(cyclic_field, cyclics.varray());
+ evaluator.evaluate();
+
cyclics.save();
}
-static void geo_node_set_spline_cyclic_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
@@ -65,15 +63,17 @@ static void geo_node_set_spline_cyclic_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_set_spline_cyclic_cc
void register_node_type_geo_set_spline_cyclic()
{
+ namespace file_ns = blender::nodes::node_geo_set_spline_cyclic_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_SET_SPLINE_CYCLIC, "Set Spline Cyclic", NODE_CLASS_GEOMETRY, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_set_spline_cyclic_exec;
- ntype.declare = blender::nodes::geo_node_set_spline_cyclic_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc b/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc
index ccf419975ca..0f93db5e6f6 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc
@@ -18,13 +18,13 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_set_spline_resolution_cc {
-static void geo_node_set_spline_resolution_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry")).supported_type(GEO_COMPONENT_TYPE_CURVE);
b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
- b.add_input<decl::Int>(N_("Resolution")).default_value(12).supports_field();
+ b.add_input<decl::Int>(N_("Resolution")).min(1).default_value(12).supports_field();
b.add_output<decl::Geometry>(N_("Geometry"));
}
@@ -38,20 +38,18 @@ static void set_resolution_in_component(GeometryComponent &component,
return;
}
- fn::FieldEvaluator selection_evaluator{field_context, domain_size};
- selection_evaluator.add(selection_field);
- selection_evaluator.evaluate();
- const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
-
OutputAttribute_Typed<int> resolutions = component.attribute_try_get_for_output_only<int>(
"resolution", ATTR_DOMAIN_CURVE);
- fn::FieldEvaluator resolution_evaluator{field_context, &selection};
- resolution_evaluator.add_with_destination(resolution_field, resolutions.varray());
- resolution_evaluator.evaluate();
+
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.set_selection(selection_field);
+ evaluator.add_with_destination(resolution_field, resolutions.varray());
+ evaluator.evaluate();
+
resolutions.save();
}
-static void geo_node_set_spline_resolution_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
@@ -81,15 +79,17 @@ static void geo_node_set_spline_resolution_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_set_spline_resolution_cc
void register_node_type_geo_set_spline_resolution()
{
+ namespace file_ns = blender::nodes::node_geo_set_spline_resolution_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_SET_SPLINE_RESOLUTION, "Set Spline Resolution", NODE_CLASS_GEOMETRY, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_set_spline_resolution_exec;
- ntype.declare = blender::nodes::geo_node_set_spline_resolution_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_string_join.cc b/source/blender/nodes/geometry/nodes/node_geo_string_join.cc
index 98d0aca084a..5308b43afb2 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_string_join.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_string_join.cc
@@ -16,16 +16,16 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_string_join_cc {
-static void geo_node_string_join_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::String>(N_("Delimiter"));
b.add_input<decl::String>(N_("Strings")).multi_input().hide_value();
b.add_output<decl::String>(N_("String"));
};
-static void geo_node_string_join_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Vector<std::string> strings = params.extract_multi_input<std::string>("Strings");
const std::string delim = params.extract_input<std::string>("Delimiter");
@@ -40,14 +40,16 @@ static void geo_node_string_join_exec(GeoNodeExecParams params)
params.set_output("String", std::move(output));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_string_join_cc
void register_node_type_geo_string_join()
{
+ namespace file_ns = blender::nodes::node_geo_string_join_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_STRING_JOIN, "Join Strings", NODE_CLASS_CONVERTER, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_string_join_exec;
- ntype.declare = blender::nodes::geo_node_string_join_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc b/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc
index 9e3ff10a3c5..33614eb3c46 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc
@@ -30,9 +30,11 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_string_to_curves_cc {
-static void geo_node_string_to_curves_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryStringToCurves)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::String>(N_("String"));
b.add_input<decl::Float>(N_("Size")).default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE);
@@ -55,12 +57,17 @@ static void geo_node_string_to_curves_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Float>(N_("Text Box Height"))
.default_value(0.0f)
.min(0.0f)
- .subtype(PROP_DISTANCE);
+ .subtype(PROP_DISTANCE)
+ .make_available([](bNode &node) {
+ node_storage(node).overflow = GEO_NODE_STRING_TO_CURVES_MODE_SCALE_TO_FIT;
+ });
b.add_output<decl::Geometry>(N_("Curves"));
- b.add_output<decl::String>(N_("Remainder"));
+ b.add_output<decl::String>(N_("Remainder")).make_available([](bNode &node) {
+ node_storage(node).overflow = GEO_NODE_STRING_TO_CURVES_MODE_TRUNCATE;
+ });
}
-static void geo_node_string_to_curves_layout(uiLayout *layout, struct bContext *C, PointerRNA *ptr)
+static void node_layout(uiLayout *layout, struct bContext *C, PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
@@ -79,7 +86,7 @@ static void geo_node_string_to_curves_layout(uiLayout *layout, struct bContext *
uiItemR(layout, ptr, "align_y", 0, "", ICON_NONE);
}
-static void geo_node_string_to_curves_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeGeometryStringToCurves *data = (NodeGeometryStringToCurves *)MEM_callocN(
sizeof(NodeGeometryStringToCurves), __func__);
@@ -91,11 +98,11 @@ static void geo_node_string_to_curves_init(bNodeTree *UNUSED(ntree), bNode *node
node->id = (ID *)BKE_vfont_builtin_get();
}
-static void geo_node_string_to_curves_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
- const NodeGeometryStringToCurves *storage = (const NodeGeometryStringToCurves *)node->storage;
+ const NodeGeometryStringToCurves &storage = node_storage(*node);
const GeometryNodeStringToCurvesOverflowMode overflow = (GeometryNodeStringToCurvesOverflowMode)
- storage->overflow;
+ storage.overflow;
bNodeSocket *socket_remainder = ((bNodeSocket *)node->outputs.first)->next;
nodeSetSocketAvailability(
ntree, socket_remainder, overflow == GEO_NODE_STRING_TO_CURVES_MODE_TRUNCATE);
@@ -131,8 +138,7 @@ static TextLayout get_text_layout(GeoNodeExecParams &params)
return {};
}
- const NodeGeometryStringToCurves &storage =
- *(const NodeGeometryStringToCurves *)params.node().storage;
+ const NodeGeometryStringToCurves &storage = node_storage(params.node());
const GeometryNodeStringToCurvesOverflowMode overflow = (GeometryNodeStringToCurvesOverflowMode)
storage.overflow;
const GeometryNodeStringToCurvesAlignXMode align_x = (GeometryNodeStringToCurvesAlignXMode)
@@ -265,7 +271,7 @@ static void add_instances_from_handles(InstancesComponent &instances,
});
}
-static void geo_node_string_to_curves_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
TextLayout layout = get_text_layout(params);
@@ -297,23 +303,25 @@ static void geo_node_string_to_curves_exec(GeoNodeExecParams params)
params.set_output("Curves", std::move(geometry_set_out));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_string_to_curves_cc
void register_node_type_geo_string_to_curves()
{
+ namespace file_ns = blender::nodes::node_geo_string_to_curves_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_STRING_TO_CURVES, "String to Curves", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_string_to_curves_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_string_to_curves_exec;
- node_type_init(&ntype, blender::nodes::geo_node_string_to_curves_init);
- node_type_update(&ntype, blender::nodes::geo_node_string_to_curves_update);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_size(&ntype, 190, 120, 700);
node_type_storage(&ntype,
"NodeGeometryStringToCurves",
node_free_standard_storage,
node_copy_standard_storage);
- ntype.draw_buttons = blender::nodes::geo_node_string_to_curves_layout;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
index 2b3430a5ed0..74e0560b32f 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
@@ -27,9 +27,11 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_subdivision_surface_cc {
-static void geo_node_subdivision_surface_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometrySubdivisionSurface)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH);
b.add_input<decl::Int>(N_("Level")).default_value(1).min(0).max(6);
@@ -42,15 +44,13 @@ static void geo_node_subdivision_surface_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Mesh"));
}
-static void geo_node_subdivision_surface_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "uv_smooth", 0, "", ICON_NONE);
uiItemR(layout, ptr, "boundary_smooth", 0, "", ICON_NONE);
}
-static void geo_node_subdivision_surface_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeGeometrySubdivisionSurface *data = (NodeGeometrySubdivisionSurface *)MEM_callocN(
sizeof(NodeGeometrySubdivisionSurface), __func__);
@@ -59,7 +59,7 @@ static void geo_node_subdivision_surface_init(bNodeTree *UNUSED(ntree), bNode *n
node->storage = data;
}
-static void geo_node_subdivision_surface_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
#ifndef WITH_OPENSUBDIV
@@ -68,8 +68,7 @@ static void geo_node_subdivision_surface_exec(GeoNodeExecParams params)
#else
Field<float> crease_field = params.extract_input<Field<float>>("Crease");
- const NodeGeometrySubdivisionSurface &storage =
- *(const NodeGeometrySubdivisionSurface *)params.node().storage;
+ const NodeGeometrySubdivisionSurface &storage = node_storage(params.node());
const int uv_smooth = storage.uv_smooth;
const int boundary_smooth = storage.boundary_smooth;
const int subdiv_level = clamp_i(params.extract_input<int>("Level"), 0, 30);
@@ -145,18 +144,20 @@ static void geo_node_subdivision_surface_exec(GeoNodeExecParams params)
params.set_output("Mesh", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_subdivision_surface_cc
void register_node_type_geo_subdivision_surface()
{
+ namespace file_ns = blender::nodes::node_geo_subdivision_surface_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_SUBDIVISION_SURFACE, "Subdivision Surface", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_subdivision_surface_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_subdivision_surface_exec;
- ntype.draw_buttons = blender::nodes::geo_node_subdivision_surface_layout;
- node_type_init(&ntype, blender::nodes::geo_node_subdivision_surface_init);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ node_type_init(&ntype, file_ns::node_init);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
node_type_storage(&ntype,
"NodeGeometrySubdivisionSurface",
diff --git a/source/blender/nodes/geometry/nodes/node_geo_switch.cc b/source/blender/nodes/geometry/nodes/node_geo_switch.cc
index 8d6f53ae375..d22522fe087 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_switch.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_switch.cc
@@ -24,11 +24,15 @@
#include "BKE_material.h"
+#include "NOD_socket_search_link.hh"
+
#include "FN_multi_function_signature.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_switch_cc {
+
+NODE_STORAGE_FUNCS(NodeSwitch)
-static void geo_node_switch_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Bool>(N_("Switch")).default_value(false).supports_field();
b.add_input<decl::Bool>(N_("Switch"), "Switch_001").default_value(false);
@@ -83,32 +87,27 @@ static void geo_node_switch_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Image>(N_("Output"), "Output_011");
}
-static void geo_node_switch_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "input_type", 0, "", ICON_NONE);
}
-static void geo_node_switch_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeSwitch *data = (NodeSwitch *)MEM_callocN(sizeof(NodeSwitch), __func__);
data->input_type = SOCK_GEOMETRY;
node->storage = data;
}
-static void geo_node_switch_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
- NodeSwitch *node_storage = (NodeSwitch *)node->storage;
+ const NodeSwitch &storage = node_storage(*node);
int index = 0;
bNodeSocket *field_switch = (bNodeSocket *)node->inputs.first;
bNodeSocket *non_field_switch = (bNodeSocket *)field_switch->next;
- const bool fields_type = ELEM((eNodeSocketDatatype)node_storage->input_type,
- SOCK_FLOAT,
- SOCK_INT,
- SOCK_BOOLEAN,
- SOCK_VECTOR,
- SOCK_RGBA,
- SOCK_STRING);
+ const bool fields_type = ELEM(
+ storage.input_type, SOCK_FLOAT, SOCK_INT, SOCK_BOOLEAN, SOCK_VECTOR, SOCK_RGBA, SOCK_STRING);
nodeSetSocketAvailability(ntree, field_switch, fields_type);
nodeSetSocketAvailability(ntree, non_field_switch, !fields_type);
@@ -117,13 +116,40 @@ static void geo_node_switch_update(bNodeTree *ntree, bNode *node)
if (index <= 1) {
continue;
}
- nodeSetSocketAvailability(
- ntree, socket, socket->type == (eNodeSocketDatatype)node_storage->input_type);
+ nodeSetSocketAvailability(ntree, socket, socket->type == storage.input_type);
}
LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) {
- nodeSetSocketAvailability(
- ntree, socket, socket->type == (eNodeSocketDatatype)node_storage->input_type);
+ nodeSetSocketAvailability(ntree, socket, socket->type == storage.input_type);
+ }
+}
+
+static void node_gather_link_searches(GatherLinkSearchOpParams &params)
+{
+ if (params.in_out() == SOCK_OUT) {
+ params.add_item(IFACE_("Output"), [](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeSwitch");
+ node_storage(node).input_type = params.socket.type;
+ params.update_and_connect_available_socket(node, "Output");
+ });
+ }
+ else {
+ if (params.other_socket().type == SOCK_BOOLEAN) {
+ params.add_item(IFACE_("Switch"), [](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeSwitch");
+ params.connect_available_socket(node, "Start");
+ });
+ }
+ params.add_item(IFACE_("False"), [](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeSwitch");
+ node_storage(node).input_type = params.socket.type;
+ params.update_and_connect_available_socket(node, "False");
+ });
+ params.add_item(IFACE_("True"), [](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeSwitch");
+ node_storage(node).input_type = params.socket.type;
+ params.update_and_connect_available_socket(node, "True");
+ });
}
}
@@ -232,9 +258,9 @@ template<typename T> void switch_no_fields(GeoNodeExecParams &params, const Stri
}
}
-static void geo_node_switch_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
- const NodeSwitch &storage = *(const NodeSwitch *)params.node().storage;
+ const NodeSwitch &storage = node_storage(params.node());
const eNodeSocketDatatype data_type = static_cast<eNodeSocketDatatype>(storage.input_type);
switch (data_type) {
@@ -293,19 +319,22 @@ static void geo_node_switch_exec(GeoNodeExecParams params)
}
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_switch_cc
void register_node_type_geo_switch()
{
+ namespace file_ns = blender::nodes::node_geo_switch_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_SWITCH, "Switch", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::geo_node_switch_declare;
- node_type_init(&ntype, blender::nodes::geo_node_switch_init);
- node_type_update(&ntype, blender::nodes::geo_node_switch_update);
+ ntype.declare = file_ns::node_declare;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(&ntype, "NodeSwitch", node_free_standard_storage, node_copy_standard_storage);
- ntype.geometry_node_execute = blender::nodes::geo_node_switch_exec;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.geometry_node_execute_supports_laziness = true;
- ntype.draw_buttons = blender::nodes::geo_node_switch_layout;
+ ntype.gather_link_search_ops = file_ns::node_gather_link_searches;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc
index 3b30806d8ae..1f099dcd04d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc
@@ -31,19 +31,24 @@
#include "UI_interface.h"
#include "UI_resources.h"
+#include "NOD_socket_search_link.hh"
+
#include "node_geometry_util.hh"
+namespace blender::nodes::node_geo_transfer_attribute_cc {
+
using namespace blender::bke::mesh_surface_sample;
using blender::fn::GArray;
-namespace blender::nodes {
+NODE_STORAGE_FUNCS(NodeGeometryTransferAttribute)
-static void geo_node_transfer_attribute_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Target"))
- .only_realized_data()
- .supported_type(
- {GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE});
+ .supported_type({GEO_COMPONENT_TYPE_MESH,
+ GEO_COMPONENT_TYPE_POINT_CLOUD,
+ GEO_COMPONENT_TYPE_CURVE,
+ GEO_COMPONENT_TYPE_INSTANCES});
b.add_input<decl::Vector>(N_("Attribute")).hide_value().supports_field();
b.add_input<decl::Float>(N_("Attribute"), "Attribute_001").hide_value().supports_field();
@@ -51,8 +56,14 @@ static void geo_node_transfer_attribute_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Bool>(N_("Attribute"), "Attribute_003").hide_value().supports_field();
b.add_input<decl::Int>(N_("Attribute"), "Attribute_004").hide_value().supports_field();
- b.add_input<decl::Vector>(N_("Source Position")).implicit_field();
- b.add_input<decl::Int>(N_("Index")).implicit_field();
+ b.add_input<decl::Vector>(N_("Source Position"))
+ .implicit_field()
+ .make_available([](bNode &node) {
+ node_storage(node).mode = GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST_FACE_INTERPOLATED;
+ });
+ b.add_input<decl::Int>(N_("Index")).implicit_field().make_available([](bNode &node) {
+ node_storage(node).mode = GEO_NODE_ATTRIBUTE_TRANSFER_INDEX;
+ });
b.add_output<decl::Vector>(N_("Attribute")).dependent_field({6, 7});
b.add_output<decl::Float>(N_("Attribute"), "Attribute_001").dependent_field({6, 7});
@@ -61,14 +72,12 @@ static void geo_node_transfer_attribute_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Int>(N_("Attribute"), "Attribute_004").dependent_field({6, 7});
}
-static void geo_node_transfer_attribute_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
const bNode &node = *static_cast<const bNode *>(ptr->data);
- const NodeGeometryTransferAttribute &data = *static_cast<const NodeGeometryTransferAttribute *>(
- node.storage);
- const GeometryNodeAttributeTransferMode mapping = (GeometryNodeAttributeTransferMode)data.mode;
+ const NodeGeometryTransferAttribute &storage = node_storage(node);
+ const GeometryNodeAttributeTransferMode mapping = (GeometryNodeAttributeTransferMode)
+ storage.mode;
uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
uiItemR(layout, ptr, "mapping", 0, "", ICON_NONE);
@@ -77,7 +86,7 @@ static void geo_node_transfer_attribute_layout(uiLayout *layout,
}
}
-static void geo_node_transfer_attribute_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryTransferAttribute *data = (NodeGeometryTransferAttribute *)MEM_callocN(
sizeof(NodeGeometryTransferAttribute), __func__);
@@ -86,12 +95,12 @@ static void geo_node_transfer_attribute_init(bNodeTree *UNUSED(tree), bNode *nod
node->storage = data;
}
-static void geo_node_transfer_attribute_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
- const NodeGeometryTransferAttribute &data = *(const NodeGeometryTransferAttribute *)
- node->storage;
- const CustomDataType data_type = static_cast<CustomDataType>(data.data_type);
- const GeometryNodeAttributeTransferMode mapping = (GeometryNodeAttributeTransferMode)data.mode;
+ const NodeGeometryTransferAttribute &storage = node_storage(*node);
+ const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
+ const GeometryNodeAttributeTransferMode mapping = (GeometryNodeAttributeTransferMode)
+ storage.mode;
bNodeSocket *socket_geometry = (bNodeSocket *)node->inputs.first;
bNodeSocket *socket_vector = socket_geometry->next;
@@ -125,6 +134,24 @@ static void geo_node_transfer_attribute_update(bNodeTree *ntree, bNode *node)
nodeSetSocketAvailability(ntree, out_socket_int32, data_type == CD_PROP_INT32);
}
+static void node_gather_link_searches(GatherLinkSearchOpParams &params)
+{
+ const NodeDeclaration &declaration = *params.node_type().fixed_declaration;
+ search_link_ops_for_declarations(params, declaration.inputs().take_back(2));
+ search_link_ops_for_declarations(params, declaration.inputs().take_front(1));
+
+ const std::optional<CustomDataType> type = node_data_type_to_custom_data_type(
+ (eNodeSocketDatatype)params.other_socket().type);
+ if (type && *type != CD_PROP_STRING) {
+ /* The input and output sockets have the same name. */
+ params.add_item(IFACE_("Attribute"), [type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeAttributeTransfer");
+ node_storage(node).data_type = *type;
+ params.update_and_connect_available_socket(node, "Attribute");
+ });
+ }
+}
+
static void get_closest_in_bvhtree(BVHTreeFromMesh &tree_data,
const VArray<float3> &positions,
const IndexMask mask,
@@ -132,9 +159,9 @@ static void get_closest_in_bvhtree(BVHTreeFromMesh &tree_data,
const MutableSpan<float> r_distances_sq,
const MutableSpan<float3> r_positions)
{
- BLI_assert(positions.size() == r_indices.size() || r_indices.is_empty());
- BLI_assert(positions.size() == r_distances_sq.size() || r_distances_sq.is_empty());
- BLI_assert(positions.size() == r_positions.size() || r_positions.is_empty());
+ BLI_assert(positions.size() >= r_indices.size());
+ BLI_assert(positions.size() >= r_distances_sq.size());
+ BLI_assert(positions.size() >= r_positions.size());
for (const int i : mask) {
BVHTreeNearest nearest;
@@ -160,7 +187,7 @@ static void get_closest_pointcloud_points(const PointCloud &pointcloud,
const MutableSpan<int> r_indices,
const MutableSpan<float> r_distances_sq)
{
- BLI_assert(positions.size() == r_indices.size());
+ BLI_assert(positions.size() >= r_indices.size());
BLI_assert(pointcloud.totpoint > 0);
BVHTreeFromPointCloud tree_data;
@@ -500,7 +527,7 @@ class NearestTransferFunction : public fn::MultiFunction {
Array<int> mesh_indices;
Array<float> mesh_distances;
- /* If there is a point-cloud, find the closest points. */
+ /* If there is a point cloud, find the closest points. */
if (use_points_) {
point_indices.reinitialize(tot_samples);
if (use_mesh_) {
@@ -593,8 +620,10 @@ static const GeometryComponent *find_target_component(const GeometrySet &geometr
{
/* Choose the other component based on a consistent order, rather than some more complicated
* heuristic. This is the same order visible in the spreadsheet and used in the ray-cast node. */
- static const Array<GeometryComponentType> supported_types = {
- GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE};
+ static const Array<GeometryComponentType> supported_types = {GEO_COMPONENT_TYPE_MESH,
+ GEO_COMPONENT_TYPE_POINT_CLOUD,
+ GEO_COMPONENT_TYPE_CURVE,
+ GEO_COMPONENT_TYPE_INSTANCES};
for (const GeometryComponentType src_type : supported_types) {
if (component_is_available(geometry, src_type, domain)) {
return geometry.get_component_for_read(src_type);
@@ -719,14 +748,14 @@ static void output_attribute_field(GeoNodeExecParams &params, GField field)
}
}
-static void geo_node_transfer_attribute_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry = params.extract_input<GeometrySet>("Target");
- const bNode &node = params.node();
- const NodeGeometryTransferAttribute &data = *(const NodeGeometryTransferAttribute *)node.storage;
- const GeometryNodeAttributeTransferMode mapping = (GeometryNodeAttributeTransferMode)data.mode;
- const CustomDataType data_type = static_cast<CustomDataType>(data.data_type);
- const AttributeDomain domain = static_cast<AttributeDomain>(data.domain);
+ const NodeGeometryTransferAttribute &storage = node_storage(params.node());
+ const GeometryNodeAttributeTransferMode mapping = (GeometryNodeAttributeTransferMode)
+ storage.mode;
+ const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
+ const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain);
GField field = get_input_attribute_field(params, data_type);
@@ -737,10 +766,6 @@ static void geo_node_transfer_attribute_exec(GeoNodeExecParams params)
});
};
- /* Since the instances are not used, there is no point in keeping
- * a reference to them while the field is passed around. */
- geometry.remove(GEO_COMPONENT_TYPE_INSTANCES);
-
GField output_field;
switch (mapping) {
case GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST_FACE_INTERPOLATED: {
@@ -794,22 +819,25 @@ static void geo_node_transfer_attribute_exec(GeoNodeExecParams params)
output_attribute_field(params, std::move(output_field));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_transfer_attribute_cc
void register_node_type_geo_transfer_attribute()
{
+ namespace file_ns = blender::nodes::node_geo_transfer_attribute_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_TRANSFER_ATTRIBUTE, "Transfer Attribute", NODE_CLASS_ATTRIBUTE, 0);
- node_type_init(&ntype, blender::nodes::geo_node_transfer_attribute_init);
- node_type_update(&ntype, blender::nodes::geo_node_transfer_attribute_update);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(&ntype,
"NodeGeometryTransferAttribute",
node_free_standard_storage,
node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_transfer_attribute_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_transfer_attribute_exec;
- ntype.draw_buttons = blender::nodes::geo_node_transfer_attribute_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.gather_link_search_ops = file_ns::node_gather_link_searches;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_transform.cc b/source/blender/nodes/geometry/nodes/node_geo_transform.cc
index 2c55a255b5d..8322de20d20 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_transform.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_transform.cc
@@ -35,15 +35,6 @@
namespace blender::nodes {
-static void geo_node_transform_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Geometry>(N_("Geometry"));
- b.add_input<decl::Vector>(N_("Translation")).subtype(PROP_TRANSLATION);
- b.add_input<decl::Vector>(N_("Rotation")).subtype(PROP_EULER);
- b.add_input<decl::Vector>(N_("Scale")).default_value({1, 1, 1}).subtype(PROP_XYZ);
- b.add_output<decl::Geometry>(N_("Geometry"));
-}
-
static bool use_translate(const float3 rotation, const float3 scale)
{
if (compare_ff(rotation.length_squared(), 0.0f, 1e-9f) != 1) {
@@ -69,15 +60,6 @@ static void transform_mesh(Mesh &mesh, const float4x4 &transform)
BKE_mesh_normals_tag_dirty(&mesh);
}
-void transform_mesh(Mesh &mesh,
- const float3 translation,
- const float3 rotation,
- const float3 scale)
-{
- const float4x4 matrix = float4x4::from_loc_eul_scale(translation, rotation, scale);
- transform_mesh(mesh, matrix);
-}
-
static void translate_pointcloud(PointCloud &pointcloud, const float3 translation)
{
CustomData_duplicate_referenced_layer(&pointcloud.pdata, CD_PROP_FLOAT3, pointcloud.totpoint);
@@ -153,49 +135,71 @@ static void translate_volume(Volume &volume, const float3 translation, const Dep
transform_volume(volume, float4x4::from_location(translation), depsgraph);
}
-void transform_geometry_set(GeometrySet &geometry,
- const float4x4 &transform,
- const Depsgraph &depsgraph)
+static void translate_geometry_set(GeometrySet &geometry,
+ const float3 translation,
+ const Depsgraph &depsgraph)
{
if (CurveEval *curve = geometry.get_curve_for_write()) {
- curve->transform(transform);
+ curve->translate(translation);
}
if (Mesh *mesh = geometry.get_mesh_for_write()) {
- transform_mesh(*mesh, transform);
+ translate_mesh(*mesh, translation);
}
if (PointCloud *pointcloud = geometry.get_pointcloud_for_write()) {
- transform_pointcloud(*pointcloud, transform);
+ translate_pointcloud(*pointcloud, translation);
}
if (Volume *volume = geometry.get_volume_for_write()) {
- transform_volume(*volume, transform, depsgraph);
+ translate_volume(*volume, translation, depsgraph);
}
if (geometry.has_instances()) {
- transform_instances(geometry.get_component_for_write<InstancesComponent>(), transform);
+ translate_instances(geometry.get_component_for_write<InstancesComponent>(), translation);
}
}
-static void translate_geometry_set(GeometrySet &geometry,
- const float3 translation,
- const Depsgraph &depsgraph)
+void transform_geometry_set(GeometrySet &geometry,
+ const float4x4 &transform,
+ const Depsgraph &depsgraph)
{
if (CurveEval *curve = geometry.get_curve_for_write()) {
- curve->translate(translation);
+ curve->transform(transform);
}
if (Mesh *mesh = geometry.get_mesh_for_write()) {
- translate_mesh(*mesh, translation);
+ transform_mesh(*mesh, transform);
}
if (PointCloud *pointcloud = geometry.get_pointcloud_for_write()) {
- translate_pointcloud(*pointcloud, translation);
+ transform_pointcloud(*pointcloud, transform);
}
if (Volume *volume = geometry.get_volume_for_write()) {
- translate_volume(*volume, translation, depsgraph);
+ transform_volume(*volume, transform, depsgraph);
}
if (geometry.has_instances()) {
- translate_instances(geometry.get_component_for_write<InstancesComponent>(), translation);
+ transform_instances(geometry.get_component_for_write<InstancesComponent>(), transform);
}
}
-static void geo_node_transform_exec(GeoNodeExecParams params)
+void transform_mesh(Mesh &mesh,
+ const float3 translation,
+ const float3 rotation,
+ const float3 scale)
+{
+ const float4x4 matrix = float4x4::from_loc_eul_scale(translation, rotation, scale);
+ transform_mesh(mesh, matrix);
+}
+
+} // namespace blender::nodes
+
+namespace blender::nodes::node_geo_transform_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Vector>(N_("Translation")).subtype(PROP_TRANSLATION);
+ b.add_input<decl::Vector>(N_("Rotation")).subtype(PROP_EULER);
+ b.add_input<decl::Vector>(N_("Scale")).default_value({1, 1, 1}).subtype(PROP_XYZ);
+ b.add_output<decl::Geometry>(N_("Geometry"));
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
const float3 translation = params.extract_input<float3>("Translation");
@@ -214,14 +218,16 @@ static void geo_node_transform_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_transform_cc
void register_node_type_geo_transform()
{
+ namespace file_ns = blender::nodes::node_geo_transform_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_TRANSFORM, "Transform", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_transform_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_transform_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc
index 1a5a60fb1b0..59049ecf0ed 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc
@@ -18,9 +18,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_translate_instances_cc {
-static void geo_node_translate_instances_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Instances")).only_instances();
b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
@@ -33,17 +33,15 @@ static void translate_instances(GeoNodeExecParams &params, InstancesComponent &i
{
GeometryComponentFieldContext field_context{instances_component, ATTR_DOMAIN_INSTANCE};
- fn::FieldEvaluator selection_evaluator{field_context, instances_component.instances_amount()};
- selection_evaluator.add(params.extract_input<Field<bool>>("Selection"));
- selection_evaluator.evaluate();
- const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
+ fn::FieldEvaluator evaluator{field_context, instances_component.instances_amount()};
+ evaluator.set_selection(params.extract_input<Field<bool>>("Selection"));
+ evaluator.add(params.extract_input<Field<float3>>("Translation"));
+ evaluator.add(params.extract_input<Field<bool>>("Local Space"));
+ evaluator.evaluate();
- fn::FieldEvaluator transforms_evaluator{field_context, &selection};
- transforms_evaluator.add(params.extract_input<Field<float3>>("Translation"));
- transforms_evaluator.add(params.extract_input<Field<bool>>("Local Space"));
- transforms_evaluator.evaluate();
- const VArray<float3> &translations = transforms_evaluator.get_evaluated<float3>(0);
- const VArray<bool> &local_spaces = transforms_evaluator.get_evaluated<bool>(1);
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
+ const VArray<float3> &translations = evaluator.get_evaluated<float3>(0);
+ const VArray<bool> &local_spaces = evaluator.get_evaluated<bool>(1);
MutableSpan<float4x4> instance_transforms = instances_component.instance_transforms();
@@ -60,7 +58,7 @@ static void translate_instances(GeoNodeExecParams &params, InstancesComponent &i
});
}
-static void geo_node_translate_instances_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Instances");
if (geometry_set.has_instances()) {
@@ -70,15 +68,17 @@ static void geo_node_translate_instances_exec(GeoNodeExecParams params)
params.set_output("Instances", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_translate_instances_cc
void register_node_type_geo_translate_instances()
{
+ namespace file_ns = blender::nodes::node_geo_translate_instances_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_TRANSLATE_INSTANCES, "Translate Instances", NODE_CLASS_GEOMETRY, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_translate_instances_exec;
- ntype.declare = blender::nodes::geo_node_translate_instances_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
index c869846e1f8..f8deaaa4a14 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
@@ -27,16 +27,16 @@ Mesh *triangulate_mesh(Mesh *mesh,
const int flag);
}
-namespace blender::nodes {
+namespace blender::nodes::node_geo_triangulate_cc {
-static void geo_node_triangulate_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH);
b.add_input<decl::Int>(N_("Minimum Vertices")).default_value(4).min(4).max(10000);
b.add_output<decl::Geometry>(N_("Mesh"));
}
-static void geo_node_triangulate_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "quad_method", 0, "", ICON_NONE);
uiItemR(layout, ptr, "ngon_method", 0, "", ICON_NONE);
@@ -48,7 +48,7 @@ static void geo_triangulate_init(bNodeTree *UNUSED(ntree), bNode *node)
node->custom2 = GEO_NODE_TRIANGULATE_NGON_BEAUTY;
}
-static void geo_node_triangulate_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
const int min_vertices = std::max(params.extract_input<int>("Minimum Vertices"), 4);
@@ -69,16 +69,18 @@ static void geo_node_triangulate_exec(GeoNodeExecParams params)
params.set_output("Mesh", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_triangulate_cc
void register_node_type_geo_triangulate()
{
+ namespace file_ns = blender::nodes::node_geo_triangulate_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_TRIANGULATE, "Triangulate", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_triangulate_declare;
- node_type_init(&ntype, blender::nodes::geo_triangulate_init);
- ntype.geometry_node_execute = blender::nodes::geo_node_triangulate_exec;
- ntype.draw_buttons = blender::nodes::geo_node_triangulate_layout;
+ ntype.declare = file_ns::node_declare;
+ node_type_init(&ntype, file_ns::geo_triangulate_init);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_viewer.cc b/source/blender/nodes/geometry/nodes/node_geo_viewer.cc
index a46d7529124..18f2fa4cd36 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_viewer.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_viewer.cc
@@ -14,13 +14,23 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include "BKE_context.h"
+
#include "UI_interface.h"
#include "UI_resources.h"
+#include "ED_node.h"
+#include "ED_spreadsheet.h"
+
+#include "NOD_socket_search_link.hh"
+
#include "node_geometry_util.hh"
-namespace blender::nodes {
-static void geo_node_viewer_declare(NodeDeclarationBuilder &b)
+namespace blender::nodes::node_geo_viewer_cc {
+
+NODE_STORAGE_FUNCS(NodeGeometryViewer)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::Float>(N_("Value")).supports_field().hide_value();
@@ -30,7 +40,7 @@ static void geo_node_viewer_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Bool>(N_("Value"), "Value_004").supports_field().hide_value();
}
-static void geo_node_viewer_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryViewer *data = (NodeGeometryViewer *)MEM_callocN(sizeof(NodeGeometryViewer),
__func__);
@@ -39,7 +49,7 @@ static void geo_node_viewer_init(bNodeTree *UNUSED(tree), bNode *node)
node->storage = data;
}
-static void geo_node_viewer_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
}
@@ -63,9 +73,9 @@ static eNodeSocketDatatype custom_data_type_to_socket_type(const CustomDataType
}
}
-static void geo_node_viewer_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
- const NodeGeometryViewer &storage = *(const NodeGeometryViewer *)node->storage;
+ const NodeGeometryViewer &storage = node_storage(*node);
const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
const eNodeSocketDatatype socket_type = custom_data_type_to_socket_type(data_type);
@@ -77,18 +87,67 @@ static void geo_node_viewer_update(bNodeTree *ntree, bNode *node)
}
}
-} // namespace blender::nodes
+static void node_gather_link_searches(GatherLinkSearchOpParams &params)
+{
+ auto set_active_fn = [](LinkSearchOpParams &params, bNode &viewer_node) {
+ /* Set this new viewer node active in spreadsheet editors. */
+ SpaceNode *snode = CTX_wm_space_node(&params.C);
+ Main *bmain = CTX_data_main(&params.C);
+ ED_node_set_active(bmain, snode, &params.node_tree, &viewer_node, nullptr);
+ ED_spreadsheet_context_paths_set_geometry_node(bmain, snode, &viewer_node);
+ };
+
+ const std::optional<CustomDataType> type = node_socket_to_custom_data_type(
+ params.other_socket());
+ if (params.in_out() == SOCK_OUT) {
+ /* The viewer node only has inputs. */
+ return;
+ }
+ if (params.other_socket().type == SOCK_GEOMETRY) {
+ params.add_item(IFACE_("Geometry"), [set_active_fn](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeViewer");
+ params.connect_available_socket(node, "Geometry");
+ set_active_fn(params, node);
+ });
+ }
+ if (type &&
+ ELEM(type, CD_PROP_FLOAT, CD_PROP_BOOL, CD_PROP_INT32, CD_PROP_FLOAT3, CD_PROP_COLOR)) {
+ params.add_item(IFACE_("Value"), [type, set_active_fn](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeViewer");
+ node_storage(node).data_type = *type;
+ params.update_and_connect_available_socket(node, "Value");
+
+ /* If the source node has a geometry socket, connect it to the new viewer node as well. */
+ LISTBASE_FOREACH (bNodeSocket *, socket, &params.node.outputs) {
+ if (socket->type == SOCK_GEOMETRY && !(socket->flag & (SOCK_UNAVAIL | SOCK_HIDDEN))) {
+ nodeAddLink(&params.node_tree,
+ &params.node,
+ socket,
+ &node,
+ static_cast<bNodeSocket *>(node.inputs.first));
+ }
+ }
+
+ set_active_fn(params, node);
+ });
+ }
+}
+
+} // namespace blender::nodes::node_geo_viewer_cc
void register_node_type_geo_viewer()
{
+ namespace file_ns = blender::nodes::node_geo_viewer_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_VIEWER, "Viewer", NODE_CLASS_OUTPUT, 0);
node_type_storage(
&ntype, "NodeGeometryViewer", node_free_standard_storage, node_copy_standard_storage);
- node_type_update(&ntype, blender::nodes::geo_node_viewer_update);
- node_type_init(&ntype, blender::nodes::geo_node_viewer_init);
- ntype.declare = blender::nodes::geo_node_viewer_declare;
- ntype.draw_buttons_ex = blender::nodes::geo_node_viewer_layout;
+ node_type_update(&ntype, file_ns::node_update);
+ node_type_init(&ntype, file_ns::node_init);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons_ex = file_ns::node_layout;
+ ntype.gather_link_search_ops = file_ns::node_gather_link_searches;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc
index 99eeae370fe..0819b401941 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc
@@ -35,26 +35,39 @@
#include "UI_interface.h"
#include "UI_resources.h"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_volume_to_mesh_cc {
-static void geo_node_volume_to_mesh_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryVolumeToMesh)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Volume")).supported_type(GEO_COMPONENT_TYPE_VOLUME);
- b.add_input<decl::Float>(N_("Voxel Size")).default_value(0.3f).min(0.01f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>(N_("Voxel Amount")).default_value(64.0f).min(0.0f);
+ b.add_input<decl::Float>(N_("Voxel Size"))
+ .default_value(0.3f)
+ .min(0.01f)
+ .subtype(PROP_DISTANCE)
+ .make_available([](bNode &node) {
+ node_storage(node).resolution_mode = VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_SIZE;
+ });
+ b.add_input<decl::Float>(N_("Voxel Amount"))
+ .default_value(64.0f)
+ .min(0.0f)
+ .make_available([](bNode &node) {
+ node_storage(node).resolution_mode = VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_AMOUNT;
+ });
b.add_input<decl::Float>(N_("Threshold")).default_value(0.1f).min(0.0f);
b.add_input<decl::Float>(N_("Adaptivity")).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
b.add_output<decl::Geometry>(N_("Mesh"));
}
-static void geo_node_volume_to_mesh_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
uiItemR(layout, ptr, "resolution_mode", 0, IFACE_("Resolution"), ICON_NONE);
}
-static void geo_node_volume_to_mesh_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeGeometryVolumeToMesh *data = (NodeGeometryVolumeToMesh *)MEM_callocN(
sizeof(NodeGeometryVolumeToMesh), __func__);
@@ -62,26 +75,26 @@ static void geo_node_volume_to_mesh_init(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = data;
}
-static void geo_node_volume_to_mesh_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
- NodeGeometryVolumeToMesh *data = (NodeGeometryVolumeToMesh *)node->storage;
+ const NodeGeometryVolumeToMesh &storage = node_storage(*node);
bNodeSocket *voxel_size_socket = nodeFindSocket(node, SOCK_IN, "Voxel Size");
bNodeSocket *voxel_amount_socket = nodeFindSocket(node, SOCK_IN, "Voxel Amount");
nodeSetSocketAvailability(ntree,
voxel_amount_socket,
- data->resolution_mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_AMOUNT);
+ storage.resolution_mode ==
+ VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_AMOUNT);
nodeSetSocketAvailability(ntree,
voxel_size_socket,
- data->resolution_mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_SIZE);
+ storage.resolution_mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_SIZE);
}
#ifdef WITH_OPENVDB
static bke::VolumeToMeshResolution get_resolution_param(const GeoNodeExecParams &params)
{
- const NodeGeometryVolumeToMesh &storage =
- *(const NodeGeometryVolumeToMesh *)params.node().storage;
+ const NodeGeometryVolumeToMesh &storage = node_storage(params.node());
bke::VolumeToMeshResolution resolution;
resolution.mode = (VolumeToMeshResolutionMode)storage.resolution_mode;
@@ -176,7 +189,7 @@ static Mesh *create_mesh_from_volume(GeometrySet &geometry_set, GeoNodeExecParam
#endif /* WITH_OPENVDB */
-static void geo_node_volume_to_mesh_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Volume");
@@ -194,20 +207,22 @@ static void geo_node_volume_to_mesh_exec(GeoNodeExecParams params)
params.set_output("Mesh", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_volume_to_mesh_cc
void register_node_type_geo_volume_to_mesh()
{
+ namespace file_ns = blender::nodes::node_geo_volume_to_mesh_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_VOLUME_TO_MESH, "Volume to Mesh", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_volume_to_mesh_declare;
+ ntype.declare = file_ns::node_declare;
node_type_storage(
&ntype, "NodeGeometryVolumeToMesh", node_free_standard_storage, node_copy_standard_storage);
node_type_size(&ntype, 170, 120, 700);
- node_type_init(&ntype, blender::nodes::geo_node_volume_to_mesh_init);
- node_type_update(&ntype, blender::nodes::geo_node_volume_to_mesh_update);
- ntype.geometry_node_execute = blender::nodes::geo_node_volume_to_mesh_exec;
- ntype.draw_buttons = blender::nodes::geo_node_volume_to_mesh_layout;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/intern/derived_node_tree.cc b/source/blender/nodes/intern/derived_node_tree.cc
index 8a9386c1137..dc223f07a26 100644
--- a/source/blender/nodes/intern/derived_node_tree.cc
+++ b/source/blender/nodes/intern/derived_node_tree.cc
@@ -20,10 +20,6 @@
namespace blender::nodes {
-/* Construct a new derived node tree for a given root node tree. The generated derived node tree
- * does not own the used node tree refs (so that those can be used by others as well). The caller
- * has to make sure that the node tree refs added to #node_tree_refs live at least as long as the
- * derived node tree. */
DerivedNodeTree::DerivedNodeTree(bNodeTree &btree, NodeTreeRefMap &node_tree_refs)
{
/* Construct all possible contexts immediately. This is significantly cheaper than inlining all
@@ -73,9 +69,6 @@ void DerivedNodeTree::destruct_context_recursively(DTreeContext *context)
context->~DTreeContext();
}
-/**
- * \return True when there is a link cycle. Unavailable sockets are ignored.
- */
bool DerivedNodeTree::has_link_cycles() const
{
for (const NodeTreeRef *tree_ref : used_node_tree_refs_) {
@@ -96,7 +89,6 @@ bool DerivedNodeTree::has_undefined_nodes_or_sockets() const
return false;
}
-/* Calls the given callback on all nodes in the (possibly nested) derived node tree. */
void DerivedNodeTree::foreach_node(FunctionRef<void(DNode)> callback) const
{
this->foreach_node_in_context_recursive(*root_context_, callback);
@@ -168,7 +160,7 @@ DInputSocket DOutputSocket::get_active_corresponding_group_output_socket() const
const DTreeContext *child_context = context_->child_context(socket_ref_->node());
if (child_context == nullptr) {
- /* Can happen when the group node references a non-existant group (e.g. when the group is
+ /* Can happen when the group node references a non-existent group (e.g. when the group is
* linked but the original file is not found). */
return {};
}
@@ -184,9 +176,6 @@ DInputSocket DOutputSocket::get_active_corresponding_group_output_socket() const
return {};
}
-/* Call `origin_fn` for every "real" origin socket. "Real" means that reroutes, muted nodes
- * and node groups are handled by this function. Origin sockets are ones where a node gets its
- * inputs from. */
void DInputSocket::foreach_origin_socket(FunctionRef<void(DSocket)> origin_fn) const
{
BLI_assert(*this);
@@ -233,9 +222,6 @@ void DInputSocket::foreach_origin_socket(FunctionRef<void(DSocket)> origin_fn) c
}
}
-/* Calls `target_fn` for every "real" target socket. "Real" means that reroutes, muted nodes
- * and node groups are handled by this function. Target sockets are on the nodes that use the value
- * from this socket. */
void DOutputSocket::foreach_target_socket(ForeachTargetSocketFn target_fn) const
{
TargetSocketPathInfo path_info;
@@ -281,7 +267,6 @@ void DOutputSocket::foreach_target_socket(ForeachTargetSocketFn target_fn,
mute_output.foreach_target_socket(target_fn, path_info);
path_info.sockets.pop_last();
path_info.sockets.pop_last();
- break;
}
}
else if (linked_node->is_group_output_node()) {
@@ -343,7 +328,6 @@ static dot::Cluster *get_dot_cluster_for_context(
});
}
-/* Generates a graph in dot format. The generated graph has all node groups inlined. */
std::string DerivedNodeTree::to_dot() const
{
dot::DirectedGraph digraph;
diff --git a/source/blender/nodes/intern/extern_implementations.cc b/source/blender/nodes/intern/extern_implementations.cc
deleted file mode 100644
index 35de319f20b..00000000000
--- a/source/blender/nodes/intern/extern_implementations.cc
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#include "NOD_socket_declarations.hh"
-#include "NOD_socket_declarations_geometry.hh"
-
-namespace blender::nodes {
-#define MAKE_EXTERN_SOCKET_IMPLEMENTATION(TYPE) \
- template class SocketDeclarationBuilder<TYPE>; \
- template TYPE::Builder &NodeDeclarationBuilder::add_input<TYPE>(StringRef, StringRef); \
- template TYPE::Builder &NodeDeclarationBuilder::add_output<TYPE>(StringRef, StringRef);
-
-MAKE_EXTERN_SOCKET_IMPLEMENTATION(decl::Float)
-MAKE_EXTERN_SOCKET_IMPLEMENTATION(decl::Int)
-MAKE_EXTERN_SOCKET_IMPLEMENTATION(decl::Vector)
-MAKE_EXTERN_SOCKET_IMPLEMENTATION(decl::Bool)
-MAKE_EXTERN_SOCKET_IMPLEMENTATION(decl::Color)
-MAKE_EXTERN_SOCKET_IMPLEMENTATION(decl::String)
-MAKE_EXTERN_SOCKET_IMPLEMENTATION(decl::Geometry)
-
-#undef MAKE_EXTERN_SOCKET_IMPLEMENTATION
-} // namespace blender::nodes
diff --git a/source/blender/nodes/intern/geometry_nodes_eval_log.cc b/source/blender/nodes/intern/geometry_nodes_eval_log.cc
index ddd3c991518..e33f6cf345d 100644
--- a/source/blender/nodes/intern/geometry_nodes_eval_log.cc
+++ b/source/blender/nodes/intern/geometry_nodes_eval_log.cc
@@ -25,12 +25,15 @@
#include "BLT_translation.h"
+#include <chrono>
+
namespace blender::nodes::geometry_nodes_eval_log {
using fn::CPPType;
using fn::FieldCPPType;
using fn::FieldInput;
using fn::GField;
+using fn::ValueOrFieldCPPType;
ModifierLog::ModifierLog(GeoLogger &logger)
: input_geometry_log_(std::move(logger.input_geometry_log_)),
@@ -63,6 +66,17 @@ ModifierLog::ModifierLog(GeoLogger &logger)
node_with_warning.node);
node_log.warnings_.append(node_with_warning.warning);
}
+
+ for (NodeWithExecutionTime &node_with_exec_time : local_logger.node_exec_times_) {
+ NodeLog &node_log = this->lookup_or_add_node_log(log_by_tree_context,
+ node_with_exec_time.node);
+ node_log.exec_time_ = node_with_exec_time.exec_time;
+ }
+
+ for (NodeWithDebugMessage &debug_message : local_logger.node_debug_messages_) {
+ NodeLog &node_log = this->lookup_or_add_node_log(log_by_tree_context, debug_message.node);
+ node_log.debug_messages_.append(debug_message.message);
+ }
}
}
@@ -177,12 +191,14 @@ const SocketLog *NodeLog::lookup_socket_log(const bNode &node, const bNodeSocket
GFieldValueLog::GFieldValueLog(fn::GField field, bool log_full_field) : type_(field.cpp_type())
{
- Set<std::reference_wrapper<const FieldInput>> field_inputs_set;
- field.node().foreach_field_input(
- [&](const FieldInput &field_input) { field_inputs_set.add(field_input); });
+ const std::shared_ptr<const fn::FieldInputs> &field_input_nodes = field.node().field_inputs();
+ /* Put the deduplicated field inputs into a vector so that they can be sorted below. */
Vector<std::reference_wrapper<const FieldInput>> field_inputs;
- field_inputs.extend(field_inputs_set.begin(), field_inputs_set.end());
+ if (field_input_nodes) {
+ field_inputs.extend(field_input_nodes->deduplicated_nodes.begin(),
+ field_input_nodes->deduplicated_nodes.end());
+ }
std::sort(
field_inputs.begin(), field_inputs.end(), [](const FieldInput &a, const FieldInput &b) {
@@ -417,25 +433,38 @@ void LocalGeoLogger::log_value_for_sockets(Span<DSocket> sockets, GPointer value
geometry_set, log_full_geometry);
values_.append({copied_sockets, std::move(value_log)});
}
- else if (const FieldCPPType *field_type = dynamic_cast<const FieldCPPType *>(&type)) {
- GField field = field_type->get_gfield(value.get());
- bool log_full_field = false;
- if (!field.node().depends_on_input()) {
- /* Always log constant fields so that their value can be shown in socket inspection.
- * In the future we can also evaluate the field here and only store the value. */
- log_full_field = true;
- }
- if (!log_full_field) {
- for (const DSocket &socket : sockets) {
- if (main_logger_->log_full_sockets_.contains(socket)) {
- log_full_field = true;
- break;
+ else if (const ValueOrFieldCPPType *value_or_field_type =
+ dynamic_cast<const ValueOrFieldCPPType *>(&type)) {
+ const void *value_or_field = value.get();
+ if (value_or_field_type->is_field(value_or_field)) {
+ GField field = *value_or_field_type->get_field_ptr(value_or_field);
+ bool log_full_field = false;
+ if (!field.node().depends_on_input()) {
+ /* Always log constant fields so that their value can be shown in socket inspection.
+ * In the future we can also evaluate the field here and only store the value. */
+ log_full_field = true;
+ }
+ if (!log_full_field) {
+ for (const DSocket &socket : sockets) {
+ if (main_logger_->log_full_sockets_.contains(socket)) {
+ log_full_field = true;
+ break;
+ }
}
}
+ destruct_ptr<GFieldValueLog> value_log = allocator_->construct<GFieldValueLog>(
+ std::move(field), log_full_field);
+ values_.append({copied_sockets, std::move(value_log)});
+ }
+ else {
+ const CPPType &base_type = value_or_field_type->base_type();
+ const void *value = value_or_field_type->get_value_ptr(value_or_field);
+ void *buffer = allocator_->allocate(base_type.size(), base_type.alignment());
+ base_type.copy_construct(value, buffer);
+ destruct_ptr<GenericValueLog> value_log = allocator_->construct<GenericValueLog>(
+ GMutablePointer{base_type, buffer});
+ values_.append({copied_sockets, std::move(value_log)});
}
- destruct_ptr<GFieldValueLog> value_log = allocator_->construct<GFieldValueLog>(
- std::move(field), log_full_field);
- values_.append({copied_sockets, std::move(value_log)});
}
else {
void *buffer = allocator_->allocate(type.size(), type.alignment());
@@ -457,4 +486,14 @@ void LocalGeoLogger::log_node_warning(DNode node, NodeWarningType type, std::str
node_warnings_.append({node, {type, std::move(message)}});
}
+void LocalGeoLogger::log_execution_time(DNode node, std::chrono::microseconds exec_time)
+{
+ node_exec_times_.append({node, exec_time});
+}
+
+void LocalGeoLogger::log_debug_message(DNode node, std::string message)
+{
+ node_debug_messages_.append({node, std::move(message)});
+}
+
} // namespace blender::nodes::geometry_nodes_eval_log
diff --git a/source/blender/nodes/intern/math_functions.cc b/source/blender/nodes/intern/math_functions.cc
index aa23777b664..00f4f2a3405 100644
--- a/source/blender/nodes/intern/math_functions.cc
+++ b/source/blender/nodes/intern/math_functions.cc
@@ -127,17 +127,17 @@ const FloatMathOperationInfo *get_float_compare_operation_info(const int operati
((void)0)
switch (operation) {
- case NODE_FLOAT_COMPARE_LESS_THAN:
+ case NODE_COMPARE_LESS_THAN:
RETURN_OPERATION_INFO("Less Than", "math_less_than");
- case NODE_FLOAT_COMPARE_LESS_EQUAL:
+ case NODE_COMPARE_LESS_EQUAL:
RETURN_OPERATION_INFO("Less Than or Equal", "math_less_equal");
- case NODE_FLOAT_COMPARE_GREATER_THAN:
+ case NODE_COMPARE_GREATER_THAN:
RETURN_OPERATION_INFO("Greater Than", "math_greater_than");
- case NODE_FLOAT_COMPARE_GREATER_EQUAL:
+ case NODE_COMPARE_GREATER_EQUAL:
RETURN_OPERATION_INFO("Greater Than or Equal", "math_greater_equal");
- case NODE_FLOAT_COMPARE_EQUAL:
+ case NODE_COMPARE_EQUAL:
RETURN_OPERATION_INFO("Equal", "math_equal");
- case NODE_FLOAT_COMPARE_NOT_EQUAL:
+ case NODE_COMPARE_NOT_EQUAL:
RETURN_OPERATION_INFO("Not Equal", "math_not_equal");
}
diff --git a/source/blender/nodes/intern/node_common.cc b/source/blender/nodes/intern/node_common.cc
index b80cedc9352..c302b1081af 100644
--- a/source/blender/nodes/intern/node_common.cc
+++ b/source/blender/nodes/intern/node_common.cc
@@ -32,6 +32,7 @@
#include "BLI_set.hh"
#include "BLI_stack.hh"
#include "BLI_string.h"
+#include "BLI_string_ref.hh"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -50,33 +51,33 @@ using blender::Map;
using blender::MultiValueMap;
using blender::Set;
using blender::Stack;
+using blender::StringRef;
/* -------------------------------------------------------------------- */
/** \name Node Group
* \{ */
-bNodeSocket *node_group_find_input_socket(bNode *groupnode, const char *identifier)
+static bNodeSocket *find_matching_socket(ListBase &sockets, StringRef identifier)
{
- LISTBASE_FOREACH (bNodeSocket *, sock, &groupnode->inputs) {
- if (STREQ(sock->identifier, identifier)) {
- return sock;
+ LISTBASE_FOREACH (bNodeSocket *, socket, &sockets) {
+ if (socket->identifier == identifier) {
+ return socket;
}
}
return nullptr;
}
+bNodeSocket *node_group_find_input_socket(bNode *groupnode, const char *identifier)
+{
+ return find_matching_socket(groupnode->inputs, identifier);
+}
+
bNodeSocket *node_group_find_output_socket(bNode *groupnode, const char *identifier)
{
- LISTBASE_FOREACH (bNodeSocket *, sock, &groupnode->outputs) {
- if (STREQ(sock->identifier, identifier)) {
- return sock;
- }
- }
- return nullptr;
+ return find_matching_socket(groupnode->outputs, identifier);
}
-/* groups display their internal tree name as label */
-void node_group_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
+void node_group_label(const bNodeTree *UNUSED(ntree), const bNode *node, char *label, int maxlen)
{
BLI_strncpy(label, (node->id) ? node->id->name + 2 : IFACE_("Missing Data-Block"), maxlen);
}
@@ -107,7 +108,7 @@ bool nodeGroupPoll(bNodeTree *nodetree, bNodeTree *grouptree, const char **r_dis
}
if (nodetree == grouptree) {
- *r_disabled_hint = "Nesting a node group inside of itself is not allowed";
+ *r_disabled_hint = TIP_("Nesting a node group inside of itself is not allowed");
return false;
}
@@ -121,83 +122,84 @@ bool nodeGroupPoll(bNodeTree *nodetree, bNodeTree *grouptree, const char **r_dis
return valid;
}
-/* used for both group nodes and interface nodes */
-static bNodeSocket *group_verify_socket(bNodeTree *ntree,
- bNode *gnode,
- bNodeSocket *iosock,
- ListBase *verify_lb,
- eNodeSocketInOut in_out)
+static void add_new_socket_from_interface(bNodeTree &node_tree,
+ bNode &node,
+ const bNodeSocket &interface_socket,
+ const eNodeSocketInOut in_out)
{
- bNodeSocket *sock;
+ bNodeSocket *socket = nodeAddSocket(&node_tree,
+ &node,
+ in_out,
+ interface_socket.idname,
+ interface_socket.identifier,
+ interface_socket.name);
- for (sock = (bNodeSocket *)verify_lb->first; sock; sock = sock->next) {
- if (STREQ(sock->identifier, iosock->identifier)) {
- break;
- }
+ if (interface_socket.typeinfo->interface_init_socket) {
+ interface_socket.typeinfo->interface_init_socket(
+ &node_tree, &interface_socket, &node, socket, "interface");
}
- if (sock) {
- strcpy(sock->name, iosock->name);
+}
- const int mask = SOCK_HIDE_VALUE;
- sock->flag = (sock->flag & ~mask) | (iosock->flag & mask);
+static void update_socket_to_match_interface(bNodeTree &node_tree,
+ bNode &node,
+ bNodeSocket &socket_to_update,
+ const bNodeSocket &interface_socket)
+{
+ strcpy(socket_to_update.name, interface_socket.name);
- /* Update socket type if necessary */
- if (sock->typeinfo != iosock->typeinfo) {
- nodeModifySocketType(ntree, gnode, sock, iosock->idname);
- /* Flag the tree to make sure link validity is updated after type changes. */
- ntree->update |= NTREE_UPDATE_LINKS;
- }
+ const int mask = SOCK_HIDE_VALUE;
+ socket_to_update.flag = (socket_to_update.flag & ~mask) | (interface_socket.flag & mask);
- if (iosock->typeinfo->interface_verify_socket) {
- iosock->typeinfo->interface_verify_socket(ntree, iosock, gnode, sock, "interface");
- }
+ /* Update socket type if necessary */
+ if (socket_to_update.typeinfo != interface_socket.typeinfo) {
+ nodeModifySocketType(&node_tree, &node, &socket_to_update, interface_socket.idname);
+ /* Flag the tree to make sure link validity is updated after type changes. */
+ node_tree.update |= NTREE_UPDATE_LINKS;
}
- else {
- sock = nodeAddSocket(ntree, gnode, in_out, iosock->idname, iosock->identifier, iosock->name);
- if (iosock->typeinfo->interface_init_socket) {
- iosock->typeinfo->interface_init_socket(ntree, iosock, gnode, sock, "interface");
- }
+ if (interface_socket.typeinfo->interface_verify_socket) {
+ interface_socket.typeinfo->interface_verify_socket(
+ &node_tree, &interface_socket, &node, &socket_to_update, "interface");
}
-
- /* remove from list temporarily, to distinguish from orphaned sockets */
- BLI_remlink(verify_lb, sock);
-
- return sock;
}
-/* used for both group nodes and interface nodes */
-static void group_verify_socket_list(bNodeTree *ntree,
- bNode *gnode,
- ListBase *iosock_lb,
- ListBase *verify_lb,
- eNodeSocketInOut in_out)
+/**
+ * Used for group nodes and group input/output nodes to update the list of input or output sockets
+ * on a node to match the provided interface. Assumes that \a verify_lb is the node's matching
+ * input or output socket list, depending on whether the node is a group input/output or a group
+ * node.
+ */
+static void group_verify_socket_list(bNodeTree &node_tree,
+ bNode &node,
+ const ListBase &interface_sockets,
+ ListBase &verify_lb,
+ const eNodeSocketInOut in_out)
{
- bNodeSocket *sock, *nextsock;
-
- /* step by step compare */
-
- bNodeSocket *iosock = (bNodeSocket *)iosock_lb->first;
- for (; iosock; iosock = iosock->next) {
- /* abusing new_sock pointer for verification here! only used inside this function */
- iosock->new_sock = group_verify_socket(ntree, gnode, iosock, verify_lb, in_out);
- }
- /* leftovers are removed */
- for (sock = (bNodeSocket *)verify_lb->first; sock; sock = nextsock) {
- nextsock = sock->next;
- nodeRemoveSocket(ntree, gnode, sock);
- }
- /* and we put back the verified sockets */
- iosock = (bNodeSocket *)iosock_lb->first;
- for (; iosock; iosock = iosock->next) {
- if (iosock->new_sock) {
- BLI_addtail(verify_lb, iosock->new_sock);
- iosock->new_sock = nullptr;
+ ListBase old_sockets = verify_lb;
+ BLI_listbase_clear(&verify_lb);
+
+ LISTBASE_FOREACH (const bNodeSocket *, interface_socket, &interface_sockets) {
+ bNodeSocket *matching_socket = find_matching_socket(old_sockets, interface_socket->identifier);
+ if (matching_socket) {
+ /* If a socket with the same identifier exists in the previous socket list, update it
+ * with the correct name, type, etc. Then move it from the old list to the new one. */
+ update_socket_to_match_interface(node_tree, node, *matching_socket, *interface_socket);
+ BLI_remlink(&old_sockets, matching_socket);
+ BLI_addtail(&verify_lb, matching_socket);
+ }
+ else {
+ /* If there was no socket withe the same identifier already, simply create a new socket
+ * based on the interface socket, which will already add it to the new list. */
+ add_new_socket_from_interface(node_tree, node, *interface_socket, in_out);
}
}
+
+ /* Remove leftover sockets that didn't match the node group's interface. */
+ LISTBASE_FOREACH_MUTABLE (bNodeSocket *, unused_socket, &old_sockets) {
+ nodeRemoveSocket(&node_tree, &node, unused_socket);
+ }
}
-/* make sure all group node in ntree, which use ngroup, are sync'd */
void node_group_update(struct bNodeTree *ntree, struct bNode *node)
{
/* check inputs and outputs, and remove or insert them */
@@ -210,8 +212,8 @@ void node_group_update(struct bNodeTree *ntree, struct bNode *node)
}
else {
bNodeTree *ngroup = (bNodeTree *)node->id;
- group_verify_socket_list(ntree, node, &ngroup->inputs, &node->inputs, SOCK_IN);
- group_verify_socket_list(ntree, node, &ngroup->outputs, &node->outputs, SOCK_OUT);
+ group_verify_socket_list(*ntree, *node, ngroup->inputs, node->inputs, SOCK_IN);
+ group_verify_socket_list(*ntree, *node, ngroup->outputs, node->outputs, SOCK_OUT);
}
}
@@ -305,9 +307,6 @@ static void propagate_reroute_type_from_start_socket(
}
}
-/* Global update function for Reroute node types.
- * This depends on connected nodes, so must be done as a tree-wide update.
- */
void ntree_update_reroute_nodes(bNodeTree *ntree)
{
/* Contains nodes that are linked to at least one reroute node. */
@@ -497,7 +496,7 @@ void node_group_input_update(bNodeTree *ntree, bNode *node)
/* check inputs and outputs, and remove or insert them */
{
/* value_in_out inverted for interface nodes to get correct socket value_property */
- group_verify_socket_list(ntree, node, &ntree->inputs, &node->outputs, SOCK_OUT);
+ group_verify_socket_list(*ntree, *node, ntree->inputs, node->outputs, SOCK_OUT);
/* add virtual extension socket */
nodeAddSocket(ntree, node, SOCK_OUT, "NodeSocketVirtual", "__extend__", "");
@@ -595,7 +594,7 @@ void node_group_output_update(bNodeTree *ntree, bNode *node)
/* check inputs and outputs, and remove or insert them */
{
/* value_in_out inverted for interface nodes to get correct socket value_property */
- group_verify_socket_list(ntree, node, &ntree->outputs, &node->inputs, SOCK_IN);
+ group_verify_socket_list(*ntree, *node, ntree->outputs, node->inputs, SOCK_IN);
/* add virtual extension socket */
nodeAddSocket(ntree, node, SOCK_IN, "NodeSocketVirtual", "__extend__", "");
@@ -613,6 +612,8 @@ void register_node_type_group_output(void)
node_type_init(ntype, node_group_output_init);
node_type_update(ntype, node_group_output_update);
+ ntype->no_muting = true;
+
nodeRegisterType(ntype);
}
diff --git a/source/blender/nodes/intern/node_common.h b/source/blender/nodes/intern/node_common.h
index cdb7b6897b9..0d1b51224e6 100644
--- a/source/blender/nodes/intern/node_common.h
+++ b/source/blender/nodes/intern/node_common.h
@@ -31,11 +31,19 @@ extern "C" {
struct bNodeTree;
-void node_group_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen);
+/** Groups display their internal tree name as label. */
+void node_group_label(const struct bNodeTree *ntree,
+ const struct bNode *node,
+ char *label,
+ int maxlen);
bool node_group_poll_instance(struct bNode *node,
struct bNodeTree *nodetree,
const char **r_disabled_hint);
+/**
+ * Global update function for Reroute node types.
+ * This depends on connected nodes, so must be done as a tree-wide update.
+ */
void ntree_update_reroute_nodes(struct bNodeTree *ntree);
#ifdef __cplusplus
diff --git a/source/blender/nodes/intern/node_declaration.cc b/source/blender/nodes/intern/node_declaration.cc
index e804d10ad75..75d47cfd386 100644
--- a/source/blender/nodes/intern/node_declaration.cc
+++ b/source/blender/nodes/intern/node_declaration.cc
@@ -51,11 +51,14 @@ bNodeSocket &SocketDeclaration::update_or_build(bNodeTree &ntree,
bNodeSocket &socket) const
{
/* By default just rebuild. */
- return this->build(ntree, node, (eNodeSocketInOut)socket.in_out);
+ BLI_assert(socket.in_out == in_out_);
+ UNUSED_VARS_NDEBUG(socket);
+ return this->build(ntree, node);
}
void SocketDeclaration::set_common_flags(bNodeSocket &socket) const
{
+ SET_FLAG_FROM_TEST(socket.flag, compact_, SOCK_COMPACT);
SET_FLAG_FROM_TEST(socket.flag, hide_value_, SOCK_HIDE_VALUE);
SET_FLAG_FROM_TEST(socket.flag, hide_label_, SOCK_HIDE_LABEL);
SET_FLAG_FROM_TEST(socket.flag, is_multi_input_, SOCK_MULTI_INPUT);
@@ -70,6 +73,9 @@ bool SocketDeclaration::matches_common_data(const bNodeSocket &socket) const
if (socket.identifier != identifier_) {
return false;
}
+ if (((socket.flag & SOCK_COMPACT) != 0) != compact_) {
+ return false;
+ }
if (((socket.flag & SOCK_HIDE_VALUE) != 0) != hide_value_) {
return false;
}
diff --git a/source/blender/nodes/intern/node_exec.cc b/source/blender/nodes/intern/node_exec.cc
index 18403417af3..95070bf735e 100644
--- a/source/blender/nodes/intern/node_exec.cc
+++ b/source/blender/nodes/intern/node_exec.cc
@@ -34,14 +34,12 @@
#include "node_exec.h"
#include "node_util.h"
-/* supported socket types in old nodes */
int node_exec_socket_use_stack(bNodeSocket *sock)
{
/* NOTE: INT supported as FLOAT. Only for EEVEE. */
return ELEM(sock->type, SOCK_INT, SOCK_FLOAT, SOCK_VECTOR, SOCK_RGBA, SOCK_SHADER);
}
-/* for a given socket, find the actual stack entry */
bNodeStack *node_get_socket_stack(bNodeStack *stack, bNodeSocket *sock)
{
if (stack && sock && sock->stack_index >= 0) {
diff --git a/source/blender/nodes/intern/node_exec.h b/source/blender/nodes/intern/node_exec.h
index de7cbb8cedb..b2e1c6564b6 100644
--- a/source/blender/nodes/intern/node_exec.h
+++ b/source/blender/nodes/intern/node_exec.h
@@ -71,8 +71,10 @@ typedef struct bNodeThreadStack {
bool used;
} bNodeThreadStack;
+/** Supported socket types in old nodes. */
int node_exec_socket_use_stack(struct bNodeSocket *sock);
+/** For a given socket, find the actual stack entry. */
struct bNodeStack *node_get_socket_stack(struct bNodeStack *stack, struct bNodeSocket *sock);
void node_get_stack(struct bNode *node,
struct bNodeStack *stack,
diff --git a/source/blender/nodes/intern/node_geometry_exec.cc b/source/blender/nodes/intern/node_geometry_exec.cc
index faa4337ba7e..b5c4e71df74 100644
--- a/source/blender/nodes/intern/node_geometry_exec.cc
+++ b/source/blender/nodes/intern/node_geometry_exec.cc
@@ -18,8 +18,9 @@
#include "DEG_depsgraph_query.h"
+#include "BKE_type_conversions.hh"
+
#include "NOD_geometry_exec.hh"
-#include "NOD_type_conversions.hh"
#include "node_geometry_util.hh"
@@ -149,7 +150,7 @@ GVArray GeoNodeExecParams::get_input_attribute(const StringRef name,
}
return GVArray::ForSingle(*cpp_type, domain_size, default_value);
}
- const DataTypeConversions &conversions = get_implicit_type_conversions();
+ const bke::DataTypeConversions &conversions = bke::get_implicit_type_conversions();
if (found_socket->type == SOCK_FLOAT) {
const float value = this->get_input<float>(found_socket->identifier);
BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer);
@@ -215,11 +216,6 @@ CustomDataType GeoNodeExecParams::get_input_attribute_data_type(
return default_type;
}
-/**
- * If any of the corresponding input sockets are attributes instead of single values,
- * use the highest priority attribute domain from among them.
- * Otherwise return the default domain.
- */
AttributeDomain GeoNodeExecParams::get_highest_priority_input_domain(
Span<std::string> names,
const GeometryComponent &component,
@@ -254,6 +250,11 @@ std::string GeoNodeExecParams::attribute_producer_name() const
return provider_->dnode->label_or_name() + TIP_(" node");
}
+void GeoNodeExecParams::set_default_remaining_outputs()
+{
+ provider_->set_default_remaining_outputs();
+}
+
void GeoNodeExecParams::check_input_access(StringRef identifier,
const CPPType *requested_type) const
{
@@ -288,7 +289,7 @@ void GeoNodeExecParams::check_input_access(StringRef identifier,
BLI_assert_unreachable();
}
else if (requested_type != nullptr) {
- const CPPType &expected_type = *found_socket->typeinfo->get_geometry_nodes_cpp_type();
+ const CPPType &expected_type = *found_socket->typeinfo->geometry_nodes_cpp_type;
if (*requested_type != expected_type) {
std::cout << "The requested type '" << requested_type->name() << "' is incorrect. Expected '"
<< expected_type.name() << "'.\n";
@@ -328,7 +329,7 @@ void GeoNodeExecParams::check_output_access(StringRef identifier, const CPPType
BLI_assert_unreachable();
}
else {
- const CPPType &expected_type = *found_socket->typeinfo->get_geometry_nodes_cpp_type();
+ const CPPType &expected_type = *found_socket->typeinfo->geometry_nodes_cpp_type;
if (value_type != expected_type) {
std::cout << "The value type '" << value_type.name() << "' is incorrect. Expected '"
<< expected_type.name() << "'.\n";
diff --git a/source/blender/nodes/intern/node_socket.cc b/source/blender/nodes/intern/node_socket.cc
index dce54d58dce..d83c05b38a1 100644
--- a/source/blender/nodes/intern/node_socket.cc
+++ b/source/blender/nodes/intern/node_socket.cc
@@ -28,7 +28,6 @@
#include "BLI_color.hh"
#include "BLI_float3.hh"
#include "BLI_listbase.h"
-#include "BLI_math.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
@@ -51,6 +50,7 @@
#include "FN_field.hh"
using namespace blender;
+using blender::fn::ValueOrField;
using blender::nodes::SocketDeclarationPtr;
struct bNodeSocket *node_add_socket_from_template(struct bNodeTree *ntree,
@@ -191,7 +191,6 @@ static void refresh_socket_list(bNodeTree &ntree,
bNode &node,
ListBase &sockets,
Span<SocketDeclarationPtr> socket_decls,
- const eNodeSocketInOut in_out,
const bool do_id_user)
{
Vector<bNodeSocket *> old_sockets = sockets;
@@ -210,7 +209,7 @@ static void refresh_socket_list(bNodeTree &ntree,
bNodeSocket *new_socket = nullptr;
if (old_socket_with_same_identifier == nullptr) {
/* Create a completely new socket. */
- new_socket = &socket_decl->build(ntree, node, in_out);
+ new_socket = &socket_decl->build(ntree, node);
}
else {
STRNCPY(old_socket_with_same_identifier->name, socket_decl->name().c_str());
@@ -258,8 +257,8 @@ static void refresh_node(bNodeTree &ntree,
blender::nodes::NodeDeclaration &node_decl,
bool do_id_user)
{
- refresh_socket_list(ntree, node, node.inputs, node_decl.inputs(), SOCK_IN, do_id_user);
- refresh_socket_list(ntree, node, node.outputs, node_decl.outputs(), SOCK_OUT, do_id_user);
+ refresh_socket_list(ntree, node, node.inputs, node_decl.inputs(), do_id_user);
+ refresh_socket_list(ntree, node, node.outputs, node_decl.outputs(), do_id_user);
}
void node_verify_sockets(bNodeTree *ntree, bNode *node, bool do_id_user)
@@ -548,7 +547,7 @@ void node_socket_skip_reroutes(
}
static void standard_node_socket_interface_init_socket(bNodeTree *UNUSED(ntree),
- bNodeSocket *stemp,
+ const bNodeSocket *interface_socket,
bNode *UNUSED(node),
bNodeSocket *sock,
const char *UNUSED(data_path))
@@ -559,47 +558,50 @@ static void standard_node_socket_interface_init_socket(bNodeTree *UNUSED(ntree),
/* XXX socket interface 'type' value is not used really,
* but has to match or the copy function will bail out
*/
- stemp->type = stemp->typeinfo->type;
+ const_cast<bNodeSocket *>(interface_socket)->type = interface_socket->typeinfo->type;
/* copy default_value settings */
- node_socket_copy_default_value(sock, stemp);
+ node_socket_copy_default_value(sock, interface_socket);
}
/* copies settings that are not changed for each socket instance */
static void standard_node_socket_interface_verify_socket(bNodeTree *UNUSED(ntree),
- bNodeSocket *stemp,
+ const bNodeSocket *interface_socket,
bNode *UNUSED(node),
bNodeSocket *sock,
const char *UNUSED(data_path))
{
/* sanity check */
- if (sock->type != stemp->typeinfo->type) {
+ if (sock->type != interface_socket->typeinfo->type) {
return;
}
/* make sure both exist */
- if (!stemp->default_value) {
+ if (!interface_socket->default_value) {
return;
}
node_socket_init_default_value(sock);
- switch (stemp->typeinfo->type) {
+ switch (interface_socket->typeinfo->type) {
case SOCK_FLOAT: {
bNodeSocketValueFloat *toval = (bNodeSocketValueFloat *)sock->default_value;
- bNodeSocketValueFloat *fromval = (bNodeSocketValueFloat *)stemp->default_value;
+ const bNodeSocketValueFloat *fromval = (const bNodeSocketValueFloat *)
+ interface_socket->default_value;
toval->min = fromval->min;
toval->max = fromval->max;
break;
}
case SOCK_INT: {
bNodeSocketValueInt *toval = (bNodeSocketValueInt *)sock->default_value;
- bNodeSocketValueInt *fromval = (bNodeSocketValueInt *)stemp->default_value;
+ const bNodeSocketValueInt *fromval = (const bNodeSocketValueInt *)
+ interface_socket->default_value;
toval->min = fromval->min;
toval->max = fromval->max;
break;
}
case SOCK_VECTOR: {
bNodeSocketValueVector *toval = (bNodeSocketValueVector *)sock->default_value;
- bNodeSocketValueVector *fromval = (bNodeSocketValueVector *)stemp->default_value;
+ const bNodeSocketValueVector *fromval = (const bNodeSocketValueVector *)
+ interface_socket->default_value;
toval->min = fromval->min;
toval->max = fromval->max;
break;
@@ -697,17 +699,15 @@ static bNodeSocketType *make_socket_type_virtual()
static bNodeSocketType *make_socket_type_bool()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_BOOLEAN, PROP_NONE);
- socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<bool>(); };
+ socktype->base_cpp_type = &blender::fn::CPPType::get<bool>();
socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) {
*(bool *)r_value = ((bNodeSocketValueBoolean *)socket.default_value)->value;
};
- socktype->get_geometry_nodes_cpp_type = []() {
- return &blender::fn::CPPType::get<blender::fn::Field<bool>>();
- };
+ socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<bool>>();
socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) {
bool value;
socket.typeinfo->get_base_cpp_value(socket, &value);
- new (r_value) blender::fn::Field<bool>(blender::fn::make_constant_field(value));
+ new (r_value) ValueOrField<bool>(value);
};
return socktype;
}
@@ -715,17 +715,15 @@ static bNodeSocketType *make_socket_type_bool()
static bNodeSocketType *make_socket_type_float(PropertySubType subtype)
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_FLOAT, subtype);
- socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<float>(); };
+ socktype->base_cpp_type = &blender::fn::CPPType::get<float>();
socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) {
*(float *)r_value = ((bNodeSocketValueFloat *)socket.default_value)->value;
};
- socktype->get_geometry_nodes_cpp_type = []() {
- return &blender::fn::CPPType::get<blender::fn::Field<float>>();
- };
+ socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<float>>();
socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) {
float value;
socket.typeinfo->get_base_cpp_value(socket, &value);
- new (r_value) blender::fn::Field<float>(blender::fn::make_constant_field(value));
+ new (r_value) ValueOrField<float>(value);
};
return socktype;
}
@@ -733,17 +731,15 @@ static bNodeSocketType *make_socket_type_float(PropertySubType subtype)
static bNodeSocketType *make_socket_type_int(PropertySubType subtype)
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_INT, subtype);
- socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<int>(); };
+ socktype->base_cpp_type = &blender::fn::CPPType::get<int>();
socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) {
*(int *)r_value = ((bNodeSocketValueInt *)socket.default_value)->value;
};
- socktype->get_geometry_nodes_cpp_type = []() {
- return &blender::fn::CPPType::get<blender::fn::Field<int>>();
- };
+ socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<int>>();
socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) {
int value;
socket.typeinfo->get_base_cpp_value(socket, &value);
- new (r_value) blender::fn::Field<int>(blender::fn::make_constant_field(value));
+ new (r_value) ValueOrField<int>(value);
};
return socktype;
}
@@ -751,17 +747,15 @@ static bNodeSocketType *make_socket_type_int(PropertySubType subtype)
static bNodeSocketType *make_socket_type_vector(PropertySubType subtype)
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_VECTOR, subtype);
- socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<blender::float3>(); };
+ socktype->base_cpp_type = &blender::fn::CPPType::get<blender::float3>();
socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) {
*(blender::float3 *)r_value = ((bNodeSocketValueVector *)socket.default_value)->value;
};
- socktype->get_geometry_nodes_cpp_type = []() {
- return &blender::fn::CPPType::get<blender::fn::Field<blender::float3>>();
- };
+ socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<blender::float3>>();
socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) {
blender::float3 value;
socket.typeinfo->get_base_cpp_value(socket, &value);
- new (r_value) blender::fn::Field<blender::float3>(blender::fn::make_constant_field(value));
+ new (r_value) ValueOrField<blender::float3>(value);
};
return socktype;
}
@@ -769,20 +763,16 @@ static bNodeSocketType *make_socket_type_vector(PropertySubType subtype)
static bNodeSocketType *make_socket_type_rgba()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_RGBA, PROP_NONE);
- socktype->get_base_cpp_type = []() {
- return &blender::fn::CPPType::get<blender::ColorGeometry4f>();
- };
+ socktype->base_cpp_type = &blender::fn::CPPType::get<blender::ColorGeometry4f>();
socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) {
*(blender::ColorGeometry4f *)r_value = ((bNodeSocketValueRGBA *)socket.default_value)->value;
};
- socktype->get_geometry_nodes_cpp_type = []() {
- return &blender::fn::CPPType::get<blender::fn::Field<blender::ColorGeometry4f>>();
- };
+ socktype->geometry_nodes_cpp_type =
+ &blender::fn::CPPType::get<ValueOrField<blender::ColorGeometry4f>>();
socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) {
blender::ColorGeometry4f value;
socket.typeinfo->get_base_cpp_value(socket, &value);
- new (r_value)
- blender::fn::Field<blender::ColorGeometry4f>(blender::fn::make_constant_field(value));
+ new (r_value) ValueOrField<blender::ColorGeometry4f>(value);
};
return socktype;
}
@@ -790,18 +780,16 @@ static bNodeSocketType *make_socket_type_rgba()
static bNodeSocketType *make_socket_type_string()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_STRING, PROP_NONE);
- socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<std::string>(); };
+ socktype->base_cpp_type = &blender::fn::CPPType::get<std::string>();
socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) {
new (r_value) std::string(((bNodeSocketValueString *)socket.default_value)->value);
};
- socktype->get_geometry_nodes_cpp_type = []() {
- return &blender::fn::CPPType::get<blender::fn::Field<std::string>>();
- };
+ socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<std::string>>();
socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) {
std::string value;
value.~basic_string();
socket.typeinfo->get_base_cpp_value(socket, &value);
- new (r_value) blender::fn::Field<std::string>(blender::fn::make_constant_field(value));
+ new (r_value) ValueOrField<std::string>(value);
};
return socktype;
}
@@ -815,11 +803,11 @@ MAKE_CPP_TYPE(Material, Material *, CPPTypeFlags::BasicType)
static bNodeSocketType *make_socket_type_object()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_OBJECT, PROP_NONE);
- socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<Object *>(); };
+ socktype->base_cpp_type = &blender::fn::CPPType::get<Object *>();
socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) {
*(Object **)r_value = ((bNodeSocketValueObject *)socket.default_value)->value;
};
- socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type;
+ socktype->geometry_nodes_cpp_type = socktype->base_cpp_type;
socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value;
return socktype;
}
@@ -827,11 +815,11 @@ static bNodeSocketType *make_socket_type_object()
static bNodeSocketType *make_socket_type_geometry()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_GEOMETRY, PROP_NONE);
- socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<GeometrySet>(); };
+ socktype->base_cpp_type = &blender::fn::CPPType::get<GeometrySet>();
socktype->get_base_cpp_value = [](const bNodeSocket &UNUSED(socket), void *r_value) {
new (r_value) GeometrySet();
};
- socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type;
+ socktype->geometry_nodes_cpp_type = socktype->base_cpp_type;
socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value;
return socktype;
}
@@ -839,11 +827,11 @@ static bNodeSocketType *make_socket_type_geometry()
static bNodeSocketType *make_socket_type_collection()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_COLLECTION, PROP_NONE);
- socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<Collection *>(); };
+ socktype->base_cpp_type = &blender::fn::CPPType::get<Collection *>();
socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) {
*(Collection **)r_value = ((bNodeSocketValueCollection *)socket.default_value)->value;
};
- socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type;
+ socktype->geometry_nodes_cpp_type = socktype->base_cpp_type;
socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value;
return socktype;
}
@@ -851,11 +839,11 @@ static bNodeSocketType *make_socket_type_collection()
static bNodeSocketType *make_socket_type_texture()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_TEXTURE, PROP_NONE);
- socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<Tex *>(); };
+ socktype->base_cpp_type = &blender::fn::CPPType::get<Tex *>();
socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) {
*(Tex **)r_value = ((bNodeSocketValueTexture *)socket.default_value)->value;
};
- socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type;
+ socktype->geometry_nodes_cpp_type = socktype->base_cpp_type;
socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value;
return socktype;
}
@@ -863,11 +851,11 @@ static bNodeSocketType *make_socket_type_texture()
static bNodeSocketType *make_socket_type_image()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_IMAGE, PROP_NONE);
- socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<Image *>(); };
+ socktype->base_cpp_type = &blender::fn::CPPType::get<Image *>();
socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) {
*(Image **)r_value = ((bNodeSocketValueImage *)socket.default_value)->value;
};
- socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type;
+ socktype->geometry_nodes_cpp_type = socktype->base_cpp_type;
socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value;
return socktype;
}
@@ -875,11 +863,11 @@ static bNodeSocketType *make_socket_type_image()
static bNodeSocketType *make_socket_type_material()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_MATERIAL, PROP_NONE);
- socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<Material *>(); };
+ socktype->base_cpp_type = &blender::fn::CPPType::get<Material *>();
socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) {
*(Material **)r_value = ((bNodeSocketValueMaterial *)socket.default_value)->value;
};
- socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type;
+ socktype->geometry_nodes_cpp_type = socktype->base_cpp_type;
socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value;
return socktype;
}
diff --git a/source/blender/nodes/intern/node_socket_declarations.cc b/source/blender/nodes/intern/node_socket_declarations.cc
index ed5691ebf7f..4fef5b96e9f 100644
--- a/source/blender/nodes/intern/node_socket_declarations.cc
+++ b/source/blender/nodes/intern/node_socket_declarations.cc
@@ -23,6 +23,52 @@
namespace blender::nodes::decl {
+/**
+ * \note This function only deals with declarations, not the field status of existing nodes. If the
+ * field status of existing nodes was stored on the sockets, an improvement would be to check the
+ * existing socket's current status instead of the declaration.
+ */
+static bool field_types_are_compatible(const SocketDeclaration &input,
+ const SocketDeclaration &output)
+{
+ if (output.output_field_dependency().field_type() == OutputSocketFieldType::FieldSource) {
+ if (input.input_field_type() == InputSocketFieldType::None) {
+ return false;
+ }
+ }
+ return true;
+}
+
+static bool sockets_can_connect(const SocketDeclaration &socket_decl,
+ const bNodeSocket &other_socket)
+{
+ /* Input sockets cannot connect to input sockets, outputs cannot connect to outputs. */
+ if (socket_decl.in_out() == other_socket.in_out) {
+ return false;
+ }
+
+ if (other_socket.declaration) {
+ if (socket_decl.in_out() == SOCK_IN) {
+ if (!field_types_are_compatible(socket_decl, *other_socket.declaration)) {
+ return false;
+ }
+ }
+ else {
+ if (!field_types_are_compatible(*other_socket.declaration, socket_decl)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+static bool basic_types_can_connect(const SocketDeclaration &UNUSED(socket_decl),
+ const bNodeSocket &other_socket)
+{
+ return ELEM(other_socket.type, SOCK_FLOAT, SOCK_INT, SOCK_BOOLEAN, SOCK_VECTOR, SOCK_RGBA);
+}
+
static void modify_subtype_except_for_storage(bNodeSocket &socket, int new_subtype)
{
const char *idname = nodeStaticSocketType(socket.type, new_subtype);
@@ -35,10 +81,10 @@ static void modify_subtype_except_for_storage(bNodeSocket &socket, int new_subty
/** \name #Float
* \{ */
-bNodeSocket &Float::build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const
+bNodeSocket &Float::build(bNodeTree &ntree, bNode &node) const
{
bNodeSocket &socket = *nodeAddStaticSocket(
- &ntree, &node, in_out, SOCK_FLOAT, subtype_, identifier_.c_str(), name_.c_str());
+ &ntree, &node, in_out_, SOCK_FLOAT, subtype_, identifier_.c_str(), name_.c_str());
this->set_common_flags(socket);
bNodeSocketValueFloat &value = *(bNodeSocketValueFloat *)socket.default_value;
value.min = soft_min_value_;
@@ -68,10 +114,19 @@ bool Float::matches(const bNodeSocket &socket) const
return true;
}
+bool Float::can_connect(const bNodeSocket &socket) const
+{
+ if (!sockets_can_connect(*this, socket)) {
+ return false;
+ }
+ return basic_types_can_connect(*this, socket);
+}
+
bNodeSocket &Float::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const
{
if (socket.type != SOCK_FLOAT) {
- return this->build(ntree, node, (eNodeSocketInOut)socket.in_out);
+ BLI_assert(socket.in_out == in_out_);
+ return this->build(ntree, node);
}
if (socket.typeinfo->subtype != subtype_) {
modify_subtype_except_for_storage(socket, subtype_);
@@ -90,10 +145,10 @@ bNodeSocket &Float::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &
/** \name #Int
* \{ */
-bNodeSocket &Int::build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const
+bNodeSocket &Int::build(bNodeTree &ntree, bNode &node) const
{
bNodeSocket &socket = *nodeAddStaticSocket(
- &ntree, &node, in_out, SOCK_INT, subtype_, identifier_.c_str(), name_.c_str());
+ &ntree, &node, in_out_, SOCK_INT, subtype_, identifier_.c_str(), name_.c_str());
this->set_common_flags(socket);
bNodeSocketValueInt &value = *(bNodeSocketValueInt *)socket.default_value;
value.min = soft_min_value_;
@@ -123,10 +178,19 @@ bool Int::matches(const bNodeSocket &socket) const
return true;
}
+bool Int::can_connect(const bNodeSocket &socket) const
+{
+ if (!sockets_can_connect(*this, socket)) {
+ return false;
+ }
+ return basic_types_can_connect(*this, socket);
+}
+
bNodeSocket &Int::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const
{
if (socket.type != SOCK_INT) {
- return this->build(ntree, node, (eNodeSocketInOut)socket.in_out);
+ BLI_assert(socket.in_out == in_out_);
+ return this->build(ntree, node);
}
if (socket.typeinfo->subtype != subtype_) {
modify_subtype_except_for_storage(socket, subtype_);
@@ -145,10 +209,10 @@ bNodeSocket &Int::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &so
/** \name #Vector
* \{ */
-bNodeSocket &Vector::build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const
+bNodeSocket &Vector::build(bNodeTree &ntree, bNode &node) const
{
bNodeSocket &socket = *nodeAddStaticSocket(
- &ntree, &node, in_out, SOCK_VECTOR, subtype_, identifier_.c_str(), name_.c_str());
+ &ntree, &node, in_out_, SOCK_VECTOR, subtype_, identifier_.c_str(), name_.c_str());
this->set_common_flags(socket);
bNodeSocketValueVector &value = *(bNodeSocketValueVector *)socket.default_value;
copy_v3_v3(value.value, default_value_);
@@ -171,10 +235,19 @@ bool Vector::matches(const bNodeSocket &socket) const
return true;
}
+bool Vector::can_connect(const bNodeSocket &socket) const
+{
+ if (!sockets_can_connect(*this, socket)) {
+ return false;
+ }
+ return basic_types_can_connect(*this, socket);
+}
+
bNodeSocket &Vector::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const
{
if (socket.type != SOCK_VECTOR) {
- return this->build(ntree, node, (eNodeSocketInOut)socket.in_out);
+ BLI_assert(socket.in_out == in_out_);
+ return this->build(ntree, node);
}
if (socket.typeinfo->subtype != subtype_) {
modify_subtype_except_for_storage(socket, subtype_);
@@ -192,10 +265,10 @@ bNodeSocket &Vector::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket
/** \name #Bool
* \{ */
-bNodeSocket &Bool::build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const
+bNodeSocket &Bool::build(bNodeTree &ntree, bNode &node) const
{
bNodeSocket &socket = *nodeAddStaticSocket(
- &ntree, &node, in_out, SOCK_BOOLEAN, PROP_NONE, identifier_.c_str(), name_.c_str());
+ &ntree, &node, in_out_, SOCK_BOOLEAN, PROP_NONE, identifier_.c_str(), name_.c_str());
this->set_common_flags(socket);
bNodeSocketValueBoolean &value = *(bNodeSocketValueBoolean *)socket.default_value;
value.value = default_value_;
@@ -213,16 +286,24 @@ bool Bool::matches(const bNodeSocket &socket) const
return true;
}
+bool Bool::can_connect(const bNodeSocket &socket) const
+{
+ if (!sockets_can_connect(*this, socket)) {
+ return false;
+ }
+ return basic_types_can_connect(*this, socket);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name #Color
* \{ */
-bNodeSocket &Color::build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const
+bNodeSocket &Color::build(bNodeTree &ntree, bNode &node) const
{
bNodeSocket &socket = *nodeAddStaticSocket(
- &ntree, &node, in_out, SOCK_RGBA, PROP_NONE, identifier_.c_str(), name_.c_str());
+ &ntree, &node, in_out_, SOCK_RGBA, PROP_NONE, identifier_.c_str(), name_.c_str());
this->set_common_flags(socket);
bNodeSocketValueRGBA &value = *(bNodeSocketValueRGBA *)socket.default_value;
copy_v4_v4(value.value, default_value_);
@@ -245,16 +326,24 @@ bool Color::matches(const bNodeSocket &socket) const
return true;
}
+bool Color::can_connect(const bNodeSocket &socket) const
+{
+ if (!sockets_can_connect(*this, socket)) {
+ return false;
+ }
+ return basic_types_can_connect(*this, socket);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name #String
* \{ */
-bNodeSocket &String::build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const
+bNodeSocket &String::build(bNodeTree &ntree, bNode &node) const
{
bNodeSocket &socket = *nodeAddStaticSocket(
- &ntree, &node, in_out, SOCK_STRING, PROP_NONE, identifier_.c_str(), name_.c_str());
+ &ntree, &node, in_out_, SOCK_STRING, PROP_NONE, identifier_.c_str(), name_.c_str());
STRNCPY(((bNodeSocketValueString *)socket.default_value)->value, default_value_.c_str());
this->set_common_flags(socket);
return socket;
@@ -271,18 +360,21 @@ bool String::matches(const bNodeSocket &socket) const
return true;
}
+bool String::can_connect(const bNodeSocket &socket) const
+{
+ return sockets_can_connect(*this, socket) && socket.type == SOCK_STRING;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name #IDSocketDeclaration
* \{ */
-bNodeSocket &IDSocketDeclaration::build(bNodeTree &ntree,
- bNode &node,
- eNodeSocketInOut in_out) const
+bNodeSocket &IDSocketDeclaration::build(bNodeTree &ntree, bNode &node) const
{
bNodeSocket &socket = *nodeAddSocket(
- &ntree, &node, in_out, idname_, identifier_.c_str(), name_.c_str());
+ &ntree, &node, in_out_, idname_, identifier_.c_str(), name_.c_str());
this->set_common_flags(socket);
return socket;
}
@@ -298,12 +390,18 @@ bool IDSocketDeclaration::matches(const bNodeSocket &socket) const
return true;
}
+bool IDSocketDeclaration::can_connect(const bNodeSocket &socket) const
+{
+ return sockets_can_connect(*this, socket) && STREQ(socket.idname, idname_);
+}
+
bNodeSocket &IDSocketDeclaration::update_or_build(bNodeTree &ntree,
bNode &node,
bNodeSocket &socket) const
{
if (StringRef(socket.idname) != idname_) {
- return this->build(ntree, node, (eNodeSocketInOut)socket.in_out);
+ BLI_assert(socket.in_out == in_out_);
+ return this->build(ntree, node);
}
this->set_common_flags(socket);
return socket;
@@ -315,10 +413,10 @@ bNodeSocket &IDSocketDeclaration::update_or_build(bNodeTree &ntree,
/** \name #Geometry
* \{ */
-bNodeSocket &Geometry::build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const
+bNodeSocket &Geometry::build(bNodeTree &ntree, bNode &node) const
{
bNodeSocket &socket = *nodeAddSocket(
- &ntree, &node, in_out, "NodeSocketGeometry", identifier_.c_str(), name_.c_str());
+ &ntree, &node, in_out_, "NodeSocketGeometry", identifier_.c_str(), name_.c_str());
this->set_common_flags(socket);
return socket;
}
@@ -334,6 +432,11 @@ bool Geometry::matches(const bNodeSocket &socket) const
return true;
}
+bool Geometry::can_connect(const bNodeSocket &socket) const
+{
+ return sockets_can_connect(*this, socket) && socket.type == SOCK_GEOMETRY;
+}
+
Span<GeometryComponentType> Geometry::supported_types() const
{
return supported_types_;
@@ -376,4 +479,41 @@ GeometryBuilder &GeometryBuilder::only_instances(bool value)
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name #Shader
+ * \{ */
+
+bNodeSocket &Shader::build(bNodeTree &ntree, bNode &node) const
+{
+ bNodeSocket &socket = *nodeAddSocket(
+ &ntree, &node, in_out_, "NodeSocketShader", identifier_.c_str(), name_.c_str());
+ this->set_common_flags(socket);
+ return socket;
+}
+
+bool Shader::matches(const bNodeSocket &socket) const
+{
+ if (!this->matches_common_data(socket)) {
+ return false;
+ }
+ if (socket.type != SOCK_SHADER) {
+ return false;
+ }
+ return true;
+}
+
+bool Shader::can_connect(const bNodeSocket &socket) const
+{
+ if (!sockets_can_connect(*this, socket)) {
+ return false;
+ }
+ /* Basic types can convert to shaders, but not the other way around. */
+ if (in_out_ == SOCK_IN) {
+ return ELEM(socket.type, SOCK_VECTOR, SOCK_RGBA, SOCK_FLOAT, SOCK_INT, SOCK_BOOLEAN);
+ }
+ return socket.type == SOCK_SHADER;
+}
+
+/** \} */
+
} // namespace blender::nodes::decl
diff --git a/source/blender/nodes/intern/node_tree_ref.cc b/source/blender/nodes/intern/node_tree_ref.cc
index 5481465aef6..912d5e5322c 100644
--- a/source/blender/nodes/intern/node_tree_ref.cc
+++ b/source/blender/nodes/intern/node_tree_ref.cc
@@ -262,7 +262,6 @@ void InputSocketRef::foreach_logical_origin(
skipped_fn.call_safe(origin);
skipped_fn.call_safe(mute_input);
mute_input.foreach_logical_origin(origin_fn, skipped_fn, true, seen_sockets_stack);
- break;
}
}
}
@@ -442,9 +441,6 @@ static bool has_link_cycles_recursive(const NodeRef &node,
return false;
}
-/**
- * \return True when there is a link cycle. Unavailable sockets are ignored.
- */
bool NodeTreeRef::has_link_cycles() const
{
const int node_amount = nodes_by_id_.size();
@@ -571,10 +567,6 @@ static void toposort_from_start_node(const NodeTreeRef::ToposortDirection direct
}
}
-/**
- * Sort nodes topologically from left to right or right to left.
- * In the future the result if this could be cached on #NodeTreeRef.
- */
NodeTreeRef::ToposortResult NodeTreeRef::toposort(const ToposortDirection direction) const
{
ToposortResult result;
diff --git a/source/blender/nodes/intern/node_util.c b/source/blender/nodes/intern/node_util.c
index 231030030eb..7620c8fa1a8 100644
--- a/source/blender/nodes/intern/node_util.c
+++ b/source/blender/nodes/intern/node_util.c
@@ -190,7 +190,7 @@ void node_math_update(bNodeTree *ntree, bNode *node)
/** \name Labels
* \{ */
-void node_blend_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
+void node_blend_label(const bNodeTree *UNUSED(ntree), const bNode *node, char *label, int maxlen)
{
const char *name;
bool enum_label = RNA_enum_name(rna_enum_ramp_blend_items, node->custom1, &name);
@@ -200,14 +200,14 @@ void node_blend_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int ma
BLI_strncpy(label, IFACE_(name), maxlen);
}
-void node_image_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
+void node_image_label(const bNodeTree *UNUSED(ntree), const bNode *node, char *label, int maxlen)
{
/* If there is no loaded image, return an empty string,
* and let nodeLabel() fill in the proper type translation. */
BLI_strncpy(label, (node->id) ? node->id->name + 2 : "", maxlen);
}
-void node_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
+void node_math_label(const bNodeTree *UNUSED(ntree), const bNode *node, char *label, int maxlen)
{
const char *name;
bool enum_label = RNA_enum_name(rna_enum_node_math_items, node->custom1, &name);
@@ -217,7 +217,10 @@ void node_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int max
BLI_strncpy(label, IFACE_(name), maxlen);
}
-void node_vector_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
+void node_vector_math_label(const bNodeTree *UNUSED(ntree),
+ const bNode *node,
+ char *label,
+ int maxlen)
{
const char *name;
bool enum_label = RNA_enum_name(rna_enum_node_vec_math_items, node->custom1, &name);
@@ -227,7 +230,7 @@ void node_vector_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label,
BLI_strncpy(label, IFACE_(name), maxlen);
}
-void node_filter_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
+void node_filter_label(const bNodeTree *UNUSED(ntree), const bNode *node, char *label, int maxlen)
{
const char *name;
bool enum_label = RNA_enum_name(rna_enum_node_filter_items, node->custom1, &name);
@@ -301,11 +304,6 @@ static bNodeSocket *node_find_linkable_socket(bNodeTree *ntree,
return NULL;
}
-/**
- * The idea behind this is: When a user connects an input to a socket that is
- * already linked (and if its not an Multi Input Socket), we try to find a replacement socket for
- * the link that we try to overwrite and connect that previous link to the new socket.
- */
void node_insert_link_default(bNodeTree *ntree, bNode *node, bNodeLink *link)
{
bNodeSocket *socket = link->tosock;
@@ -351,11 +349,11 @@ void node_insert_link_default(bNodeTree *ntree, bNode *node, bNodeLink *link)
* `< 0`: never connect these types.
* `>= 0`: priority of connection (higher values chosen first).
*/
-static int node_datatype_priority(eNodeSocketDatatype from, eNodeSocketDatatype to)
+static int node_datatype_priority(const bNodeSocketType *from, const bNodeSocketType *to)
{
- switch (to) {
+ switch (to->type) {
case SOCK_RGBA:
- switch (from) {
+ switch (from->type) {
case SOCK_RGBA:
return 4;
case SOCK_FLOAT:
@@ -364,11 +362,10 @@ static int node_datatype_priority(eNodeSocketDatatype from, eNodeSocketDatatype
return 2;
case SOCK_BOOLEAN:
return 1;
- default:
- return -1;
}
+ return -1;
case SOCK_VECTOR:
- switch (from) {
+ switch (from->type) {
case SOCK_VECTOR:
return 4;
case SOCK_FLOAT:
@@ -377,11 +374,10 @@ static int node_datatype_priority(eNodeSocketDatatype from, eNodeSocketDatatype
return 2;
case SOCK_BOOLEAN:
return 1;
- default:
- return -1;
}
+ return -1;
case SOCK_FLOAT:
- switch (from) {
+ switch (from->type) {
case SOCK_FLOAT:
return 5;
case SOCK_INT:
@@ -392,11 +388,10 @@ static int node_datatype_priority(eNodeSocketDatatype from, eNodeSocketDatatype
return 2;
case SOCK_VECTOR:
return 1;
- default:
- return -1;
}
+ return -1;
case SOCK_INT:
- switch (from) {
+ switch (from->type) {
case SOCK_INT:
return 5;
case SOCK_FLOAT:
@@ -407,11 +402,10 @@ static int node_datatype_priority(eNodeSocketDatatype from, eNodeSocketDatatype
return 2;
case SOCK_VECTOR:
return 1;
- default:
- return -1;
}
+ return -1;
case SOCK_BOOLEAN:
- switch (from) {
+ switch (from->type) {
case SOCK_BOOLEAN:
return 5;
case SOCK_INT:
@@ -422,74 +416,17 @@ static int node_datatype_priority(eNodeSocketDatatype from, eNodeSocketDatatype
return 2;
case SOCK_VECTOR:
return 1;
- default:
- return -1;
- }
- case SOCK_SHADER:
- switch (from) {
- case SOCK_SHADER:
- return 1;
- default:
- return -1;
}
- case SOCK_STRING:
- switch (from) {
- case SOCK_STRING:
- return 1;
- default:
- return -1;
- }
- case SOCK_OBJECT: {
- switch (from) {
- case SOCK_OBJECT:
- return 1;
- default:
- return -1;
- }
- }
- case SOCK_GEOMETRY: {
- switch (from) {
- case SOCK_GEOMETRY:
- return 1;
- default:
- return -1;
- }
- }
- case SOCK_COLLECTION: {
- switch (from) {
- case SOCK_COLLECTION:
- return 1;
- default:
- return -1;
- }
- }
- case SOCK_TEXTURE: {
- switch (from) {
- case SOCK_TEXTURE:
- return 1;
- default:
- return -1;
- }
- }
- case SOCK_IMAGE: {
- switch (from) {
- case SOCK_IMAGE:
- return 1;
- default:
- return -1;
- }
- }
- case SOCK_MATERIAL: {
- switch (from) {
- case SOCK_MATERIAL:
- return 1;
- default:
- return -1;
- }
- }
- default:
return -1;
}
+
+ /* The rest of the socket types only allow an internal link if both the input and output socket
+ * have the same type. If the sockets are custom, we check the idname instead. */
+ if (to->type == from->type && (to->type != SOCK_CUSTOM || STREQ(to->idname, from->idname))) {
+ return 1;
+ }
+
+ return -1;
}
/* select a suitable input socket for an output */
@@ -505,7 +442,7 @@ static bNodeSocket *select_internal_link_input(bNode *node, bNodeSocket *output)
bool sel_is_linked = false;
for (input = node->inputs.first, i = 0; input; input = input->next, i++) {
- int priority = node_datatype_priority(input->type, output->type);
+ int priority = node_datatype_priority(input->typeinfo, output->typeinfo);
bool is_linked = (input->link != NULL);
bool preferred;
diff --git a/source/blender/nodes/intern/node_util.h b/source/blender/nodes/intern/node_util.h
index c064ef4ab36..d7da2303088 100644
--- a/source/blender/nodes/intern/node_util.h
+++ b/source/blender/nodes/intern/node_util.h
@@ -23,20 +23,6 @@
#pragma once
-#include "DNA_listBase.h"
-
-#include "BLI_utildefines.h"
-
-#include "BKE_node.h"
-
-#include "MEM_guardedalloc.h"
-
-#include "NOD_socket.h"
-
-#include "GPU_material.h" /* For Shader muting GPU code... */
-
-#include "RNA_access.h"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -56,18 +42,18 @@ typedef struct bNodeExecData {
/**** Storage Data ****/
-extern void node_free_curves(struct bNode *node);
-extern void node_free_standard_storage(struct bNode *node);
+void node_free_curves(struct bNode *node);
+void node_free_standard_storage(struct bNode *node);
-extern void node_copy_curves(struct bNodeTree *dest_ntree,
- struct bNode *dest_node,
- const struct bNode *src_node);
-extern void node_copy_standard_storage(struct bNodeTree *dest_ntree,
- struct bNode *dest_node,
- const struct bNode *src_node);
-extern void *node_initexec_curves(struct bNodeExecContext *context,
- struct bNode *node,
- bNodeInstanceKey key);
+void node_copy_curves(struct bNodeTree *dest_ntree,
+ struct bNode *dest_node,
+ const struct bNode *src_node);
+void node_copy_standard_storage(struct bNodeTree *dest_ntree,
+ struct bNode *dest_node,
+ const struct bNode *src_node);
+void *node_initexec_curves(struct bNodeExecContext *context,
+ struct bNode *node,
+ bNodeInstanceKey key);
/**** Updates ****/
void node_sock_label(struct bNodeSocket *sock, const char *name);
@@ -75,13 +61,34 @@ void node_sock_label_clear(struct bNodeSocket *sock);
void node_math_update(struct bNodeTree *ntree, struct bNode *node);
/**** Labels ****/
-void node_blend_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen);
-void node_image_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen);
-void node_math_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen);
-void node_vector_math_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen);
-void node_filter_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen);
+void node_blend_label(const struct bNodeTree *ntree,
+ const struct bNode *node,
+ char *label,
+ int maxlen);
+void node_image_label(const struct bNodeTree *ntree,
+ const struct bNode *node,
+ char *label,
+ int maxlen);
+void node_math_label(const struct bNodeTree *ntree,
+ const struct bNode *node,
+ char *label,
+ int maxlen);
+void node_vector_math_label(const struct bNodeTree *ntree,
+ const struct bNode *node,
+ char *label,
+ int maxlen);
+void node_filter_label(const struct bNodeTree *ntree,
+ const struct bNode *node,
+ char *label,
+ int maxlen);
/*** Link Handling */
+
+/**
+ * The idea behind this is: When a user connects an input to a socket that is
+ * already linked (and if its not an Multi Input Socket), we try to find a replacement socket for
+ * the link that we try to overwrite and connect that previous link to the new socket.
+ */
void node_insert_link_default(struct bNodeTree *ntree, struct bNode *node, struct bNodeLink *link);
float node_socket_get_float(struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *sock);
diff --git a/source/blender/nodes/intern/socket_search_link.cc b/source/blender/nodes/intern/socket_search_link.cc
new file mode 100644
index 00000000000..8543efe7f9b
--- /dev/null
+++ b/source/blender/nodes/intern/socket_search_link.cc
@@ -0,0 +1,199 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "BLI_set.hh"
+
+#include "BKE_node.h"
+
+#include "UI_interface.h"
+
+#include "NOD_node_declaration.hh"
+#include "NOD_socket_search_link.hh"
+
+namespace blender::nodes {
+
+void GatherLinkSearchOpParams::add_item(std::string socket_name,
+ SocketLinkOperation::LinkSocketFn fn,
+ const int weight)
+{
+
+ std::string name = std::string(node_type_.ui_name) + " " + UI_MENU_ARROW_SEP + socket_name;
+
+ items_.append({std::move(name), std::move(fn), weight});
+}
+
+const bNodeSocket &GatherLinkSearchOpParams::other_socket() const
+{
+ return other_socket_;
+}
+
+const bNodeTree &GatherLinkSearchOpParams::node_tree() const
+{
+ return node_tree_;
+}
+
+const bNodeType &GatherLinkSearchOpParams::node_type() const
+{
+ return node_type_;
+}
+
+eNodeSocketInOut GatherLinkSearchOpParams::in_out() const
+{
+ return other_socket_.in_out == SOCK_IN ? SOCK_OUT : SOCK_IN;
+}
+
+void LinkSearchOpParams::connect_available_socket(bNode &new_node, StringRef socket_name)
+{
+ const eNodeSocketInOut in_out = socket.in_out == SOCK_IN ? SOCK_OUT : SOCK_IN;
+ bNodeSocket *new_node_socket = bke::node_find_enabled_socket(new_node, in_out, socket_name);
+ if (new_node_socket == nullptr) {
+ /* If the socket isn't found, some node's search gather functions probably aren't configured
+ * properly. It's likely enough that it's worth avoiding a crash in a release build though. */
+ BLI_assert_unreachable();
+ return;
+ }
+ nodeAddLink(&node_tree, &new_node, new_node_socket, &node, &socket);
+}
+
+bNode &LinkSearchOpParams::add_node(StringRef idname)
+{
+ std::string idname_str = idname;
+ bNode *node = nodeAddNode(&C, &node_tree, idname_str.c_str());
+ BLI_assert(node != nullptr);
+ added_nodes_.append(node);
+ return *node;
+}
+
+bNode &LinkSearchOpParams::add_node(const bNodeType &node_type)
+{
+ return this->add_node(node_type.idname);
+}
+
+void LinkSearchOpParams::update_and_connect_available_socket(bNode &new_node,
+ StringRef socket_name)
+{
+ if (new_node.typeinfo->updatefunc) {
+ new_node.typeinfo->updatefunc(&node_tree, &new_node);
+ }
+ this->connect_available_socket(new_node, socket_name);
+}
+
+void search_link_ops_for_declarations(GatherLinkSearchOpParams &params,
+ Span<SocketDeclarationPtr> declarations)
+{
+ const bNodeType &node_type = params.node_type();
+
+ const SocketDeclaration *main_socket = nullptr;
+ Vector<const SocketDeclaration *> connectable_sockets;
+
+ Set<StringRef> socket_names;
+ for (const int i : declarations.index_range()) {
+ const SocketDeclaration &socket = *declarations[i];
+ if (!socket_names.add(socket.name())) {
+ /* Don't add sockets with the same name to the search. Needed to support being called from
+ * #search_link_ops_for_basic_node, which should have "okay" behavior for nodes with
+ * duplicate socket names. */
+ continue;
+ }
+ if (!socket.can_connect(params.other_socket())) {
+ continue;
+ }
+ if (socket.is_default_link_socket() || main_socket == nullptr) {
+ /* Either the first connectable or explicitly tagged socket is the main socket. */
+ main_socket = &socket;
+ }
+ connectable_sockets.append(&socket);
+ }
+ for (const int i : connectable_sockets.index_range()) {
+ const SocketDeclaration &socket = *connectable_sockets[i];
+ /* Give non-main sockets a lower weight so that they don't show up at the top of the search
+ * when they are not explicitly searched for. The -1 is used to make sure that the first socket
+ * has a smaller weight than zero so that it does not have the same weight as the main socket.
+ * Negative weights are used to avoid making the highest weight dependent on the number of
+ * sockets. */
+ const int weight = (&socket == main_socket) ? 0 : -1 - i;
+ params.add_item(
+ socket.name(),
+ [&node_type, &socket](LinkSearchOpParams &params) {
+ bNode &node = params.add_node(node_type);
+ socket.make_available(node);
+ params.update_and_connect_available_socket(node, socket.name());
+ },
+ weight);
+ }
+}
+
+static void search_link_ops_for_socket_templates(GatherLinkSearchOpParams &params,
+ const bNodeSocketTemplate *templates,
+ const eNodeSocketInOut in_out)
+{
+ const bNodeType &node_type = params.node_type();
+ const bNodeTreeType &node_tree_type = *params.node_tree().typeinfo;
+
+ Set<StringRef> socket_names;
+ for (const bNodeSocketTemplate *socket_template = templates; socket_template->type != -1;
+ socket_template++) {
+ eNodeSocketDatatype from = (eNodeSocketDatatype)socket_template->type;
+ eNodeSocketDatatype to = (eNodeSocketDatatype)params.other_socket().type;
+ if (in_out == SOCK_IN) {
+ std::swap(from, to);
+ }
+ if (node_tree_type.validate_link && !node_tree_type.validate_link(from, to)) {
+ continue;
+ }
+ if (!socket_names.add(socket_template->name)) {
+ /* See comment in #search_link_ops_for_declarations. */
+ continue;
+ }
+
+ params.add_item(
+ socket_template->name, [socket_template, node_type, in_out](LinkSearchOpParams &params) {
+ bNode &node = params.add_node(node_type);
+ bNodeSocket *new_node_socket = bke::node_find_enabled_socket(
+ node, in_out, socket_template->name);
+ if (new_node_socket != nullptr) {
+ /* Rely on the way #nodeAddLink switches in/out if necessary. */
+ nodeAddLink(&params.node_tree, &params.node, &params.socket, &node, new_node_socket);
+ }
+ });
+ }
+}
+
+void search_link_ops_for_basic_node(GatherLinkSearchOpParams &params)
+{
+ const bNodeType &node_type = params.node_type();
+
+ if (node_type.declare) {
+ if (node_type.declaration_is_dynamic) {
+ /* Dynamic declarations (whatever they end up being) aren't supported
+ * by this function, but still avoid a crash in release builds. */
+ BLI_assert_unreachable();
+ return;
+ }
+
+ const NodeDeclaration &declaration = *node_type.fixed_declaration;
+
+ search_link_ops_for_declarations(params, declaration.sockets(params.in_out()));
+ }
+ else if (node_type.inputs && params.in_out() == SOCK_IN) {
+ search_link_ops_for_socket_templates(params, node_type.inputs, SOCK_IN);
+ }
+ else if (node_type.outputs && params.in_out() == SOCK_OUT) {
+ search_link_ops_for_socket_templates(params, node_type.outputs, SOCK_OUT);
+ }
+}
+
+} // namespace blender::nodes
diff --git a/source/blender/nodes/shader/CMakeLists.txt b/source/blender/nodes/shader/CMakeLists.txt
new file mode 100644
index 00000000000..7d99c233197
--- /dev/null
+++ b/source/blender/nodes/shader/CMakeLists.txt
@@ -0,0 +1,166 @@
+# ***** 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) 2021, Blender Foundation
+# All rights reserved.
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ .
+ ../
+ ../intern
+ ../../blenkernel
+ ../../blenlib
+ ../../blentranslation
+ ../../depsgraph
+ ../../functions
+ ../../gpu
+ ../../imbuf
+ ../../makesdna
+ ../../makesrna
+ ../../render
+ ../../windowmanager
+ ../../../../intern/guardedalloc
+ ../../../../intern/sky/include
+)
+
+
+set(SRC
+ nodes/node_shader_add_shader.c
+ nodes/node_shader_ambient_occlusion.c
+ nodes/node_shader_attribute.c
+ nodes/node_shader_background.c
+ nodes/node_shader_bevel.c
+ nodes/node_shader_blackbody.c
+ nodes/node_shader_brightness.c
+ nodes/node_shader_bsdf_anisotropic.c
+ nodes/node_shader_bsdf_diffuse.c
+ nodes/node_shader_bsdf_glass.c
+ nodes/node_shader_bsdf_glossy.c
+ nodes/node_shader_bsdf_hair.c
+ nodes/node_shader_bsdf_hair_principled.c
+ nodes/node_shader_bsdf_principled.c
+ nodes/node_shader_bsdf_refraction.c
+ nodes/node_shader_bsdf_toon.c
+ nodes/node_shader_bsdf_translucent.c
+ nodes/node_shader_bsdf_transparent.c
+ nodes/node_shader_bsdf_velvet.c
+ nodes/node_shader_bump.c
+ nodes/node_shader_camera.c
+ nodes/node_shader_clamp.cc
+ nodes/node_shader_common.c
+ nodes/node_shader_curves.cc
+ nodes/node_shader_displacement.c
+ nodes/node_shader_eevee_specular.c
+ nodes/node_shader_emission.c
+ nodes/node_shader_fresnel.c
+ nodes/node_shader_gamma.c
+ nodes/node_shader_geometry.c
+ nodes/node_shader_hair_info.c
+ nodes/node_shader_holdout.c
+ nodes/node_shader_hueSatVal.c
+ nodes/node_shader_ies_light.c
+ nodes/node_shader_invert.c
+ nodes/node_shader_layer_weight.c
+ nodes/node_shader_light_falloff.c
+ nodes/node_shader_light_path.c
+ nodes/node_shader_map_range.cc
+ nodes/node_shader_mapping.c
+ nodes/node_shader_math.cc
+ nodes/node_shader_mix_rgb.cc
+ nodes/node_shader_mix_shader.c
+ nodes/node_shader_normal.c
+ nodes/node_shader_normal_map.c
+ nodes/node_shader_object_info.c
+ nodes/node_shader_output_aov.c
+ nodes/node_shader_output_light.c
+ nodes/node_shader_output_linestyle.c
+ nodes/node_shader_output_material.c
+ nodes/node_shader_output_world.c
+ nodes/node_shader_particle_info.c
+ nodes/node_shader_rgb_to_bw.cc
+ nodes/node_shader_rgb.c
+ nodes/node_shader_script.c
+ nodes/node_shader_sepcomb_hsv.c
+ nodes/node_shader_sepcomb_rgb.cc
+ nodes/node_shader_sepcomb_xyz.cc
+ nodes/node_shader_shader_to_rgb.c
+ nodes/node_shader_squeeze.c
+ nodes/node_shader_subsurface_scattering.c
+ nodes/node_shader_tangent.c
+ nodes/node_shader_tex_brick.cc
+ nodes/node_shader_tex_checker.cc
+ nodes/node_shader_tex_coord.c
+ nodes/node_shader_tex_environment.c
+ nodes/node_shader_tex_gradient.cc
+ nodes/node_shader_tex_image.cc
+ nodes/node_shader_tex_magic.cc
+ nodes/node_shader_tex_musgrave.cc
+ nodes/node_shader_tex_noise.cc
+ nodes/node_shader_tex_pointdensity.c
+ nodes/node_shader_tex_sky.c
+ nodes/node_shader_tex_voronoi.cc
+ nodes/node_shader_tex_wave.cc
+ nodes/node_shader_tex_white_noise.cc
+ nodes/node_shader_uv_along_stroke.c
+ nodes/node_shader_uvmap.c
+ nodes/node_shader_value.cc
+ nodes/node_shader_vector_displacement.c
+ nodes/node_shader_vector_math.cc
+ nodes/node_shader_vector_rotate.cc
+ nodes/node_shader_vector_transform.c
+ nodes/node_shader_vertex_color.c
+ nodes/node_shader_volume_absorption.c
+ nodes/node_shader_volume_info.c
+ nodes/node_shader_volume_principled.c
+ nodes/node_shader_volume_scatter.c
+ nodes/node_shader_wavelength.c
+ nodes/node_shader_wireframe.c
+
+ node_shader_tree.c
+ node_shader_util.cc
+
+ node_shader_util.h
+)
+
+set(LIB
+ bf_functions
+ bf_intern_sky
+)
+
+if(WITH_PYTHON)
+ list(APPEND INC
+ ../../python
+ )
+ list(APPEND INC_SYS
+ ${PYTHON_INCLUDE_DIRS}
+ )
+ list(APPEND LIB
+ ${PYTHON_LINKFLAGS}
+ ${PYTHON_LIBRARIES}
+ )
+ add_definitions(-DWITH_PYTHON)
+endif()
+
+if(WITH_INTERNATIONAL)
+ add_definitions(-DWITH_INTERNATIONAL)
+endif()
+
+if(WITH_FREESTYLE)
+ add_definitions(-DWITH_FREESTYLE)
+endif()
+
+blender_add_lib(bf_nodes_shader "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.c
index 83ee0c2f411..c3b5236373c 100644
--- a/source/blender/nodes/shader/node_shader_tree.c
+++ b/source/blender/nodes/shader/node_shader_tree.c
@@ -139,12 +139,8 @@ static void foreach_nodeclass(Scene *UNUSED(scene), void *calldata, bNodeClassCa
static void localize(bNodeTree *localtree, bNodeTree *UNUSED(ntree))
{
- bNode *node, *node_next;
-
/* replace muted nodes and reroute nodes by internal links */
- for (node = localtree->nodes.first; node; node = node_next) {
- node_next = node->next;
-
+ LISTBASE_FOREACH_MUTABLE (bNode *, node, &localtree->nodes) {
if (node->flag & NODE_MUTED || node->type == NODE_REROUTE) {
nodeInternalRelink(localtree, node);
ntreeFreeLocalNode(localtree, node);
@@ -174,12 +170,12 @@ static void update(bNodeTree *ntree)
}
}
-static bool shader_validate_link(bNodeTree *UNUSED(ntree), bNodeLink *link)
+static bool shader_validate_link(eNodeSocketDatatype from, eNodeSocketDatatype to)
{
/* Can't connect shader into other socket types, other way around is fine
* since it will be interpreted as emission. */
- if (link->fromsock->type == SOCK_SHADER) {
- return (link->tosock->type == SOCK_SHADER);
+ if (from == SOCK_SHADER) {
+ return to == SOCK_SHADER;
}
return true;
}
@@ -221,13 +217,6 @@ void register_node_tree_type_sh(void)
/* GPU material from shader nodes */
-/* Find an output node of the shader tree.
- *
- * NOTE: it will only return output which is NOT in the group, which isn't how
- * render engines works but it's how the GPU shader compilation works. This we
- * can change in the future and make it a generic function, but for now it stays
- * private here.
- */
bNode *ntreeShaderOutputNode(bNodeTree *ntree, int target)
{
/* Make sure we only have single node tagged as output. */
@@ -887,7 +876,6 @@ void ntree_shader_tag_nodes(bNodeTree *ntree, bNode *output_node, nTreeTags *tag
nodeChainIterBackwards(ntree, output_node, ntree_tag_bsdf_cb, tags, 0);
}
-/* This one needs to work on a local tree. */
void ntreeGPUMaterialNodes(bNodeTree *localtree,
GPUMaterial *mat,
bool *has_surface_output,
diff --git a/source/blender/nodes/shader/node_shader_util.c b/source/blender/nodes/shader/node_shader_util.cc
index e1f6c135568..f2464d4c1b4 100644
--- a/source/blender/nodes/shader/node_shader_util.c
+++ b/source/blender/nodes/shader/node_shader_util.cc
@@ -25,12 +25,14 @@
#include "node_shader_util.h"
+#include "NOD_socket_search_link.hh"
+
#include "node_exec.h"
bool sh_node_poll_default(bNodeType *UNUSED(ntype), bNodeTree *ntree, const char **r_disabled_hint)
{
if (!STREQ(ntree->idname, "ShaderNodeTree")) {
- *r_disabled_hint = "Not a shader node tree";
+ *r_disabled_hint = TIP_("Not a shader node tree");
return false;
}
return true;
@@ -41,7 +43,7 @@ static bool sh_fn_poll_default(bNodeType *UNUSED(ntype),
const char **r_disabled_hint)
{
if (!STR_ELEM(ntree->idname, "ShaderNodeTree", "GeometryNodeTree")) {
- *r_disabled_hint = "Not a shader or geometry node tree";
+ *r_disabled_hint = TIP_("Not a shader or geometry node tree");
return false;
}
return true;
@@ -54,12 +56,14 @@ void sh_node_type_base(
ntype->poll = sh_node_poll_default;
ntype->insert_link = node_insert_link_default;
+ ntype->gather_link_search_ops = blender::nodes::search_link_ops_for_basic_node;
}
void sh_fn_node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag)
{
sh_node_type_base(ntype, type, name, nclass, flag);
ntype->poll = sh_fn_poll_default;
+ ntype->gather_link_search_ops = blender::nodes::search_link_ops_for_basic_node;
}
/* ****** */
@@ -107,11 +111,11 @@ void node_gpu_stack_from_data(struct GPUNodeStack *gs, int type, bNodeStack *ns)
{
memset(gs, 0, sizeof(*gs));
- if (ns == NULL) {
- /* node_get_stack() will generate NULL bNodeStack pointers
+ if (ns == nullptr) {
+ /* node_get_stack() will generate nullptr bNodeStack pointers
* for unknown/unsupported types of sockets. */
zero_v4(gs->vec);
- gs->link = NULL;
+ gs->link = nullptr;
gs->type = GPU_NONE;
gs->hasinput = false;
gs->hasoutput = false;
@@ -119,7 +123,7 @@ void node_gpu_stack_from_data(struct GPUNodeStack *gs, int type, bNodeStack *ns)
}
else {
nodestack_get_vec(gs->vec, type, ns);
- gs->link = ns->data;
+ gs->link = (GPUNodeLink *)ns->data;
if (type == SOCK_FLOAT) {
gs->type = GPU_FLOAT;
@@ -159,11 +163,9 @@ void node_data_from_gpu_stack(bNodeStack *ns, GPUNodeStack *gs)
static void gpu_stack_from_data_list(GPUNodeStack *gs, ListBase *sockets, bNodeStack **ns)
{
- bNodeSocket *sock;
int i;
-
- for (sock = sockets->first, i = 0; sock; sock = sock->next, i++) {
- node_gpu_stack_from_data(&gs[i], sock->type, ns[i]);
+ LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, sockets, i) {
+ node_gpu_stack_from_data(&gs[i], socket->type, ns[i]);
}
gs[i].end = true;
@@ -171,10 +173,8 @@ static void gpu_stack_from_data_list(GPUNodeStack *gs, ListBase *sockets, bNodeS
static void data_from_gpu_stack_list(ListBase *sockets, bNodeStack **ns, GPUNodeStack *gs)
{
- bNodeSocket *sock;
int i;
-
- for (sock = sockets->first, i = 0; sock; sock = sock->next, i++) {
+ LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, sockets, i) {
node_data_from_gpu_stack(ns[i], &gs[i]);
}
}
@@ -182,14 +182,14 @@ static void data_from_gpu_stack_list(ListBase *sockets, bNodeStack **ns, GPUNode
bNode *nodeGetActiveTexture(bNodeTree *ntree)
{
/* this is the node we texture paint and draw in textured draw */
- bNode *node, *tnode, *inactivenode = NULL, *activetexnode = NULL, *activegroup = NULL;
+ bNode *inactivenode = nullptr, *activetexnode = nullptr, *activegroup = nullptr;
bool hasgroup = false;
if (!ntree) {
- return NULL;
+ return nullptr;
}
- for (node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->flag & NODE_ACTIVE_TEXTURE) {
activetexnode = node;
/* if active we can return immediately */
@@ -212,7 +212,7 @@ bNode *nodeGetActiveTexture(bNodeTree *ntree)
/* first, check active group for textures */
if (activegroup) {
- tnode = nodeGetActiveTexture((bNodeTree *)activegroup->id);
+ bNode *tnode = nodeGetActiveTexture((bNodeTree *)activegroup->id);
/* active node takes priority, so ignore any other possible nodes here */
if (tnode) {
return tnode;
@@ -225,9 +225,9 @@ bNode *nodeGetActiveTexture(bNodeTree *ntree)
if (hasgroup) {
/* node active texture node in this tree, look inside groups */
- for (node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->type == NODE_GROUP) {
- tnode = nodeGetActiveTexture((bNodeTree *)node->id);
+ bNode *tnode = nodeGetActiveTexture((bNodeTree *)node->id);
if (tnode && ((tnode->flag & NODE_ACTIVE_TEXTURE) || !inactivenode)) {
return tnode;
}
@@ -257,7 +257,7 @@ void ntreeExecGPUNodes(bNodeTreeExec *exec, GPUMaterial *mat, bNode *output_node
do_it = false;
/* for groups, only execute outputs for edited group */
if (node->typeinfo->nclass == NODE_CLASS_OUTPUT) {
- if ((output_node != NULL) && (node == output_node)) {
+ if ((output_node != nullptr) && (node == output_node)) {
do_it = true;
}
}
@@ -281,11 +281,11 @@ void ntreeExecGPUNodes(bNodeTreeExec *exec, GPUMaterial *mat, bNode *output_node
void node_shader_gpu_bump_tex_coord(GPUMaterial *mat, bNode *node, GPUNodeLink **link)
{
if (node->branch_tag == 1) {
- /* Add one time the value fo derivative to the input vector. */
+ /* Add one time the value for derivative to the input vector. */
GPU_link(mat, "dfdx_v3", *link, link);
}
else if (node->branch_tag == 2) {
- /* Add one time the value fo derivative to the input vector. */
+ /* Add one time the value for derivative to the input vector. */
GPU_link(mat, "dfdy_v3", *link, link);
}
else {
@@ -307,7 +307,7 @@ void node_shader_gpu_tex_mapping(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *UNUSED(out))
{
- NodeTexBase *base = node->storage;
+ NodeTexBase *base = (NodeTexBase *)node->storage;
TexMapping *texmap = &base->tex_mapping;
float domin = (texmap->flag & TEXMAP_CLIP_MIN) != 0;
float domax = (texmap->flag & TEXMAP_CLIP_MAX) != 0;
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c
index 89b7164693f..b9f4106c79a 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c
@@ -169,17 +169,16 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat,
static void node_shader_update_principled(bNodeTree *ntree, bNode *node)
{
- bNodeSocket *sock;
- int distribution = node->custom1;
- int sss_method = node->custom2;
+ const int distribution = node->custom1;
+ const int sss_method = node->custom2;
- for (sock = node->inputs.first; sock; sock = sock->next) {
+ for (bNodeSocket *sock = node->inputs.first; sock; sock = sock->next) {
if (STREQ(sock->name, "Transmission Roughness")) {
nodeSetSocketAvailability(ntree, sock, distribution == SHD_GLOSSY_GGX);
}
if (STR_ELEM(sock->name, "Subsurface IOR", "Subsurface Anisotropy")) {
- nodeSetSocketAvailability(ntree, sock, sss_method == SHD_SUBSURFACE_BURLEY);
+ nodeSetSocketAvailability(ntree, sock, sss_method != SHD_SUBSURFACE_BURLEY);
}
}
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_clamp.cc b/source/blender/nodes/shader/nodes/node_shader_clamp.cc
index 57a992a4275..6c3457151e5 100644
--- a/source/blender/nodes/shader/nodes/node_shader_clamp.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_clamp.cc
@@ -75,7 +75,7 @@ static void sh_node_clamp_build_multi_function(blender::nodes::NodeMultiFunction
}
}
-void register_node_type_sh_clamp(void)
+void register_node_type_sh_clamp()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/shader/nodes/node_shader_common.c b/source/blender/nodes/shader/nodes/node_shader_common.c
index a1dac05434e..190e0cfad4c 100644
--- a/source/blender/nodes/shader/nodes/node_shader_common.c
+++ b/source/blender/nodes/shader/nodes/node_shader_common.c
@@ -232,7 +232,7 @@ void register_node_type_sh_group(void)
/* NOTE: cannot use #sh_node_type_base for node group, because it would map the node type
* to the shared #NODE_GROUP integer type id. */
- node_type_base_custom(&ntype, "ShaderNodeGroup", "Group", NODE_CLASS_GROUP, NODE_CONST_OUTPUT);
+ node_type_base_custom(&ntype, "ShaderNodeGroup", "Group", NODE_CLASS_GROUP, 0);
ntype.type = NODE_GROUP;
ntype.poll = sh_node_poll_default;
ntype.poll_instance = node_group_poll_instance;
@@ -243,7 +243,7 @@ void register_node_type_sh_group(void)
node_type_socket_templates(&ntype, NULL, NULL);
node_type_size(&ntype, 140, 60, 400);
- node_type_label(&ntype, node_group_label);
+ ntype.labelfunc = node_group_label;
node_type_group_update(&ntype, node_group_update);
node_type_exec(&ntype, group_initexec, group_freeexec, group_execute);
node_type_gpu(&ntype, gpu_group_execute);
diff --git a/source/blender/nodes/shader/nodes/node_shader_curves.cc b/source/blender/nodes/shader/nodes/node_shader_curves.cc
index 7ce5150bf85..09bbf3d851c 100644
--- a/source/blender/nodes/shader/nodes/node_shader_curves.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_curves.cc
@@ -152,7 +152,7 @@ static void sh_node_curve_vec_build_multi_function(
builder.construct_and_set_matching_fn<CurveVecFunction>(*cumap);
}
-void register_node_type_sh_curve_vec(void)
+void register_node_type_sh_curve_vec()
{
static bNodeType ntype;
@@ -329,7 +329,7 @@ static void sh_node_curve_rgb_build_multi_function(
builder.construct_and_set_matching_fn<CurveRGBFunction>(*cumap);
}
-void register_node_type_sh_curve_rgb(void)
+void register_node_type_sh_curve_rgb()
{
static bNodeType ntype;
@@ -473,7 +473,7 @@ static void sh_node_curve_float_build_multi_function(
builder.construct_and_set_matching_fn<CurveFloatFunction>(*cumap);
}
-void register_node_type_sh_curve_float(void)
+void register_node_type_sh_curve_float()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/shader/nodes/node_shader_map_range.cc b/source/blender/nodes/shader/nodes/node_shader_map_range.cc
index e55963eb500..615ae276eb4 100644
--- a/source/blender/nodes/shader/nodes/node_shader_map_range.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_map_range.cc
@@ -21,10 +21,14 @@
* \ingroup shdnodes
*/
+#include <algorithm>
+
#include "node_shader_util.h"
#include "BLI_math_base_safe.h"
+NODE_STORAGE_FUNCS(NodeMapRange)
+
namespace blender::nodes {
static void sh_node_map_range_declare(NodeDeclarationBuilder &b)
@@ -36,34 +40,80 @@ static void sh_node_map_range_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Float>(N_("To Min")).min(-10000.0f).max(10000.0f);
b.add_input<decl::Float>(N_("To Max")).min(-10000.0f).max(10000.0f).default_value(1.0f);
b.add_input<decl::Float>(N_("Steps")).min(-10000.0f).max(10000.0f).default_value(4.0f);
+ b.add_input<decl::Vector>(N_("Vector")).min(0.0f).max(1.0f).hide_value();
+ b.add_input<decl::Vector>(N_("From Min"), "From_Min_FLOAT3");
+ b.add_input<decl::Vector>(N_("From Max"), "From_Max_FLOAT3").default_value(float3(1.0f));
+ b.add_input<decl::Vector>(N_("To Min"), "To_Min_FLOAT3");
+ b.add_input<decl::Vector>(N_("To Max"), "To_Max_FLOAT3").default_value(float3(1.0f));
+ b.add_input<decl::Vector>(N_("Steps"), "Steps_FLOAT3").default_value(float3(4.0f));
b.add_output<decl::Float>(N_("Result"));
+ b.add_output<decl::Vector>(N_("Vector"));
};
} // namespace blender::nodes
static void node_shader_update_map_range(bNodeTree *ntree, bNode *node)
{
- bNodeSocket *sockSteps = nodeFindSocket(node, SOCK_IN, "Steps");
- nodeSetSocketAvailability(ntree, sockSteps, node->custom2 == NODE_MAP_RANGE_STEPPED);
+ const NodeMapRange &storage = node_storage(*node);
+ const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
+ const int type = (data_type == CD_PROP_FLOAT) ? SOCK_FLOAT : SOCK_VECTOR;
+
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
+ nodeSetSocketAvailability(ntree, socket, socket->type == type);
+ }
+
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) {
+ nodeSetSocketAvailability(ntree, socket, socket->type == type);
+ }
+
+ if (storage.interpolation_type != NODE_MAP_RANGE_STEPPED) {
+ if (type == SOCK_FLOAT) {
+ bNodeSocket *sockSteps = (bNodeSocket *)BLI_findlink(&node->inputs, 5);
+ nodeSetSocketAvailability(ntree, sockSteps, false);
+ }
+ else {
+ bNodeSocket *sockSteps = (bNodeSocket *)BLI_findlink(&node->inputs, 11);
+ nodeSetSocketAvailability(ntree, sockSteps, false);
+ }
+ }
}
static void node_shader_init_map_range(bNodeTree *UNUSED(ntree), bNode *node)
{
+ NodeMapRange *data = (NodeMapRange *)MEM_callocN(sizeof(NodeMapRange), __func__);
+ data->clamp = 1;
+ data->data_type = CD_PROP_FLOAT;
+ data->interpolation_type = NODE_MAP_RANGE_LINEAR;
node->custom1 = true; /* use_clamp */
node->custom2 = NODE_MAP_RANGE_LINEAR; /* interpolation */
+ node->storage = data;
}
-static const char *gpu_shader_get_name(int mode)
+static const char *gpu_shader_get_name(int mode, bool use_vector)
{
- switch (mode) {
- case NODE_MAP_RANGE_LINEAR:
- return "map_range_linear";
- case NODE_MAP_RANGE_STEPPED:
- return "map_range_stepped";
- case NODE_MAP_RANGE_SMOOTHSTEP:
- return "map_range_smoothstep";
- case NODE_MAP_RANGE_SMOOTHERSTEP:
- return "map_range_smootherstep";
+ if (use_vector) {
+ switch (mode) {
+ case NODE_MAP_RANGE_LINEAR:
+ return "vector_map_range_linear";
+ case NODE_MAP_RANGE_STEPPED:
+ return "vector_map_range_stepped";
+ case NODE_MAP_RANGE_SMOOTHSTEP:
+ return "vector_map_range_smoothstep";
+ case NODE_MAP_RANGE_SMOOTHERSTEP:
+ return "vector_map_range_smootherstep";
+ }
+ }
+ else {
+ switch (mode) {
+ case NODE_MAP_RANGE_LINEAR:
+ return "map_range_linear";
+ case NODE_MAP_RANGE_STEPPED:
+ return "map_range_stepped";
+ case NODE_MAP_RANGE_SMOOTHSTEP:
+ return "map_range_smoothstep";
+ case NODE_MAP_RANGE_SMOOTHERSTEP:
+ return "map_range_smootherstep";
+ }
}
return nullptr;
@@ -75,22 +125,207 @@ static int gpu_shader_map_range(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
- const char *name = gpu_shader_get_name(node->custom2);
-
+ const NodeMapRange &storage = node_storage(*node);
+ bool use_vector = (storage.data_type == CD_PROP_FLOAT3);
+ const char *name = gpu_shader_get_name(storage.interpolation_type, use_vector);
+ float clamp = storage.clamp ? 1.0f : 0.0f;
int ret = 0;
if (name != nullptr) {
- ret = GPU_stack_link(mat, node, name, in, out);
+ ret = GPU_stack_link(mat, node, name, in, out, GPU_constant(&clamp));
}
else {
- ret = GPU_stack_link(mat, node, "map_range_linear", in, out);
+ ret = GPU_stack_link(mat, node, "map_range_linear", in, out, GPU_constant(&clamp));
}
- if (ret && node->custom1 &&
- !ELEM(node->custom2, NODE_MAP_RANGE_SMOOTHSTEP, NODE_MAP_RANGE_SMOOTHERSTEP)) {
+ if (ret && storage.clamp && !use_vector &&
+ !ELEM(storage.interpolation_type, NODE_MAP_RANGE_SMOOTHSTEP, NODE_MAP_RANGE_SMOOTHERSTEP)) {
GPU_link(mat, "clamp_range", out[0].link, in[3].link, in[4].link, &out[0].link);
}
return ret;
}
+namespace blender::nodes {
+
+static inline float clamp_range(const float value, const float min, const float max)
+{
+ return (min > max) ? std::clamp(value, max, min) : std::clamp(value, min, max);
+}
+
+static float3 clamp_range(const float3 value, const float3 min, const float3 max)
+{
+ return float3(clamp_range(value.x, min.x, max.x),
+ clamp_range(value.y, min.y, max.y),
+ clamp_range(value.z, min.z, max.z));
+}
+
+static void map_range_vector_signature(blender::fn::MFSignatureBuilder *signature, bool use_steps)
+{
+ signature->single_input<float3>("Vector");
+ signature->single_input<float3>("From Min");
+ signature->single_input<float3>("From Max");
+ signature->single_input<float3>("To Min");
+ signature->single_input<float3>("To Max");
+ if (use_steps) {
+ signature->single_input<float3>("Steps");
+ }
+ signature->single_output<float3>("Vector");
+}
+
+class MapRangeVectorFunction : public blender::fn::MultiFunction {
+ private:
+ bool clamp_;
+
+ public:
+ MapRangeVectorFunction(bool clamp) : clamp_(clamp)
+ {
+ static blender::fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static blender::fn::MFSignature create_signature()
+ {
+ blender::fn::MFSignatureBuilder signature{"Vector Map Range"};
+ map_range_vector_signature(&signature, false);
+ return signature.build();
+ }
+
+ void call(blender::IndexMask mask,
+ blender::fn::MFParams params,
+ blender::fn::MFContext UNUSED(context)) const override
+ {
+ const blender::VArray<float3> &values = params.readonly_single_input<float3>(0, "Vector");
+ const blender::VArray<float3> &from_min = params.readonly_single_input<float3>(1, "From Min");
+ const blender::VArray<float3> &from_max = params.readonly_single_input<float3>(2, "From Max");
+ const blender::VArray<float3> &to_min = params.readonly_single_input<float3>(3, "To Min");
+ const blender::VArray<float3> &to_max = params.readonly_single_input<float3>(4, "To Max");
+ blender::MutableSpan<float3> results = params.uninitialized_single_output<float3>(5, "Vector");
+
+ for (int64_t i : mask) {
+ float3 factor = float3::safe_divide(values[i] - from_min[i], from_max[i] - from_min[i]);
+ results[i] = factor * (to_max[i] - to_min[i]) + to_min[i];
+ }
+
+ if (clamp_) {
+ for (int64_t i : mask) {
+ results[i] = clamp_range(results[i], to_min[i], to_max[i]);
+ }
+ }
+ }
+};
+
+class MapRangeSteppedVectorFunction : public blender::fn::MultiFunction {
+ private:
+ bool clamp_;
+
+ public:
+ MapRangeSteppedVectorFunction(bool clamp) : clamp_(clamp)
+ {
+ static blender::fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static blender::fn::MFSignature create_signature()
+ {
+ blender::fn::MFSignatureBuilder signature{"Vector Map Range Stepped"};
+ map_range_vector_signature(&signature, true);
+ return signature.build();
+ }
+
+ void call(blender::IndexMask mask,
+ blender::fn::MFParams params,
+ blender::fn::MFContext UNUSED(context)) const override
+ {
+ const blender::VArray<float3> &values = params.readonly_single_input<float3>(0, "Vector");
+ const blender::VArray<float3> &from_min = params.readonly_single_input<float3>(1, "From Min");
+ const blender::VArray<float3> &from_max = params.readonly_single_input<float3>(2, "From Max");
+ const blender::VArray<float3> &to_min = params.readonly_single_input<float3>(3, "To Min");
+ const blender::VArray<float3> &to_max = params.readonly_single_input<float3>(4, "To Max");
+ const blender::VArray<float3> &steps = params.readonly_single_input<float3>(5, "Steps");
+ blender::MutableSpan<float3> results = params.uninitialized_single_output<float3>(6, "Vector");
+
+ for (int64_t i : mask) {
+ float3 factor = float3::safe_divide(values[i] - from_min[i], from_max[i] - from_min[i]);
+ factor = float3::safe_divide(float3::floor(factor * (steps[i] + 1.0f)), steps[i]);
+ results[i] = factor * (to_max[i] - to_min[i]) + to_min[i];
+ }
+
+ if (clamp_) {
+ for (int64_t i : mask) {
+ results[i] = clamp_range(results[i], to_min[i], to_max[i]);
+ }
+ }
+ }
+};
+
+class MapRangeSmoothstepVectorFunction : public blender::fn::MultiFunction {
+ public:
+ MapRangeSmoothstepVectorFunction()
+ {
+ static blender::fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static blender::fn::MFSignature create_signature()
+ {
+ blender::fn::MFSignatureBuilder signature{"Vector Map Range Smoothstep"};
+ map_range_vector_signature(&signature, false);
+ return signature.build();
+ }
+
+ void call(blender::IndexMask mask,
+ blender::fn::MFParams params,
+ blender::fn::MFContext UNUSED(context)) const override
+ {
+ const blender::VArray<float3> &values = params.readonly_single_input<float3>(0, "Vector");
+ const blender::VArray<float3> &from_min = params.readonly_single_input<float3>(1, "From Min");
+ const blender::VArray<float3> &from_max = params.readonly_single_input<float3>(2, "From Max");
+ const blender::VArray<float3> &to_min = params.readonly_single_input<float3>(3, "To Min");
+ const blender::VArray<float3> &to_max = params.readonly_single_input<float3>(4, "To Max");
+ blender::MutableSpan<float3> results = params.uninitialized_single_output<float3>(5, "Vector");
+
+ for (int64_t i : mask) {
+ float3 factor = float3::safe_divide(values[i] - from_min[i], from_max[i] - from_min[i]);
+ clamp_v3(factor, 0.0f, 1.0f);
+ factor = (float3(3.0f) - 2.0f * factor) * (factor * factor);
+ results[i] = factor * (to_max[i] - to_min[i]) + to_min[i];
+ }
+ }
+};
+
+class MapRangeSmootherstepVectorFunction : public blender::fn::MultiFunction {
+ public:
+ MapRangeSmootherstepVectorFunction()
+ {
+ static blender::fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static blender::fn::MFSignature create_signature()
+ {
+ blender::fn::MFSignatureBuilder signature{"Vector Map Range Smoothstep"};
+ map_range_vector_signature(&signature, false);
+ return signature.build();
+ }
+
+ void call(blender::IndexMask mask,
+ blender::fn::MFParams params,
+ blender::fn::MFContext UNUSED(context)) const override
+ {
+ const blender::VArray<float3> &values = params.readonly_single_input<float3>(0, "Vector");
+ const blender::VArray<float3> &from_min = params.readonly_single_input<float3>(1, "From Min");
+ const blender::VArray<float3> &from_max = params.readonly_single_input<float3>(2, "From Max");
+ const blender::VArray<float3> &to_min = params.readonly_single_input<float3>(3, "To Min");
+ const blender::VArray<float3> &to_max = params.readonly_single_input<float3>(4, "To Max");
+ blender::MutableSpan<float3> results = params.uninitialized_single_output<float3>(5, "Vector");
+
+ for (int64_t i : mask) {
+ float3 factor = float3::safe_divide(values[i] - from_min[i], from_max[i] - from_min[i]);
+ clamp_v3(factor, 0.0f, 1.0f);
+ factor = factor * factor * factor * (factor * (factor * 6.0f - 15.0f) + 10.0f);
+ results[i] = factor * (to_max[i] - to_min[i]) + to_min[i];
+ }
+ }
+};
+
static void map_range_signature(blender::fn::MFSignatureBuilder *signature, bool use_steps)
{
signature->single_input<float>("Value");
@@ -140,8 +375,7 @@ class MapRangeFunction : public blender::fn::MultiFunction {
if (clamp_) {
for (int64_t i : mask) {
- results[i] = (to_min[i] > to_max[i]) ? clamp_f(results[i], to_max[i], to_min[i]) :
- clamp_f(results[i], to_min[i], to_max[i]);
+ results[i] = clamp_range(results[i], to_min[i], to_max[i]);
}
}
}
@@ -185,8 +419,7 @@ class MapRangeSteppedFunction : public blender::fn::MultiFunction {
if (clamp_) {
for (int64_t i : mask) {
- results[i] = (to_min[i] > to_max[i]) ? clamp_f(results[i], to_max[i], to_min[i]) :
- clamp_f(results[i], to_min[i], to_max[i]);
+ results[i] = clamp_range(results[i], to_min[i], to_max[i]);
}
}
}
@@ -265,58 +498,104 @@ class MapRangeSmootherstepFunction : public blender::fn::MultiFunction {
static void sh_node_map_range_build_multi_function(
blender::nodes::NodeMultiFunctionBuilder &builder)
{
- bNode &bnode = builder.node();
- bool clamp = bnode.custom1 != 0;
- int interpolation_type = bnode.custom2;
-
- switch (interpolation_type) {
- case NODE_MAP_RANGE_LINEAR: {
- if (clamp) {
- static MapRangeFunction fn_with_clamp{true};
- builder.set_matching_fn(fn_with_clamp);
- }
- else {
- static MapRangeFunction fn_without_clamp{false};
- builder.set_matching_fn(fn_without_clamp);
+ const NodeMapRange &storage = node_storage(builder.node());
+ bool clamp = storage.clamp != 0;
+ int interpolation_type = storage.interpolation_type;
+
+ switch (storage.data_type) {
+ case CD_PROP_FLOAT3:
+ switch (interpolation_type) {
+ case NODE_MAP_RANGE_LINEAR: {
+ if (clamp) {
+ static MapRangeVectorFunction fn_with_clamp{true};
+ builder.set_matching_fn(fn_with_clamp);
+ }
+ else {
+ static MapRangeVectorFunction fn_without_clamp{false};
+ builder.set_matching_fn(fn_without_clamp);
+ }
+ break;
+ }
+ case NODE_MAP_RANGE_STEPPED: {
+ if (clamp) {
+ static MapRangeSteppedVectorFunction fn_stepped_with_clamp{true};
+ builder.set_matching_fn(fn_stepped_with_clamp);
+ }
+ else {
+ static MapRangeSteppedVectorFunction fn_stepped_without_clamp{false};
+ builder.set_matching_fn(fn_stepped_without_clamp);
+ }
+ break;
+ }
+ case NODE_MAP_RANGE_SMOOTHSTEP: {
+ static MapRangeSmoothstepVectorFunction smoothstep;
+ builder.set_matching_fn(smoothstep);
+ break;
+ }
+ case NODE_MAP_RANGE_SMOOTHERSTEP: {
+ static MapRangeSmootherstepVectorFunction smootherstep;
+ builder.set_matching_fn(smootherstep);
+ break;
+ }
+ default:
+ break;
}
break;
- }
- case NODE_MAP_RANGE_STEPPED: {
- if (clamp) {
- static MapRangeSteppedFunction fn_stepped_with_clamp{true};
- builder.set_matching_fn(fn_stepped_with_clamp);
- }
- else {
- static MapRangeSteppedFunction fn_stepped_without_clamp{false};
- builder.set_matching_fn(fn_stepped_without_clamp);
+ case CD_PROP_FLOAT:
+ switch (interpolation_type) {
+ case NODE_MAP_RANGE_LINEAR: {
+ if (clamp) {
+ static MapRangeFunction fn_with_clamp{true};
+ builder.set_matching_fn(fn_with_clamp);
+ }
+ else {
+ static MapRangeFunction fn_without_clamp{false};
+ builder.set_matching_fn(fn_without_clamp);
+ }
+ break;
+ }
+ case NODE_MAP_RANGE_STEPPED: {
+ if (clamp) {
+ static MapRangeSteppedFunction fn_stepped_with_clamp{true};
+ builder.set_matching_fn(fn_stepped_with_clamp);
+ }
+ else {
+ static MapRangeSteppedFunction fn_stepped_without_clamp{false};
+ builder.set_matching_fn(fn_stepped_without_clamp);
+ }
+ break;
+ }
+ case NODE_MAP_RANGE_SMOOTHSTEP: {
+ static MapRangeSmoothstepFunction smoothstep;
+ builder.set_matching_fn(smoothstep);
+ break;
+ }
+ case NODE_MAP_RANGE_SMOOTHERSTEP: {
+ static MapRangeSmootherstepFunction smootherstep;
+ builder.set_matching_fn(smootherstep);
+ break;
+ }
+ default:
+ break;
}
break;
- }
- case NODE_MAP_RANGE_SMOOTHSTEP: {
- static MapRangeSmoothstepFunction smoothstep;
- builder.set_matching_fn(smoothstep);
- break;
- }
- case NODE_MAP_RANGE_SMOOTHERSTEP: {
- static MapRangeSmootherstepFunction smootherstep;
- builder.set_matching_fn(smootherstep);
- break;
- }
- default:
- break;
}
}
-void register_node_type_sh_map_range(void)
+} // namespace blender::nodes
+
+void register_node_type_sh_map_range()
{
static bNodeType ntype;
sh_fn_node_type_base(&ntype, SH_NODE_MAP_RANGE, "Map Range", NODE_CLASS_CONVERTER, 0);
ntype.declare = blender::nodes::sh_node_map_range_declare;
node_type_init(&ntype, node_shader_init_map_range);
+ node_type_storage(
+ &ntype, "NodeMapRange", node_free_standard_storage, node_copy_standard_storage);
node_type_update(&ntype, node_shader_update_map_range);
node_type_gpu(&ntype, gpu_shader_map_range);
- ntype.build_multi_function = sh_node_map_range_build_multi_function;
+ ntype.build_multi_function = blender::nodes::sh_node_map_range_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_math.cc b/source/blender/nodes/shader/nodes/node_shader_math.cc
index 284a5f1189f..da237be273f 100644
--- a/source/blender/nodes/shader/nodes/node_shader_math.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_math.cc
@@ -24,6 +24,7 @@
#include "node_shader_util.h"
#include "NOD_math_functions.hh"
+#include "NOD_socket_search_link.hh"
/* **************** SCALAR MATH ******************** */
@@ -44,6 +45,18 @@ static void sh_node_math_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Float>(N_("Value"));
};
+static void sh_node_math_gather_link_searches(GatherLinkSearchOpParams &params)
+{
+ /* For now, do something very basic (only exposing "Add", and a single "Value" socket). */
+ if (params.node_tree().typeinfo->validate_link(
+ static_cast<eNodeSocketDatatype>(params.other_socket().type), SOCK_FLOAT)) {
+ params.add_item(IFACE_("Value"), [](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("ShaderNodeMath");
+ params.update_and_connect_available_socket(node, "Value");
+ });
+ }
+}
+
} // namespace blender::nodes
static const char *gpu_shader_get_name(int mode)
@@ -88,7 +101,8 @@ static const blender::fn::MultiFunction *get_base_multi_function(bNode &node)
blender::nodes::try_dispatch_float_math_fl_to_fl(
mode, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) {
- static blender::fn::CustomMF_SI_SO<float, float> fn{info.title_case_name, function};
+ static blender::fn::CustomMF_SI_SO<float, float> fn{info.title_case_name.c_str(),
+ function};
base_fn = &fn;
});
if (base_fn != nullptr) {
@@ -97,7 +111,7 @@ static const blender::fn::MultiFunction *get_base_multi_function(bNode &node)
blender::nodes::try_dispatch_float_math_fl_fl_to_fl(
mode, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) {
- static blender::fn::CustomMF_SI_SI_SO<float, float, float> fn{info.title_case_name,
+ static blender::fn::CustomMF_SI_SI_SO<float, float, float> fn{info.title_case_name.c_str(),
function};
base_fn = &fn;
});
@@ -108,7 +122,7 @@ static const blender::fn::MultiFunction *get_base_multi_function(bNode &node)
blender::nodes::try_dispatch_float_math_fl_fl_fl_to_fl(
mode, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) {
static blender::fn::CustomMF_SI_SI_SI_SO<float, float, float, float> fn{
- info.title_case_name, function};
+ info.title_case_name.c_str(), function};
base_fn = &fn;
});
if (base_fn != nullptr) {
@@ -160,16 +174,17 @@ static void sh_node_math_build_multi_function(blender::nodes::NodeMultiFunctionB
}
}
-void register_node_type_sh_math(void)
+void register_node_type_sh_math()
{
static bNodeType ntype;
sh_fn_node_type_base(&ntype, SH_NODE_MATH, "Math", NODE_CLASS_CONVERTER, 0);
ntype.declare = blender::nodes::sh_node_math_declare;
- node_type_label(&ntype, node_math_label);
+ ntype.labelfunc = node_math_label;
node_type_gpu(&ntype, gpu_shader_math);
node_type_update(&ntype, node_math_update);
ntype.build_multi_function = sh_node_math_build_multi_function;
+ ntype.gather_link_search_ops = blender::nodes::sh_node_math_gather_link_searches;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_mixRgb.cc b/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc
index 06fafff578e..b89e0527eed 100644
--- a/source/blender/nodes/shader/nodes/node_shader_mixRgb.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc
@@ -183,13 +183,13 @@ static void sh_node_mix_rgb_build_multi_function(blender::nodes::NodeMultiFuncti
builder.construct_and_set_matching_fn<MixRGBFunction>(clamp, mix_type);
}
-void register_node_type_sh_mix_rgb(void)
+void register_node_type_sh_mix_rgb()
{
static bNodeType ntype;
sh_fn_node_type_base(&ntype, SH_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR, 0);
ntype.declare = blender::nodes::sh_node_mix_rgb_declare;
- node_type_label(&ntype, node_blend_label);
+ ntype.labelfunc = node_blend_label;
node_type_exec(&ntype, nullptr, nullptr, node_shader_exec_mix_rgb);
node_type_gpu(&ntype, gpu_shader_mix_rgb);
ntype.build_multi_function = sh_node_mix_rgb_build_multi_function;
diff --git a/source/blender/nodes/shader/nodes/node_shader_valToRgb.cc b/source/blender/nodes/shader/nodes/node_shader_rgb_to_bw.cc
index e4f1b2c76f0..e3808985c0e 100644
--- a/source/blender/nodes/shader/nodes/node_shader_valToRgb.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_rgb_to_bw.cc
@@ -172,7 +172,7 @@ static void sh_node_valtorgb_build_multi_function(
builder.construct_and_set_matching_fn<ColorBandFunction>(*color_band);
}
-void register_node_type_sh_valtorgb(void)
+void register_node_type_sh_valtorgb()
{
static bNodeType ntype;
@@ -222,7 +222,7 @@ static int gpu_shader_rgbtobw(GPUMaterial *mat,
return GPU_stack_link(mat, node, "rgbtobw", in, out);
}
-void register_node_type_sh_rgbtobw(void)
+void register_node_type_sh_rgbtobw()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcombHSV.c b/source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.c
index dfecb830b35..dfecb830b35 100644
--- a/source/blender/nodes/shader/nodes/node_shader_sepcombHSV.c
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.c
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.cc b/source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc
index 08a9e01786e..4984a530d8b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc
@@ -103,7 +103,7 @@ static void sh_node_seprgb_build_multi_function(blender::nodes::NodeMultiFunctio
builder.set_matching_fn(fn);
}
-void register_node_type_sh_seprgb(void)
+void register_node_type_sh_seprgb()
{
static bNodeType ntype;
@@ -163,7 +163,7 @@ static void sh_node_combrgb_build_multi_function(blender::nodes::NodeMultiFuncti
builder.set_matching_fn(fn);
}
-void register_node_type_sh_combrgb(void)
+void register_node_type_sh_combrgb()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.cc b/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc
index 1bbfa629462..a414630829e 100644
--- a/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc
@@ -88,7 +88,7 @@ static void sh_node_sepxyz_build_multi_function(blender::nodes::NodeMultiFunctio
builder.set_matching_fn(separate_fn);
}
-void register_node_type_sh_sepxyz(void)
+void register_node_type_sh_sepxyz()
{
static bNodeType ntype;
@@ -129,7 +129,7 @@ static void sh_node_combxyz_build_multi_function(blender::nodes::NodeMultiFuncti
builder.set_matching_fn(fn);
}
-void register_node_type_sh_combxyz(void)
+void register_node_type_sh_combxyz()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/shader/nodes/node_shader_shaderToRgb.c b/source/blender/nodes/shader/nodes/node_shader_shader_to_rgb.c
index 25c30aa4081..25c30aa4081 100644
--- a/source/blender/nodes/shader/nodes/node_shader_shaderToRgb.c
+++ b/source/blender/nodes/shader/nodes/node_shader_shader_to_rgb.c
diff --git a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c
index e917858e0f2..85a4a6aa425 100644
--- a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c
+++ b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c
@@ -67,6 +67,17 @@ static int node_shader_gpu_subsurface_scattering(GPUMaterial *mat,
mat, node, "node_subsurface_scattering", in, out, GPU_constant(&node->sss_id));
}
+static void node_shader_update_subsurface_scattering(bNodeTree *ntree, bNode *node)
+{
+ const int sss_method = node->custom1;
+
+ for (bNodeSocket *sock = node->inputs.first; sock; sock = sock->next) {
+ if (STR_ELEM(sock->name, "IOR", "Anisotropy")) {
+ nodeSetSocketAvailability(ntree, sock, sss_method != SHD_SUBSURFACE_BURLEY);
+ }
+ }
+}
+
/* node type definition */
void register_node_type_sh_subsurface_scattering(void)
{
@@ -80,6 +91,7 @@ void register_node_type_sh_subsurface_scattering(void)
node_type_init(&ntype, node_shader_init_subsurface_scattering);
node_type_storage(&ntype, "", NULL, NULL);
node_type_gpu(&ntype, node_shader_gpu_subsurface_scattering);
+ node_type_update(&ntype, node_shader_update_subsurface_scattering);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_brick.cc b/source/blender/nodes/shader/nodes/node_shader_tex_brick.cc
index b840bd75e42..7925c96db3d 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_brick.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_brick.cc
@@ -268,7 +268,7 @@ static void sh_node_brick_build_multi_function(blender::nodes::NodeMultiFunction
} // namespace blender::nodes
-void register_node_type_sh_tex_brick(void)
+void register_node_type_sh_tex_brick()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_checker.cc b/source/blender/nodes/shader/nodes/node_shader_tex_checker.cc
index 7c1223a6a32..6d2d199aec8 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_checker.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_checker.cc
@@ -123,7 +123,7 @@ static void sh_node_tex_checker_build_multi_function(
} // namespace blender::nodes
-void register_node_type_sh_tex_checker(void)
+void register_node_type_sh_tex_checker()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
index 26a1db1f3a6..ff08961b3e9 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
@@ -143,7 +143,7 @@ void register_node_type_sh_tex_environment(void)
node_type_storage(
&ntype, "NodeTexEnvironment", node_free_standard_storage, node_copy_standard_storage);
node_type_gpu(&ntype, node_shader_gpu_tex_environment);
- node_type_label(&ntype, node_image_label);
+ ntype.labelfunc = node_image_label;
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc b/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc
index 33832c42b3c..48199968547 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc
@@ -160,7 +160,7 @@ static void sh_node_gradient_tex_build_multi_function(
} // namespace blender::nodes
-void register_node_type_sh_tex_gradient(void)
+void register_node_type_sh_tex_gradient()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_image.cc b/source/blender/nodes/shader/nodes/node_shader_tex_image.cc
index f20fc85cbe0..d139707c6d7 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_image.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.cc
@@ -174,7 +174,7 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat,
}
/* node type definition */
-void register_node_type_sh_tex_image(void)
+void register_node_type_sh_tex_image()
{
static bNodeType ntype;
@@ -184,7 +184,7 @@ void register_node_type_sh_tex_image(void)
node_type_storage(
&ntype, "NodeTexImage", node_free_standard_storage, node_copy_standard_storage);
node_type_gpu(&ntype, node_shader_gpu_tex_image);
- node_type_label(&ntype, node_image_label);
+ ntype.labelfunc = node_image_label;
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_magic.cc b/source/blender/nodes/shader/nodes/node_shader_tex_magic.cc
index 62e68d53d03..9bd5c335cee 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_magic.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_magic.cc
@@ -181,7 +181,7 @@ static void sh_node_magic_tex_build_multi_function(
} // namespace blender::nodes
-void register_node_type_sh_tex_magic(void)
+void register_node_type_sh_tex_magic()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc
index e426d9cc49c..97ac199bc03 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc
@@ -21,13 +21,18 @@
#include "BLI_noise.hh"
+NODE_STORAGE_FUNCS(NodeTexMusgrave)
+
namespace blender::nodes {
static void sh_node_tex_musgrave_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
b.add_input<decl::Vector>(N_("Vector")).hide_value().implicit_field();
- b.add_input<decl::Float>(N_("W")).min(-1000.0f).max(1000.0f);
+ b.add_input<decl::Float>(N_("W")).min(-1000.0f).max(1000.0f).make_available([](bNode &node) {
+ /* Default to 1 instead of 4, because it is much faster. */
+ node_storage(node).dimensions = 1;
+ });
b.add_input<decl::Float>(N_("Scale")).min(-1000.0f).max(1000.0f).default_value(5.0f);
b.add_input<decl::Float>(N_("Detail")).min(0.0f).max(15.0f).default_value(2.0f);
b.add_input<decl::Float>(N_("Dimension")).min(0.0f).max(1000.0f).default_value(2.0f);
@@ -106,23 +111,23 @@ static int node_shader_gpu_tex_musgrave(GPUMaterial *mat,
static void node_shader_update_tex_musgrave(bNodeTree *ntree, bNode *node)
{
- NodeTexMusgrave *tex = (NodeTexMusgrave *)node->storage;
+ const NodeTexMusgrave &storage = node_storage(*node);
bNodeSocket *inVectorSock = nodeFindSocket(node, SOCK_IN, "Vector");
bNodeSocket *inWSock = nodeFindSocket(node, SOCK_IN, "W");
bNodeSocket *inOffsetSock = nodeFindSocket(node, SOCK_IN, "Offset");
bNodeSocket *inGainSock = nodeFindSocket(node, SOCK_IN, "Gain");
- nodeSetSocketAvailability(ntree, inVectorSock, tex->dimensions != 1);
- nodeSetSocketAvailability(ntree, inWSock, tex->dimensions == 1 || tex->dimensions == 4);
+ nodeSetSocketAvailability(ntree, inVectorSock, storage.dimensions != 1);
+ nodeSetSocketAvailability(ntree, inWSock, storage.dimensions == 1 || storage.dimensions == 4);
nodeSetSocketAvailability(ntree,
inOffsetSock,
- tex->musgrave_type != SHD_MUSGRAVE_MULTIFRACTAL &&
- tex->musgrave_type != SHD_MUSGRAVE_FBM);
+ storage.musgrave_type != SHD_MUSGRAVE_MULTIFRACTAL &&
+ storage.musgrave_type != SHD_MUSGRAVE_FBM);
nodeSetSocketAvailability(ntree,
inGainSock,
- tex->musgrave_type == SHD_MUSGRAVE_HYBRID_MULTIFRACTAL ||
- tex->musgrave_type == SHD_MUSGRAVE_RIDGED_MULTIFRACTAL);
+ storage.musgrave_type == SHD_MUSGRAVE_HYBRID_MULTIFRACTAL ||
+ storage.musgrave_type == SHD_MUSGRAVE_RIDGED_MULTIFRACTAL);
bNodeSocket *outFacSock = nodeFindSocket(node, SOCK_OUT, "Fac");
node_sock_label(outFacSock, "Height");
@@ -531,7 +536,7 @@ static void sh_node_musgrave_build_multi_function(
} // namespace blender::nodes
-void register_node_type_sh_tex_musgrave(void)
+void register_node_type_sh_tex_musgrave()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc b/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc
index 7dd2695ecf7..d7f21853a01 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc
@@ -21,13 +21,18 @@
#include "BLI_noise.hh"
+NODE_STORAGE_FUNCS(NodeTexNoise)
+
namespace blender::nodes {
static void sh_node_tex_noise_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
b.add_input<decl::Vector>(N_("Vector")).implicit_field();
- b.add_input<decl::Float>(N_("W")).min(-1000.0f).max(1000.0f);
+ b.add_input<decl::Float>(N_("W")).min(-1000.0f).max(1000.0f).make_available([](bNode &node) {
+ /* Default to 1 instead of 4, because it is much faster. */
+ node_storage(node).dimensions = 1;
+ });
b.add_input<decl::Float>(N_("Scale")).min(-1000.0f).max(1000.0f).default_value(5.0f);
b.add_input<decl::Float>(N_("Detail")).min(0.0f).max(15.0f).default_value(2.0f);
b.add_input<decl::Float>(N_("Roughness"))
@@ -71,8 +76,8 @@ static int node_shader_gpu_tex_noise(GPUMaterial *mat,
node_shader_gpu_default_tex_coord(mat, node, &in[0].link);
node_shader_gpu_tex_mapping(mat, node, in, out);
- NodeTexNoise *tex = (NodeTexNoise *)node->storage;
- const char *name = gpu_shader_get_name(tex->dimensions);
+ const NodeTexNoise &storage = node_storage(*node);
+ const char *name = gpu_shader_get_name(storage.dimensions);
return GPU_stack_link(mat, node, name, in, out);
}
@@ -81,9 +86,9 @@ static void node_shader_update_tex_noise(bNodeTree *ntree, bNode *node)
bNodeSocket *sockVector = nodeFindSocket(node, SOCK_IN, "Vector");
bNodeSocket *sockW = nodeFindSocket(node, SOCK_IN, "W");
- NodeTexNoise *tex = (NodeTexNoise *)node->storage;
- nodeSetSocketAvailability(ntree, sockVector, tex->dimensions != 1);
- nodeSetSocketAvailability(ntree, sockW, tex->dimensions == 1 || tex->dimensions == 4);
+ const NodeTexNoise &storage = node_storage(*node);
+ nodeSetSocketAvailability(ntree, sockVector, storage.dimensions != 1);
+ nodeSetSocketAvailability(ntree, sockW, storage.dimensions == 1 || storage.dimensions == 4);
}
namespace blender::nodes {
@@ -229,19 +234,26 @@ class NoiseFunction : public fn::MultiFunction {
}
}
}
+
+ ExecutionHints get_execution_hints() const override
+ {
+ ExecutionHints hints;
+ hints.allocates_array = false;
+ hints.min_grain_size = 100;
+ return hints;
+ }
};
static void sh_node_noise_build_multi_function(blender::nodes::NodeMultiFunctionBuilder &builder)
{
- bNode &node = builder.node();
- NodeTexNoise *tex = (NodeTexNoise *)node.storage;
- builder.construct_and_set_matching_fn<NoiseFunction>(tex->dimensions);
+ const NodeTexNoise &storage = node_storage(builder.node());
+ builder.construct_and_set_matching_fn<NoiseFunction>(storage.dimensions);
}
} // namespace blender::nodes
/* node type definition */
-void register_node_type_sh_tex_noise(void)
+void register_node_type_sh_tex_noise()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc b/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc
index 1bc3741d27c..8a1170de304 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc
@@ -21,20 +21,30 @@
#include "BLI_noise.hh"
+NODE_STORAGE_FUNCS(NodeTexVoronoi)
+
namespace blender::nodes {
static void sh_node_tex_voronoi_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
b.add_input<decl::Vector>(N_("Vector")).hide_value().implicit_field();
- b.add_input<decl::Float>(N_("W")).min(-1000.0f).max(1000.0f);
+ b.add_input<decl::Float>(N_("W")).min(-1000.0f).max(1000.0f).make_available([](bNode &node) {
+ /* Default to 1 instead of 4, because it is much faster. */
+ node_storage(node).dimensions = 1;
+ });
b.add_input<decl::Float>(N_("Scale")).min(-1000.0f).max(1000.0f).default_value(5.0f);
b.add_input<decl::Float>(N_("Smoothness"))
.min(0.0f)
.max(1.0f)
.default_value(1.0f)
- .subtype(PROP_FACTOR);
- b.add_input<decl::Float>(N_("Exponent")).min(0.0f).max(32.0f).default_value(0.5f);
+ .subtype(PROP_FACTOR)
+ .make_available([](bNode &node) { node_storage(node).feature = SHD_VORONOI_SMOOTH_F1; });
+ b.add_input<decl::Float>(N_("Exponent"))
+ .min(0.0f)
+ .max(32.0f)
+ .default_value(0.5f)
+ .make_available([](bNode &node) { node_storage(node).distance = SHD_VORONOI_MINKOWSKI; });
b.add_input<decl::Float>(N_("Randomness"))
.min(0.0f)
.max(1.0f)
@@ -43,8 +53,13 @@ static void sh_node_tex_voronoi_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Float>(N_("Distance")).no_muted_links();
b.add_output<decl::Color>(N_("Color")).no_muted_links();
b.add_output<decl::Vector>(N_("Position")).no_muted_links();
- b.add_output<decl::Float>(N_("W")).no_muted_links();
- b.add_output<decl::Float>(N_("Radius")).no_muted_links();
+ b.add_output<decl::Float>(N_("W")).no_muted_links().make_available([](bNode &node) {
+ /* Default to 1 instead of 4, because it is much faster. */
+ node_storage(node).dimensions = 1;
+ });
+ b.add_output<decl::Float>(N_("Radius")).no_muted_links().make_available([](bNode &node) {
+ node_storage(node).feature = SHD_VORONOI_N_SPHERE_RADIUS;
+ });
};
} // namespace blender::nodes
@@ -136,37 +151,40 @@ static void node_shader_update_tex_voronoi(bNodeTree *ntree, bNode *node)
bNodeSocket *outWSock = nodeFindSocket(node, SOCK_OUT, "W");
bNodeSocket *outRadiusSock = nodeFindSocket(node, SOCK_OUT, "Radius");
- NodeTexVoronoi *tex = (NodeTexVoronoi *)node->storage;
+ const NodeTexVoronoi &storage = node_storage(*node);
- nodeSetSocketAvailability(ntree, inWSock, tex->dimensions == 1 || tex->dimensions == 4);
- nodeSetSocketAvailability(ntree, inVectorSock, tex->dimensions != 1);
+ nodeSetSocketAvailability(ntree, inWSock, storage.dimensions == 1 || storage.dimensions == 4);
+ nodeSetSocketAvailability(ntree, inVectorSock, storage.dimensions != 1);
nodeSetSocketAvailability(
ntree,
inExponentSock,
- tex->distance == SHD_VORONOI_MINKOWSKI && tex->dimensions != 1 &&
- !ELEM(tex->feature, SHD_VORONOI_DISTANCE_TO_EDGE, SHD_VORONOI_N_SPHERE_RADIUS));
- nodeSetSocketAvailability(ntree, inSmoothnessSock, tex->feature == SHD_VORONOI_SMOOTH_F1);
+ storage.distance == SHD_VORONOI_MINKOWSKI && storage.dimensions != 1 &&
+ !ELEM(storage.feature, SHD_VORONOI_DISTANCE_TO_EDGE, SHD_VORONOI_N_SPHERE_RADIUS));
+ nodeSetSocketAvailability(ntree, inSmoothnessSock, storage.feature == SHD_VORONOI_SMOOTH_F1);
- nodeSetSocketAvailability(ntree, outDistanceSock, tex->feature != SHD_VORONOI_N_SPHERE_RADIUS);
+ nodeSetSocketAvailability(
+ ntree, outDistanceSock, storage.feature != SHD_VORONOI_N_SPHERE_RADIUS);
nodeSetSocketAvailability(ntree,
outColorSock,
- tex->feature != SHD_VORONOI_DISTANCE_TO_EDGE &&
- tex->feature != SHD_VORONOI_N_SPHERE_RADIUS);
+ storage.feature != SHD_VORONOI_DISTANCE_TO_EDGE &&
+ storage.feature != SHD_VORONOI_N_SPHERE_RADIUS);
nodeSetSocketAvailability(ntree,
outPositionSock,
- tex->feature != SHD_VORONOI_DISTANCE_TO_EDGE &&
- tex->feature != SHD_VORONOI_N_SPHERE_RADIUS &&
- tex->dimensions != 1);
+ storage.feature != SHD_VORONOI_DISTANCE_TO_EDGE &&
+ storage.feature != SHD_VORONOI_N_SPHERE_RADIUS &&
+ storage.dimensions != 1);
nodeSetSocketAvailability(ntree,
outWSock,
- tex->feature != SHD_VORONOI_DISTANCE_TO_EDGE &&
- tex->feature != SHD_VORONOI_N_SPHERE_RADIUS &&
- (ELEM(tex->dimensions, 1, 4)));
- nodeSetSocketAvailability(ntree, outRadiusSock, tex->feature == SHD_VORONOI_N_SPHERE_RADIUS);
+ storage.feature != SHD_VORONOI_DISTANCE_TO_EDGE &&
+ storage.feature != SHD_VORONOI_N_SPHERE_RADIUS &&
+ (ELEM(storage.dimensions, 1, 4)));
+ nodeSetSocketAvailability(ntree, outRadiusSock, storage.feature == SHD_VORONOI_N_SPHERE_RADIUS);
}
namespace blender::nodes {
+static MultiFunction::ExecutionHints voronoi_execution_hints{50, false};
+
class VoronoiMinowskiFunction : public fn::MultiFunction {
private:
int dimensions_;
@@ -592,6 +610,11 @@ class VoronoiMinowskiFunction : public fn::MultiFunction {
}
}
}
+
+ ExecutionHints get_execution_hints() const override
+ {
+ return voronoi_execution_hints;
+ }
};
class VoronoiMetricFunction : public fn::MultiFunction {
@@ -1106,6 +1129,11 @@ class VoronoiMetricFunction : public fn::MultiFunction {
}
}
}
+
+ ExecutionHints get_execution_hints() const override
+ {
+ return voronoi_execution_hints;
+ }
};
class VoronoiEdgeFunction : public fn::MultiFunction {
@@ -1282,31 +1310,39 @@ class VoronoiEdgeFunction : public fn::MultiFunction {
break;
}
}
- };
+ }
+
+ ExecutionHints get_execution_hints() const override
+ {
+ return voronoi_execution_hints;
+ }
};
static void sh_node_voronoi_build_multi_function(blender::nodes::NodeMultiFunctionBuilder &builder)
{
- bNode &node = builder.node();
- NodeTexVoronoi *tex = (NodeTexVoronoi *)node.storage;
- bool minowski = (tex->distance == SHD_VORONOI_MINKOWSKI && tex->dimensions != 1 &&
- !ELEM(tex->feature, SHD_VORONOI_DISTANCE_TO_EDGE, SHD_VORONOI_N_SPHERE_RADIUS));
- bool dist_radius = ELEM(tex->feature, SHD_VORONOI_DISTANCE_TO_EDGE, SHD_VORONOI_N_SPHERE_RADIUS);
+ const NodeTexVoronoi &storage = node_storage(builder.node());
+ bool minowski =
+ (storage.distance == SHD_VORONOI_MINKOWSKI && storage.dimensions != 1 &&
+ !ELEM(storage.feature, SHD_VORONOI_DISTANCE_TO_EDGE, SHD_VORONOI_N_SPHERE_RADIUS));
+ bool dist_radius = ELEM(
+ storage.feature, SHD_VORONOI_DISTANCE_TO_EDGE, SHD_VORONOI_N_SPHERE_RADIUS);
if (dist_radius) {
- builder.construct_and_set_matching_fn<VoronoiEdgeFunction>(tex->dimensions, tex->feature);
+ builder.construct_and_set_matching_fn<VoronoiEdgeFunction>(storage.dimensions,
+ storage.feature);
}
else if (minowski) {
- builder.construct_and_set_matching_fn<VoronoiMinowskiFunction>(tex->dimensions, tex->feature);
+ builder.construct_and_set_matching_fn<VoronoiMinowskiFunction>(storage.dimensions,
+ storage.feature);
}
else {
builder.construct_and_set_matching_fn<VoronoiMetricFunction>(
- tex->dimensions, tex->feature, tex->distance);
+ storage.dimensions, storage.feature, storage.distance);
}
}
} // namespace blender::nodes
-void register_node_type_sh_tex_voronoi(void)
+void register_node_type_sh_tex_voronoi()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc b/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc
index fe534c605e9..d3e25b533e5 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc
@@ -218,7 +218,7 @@ static void sh_node_wave_tex_build_multi_function(
} // namespace blender::nodes
-void register_node_type_sh_tex_wave(void)
+void register_node_type_sh_tex_wave()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc b/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc
index 7b4ff7fec5c..0e72cee38e7 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc
@@ -27,7 +27,10 @@ static void sh_node_tex_white_noise_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
b.add_input<decl::Vector>(N_("Vector")).min(-10000.0f).max(10000.0f).implicit_field();
- b.add_input<decl::Float>(N_("W")).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>(N_("W")).min(-10000.0f).max(10000.0f).make_available([](bNode &node) {
+ /* Default to 1 instead of 4, because it is faster. */
+ node.custom1 = 1;
+ });
b.add_output<decl::Float>(N_("Value"));
b.add_output<decl::Color>(N_("Color"));
};
@@ -191,7 +194,7 @@ static void sh_node_noise_build_multi_function(blender::nodes::NodeMultiFunction
} // namespace blender::nodes
-void register_node_type_sh_tex_white_noise(void)
+void register_node_type_sh_tex_white_noise()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/shader/nodes/node_shader_uvAlongStroke.c b/source/blender/nodes/shader/nodes/node_shader_uv_along_stroke.c
index 05c3248af65..05c3248af65 100644
--- a/source/blender/nodes/shader/nodes/node_shader_uvAlongStroke.c
+++ b/source/blender/nodes/shader/nodes/node_shader_uv_along_stroke.c
diff --git a/source/blender/nodes/shader/nodes/node_shader_value.cc b/source/blender/nodes/shader/nodes/node_shader_value.cc
index b0f152d8526..f0eb3ea9bee 100644
--- a/source/blender/nodes/shader/nodes/node_shader_value.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_value.cc
@@ -49,7 +49,7 @@ static void sh_node_value_build_multi_function(blender::nodes::NodeMultiFunction
builder.construct_and_set_matching_fn<blender::fn::CustomMF_Constant<float>>(value->value);
}
-void register_node_type_sh_value(void)
+void register_node_type_sh_value()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_math.cc b/source/blender/nodes/shader/nodes/node_shader_vector_math.cc
index fad93962708..5f5969de78c 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vector_math.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_vector_math.cc
@@ -24,6 +24,7 @@
#include "node_shader_util.h"
#include "NOD_math_functions.hh"
+#include "NOD_socket_search_link.hh"
namespace blender::nodes {
@@ -38,6 +39,18 @@ static void sh_node_vector_math_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Float>(N_("Value"));
};
+static void sh_node_vector_math_gather_link_searches(GatherLinkSearchOpParams &params)
+{
+ /* For now, do something very basic (only exposing "Add", and a single "Vector" socket). */
+ if (params.node_tree().typeinfo->validate_link(
+ static_cast<eNodeSocketDatatype>(params.other_socket().type), SOCK_VECTOR)) {
+ params.add_item(IFACE_("Vector"), [](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("ShaderNodeVectorMath");
+ params.update_and_connect_available_socket(node, "Vector");
+ });
+ }
+}
+
} // namespace blender::nodes
static const char *gpu_shader_get_name(int mode)
@@ -201,8 +214,8 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node)
blender::nodes::try_dispatch_float_math_fl3_fl3_to_fl3(
operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) {
- static blender::fn::CustomMF_SI_SI_SO<float3, float3, float3> fn{info.title_case_name,
- function};
+ static blender::fn::CustomMF_SI_SI_SO<float3, float3, float3> fn{
+ info.title_case_name.c_str(), function};
multi_fn = &fn;
});
if (multi_fn != nullptr) {
@@ -212,7 +225,7 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node)
blender::nodes::try_dispatch_float_math_fl3_fl3_fl3_to_fl3(
operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) {
static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float3, float3> fn{
- info.title_case_name, function};
+ info.title_case_name.c_str(), function};
multi_fn = &fn;
});
if (multi_fn != nullptr) {
@@ -222,7 +235,7 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node)
blender::nodes::try_dispatch_float_math_fl3_fl3_fl_to_fl3(
operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) {
static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{
- info.title_case_name, function};
+ info.title_case_name.c_str(), function};
multi_fn = &fn;
});
if (multi_fn != nullptr) {
@@ -231,8 +244,8 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node)
blender::nodes::try_dispatch_float_math_fl3_fl3_to_fl(
operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) {
- static blender::fn::CustomMF_SI_SI_SO<float3, float3, float> fn{info.title_case_name,
- function};
+ static blender::fn::CustomMF_SI_SI_SO<float3, float3, float> fn{
+ info.title_case_name.c_str(), function};
multi_fn = &fn;
});
if (multi_fn != nullptr) {
@@ -241,8 +254,8 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node)
blender::nodes::try_dispatch_float_math_fl3_fl_to_fl3(
operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) {
- static blender::fn::CustomMF_SI_SI_SO<float3, float, float3> fn{info.title_case_name,
- function};
+ static blender::fn::CustomMF_SI_SI_SO<float3, float, float3> fn{
+ info.title_case_name.c_str(), function};
multi_fn = &fn;
});
if (multi_fn != nullptr) {
@@ -251,7 +264,8 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node)
blender::nodes::try_dispatch_float_math_fl3_to_fl3(
operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) {
- static blender::fn::CustomMF_SI_SO<float3, float3> fn{info.title_case_name, function};
+ static blender::fn::CustomMF_SI_SO<float3, float3> fn{info.title_case_name.c_str(),
+ function};
multi_fn = &fn;
});
if (multi_fn != nullptr) {
@@ -260,7 +274,8 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node)
blender::nodes::try_dispatch_float_math_fl3_to_fl(
operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) {
- static blender::fn::CustomMF_SI_SO<float3, float> fn{info.title_case_name, function};
+ static blender::fn::CustomMF_SI_SO<float3, float> fn{info.title_case_name.c_str(),
+ function};
multi_fn = &fn;
});
if (multi_fn != nullptr) {
@@ -277,16 +292,17 @@ static void sh_node_vector_math_build_multi_function(
builder.set_matching_fn(fn);
}
-void register_node_type_sh_vect_math(void)
+void register_node_type_sh_vect_math()
{
static bNodeType ntype;
sh_fn_node_type_base(&ntype, SH_NODE_VECTOR_MATH, "Vector Math", NODE_CLASS_OP_VECTOR, 0);
ntype.declare = blender::nodes::sh_node_vector_math_declare;
- node_type_label(&ntype, node_vector_math_label);
+ ntype.labelfunc = node_vector_math_label;
node_type_gpu(&ntype, gpu_shader_vector_math);
node_type_update(&ntype, node_shader_update_vector_math);
ntype.build_multi_function = sh_node_vector_math_build_multi_function;
+ ntype.gather_link_search_ops = blender::nodes::sh_node_vector_math_gather_link_searches;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc
index 3c1f1ed8d39..a3cb82f3245 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc
@@ -205,7 +205,7 @@ static void node_shader_update_vector_rotate(bNodeTree *ntree, bNode *node)
ntree, sock_angle, !ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_EULER_XYZ));
}
-void register_node_type_sh_vector_rotate(void)
+void register_node_type_sh_vector_rotate()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/shader/nodes/node_shader_vectTransform.c b/source/blender/nodes/shader/nodes/node_shader_vector_transform.c
index 7b08178f874..7b08178f874 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vectTransform.c
+++ b/source/blender/nodes/shader/nodes/node_shader_vector_transform.c
diff --git a/source/blender/nodes/texture/node_texture_util.c b/source/blender/nodes/texture/node_texture_util.c
index c968d0bae56..fe8e68bfc42 100644
--- a/source/blender/nodes/texture/node_texture_util.c
+++ b/source/blender/nodes/texture/node_texture_util.c
@@ -44,7 +44,7 @@ bool tex_node_poll_default(bNodeType *UNUSED(ntype),
const char **r_disabled_hint)
{
if (!STREQ(ntree->idname, "TextureNodeTree")) {
- *r_disabled_hint = "Not a texture node tree";
+ *r_disabled_hint = TIP_("Not a texture node tree");
return false;
}
return true;
diff --git a/source/blender/nodes/texture/node_texture_util.h b/source/blender/nodes/texture/node_texture_util.h
index 8f63a1ad07d..84d2c5c903a 100644
--- a/source/blender/nodes/texture/node_texture_util.h
+++ b/source/blender/nodes/texture/node_texture_util.h
@@ -37,8 +37,7 @@
#include "DNA_scene_types.h"
#include "DNA_texture_types.h"
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
+#include "BLI_math_vector.h"
#include "BLI_rand.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
diff --git a/source/blender/nodes/texture/nodes/node_texture_common.c b/source/blender/nodes/texture/nodes/node_texture_common.c
index 868c97e5850..f873ed5e457 100644
--- a/source/blender/nodes/texture/nodes/node_texture_common.c
+++ b/source/blender/nodes/texture/nodes/node_texture_common.c
@@ -161,7 +161,7 @@ void register_node_type_tex_group(void)
/* NOTE: Cannot use #sh_node_type_base for node group, because it would map the node type
* to the shared #NODE_GROUP integer type id. */
- node_type_base_custom(&ntype, "TextureNodeGroup", "Group", NODE_CLASS_GROUP, NODE_CONST_OUTPUT);
+ node_type_base_custom(&ntype, "TextureNodeGroup", "Group", NODE_CLASS_GROUP, 0);
ntype.type = NODE_GROUP;
ntype.poll = tex_node_poll_default;
ntype.poll_instance = node_group_poll_instance;
@@ -172,7 +172,7 @@ void register_node_type_tex_group(void)
node_type_socket_templates(&ntype, NULL, NULL);
node_type_size(&ntype, 140, 60, 400);
- node_type_label(&ntype, node_group_label);
+ ntype.labelfunc = node_group_label;
node_type_group_update(&ntype, node_group_update);
node_type_exec(&ntype, group_initexec, group_freeexec, group_execute);
diff --git a/source/blender/nodes/texture/nodes/node_texture_distance.c b/source/blender/nodes/texture/nodes/node_texture_distance.c
index f7deac9ff4a..c2241858737 100644
--- a/source/blender/nodes/texture/nodes/node_texture_distance.c
+++ b/source/blender/nodes/texture/nodes/node_texture_distance.c
@@ -21,7 +21,6 @@
* \ingroup texnodes
*/
-#include "BLI_math.h"
#include "NOD_texture.h"
#include "node_texture_util.h"
#include <math.h>
diff --git a/source/blender/nodes/texture/nodes/node_texture_image.c b/source/blender/nodes/texture/nodes/node_texture_image.c
index a85b963286b..9c61405ea23 100644
--- a/source/blender/nodes/texture/nodes/node_texture_image.c
+++ b/source/blender/nodes/texture/nodes/node_texture_image.c
@@ -113,7 +113,7 @@ void register_node_type_tex_image(void)
node_type_init(&ntype, init);
node_type_storage(&ntype, "ImageUser", node_free_standard_storage, node_copy_standard_storage);
node_type_exec(&ntype, NULL, NULL, exec);
- node_type_label(&ntype, node_image_label);
+ ntype.labelfunc = node_image_label;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/texture/nodes/node_texture_math.c b/source/blender/nodes/texture/nodes/node_texture_math.c
index ab226a4dd38..9e37f4ee643 100644
--- a/source/blender/nodes/texture/nodes/node_texture_math.c
+++ b/source/blender/nodes/texture/nodes/node_texture_math.c
@@ -337,7 +337,7 @@ void register_node_type_tex_math(void)
tex_node_type_base(&ntype, TEX_NODE_MATH, "Math", NODE_CLASS_CONVERTER, 0);
node_type_socket_templates(&ntype, inputs, outputs);
- node_type_label(&ntype, node_math_label);
+ ntype.labelfunc = node_math_label;
node_type_storage(&ntype, "", NULL, NULL);
node_type_exec(&ntype, NULL, NULL, exec);
node_type_update(&ntype, node_math_update);
diff --git a/source/blender/nodes/texture/nodes/node_texture_mixRgb.c b/source/blender/nodes/texture/nodes/node_texture_mixRgb.c
index b1aeb269018..044875cce90 100644
--- a/source/blender/nodes/texture/nodes/node_texture_mixRgb.c
+++ b/source/blender/nodes/texture/nodes/node_texture_mixRgb.c
@@ -71,7 +71,7 @@ void register_node_type_tex_mix_rgb(void)
tex_node_type_base(&ntype, TEX_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR, 0);
node_type_socket_templates(&ntype, inputs, outputs);
- node_type_label(&ntype, node_blend_label);
+ ntype.labelfunc = node_blend_label;
node_type_exec(&ntype, NULL, NULL, exec);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/texture/nodes/node_texture_output.c b/source/blender/nodes/texture/nodes/node_texture_output.c
index 9145df0038b..19e24c9f82a 100644
--- a/source/blender/nodes/texture/nodes/node_texture_output.c
+++ b/source/blender/nodes/texture/nodes/node_texture_output.c
@@ -21,6 +21,8 @@
* \ingroup texnodes
*/
+#include "BLI_string.h"
+
#include "NOD_texture.h"
#include "node_texture_util.h"
diff --git a/source/blender/python/BPY_extern.h b/source/blender/python/BPY_extern.h
index 43a73363c98..e233a078ea9 100644
--- a/source/blender/python/BPY_extern.h
+++ b/source/blender/python/BPY_extern.h
@@ -55,7 +55,13 @@ int BPY_is_pyconstraint(struct Text *text);
typedef void *BPy_ThreadStatePtr;
+/**
+ * Analogue of #PyEval_SaveThread()
+ */
BPy_ThreadStatePtr BPY_thread_save(void);
+/**
+ * Analogue of #PyEval_RestoreThread()
+ */
void BPY_thread_restore(BPy_ThreadStatePtr tstate);
/* our own wrappers to Py_BEGIN_ALLOW_THREADS/Py_END_ALLOW_THREADS */
@@ -69,12 +75,26 @@ void BPY_thread_restore(BPy_ThreadStatePtr tstate);
(void)0
void BPY_text_free_code(struct Text *text);
+/**
+ * Needed so the #Main pointer in `bpy.data` doesn't become out of date.
+ */
void BPY_modules_update(void);
void BPY_modules_load_user(struct bContext *C);
void BPY_app_handlers_reset(const short do_all);
+/**
+ * Update function, it gets rid of py-drivers global dictionary, forcing
+ * BPY_driver_exec to recreate it. This function is used to force
+ * reloading the Blender text module "pydrivers.py", if available, so
+ * updates in it reach py-driver evaluation.
+ */
void BPY_driver_reset(void);
+
+/**
+ * This evaluates Python driver expressions, `driver_orig->expression`
+ * is a Python expression that should evaluate to a float number, which is returned.
+ */
float BPY_driver_exec(struct PathResolvedRNA *anim_rna,
struct ChannelDriver *driver,
struct ChannelDriver *driver_orig,
@@ -86,6 +106,9 @@ int BPY_context_member_get(struct bContext *C,
const char *member,
struct bContextDataResult *result);
void BPY_context_set(struct bContext *C);
+/**
+ * Use for updating while a python script runs - in case of file load.
+ */
void BPY_context_update(struct bContext *C);
#define BPY_context_dict_clear_members(C, ...) \
@@ -93,6 +116,16 @@ void BPY_context_update(struct bContext *C);
(C)->data.py_context_orig, \
((const char *[]){__VA_ARGS__}), \
VA_NARGS_COUNT(__VA_ARGS__))
+/**
+ * Use for `CTX_*_set(..)` functions need to set values which are later read back as expected.
+ * In this case we don't want the Python context to override the values as it causes problems
+ * see T66256.
+ *
+ * \param dict_p: A pointer to #bContext.data.py_context so we can assign a new value.
+ * \param dict_orig: The value of #bContext.data.py_context_orig to check if we need to copy.
+ *
+ * \note Typically accessed via #BPY_context_dict_clear_members macro.
+ */
void BPY_context_dict_clear_members_array(void **dict_p,
void *dict_orig,
const char *context_members[],
@@ -100,6 +133,9 @@ void BPY_context_dict_clear_members_array(void **dict_p,
void BPY_id_release(struct ID *id);
+/**
+ * Avoids duplicating keyword list.
+ */
bool BPY_string_is_keyword(const char *str);
/* bpy_rna_callback.c */
diff --git a/source/blender/python/BPY_extern_python.h b/source/blender/python/BPY_extern_python.h
index c321fd93379..56662ffc040 100644
--- a/source/blender/python/BPY_extern_python.h
+++ b/source/blender/python/BPY_extern_python.h
@@ -32,6 +32,8 @@ extern "C" {
#include <stdio.h>
/* bpy_interface.c */
+
+/** Call #BPY_context_set first. */
void BPY_python_start(struct bContext *C, int argc, const char **argv);
void BPY_python_end(void);
void BPY_python_reset(struct bContext *C);
diff --git a/source/blender/python/BPY_extern_run.h b/source/blender/python/BPY_extern_run.h
index b65b5d61b9d..30740d7fb60 100644
--- a/source/blender/python/BPY_extern_run.h
+++ b/source/blender/python/BPY_extern_run.h
@@ -16,6 +16,20 @@
/** \file
* \ingroup python
+ *
+ * \subsection common_args Common Arguments
+ *
+ * - `C` the #bContext (never NULL).
+ *
+ * - `imports`: This is simply supported for convenience since imports can make constructing
+ * strings more cumbersome as otherwise small expressions become multi-line code-blocks.
+ * Optional (ignored when NULL), otherwise this is a NULL terminated array of module names.
+ *
+ Failure to import any modules prevents any further execution.
+ *
+ * - `err_info` #BPy_RunErrInfo is passed to some functions so errors can be forwarded to the UI.
+ * Option (when NULL errors are printed to the `stdout` and cleared).
+ * However this should be used in any case the error would be useful to show to the user.
*/
#pragma once
@@ -26,22 +40,85 @@ extern "C" {
#include "BLI_sys_types.h"
+#include "BLI_compiler_attrs.h"
+
struct ReportList;
struct Text;
struct bContext;
/* bpy_interface_run.c */
-bool BPY_run_filepath(struct bContext *C, const char *filepath, struct ReportList *reports);
+
+/* -------------------------------------------------------------------- */
+/** \name Run File/Text as a Script
+ *
+ * \note #BPY_run_filepath and #BPY_run_filepath have almost identical behavior
+ * one operates on a file-path, the other on a blender text-block.
+ * \{ */
+
+/**
+ * Execute `filepath` as a Python script.
+ *
+ * Wrapper for `PyRun_File` (similar to calling python with a script argument).
+ * Used for the `--python` command line argument.
+ *
+ * \param C: The context (never NULL).
+ * \param filepath: The file path to execute.
+ * \param reports: Failure to execute the script will report the exception here (may be NULL).
+ * \return true on success, otherwise false with an error reported to `reports`.
+ *
+ * \note Python scripts could consider `bpy.utils.execfile`, which has the advantage of returning
+ * the object as a module for data access & caching `pyc` file for faster re-execution.
+ */
+bool BPY_run_filepath(struct bContext *C, const char *filepath, struct ReportList *reports)
+ ATTR_NONNULL(1, 2);
+/**
+ * Execute a Blender `text` block as a Python script.
+ *
+ * Wrapper for `Py_CompileStringObject` & `PyEval_EvalCode`.
+ * Used for the `--python-text` command line argument.
+ *
+ * \param C: The context (never NULL).
+ * \param text: The text-block to execute.
+ * \param reports: Failure to execute the script will report the exception here (may be NULL).
+ * \param do_jump: When true, any error moves the cursor to the location of that error.
+ * Useful for executing scripts interactively from the text editor.
+ * \return true on success, otherwise false with an error reported to `reports`.
+ *
+ * \note The `__file__` is constructed by joining the blend file-path to the name of the text.
+ * This is done so error messages give useful output however there are rare cases causes problems
+ * with introspection tools which attempt to load `__file__`.
+ */
bool BPY_run_text(struct bContext *C,
struct Text *text,
struct ReportList *reports,
- const bool do_jump);
+ const bool do_jump) ATTR_NONNULL(1, 2);
-/* Use the 'eval' for simple single-line expressions,
- * otherwise 'exec' for full multi-line scripts. */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Run a String as a Script
+ *
+ * - Use 'eval' for simple single-line expressions.
+ * - Use 'exec' for full multi-line scripts.
+ * \{ */
+
+/**
+ * Run an entire script, matches: `exec(compile(..., "exec"))`
+ */
bool BPY_run_string_exec(struct bContext *C, const char *imports[], const char *expr);
+/**
+ * Run an expression, matches: `exec(compile(..., "eval"))`.
+ */
bool BPY_run_string_eval(struct bContext *C, const char *imports[], const char *expr);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Run a String as a Script & Return the Result
+ *
+ * Convenience functions for executing a script and returning the result as an expected type.
+ * \{ */
+
/**
* \note When this struct is passed in as NULL,
* print errors to the `stdout` and clear.
@@ -58,28 +135,63 @@ struct BPy_RunErrInfo {
char **r_string;
};
-/* Run, evaluating to fixed type result. */
+/**
+ * Evaluate `expr` as a number (double).
+ *
+ * \param C: See \ref common_args.
+ * \param imports: See \ref common_args.
+ * \param expr: The expression to evaluate.
+ * \param err_info: See \ref common_args.
+ * \param r_value: The resulting value.
+ * \return Success.
+ */
bool BPY_run_string_as_number(struct bContext *C,
const char *imports[],
const char *expr,
struct BPy_RunErrInfo *err_info,
- double *r_value);
+ double *r_value) ATTR_NONNULL(1, 3, 5);
+/**
+ * Evaluate `expr` as an integer or pointer.
+ *
+ * \note Support both int and pointers.
+ *
+ * \param C: See \ref common_args.
+ * \param imports: See \ref common_args.
+ * \param expr: The expression to evaluate.
+ * \param err_info: See \ref common_args.
+ * \param r_value: The resulting value.
+ * \return Success.
+ */
bool BPY_run_string_as_intptr(struct bContext *C,
const char *imports[],
const char *expr,
struct BPy_RunErrInfo *err_info,
- intptr_t *r_value);
+ intptr_t *r_value) ATTR_NONNULL(1, 3, 5);
+/**
+ * Evaluate `expr` as a string.
+ *
+ * \param C: See \ref common_args.
+ * \param imports: See \ref common_args.
+ * \param expr: The expression to evaluate.
+ * \param err_info: See \ref common_args.
+ * \param r_value: The resulting value.
+ * \return Success.
+ */
bool BPY_run_string_as_string_and_size(struct bContext *C,
const char *imports[],
const char *expr,
struct BPy_RunErrInfo *err_info,
char **r_value,
- size_t *r_value_size);
+ size_t *r_value_size) ATTR_NONNULL(1, 3, 5, 6);
+
+/** See #BPY_run_string_as_string_and_size */
bool BPY_run_string_as_string(struct bContext *C,
const char *imports[],
const char *expr,
struct BPy_RunErrInfo *err_info,
- char **r_value);
+ char **r_value) ATTR_NONNULL(1, 3, 5);
+
+/** \} */
#ifdef __cplusplus
} /* extern "C" */
diff --git a/source/blender/python/bmesh/bmesh_py_ops_call.c b/source/blender/python/bmesh/bmesh_py_ops_call.c
index 24887b24eb6..f1423c20b3b 100644
--- a/source/blender/python/bmesh/bmesh_py_ops_call.c
+++ b/source/blender/python/bmesh/bmesh_py_ops_call.c
@@ -745,9 +745,6 @@ static PyObject *bpy_slot_to_py(BMesh *bm, BMOpSlot *slot)
return item;
}
-/**
- * This is the __call__ for bmesh.ops.xxx()
- */
PyObject *BPy_BMO_call(BPy_BMeshOpFunc *self, PyObject *args, PyObject *kw)
{
PyObject *ret;
diff --git a/source/blender/python/bmesh/bmesh_py_ops_call.h b/source/blender/python/bmesh/bmesh_py_ops_call.h
index 1c7a35788d2..c567375c568 100644
--- a/source/blender/python/bmesh/bmesh_py_ops_call.h
+++ b/source/blender/python/bmesh/bmesh_py_ops_call.h
@@ -28,4 +28,7 @@ typedef struct {
const char *opname;
} BPy_BMeshOpFunc;
+/**
+ * This is the `__call__` for `bmesh.ops.xxx()`.
+ */
PyObject *BPy_BMO_call(BPy_BMeshOpFunc *self, PyObject *args, PyObject *kw);
diff --git a/source/blender/python/bmesh/bmesh_py_types.c b/source/blender/python/bmesh/bmesh_py_types.c
index cbebe4746e9..38ec242fa49 100644
--- a/source/blender/python/bmesh/bmesh_py_types.c
+++ b/source/blender/python/bmesh/bmesh_py_types.c
@@ -3349,8 +3349,8 @@ static PyObject *bpy_bmiter_next(BPy_BMIter *self)
return (PyObject *)BPy_BMElem_CreatePyObject(self->bm, ele);
}
-/* Dealloc Functions
- * ================= */
+/* Deallocate Functions
+ * ==================== */
static void bpy_bmesh_dealloc(BPy_BMesh *self)
{
@@ -3954,7 +3954,6 @@ PyObject *BPy_BMIter_CreatePyObject(BMesh *bm)
return (PyObject *)self;
}
-/* this is just a helper func */
PyObject *BPy_BMElem_CreatePyObject(BMesh *bm, BMHeader *ele)
{
switch (ele->htype) {
@@ -4036,11 +4035,6 @@ void bpy_bm_generic_invalidate(BPy_BMGeneric *self)
self->bm = NULL;
}
-/* generic python seq as BMVert/Edge/Face array,
- * return value must be freed with PyMem_FREE(...);
- *
- * The 'bm_r' value is assigned when empty, and used when set.
- */
void *BPy_BMElem_PySeq_As_Array_FAST(BMesh **r_bm,
PyObject *seq_fast,
Py_ssize_t min,
@@ -4233,11 +4227,6 @@ int BPy_BMElem_CheckHType(PyTypeObject *type, const char htype)
((htype & BM_LOOP) && (type == &BPy_BMLoop_Type)));
}
-/**
- * Use for error strings only, not thread safe,
- *
- * \return a string like '(BMVert/BMEdge/BMFace/BMLoop)'
- */
char *BPy_BMElem_StringFromHType_ex(const char htype, char ret[32])
{
/* zero to ensure string is always NULL terminated */
diff --git a/source/blender/python/bmesh/bmesh_py_types.h b/source/blender/python/bmesh/bmesh_py_types.h
index 043c5322735..42d1fee31c3 100644
--- a/source/blender/python/bmesh/bmesh_py_types.h
+++ b/source/blender/python/bmesh/bmesh_py_types.h
@@ -148,9 +148,15 @@ PyObject *BPy_BMFaceSeq_CreatePyObject(BMesh *bm);
PyObject *BPy_BMLoopSeq_CreatePyObject(BMesh *bm);
PyObject *BPy_BMIter_CreatePyObject(BMesh *bm);
-/* Just checks type and creates v/e/f/l. */
+/** Just checks type and creates vert/edge/face/loop. */
PyObject *BPy_BMElem_CreatePyObject(BMesh *bm, BMHeader *ele);
+/**
+ * Generic python seq as BMVert/Edge/Face array,
+ * return value must be freed with PyMem_FREE(...);
+ *
+ * The 'bm_r' value is assigned when empty, and used when set.
+ */
void *BPy_BMElem_PySeq_As_Array_FAST(BMesh **r_bm,
PyObject *seq_fast,
Py_ssize_t min,
@@ -177,6 +183,11 @@ PyObject *BPy_BMFace_Array_As_Tuple(BMesh *bm, BMFace **elem, Py_ssize_t elem_le
PyObject *BPy_BMLoop_Array_As_Tuple(BMesh *bm, BMLoop **elem, Py_ssize_t elem_len);
int BPy_BMElem_CheckHType(PyTypeObject *type, const char htype);
+/**
+ * Use for error strings only, not thread safe,
+ *
+ * \return a string like '(BMVert/BMEdge/BMFace/BMLoop)'
+ */
char *BPy_BMElem_StringFromHType_ex(const char htype, char ret[32]);
char *BPy_BMElem_StringFromHType(const char htype);
@@ -198,7 +209,9 @@ int bpy_bm_generic_valid_check_source(BMesh *bm_source,
} \
(void)0
-/* macros like BPY_BM_CHECK_OBJ/BPY_BM_CHECK_INT that ensure we're from the right BMesh */
+/**
+ * Macros like `BPY_BM_CHECK_OBJ/BPY_BM_CHECK_INT` that ensure we're from the right #BMesh.
+ */
#define BPY_BM_CHECK_SOURCE_OBJ(bm, errmsg, ...) \
{ \
void *_args[] = {__VA_ARGS__}; \
diff --git a/source/blender/python/bmesh/bmesh_py_types_customdata.c b/source/blender/python/bmesh/bmesh_py_types_customdata.c
index 0aa92158524..1e1ba5edb0f 100644
--- a/source/blender/python/bmesh/bmesh_py_types_customdata.c
+++ b/source/blender/python/bmesh/bmesh_py_types_customdata.c
@@ -1104,13 +1104,6 @@ static void *bpy_bmlayeritem_ptr_get(BPy_BMElem *py_ele, BPy_BMLayerItem *py_lay
return value;
}
-/**
- *\brief BMElem.__getitem__()
- *
- * assume all error checks are done, eg:
- *
- * uv = vert[uv_layer]
- */
PyObject *BPy_BMLayerItem_GetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer)
{
void *value = bpy_bmlayeritem_ptr_get(py_ele, py_layer);
diff --git a/source/blender/python/bmesh/bmesh_py_types_customdata.h b/source/blender/python/bmesh/bmesh_py_types_customdata.h
index 8552942f73a..a5555a14ad7 100644
--- a/source/blender/python/bmesh/bmesh_py_types_customdata.h
+++ b/source/blender/python/bmesh/bmesh_py_types_customdata.h
@@ -23,7 +23,8 @@
#pragma once
-/* all use BPy_BMLayerAccess struct */
+/* All use #BPy_BMLayerAccess struct. */
+
extern PyTypeObject BPy_BMLayerAccessVert_Type;
extern PyTypeObject BPy_BMLayerAccessEdge_Type;
extern PyTypeObject BPy_BMLayerAccessFace_Type;
@@ -36,14 +37,14 @@ extern PyTypeObject BPy_BMLayerItem_Type;
#define BPy_BMLayerCollection_Check(v) (Py_TYPE(v) == &BPy_BMLayerCollection_Type)
#define BPy_BMLayerItem_Check(v) (Py_TYPE(v) == &BPy_BMLayerItem_Type)
-/* all layers for vert/edge/face/loop */
+/** All layers for vert/edge/face/loop. */
typedef struct BPy_BMLayerAccess {
PyObject_VAR_HEAD
struct BMesh *bm; /* keep first */
char htype;
} BPy_BMLayerAccess;
-/* access different layer types deform/uv/vertexcolor */
+/** Access different layer types deform/uv/vertex-color. */
typedef struct BPy_BMLayerCollection {
PyObject_VAR_HEAD
struct BMesh *bm; /* keep first */
@@ -51,7 +52,7 @@ typedef struct BPy_BMLayerCollection {
int type; /* customdata type - CD_XXX */
} BPy_BMLayerCollection;
-/* access a specific layer directly */
+/** Access a specific layer directly. */
typedef struct BPy_BMLayerItem {
PyObject_VAR_HEAD
struct BMesh *bm; /* keep first */
@@ -66,6 +67,10 @@ PyObject *BPy_BMLayerItem_CreatePyObject(BMesh *bm, const char htype, int type,
void BPy_BM_init_types_customdata(void);
-/* __getitem__ / __setitem__ */
+/**
+ *\brief BMElem.__getitem__() / __setitem__()
+ *
+ * Assume all error checks are done, eg: `uv = vert[uv_layer]`
+ */
PyObject *BPy_BMLayerItem_GetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer);
int BPy_BMLayerItem_SetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer, PyObject *value);
diff --git a/source/blender/python/bmesh/bmesh_py_types_meshdata.c b/source/blender/python/bmesh/bmesh_py_types_meshdata.c
index ca5d408bfdb..766e1d08443 100644
--- a/source/blender/python/bmesh/bmesh_py_types_meshdata.c
+++ b/source/blender/python/bmesh/bmesh_py_types_meshdata.c
@@ -689,7 +689,6 @@ PyObject *BPy_BMDeformVert_CreatePyObject(struct MDeformVert *dvert)
/* --- End Mesh Deform Vert --- */
-/* call to init all types */
void BPy_BM_init_types_meshdata(void)
{
bm_init_types_bmloopuv();
diff --git a/source/blender/python/bmesh/bmesh_py_types_meshdata.h b/source/blender/python/bmesh/bmesh_py_types_meshdata.h
index 426bfcef6a0..b52bf6889bc 100644
--- a/source/blender/python/bmesh/bmesh_py_types_meshdata.h
+++ b/source/blender/python/bmesh/bmesh_py_types_meshdata.h
@@ -50,4 +50,5 @@ PyObject *BPy_BMLoopColor_CreatePyObject(struct MLoopCol *mloopcol);
int BPy_BMDeformVert_AssignPyObject(struct MDeformVert *dvert, PyObject *value);
PyObject *BPy_BMDeformVert_CreatePyObject(struct MDeformVert *dvert);
+/* call to init all types */
void BPy_BM_init_types_meshdata(void);
diff --git a/source/blender/python/bmesh/bmesh_py_types_select.c b/source/blender/python/bmesh/bmesh_py_types_select.c
index b89822a080c..bc8c6853ff5 100644
--- a/source/blender/python/bmesh/bmesh_py_types_select.c
+++ b/source/blender/python/bmesh/bmesh_py_types_select.c
@@ -411,9 +411,6 @@ void BPy_BM_init_types_select(void)
/* utility function */
-/**
- * \note doesn't actually check selection.
- */
int BPy_BMEditSel_Assign(BPy_BMesh *self, PyObject *value)
{
BMesh *bm;
diff --git a/source/blender/python/bmesh/bmesh_py_types_select.h b/source/blender/python/bmesh/bmesh_py_types_select.h
index 34ca162dd09..6b8609e36a6 100644
--- a/source/blender/python/bmesh/bmesh_py_types_select.h
+++ b/source/blender/python/bmesh/bmesh_py_types_select.h
@@ -46,4 +46,7 @@ void BPy_BM_init_types_select(void);
PyObject *BPy_BMEditSel_CreatePyObject(BMesh *bm);
PyObject *BPy_BMEditSelIter_CreatePyObject(BMesh *bm);
+/**
+ * \note doesn't actually check selection.
+ */
int BPy_BMEditSel_Assign(struct BPy_BMesh *self, PyObject *value);
diff --git a/source/blender/python/generic/bgl.c b/source/blender/python/generic/bgl.c
index e416727fa70..3f01ff86f49 100644
--- a/source/blender/python/generic/bgl.c
+++ b/source/blender/python/generic/bgl.c
@@ -666,13 +666,6 @@ static Buffer *BGL_MakeBuffer_FromData(
return buffer;
}
-/**
- * Create a buffer object
- *
- * \param dimensions: An array of ndimensions integers representing the size of each dimension.
- * \param initbuffer: When not NULL holds a contiguous buffer
- * with the correct format from which the buffer will be initialized
- */
Buffer *BGL_MakeBuffer(int type, int ndimensions, int *dimensions, void *initbuffer)
{
Buffer *buffer;
diff --git a/source/blender/python/generic/bgl.h b/source/blender/python/generic/bgl.h
index 4e59eab46ce..479c69b5de2 100644
--- a/source/blender/python/generic/bgl.h
+++ b/source/blender/python/generic/bgl.h
@@ -22,6 +22,13 @@
PyObject *BPyInit_bgl(void);
+/**
+ * Create a buffer object
+ *
+ * \param dimensions: An array of ndimensions integers representing the size of each dimension.
+ * \param initbuffer: When not NULL holds a contiguous buffer
+ * with the correct format from which the buffer will be initialized
+ */
struct _Buffer *BGL_MakeBuffer(int type, int ndimensions, int *dimensions, void *initbuffer);
int BGL_typeSize(int type);
@@ -50,5 +57,5 @@ typedef struct _Buffer {
} buf;
} Buffer;
-/** The type object */
+/** The type object. */
extern PyTypeObject BGL_bufferType;
diff --git a/source/blender/python/generic/bpy_threads.c b/source/blender/python/generic/bpy_threads.c
index 8aa8c5c5d92..41e2fb4adf2 100644
--- a/source/blender/python/generic/bpy_threads.c
+++ b/source/blender/python/generic/bpy_threads.c
@@ -26,7 +26,6 @@
#include "../BPY_extern.h"
#include "BLI_utildefines.h"
-/* analogue of PyEval_SaveThread() */
BPy_ThreadStatePtr BPY_thread_save(void)
{
/* Use `_PyThreadState_UncheckedGet()` instead of `PyThreadState_Get()`, to avoid a fatal error
@@ -40,7 +39,6 @@ BPy_ThreadStatePtr BPY_thread_save(void)
return NULL;
}
-/* analogue of PyEval_RestoreThread() */
void BPY_thread_restore(BPy_ThreadStatePtr tstate)
{
if (tstate) {
diff --git a/source/blender/python/generic/idprop_py_api.c b/source/blender/python/generic/idprop_py_api.c
index 8dc0d2fb857..0a870102b6f 100644
--- a/source/blender/python/generic/idprop_py_api.c
+++ b/source/blender/python/generic/idprop_py_api.c
@@ -686,12 +686,6 @@ static IDProperty *idp_from_PyObject(PyObject *name_obj, PyObject *ob)
/** \name Mapping Get/Set (Internal Access)
* \{ */
-/**
- * \note group can be a pointer array or a group.
- * assume we already checked key is a string.
- *
- * \return success.
- */
bool BPy_IDProperty_Map_ValidateAndCreate(PyObject *name_obj, IDProperty *group, PyObject *ob)
{
IDProperty *prop = idp_from_PyObject(name_obj, ob);
@@ -779,7 +773,6 @@ static PyObject *BPy_IDGroup_iter(BPy_IDProperty *self)
return BPy_IDGroup_ViewKeys_CreatePyObject(self);
}
-/* for simple, non nested types this is the same as BPy_IDGroup_WrapData */
PyObject *BPy_IDGroup_MapDataToPy(IDProperty *prop)
{
switch (prop->type) {
@@ -1975,6 +1968,8 @@ static PyBufferProcs BPy_IDArray_Buffer = {
(releasebufferproc)BPy_IDArray_releasebuffer,
};
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name ID Array Type
* \{ */
diff --git a/source/blender/python/generic/idprop_py_api.h b/source/blender/python/generic/idprop_py_api.h
index f53c45b07c2..e4addcecc10 100644
--- a/source/blender/python/generic/idprop_py_api.h
+++ b/source/blender/python/generic/idprop_py_api.h
@@ -95,8 +95,17 @@ PyObject *BPy_Wrap_GetItems_View_WithID(struct ID *id, struct IDProperty *prop);
int BPy_Wrap_SetMapItem(struct IDProperty *prop, PyObject *key, PyObject *val);
+/**
+ * For simple, non nested types this is the same as #BPy_IDGroup_WrapData.
+ */
PyObject *BPy_IDGroup_MapDataToPy(struct IDProperty *prop);
PyObject *BPy_IDGroup_WrapData(struct ID *id, struct IDProperty *prop, struct IDProperty *parent);
+/**
+ * \note group can be a pointer array or a group.
+ * assume we already checked key is a string.
+ *
+ * \return success.
+ */
bool BPy_IDProperty_Map_ValidateAndCreate(PyObject *key, struct IDProperty *group, PyObject *ob);
void IDProp_Init_Types(void);
diff --git a/source/blender/python/generic/py_capi_rna.c b/source/blender/python/generic/py_capi_rna.c
index 235b136ca74..a6a0d820d07 100644
--- a/source/blender/python/generic/py_capi_rna.c
+++ b/source/blender/python/generic/py_capi_rna.c
@@ -41,10 +41,6 @@
/** \name Enum Utilities
* \{ */
-/**
- * Convert all items into a single comma separated string.
- * Use for creating useful error messages.
- */
char *pyrna_enum_repr(const EnumPropertyItem *item)
{
DynStr *dynstr = BLI_dynstr_new();
@@ -69,9 +65,6 @@ char *pyrna_enum_repr(const EnumPropertyItem *item)
/** \name Enum Conversion Utilities
* \{ */
-/**
- * Same as #RNA_enum_value_from_id, but raises an exception.
- */
int pyrna_enum_value_from_id(const EnumPropertyItem *item,
const char *identifier,
int *r_value,
@@ -88,14 +81,6 @@ int pyrna_enum_value_from_id(const EnumPropertyItem *item,
return 0;
}
-/**
- * Takes a set of strings and map it to and array of booleans.
- *
- * Useful when the values aren't flags.
- *
- * \param type_convert_sign: Maps signed to unsigned range,
- * needed when we want to use the full range of a signed short/char.
- */
BLI_bitmap *pyrna_enum_bitmap_from_set(const EnumPropertyItem *items,
PyObject *value,
int type_size,
@@ -159,9 +144,6 @@ error:
return NULL;
}
-/**
- * 'value' _must_ be a set type, error check before calling.
- */
int pyrna_enum_bitfield_from_set(const EnumPropertyItem *items,
PyObject *value,
int *r_value,
@@ -223,9 +205,6 @@ PyObject *pyrna_enum_bitfield_as_set(const EnumPropertyItem *items, int value)
/** \name Argument Parsing Helpers
* \{ */
-/**
- * Use with #PyArg_ParseTuple's `O&` formatting.
- */
int pyrna_enum_value_parse_string(PyObject *o, void *p)
{
const char *identifier = PyUnicode_AsUTF8(o);
@@ -244,9 +223,6 @@ int pyrna_enum_value_parse_string(PyObject *o, void *p)
return 1;
}
-/**
- * Use with #PyArg_ParseTuple's `O&` formatting.
- */
int pyrna_enum_bitfield_parse_set(PyObject *o, void *p)
{
if (!PySet_Check(o)) {
diff --git a/source/blender/python/generic/py_capi_rna.h b/source/blender/python/generic/py_capi_rna.h
index 326ca777a4b..9733cb043ea 100644
--- a/source/blender/python/generic/py_capi_rna.h
+++ b/source/blender/python/generic/py_capi_rna.h
@@ -25,13 +25,28 @@
struct EnumPropertyItem;
+/**
+ * Convert all items into a single comma separated string.
+ * Use for creating useful error messages.
+ */
char *pyrna_enum_repr(const struct EnumPropertyItem *item);
+/**
+ * Same as #RNA_enum_value_from_id, but raises an exception.
+ */
int pyrna_enum_value_from_id(const struct EnumPropertyItem *item,
const char *identifier,
int *value,
const char *error_prefix);
+/**
+ * Takes a set of strings and map it to and array of booleans.
+ *
+ * Useful when the values aren't flags.
+ *
+ * \param type_convert_sign: Maps signed to unsigned range,
+ * needed when we want to use the full range of a signed short/char.
+ */
unsigned int *pyrna_enum_bitmap_from_set(const struct EnumPropertyItem *items,
PyObject *value,
int type_size,
@@ -39,6 +54,9 @@ unsigned int *pyrna_enum_bitmap_from_set(const struct EnumPropertyItem *items,
int bitmap_size,
const char *error_prefix);
+/**
+ * 'value' _must_ be a set type, error check before calling.
+ */
int pyrna_enum_bitfield_from_set(const struct EnumPropertyItem *items,
PyObject *value,
int *r_value,
@@ -62,5 +80,11 @@ struct BPy_EnumProperty_Parse {
int value;
bool is_set;
};
+/**
+ * Use with #PyArg_ParseTuple's `O&` formatting.
+ */
int pyrna_enum_value_parse_string(PyObject *o, void *p);
+/**
+ * Use with #PyArg_ParseTuple's `O&` formatting.
+ */
int pyrna_enum_bitfield_parse_set(PyObject *o, void *p);
diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c
index 9cccc2f608f..acb6d76f30b 100644
--- a/source/blender/python/generic/py_capi_utils.c
+++ b/source/blender/python/generic/py_capi_utils.c
@@ -470,10 +470,6 @@ PyObject *PyC_Tuple_PackArray_Multi_Bool(const bool *array, const int dims[], co
/** \name Tuple/List Filling
* \{ */
-/**
- * Caller needs to ensure tuple is uninitialized.
- * Handy for filling a tuple with None for eg.
- */
void PyC_Tuple_Fill(PyObject *tuple, PyObject *value)
{
const uint tot = PyTuple_GET_SIZE(tuple);
@@ -502,11 +498,6 @@ void PyC_List_Fill(PyObject *list, PyObject *value)
/** \name Bool/Enum Argument Parsing
* \{ */
-/**
- * Use with PyArg_ParseTuple's "O&" formatting.
- *
- * \see #PyC_Long_AsBool for a similar function to use outside of argument parsing.
- */
int PyC_ParseBool(PyObject *o, void *p)
{
bool *bool_p = p;
@@ -520,9 +511,6 @@ int PyC_ParseBool(PyObject *o, void *p)
return 1;
}
-/**
- * Use with PyArg_ParseTuple's "O&" formatting.
- */
int PyC_ParseStringEnum(PyObject *o, void *p)
{
struct PyC_StringEnum *e = p;
@@ -598,10 +586,6 @@ void PyC_ObSpit(const char *name, PyObject *var)
}
}
-/**
- * A version of #PyC_ObSpit that writes into a string (and doesn't take a name argument).
- * Use for logging.
- */
void PyC_ObSpitStr(char *result, size_t result_len, PyObject *var)
{
/* No name, creator of string can manage that. */
@@ -789,13 +773,6 @@ PyObject *PyC_FrozenSetFromStrings(const char **strings)
/** \name Exception Utilities
* \{ */
-/**
- * Similar to #PyErr_Format(),
- *
- * Implementation - we can't actually prepend the existing exception,
- * because it could have _any_ arguments given to it, so instead we get its
- * `__str__` output and raise our own exception including it.
- */
PyObject *PyC_Err_Format_Prefix(PyObject *exception_type_prefix, const char *format, ...)
{
PyObject *error_value_prefix;
@@ -835,10 +812,6 @@ PyObject *PyC_Err_SetString_Prefix(PyObject *exception_type_prefix, const char *
return PyC_Err_Format_Prefix(exception_type_prefix, "%s", str);
}
-/**
- * Use for Python callbacks run directly from C,
- * when we can't use normal methods of raising exceptions.
- */
void PyC_Err_PrintWithFunc(PyObject *py_func)
{
/* since we return to C code we can't leave the error */
@@ -1014,7 +987,6 @@ PyObject *PyC_ExceptionBuffer_Simple(void)
* In some cases we need to coerce strings, avoid doing this inline.
* \{ */
-/* string conversion, escape non-unicode chars, coerce must be set to NULL */
const char *PyC_UnicodeAsByteAndSize(PyObject *py_str, Py_ssize_t *size, PyObject **coerce)
{
const char *result;
@@ -1093,18 +1065,6 @@ PyObject *PyC_UnicodeFromByte(const char *str)
/** \name Name Space Creation/Manipulation
* \{ */
-/*****************************************************************************
- * Description: This function creates a new Python dictionary object.
- * NOTE: dict is owned by sys.modules["__main__"] module, reference is borrowed
- * NOTE: important we use the dict from __main__, this is what python expects
- * for 'pickle' to work as well as strings like this...
- * >> foo = 10
- * >> print(__import__("__main__").foo)
- *
- * NOTE: this overwrites __main__ which gives problems with nested calls.
- * be sure to run PyC_MainModule_Backup & PyC_MainModule_Restore if there is
- * any chance that python is in the call stack.
- ****************************************************************************/
PyObject *PyC_DefaultNameSpace(const char *filename)
{
PyObject *modules = PyImport_GetModuleDict();
@@ -1143,7 +1103,6 @@ bool PyC_NameSpace_ImportArray(PyObject *py_dict, const char *imports[])
return true;
}
-/* restore MUST be called after this */
void PyC_MainModule_Backup(PyObject **r_main_mod)
{
PyObject *modules = PyImport_GetModuleDict();
@@ -1468,11 +1427,6 @@ PyObject *PyC_FlagSet_FromBitfield(PyC_FlagSet *items, int flag)
/** \name Run String (Evaluate to Primitive Types)
* \{ */
-/**
- * \return success
- *
- * \note it is caller's responsibility to acquire & release GIL!
- */
bool PyC_RunString_AsNumber(const char *imports[],
const char *expr,
const char *filename,
@@ -1648,32 +1602,6 @@ bool PyC_RunString_AsString(const char *imports[],
# pragma GCC diagnostic ignored "-Wtype-limits"
#endif
-/**
- *
- * Comparison with #PyObject_IsTrue
- * ================================
- *
- * Even though Python provides a way to retrieve the boolean value for an object,
- * in many cases it's far too relaxed, with the following examples coercing values.
- *
- * \code{.py}
- * data.value = "Text" # True.
- * data.value = "" # False.
- * data.value = {1, 2} # True
- * data.value = {} # False.
- * data.value = None # False.
- * \endcode
- *
- * In practice this is often a mistake by the script author that doesn't behave as they expect.
- * So it's better to be more strict for attribute assignment and function arguments,
- * only accepting True/False 0/1.
- *
- * If coercing a value is desired, it can be done explicitly: `data.value = bool(value)`
- *
- * \see #PyC_ParseBool for use with #PyArg_ParseTuple and related functions.
- *
- * \note Don't use `bool` return type, so -1 can be used as an error value.
- */
int PyC_Long_AsBool(PyObject *value)
{
const int test = _PyLong_AsInt(value);
diff --git a/source/blender/python/generic/py_capi_utils.h b/source/blender/python/generic/py_capi_utils.h
index a8695d2330a..f6d8d7298af 100644
--- a/source/blender/python/generic/py_capi_utils.h
+++ b/source/blender/python/generic/py_capi_utils.h
@@ -26,6 +26,10 @@
#include "BLI_utildefines_variadic.h"
void PyC_ObSpit(const char *name, PyObject *var);
+/**
+ * A version of #PyC_ObSpit that writes into a string (and doesn't take a name argument).
+ * Use for logging.
+ */
void PyC_ObSpitStr(char *result, size_t result_len, PyObject *var);
void PyC_LineSpit(void);
void PyC_StackSpit(void);
@@ -34,9 +38,20 @@ PyObject *PyC_ExceptionBuffer_Simple(void);
PyObject *PyC_Object_GetAttrStringArgs(PyObject *o, Py_ssize_t n, ...);
PyObject *PyC_FrozenSetFromStrings(const char **strings);
+/**
+ * Similar to #PyErr_Format(),
+ *
+ * Implementation - we can't actually prepend the existing exception,
+ * because it could have _any_ arguments given to it, so instead we get its
+ * `__str__` output and raise our own exception including it.
+ */
PyObject *PyC_Err_Format_Prefix(PyObject *exception_type_prefix, const char *format, ...);
PyObject *PyC_Err_SetString_Prefix(PyObject *exception_type_prefix, const char *str);
+/**
+ * Use for Python callbacks run directly from C,
+ * when we can't use normal methods of raising exceptions.
+ */
void PyC_Err_PrintWithFunc(PyObject *py_func);
void PyC_FileAndNum(const char **r_filename, int *r_lineno);
@@ -92,6 +107,10 @@ PyObject *PyC_Tuple_PackArray_Multi_F64(const double *array, const int dims[], c
PyObject *PyC_Tuple_PackArray_Multi_I32(const int *array, const int dims[], const int dims_len);
PyObject *PyC_Tuple_PackArray_Multi_Bool(const bool *array, const int dims[], const int dims_len);
+/**
+ * Caller needs to ensure tuple is uninitialized.
+ * Handy for filling a tuple with None for eg.
+ */
void PyC_Tuple_Fill(PyObject *tuple, PyObject *value);
void PyC_List_Fill(PyObject *list, PyObject *value);
@@ -99,13 +118,39 @@ void PyC_List_Fill(PyObject *list, PyObject *value);
PyObject *PyC_UnicodeFromByte(const char *str);
PyObject *PyC_UnicodeFromByteAndSize(const char *str, Py_ssize_t size);
const char *PyC_UnicodeAsByte(PyObject *py_str, PyObject **coerce); /* coerce must be NULL */
+/**
+ * String conversion, escape non-unicode chars
+ * \param coerce: must be set to NULL.
+ */
const char *PyC_UnicodeAsByteAndSize(PyObject *py_str, Py_ssize_t *size, PyObject **coerce);
-/* name namespace function for bpy */
+/**
+ * Description: This function creates a new Python dictionary object.
+ * NOTE: dict is owned by sys.modules["__main__"] module, reference is borrowed
+ * NOTE: important we use the dict from __main__, this is what python expects
+ * for 'pickle' to work as well as strings like this...
+ * >> foo = 10
+ * >> print(__import__("__main__").foo)
+ *
+ * NOTE: this overwrites __main__ which gives problems with nested calls.
+ * be sure to run PyC_MainModule_Backup & PyC_MainModule_Restore if there is
+ * any chance that python is in the call stack.
+ */
PyObject *PyC_DefaultNameSpace(const char *filename);
void PyC_RunQuicky(const char *filepath, int n, ...);
+/**
+ * Import `imports` into `py_dict`.
+ *
+ * \param py_dict: A Python dictionary, typically used as a name-space for script execution.
+ * \param imports: A NULL terminated array of strings.
+ * \return true when all modules import without errors, otherwise return false.
+ * The caller is expected to handle the exception.
+ */
bool PyC_NameSpace_ImportArray(PyObject *py_dict, const char *imports[]);
+/**
+ * #PyC_MainModule_Restore MUST be called after #PyC_MainModule_Backup.
+ */
void PyC_MainModule_Backup(PyObject **r_main_mod);
void PyC_MainModule_Restore(PyObject *main_mod);
@@ -131,6 +176,11 @@ int PyC_FlagSet_ToBitfield(const PyC_FlagSet *items,
const char *error_prefix);
PyObject *PyC_FlagSet_FromBitfield(PyC_FlagSet *items, int flag);
+/**
+ * \return success
+ *
+ * \note it is caller's responsibility to acquire & release GIL!
+ */
bool PyC_RunString_AsNumber(const char **imports,
const char *expr,
const char *filename,
@@ -149,6 +199,11 @@ bool PyC_RunString_AsString(const char **imports,
const char *filename,
char **r_value);
+/**
+ * Use with PyArg_ParseTuple's "O&" formatting.
+ *
+ * \see #PyC_Long_AsBool for a similar function to use outside of argument parsing.
+ */
int PyC_ParseBool(PyObject *o, void *p);
struct PyC_StringEnumItems {
@@ -160,6 +215,9 @@ struct PyC_StringEnum {
int value_found;
};
+/**
+ * Use with PyArg_ParseTuple's "O&" formatting.
+ */
int PyC_ParseStringEnum(PyObject *o, void *p);
const char *PyC_StringEnum_FindIDFromValue(const struct PyC_StringEnumItems *items,
const int value);
@@ -167,6 +225,32 @@ const char *PyC_StringEnum_FindIDFromValue(const struct PyC_StringEnumItems *ite
int PyC_CheckArgs_DeepCopy(PyObject *args);
/* Integer parsing (with overflow checks), -1 on error. */
+/**
+ *
+ * Comparison with #PyObject_IsTrue
+ * ================================
+ *
+ * Even though Python provides a way to retrieve the boolean value for an object,
+ * in many cases it's far too relaxed, with the following examples coercing values.
+ *
+ * \code{.py}
+ * data.value = "Text" # True.
+ * data.value = "" # False.
+ * data.value = {1, 2} # True
+ * data.value = {} # False.
+ * data.value = None # False.
+ * \endcode
+ *
+ * In practice this is often a mistake by the script author that doesn't behave as they expect.
+ * So it's better to be more strict for attribute assignment and function arguments,
+ * only accepting True/False 0/1.
+ *
+ * If coercing a value is desired, it can be done explicitly: `data.value = bool(value)`
+ *
+ * \see #PyC_ParseBool for use with #PyArg_ParseTuple and related functions.
+ *
+ * \note Don't use `bool` return type, so -1 can be used as an error value.
+ */
int PyC_Long_AsBool(PyObject *value);
int8_t PyC_Long_AsI8(PyObject *value);
int16_t PyC_Long_AsI16(PyObject *value);
diff --git a/source/blender/python/generic/python_utildefines.h b/source/blender/python/generic/python_utildefines.h
index 1f093e633e4..25300c2fd45 100644
--- a/source/blender/python/generic/python_utildefines.h
+++ b/source/blender/python/generic/python_utildefines.h
@@ -36,16 +36,20 @@ extern "C" {
} \
(void)0
-/* wrap Py_INCREF & return the result,
- * use sparingly to avoid comma operator or temp var assignment */
+/**
+ * Wrap #Py_INCREF & return the result,
+ * use sparingly to avoid comma operator or temp var assignment.
+ */
Py_LOCAL_INLINE(PyObject *) Py_INCREF_RET(PyObject *op)
{
Py_INCREF(op);
return op;
}
-/* Append & transfer ownership to the list,
- * avoids inline Py_DECREF all over (which is quite a large macro). */
+/**
+ * Append & transfer ownership to the list,
+ * avoids inline #Py_DECREF all over (which is quite a large macro).
+ */
Py_LOCAL_INLINE(int) PyList_APPEND(PyObject *op, PyObject *v)
{
int ret = PyList_Append(op, v);
diff --git a/source/blender/python/gpu/gpu_py.c b/source/blender/python/gpu/gpu_py.c
index e6ba46b2b05..a2d4b0e1031 100644
--- a/source/blender/python/gpu/gpu_py.c
+++ b/source/blender/python/gpu/gpu_py.c
@@ -58,6 +58,7 @@ struct PyC_StringEnumItems bpygpu_dataformat_items[] = {
{GPU_DATA_10_11_11_REV, "10_11_11_REV"},
{0, NULL},
};
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/python/gpu/gpu_py_buffer.c b/source/blender/python/gpu/gpu_py_buffer.c
index abfde7b48c8..f074b51af32 100644
--- a/source/blender/python/gpu/gpu_py_buffer.c
+++ b/source/blender/python/gpu/gpu_py_buffer.c
@@ -687,13 +687,6 @@ size_t bpygpu_Buffer_size(BPyGPUBuffer *buffer)
return pygpu_buffer_calc_size(buffer->format, buffer->shape_len, buffer->shape);
}
-/**
- * Create a buffer object
- *
- * \param shape: An array of `shape_len` integers representing the size of each dimension.
- * \param buffer: When not NULL holds a contiguous buffer
- * with the correct format from which the buffer will be initialized
- */
BPyGPUBuffer *BPyGPU_Buffer_CreatePyObject(const int format,
const Py_ssize_t *shape,
const int shape_len,
diff --git a/source/blender/python/gpu/gpu_py_buffer.h b/source/blender/python/gpu/gpu_py_buffer.h
index 9df22e9b780..cbc46339628 100644
--- a/source/blender/python/gpu/gpu_py_buffer.h
+++ b/source/blender/python/gpu/gpu_py_buffer.h
@@ -48,6 +48,13 @@ typedef struct BPyGPUBuffer {
} BPyGPUBuffer;
size_t bpygpu_Buffer_size(BPyGPUBuffer *buffer);
+/**
+ * Create a buffer object
+ *
+ * \param shape: An array of `shape_len` integers representing the size of each dimension.
+ * \param buffer: When not NULL holds a contiguous buffer
+ * with the correct format from which the buffer will be initialized
+ */
BPyGPUBuffer *BPyGPU_Buffer_CreatePyObject(const int format,
const Py_ssize_t *shape,
const int shape_len,
diff --git a/source/blender/python/gpu/gpu_py_offscreen.c b/source/blender/python/gpu/gpu_py_offscreen.c
index 6f23c2213e2..48fbe09f0ce 100644
--- a/source/blender/python/gpu/gpu_py_offscreen.c
+++ b/source/blender/python/gpu/gpu_py_offscreen.c
@@ -44,6 +44,7 @@
#include "GPU_context.h"
#include "GPU_framebuffer.h"
#include "GPU_texture.h"
+#include "GPU_viewport.h"
#include "ED_view3d.h"
#include "ED_view3d_offscreen.h"
@@ -355,6 +356,15 @@ static PyObject *pygpu_offscreen_draw_view3d(BPyGPUOffScreen *self, PyObject *ar
GPU_offscreen_bind(self->ofs, true);
+ /* Cache the #GPUViewport so the frame-buffers and associated textures are
+ * not reallocated each time, see: T89204 */
+ if (!self->viewport) {
+ self->viewport = GPU_viewport_create();
+ }
+ else {
+ GPU_viewport_tag_update(self->viewport);
+ }
+
ED_view3d_draw_offscreen(depsgraph,
scene,
v3d->shading.type,
@@ -370,7 +380,7 @@ static PyObject *pygpu_offscreen_draw_view3d(BPyGPUOffScreen *self, PyObject *ar
do_color_management,
true,
self->ofs,
- NULL);
+ self->viewport);
GPU_offscreen_unbind(self->ofs, true);
@@ -391,6 +401,11 @@ static PyObject *pygpu_offscreen_free(BPyGPUOffScreen *self)
{
BPY_GPU_OFFSCREEN_CHECK_OBJ(self);
+ if (self->viewport) {
+ GPU_viewport_free(self->viewport);
+ self->viewport = NULL;
+ }
+
GPU_offscreen_free(self->ofs);
self->ofs = NULL;
Py_RETURN_NONE;
@@ -399,6 +414,9 @@ static PyObject *pygpu_offscreen_free(BPyGPUOffScreen *self)
static void BPyGPUOffScreen__tp_dealloc(BPyGPUOffScreen *self)
{
+ if (self->viewport) {
+ GPU_viewport_free(self->viewport);
+ }
if (self->ofs) {
GPU_offscreen_free(self->ofs);
}
@@ -469,6 +487,7 @@ PyObject *BPyGPUOffScreen_CreatePyObject(GPUOffScreen *ofs)
self = PyObject_New(BPyGPUOffScreen, &BPyGPUOffScreen_Type);
self->ofs = ofs;
+ self->viewport = NULL;
return (PyObject *)self;
}
diff --git a/source/blender/python/gpu/gpu_py_offscreen.h b/source/blender/python/gpu/gpu_py_offscreen.h
index 309735a6202..78bad595a3d 100644
--- a/source/blender/python/gpu/gpu_py_offscreen.h
+++ b/source/blender/python/gpu/gpu_py_offscreen.h
@@ -26,9 +26,13 @@ extern PyTypeObject BPyGPUOffScreen_Type;
#define BPyGPUOffScreen_Check(v) (Py_TYPE(v) == &BPyGPUOffScreen_Type)
+struct GPUOffscreen;
+struct GPUViewport;
+
typedef struct BPyGPUOffScreen {
PyObject_HEAD
struct GPUOffScreen *ofs;
+ struct GPUViewport *viewport;
} BPyGPUOffScreen;
PyObject *BPyGPUOffScreen_CreatePyObject(struct GPUOffScreen *ofs) ATTR_NONNULL(1);
diff --git a/source/blender/python/gpu/gpu_py_select.c b/source/blender/python/gpu/gpu_py_select.c
index 4db102118f1..43980530f38 100644
--- a/source/blender/python/gpu/gpu_py_select.c
+++ b/source/blender/python/gpu/gpu_py_select.c
@@ -56,6 +56,7 @@ static PyObject *pygpu_select_load_id(PyObject *UNUSED(self), PyObject *value)
GPU_select_load_id(id);
Py_RETURN_NONE;
}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/python/gpu/gpu_py_texture.c b/source/blender/python/gpu/gpu_py_texture.c
index c034c31d828..66b9cf5e86e 100644
--- a/source/blender/python/gpu/gpu_py_texture.c
+++ b/source/blender/python/gpu/gpu_py_texture.c
@@ -527,6 +527,7 @@ PyTypeObject BPyGPUTexture_Type = {
/* -------------------------------------------------------------------- */
/** \name GPU Texture module
* \{ */
+
PyDoc_STRVAR(pygpu_texture_from_image_doc,
".. function:: from_image(image)\n"
"\n"
diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c
index 3377b2c283e..c792773272b 100644
--- a/source/blender/python/intern/bpy.c
+++ b/source/blender/python/intern/bpy.c
@@ -94,10 +94,13 @@ static PyObject *bpy_script_paths(PyObject *UNUSED(self))
return ret;
}
-static bool bpy_blend_paths_visit_cb(void *userdata, char *UNUSED(path_dst), const char *path_src)
+static bool bpy_blend_foreach_path_cb(BPathForeachPathData *bpath_data,
+ char *UNUSED(path_dst),
+ const char *path_src)
{
- PyList_APPEND((PyObject *)userdata, PyC_UnicodeFromByte(path_src));
- return false; /* never edits the path */
+ PyObject *py_list = bpath_data->user_data;
+ PyList_APPEND(py_list, PyC_UnicodeFromByte(path_src));
+ return false; /* Never edits the path. */
}
PyDoc_STRVAR(bpy_blend_paths_doc,
@@ -115,7 +118,7 @@ PyDoc_STRVAR(bpy_blend_paths_doc,
" :rtype: list of strings\n");
static PyObject *bpy_blend_paths(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
- int flag = 0;
+ eBPathForeachFlag flag = 0;
PyObject *list;
bool absolute = false;
@@ -137,18 +140,23 @@ static PyObject *bpy_blend_paths(PyObject *UNUSED(self), PyObject *args, PyObjec
}
if (absolute) {
- flag |= BKE_BPATH_TRAVERSE_ABS;
+ flag |= BKE_BPATH_FOREACH_PATH_ABSOLUTE;
}
if (!packed) {
- flag |= BKE_BPATH_TRAVERSE_SKIP_PACKED;
+ flag |= BKE_BPATH_FOREACH_PATH_SKIP_PACKED;
}
if (local) {
- flag |= BKE_BPATH_TRAVERSE_SKIP_LIBRARY;
+ flag |= BKE_BPATH_FOREACH_PATH_SKIP_LINKED;
}
list = PyList_New(0);
- BKE_bpath_traverse_main(G_MAIN, bpy_blend_paths_visit_cb, flag, (void *)list);
+ BKE_bpath_foreach_path_main(&(BPathForeachPathData){
+ .bmain = G_MAIN,
+ .callback_function = bpy_blend_foreach_path_cb,
+ .flag = flag,
+ .user_data = list,
+ });
return list;
}
@@ -442,9 +450,6 @@ static PyObject *bpy_import_test(const char *modname)
return mod;
}
-/******************************************************************************
- * Description: Creates the bpy module and adds it to sys.modules for importing
- ******************************************************************************/
void BPy_init_modules(struct bContext *C)
{
PointerRNA ctx_ptr;
diff --git a/source/blender/python/intern/bpy.h b/source/blender/python/intern/bpy.h
index 25a047edfb5..b77a3e9fb7d 100644
--- a/source/blender/python/intern/bpy.h
+++ b/source/blender/python/intern/bpy.h
@@ -26,7 +26,9 @@ extern "C" {
struct bContext;
+/** Creates the bpy module and adds it to `sys.modules` for importing. */
void BPy_init_modules(struct bContext *C);
+
extern PyObject *bpy_package_py;
/* bpy_interface_atexit.c */
diff --git a/source/blender/python/intern/bpy_app_translations.c b/source/blender/python/intern/bpy_app_translations.c
index de70035eb2b..4fa71c0c976 100644
--- a/source/blender/python/intern/bpy_app_translations.c
+++ b/source/blender/python/intern/bpy_app_translations.c
@@ -69,12 +69,12 @@ static BlenderAppTranslations *_translations = NULL;
/** \} */
-#ifdef WITH_INTERNATIONAL
-
/* ------------------------------------------------------------------- */
/** \name Helpers for GHash
* \{ */
+#ifdef WITH_INTERNATIONAL
+
typedef struct GHashKey {
const char *msgctxt;
const char *msgid;
diff --git a/source/blender/python/intern/bpy_capi_utils.c b/source/blender/python/intern/bpy_capi_utils.c
index 8e9d8c02c03..ed01132ed4e 100644
--- a/source/blender/python/intern/bpy_capi_utils.c
+++ b/source/blender/python/intern/bpy_capi_utils.c
@@ -56,9 +56,6 @@ short BPy_reports_to_error(ReportList *reports, PyObject *exception, const bool
return (report_str == NULL) ? 0 : -1;
}
-/**
- * A version of #BKE_report_write_file_fp that uses Python's stdout.
- */
void BPy_reports_write_stdout(const ReportList *reports, const char *header)
{
if (header) {
diff --git a/source/blender/python/intern/bpy_capi_utils.h b/source/blender/python/intern/bpy_capi_utils.h
index 80e92d918ac..0e4a28fb657 100644
--- a/source/blender/python/intern/bpy_capi_utils.h
+++ b/source/blender/python/intern/bpy_capi_utils.h
@@ -33,6 +33,9 @@ struct ReportList;
/* error reporting */
short BPy_reports_to_error(struct ReportList *reports, PyObject *exception, const bool clear);
+/**
+ * A version of #BKE_report_write_file_fp that uses Python's stdout.
+ */
void BPy_reports_write_stdout(const struct ReportList *reports, const char *header);
bool BPy_errors_to_report_ex(struct ReportList *reports,
const char *error_prefix,
@@ -44,6 +47,9 @@ bool BPy_errors_to_report(struct ReportList *reports);
struct bContext *BPY_context_get(void);
extern void bpy_context_set(struct bContext *C, PyGILState_STATE *gilstate);
+/**
+ * Context should be used but not now because it causes some bugs.
+ */
extern void bpy_context_clear(struct bContext *C, const PyGILState_STATE *gilstate);
#ifdef __cplusplus
diff --git a/source/blender/python/intern/bpy_driver.c b/source/blender/python/intern/bpy_driver.c
index 7effa25e6e8..bd1f3cd301f 100644
--- a/source/blender/python/intern/bpy_driver.c
+++ b/source/blender/python/intern/bpy_driver.c
@@ -57,19 +57,12 @@
# include <opcode.h>
#endif
-/**
- * For PyDrivers
- * (drivers using one-line Python expressions to express relationships between targets).
- */
PyObject *bpy_pydriver_Dict = NULL;
#ifdef USE_BYTECODE_WHITELIST
static PyObject *bpy_pydriver_Dict__whitelist = NULL;
#endif
-/* For faster execution we keep a special dictionary for pydrivers, with
- * the needed modules and aliases.
- */
int bpy_pydriver_create_dict(void)
{
PyObject *d, *mod;
@@ -220,11 +213,6 @@ static void bpy_pydriver_namespace_clear_self(void)
}
}
-/* Update function, it gets rid of pydrivers global dictionary, forcing
- * BPY_driver_exec to recreate it. This function is used to force
- * reloading the Blender text module "pydrivers.py", if available, so
- * updates in it reach pydriver evaluation.
- */
void BPY_driver_reset(void)
{
PyGILState_STATE gilstate;
@@ -429,28 +417,24 @@ static void bpy_pydriver_namespace_add_depsgraph(PyObject *driver_vars,
}
}
-/**
- * This evaluates Python driver expressions, `driver_orig->expression`
- * is a Python expression that should evaluate to a float number, which is returned.
- *
- * (old) NOTE: PyGILState_Ensure() isn't always called because python can call
- * the bake operator which intern starts a thread which calls scene update
- * which does a driver update. to avoid a deadlock check #PyC_IsInterpreterActive()
- * if #PyGILState_Ensure() is needed, see T27683.
- *
- * (new) NOTE: checking if python is running is not thread-safe T28114
- * now release the GIL on python operator execution instead, using
- * #PyEval_SaveThread() / #PyEval_RestoreThread() so we don't lock up blender.
- *
- * For copy-on-write we always cache expressions and write errors in the
- * original driver, otherwise these would get freed while editing. Due to
- * the GIL this is thread-safe.
- */
float BPY_driver_exec(struct PathResolvedRNA *anim_rna,
ChannelDriver *driver,
ChannelDriver *driver_orig,
const AnimationEvalContext *anim_eval_context)
{
+ /* (old) NOTE: PyGILState_Ensure() isn't always called because python can call
+ * the bake operator which intern starts a thread which calls scene update
+ * which does a driver update. to avoid a deadlock check #PyC_IsInterpreterActive()
+ * if #PyGILState_Ensure() is needed, see T27683.
+ *
+ * (new) NOTE: checking if python is running is not thread-safe T28114
+ * now release the GIL on python operator execution instead, using
+ * #PyEval_SaveThread() / #PyEval_RestoreThread() so we don't lock up blender.
+ *
+ * For copy-on-write we always cache expressions and write errors in the
+ * original driver, otherwise these would get freed while editing.
+ * Due to the GIL this is thread-safe. */
+
PyObject *driver_vars = NULL;
PyObject *retval = NULL;
diff --git a/source/blender/python/intern/bpy_driver.h b/source/blender/python/intern/bpy_driver.h
index d5064d9fa56..b7bb0f846e8 100644
--- a/source/blender/python/intern/bpy_driver.h
+++ b/source/blender/python/intern/bpy_driver.h
@@ -24,7 +24,15 @@
extern "C" {
#endif
+/**
+ * For faster execution we keep a special dictionary for py-drivers, with
+ * the needed modules and aliases.
+ */
int bpy_pydriver_create_dict(void);
+/**
+ * For PyDrivers
+ * (drivers using one-line Python expressions to express relationships between targets).
+ */
extern PyObject *bpy_pydriver_Dict;
#ifdef __cplusplus
diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c
index 95affa9dba9..faa668df775 100644
--- a/source/blender/python/intern/bpy_interface.c
+++ b/source/blender/python/intern/bpy_interface.c
@@ -80,6 +80,7 @@
#include "../mathutils/mathutils.h"
/* Logging types to use anywhere in the Python modules. */
+
CLG_LOGREF_DECLARE_GLOBAL(BPY_LOG_CONTEXT, "bpy.context");
CLG_LOGREF_DECLARE_GLOBAL(BPY_LOG_INTERFACE, "bpy.interface");
CLG_LOGREF_DECLARE_GLOBAL(BPY_LOG_RNA, "bpy.rna");
@@ -103,7 +104,6 @@ static double bpy_timer_run; /* time for each python script run */
static double bpy_timer_run_tot; /* accumulate python runs */
#endif
-/* use for updating while a python script runs - in case of file load */
void BPY_context_update(bContext *C)
{
/* don't do this from a non-main (e.g. render) thread, it can cause a race
@@ -141,7 +141,6 @@ void bpy_context_set(bContext *C, PyGILState_STATE *gilstate)
}
}
-/* context should be used but not now because it causes some bugs */
void bpy_context_clear(bContext *UNUSED(C), const PyGILState_STATE *gilstate)
{
py_call_level--;
@@ -175,16 +174,6 @@ static void bpy_context_end(bContext *C)
CTX_wm_operator_poll_msg_clear(C);
}
-/**
- * Use for `CTX_*_set(..)` functions need to set values which are later read back as expected.
- * In this case we don't want the Python context to override the values as it causes problems
- * see T66256.
- *
- * \param dict_p: A pointer to #bContext.data.py_context so we can assign a new value.
- * \param dict_orig: The value of #bContext.data.py_context_orig to check if we need to copy.
- *
- * \note Typically accessed via #BPY_context_dict_clear_members macro.
- */
void BPY_context_dict_clear_members_array(void **dict_p,
void *dict_orig,
const char *context_members[],
@@ -238,9 +227,6 @@ void BPY_text_free_code(Text *text)
}
}
-/**
- * Needed so the #Main pointer in `bpy.data` doesn't become out of date.
- */
void BPY_modules_update(void)
{
#if 0 /* slow, this runs all the time poll, draw etc 100's of time a sec. */
@@ -333,7 +319,6 @@ static void pystatus_exit_on_error(PyStatus status)
}
#endif
-/* call BPY_context_set first */
void BPY_python_start(bContext *C, int argc, const char **argv)
{
#ifndef WITH_PYTHON_MODULE
@@ -881,9 +866,6 @@ static void bpy_module_free(void *UNUSED(mod))
#endif
-/**
- * Avoids duplicating keyword list.
- */
bool BPY_string_is_keyword(const char *str)
{
/* list is from...
@@ -905,8 +887,7 @@ bool BPY_string_is_keyword(const char *str)
return false;
}
-/* EVIL, define text.c functions here... */
-/* BKE_text.h */
+/* EVIL: define `text.c` functions here (declared in `BKE_text.h`). */
int text_check_identifier_unicode(const uint ch)
{
return (ch < 255 && text_check_identifier((char)ch)) || Py_UNICODE_ISALNUM(ch);
diff --git a/source/blender/python/intern/bpy_interface_run.c b/source/blender/python/intern/bpy_interface_run.c
index f7d6a33c904..bc21c91074f 100644
--- a/source/blender/python/intern/bpy_interface_run.c
+++ b/source/blender/python/intern/bpy_interface_run.c
@@ -80,6 +80,14 @@ typedef struct {
} PyModuleObject;
#endif
+/**
+ * Execute a file-path or text-block.
+ *
+ * \param reports: Report exceptions as errors (may be NULL).
+ * \param do_jump: See #BPY_run_text.
+ *
+ * \note Share a function for this since setup/cleanup logic is the same.
+ */
static bool python_script_exec(
bContext *C, const char *fn, struct Text *text, struct ReportList *reports, const bool do_jump)
{
@@ -212,7 +220,6 @@ static bool python_script_exec(
/** \name Run Text / Filename / String
* \{ */
-/* Can run a file or text block */
bool BPY_run_filepath(bContext *C, const char *filepath, struct ReportList *reports)
{
return python_script_exec(C, filepath, NULL, reports, false);
@@ -271,17 +278,11 @@ static bool bpy_run_string_impl(bContext *C,
return ok;
}
-/**
- * Run an expression, matches: `exec(compile(..., "eval"))`
- */
bool BPY_run_string_eval(bContext *C, const char *imports[], const char *expr)
{
return bpy_run_string_impl(C, imports, expr, Py_eval_input);
}
-/**
- * Run an entire script, matches: `exec(compile(..., "exec"))`
- */
bool BPY_run_string_exec(bContext *C, const char *imports[], const char *expr)
{
return bpy_run_string_impl(C, imports, expr, Py_file_input);
@@ -330,9 +331,6 @@ static void run_string_handle_error(struct BPy_RunErrInfo *err_info)
Py_XDECREF(py_err_str);
}
-/**
- * \return success
- */
bool BPY_run_string_as_number(bContext *C,
const char *imports[],
const char *expr,
@@ -342,10 +340,6 @@ bool BPY_run_string_as_number(bContext *C,
PyGILState_STATE gilstate;
bool ok = true;
- if (!r_value || !expr) {
- return -1;
- }
-
if (expr[0] == '\0') {
*r_value = 0.0;
return ok;
@@ -364,9 +358,6 @@ bool BPY_run_string_as_number(bContext *C,
return ok;
}
-/**
- * \return success
- */
bool BPY_run_string_as_string_and_size(bContext *C,
const char *imports[],
const char *expr,
@@ -374,7 +365,6 @@ bool BPY_run_string_as_string_and_size(bContext *C,
char **r_value,
size_t *r_value_size)
{
- BLI_assert(r_value && expr);
PyGILState_STATE gilstate;
bool ok = true;
@@ -406,18 +396,12 @@ bool BPY_run_string_as_string(bContext *C,
return BPY_run_string_as_string_and_size(C, imports, expr, err_info, r_value, &value_dummy_size);
}
-/**
- * Support both int and pointers.
- *
- * \return success
- */
bool BPY_run_string_as_intptr(bContext *C,
const char *imports[],
const char *expr,
struct BPy_RunErrInfo *err_info,
intptr_t *r_value)
{
- BLI_assert(r_value && expr);
PyGILState_STATE gilstate;
bool ok = true;
diff --git a/source/blender/python/intern/bpy_library_load.c b/source/blender/python/intern/bpy_library_load.c
index 059d692a9ba..fe279c0b940 100644
--- a/source/blender/python/intern/bpy_library_load.c
+++ b/source/blender/python/intern/bpy_library_load.c
@@ -34,6 +34,7 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
+#include "BKE_blendfile_link_append.h"
#include "BKE_context.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
@@ -346,11 +347,63 @@ static void bpy_lib_exit_warn_type(BPy_Library *self, PyObject *item)
PyErr_Restore(exc, val, tb);
}
+struct LibExitLappContextItemsIterData {
+ short idcode;
+ BPy_Library *py_library;
+ PyObject *py_list;
+ Py_ssize_t py_list_size;
+};
+
+static bool bpy_lib_exit_lapp_context_items_cb(BlendfileLinkAppendContext *lapp_context,
+ BlendfileLinkAppendContextItem *item,
+ void *userdata)
+{
+ struct LibExitLappContextItemsIterData *data = userdata;
+
+ /* Since `bpy_lib_exit` loops over all ID types, all items in `lapp_context` end up being looped
+ * over for each ID type, so when it does not match the item can simply be skipped: it either has
+ * already been processed, or will be processed in a later loop. */
+ if (BKE_blendfile_link_append_context_item_idcode_get(lapp_context, item) != data->idcode) {
+ return true;
+ }
+
+ const int py_list_index = POINTER_AS_INT(
+ BKE_blendfile_link_append_context_item_userdata_get(lapp_context, item));
+ ID *new_id = BKE_blendfile_link_append_context_item_newid_get(lapp_context, item);
+
+ BLI_assert(py_list_index < data->py_list_size);
+
+ /* Fully invalid items (which got set to `Py_None` already in first loop of `bpy_lib_exit`)
+ * should never be accessed here, since their index should never be set to any item in
+ * `lapp_context`. */
+ PyObject *item_src = PyList_GET_ITEM(data->py_list, py_list_index);
+ BLI_assert(item_src != Py_None);
+
+ PyObject *py_item;
+ if (new_id != NULL) {
+ PointerRNA newid_ptr;
+ RNA_id_pointer_create(new_id, &newid_ptr);
+ py_item = pyrna_struct_CreatePyObject(&newid_ptr);
+ }
+ else {
+ const char *item_idname = PyUnicode_AsUTF8(item_src);
+ const char *idcode_name_plural = BKE_idtype_idcode_to_name_plural(data->idcode);
+
+ bpy_lib_exit_warn_idname(data->py_library, idcode_name_plural, item_idname);
+
+ py_item = Py_INCREF_RET(Py_None);
+ }
+
+ PyList_SET_ITEM(data->py_list, py_list_index, py_item);
+
+ Py_DECREF(item_src);
+
+ return true;
+}
+
static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args))
{
Main *bmain = self->bmain;
- Main *mainl = NULL;
- const int err = 0;
const bool do_append = ((self->flag & FILE_LINK) == 0);
BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
@@ -360,134 +413,100 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args))
struct LibraryLink_Params liblink_params;
BLO_library_link_params_init(&liblink_params, bmain, self->flag, id_tag_extra);
- mainl = BLO_library_link_begin(&(self->blo_handle), self->relpath, &liblink_params);
-
- {
- int idcode_step = 0, idcode;
- while ((idcode = BKE_idtype_idcode_iter_step(&idcode_step))) {
- if (BKE_idtype_idcode_is_linkable(idcode) && (idcode != ID_WS || do_append)) {
- const char *name_plural = BKE_idtype_idcode_to_name_plural(idcode);
- PyObject *ls = PyDict_GetItemString(self->dict, name_plural);
- // printf("lib: %s\n", name_plural);
- if (ls && PyList_Check(ls)) {
- /* loop */
- const Py_ssize_t size = PyList_GET_SIZE(ls);
- Py_ssize_t i;
-
- for (i = 0; i < size; i++) {
- PyObject *item_src = PyList_GET_ITEM(ls, i);
- PyObject *item_dst; /* must be set below */
- const char *item_idname = PyUnicode_AsUTF8(item_src);
-
- // printf(" %s\n", item_idname);
-
- if (item_idname) {
- ID *id = BLO_library_link_named_part(
- mainl, &(self->blo_handle), idcode, item_idname, &liblink_params);
- if (id) {
-
- if (self->bmain_is_temp) {
- /* If this fails, #LibraryLink_Params.id_tag_extra is not being applied. */
- BLI_assert(id->tag & LIB_TAG_TEMP_MAIN);
- }
+ BlendfileLinkAppendContext *lapp_context = BKE_blendfile_link_append_context_new(
+ &liblink_params);
+ BKE_blendfile_link_append_context_library_add(lapp_context, self->abspath, self->blo_handle);
-#ifdef USE_RNA_DATABLOCKS
- /* swap name for pointer to the id */
- item_dst = PyCapsule_New((void *)id, NULL, NULL);
-#else
- /* leave as is */
- continue;
-#endif
- }
- else {
- bpy_lib_exit_warn_idname(self, name_plural, item_idname);
- /* just warn for now */
- /* err = -1; */
- item_dst = Py_INCREF_RET(Py_None);
- }
-
- /* ID or None */
- }
- else {
- /* XXX, could complain about this */
- bpy_lib_exit_warn_type(self, item_src);
- PyErr_Clear();
- item_dst = Py_INCREF_RET(Py_None);
- }
-
- /* item_dst must be new or already incref'd */
- Py_DECREF(item_src);
- PyList_SET_ITEM(ls, i, item_dst);
- }
- }
- }
+ int idcode_step = 0;
+ short idcode;
+ while ((idcode = BKE_idtype_idcode_iter_step(&idcode_step))) {
+ if (!BKE_idtype_idcode_is_linkable(idcode) || (idcode == ID_WS && !do_append)) {
+ continue;
}
- }
- if (err == -1) {
- /* exception raised above, XXX, this leaks some memory */
- BLO_blendhandle_close(self->blo_handle);
- self->blo_handle = NULL;
- BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
- return NULL;
- }
+ const char *name_plural = BKE_idtype_idcode_to_name_plural(idcode);
+ PyObject *ls = PyDict_GetItemString(self->dict, name_plural);
+ // printf("lib: %s\n", name_plural);
+ if (ls == NULL || !PyList_Check(ls)) {
+ continue;
+ }
- Library *lib = mainl->curlib; /* newly added lib, assign before append end */
- BLO_library_link_end(mainl, &(self->blo_handle), &liblink_params);
- BLO_blendhandle_close(self->blo_handle);
- self->blo_handle = NULL;
+ const Py_ssize_t size = PyList_GET_SIZE(ls);
+ if (size == 0) {
+ continue;
+ }
- GHash *old_to_new_ids = BLI_ghash_ptr_new(__func__);
+ /* loop */
+ for (Py_ssize_t i = 0; i < size; i++) {
+ PyObject *item_src = PyList_GET_ITEM(ls, i);
+ const char *item_idname = PyUnicode_AsUTF8(item_src);
- /* copied from wm_operator.c */
- {
- /* mark all library linked objects to be updated */
- BKE_main_lib_objects_recalc_all(bmain);
+ // printf(" %s\n", item_idname);
- /* append, rather than linking */
- if (do_append) {
- BKE_library_make_local(bmain, lib, old_to_new_ids, true, false);
+ /* NOTE: index of item in py list is stored in userdata pointer, so that it can be found
+ * later on to replace the ID name by the actual ID pointer. */
+ if (item_idname != NULL) {
+ BlendfileLinkAppendContextItem *item = BKE_blendfile_link_append_context_item_add(
+ lapp_context, item_idname, idcode, POINTER_FROM_INT(i));
+ BKE_blendfile_link_append_context_item_library_index_enable(lapp_context, item, 0);
+ }
+ else {
+ /* XXX, could complain about this */
+ bpy_lib_exit_warn_type(self, item_src);
+ PyErr_Clear();
+
+#ifdef USE_RNA_DATABLOCKS
+ /* We can replace the item immediately with `None`. */
+ PyObject *py_item = Py_INCREF_RET(Py_None);
+ PyList_SET_ITEM(ls, i, py_item);
+ Py_DECREF(item_src);
+#endif
+ }
}
}
- BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
+ BKE_blendfile_link(lapp_context, NULL);
+ if (do_append) {
+ BKE_blendfile_append(lapp_context, NULL);
+ }
- /* finally swap the capsules for real bpy objects
- * important since BLO_library_append_end initializes NodeTree types used by srna->refine */
+ /* If enabled, replace named items in given lists by the final matching new ID pointer. */
#ifdef USE_RNA_DATABLOCKS
- {
- int idcode_step = 0, idcode;
- while ((idcode = BKE_idtype_idcode_iter_step(&idcode_step))) {
- if (BKE_idtype_idcode_is_linkable(idcode) && (idcode != ID_WS || do_append)) {
- const char *name_plural = BKE_idtype_idcode_to_name_plural(idcode);
- PyObject *ls = PyDict_GetItemString(self->dict, name_plural);
- if (ls && PyList_Check(ls)) {
- const Py_ssize_t size = PyList_GET_SIZE(ls);
- Py_ssize_t i;
- PyObject *item;
-
- for (i = 0; i < size; i++) {
- item = PyList_GET_ITEM(ls, i);
- if (PyCapsule_CheckExact(item)) {
- PointerRNA id_ptr;
- ID *id;
-
- id = PyCapsule_GetPointer(item, NULL);
- id = BLI_ghash_lookup_default(old_to_new_ids, id, id);
- Py_DECREF(item);
-
- RNA_id_pointer_create(id, &id_ptr);
- item = pyrna_struct_CreatePyObject(&id_ptr);
- PyList_SET_ITEM(ls, i, item);
- }
- }
- }
- }
+ idcode_step = 0;
+ while ((idcode = BKE_idtype_idcode_iter_step(&idcode_step))) {
+ if (!BKE_idtype_idcode_is_linkable(idcode) || (idcode == ID_WS && !do_append)) {
+ continue;
+ }
+ const char *name_plural = BKE_idtype_idcode_to_name_plural(idcode);
+ PyObject *ls = PyDict_GetItemString(self->dict, name_plural);
+ // printf("lib: %s\n", name_plural);
+ if (ls == NULL || !PyList_Check(ls)) {
+ continue;
}
+
+ const Py_ssize_t size = PyList_GET_SIZE(ls);
+ if (size == 0) {
+ continue;
+ }
+
+ /* Loop over linked items in `lapp_context` to find matching python one in the list, and
+ * replace them with proper ID pointer. */
+ struct LibExitLappContextItemsIterData iter_data = {
+ .idcode = idcode, .py_library = self, .py_list = ls, .py_list_size = size};
+ BKE_blendfile_link_append_context_item_foreach(
+ lapp_context,
+ bpy_lib_exit_lapp_context_items_cb,
+ BKE_BLENDFILE_LINK_APPEND_FOREACH_ITEM_FLAG_DO_DIRECT,
+ &iter_data);
}
-#endif /* USE_RNA_DATABLOCKS */
+#endif // USE_RNA_DATABLOCKS
+
+ BLO_blendhandle_close(self->blo_handle);
+ self->blo_handle = NULL;
+
+ BKE_blendfile_link_append_context_free(lapp_context);
+ BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
- BLI_ghash_free(old_to_new_ids, NULL, NULL);
Py_RETURN_NONE;
}
diff --git a/source/blender/python/intern/bpy_operator_wrap.c b/source/blender/python/intern/bpy_operator_wrap.c
index c2d7257e458..bee64f5de2c 100644
--- a/source/blender/python/intern/bpy_operator_wrap.c
+++ b/source/blender/python/intern/bpy_operator_wrap.c
@@ -115,10 +115,6 @@ static void operator_properties_init(wmOperatorType *ot)
/* end 'ot->prop' assignment */
}
-/**
- * Generic function used by all Python defined operators
- * it's passed as an argument to #WM_operatortype_append_ptr in for operator registration.
- */
void BPY_RNA_operator_wrapper(wmOperatorType *ot, void *userdata)
{
/* take care not to overwrite anything set in
@@ -135,10 +131,6 @@ void BPY_RNA_operator_wrapper(wmOperatorType *ot, void *userdata)
operator_properties_init(ot);
}
-/**
- * Generic function used by all Python defined macro-operators
- * it's passed as an argument to #WM_operatortype_append_ptr in for operator registration.
- */
void BPY_RNA_operator_macro_wrapper(wmOperatorType *ot, void *userdata)
{
wmOperatorType *data = (wmOperatorType *)userdata;
diff --git a/source/blender/python/intern/bpy_operator_wrap.h b/source/blender/python/intern/bpy_operator_wrap.h
index 9e496cd8d26..41deb06814b 100644
--- a/source/blender/python/intern/bpy_operator_wrap.h
+++ b/source/blender/python/intern/bpy_operator_wrap.h
@@ -30,7 +30,15 @@ extern "C" {
PyObject *PYOP_wrap_macro_define(PyObject *self, PyObject *args);
/* exposed to rna/wm api */
+/**
+ * Generic function used by all Python defined operators
+ * it's passed as an argument to #WM_operatortype_append_ptr in for operator registration.
+ */
void BPY_RNA_operator_wrapper(struct wmOperatorType *ot, void *userdata);
+/**
+ * Generic function used by all Python defined macro-operators
+ * it's passed as an argument to #WM_operatortype_append_ptr in for operator registration.
+ */
void BPY_RNA_operator_macro_wrapper(struct wmOperatorType *ot, void *userdata);
#ifdef __cplusplus
diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c
index 13c7d2947cf..ed9547ee13f 100644
--- a/source/blender/python/intern/bpy_props.c
+++ b/source/blender/python/intern/bpy_props.c
@@ -434,6 +434,10 @@ static PyObject *bpy_prop_deferred_data_CreatePyObject(PyObject *fn, PyObject *k
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Shared Property Utilities
+ * \{ */
+
/* PyObject's */
static PyObject *pymeth_BoolProperty = NULL;
static PyObject *pymeth_BoolVectorProperty = NULL;
@@ -2630,10 +2634,14 @@ static int bpy_prop_arg_parse_tag_defines(PyObject *o, void *p)
" This function must take 2 values (self, value) and return None.\n" \
" :type set: function\n"
-#define BPY_PROPDEF_TYPE_DOC \
+#define BPY_PROPDEF_POINTER_TYPE_DOC \
" :arg type: A subclass of :class:`bpy.types.PropertyGroup` or :class:`bpy.types.ID`.\n" \
" :type type: class\n"
+#define BPY_PROPDEF_COLLECTION_TYPE_DOC \
+ " :arg type: A subclass of :class:`bpy.types.PropertyGroup`.\n" \
+ " :type type: class\n"
+
#define BPY_PROPDEF_TAGS_DOC \
" :arg tags: Enumerator of tags that are defined by parent class.\n" \
" :type tags: set\n"
@@ -3981,7 +3989,7 @@ PyDoc_STRVAR(BPy_PointerProperty_doc,
"update=None)\n"
"\n"
" Returns a new pointer property definition.\n"
- "\n" BPY_PROPDEF_TYPE_DOC BPY_PROPDEF_NAME_DOC BPY_PROPDEF_DESC_DOC
+ "\n" BPY_PROPDEF_POINTER_TYPE_DOC BPY_PROPDEF_NAME_DOC BPY_PROPDEF_DESC_DOC
BPY_PROPDEF_OPTIONS_DOC BPY_PROPDEF_OPTIONS_OVERRIDE_DOC BPY_PROPDEF_TAGS_DOC
BPY_PROPDEF_POLL_DOC BPY_PROPDEF_UPDATE_DOC);
PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw)
@@ -4104,7 +4112,7 @@ PyDoc_STRVAR(BPy_CollectionProperty_doc,
"tags=set())\n"
"\n"
" Returns a new collection property definition.\n"
- "\n" BPY_PROPDEF_TYPE_DOC BPY_PROPDEF_NAME_DOC BPY_PROPDEF_DESC_DOC
+ "\n" BPY_PROPDEF_COLLECTION_TYPE_DOC BPY_PROPDEF_NAME_DOC BPY_PROPDEF_DESC_DOC
BPY_PROPDEF_OPTIONS_DOC BPY_PROPDEF_OPTIONS_OVERRIDE_COLLECTION_DOC
BPY_PROPDEF_TAGS_DOC);
PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw)
@@ -4392,10 +4400,6 @@ PyObject *BPY_rna_props(void)
return submodule;
}
-/**
- * Run this on exit, clearing all Python callback users and disable the RNA callback,
- * as it would be called after Python has already finished.
- */
void BPY_rna_props_clear_all(void)
{
/* Remove all user counts, so this isn't considered a leak from Python's perspective. */
diff --git a/source/blender/python/intern/bpy_props.h b/source/blender/python/intern/bpy_props.h
index e6bbd6f708d..9d739540919 100644
--- a/source/blender/python/intern/bpy_props.h
+++ b/source/blender/python/intern/bpy_props.h
@@ -25,6 +25,10 @@ extern "C" {
#endif
PyObject *BPY_rna_props(void);
+/**
+ * Run this on exit, clearing all Python callback users and disable the RNA callback,
+ * as it would be called after Python has already finished.
+ */
void BPY_rna_props_clear_all(void);
PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw);
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index 707de1c2581..a79a0ed32bf 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -1462,10 +1462,6 @@ PyObject *pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop)
return ret;
}
-/**
- * This function is used by operators and converting dicts into collections.
- * It takes keyword args and fills them with property values.
- */
int pyrna_pydict_to_props(PointerRNA *ptr,
PyObject *kw,
const bool all_args,
@@ -7545,7 +7541,6 @@ PyObject *pyrna_prop_CreatePyObject(PointerRNA *ptr, PropertyRNA *prop)
return (PyObject *)pyrna;
}
-/* Utility func to be used by external modules, sneaky! */
PyObject *pyrna_id_CreatePyObject(ID *id)
{
if (id) {
@@ -7777,9 +7772,6 @@ static struct PyModuleDef bpy_types_module_def = {
NULL, /* m_free */
};
-/**
- * Accessed from Python as 'bpy.types'
- */
PyObject *BPY_rna_types(void)
{
PyObject *submodule = PyModule_Create(&bpy_types_module_def);
@@ -7864,11 +7856,6 @@ StructRNA *pyrna_struct_as_srna(PyObject *self, const bool parent, const char *e
}
/* Orphan functions, not sure where they should go. */
-/**
- * Get the SRNA for methods attached to types.
- *
- * Caller needs to raise error.
- */
StructRNA *srna_from_self(PyObject *self, const char *error_prefix)
{
@@ -9094,9 +9081,6 @@ static PyObject *pyrna_unregister_class(PyObject *UNUSED(self), PyObject *py_cla
Py_RETURN_NONE;
}
-/**
- * Extend RNA types with C/API methods, properties.
- */
void pyrna_struct_type_extend_capi(struct StructRNA *srna,
struct PyMethodDef *method,
struct PyGetSetDef *getset)
diff --git a/source/blender/python/intern/bpy_rna_anim.c b/source/blender/python/intern/bpy_rna_anim.c
index 2096734ef96..9a6339c0a89 100644
--- a/source/blender/python/intern/bpy_rna_anim.c
+++ b/source/blender/python/intern/bpy_rna_anim.c
@@ -401,6 +401,10 @@ PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA *self, PyObject *args, PyOb
return NULL;
}
+ if (result) {
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+ }
+
return PyBool_FromLong(result);
}
diff --git a/source/blender/python/intern/bpy_rna_array.c b/source/blender/python/intern/bpy_rna_array.c
index fcc796d4545..270c9ad431c 100644
--- a/source/blender/python/intern/bpy_rna_array.c
+++ b/source/blender/python/intern/bpy_rna_array.c
@@ -990,9 +990,10 @@ PyObject *pyrna_py_from_array(PointerRNA *ptr, PropertyRNA *prop)
return pyrna_prop_CreatePyObject(ptr, prop);
}
-/* TODO: multi-dimensional arrays. */
int pyrna_array_contains_py(PointerRNA *ptr, PropertyRNA *prop, PyObject *value)
{
+ /* TODO: multi-dimensional arrays. */
+
const int len = RNA_property_array_length(ptr, prop);
int type;
int i;
diff --git a/source/blender/python/intern/bpy_rna_data.c b/source/blender/python/intern/bpy_rna_data.c
index 639999b69d4..c781fe4a4e7 100644
--- a/source/blender/python/intern/bpy_rna_data.c
+++ b/source/blender/python/intern/bpy_rna_data.c
@@ -177,7 +177,7 @@ static PyObject *bpy_rna_data_temp_data(PyObject *UNUSED(self), PyObject *args,
ret = PyObject_GC_New(BPy_DataContext, &bpy_rna_data_context_Type);
- STRNCPY(ret->filepath, filepath ? filepath : G_MAIN->name);
+ STRNCPY(ret->filepath, filepath ? filepath : G_MAIN->filepath);
return (PyObject *)ret;
}
diff --git a/source/blender/python/intern/bpy_rna_driver.c b/source/blender/python/intern/bpy_rna_driver.c
index 3bddd0ad8c0..0bb8b1ba3e1 100644
--- a/source/blender/python/intern/bpy_rna_driver.c
+++ b/source/blender/python/intern/bpy_rna_driver.c
@@ -34,9 +34,6 @@
#include "bpy_rna_driver.h" /* own include */
-/**
- * A version of #driver_get_variable_value which returns a PyObject.
- */
PyObject *pyrna_driver_get_variable_value(struct ChannelDriver *driver, struct DriverTarget *dtar)
{
PyObject *driver_arg = NULL;
diff --git a/source/blender/python/intern/bpy_rna_driver.h b/source/blender/python/intern/bpy_rna_driver.h
index cc2c4550870..e34c7e4597c 100644
--- a/source/blender/python/intern/bpy_rna_driver.h
+++ b/source/blender/python/intern/bpy_rna_driver.h
@@ -28,6 +28,9 @@ struct PathResolvedRNA;
extern "C" {
#endif
+/**
+ * A version of #driver_get_variable_value which returns a #PyObject.
+ */
PyObject *pyrna_driver_get_variable_value(struct ChannelDriver *driver, struct DriverTarget *dtar);
PyObject *pyrna_driver_self_from_anim_rna(struct PathResolvedRNA *anim_rna);
diff --git a/source/blender/python/mathutils/mathutils.c b/source/blender/python/mathutils/mathutils.c
index 0043fc36162..6eee9ceebb8 100644
--- a/source/blender/python/mathutils/mathutils.c
+++ b/source/blender/python/mathutils/mathutils.c
@@ -77,11 +77,6 @@ static int mathutils_array_parse_fast(float *array,
return size;
}
-/**
- * helper function that returns a Python `__hash__`.
- *
- * \note consistent with the equivalent tuple of floats (CPython's 'tuplehash')
- */
Py_hash_t mathutils_array_hash(const float *array, size_t array_len)
{
int i;
@@ -114,7 +109,6 @@ Py_hash_t mathutils_array_hash(const float *array, size_t array_len)
return x;
}
-/* helper function returns length of the 'value', -1 on error */
int mathutils_array_parse(
float *array, int array_min, int array_max, PyObject *value, const char *error_prefix)
{
@@ -211,7 +205,6 @@ int mathutils_array_parse(
return size;
}
-/* on error, -1 is returned and no allocation is made */
int mathutils_array_parse_alloc(float **array,
int array_min,
PyObject *value,
@@ -279,7 +272,6 @@ int mathutils_array_parse_alloc(float **array,
return ret;
}
-/* parse an array of vectors */
int mathutils_array_parse_alloc_v(float **array,
int array_dim,
PyObject *value,
@@ -321,7 +313,6 @@ int mathutils_array_parse_alloc_v(float **array,
return size;
}
-/* Parse an sequence array_dim integers into array. */
int mathutils_int_array_parse(int *array, int array_dim, PyObject *value, const char *error_prefix)
{
int size, i;
@@ -357,7 +348,6 @@ int mathutils_int_array_parse(int *array, int array_dim, PyObject *value, const
return size;
}
-/* Parse sequence of array_dim sequences of integers and return allocated result. */
int mathutils_array_parse_alloc_vi(int **array,
int array_dim,
PyObject *value,
@@ -395,12 +385,6 @@ int mathutils_array_parse_alloc_vi(int **array,
return size;
}
-/* Parse sequence of variable-length sequences of int and return allocated
- * triple of arrays to represent the result:
- * The flattened sequences are put into *array.
- * The start index of each sequence goes into start_table.
- * The length of each index goes into len_table.
- */
int mathutils_array_parse_alloc_viseq(
int **array, int **start_table, int **len_table, PyObject *value, const char *error_prefix)
{
@@ -560,7 +544,6 @@ int EXPP_VectorsAreEqual(const float *vecA, const float *vecB, int size, int flo
}
#ifndef MATH_STANDALONE
-/* dynstr as python string utility functions, frees 'ds'! */
PyObject *mathutils_dynstr_to_py(struct DynStr *ds)
{
const int ds_len = BLI_dynstr_get_len(ds); /* space for \0 */
diff --git a/source/blender/python/mathutils/mathutils.h b/source/blender/python/mathutils/mathutils.h
index 4aa26dcc5be..d73d2afe69b 100644
--- a/source/blender/python/mathutils/mathutils.h
+++ b/source/blender/python/mathutils/mathutils.h
@@ -162,28 +162,56 @@ void _BaseMathObject_RaiseNotFrozenExc(const BaseMathObject *self);
0)
/* utility func */
+/**
+ * Helper function.
+ * \return length of `value`, -1 on error.
+ */
int mathutils_array_parse(
float *array, int array_min, int array_max, PyObject *value, const char *error_prefix);
+/**
+ * \return -1 is returned on error and no allocation is made.
+ */
int mathutils_array_parse_alloc(float **array,
int array_min,
PyObject *value,
const char *error_prefix);
+/**
+ * Parse an array of vectors.
+ */
int mathutils_array_parse_alloc_v(float **array,
int array_dim,
PyObject *value,
const char *error_prefix);
+/**
+ * Parse an sequence array_dim integers into array.
+ */
int mathutils_int_array_parse(int *array,
int array_dim,
PyObject *value,
const char *error_prefix);
+/**
+ * Parse sequence of array_dim sequences of integers and return allocated result.
+ */
int mathutils_array_parse_alloc_vi(int **array,
int array_dim,
PyObject *value,
const char *error_prefix);
+/**
+ * Parse sequence of variable-length sequences of int and return allocated
+ * triple of arrays to represent the result:
+ * The flattened sequences are put into *array.
+ * The start index of each sequence goes into start_table.
+ * The length of each index goes into len_table.
+ */
int mathutils_array_parse_alloc_viseq(
int **array, int **start_table, int **len_table, PyObject *value, const char *error_prefix);
int mathutils_any_to_rotmat(float rmat[3][3], PyObject *value, const char *error_prefix);
+/**
+ * helper function that returns a Python `__hash__`.
+ *
+ * \note consistent with the equivalent tuple of floats (CPython's 'tuplehash')
+ */
Py_hash_t mathutils_array_hash(const float *float_array, size_t array_len);
/* zero remaining unused elements of the array */
@@ -194,9 +222,21 @@ Py_hash_t mathutils_array_hash(const float *float_array, size_t array_len);
#define MU_ARRAY_FLAGS (MU_ARRAY_ZERO | MU_ARRAY_SPILL)
+/**
+ * Column vector multiplication (Matrix * Vector).
+ * <pre>
+ * [1][4][7] [a]
+ * [2][5][8] * [b]
+ * [3][6][9] [c]
+ * </pre>
+ *
+ * \note Vector/Matrix multiplication is not commutative.
+ * \note Assume read callbacks have been done first.
+ */
int column_vector_multiplication(float r_vec[4], VectorObject *vec, MatrixObject *mat);
#ifndef MATH_STANDALONE
/* dynstr as python string utility functions */
+/* dynstr as python string utility functions, frees 'ds'! */
PyObject *mathutils_dynstr_to_py(struct DynStr *ds);
#endif
diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c
index 28b91e13d47..4396e2f9c7b 100644
--- a/source/blender/python/mathutils/mathutils_Matrix.c
+++ b/source/blender/python/mathutils/mathutils_Matrix.c
@@ -3382,9 +3382,6 @@ PyObject *Matrix_CreatePyObject_cb(
return (PyObject *)self;
}
-/**
- * \param mat: Initialized matrix value to use in-place, allocated with #PyMem_Malloc
- */
PyObject *Matrix_CreatePyObject_alloc(float *mat,
const ushort num_col,
const ushort num_row,
diff --git a/source/blender/python/mathutils/mathutils_Matrix.h b/source/blender/python/mathutils/mathutils_Matrix.h
index 588c0b94891..56bb4d39d01 100644
--- a/source/blender/python/mathutils/mathutils_Matrix.h
+++ b/source/blender/python/mathutils/mathutils_Matrix.h
@@ -75,6 +75,9 @@ PyObject *Matrix_CreatePyObject_cb(PyObject *user,
unsigned char cb_type,
unsigned char cb_subtype) ATTR_WARN_UNUSED_RESULT;
+/**
+ * \param mat: Initialized matrix value to use in-place, allocated with #PyMem_Malloc
+ */
PyObject *Matrix_CreatePyObject_alloc(float *mat,
const ushort num_col,
const ushort num_row,
diff --git a/source/blender/python/mathutils/mathutils_Vector.c b/source/blender/python/mathutils/mathutils_Vector.c
index 23758c5603e..daaf3b3da26 100644
--- a/source/blender/python/mathutils/mathutils_Vector.c
+++ b/source/blender/python/mathutils/mathutils_Vector.c
@@ -1676,17 +1676,6 @@ static PyObject *Vector_isub(PyObject *v1, PyObject *v2)
/*------------------------obj * obj------------------------------
* multiplication */
-/**
- * Column vector multiplication (Matrix * Vector).
- * <pre>
- * [1][4][7] [a]
- * [2][5][8] * [b]
- * [3][6][9] [c]
- * </pre>
- *
- * \note Vector/Matrix multiplication is not commutative.
- * \note Assume read callbacks have been done first.
- */
int column_vector_multiplication(float r_vec[MAX_DIMENSIONS], VectorObject *vec, MatrixObject *mat)
{
float vec_cpy[MAX_DIMENSIONS];
@@ -3166,11 +3155,6 @@ PyObject *Vector_CreatePyObject(const float *vec, const int size, PyTypeObject *
return (PyObject *)self;
}
-/**
- * Create a vector that wraps existing memory.
- *
- * \param vec: Use this vector in-place.
- */
PyObject *Vector_CreatePyObject_wrap(float *vec, const int size, PyTypeObject *base_type)
{
VectorObject *self;
@@ -3194,10 +3178,6 @@ PyObject *Vector_CreatePyObject_wrap(float *vec, const int size, PyTypeObject *b
return (PyObject *)self;
}
-/**
- * Create a vector where the value is defined by registered callbacks,
- * see: #Mathutils_RegisterCallback
- */
PyObject *Vector_CreatePyObject_cb(PyObject *cb_user, int size, uchar cb_type, uchar cb_subtype)
{
VectorObject *self = (VectorObject *)Vector_CreatePyObject(NULL, size, NULL);
@@ -3212,9 +3192,6 @@ PyObject *Vector_CreatePyObject_cb(PyObject *cb_user, int size, uchar cb_type, u
return (PyObject *)self;
}
-/**
- * \param vec: Initialized vector value to use in-place, allocated with #PyMem_Malloc
- */
PyObject *Vector_CreatePyObject_alloc(float *vec, const int size, PyTypeObject *base_type)
{
VectorObject *self;
diff --git a/source/blender/python/mathutils/mathutils_Vector.h b/source/blender/python/mathutils/mathutils_Vector.h
index 09fc429f9cc..fb420b32df4 100644
--- a/source/blender/python/mathutils/mathutils_Vector.h
+++ b/source/blender/python/mathutils/mathutils_Vector.h
@@ -35,14 +35,26 @@ typedef struct {
PyObject *Vector_CreatePyObject(const float *vec,
const int size,
PyTypeObject *base_type) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Create a vector that wraps existing memory.
+ *
+ * \param vec: Use this vector in-place.
+ */
PyObject *Vector_CreatePyObject_wrap(float *vec,
const int size,
PyTypeObject *base_type) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1);
+/**
+ * Create a vector where the value is defined by registered callbacks,
+ * see: #Mathutils_RegisterCallback
+ */
PyObject *Vector_CreatePyObject_cb(PyObject *user,
int size,
unsigned char cb_type,
unsigned char subtype) ATTR_WARN_UNUSED_RESULT;
+/**
+ * \param vec: Initialized vector value to use in-place, allocated with #PyMem_Malloc
+ */
PyObject *Vector_CreatePyObject_alloc(float *vec,
const int size,
PyTypeObject *base_type) ATTR_WARN_UNUSED_RESULT
diff --git a/source/blender/render/RE_bake.h b/source/blender/render/RE_bake.h
index 47a15199701..b2c44e051d1 100644
--- a/source/blender/render/RE_bake.h
+++ b/source/blender/render/RE_bake.h
@@ -120,6 +120,10 @@ void RE_bake_normal_world_to_object(const BakePixel pixel_array[],
float result[],
struct Object *ob,
const eBakeNormalSwizzle normal_swizzle[3]);
+/**
+ * This function converts an object space normal map
+ * to a tangent space normal map for a given low poly mesh.
+ */
void RE_bake_normal_world_to_tangent(const BakePixel pixel_array[],
const size_t num_pixels,
const int depth,
diff --git a/source/blender/render/RE_engine.h b/source/blender/render/RE_engine.h
index 2a3a5964262..b22d263490c 100644
--- a/source/blender/render/RE_engine.h
+++ b/source/blender/render/RE_engine.h
@@ -180,6 +180,10 @@ typedef struct RenderEngine {
RenderEngine *RE_engine_create(RenderEngineType *type);
void RE_engine_free(RenderEngine *engine);
+/**
+ * Loads in image into a result, size must match
+ * x/y offsets are only used on a partial copy when dimensions don't match.
+ */
void RE_layer_load_from_file(
struct RenderLayer *layer, struct ReportList *reports, const char *filename, int x, int y);
void RE_result_load_from_file(struct RenderResult *result,
diff --git a/source/blender/render/RE_pipeline.h b/source/blender/render/RE_pipeline.h
index 0d2d93ae026..073bb0a3697 100644
--- a/source/blender/render/RE_pipeline.h
+++ b/source/blender/render/RE_pipeline.h
@@ -167,8 +167,10 @@ typedef struct RenderStats {
/* *********************** API ******************** */
-/* the name is used as identifier, so elsewhere in blender the result can retrieved */
-/* calling a new render with same name, frees automatic existing render */
+/**
+ * The name is used as identifier, so elsewhere in blender the result can retrieved.
+ * Calling a new render with same name, frees automatic existing render.
+ */
struct Render *RE_NewRender(const char *name);
struct Render *RE_GetRender(const char *name);
@@ -176,36 +178,80 @@ struct Scene;
struct Render *RE_NewSceneRender(const struct Scene *scene);
struct Render *RE_GetSceneRender(const struct Scene *scene);
-/* assign default dummy callbacks */
+/* Assign default dummy callbacks. */
+
+/**
+ * Called for new renders and when finishing rendering
+ * so we always have valid callbacks on a render.
+ */
void RE_InitRenderCB(struct Render *re);
-/* use free render as signal to do everything over (previews) */
+/**
+ * Use free render as signal to do everything over (previews).
+ *
+ * Only call this while you know it will remove the link too.
+ */
void RE_FreeRender(struct Render *re);
-/* only called on exit */
+/**
+ * Only called on exit.
+ */
void RE_FreeAllRender(void);
-/* On file load, free render results. */
+/**
+ * On file load, free render results.
+ */
void RE_FreeAllRenderResults(void);
-/* On file load or changes engines, free persistent render data.
- * Assumes no engines are currently rendering. */
+/**
+ * On file load or changes engines, free persistent render data.
+ * Assumes no engines are currently rendering.
+ */
void RE_FreeAllPersistentData(void);
-/* Free persistent render data, optionally only for the given scene. */
+/**
+ * Free persistent render data, optionally only for the given scene.
+ */
void RE_FreePersistentData(const Scene *scene);
-/* get results and statistics */
+/**
+ * Get results and statistics.
+ */
void RE_FreeRenderResult(struct RenderResult *rr);
+/**
+ * If you want to know exactly what has been done.
+ */
struct RenderResult *RE_AcquireResultRead(struct Render *re);
struct RenderResult *RE_AcquireResultWrite(struct Render *re);
void RE_ReleaseResult(struct Render *re);
+/**
+ * Same as #RE_AcquireResultImage but creating the necessary views to store the result
+ * fill provided result struct with a copy of thew views of what is done so far the
+ * #RenderResult.views #ListBase needs to be freed after with #RE_ReleaseResultImageViews
+ */
void RE_AcquireResultImageViews(struct Render *re, struct RenderResult *rr);
+/**
+ * Clear temporary #RenderResult struct.
+ */
void RE_ReleaseResultImageViews(struct Render *re, struct RenderResult *rr);
+
+/**
+ * Fill provided result struct with what's currently active or done.
+ * This #RenderResult struct is the only exception to the rule of a #RenderResult
+ * always having at least one #RenderView.
+ */
void RE_AcquireResultImage(struct Render *re, struct RenderResult *rr, const int view_id);
void RE_ReleaseResultImage(struct Render *re);
void RE_SwapResult(struct Render *re, struct RenderResult **rr);
void RE_ClearResult(struct Render *re);
struct RenderStats *RE_GetStats(struct Render *re);
+/**
+ * Caller is responsible for allocating `rect` in correct size!
+ */
void RE_ResultGet32(struct Render *re, unsigned int *rect);
+/**
+ * Only for acquired results, for lock.
+ *
+ * \note The caller is responsible for allocating `rect` in correct size!
+ */
void RE_AcquiredResultGet32(struct Render *re,
struct RenderResult *result,
unsigned int *rect,
@@ -223,7 +269,10 @@ float *RE_RenderLayerGetPass(volatile struct RenderLayer *rl,
bool RE_HasSingleLayer(struct Render *re);
-/* add passes for grease pencil */
+/**
+ * Add passes for grease pencil.
+ * Create a render-layer and render-pass for grease-pencil layer.
+ */
struct RenderPass *RE_create_gp_pass(struct RenderResult *rr,
const char *layername,
const char *viewname);
@@ -236,7 +285,10 @@ void RE_create_render_pass(struct RenderResult *rr,
const char *viewname,
const bool allocate);
-/* obligatory initialize call, disprect is optional */
+/**
+ * Obligatory initialize call, doesn't change during entire render sequence.
+ * \param disprect: is optional. if NULL it assumes full window render.
+ */
void RE_InitState(struct Render *re,
struct Render *source,
struct RenderData *rd,
@@ -246,15 +298,28 @@ void RE_InitState(struct Render *re,
int winy,
rcti *disprect);
-/* set up the viewplane/perspective matrix, three choices */
-struct Object *RE_GetCamera(struct Render *re); /* return camera override if set */
+/**
+ * Set up the view-plane/perspective matrix, three choices.
+ *
+ * \return camera override if set.
+ */
+struct Object *RE_GetCamera(struct Render *re);
void RE_SetOverrideCamera(struct Render *re, struct Object *cam_ob);
+/**
+ * Per render, there's one persistent view-plane. Parts will set their own view-planes.
+ *
+ * \note call this after #RE_InitState().
+ */
void RE_SetCamera(struct Render *re, struct Object *cam_ob);
-/* get current view and window transform */
+/**
+ * Get current view and window transform.
+ */
void RE_GetViewPlane(struct Render *re, rctf *r_viewplane, rcti *r_disprect);
-/* Set the render threads based on the command-line and auto-threads setting. */
+/**
+ * Set the render threads based on the command-line and auto-threads setting.
+ */
void RE_init_threadcount(Render *re);
bool RE_WriteRenderViewsImage(struct ReportList *reports,
@@ -271,7 +336,11 @@ bool RE_WriteRenderViewsMovie(struct ReportList *reports,
const int totvideos,
bool preview);
-/* only RE_NewRender() needed, main Blender render calls */
+/**
+ * Only #RE_NewRender() needed, main Blender render calls.
+ *
+ * General Blender frame render call.
+ */
void RE_RenderFrame(struct Render *re,
struct Main *bmain,
struct Scene *scene,
@@ -279,6 +348,9 @@ void RE_RenderFrame(struct Render *re,
struct Object *camera_override,
int frame,
const bool write_still);
+/**
+ * Saves images to disk.
+ */
void RE_RenderAnim(struct Render *re,
struct Main *bmain,
struct Scene *scene,
@@ -298,13 +370,24 @@ void RE_RenderFreestyleExternal(struct Render *re);
void RE_SetActiveRenderView(struct Render *re, const char *viewname);
const char *RE_GetActiveRenderView(struct Render *re);
-/* error reporting */
+/**
+ * Error reporting.
+ */
void RE_SetReports(struct Render *re, struct ReportList *reports);
-/* main preview render call */
+/**
+ * Main preview render call.
+ */
void RE_PreviewRender(struct Render *re, struct Main *bmain, struct Scene *scene);
+/**
+ * Only the temp file!
+ */
bool RE_ReadRenderResult(struct Scene *scene, struct Scene *scenode);
+/**
+ * Called from the UI and render pipeline, to save multi-layer and multi-view
+ * images, optionally isolating a specific, view, layer or RGBA/Z pass.
+ */
bool RE_WriteRenderResult(struct ReportList *reports,
RenderResult *rr,
const char *filename,
@@ -314,7 +397,11 @@ bool RE_WriteRenderResult(struct ReportList *reports,
struct RenderResult *RE_MultilayerConvert(
void *exrhandle, const char *colorspace, bool predivide, int rectx, int recty);
-/* display and event callbacks */
+/* Display and event callbacks. */
+
+/**
+ * Image and movie output has to move to either imbuf or kernel.
+ */
void RE_display_init_cb(struct Render *re,
void *handle,
void (*f)(void *handle, RenderResult *rr));
@@ -337,17 +424,27 @@ void RE_gl_context_destroy(Render *re);
void *RE_gl_context_get(Render *re);
void *RE_gpu_context_get(Render *re);
-/* should move to kernel once... still unsure on how/where */
+/**
+ * \param x: ranges from -1 to 1.
+ *
+ * TODO: Should move to kernel once... still unsure on how/where.
+ */
float RE_filter_value(int type, float x);
int RE_seq_render_active(struct Scene *scene, struct RenderData *rd);
+/**
+ * Used in the interface to decide whether to show layers or passes.
+ */
bool RE_layers_have_name(struct RenderResult *result);
bool RE_passes_have_name(struct RenderLayer *rl);
struct RenderPass *RE_pass_find_by_name(volatile struct RenderLayer *rl,
const char *name,
const char *viewname);
+/**
+ * Only provided for API compatibility, don't use this in new code!
+ */
struct RenderPass *RE_pass_find_by_type(volatile struct RenderLayer *rl,
int passtype,
const char *viewname);
@@ -358,8 +455,14 @@ struct RenderPass *RE_pass_find_by_type(volatile struct RenderLayer *rl,
#define RE_BAKE_AO 2
void RE_GetCameraWindow(struct Render *re, struct Object *camera, float mat[4][4]);
+/**
+ * Must be called after #RE_GetCameraWindow(), does not change `re->winmat`.
+ */
void RE_GetCameraWindowWithOverscan(struct Render *re, float overscan, float r_winmat[4][4]);
void RE_GetCameraModelMatrix(struct Render *re, struct Object *camera, float r_modelmat[4][4]);
+
+/* displist.c utility. */
+
struct Scene *RE_GetScene(struct Render *re);
void RE_SetScene(struct Render *re, struct Scene *sce);
diff --git a/source/blender/render/RE_texture.h b/source/blender/render/RE_texture.h
index 39d773777ab..cb18dc92415 100644
--- a/source/blender/render/RE_texture.h
+++ b/source/blender/render/RE_texture.h
@@ -18,13 +18,13 @@
*/
/** \file
* \ingroup render
+ *
+ * This include is for non-render pipeline exports (still old cruft here).
*/
#pragma once
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-/* this include is for non-render pipeline exports (still old cruft here) */
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+#include "BLI_compiler_attrs.h"
/* called by meshtools */
struct Depsgraph;
@@ -37,6 +37,12 @@ extern "C" {
#endif
/* texture_procedural.c */
+
+/**
+ * \param pool: Thread pool, may be NULL.
+ *
+ * \return True if the texture has color, otherwise false.
+ */
bool RE_texture_evaluate(const struct MTex *mtex,
const float vec[3],
const int thread,
@@ -47,6 +53,13 @@ bool RE_texture_evaluate(const struct MTex *mtex,
float *r_intensity,
float r_rgba[4]) ATTR_NONNULL(1, 2, 7, 8);
+/**
+ * \param in: Destination
+ * \param tex: Texture.
+ * \param out: Previous color.
+ * \param fact: Texture strength.
+ * \param facg: Button strength value.
+ */
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);
@@ -55,9 +68,11 @@ void RE_texture_rng_init(void);
void RE_texture_rng_exit(void);
/* texture_image.c */
+
void ibuf_sample(struct ImBuf *ibuf, float fx, float fy, float dx, float dy, float result[4]);
/* texture_pointdensity.c */
+
struct PointDensity;
void RE_point_density_cache(struct Depsgraph *depsgraph, struct PointDensity *pd);
@@ -67,6 +82,10 @@ void RE_point_density_minmax(struct Depsgraph *depsgraph,
float r_min[3],
float r_max[3]);
+/**
+ * \note Requires #RE_point_density_cache() to be called first.
+ * \note Frees point density structure after sampling.
+ */
void RE_point_density_sample(struct Depsgraph *depsgraph,
struct PointDensity *pd,
const int resolution,
@@ -78,8 +97,10 @@ void RE_point_density_fix_linking(void);
/* texture_procedural.c */
-/* Texture evaluation result.
- * NOTE: tr tg tb ta has to remain in this order for array access. */
+/**
+ * Texture evaluation result.
+ * \note `tr tg tb ta` have to remain in this order for array access.
+ */
typedef struct TexResult {
float tin, tr, tg, tb, ta;
int talpha;
@@ -87,6 +108,14 @@ typedef struct TexResult {
} TexResult;
/* This one uses nodes. */
+
+/**
+ * \warning if the texres's values are not declared zero,
+ * check the return value to be sure the color values are set before using the r/g/b values,
+ * otherwise you may use uninitialized values - Campbell
+ *
+ * Use it for stuff which is out of render pipeline.
+ */
int multitex_ext(struct Tex *tex,
float texvec[3],
float dxt[3],
@@ -97,14 +126,26 @@ int multitex_ext(struct Tex *tex,
struct ImagePool *pool,
bool scene_color_manage,
const bool skip_load_image);
-/* Nodes disabled. */
+
+/**
+ * Nodes disabled.
+ * extern-tex doesn't support nodes (#ntreeBeginExec() can't be called when rendering is going on).
+ *
+ * Use it for stuff which is out of render pipeline.
+ */
int multitex_ext_safe(struct Tex *tex,
const float texvec[3],
struct TexResult *texres,
struct ImagePool *pool,
bool scene_color_manage,
const bool skip_load_image);
-/* Only for internal node usage. */
+
+/**
+ * Only for internal node usage.
+ *
+ * this is called from the shader and texture nodes
+ * Use it from render pipeline only!
+ */
int multitex_nodes(struct Tex *tex,
const float texvec[3],
float dxt[3],
diff --git a/source/blender/render/intern/bake.c b/source/blender/render/intern/bake.c
index 0f893ce8cd5..6794a9cd1ad 100644
--- a/source/blender/render/intern/bake.c
+++ b/source/blender/render/intern/bake.c
@@ -814,10 +814,6 @@ static void normal_compress(float out[3],
}
}
-/**
- * This function converts an object space normal map
- * to a tangent space normal map for a given low poly mesh.
- */
void RE_bake_normal_world_to_tangent(const BakePixel pixel_array[],
const size_t num_pixels,
const int depth,
diff --git a/source/blender/render/intern/engine.c b/source/blender/render/intern/engine.c
index cb92b15f873..e1778897777 100644
--- a/source/blender/render/intern/engine.c
+++ b/source/blender/render/intern/engine.c
@@ -784,6 +784,7 @@ void RE_engine_frame_set(RenderEngine *engine, int frame, float subframe)
}
/* Bake */
+
void RE_bake_engine_set_engine_parameters(Render *re, Main *bmain, Scene *scene)
{
re->scene = scene;
diff --git a/source/blender/render/intern/initrender.c b/source/blender/render/intern/initrender.c
index 2370d8e893b..f696b81cffb 100644
--- a/source/blender/render/intern/initrender.c
+++ b/source/blender/render/intern/initrender.c
@@ -121,7 +121,6 @@ static float filt_mitchell(float x) /* Mitchell & Netravali's two-param cubic */
return 0.0f;
}
-/* x ranges from -1 to 1 */
float RE_filter_value(int type, float x)
{
float gaussfac = 1.6f;
@@ -163,6 +162,7 @@ float RE_filter_value(int type, float x)
}
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
struct Object *RE_GetCamera(Render *re)
{
Object *camera = re->camera_override ? re->camera_override : re->scene->camera;
@@ -174,11 +174,6 @@ void RE_SetOverrideCamera(Render *re, Object *cam_ob)
re->camera_override = cam_ob;
}
-/**
- * Per render, there's one persistent view-plane. Parts will set their own view-planes.
- *
- * \note call this after #RE_InitState().
- */
void RE_SetCamera(Render *re, Object *cam_ob)
{
CameraParams params;
@@ -205,7 +200,6 @@ void RE_GetCameraWindow(struct Render *re, struct Object *camera, float r_winmat
copy_m4_m4(r_winmat, re->winmat);
}
-/* Must be called after RE_GetCameraWindow(), does not change re->winmat. */
void RE_GetCameraWindowWithOverscan(struct Render *re, float overscan, float r_winmat[4][4])
{
CameraParams params;
diff --git a/source/blender/render/intern/pipeline.c b/source/blender/render/intern/pipeline.c
index 1bf0dfe079c..44abbbdf074 100644
--- a/source/blender/render/intern/pipeline.c
+++ b/source/blender/render/intern/pipeline.c
@@ -338,7 +338,6 @@ Render *RE_GetRender(const char *name)
return re;
}
-/* if you want to know exactly what has been done */
RenderResult *RE_AcquireResultRead(Render *re)
{
if (re) {
@@ -383,7 +382,6 @@ void RE_ReleaseResult(Render *re)
}
}
-/* displist.c util.... */
Scene *RE_GetScene(Render *re)
{
if (re) {
@@ -399,11 +397,6 @@ void RE_SetScene(Render *re, Scene *sce)
}
}
-/**
- * Same as #RE_AcquireResultImage but creating the necessary views to store the result
- * fill provided result struct with a copy of thew views of what is done so far the
- * #RenderResult.views #ListBase needs to be freed after with #RE_ReleaseResultImageViews
- */
void RE_AcquireResultImageViews(Render *re, RenderResult *rr)
{
memset(rr, 0, sizeof(RenderResult));
@@ -449,7 +442,6 @@ void RE_AcquireResultImageViews(Render *re, RenderResult *rr)
}
}
-/* clear temporary renderresult struct */
void RE_ReleaseResultImageViews(Render *re, RenderResult *rr)
{
if (re) {
@@ -460,9 +452,6 @@ void RE_ReleaseResultImageViews(Render *re, RenderResult *rr)
}
}
-/* fill provided result struct with what's currently active or done */
-/* this RenderResult struct is the only exception to the rule of a RenderResult */
-/* always having at least one RenderView */
void RE_AcquireResultImage(Render *re, RenderResult *rr, const int view_id)
{
memset(rr, 0, sizeof(RenderResult));
@@ -516,7 +505,6 @@ void RE_ReleaseResultImage(Render *re)
}
}
-/* caller is responsible for allocating rect in correct size! */
void RE_ResultGet32(Render *re, unsigned int *rect)
{
RenderResult rres;
@@ -533,8 +521,6 @@ void RE_ResultGet32(Render *re, unsigned int *rect)
RE_ReleaseResultImageViews(re, &rres);
}
-/* caller is responsible for allocating rect in correct size! */
-/* Only for acquired results, for lock */
void RE_AcquiredResultGet32(Render *re,
RenderResult *result,
unsigned int *rect,
@@ -603,8 +589,6 @@ Render *RE_NewSceneRender(const Scene *scene)
return RE_NewRender(render_name);
}
-/* called for new renders and when finishing rendering so
- * we always have valid callbacks on a render */
void RE_InitRenderCB(Render *re)
{
/* set default empty callbacks */
@@ -624,7 +608,6 @@ void RE_InitRenderCB(Render *re)
re->dih = re->dch = re->duh = re->sdh = re->prh = re->tbh = NULL;
}
-/* only call this while you know it will remove the link too */
void RE_FreeRender(Render *re)
{
if (re->engine) {
@@ -655,7 +638,6 @@ void RE_FreeRender(Render *re)
MEM_freeN(re);
}
-/* exit blender */
void RE_FreeAllRender(void)
{
while (RenderGlobal.renderlist.first) {
@@ -668,7 +650,6 @@ void RE_FreeAllRender(void)
#endif
}
-/* on file load, free all re */
void RE_FreeAllRenderResults(void)
{
Render *re;
@@ -769,8 +750,6 @@ void render_copy_renderdata(RenderData *to, RenderData *from)
BKE_curvemapping_copy_data(&to->mblur_shutter_curve, &from->mblur_shutter_curve);
}
-/* what doesn't change during entire render sequence */
-/* disprect is optional, if NULL it assumes full window render */
void RE_InitState(Render *re,
Render *source,
RenderData *rd,
@@ -874,8 +853,6 @@ void RE_InitState(Render *re,
RE_point_density_fix_linking();
}
-/* update some variables that can be animated, and otherwise wouldn't be due to
- * RenderData getting copied once at the start of animation render */
void render_update_anim_renderdata(Render *re, RenderData *rd, ListBase *render_layers)
{
/* filter */
@@ -897,7 +874,6 @@ void render_update_anim_renderdata(Render *re, RenderData *rd, ListBase *render_
BLI_duplicatelist(&re->r.views, &rd->views);
}
-/* image and movie output has to move to either imbuf or kernel */
void RE_display_init_cb(Render *re, void *handle, void (*f)(void *handle, RenderResult *rr))
{
re->display_init = f;
@@ -1834,7 +1810,6 @@ static void render_pipeline_free(Render *re)
}
}
-/* general Blender frame render call */
void RE_RenderFrame(Render *re,
Main *bmain,
Scene *scene,
@@ -1846,7 +1821,7 @@ void RE_RenderFrame(Render *re,
render_callback_exec_id(re, re->main, &scene->id, BKE_CB_EVT_RENDER_INIT);
/* Ugly global still...
- * is to prevent preview events and signal subsurfs etc to make full resol. */
+ * is to prevent preview events and signal subdivision-surface etc to make full resolution. */
G.is_rendering = true;
scene->r.cfra = frame;
@@ -2280,7 +2255,6 @@ static void re_movie_free_all(Render *re, bMovieHandle *mh, int totvideos)
MEM_SAFE_FREE(re->movie_ctx_arr);
}
-/* saves images to disk */
void RE_RenderAnim(Render *re,
Main *bmain,
Scene *scene,
@@ -2357,8 +2331,8 @@ void RE_RenderAnim(Render *re,
}
}
- /* Ugly global still... is to prevent renderwin events and signal subsurfs etc to make full resol
- * is also set by caller renderwin.c */
+ /* Ugly global still... is to prevent renderwin events and signal subdivision-surface etc
+ * to make full resolution is also set by caller renderwin.c */
G.is_rendering = true;
re->flag |= R_ANIMATION;
@@ -2583,7 +2557,6 @@ void RE_PreviewRender(Render *re, Main *bmain, Scene *sce)
/* NOTE: repeated win/disprect calc... solve that nicer, also in compo. */
-/* only the temp file! */
bool RE_ReadRenderResult(Scene *scene, Scene *scenode)
{
Render *re;
@@ -2635,8 +2608,6 @@ void RE_init_threadcount(Render *re)
re->r.threads = BKE_render_num_threads(&re->r);
}
-/* loads in image into a result, size must match
- * x/y offsets are only used on a partial copy when dimensions don't match */
void RE_layer_load_from_file(
RenderLayer *layer, ReportList *reports, const char *filename, int x, int y)
{
@@ -2712,7 +2683,6 @@ void RE_result_load_from_file(RenderResult *result, ReportList *reports, const c
}
}
-/* Used in the interface to decide whether to show layers or passes. */
bool RE_layers_have_name(struct RenderResult *rr)
{
switch (BLI_listbase_count_at_most(&rr->layers, 2)) {
@@ -2754,7 +2724,6 @@ RenderPass *RE_pass_find_by_name(volatile RenderLayer *rl, const char *name, con
return rp;
}
-/* Only provided for API compatibility, don't use this in new code! */
RenderPass *RE_pass_find_by_type(volatile RenderLayer *rl, int passtype, const char *viewname)
{
#define CHECK_PASS(NAME) \
@@ -2793,7 +2762,6 @@ RenderPass *RE_pass_find_by_type(volatile RenderLayer *rl, int passtype, const c
return NULL;
}
-/* create a renderlayer and renderpass for grease pencil layer */
RenderPass *RE_create_gp_pass(RenderResult *rr, const char *layername, const char *viewname)
{
RenderLayer *rl = BLI_findstring(&rr->layers, layername, offsetof(RenderLayer, name));
diff --git a/source/blender/render/intern/pipeline.h b/source/blender/render/intern/pipeline.h
index 062df59bfd3..ba2e382619d 100644
--- a/source/blender/render/intern/pipeline.h
+++ b/source/blender/render/intern/pipeline.h
@@ -34,6 +34,10 @@ extern "C" {
#endif
struct RenderLayer *render_get_active_layer(struct Render *re, struct RenderResult *rr);
+/**
+ * Update some variables that can be animated, and otherwise wouldn't be due to
+ * #RenderData getting copied once at the start of animation render.
+ */
void render_update_anim_renderdata(struct Render *re,
struct RenderData *rd,
struct ListBase *render_layers);
diff --git a/source/blender/render/intern/render_result.c b/source/blender/render/intern/render_result.c
index 0681bcd9aa5..a21351539f6 100644
--- a/source/blender/render/intern/render_result.c
+++ b/source/blender/render/intern/render_result.c
@@ -126,7 +126,6 @@ void render_result_free(RenderResult *rr)
MEM_freeN(rr);
}
-/** Version that's compatible with full-sample buffers. */
void render_result_free_list(ListBase *lb, RenderResult *rr)
{
RenderResult *rrnext;
@@ -144,7 +143,6 @@ void render_result_free_list(ListBase *lb, RenderResult *rr)
/********************************* multiview *************************************/
-/* create a new views Listbase in rr without duplicating the memory pointers */
void render_result_views_shallowcopy(RenderResult *dst, RenderResult *src)
{
RenderView *rview;
@@ -166,7 +164,6 @@ void render_result_views_shallowcopy(RenderResult *dst, RenderResult *src)
}
}
-/* free the views created temporarily */
void render_result_views_shallowdelete(RenderResult *rr)
{
if (rr == NULL) {
@@ -286,10 +283,6 @@ RenderPass *render_layer_add_pass(RenderResult *rr,
return rpass;
}
-/* called by main render as well for parts */
-/* will read info from Render *re to define layers */
-/* called in threads */
-/* re->winx,winy is coordinate space of entire image, partrct the part within */
RenderResult *render_result_new(Render *re,
rcti *partrct,
const char *layername,
@@ -733,10 +726,6 @@ static int order_render_passes(const void *a, const void *b)
return (rpa->view_id < rpb->view_id);
}
-/**
- * From imbuf, if a handle was returned and
- * it's not a single-layer multi-view we convert this to render result.
- */
RenderResult *render_result_new_from_exr(
void *exrhandle, const char *colorspace, bool predivide, int rectx, int recty)
{
@@ -837,9 +826,6 @@ static void do_merge_tile(
}
}
-/* used when rendering to a full buffer, or when reading the exr part-layer-pass file */
-/* no test happens here if it fits... we also assume layers are in sync */
-/* is used within threads */
void render_result_merge(RenderResult *rr, RenderResult *rrpart)
{
RenderLayer *rl, *rlp;
@@ -869,8 +855,6 @@ void render_result_merge(RenderResult *rr, RenderResult *rrpart)
}
}
-/* Called from the UI and render pipeline, to save multilayer and multiview
- * images, optionally isolating a specific, view, layer or RGBA/Z pass. */
bool RE_WriteRenderResult(ReportList *reports,
RenderResult *rr,
const char *filename,
@@ -1040,7 +1024,6 @@ void render_result_single_layer_begin(Render *re)
re->result = NULL;
}
-/* if scemode is R_SINGLE_LAYER, at end of rendering, merge the both render results */
void render_result_single_layer_end(Render *re)
{
ViewLayer *view_layer;
@@ -1085,7 +1068,6 @@ void render_result_single_layer_end(Render *re)
re->pushedresult = NULL;
}
-/* called for reading temp files, and for external engines */
int render_result_exr_file_read_path(RenderResult *rr,
RenderLayer *rl_single,
const char *filepath)
@@ -1184,7 +1166,6 @@ void render_result_exr_file_cache_write(Render *re)
RE_WriteRenderResult(NULL, rr, str, NULL, NULL, -1);
}
-/* For cache, makes exact copy of render result */
bool render_result_exr_file_cache_read(Render *re)
{
/* File path to cache. */
diff --git a/source/blender/render/intern/render_result.h b/source/blender/render/intern/render_result.h
index 34b8143869c..ede0a0d21ea 100644
--- a/source/blender/render/intern/render_result.h
+++ b/source/blender/render/intern/render_result.h
@@ -46,6 +46,12 @@ extern "C" {
/* New */
+/**
+ * Called by main render as well for parts will read info from Render *re to define layers.
+ * \note Called in threads.
+ *
+ * `re->winx`, `re->winy` is coordinate space of entire image, `partrct` the part within.
+ */
struct RenderResult *render_result_new(struct Render *re,
struct rcti *partrct,
const char *layername,
@@ -53,6 +59,10 @@ struct RenderResult *render_result_new(struct Render *re,
void render_result_passes_allocated_ensure(struct RenderResult *rr);
+/**
+ * From imbuf, if a handle was returned and
+ * it's not a single-layer multi-view we convert this to render result.
+ */
struct RenderResult *render_result_new_from_exr(
void *exrhandle, const char *colorspace, bool predivide, int rectx, int recty);
@@ -61,6 +71,11 @@ void render_result_views_new(struct RenderResult *rr, const struct RenderData *r
/* Merge */
+/**
+ * Used when rendering to a full buffer, or when reading the EXR part-layer-pass file.
+ * no test happens here if it fits... we also assume layers are in sync.
+ * \note Is used within threads.
+ */
void render_result_merge(struct RenderResult *rr, struct RenderResult *rrpart);
/* Add Passes */
@@ -70,14 +85,22 @@ void render_result_clone_passes(struct Render *re, struct RenderResult *rr, cons
/* Free */
void render_result_free(struct RenderResult *rr);
+/**
+ * Version that's compatible with full-sample buffers.
+ */
void render_result_free_list(struct ListBase *lb, struct RenderResult *rr);
/* Single Layer Render */
void render_result_single_layer_begin(struct Render *re);
+/**
+ * If #RenderData.scemode is #R_SINGLE_LAYER, at end of rendering, merge the both render results.
+ */
void render_result_single_layer_end(struct Render *re);
-/* render pass wrapper for gpencil */
+/**
+ * Render pass wrapper for grease-pencil.
+ */
struct RenderPass *render_layer_add_pass(struct RenderResult *rr,
struct RenderLayer *rl,
int channels,
@@ -86,6 +109,9 @@ struct RenderPass *render_layer_add_pass(struct RenderResult *rr,
const char *chan_id,
const bool allocate);
+/**
+ * Called for reading temp files, and for external engines.
+ */
int render_result_exr_file_read_path(struct RenderResult *rr,
struct RenderLayer *rl_single,
const char *filepath);
@@ -93,6 +119,9 @@ int render_result_exr_file_read_path(struct RenderResult *rr,
/* EXR cache */
void render_result_exr_file_cache_write(struct Render *re);
+/**
+ * For cache, makes exact copy of render result.
+ */
bool render_result_exr_file_cache_read(struct Render *re);
/* Combined Pixel Rect */
@@ -110,7 +139,13 @@ void render_result_rect_get_pixels(struct RenderResult *rr,
const struct ColorManagedDisplaySettings *display_settings,
const int view_id);
+/**
+ * Create a new views #ListBase in rr without duplicating the memory pointers.
+ */
void render_result_views_shallowcopy(struct RenderResult *dst, struct RenderResult *src);
+/**
+ * Free the views created temporarily.
+ */
void render_result_views_shallowdelete(struct RenderResult *rr);
bool render_result_has_views(const struct RenderResult *rr);
diff --git a/source/blender/render/intern/texture_pointdensity.c b/source/blender/render/intern/texture_pointdensity.c
index 06dd570ce2c..8ca1decdea7 100644
--- a/source/blender/render/intern/texture_pointdensity.c
+++ b/source/blender/render/intern/texture_pointdensity.c
@@ -928,9 +928,6 @@ static void point_density_sample_func(void *__restrict data_v,
}
}
-/* NOTE 1: Requires RE_point_density_cache() to be called first.
- * NOTE 2: Frees point density structure after sampling.
- */
void RE_point_density_sample(Depsgraph *depsgraph,
PointDensity *pd,
const int resolution,
diff --git a/source/blender/render/intern/texture_procedural.c b/source/blender/render/intern/texture_procedural.c
index 5a94bc09b93..f563cb9f84a 100644
--- a/source/blender/render/intern/texture_procedural.c
+++ b/source/blender/render/intern/texture_procedural.c
@@ -1399,9 +1399,6 @@ static int multitex_nodes_intern(Tex *tex,
use_nodes);
}
-/* this is called from the shader and texture nodes
- * Use it from render pipeline only!
- */
int multitex_nodes(Tex *tex,
const float texvec[3],
float dxt[3],
@@ -1429,13 +1426,6 @@ int multitex_nodes(Tex *tex,
true);
}
-/**
- * \warning if the texres's values are not declared zero,
- * check the return value to be sure the color values are set before using the r/g/b values,
- * otherwise you may use uninitialized values - Campbell
- *
- * Use it for stuff which is out of render pipeline.
- */
int multitex_ext(Tex *tex,
float texvec[3],
float dxt[3],
@@ -1463,10 +1453,6 @@ int multitex_ext(Tex *tex,
true);
}
-/* extern-tex doesn't support nodes (ntreeBeginExec() can't be called when rendering is going on)\
- *
- * Use it for stuff which is out of render pipeline.
- */
int multitex_ext_safe(Tex *tex,
const float texvec[3],
TexResult *texres,
@@ -1492,8 +1478,6 @@ int multitex_ext_safe(Tex *tex,
/* ------------------------------------------------------------------------- */
-/* in = destination, tex = texture, out = previous color */
-/* fact = texture strength, facg = button strength value */
void texture_rgb_blend(
float in[3], const float tex[3], const float out[3], float fact, float facg, int blendtype)
{
@@ -1722,11 +1706,6 @@ float texture_value_blend(float tex, float out, float fact, float facg, int blen
/* ------------------------------------------------------------------------- */
-/**
- * \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,
diff --git a/source/blender/render/intern/zbuf.c b/source/blender/render/intern/zbuf.c
index 726124871ee..1812a492ac0 100644
--- a/source/blender/render/intern/zbuf.c
+++ b/source/blender/render/intern/zbuf.c
@@ -41,7 +41,6 @@
/* ****************** Spans ******************************* */
-/* each zbuffer has coordinates transformed to local rect coordinates, so we can simply clip */
void zbuf_alloc_span(ZSpan *zspan, int rectx, int recty)
{
memset(zspan, 0, sizeof(ZSpan));
@@ -170,9 +169,6 @@ static void zbuf_add_to_span(ZSpan *zspan, const float v1[2], const float v2[2])
/* Functions */
/*-----------------------------------------------------------*/
-/* Scan-convert for strand triangles, calls function for each x, y coordinate
- * and gives UV barycentrics and z. */
-
void zspan_scanconvert(ZSpan *zspan,
void *handle,
float *v1,
diff --git a/source/blender/render/intern/zbuf.h b/source/blender/render/intern/zbuf.h
index 41fa15c594f..c5108a9d6a7 100644
--- a/source/blender/render/intern/zbuf.h
+++ b/source/blender/render/intern/zbuf.h
@@ -33,9 +33,16 @@ typedef struct ZSpan {
float *span1, *span2;
} ZSpan;
+/**
+ * Each Z-buffer has coordinates transformed to local rect coordinates, so we can simply clip.
+ */
void zbuf_alloc_span(struct ZSpan *zspan, int rectx, int recty);
void zbuf_free_span(struct ZSpan *zspan);
+/**
+ * Scan-convert for strand triangles, calls function for each x, y coordinate
+ * and gives UV barycentrics and z.
+ */
void zspan_scanconvert(struct ZSpan *zspan,
void *handle,
float *v1,
diff --git a/source/blender/sequencer/SEQ_add.h b/source/blender/sequencer/SEQ_add.h
index d2a731d9953..936868725b4 100644
--- a/source/blender/sequencer/SEQ_add.h
+++ b/source/blender/sequencer/SEQ_add.h
@@ -67,43 +67,142 @@ typedef struct SeqLoadData {
bool allow_invalid_file; /* Used by RNA API to create placeholder strips. */
} SeqLoadData;
+/**
+ * Initialize common SeqLoadData members
+ *
+ * \param load_data: SeqLoadData to be initialized
+ * \param name: strip name (can be NULL)
+ * \param path: path to file that is used as strip input (can be NULL)
+ * \param start_frame: timeline frame where strip will be created
+ * \param channel: timeline channel where strip will be created
+ */
void SEQ_add_load_data_init(struct SeqLoadData *load_data,
const char *name,
const char *path,
const int start_frame,
const int channel);
+/**
+ * Add image strip.
+ * \note Use #SEQ_add_image_set_directory() and #SEQ_add_image_load_file() to load image sequences
+ *
+ * \param bmain: Main reference
+ * \param scene: Scene where strips will be added
+ * \param seqbase: ListBase where strips will be added
+ * \param load_data: SeqLoadData with information necessary to create strip
+ * \return created strip
+ */
struct Sequence *SEQ_add_image_strip(struct Main *bmain,
struct Scene *scene,
struct ListBase *seqbase,
struct SeqLoadData *load_data);
+/**
+ * Add sound strip.
+ * \note Use SEQ_add_image_set_directory() and SEQ_add_image_load_file() to load image sequences
+ *
+ * \param bmain: Main reference
+ * \param scene: Scene where strips will be added
+ * \param seqbase: ListBase where strips will be added
+ * \param load_data: SeqLoadData with information necessary to create strip
+ * \return created strip
+ */
struct Sequence *SEQ_add_sound_strip(struct Main *bmain,
struct Scene *scene,
struct ListBase *seqbase,
struct SeqLoadData *load_data,
const double audio_offset);
+/**
+ * Add meta strip.
+ *
+ * \param scene: Scene where strips will be added
+ * \param seqbase: ListBase where strips will be added
+ * \param load_data: SeqLoadData with information necessary to create strip
+ * \return created strip
+ */
struct Sequence *SEQ_add_meta_strip(struct Scene *scene,
struct ListBase *seqbase,
struct SeqLoadData *load_data);
+/**
+ * Add movie strip.
+ *
+ * \param bmain: Main reference
+ * \param scene: Scene where strips will be added
+ * \param seqbase: ListBase where strips will be added
+ * \param load_data: SeqLoadData with information necessary to create strip
+ * \return created strip
+ */
struct Sequence *SEQ_add_movie_strip(struct Main *bmain,
struct Scene *scene,
struct ListBase *seqbase,
struct SeqLoadData *load_data,
double *r_start_offset);
+/**
+ * Add scene strip.
+ *
+ * \param scene: Scene where strips will be added
+ * \param seqbase: ListBase where strips will be added
+ * \param load_data: SeqLoadData with information necessary to create strip
+ * \return created strip
+ */
struct Sequence *SEQ_add_scene_strip(struct Scene *scene,
struct ListBase *seqbase,
struct SeqLoadData *load_data);
+/**
+ * Add movieclip strip.
+ *
+ * \param scene: Scene where strips will be added
+ * \param seqbase: ListBase where strips will be added
+ * \param load_data: SeqLoadData with information necessary to create strip
+ * \return created strip
+ */
struct Sequence *SEQ_add_movieclip_strip(struct Scene *scene,
struct ListBase *seqbase,
struct SeqLoadData *load_data);
+/**
+ * Add mask strip.
+ *
+ * \param scene: Scene where strips will be added
+ * \param seqbase: ListBase where strips will be added
+ * \param load_data: SeqLoadData with information necessary to create strip
+ * \return created strip
+ */
struct Sequence *SEQ_add_mask_strip(struct Scene *scene,
struct ListBase *seqbase,
struct SeqLoadData *load_data);
+/**
+ * Add effect strip.
+ *
+ * \param scene: Scene where strips will be added
+ * \param seqbase: ListBase where strips will be added
+ * \param load_data: SeqLoadData with information necessary to create strip
+ * \return created strip
+ */
struct Sequence *SEQ_add_effect_strip(struct Scene *scene,
struct ListBase *seqbase,
struct SeqLoadData *load_data);
+/**
+ * Set directory used by image strip.
+ *
+ * \param seq: image strip to be changed
+ * \param path: directory path
+ */
void SEQ_add_image_set_directory(struct Sequence *seq, char *path);
+/**
+ * Set directory used by image strip.
+ *
+ * \param seq: image strip to be changed
+ * \param strip_frame: frame index of strip to be changed
+ * \param filename: image filename (only filename, not complete path)
+ */
void SEQ_add_image_load_file(struct Sequence *seq, size_t strip_frame, char *filename);
+/**
+ * Set image strip alpha mode
+ *
+ * \param seq: image strip to be changed
+ */
void SEQ_add_image_init_alpha_mode(struct Sequence *seq);
+/**
+ * \note caller should run `SEQ_time_update_sequence(scene, seq)` after..
+ */
void SEQ_add_reload_new_file(struct Main *bmain,
struct Scene *scene,
struct Sequence *seq,
diff --git a/source/blender/sequencer/SEQ_clipboard.h b/source/blender/sequencer/SEQ_clipboard.h
index ea7f01e6ae3..72388c5db64 100644
--- a/source/blender/sequencer/SEQ_clipboard.h
+++ b/source/blender/sequencer/SEQ_clipboard.h
@@ -38,6 +38,13 @@ void SEQ_clipboard_pointers_store(struct Main *bmain, struct ListBase *seqbase);
void SEQ_clipboard_pointers_restore(struct ListBase *seqbase, struct Main *bmain);
void SEQ_clipboard_free(void);
void SEQ_clipboard_active_seq_name_store(struct Scene *scene);
+/**
+ * Check if strip was active when it was copied. User should restrict this check to pasted strips
+ * before ensuring original name, because strip name comparison is used to check.
+ *
+ * \param pasted_seq: Strip that is pasted(duplicated) from clipboard
+ * \return true if strip was active, false otherwise
+ */
bool SEQ_clipboard_pasted_seq_was_active(struct Sequence *pasted_seq);
#ifdef __cplusplus
diff --git a/source/blender/sequencer/SEQ_edit.h b/source/blender/sequencer/SEQ_edit.h
index f3a64c9cd62..fe12ac253b9 100644
--- a/source/blender/sequencer/SEQ_edit.h
+++ b/source/blender/sequencer/SEQ_edit.h
@@ -33,18 +33,40 @@ struct Scene;
struct Sequence;
int SEQ_edit_sequence_swap(struct Sequence *seq_a, struct Sequence *seq_b, const char **error_str);
+/**
+ * Move sequence to seqbase.
+ *
+ * \param scene: Scene containing the editing
+ * \param seqbase: seqbase where `seq` is located
+ * \param seq: Sequence to move
+ * \param dst_seqbase: Target seqbase
+ */
bool SEQ_edit_move_strip_to_seqbase(struct Scene *scene,
ListBase *seqbase,
- struct Sequence *src_seq,
+ struct Sequence *seq,
ListBase *dst_seqbase);
+/**
+ * Move sequence to meta sequence.
+ *
+ * \param scene: Scene containing the editing
+ * \param src_seq: Sequence to move
+ * \param dst_seqm: Target Meta sequence
+ * \param error_str: Error message
+ */
bool SEQ_edit_move_strip_to_meta(struct Scene *scene,
struct Sequence *src_seq,
struct Sequence *dst_seqm,
const char **error_str);
bool SEQ_meta_separate(struct Scene *scene, struct Sequence *src_meta, const char **error_str);
+/**
+ * Flag seq and its users (effects) for removal.
+ */
void SEQ_edit_flag_for_removal(struct Scene *scene,
struct ListBase *seqbase,
struct Sequence *seq);
+/**
+ * Remove all flagged sequences, return true if sequence is removed.
+ */
void SEQ_edit_remove_flagged_sequences(struct Scene *scene, struct ListBase *seqbase);
void SEQ_edit_update_muting(struct Editing *ed);
@@ -53,6 +75,17 @@ typedef enum eSeqSplitMethod {
SEQ_SPLIT_HARD,
} eSeqSplitMethod;
+/**
+ * Split Sequence at timeline_frame in two.
+ *
+ * \param bmain: Main in which Sequence is located
+ * \param scene: Scene in which Sequence is located
+ * \param seqbase: ListBase in which Sequence is located
+ * \param seq: Sequence to be split
+ * \param timeline_frame: frame at which seq is split.
+ * \param method: affects type of offset to be applied to resize Sequence
+ * \return The newly created sequence strip. This is always Sequence on right side.
+ */
struct Sequence *SEQ_edit_strip_split(struct Main *bmain,
struct Scene *scene,
struct ListBase *seqbase,
@@ -60,6 +93,15 @@ struct Sequence *SEQ_edit_strip_split(struct Main *bmain,
const int timeline_frame,
const eSeqSplitMethod method,
const char **r_error);
+/**
+ * Find gap after initial_frame and move strips on right side to close the gap
+ *
+ * \param scene: Scene in which strips are located
+ * \param seqbase: ListBase in which strips are located
+ * \param initial_frame: frame on timeline from where gaps are searched for
+ * \param remove_all_gaps: remove all gaps instead of one gap
+ * \return true if gap is removed, otherwise false
+ */
bool SEQ_edit_remove_gaps(struct Scene *scene,
struct ListBase *seqbase,
const int initial_frame,
diff --git a/source/blender/sequencer/SEQ_iterator.h b/source/blender/sequencer/SEQ_iterator.h
index 4de7c09640b..2826e6b75cb 100644
--- a/source/blender/sequencer/SEQ_iterator.h
+++ b/source/blender/sequencer/SEQ_iterator.h
@@ -63,52 +63,184 @@ typedef struct SeqIterator {
bool iterator_initialized;
} SeqIterator;
+/**
+ * Utility function for SEQ_ITERATOR_FOREACH macro.
+ * Ensure, that iterator is initialized. During initialization return pointer to collection element
+ * and step gset iterator. When this function is called after iterator has been initialized, it
+ * will do nothing and return true.
+ *
+ * \param collection: collection to iterate
+ * \param iterator: iterator to be initialized
+ * \param r_seq: pointer to Sequence pointer
+ *
+ * \return false when iterator can not be initialized, true otherwise
+ */
bool SEQ_iterator_ensure(SeqCollection *collection,
SeqIterator *iterator,
struct Sequence **r_seq);
+/**
+ * Utility function for SEQ_ITERATOR_FOREACH macro.
+ * Yield collection element
+ *
+ * \param iterator: iterator to be initialized
+ *
+ * \return collection element or NULL when iteration has ended
+ */
struct Sequence *SEQ_iterator_yield(SeqIterator *iterator);
-/* Callback format for the for_each function below. */
+/**
+ * Callback format for the for_each function below.
+ */
typedef bool (*SeqForEachFunc)(struct Sequence *seq, void *user_data);
+/**
+ * Utility function to recursively iterate through all sequence strips in a `seqbase` list.
+ * Uses callback to do operations on each sequence element.
+ * The callback can stop the iteration if needed.
+ *
+ * \param seqbase: #ListBase of sequences to be iterated over.
+ * \param callback: query function callback, returns false if iteration should stop.
+ * \param user_data: pointer to user data that can be used in the callback function.
+ */
void SEQ_for_each_callback(struct ListBase *seqbase, SeqForEachFunc callback, void *user_data);
+/**
+ * Create new empty strip collection.
+ *
+ * \return empty strip collection.
+ */
SeqCollection *SEQ_collection_create(const char *name);
+/**
+ * Duplicate collection
+ *
+ * \param collection: collection to be duplicated
+ * \return duplicate of collection
+ */
SeqCollection *SEQ_collection_duplicate(SeqCollection *collection);
+/**
+ * Return number of items in collection.
+ */
uint SEQ_collection_len(const SeqCollection *collection);
+/**
+ * Check if seq is in collection.
+ */
bool SEQ_collection_has_strip(const struct Sequence *seq, const SeqCollection *collection);
-bool SEQ_collection_append_strip(struct Sequence *seq, SeqCollection *data);
-bool SEQ_collection_remove_strip(struct Sequence *seq, SeqCollection *data);
+/**
+ * Add strip to collection.
+ *
+ * \param seq: strip to be added
+ * \param collection: collection to which strip will be added
+ * \return false if strip is already in set, otherwise true
+ */
+bool SEQ_collection_append_strip(struct Sequence *seq, SeqCollection *collection);
+/**
+ * Remove strip from collection.
+ *
+ * \param seq: strip to be removed
+ * \param collection: collection from which strip will be removed
+ * \return true if strip exists in set and it was removed from set, otherwise false
+ */
+bool SEQ_collection_remove_strip(struct Sequence *seq, SeqCollection *collection);
+/**
+ * Free strip collection.
+ *
+ * \param collection: collection to be freed
+ */
void SEQ_collection_free(SeqCollection *collection);
+/**
+ * Move strips from collection_src to collection_dst. Source collection will be freed.
+ *
+ * \param collection_dst: destination collection
+ * \param collection_src: source collection
+ */
void SEQ_collection_merge(SeqCollection *collection_dst, SeqCollection *collection_src);
+/**
+ * Remove strips from collection that are also in `exclude_elements`. Source collection will be
+ * freed.
+ *
+ * \param collection: collection from which strips are removed
+ * \param exclude_elements: collection of strips to be removed
+ */
void SEQ_collection_exclude(SeqCollection *collection, SeqCollection *exclude_elements);
+/**
+ * Expand collection by running SEQ_query() for each strip, which will be used as reference.
+ * Results of these queries will be merged into provided collection.
+ *
+ * \param seqbase: ListBase in which strips are queried
+ * \param collection: SeqCollection to be expanded
+ * \param seq_query_func: query function callback
+ */
void SEQ_collection_expand(struct ListBase *seqbase,
SeqCollection *collection,
- void query_func(struct Sequence *seq_reference,
- struct ListBase *seqbase,
- SeqCollection *collection));
+ void seq_query_func(struct Sequence *seq_reference,
+ struct ListBase *seqbase,
+ SeqCollection *collection));
+/**
+ * Query strips from seqbase. seq_reference is used by query function as filter condition.
+ *
+ * \param seq_reference: reference strip for query function
+ * \param seqbase: ListBase in which strips are queried
+ * \param seq_query_func: query function callback
+ * \return strip collection
+ */
SeqCollection *SEQ_query_by_reference(struct Sequence *seq_reference,
struct ListBase *seqbase,
void seq_query_func(struct Sequence *seq_reference,
struct ListBase *seqbase,
SeqCollection *collection));
+/**
+ * Query all selected strips in seqbase.
+ *
+ * \param seqbase: ListBase in which strips are queried
+ * \return strip collection
+ */
SeqCollection *SEQ_query_selected_strips(struct ListBase *seqbase);
+/**
+ * Query all unselected strips in seqbase.
+ *
+ * \param seqbase: ListBase in which strips are queried
+ * \return strip collection
+ */
SeqCollection *SEQ_query_unselected_strips(struct ListBase *seqbase);
+/**
+ * Query all strips in seqbase. This does not include strips nested in meta strips.
+ *
+ * \param seqbase: ListBase in which strips are queried
+ * \return strip collection
+ */
SeqCollection *SEQ_query_all_strips(ListBase *seqbase);
+/**
+ * Query all strips in seqbase and nested meta strips.
+ *
+ * \param seqbase: ListBase in which strips are queried
+ * \return strip collection
+ */
SeqCollection *SEQ_query_all_strips_recursive(ListBase *seqbase);
+/**
+ * Query strips that are rendered at \a timeline_frame when \a displayed channel is viewed
+ *
+ * \param seqbase: ListBase in which strips are queried
+ * \param timeline_frame: viewed frame
+ * \param displayed_channel: viewed channel. when set to 0, no channel filter is applied
+ * \return strip collection
+ */
SeqCollection *SEQ_query_rendered_strips(ListBase *seqbase,
const int timeline_frame,
const int displayed_channel);
+/**
+ * Query all effect strips that are directly or indirectly connected to seq_reference.
+ * This includes all effects of seq_reference, strips used by another inputs and their effects, so
+ * that whole chain is fully independent of other strips.
+ *
+ * \param seq_reference: reference strip
+ * \param seqbase: ListBase in which strips are queried
+ * \param collection: collection to be filled
+ */
void SEQ_query_strip_effect_chain(struct Sequence *seq_reference,
struct ListBase *seqbase,
SeqCollection *collection);
void SEQ_filter_selected_strips(SeqCollection *collection);
-/* Utilities to access these as tags. */
-int SEQ_query_rendered_strips_to_tag(ListBase *seqbase,
- const int timeline_frame,
- const int displayed_channel);
-
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/sequencer/SEQ_prefetch.h b/source/blender/sequencer/SEQ_prefetch.h
index 93fc8883e99..980f7611094 100644
--- a/source/blender/sequencer/SEQ_prefetch.h
+++ b/source/blender/sequencer/SEQ_prefetch.h
@@ -31,6 +31,10 @@ struct Main;
struct Scene;
void SEQ_prefetch_stop_all(void);
+/**
+ * Use also to update scene and context changes
+ * This function should almost always be called by cache invalidation, not directly.
+ */
void SEQ_prefetch_stop(struct Scene *scene);
bool SEQ_prefetch_need_redraw(struct Main *bmain, struct Scene *scene);
diff --git a/source/blender/sequencer/SEQ_relations.h b/source/blender/sequencer/SEQ_relations.h
index 3b9d430a3c9..9571e826759 100644
--- a/source/blender/sequencer/SEQ_relations.h
+++ b/source/blender/sequencer/SEQ_relations.h
@@ -34,8 +34,14 @@ struct ReportList;
struct Scene;
struct Sequence;
+/**
+ * Function to free imbuf and anim data on changes.
+ */
void SEQ_relations_sequence_free_anim(struct Sequence *seq);
bool SEQ_relations_check_scene_recursion(struct Scene *scene, struct ReportList *reports);
+/**
+ * Check if "seq_main" (indirectly) uses strip "seq".
+ */
bool SEQ_relations_render_loop_check(struct Sequence *seq_main, struct Sequence *seq);
void SEQ_relations_free_imbuf(struct Scene *scene, struct ListBase *seqbasep, bool for_render);
void SEQ_relations_invalidate_cache_raw(struct Scene *scene, struct Sequence *seq);
@@ -48,11 +54,18 @@ void SEQ_relations_invalidate_cache_in_range(struct Scene *scene,
struct Sequence *seq,
struct Sequence *range_mask,
int invalidate_types);
+/**
+ * Release FFmpeg handles of strips that are not currently displayed to minimize memory usage.
+ */
void SEQ_relations_free_all_anim_ibufs(struct Scene *scene, int timeline_frame);
-/* A debug and development function which checks whether sequences have unique UUIDs.
- * Errors will be reported to the console. */
+/**
+ * A debug and development function which checks whether sequences have unique UUIDs.
+ * Errors will be reported to the console.
+ */
void SEQ_relations_check_uuids_unique_and_report(const struct Scene *scene);
-/* Generate new UUID for the given sequence. */
+/**
+ * Generate new UUID for the given sequence.
+ */
void SEQ_relations_session_uuid_generate(struct Sequence *sequence);
void SEQ_cache_cleanup(struct Scene *scene);
@@ -61,6 +74,9 @@ void SEQ_cache_iterate(
void *userdata,
bool callback_init(void *userdata, size_t item_count),
bool callback_iter(void *userdata, struct Sequence *seq, int timeline_frame, int cache_type));
+/**
+ * Return immediate parent meta of sequence.
+ */
struct Sequence *SEQ_find_metastrip_by_sequence(ListBase *seqbase /* = ed->seqbase */,
struct Sequence *meta /* = NULL */,
struct Sequence *seq);
diff --git a/source/blender/sequencer/SEQ_render.h b/source/blender/sequencer/SEQ_render.h
index e99dc6d344f..7f10160bf6a 100644
--- a/source/blender/sequencer/SEQ_render.h
+++ b/source/blender/sequencer/SEQ_render.h
@@ -63,12 +63,20 @@ typedef struct SeqRenderData {
// bool gpu_full_samples;
} SeqRenderData;
+/**
+ * \return The image buffer or NULL.
+ *
+ * \note The returned #ImBuf has its reference increased, free after usage!
+ */
struct ImBuf *SEQ_render_give_ibuf(const SeqRenderData *context,
float timeline_frame,
int chanshown);
struct ImBuf *SEQ_render_give_ibuf_direct(const SeqRenderData *context,
float timeline_frame,
struct Sequence *seq);
+/**
+ * Render the series of thumbnails and store in cache.
+ */
void SEQ_render_thumbnails(const struct SeqRenderData *context,
struct Sequence *seq,
struct Sequence *seq_orig,
@@ -76,12 +84,22 @@ void SEQ_render_thumbnails(const struct SeqRenderData *context,
float frame_step,
rctf *view_area,
const short *stop);
+/**
+ * Get cached thumbnails.
+ */
struct ImBuf *SEQ_get_thumbnail(const struct SeqRenderData *context,
struct Sequence *seq,
float timeline_frame,
rcti *crop,
bool clipped);
+/**
+ * Get frame step for equally spaced thumbnails. These thumbnails should always be present in
+ * memory, so they can be used when zooming.
+ */
int SEQ_render_thumbnails_guaranteed_set_frame_step_get(const struct Sequence *seq);
+/**
+ * Render set of evenly spaced thumbnails that are drawn when zooming..
+ */
void SEQ_render_thumbnails_base_set(const struct SeqRenderData *context,
struct Sequence *seq,
struct Sequence *seq_orig,
diff --git a/source/blender/sequencer/SEQ_sequencer.h b/source/blender/sequencer/SEQ_sequencer.h
index 1b8982da0d2..a3ee716c3f6 100644
--- a/source/blender/sequencer/SEQ_sequencer.h
+++ b/source/blender/sequencer/SEQ_sequencer.h
@@ -69,12 +69,43 @@ struct SequencerToolSettings *SEQ_tool_settings_copy(struct SequencerToolSetting
struct Editing *SEQ_editing_get(const struct Scene *scene);
struct Editing *SEQ_editing_ensure(struct Scene *scene);
void SEQ_editing_free(struct Scene *scene, const bool do_id_user);
+/**
+ * Get seqbase that is being viewed currently. This can be main seqbase or meta strip seqbase
+ *
+ * \param ed: sequence editor data
+ * \return pointer to active seqbase. returns NULL if ed is NULL
+ */
struct ListBase *SEQ_active_seqbase_get(const struct Editing *ed);
+/**
+ * Set seqbase that is being viewed currently. This can be main seqbase or meta strip seqbase
+ *
+ * \param ed: sequence editor data
+ * \param seqbase: ListBase with strips
+ */
void SEQ_seqbase_active_set(struct Editing *ed, struct ListBase *seqbase);
struct Sequence *SEQ_sequence_alloc(ListBase *lb, int timeline_frame, int machine, int type);
void SEQ_sequence_free(struct Scene *scene, struct Sequence *seq, const bool do_clean_animdata);
+/**
+ * Create and initialize #MetaStack, append it to `ed->metastack` ListBase
+ *
+ * \param ed: sequence editor data
+ * \param seq_meta: meta strip
+ * \return pointer to created meta stack
+ */
struct MetaStack *SEQ_meta_stack_alloc(struct Editing *ed, struct Sequence *seq_meta);
+/**
+ * Get #MetaStack that corresponds to current level that is being viewed
+ *
+ * \param ed: sequence editor data
+ * \return pointer to meta stack
+ */
struct MetaStack *SEQ_meta_stack_active_get(const struct Editing *ed);
+/**
+ * Free #MetaStack and remove it from `ed->metastack` ListBase.
+ *
+ * \param ed: sequence editor data
+ * \param ms: meta stack
+ */
void SEQ_meta_stack_free(struct Editing *ed, struct MetaStack *ms);
void SEQ_offset_animdata(struct Scene *scene, struct Sequence *seq, int ofs);
void SEQ_dupe_animdata(struct Scene *scene, const char *name_src, const char *name_dst);
@@ -91,7 +122,9 @@ void SEQ_sequence_base_dupli_recursive(const struct Scene *scene_src,
const int flag);
bool SEQ_valid_strip_channel(struct Sequence *seq);
-/* Read and Write functions for .blend file data */
+/**
+ * Read and Write functions for `.blend` file data.
+ */
void SEQ_blend_write(struct BlendWriter *writer, struct ListBase *seqbase);
void SEQ_blend_read(struct BlendDataReader *reader, struct ListBase *seqbase);
@@ -101,7 +134,13 @@ void SEQ_blend_read_lib(struct BlendLibReader *reader,
void SEQ_blend_read_expand(struct BlendExpander *expander, struct ListBase *seqbase);
-/* Depsgraph update function */
+/* Depsgraph update function. */
+
+/**
+ * Evaluate parts of sequences which needs to be done as a part of a dependency graph evaluation.
+ * This does NOT include actual rendering of the strips, but rather makes them up-to-date for
+ * animation playback and makes them ready for the sequencer's rendering pipeline to render them.
+ */
void SEQ_eval_sequences(struct Depsgraph *depsgraph,
struct Scene *scene,
struct ListBase *seqbase);
@@ -112,8 +151,29 @@ typedef enum eSequenceLookupTag {
SEQ_LOOKUP_TAG_INVALID = (1 << 0),
} eSequenceLookupTag;
+/**
+ * Find a sequence with a given name.
+ * If lookup hash doesn't exist, it will be created. If hash is tagged as invalid, it will be
+ * rebuilt.
+ *
+ * \param scene: scene that owns lookup hash
+ * \param key: Sequence name without SQ prefix (seq->name + 2)
+ *
+ * \return pointer to Sequence
+ */
struct Sequence *SEQ_sequence_lookup_by_name(const struct Scene *scene, const char *key);
+/**
+ * Free lookup hash data.
+ *
+ * \param scene: scene that owns lookup hash
+ */
void SEQ_sequence_lookup_free(const struct Scene *scene);
+/**
+ * Find a sequence with a given name.
+ *
+ * \param scene: scene that owns lookup hash
+ * \param tag: tag to set
+ */
void SEQ_sequence_lookup_tag(const struct Scene *scene, eSequenceLookupTag tag);
#ifdef __cplusplus
diff --git a/source/blender/sequencer/SEQ_time.h b/source/blender/sequencer/SEQ_time.h
index a0abaf8813a..e563e94da24 100644
--- a/source/blender/sequencer/SEQ_time.h
+++ b/source/blender/sequencer/SEQ_time.h
@@ -32,8 +32,27 @@ struct Scene;
struct Sequence;
struct rctf;
+/**
+ * Initialize given rectangle with the Scene's timeline boundaries.
+ *
+ * \param scene: the Scene instance whose timeline boundaries are extracted from
+ * \param rect: output parameter to be filled with timeline boundaries
+ */
void SEQ_timeline_init_boundbox(const struct Scene *scene, struct rctf *rect);
+/**
+ * Stretch the given rectangle to include the given strips boundaries
+ *
+ * \param seqbase: ListBase in which strips are located
+ * \param rect: output parameter to be filled with strips' boundaries
+ */
void SEQ_timeline_expand_boundbox(const struct ListBase *seqbase, struct rctf *rect);
+/**
+ * Define boundary rectangle of sequencer timeline and fill in rect data
+ *
+ * \param scene: Scene in which strips are located
+ * \param seqbase: ListBase in which strips are located
+ * \param rect: data structure describing rectangle, that will be filled in by this function
+ */
void SEQ_timeline_boundbox(const struct Scene *scene,
const struct ListBase *seqbase,
struct rctf *rect);
@@ -46,6 +65,15 @@ int SEQ_time_find_next_prev_edit(struct Scene *scene,
const bool do_unselected);
void SEQ_time_update_sequence(struct Scene *scene, struct ListBase *seqbase, struct Sequence *seq);
void SEQ_time_update_recursive(struct Scene *scene, struct Sequence *changed_seq);
+/**
+ * Test if strip intersects with timeline frame.
+ * \note This checks if strip would be rendered at this frame. For rendering it is assumed, that
+ * timeline frame has width of 1 frame and therefore ends at timeline_frame + 1
+ *
+ * \param seq: Sequence to be checked
+ * \param timeline_frame: absolute frame position
+ * \return true if strip intersects with timeline frame.
+ */
bool SEQ_time_strip_intersects_frame(const struct Sequence *seq, const int timeline_frame);
void SEQ_time_update_meta_strip_range(struct Scene *scene, struct Sequence *seq_meta);
diff --git a/source/blender/sequencer/SEQ_transform.h b/source/blender/sequencer/SEQ_transform.h
index 18437680731..fe0c223bcb1 100644
--- a/source/blender/sequencer/SEQ_transform.h
+++ b/source/blender/sequencer/SEQ_transform.h
@@ -36,13 +36,24 @@ int SEQ_transform_get_left_handle_frame(struct Sequence *seq);
int SEQ_transform_get_right_handle_frame(struct Sequence *seq);
void SEQ_transform_set_left_handle_frame(struct Sequence *seq, int val);
void SEQ_transform_set_right_handle_frame(struct Sequence *seq, int val);
+/**
+ * Use to impose limits when dragging/extending - so impossible situations don't happen.
+ * Can't use the #SEQ_LEFTSEL and #SEQ_LEFTSEL directly because the strip may be in a meta-strip.
+ */
void SEQ_transform_handle_xlimits(struct Sequence *seq, int leftflag, int rightflag);
bool SEQ_transform_sequence_can_be_translated(struct Sequence *seq);
+/**
+ * Used so we can do a quick check for single image seq
+ * since they work a bit differently to normal image seq's (during transform).
+ */
bool SEQ_transform_single_image_check(struct Sequence *seq);
void SEQ_transform_fix_single_image_seq_offsets(struct Sequence *seq);
bool SEQ_transform_test_overlap(struct ListBase *seqbasep, struct Sequence *test);
bool SEQ_transform_test_overlap_seq_seq(struct Sequence *seq1, struct Sequence *seq2);
void SEQ_transform_translate_sequence(struct Scene *scene, struct Sequence *seq, int delta);
+/**
+ * \return 0 if there weren't enough space.
+ */
bool SEQ_transform_seqbase_shuffle_ex(struct ListBase *seqbasep,
struct Sequence *test,
struct Scene *evil_scene,
@@ -55,21 +66,57 @@ bool SEQ_transform_seqbase_shuffle_time(struct SeqCollection *strips_to_shuffle,
struct Scene *evil_scene,
struct ListBase *markers,
const bool use_sync_markers);
+/**
+ * Check if the selected seq's reference unselected seq's.
+ */
bool SEQ_transform_seqbase_isolated_sel_check(struct ListBase *seqbase);
+/**
+ * Move strips and markers (if not locked) that start after timeline_frame by delta frames
+ *
+ * \param scene: Scene in which strips are located
+ * \param seqbase: ListBase in which strips are located
+ * \param delta: offset in frames to be applied
+ * \param timeline_frame: frame on timeline from where strips are moved
+ */
void SEQ_transform_offset_after_frame(struct Scene *scene,
struct ListBase *seqbase,
const int delta,
const int timeline_frame);
/* Image transformation. */
+
void SEQ_image_transform_mirror_factor_get(const struct Sequence *seq, float r_mirror[2]);
+/**
+ * Get strip transform origin offset from image center
+ * NOTE: This function does not apply axis mirror.
+ *
+ * \param scene: Scene in which strips are located
+ * \param seq: Sequence to calculate image transform origin
+ * \param r_origin: return value
+ */
void SEQ_image_transform_origin_offset_pixelspace_get(const struct Scene *scene,
const struct Sequence *seq,
float r_origin[2]);
+/**
+ * Get 4 corner points of strip image, optionally without rotation component applied.
+ * Corner vectors are in viewport space.
+ *
+ * \param scene: Scene in which strips are located
+ * \param seq: Sequence to calculate transformed image quad
+ * \param apply_rotation: Apply sequence rotation transform to the quad
+ * \param r_quad: array of 4 2D vectors
+ */
void SEQ_image_transform_quad_get(const struct Scene *scene,
const struct Sequence *seq,
bool apply_rotation,
float r_quad[4][2]);
+/**
+ * Get 4 corner points of strip image. Corner vectors are in viewport space.
+ *
+ * \param scene: Scene in which strips are located
+ * \param seq: Sequence to calculate transformed image quad
+ * \param r_quad: array of 4 2D vectors
+ */
void SEQ_image_transform_final_quad_get(const struct Scene *scene,
const struct Sequence *seq,
float r_quad[4][2]);
diff --git a/source/blender/sequencer/SEQ_utils.h b/source/blender/sequencer/SEQ_utils.h
index d30a1b2d7ae..58d7a92f370 100644
--- a/source/blender/sequencer/SEQ_utils.h
+++ b/source/blender/sequencer/SEQ_utils.h
@@ -36,6 +36,13 @@ struct Sequence;
struct StripElem;
struct SeqRenderData;
+/**
+ * Sort strips in provided seqbase. Effect strips are trailing the list and they are sorted by
+ * channel position as well.
+ * This is important for SEQ_time_update_sequence to work properly
+ *
+ * \param seqbase: ListBase with strips
+ */
void SEQ_sort(struct ListBase *seqbase);
void SEQ_sequence_base_unique_name_recursive(struct Scene *scene,
struct ListBase *seqbasep,
@@ -43,7 +50,14 @@ void SEQ_sequence_base_unique_name_recursive(struct Scene *scene,
const char *SEQ_sequence_give_name(struct Sequence *seq);
struct ListBase *SEQ_get_seqbase_from_sequence(struct Sequence *seq, int *r_offset);
const struct Sequence *SEQ_get_topmost_sequence(const struct Scene *scene, int frame);
+/**
+ * In cases where we don't know the sequence's listbase.
+ */
struct ListBase *SEQ_get_seqbase_by_seq(struct ListBase *seqbase, struct Sequence *seq);
+/**
+ * Only use as last resort when the StripElem is available but no the Sequence.
+ * (needed for RNA)
+ */
struct Sequence *SEQ_sequence_from_strip_elem(struct ListBase *seqbase, struct StripElem *se);
struct Sequence *SEQ_get_sequence_by_name(struct ListBase *seqbase,
const char *name,
@@ -57,6 +71,13 @@ void SEQ_set_scale_to_fit(const struct Sequence *seq,
const int preview_width,
const int preview_height,
const eSeqImageFitMethod fit_method);
+/**
+ * Ensure, that provided Sequence has unique name. If animation data exists for this Sequence, it
+ * will be duplicated and mapped onto new name
+ *
+ * \param seq: Sequence which name will be ensured to be unique
+ * \param scene: Scene in which name must be unique
+ */
void SEQ_ensure_unique_name(struct Sequence *seq, struct Scene *scene);
#ifdef __cplusplus
}
diff --git a/source/blender/sequencer/intern/clipboard.c b/source/blender/sequencer/intern/clipboard.c
index 05406c50303..73e0f616da4 100644
--- a/source/blender/sequencer/intern/clipboard.c
+++ b/source/blender/sequencer/intern/clipboard.c
@@ -194,13 +194,6 @@ void SEQ_clipboard_active_seq_name_store(Scene *scene)
}
}
-/**
- * Check if strip was active when it was copied. User should restrict this check to pasted strips
- * before ensuring original name, because strip name comparison is used to check.
- *
- * \param pasted_seq: Strip that is pasted(duplicated) from clipboard
- * \return true if strip was active, false otherwise
- */
bool SEQ_clipboard_pasted_seq_was_active(Sequence *pasted_seq)
{
return STREQ(pasted_seq->name, seq_clipboard_active_seq_name);
diff --git a/source/blender/sequencer/intern/disk_cache.c b/source/blender/sequencer/intern/disk_cache.c
index 06d27717bdd..2db6a3cc8ee 100644
--- a/source/blender/sequencer/intern/disk_cache.c
+++ b/source/blender/sequencer/intern/disk_cache.c
@@ -148,7 +148,7 @@ bool seq_disk_cache_is_enabled(Main *bmain)
{
return (U.sequencer_disk_cache_dir[0] != '\0' && U.sequencer_disk_cache_size_limit != 0 &&
(U.sequencer_disk_cache_flag & SEQ_CACHE_DISK_CACHE_ENABLE) != 0 &&
- bmain->name[0] != '\0');
+ bmain->filepath[0] != '\0');
}
static DiskCacheFile *seq_disk_cache_add_file_to_list(SeqDiskCache *disk_cache, const char *path)
diff --git a/source/blender/sequencer/intern/effects.c b/source/blender/sequencer/intern/effects.c
index 6a6889c3679..05ce35deeec 100644
--- a/source/blender/sequencer/intern/effects.c
+++ b/source/blender/sequencer/intern/effects.c
@@ -3135,8 +3135,6 @@ static FCurve *seq_effect_speed_speed_factor_curve_get(Scene *scene, Sequence *s
return id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "speed_factor", 0, NULL);
}
-/* Build frame map when speed in mode #SEQ_SPEED_MULTIPLY is animated.
- * This is, because `target_frame` value is integrated over time. */
void seq_effect_speed_rebuild_map(Scene *scene, Sequence *seq)
{
if ((seq->seq1 == NULL) || (seq->len < 1)) {
@@ -3175,7 +3173,6 @@ static void seq_effect_speed_frame_map_ensure(Scene *scene, Sequence *seq)
seq_effect_speed_rebuild_map(scene, seq);
}
-/* Override timeline_frame when rendering speed effect input. */
float seq_speed_effect_target_frame_get(Scene *scene,
Sequence *seq_speed,
float timeline_frame,
diff --git a/source/blender/sequencer/intern/effects.h b/source/blender/sequencer/intern/effects.h
index 25ba4d8956e..c63f8f7a404 100644
--- a/source/blender/sequencer/intern/effects.h
+++ b/source/blender/sequencer/intern/effects.h
@@ -39,7 +39,14 @@ struct Sequence;
*/
struct SeqEffectHandle seq_effect_get_sequence_blend(struct Sequence *seq);
+/**
+ * Build frame map when speed in mode #SEQ_SPEED_MULTIPLY is animated.
+ * This is, because `target_frame` value is integrated over time.
+ */
void seq_effect_speed_rebuild_map(struct Scene *scene, struct Sequence *seq);
+/**
+ * Override timeline_frame when rendering speed effect input.
+ */
float seq_speed_effect_target_frame_get(struct Scene *scene,
struct Sequence *seq,
float timeline_frame,
diff --git a/source/blender/sequencer/intern/image_cache.c b/source/blender/sequencer/intern/image_cache.c
index c742fca0562..51e4613f088 100644
--- a/source/blender/sequencer/intern/image_cache.c
+++ b/source/blender/sequencer/intern/image_cache.c
@@ -453,9 +453,6 @@ static SeqCacheKey *seq_cache_get_item_for_removal(Scene *scene)
return finalkey;
}
-/* Find only "base" keys.
- * Sources(other types) for a frame must be freed all at once.
- */
bool seq_cache_recycle_item(Scene *scene)
{
SeqCache *cache = seq_cache_get_from_scene(scene);
diff --git a/source/blender/sequencer/intern/image_cache.h b/source/blender/sequencer/intern/image_cache.h
index e7827c15305..65732b5d83d 100644
--- a/source/blender/sequencer/intern/image_cache.h
+++ b/source/blender/sequencer/intern/image_cache.h
@@ -70,6 +70,10 @@ bool seq_cache_put_if_possible(const struct SeqRenderData *context,
float timeline_frame,
int type,
struct ImBuf *nval);
+/**
+ * Find only "base" keys.
+ * Sources(other types) for a frame must be freed all at once.
+ */
bool seq_cache_recycle_item(struct Scene *scene);
void seq_cache_free_temp_cache(struct Scene *scene, short id, int timeline_frame);
void seq_cache_destruct(struct Scene *scene);
diff --git a/source/blender/sequencer/intern/iterator.c b/source/blender/sequencer/intern/iterator.c
index 68f632ddb28..6cd53f08b3a 100644
--- a/source/blender/sequencer/intern/iterator.c
+++ b/source/blender/sequencer/intern/iterator.c
@@ -44,18 +44,6 @@
/** \Iterator API
* \{ */
-/**
- * Utility function for SEQ_ITERATOR_FOREACH macro.
- * Ensure, that iterator is initialized. During initialization return pointer to collection element
- * and step gset iterator. When this function is called after iterator has been initialized, it
- * will do nothing and return true.
- *
- * \param collection: collection to iterate
- * \param iterator: iterator to be initialized
- * \param r_seq: pointer to Sequence pointer
- *
- * \return false when iterator can not be initialized, true otherwise
- */
bool SEQ_iterator_ensure(SeqCollection *collection, SeqIterator *iterator, Sequence **r_seq)
{
if (iterator->iterator_initialized) {
@@ -76,14 +64,6 @@ bool SEQ_iterator_ensure(SeqCollection *collection, SeqIterator *iterator, Seque
return true;
}
-/**
- * Utility function for SEQ_ITERATOR_FOREACH macro.
- * Yield collection element
- *
- * \param iterator: iterator to be initialized
- *
- * \return collection element or NULL when iteration has ended
- */
Sequence *SEQ_iterator_yield(SeqIterator *iterator)
{
Sequence *seq = BLI_gsetIterator_done(&iterator->gsi) ? NULL :
@@ -108,36 +88,17 @@ static bool seq_for_each_recursive(ListBase *seqbase, SeqForEachFunc callback, v
return true;
}
-/**
- * Utility function to recursively iterate through all sequence strips in a `seqbase` list.
- * Uses callback to do operations on each sequence element.
- * The callback can stop the iteration if needed.
- *
- * \param seqbase: #ListBase of sequences to be iterated over.
- * \param callback: query function callback, returns false if iteration should stop.
- * \param user_data: pointer to user data that can be used in the callback function.
- */
void SEQ_for_each_callback(ListBase *seqbase, SeqForEachFunc callback, void *user_data)
{
seq_for_each_recursive(seqbase, callback, user_data);
}
-/**
- * Free strip collection.
- *
- * \param collection: collection to be freed
- */
void SEQ_collection_free(SeqCollection *collection)
{
BLI_gset_free(collection->set, NULL);
MEM_freeN(collection);
}
-/**
- * Create new empty strip collection.
- *
- * \return empty strip collection.
- */
SeqCollection *SEQ_collection_create(const char *name)
{
SeqCollection *collection = MEM_callocN(sizeof(SeqCollection), name);
@@ -146,30 +107,16 @@ SeqCollection *SEQ_collection_create(const char *name)
return collection;
}
-/**
- * Return number of items in collection.
- */
uint SEQ_collection_len(const SeqCollection *collection)
{
return BLI_gset_len(collection->set);
}
-/**
- * Check if seq is in collection.
- */
bool SEQ_collection_has_strip(const Sequence *seq, const SeqCollection *collection)
{
return BLI_gset_haskey(collection->set, seq);
}
-/**
- * Query strips from seqbase. seq_reference is used by query function as filter condition.
- *
- * \param seq_reference: reference strip for query function
- * \param seqbase: ListBase in which strips are queried
- * \param seq_query_func: query function callback
- * \return strip collection
- */
SeqCollection *SEQ_query_by_reference(Sequence *seq_reference,
ListBase *seqbase,
void seq_query_func(Sequence *seq_reference,
@@ -180,13 +127,6 @@ SeqCollection *SEQ_query_by_reference(Sequence *seq_reference,
seq_query_func(seq_reference, seqbase, collection);
return collection;
}
-/**
- * Add strip to collection.
- *
- * \param seq: strip to be added
- * \param collection: collection to which strip will be added
- * \return false if strip is already in set, otherwise true
- */
bool SEQ_collection_append_strip(Sequence *seq, SeqCollection *collection)
{
void **key;
@@ -198,24 +138,11 @@ bool SEQ_collection_append_strip(Sequence *seq, SeqCollection *collection)
return true;
}
-/**
- * Remove strip from collection.
- *
- * \param seq: strip to be removed
- * \param collection: collection from which strip will be removed
- * \return true if strip exists in set and it was removed from set, otherwise false
- */
bool SEQ_collection_remove_strip(Sequence *seq, SeqCollection *collection)
{
return BLI_gset_remove(collection->set, seq, NULL);
}
-/**
- * Move strips from collection_src to collection_dst. Source collection will be freed.
- *
- * \param collection_dst: destination collection
- * \param collection_src: source collection
- */
void SEQ_collection_merge(SeqCollection *collection_dst, SeqCollection *collection_src)
{
Sequence *seq;
@@ -225,13 +152,6 @@ void SEQ_collection_merge(SeqCollection *collection_dst, SeqCollection *collecti
SEQ_collection_free(collection_src);
}
-/**
- * Remove strips from collection that are also in `exclude_elements`. Source collection will be
- * freed.
- *
- * \param collection: collection from which strips are removed
- * \param exclude_elements: collection of strips to be removed
- */
void SEQ_collection_exclude(SeqCollection *collection, SeqCollection *exclude_elements)
{
Sequence *seq;
@@ -241,14 +161,6 @@ void SEQ_collection_exclude(SeqCollection *collection, SeqCollection *exclude_el
SEQ_collection_free(exclude_elements);
}
-/**
- * Expand collection by running SEQ_query() for each strip, which will be used as reference.
- * Results of these queries will be merged into provided collection.
- *
- * \param seqbase: ListBase in which strips are queried
- * \param collection: SeqCollection to be expanded
- * \param seq_query_func: query function callback
- */
void SEQ_collection_expand(ListBase *seqbase,
SeqCollection *collection,
void seq_query_func(Sequence *seq_reference,
@@ -267,12 +179,6 @@ void SEQ_collection_expand(ListBase *seqbase,
SEQ_collection_merge(collection, query_matches);
}
-/**
- * Duplicate collection
- *
- * \param collection: collection to be duplicated
- * \return duplicate of collection
- */
SeqCollection *SEQ_collection_duplicate(SeqCollection *collection)
{
SeqCollection *duplicate = SEQ_collection_create(__func__);
@@ -295,12 +201,6 @@ static void query_all_strips_recursive(ListBase *seqbase, SeqCollection *collect
}
}
-/**
- * Query all strips in seqbase and nested meta strips.
- *
- * \param seqbase: ListBase in which strips are queried
- * \return strip collection
- */
SeqCollection *SEQ_query_all_strips_recursive(ListBase *seqbase)
{
SeqCollection *collection = SEQ_collection_create(__func__);
@@ -313,12 +213,6 @@ SeqCollection *SEQ_query_all_strips_recursive(ListBase *seqbase)
return collection;
}
-/**
- * Query all strips in seqbase. This does not include strips nested in meta strips.
- *
- * \param seqbase: ListBase in which strips are queried
- * \return strip collection
- */
SeqCollection *SEQ_query_all_strips(ListBase *seqbase)
{
SeqCollection *collection = SEQ_collection_create(__func__);
@@ -328,12 +222,6 @@ SeqCollection *SEQ_query_all_strips(ListBase *seqbase)
return collection;
}
-/**
- * Query all selected strips in seqbase.
- *
- * \param seqbase: ListBase in which strips are queried
- * \return strip collection
- */
SeqCollection *SEQ_query_selected_strips(ListBase *seqbase)
{
SeqCollection *collection = SEQ_collection_create(__func__);
@@ -434,14 +322,6 @@ static void collection_filter_rendered_strips(SeqCollection *collection)
}
}
-/**
- * Query strips that are rendered at \a timeline_frame when \a displayed channel is viewed
- *
- * \param seqbase: ListBase in which strips are queried
- * \param timeline_frame: viewed frame
- * \param displayed_channel: viewed channel. when set to 0, no channel filter is applied
- * \return strip collection
- */
SeqCollection *SEQ_query_rendered_strips(ListBase *seqbase,
const int timeline_frame,
const int displayed_channel)
@@ -454,12 +334,6 @@ SeqCollection *SEQ_query_rendered_strips(ListBase *seqbase,
return collection;
}
-/**
- * Query all unselected strips in seqbase.
- *
- * \param seqbase: ListBase in which strips are queried
- * \return strip collection
- */
SeqCollection *SEQ_query_unselected_strips(ListBase *seqbase)
{
SeqCollection *collection = SEQ_collection_create(__func__);
@@ -472,15 +346,6 @@ SeqCollection *SEQ_query_unselected_strips(ListBase *seqbase)
return collection;
}
-/**
- * Query all effect strips that are directly or indirectly connected to seq_reference.
- * This includes all effects of seq_reference, strips used by another inputs and their effects, so
- * that whole chain is fully independent of other strips.
- *
- * \param seq_reference: reference strip
- * \param seqbase: ListBase in which strips are queried
- * \param collection: collection to be filled
- */
void SEQ_query_strip_effect_chain(Sequence *seq_reference,
ListBase *seqbase,
SeqCollection *collection)
@@ -520,29 +385,3 @@ void SEQ_filter_selected_strips(SeqCollection *collection)
}
}
}
-
-static void seq_collection_to_tag(ListBase *seqbase, SeqCollection *collection)
-{
- LISTBASE_FOREACH (Sequence *, seq, seqbase) {
- seq->tmp_tag = false;
- }
- Sequence *seq;
- SEQ_ITERATOR_FOREACH (seq, collection) {
- seq->tmp_tag = true;
- }
-}
-
-/* Utilities to access these as tags. */
-int SEQ_query_rendered_strips_to_tag(ListBase *seqbase,
- const int timeline_frame,
- const int displayed_channel)
-{
- SeqCollection *collection = SEQ_query_rendered_strips(
- seqbase, timeline_frame, displayed_channel);
-
- seq_collection_to_tag(seqbase, collection);
-
- const int len = SEQ_collection_len(collection);
- SEQ_collection_free(collection);
- return len;
-}
diff --git a/source/blender/sequencer/intern/modifier.c b/source/blender/sequencer/intern/modifier.c
index 1a63f4c4655..00ae88232fd 100644
--- a/source/blender/sequencer/intern/modifier.c
+++ b/source/blender/sequencer/intern/modifier.c
@@ -1161,6 +1161,7 @@ static void maskmodifier_apply(struct SequenceModifierData *UNUSED(smd), ImBuf *
// SequencerMaskModifierData *bcmd = (SequencerMaskModifierData *)smd;
modifier_apply_threaded(ibuf, mask, maskmodifier_apply_threaded, NULL);
+ ibuf->planes = R_IMF_PLANES_RGBA;
}
static SequenceModifierTypeInfo seqModifier_Mask = {
diff --git a/source/blender/sequencer/intern/multiview.c b/source/blender/sequencer/intern/multiview.c
index e120234ed8b..68d2a33fd5c 100644
--- a/source/blender/sequencer/intern/multiview.c
+++ b/source/blender/sequencer/intern/multiview.c
@@ -40,7 +40,6 @@ void seq_anim_add_suffix(Scene *scene, struct anim *anim, const int view_id)
IMB_suffix_anim(anim, suffix);
}
-/* the number of files will vary according to the stereo format */
int seq_num_files(Scene *scene, char views_format, const bool is_multiview)
{
if (!is_multiview) {
diff --git a/source/blender/sequencer/intern/multiview.h b/source/blender/sequencer/intern/multiview.h
index bbc66c6f84c..3d528c22fff 100644
--- a/source/blender/sequencer/intern/multiview.h
+++ b/source/blender/sequencer/intern/multiview.h
@@ -43,6 +43,9 @@ void seq_multiview_name(struct Scene *scene,
const char *ext,
char *r_path,
size_t r_size);
+/**
+ * The number of files will vary according to the stereo format.
+ */
int seq_num_files(struct Scene *scene, char views_format, const bool is_multiview);
#ifdef __cplusplus
diff --git a/source/blender/sequencer/intern/prefetch.c b/source/blender/sequencer/intern/prefetch.c
index 3e0b4738db1..0c45eb09492 100644
--- a/source/blender/sequencer/intern/prefetch.c
+++ b/source/blender/sequencer/intern/prefetch.c
@@ -162,14 +162,12 @@ static Sequence *sequencer_prefetch_get_original_sequence(Sequence *seq, ListBas
return NULL;
}
-/* for cache context swapping */
Sequence *seq_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 */
SeqRenderData *seq_prefetch_get_original_context(const SeqRenderData *context)
{
PrefetchJob *pfjob = seq_prefetch_job_get(context->scene);
@@ -268,9 +266,6 @@ void SEQ_prefetch_stop_all(void)
}
}
-/* Use also to update scene and context changes
- * This function should almost always be called by cache invalidation, not directly.
- */
void SEQ_prefetch_stop(Scene *scene)
{
PrefetchJob *pfjob;
@@ -561,7 +556,6 @@ static PrefetchJob *seq_prefetch_start_ex(const SeqRenderData *context, float cf
return pfjob;
}
-/* Start or resume prefetching. */
void seq_prefetch_start(const SeqRenderData *context, float timeline_frame)
{
Scene *scene = context->scene;
diff --git a/source/blender/sequencer/intern/prefetch.h b/source/blender/sequencer/intern/prefetch.h
index 8cfc6bf90bd..8cc5f6d35d1 100644
--- a/source/blender/sequencer/intern/prefetch.h
+++ b/source/blender/sequencer/intern/prefetch.h
@@ -35,11 +35,20 @@ struct Sequence;
}
#endif
+/**
+ * Start or resume prefetching.
+ */
void seq_prefetch_start(const struct SeqRenderData *context, float timeline_frame);
void seq_prefetch_free(struct Scene *scene);
bool seq_prefetch_job_is_running(struct Scene *scene);
void seq_prefetch_get_time_range(struct Scene *scene, int *start, int *end);
+/**
+ * For cache context swapping.
+ */
struct SeqRenderData *seq_prefetch_get_original_context(const struct SeqRenderData *context);
+/**
+ * For cache context swapping.
+ */
struct Sequence *seq_prefetch_get_original_sequence(struct Sequence *seq, struct Scene *scene);
#ifdef __cplusplus
diff --git a/source/blender/sequencer/intern/proxy.c b/source/blender/sequencer/intern/proxy.c
index 2bc294c91cd..30afa3f9c59 100644
--- a/source/blender/sequencer/intern/proxy.c
+++ b/source/blender/sequencer/intern/proxy.c
@@ -34,6 +34,7 @@
#include "BLI_fileops.h"
#include "BLI_listbase.h"
#include "BLI_path_util.h"
+#include "BLI_session_uuid.h"
#include "BLI_string.h"
#ifdef WIN32
@@ -54,6 +55,7 @@
#include "IMB_imbuf_types.h"
#include "IMB_metadata.h"
+#include "SEQ_iterator.h"
#include "SEQ_proxy.h"
#include "SEQ_relations.h"
#include "SEQ_render.h"
@@ -79,6 +81,7 @@ typedef struct SeqIndexBuildContext {
Depsgraph *depsgraph;
Scene *scene;
Sequence *seq, *orig_seq;
+ SessionUUID orig_seq_uuid;
} SeqIndexBuildContext;
int SEQ_rendersize_to_proxysize(int render_size)
@@ -458,6 +461,7 @@ bool SEQ_proxy_rebuild_context(Main *bmain,
context->depsgraph = depsgraph;
context->scene = scene;
context->orig_seq = seq;
+ context->orig_seq_uuid = seq->runtime.session_uuid;
context->seq = nseq;
context->view_id = i; /* only for images */
@@ -560,6 +564,18 @@ void SEQ_proxy_rebuild(SeqIndexBuildContext *context,
}
}
+static bool seq_orig_free_anims(Sequence *seq_iter, void *data)
+{
+ SessionUUID orig_seq_uuid = ((SeqIndexBuildContext *)data)->orig_seq_uuid;
+
+ if (BLI_session_uuid_is_equal(&seq_iter->runtime.session_uuid, &orig_seq_uuid)) {
+ for (StripAnim *sanim = seq_iter->anims.first; sanim; sanim = sanim->next) {
+ IMB_close_anim_proxies(sanim->anim);
+ }
+ }
+ return true;
+}
+
void SEQ_proxy_rebuild_finish(SeqIndexBuildContext *context, bool stop)
{
if (context->index_context) {
@@ -569,9 +585,8 @@ void SEQ_proxy_rebuild_finish(SeqIndexBuildContext *context, bool stop)
IMB_close_anim_proxies(sanim->anim);
}
- for (sanim = context->orig_seq->anims.first; sanim; sanim = sanim->next) {
- IMB_close_anim_proxies(sanim->anim);
- }
+ /* `context->seq_orig` may have been removed during building. */
+ SEQ_for_each_callback(&context->scene->ed->seqbase, seq_orig_free_anims, context);
IMB_anim_index_rebuild_finish(context->index_context, stop);
}
diff --git a/source/blender/sequencer/intern/render.c b/source/blender/sequencer/intern/render.c
index 6030b49537c..a391deaccb4 100644
--- a/source/blender/sequencer/intern/render.c
+++ b/source/blender/sequencer/intern/render.c
@@ -97,6 +97,7 @@ SequencerDrawView sequencer_view3d_fn = NULL; /* NULL in background mode */
/* -------------------------------------------------------------------- */
/** \name Color-space utility functions
* \{ */
+
void seq_imbuf_assign_spaces(Scene *scene, ImBuf *ibuf)
{
#if 0
@@ -213,6 +214,7 @@ void SEQ_render_pixel_from_sequencer_space_v4(struct Scene *scene, float pixel[4
/* -------------------------------------------------------------------- */
/** \name Rendering utility functions
* \{ */
+
void SEQ_render_new_render_data(Main *bmain,
struct Depsgraph *depsgraph,
Scene *scene,
@@ -301,25 +303,24 @@ int seq_get_shown_sequences(ListBase *seqbase,
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Preprocessing and effects
- * \{ */
-/*
- * input preprocessing for SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE, SEQ_TYPE_MOVIECLIP and SEQ_TYPE_SCENE
+/** \name Preprocessing and Effects
+ *
+ * Input pre-processing for SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE, SEQ_TYPE_MOVIECLIP and SEQ_TYPE_SCENE.
*
* Do all the things you can't really do afterwards using sequence effects
- * (read: before rescaling to render resolution has been done)
+ * (read: before re-scaling to render resolution has been done).
*
* Order is important!
*
- * - Deinterlace
- * - Crop and transform in image source coordinate space
- * - Flip X + Flip Y (could be done afterwards, backward compatibility)
- * - Promote image to float data (affects pipeline operations afterwards)
+ * - De-interlace.
+ * - Crop and transform in image source coordinate space.
+ * - Flip X + Flip Y (could be done afterwards, backward compatibility).
+ * - Promote image to float data (affects pipeline operations afterwards).
* - Color balance (is most efficient in the byte -> float
* (future: half -> float should also work fine!)
- * case, if done on load, since we can use lookup tables)
- * - Premultiply
- */
+ * case, if done on load, since we can use lookup tables).
+ * - Pre-multiply.
+ * \{ */
static bool sequencer_use_transform(const Sequence *seq)
{
@@ -459,11 +460,7 @@ static void sequencer_thumbnail_transform(ImBuf *in, ImBuf *out)
transform_pivot_set_m4(transform_matrix, pivot);
invert_m4(transform_matrix);
- /* No crop. */
- rctf source_crop;
- BLI_rctf_init(&source_crop, 0, in->x, 0, in->y);
-
- IMB_transform(in, out, transform_matrix, &source_crop, IMB_FILTER_NEAREST);
+ IMB_transform(in, out, IMB_TRANSFORM_MODE_REGULAR, IMB_FILTER_NEAREST, transform_matrix, NULL);
}
/* Check whether transform introduces transparent ares in the result (happens when the transformed
@@ -528,7 +525,7 @@ static void sequencer_preprocess_transform_crop(
const eIMBInterpolationFilterMode filter = context->for_render ? IMB_FILTER_BILINEAR :
IMB_FILTER_NEAREST;
- IMB_transform(in, out, transform_matrix, &source_crop, filter);
+ IMB_transform(in, out, IMB_TRANSFORM_MODE_CROP_SRC, filter, transform_matrix, &source_crop);
if (!seq_image_transform_transparency_gained(context, seq)) {
out->planes = in->planes;
@@ -871,11 +868,13 @@ static ImBuf *seq_render_effect_strip_impl(const SeqRenderData *context,
return out;
}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name Individual strip rendering functions
* \{ */
+
/**
* Render individual view for multi-view or single (default view) for mono-view.
*/
@@ -1618,11 +1617,13 @@ static ImBuf *do_render_strip_seqbase(const SeqRenderData *context,
return ibuf;
}
+
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Strip stack rendering functions
+/** \name Strip Stack Rendering Functions
* \{ */
+
static ImBuf *do_render_strip_uncached(const SeqRenderData *context,
SeqRenderState *state,
Sequence *seq,
@@ -1918,11 +1919,6 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context,
return out;
}
-/**
- * \return The image buffer or NULL.
- *
- * \note The returned #ImBuf has its reference increased, free after usage!
- */
ImBuf *SEQ_render_give_ibuf(const SeqRenderData *context, float timeline_frame, int chanshown)
{
Scene *scene = context->scene;
@@ -2033,7 +2029,6 @@ static ImBuf *seq_get_uncached_thumbnail(const SeqRenderData *context,
return scaled_ibuf;
}
-/* Get cached thumbnails. */
ImBuf *SEQ_get_thumbnail(
const SeqRenderData *context, Sequence *seq, float timeline_frame, rcti *crop, bool clipped)
{
@@ -2058,7 +2053,6 @@ ImBuf *SEQ_get_thumbnail(
return ibuf_cropped;
}
-/* Render the series of thumbnails and store in cache. */
void SEQ_render_thumbnails(const SeqRenderData *context,
Sequence *seq,
Sequence *seq_orig,
@@ -2103,8 +2097,6 @@ void SEQ_render_thumbnails(const SeqRenderData *context,
}
}
-/* Get frame step for equally spaced thumbnails. These thumbnails should always be present in
- * memory, so they can be used when zooming.*/
int SEQ_render_thumbnails_guaranteed_set_frame_step_get(const Sequence *seq)
{
const int content_len = (seq->enddisp - seq->startdisp - seq->startstill - seq->endstill);
@@ -2117,7 +2109,6 @@ int SEQ_render_thumbnails_guaranteed_set_frame_step_get(const Sequence *seq)
return content_len / thumbnails_base_set_count;
}
-/* Render set of evenly spaced thumbnails that are drawn when zooming. */
void SEQ_render_thumbnails_base_set(const SeqRenderData *context,
Sequence *seq,
Sequence *seq_orig,
diff --git a/source/blender/sequencer/intern/sequence_lookup.c b/source/blender/sequencer/intern/sequence_lookup.c
index 25b42957d99..8d451d59e92 100644
--- a/source/blender/sequencer/intern/sequence_lookup.c
+++ b/source/blender/sequencer/intern/sequence_lookup.c
@@ -105,11 +105,6 @@ static void seq_sequence_lookup_update_if_needed(const struct Scene *scene,
seq_sequence_lookup_rebuild(scene, lookup);
}
-/**
- * Free lookup hash data.
- *
- * \param scene: scene that owns lookup hash
- */
void SEQ_sequence_lookup_free(const Scene *scene)
{
BLI_assert(scene->ed);
@@ -119,16 +114,6 @@ void SEQ_sequence_lookup_free(const Scene *scene)
BLI_mutex_unlock(&lookup_lock);
}
-/**
- * Find a sequence with a given name.
- * If lookup hash doesn't exist, it will be created. If hash is tagged as invalid, it will be
- * rebuilt.
- *
- * \param scene: scene that owns lookup hash
- * \param key: Sequence name without SQ prefix (seq->name + 2)
- *
- * \return pointer to Sequence
- */
Sequence *SEQ_sequence_lookup_by_name(const Scene *scene, const char *key)
{
BLI_assert(scene->ed);
@@ -140,12 +125,6 @@ Sequence *SEQ_sequence_lookup_by_name(const Scene *scene, const char *key)
return seq;
}
-/**
- * Find a sequence with a given name.
- *
- * \param scene: scene that owns lookup hash
- * \param tag: tag to set
- */
void SEQ_sequence_lookup_tag(const Scene *scene, eSequenceLookupTag tag)
{
if (!scene->ed) {
diff --git a/source/blender/sequencer/intern/sequencer.c b/source/blender/sequencer/intern/sequencer.c
index 3478c2d4f97..908a5bd4f79 100644
--- a/source/blender/sequencer/intern/sequencer.c
+++ b/source/blender/sequencer/intern/sequencer.c
@@ -227,8 +227,6 @@ void SEQ_sequence_free(Scene *scene, Sequence *seq, const bool do_clean_animdata
seq_sequence_free_ex(scene, seq, true, true, do_clean_animdata);
}
-/* cache must be freed before calling this function
- * since it leaves the seqbase in an invalid state */
void seq_free_sequence_recurse(Scene *scene,
Sequence *seq,
const bool do_id_user,
@@ -388,12 +386,6 @@ int SEQ_tool_settings_pivot_point_get(Scene *scene)
return tool_settings->pivot_point;
}
-/**
- * Get seqbase that is being viewed currently. This can be main seqbase or meta strip seqbase
- *
- * \param ed: sequence editor data
- * \return pointer to active seqbase. returns NULL if ed is NULL
- */
ListBase *SEQ_active_seqbase_get(const Editing *ed)
{
if (ed == NULL) {
@@ -403,24 +395,11 @@ ListBase *SEQ_active_seqbase_get(const Editing *ed)
return ed->seqbasep;
}
-/**
- * Set seqbase that is being viewed currently. This can be main seqbase or meta strip seqbase
- *
- * \param ed: sequence editor data
- * \param seqbase: ListBase with strips
- */
void SEQ_seqbase_active_set(Editing *ed, ListBase *seqbase)
{
ed->seqbasep = seqbase;
}
-/**
- * Create and initialize #MetaStack, append it to `ed->metastack` ListBase
- *
- * \param ed: sequence editor data
- * \param seq_meta: meta strip
- * \return pointer to created meta stack
- */
MetaStack *SEQ_meta_stack_alloc(Editing *ed, Sequence *seq_meta)
{
MetaStack *ms = MEM_mallocN(sizeof(MetaStack), "metastack");
@@ -431,24 +410,12 @@ MetaStack *SEQ_meta_stack_alloc(Editing *ed, Sequence *seq_meta)
return ms;
}
-/**
- * Free #MetaStack and remove it from `ed->metastack` ListBase.
- *
- * \param ed: sequence editor data
- * \param ms: meta stack
- */
void SEQ_meta_stack_free(Editing *ed, MetaStack *ms)
{
BLI_remlink(&ed->metastack, ms);
MEM_freeN(ms);
}
-/**
- * Get #MetaStack that corresponds to current level that is being viewed
- *
- * \param ed: sequence editor data
- * \return pointer to meta stack
- */
MetaStack *SEQ_meta_stack_active_get(const Editing *ed)
{
return ed->metastack.last;
@@ -459,6 +426,7 @@ MetaStack *SEQ_meta_stack_active_get(const Editing *ed)
/* -------------------------------------------------------------------- */
/** \name Duplicate Functions
* \{ */
+
static Sequence *seq_dupli(const Scene *scene_src,
Scene *scene_dst,
ListBase *new_seq_list,
@@ -662,9 +630,11 @@ static size_t sequencer_rna_path_prefix(char str[SEQ_RNAPATH_MAXSTR], const char
str, SEQ_RNAPATH_MAXSTR, "sequence_editor.sequences_all[\"%s\"]", name_esc);
}
-/* XXX: hackish function needed for transforming strips! TODO: have some better solution. */
void SEQ_offset_animdata(Scene *scene, Sequence *seq, int ofs)
{
+ /* XXX: hackish function needed for transforming strips!
+ * TODO: have some better solution. */
+
char str[SEQ_RNAPATH_MAXSTR];
size_t str_len;
FCurve *fcu;
@@ -1069,10 +1039,6 @@ static bool seq_update_seq_cb(Sequence *seq, void *user_data)
return true;
}
-/* Evaluate parts of sequences which needs to be done as a part of a dependency graph evaluation.
- * This does NOT include actual rendering of the strips, but rather makes them up-to-date for
- * animation playback and makes them ready for the sequencer's rendering pipeline to render them.
- */
void SEQ_eval_sequences(Depsgraph *depsgraph, Scene *scene, ListBase *seqbase)
{
DEG_debug_print_eval(depsgraph, __func__, scene->id.name, scene);
diff --git a/source/blender/sequencer/intern/sequencer.h b/source/blender/sequencer/intern/sequencer.h
index e43535d14ee..f8ad17e9032 100644
--- a/source/blender/sequencer/intern/sequencer.h
+++ b/source/blender/sequencer/intern/sequencer.h
@@ -30,6 +30,10 @@ extern "C" {
struct Scene;
struct Sequence;
+/**
+ * Cache must be freed before calling this function
+ * since it leaves the seqbase in an invalid state.
+ */
void seq_free_sequence_recurse(struct Scene *scene,
struct Sequence *seq,
const bool do_id_user,
diff --git a/source/blender/sequencer/intern/strip_add.c b/source/blender/sequencer/intern/strip_add.c
index 382fdd4953f..a4b537b9074 100644
--- a/source/blender/sequencer/intern/strip_add.c
+++ b/source/blender/sequencer/intern/strip_add.c
@@ -70,16 +70,6 @@
#include "proxy.h"
#include "utils.h"
-/**
- * Initialize common SeqLoadData members
- *
- * \param load_data: SeqLoadData to be initialized
- * \param name: strip name (can be NULL)
- * \param path: path to file that is used as strip input (can be NULL)
- * \param start_frame: timeline frame where strip will be created
- * \param channel: timeline channel where strip will be created
- *
- */
void SEQ_add_load_data_init(SeqLoadData *load_data,
const char *name,
const char *path,
@@ -147,14 +137,6 @@ static void seq_add_set_view_transform(Scene *scene, Sequence *seq, SeqLoadData
}
}
-/**
- * Add scene strip.
- *
- * \param scene: Scene where strips will be added
- * \param seqbase: ListBase where strips will be added
- * \param load_data: SeqLoadData with information necessary to create strip
- * \return created strip
- */
Sequence *SEQ_add_scene_strip(Scene *scene, ListBase *seqbase, struct SeqLoadData *load_data)
{
Sequence *seq = SEQ_sequence_alloc(
@@ -168,14 +150,6 @@ Sequence *SEQ_add_scene_strip(Scene *scene, ListBase *seqbase, struct SeqLoadDat
return seq;
}
-/**
- * Add movieclip strip.
- *
- * \param scene: Scene where strips will be added
- * \param seqbase: ListBase where strips will be added
- * \param load_data: SeqLoadData with information necessary to create strip
- * \return created strip
- */
Sequence *SEQ_add_movieclip_strip(Scene *scene, ListBase *seqbase, struct SeqLoadData *load_data)
{
Sequence *seq = SEQ_sequence_alloc(
@@ -189,14 +163,6 @@ Sequence *SEQ_add_movieclip_strip(Scene *scene, ListBase *seqbase, struct SeqLoa
return seq;
}
-/**
- * Add mask strip.
- *
- * \param scene: Scene where strips will be added
- * \param seqbase: ListBase where strips will be added
- * \param load_data: SeqLoadData with information necessary to create strip
- * \return created strip
- */
Sequence *SEQ_add_mask_strip(Scene *scene, ListBase *seqbase, struct SeqLoadData *load_data)
{
Sequence *seq = SEQ_sequence_alloc(
@@ -210,14 +176,6 @@ Sequence *SEQ_add_mask_strip(Scene *scene, ListBase *seqbase, struct SeqLoadData
return seq;
}
-/**
- * Add effect strip.
- *
- * \param scene: Scene where strips will be added
- * \param seqbase: ListBase where strips will be added
- * \param load_data: SeqLoadData with information necessary to create strip
- * \return created strip
- */
Sequence *SEQ_add_effect_strip(Scene *scene, ListBase *seqbase, struct SeqLoadData *load_data)
{
Sequence *seq = SEQ_sequence_alloc(
@@ -248,35 +206,17 @@ Sequence *SEQ_add_effect_strip(Scene *scene, ListBase *seqbase, struct SeqLoadDa
return seq;
}
-/**
- * Set directory used by image strip.
- *
- * \param seq: image strip to be changed
- * \param path: directory path
- */
void SEQ_add_image_set_directory(Sequence *seq, char *path)
{
BLI_strncpy(seq->strip->dir, path, sizeof(seq->strip->dir));
}
-/**
- * Set directory used by image strip.
- *
- * \param seq: image strip to be changed
- * \param strip_frame: frame index of strip to be changed
- * \param filename: image filename (only filename, not complete path)
- */
void SEQ_add_image_load_file(Sequence *seq, size_t strip_frame, char *filename)
{
StripElem *se = SEQ_render_give_stripelem(seq, seq->start + strip_frame);
BLI_strncpy(se->name, filename, sizeof(se->name));
}
-/**
- * Set image strip alpha mode
- *
- * \param seq: image strip to be changed
- */
void SEQ_add_image_init_alpha_mode(Sequence *seq)
{
if (seq->strip && seq->strip->stripdata) {
@@ -306,16 +246,6 @@ void SEQ_add_image_init_alpha_mode(Sequence *seq)
}
}
-/**
- * Add image strip.
- * NOTE: Use SEQ_add_image_set_directory() and SEQ_add_image_load_file() to load image sequences
- *
- * \param main: Main reference
- * \param scene: Scene where strips will be added
- * \param seqbase: ListBase where strips will be added
- * \param load_data: SeqLoadData with information necessary to create strip
- * \return created strip
- */
Sequence *SEQ_add_image_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqLoadData *load_data)
{
Sequence *seq = SEQ_sequence_alloc(
@@ -364,17 +294,6 @@ Sequence *SEQ_add_image_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqL
}
#ifdef WITH_AUDASPACE
-/**
- * Add sound strip.
- * NOTE: Use SEQ_add_image_set_directory() and SEQ_add_image_load_file() to load image sequences
- *
- * \param main: Main reference
- * \param scene: Scene where strips will be added
- * \param seqbase: ListBase where strips will be added
- * \param load_data: SeqLoadData with information necessary to create strip
- * \return created strip
- */
-
Sequence *SEQ_add_sound_strip(Main *bmain,
Scene *scene,
ListBase *seqbase,
@@ -444,15 +363,6 @@ Sequence *SEQ_add_sound_strip(Main *UNUSED(bmain),
}
#endif // WITH_AUDASPACE
-/**
- * Add meta strip.
- *
- * \param scene: Scene where strips will be added
- * \param seqbase: ListBase where strips will be added
- * \param load_data: SeqLoadData with information necessary to create strip
- * \return created strip
- */
-
Sequence *SEQ_add_meta_strip(Scene *scene, ListBase *seqbase, SeqLoadData *load_data)
{
/* Allocate sequence. */
@@ -470,15 +380,6 @@ Sequence *SEQ_add_meta_strip(Scene *scene, ListBase *seqbase, SeqLoadData *load_
return seqm;
}
-/**
- * Add movie strip.
- *
- * \param main: Main reference
- * \param scene: Scene where strips will be added
- * \param seqbase: ListBase where strips will be added
- * \param load_data: SeqLoadData with information necessary to create strip
- * \return created strip
- */
Sequence *SEQ_add_movie_strip(
Main *bmain, Scene *scene, ListBase *seqbase, SeqLoadData *load_data, double *r_start_offset)
{
@@ -617,7 +518,6 @@ Sequence *SEQ_add_movie_strip(
return seq;
}
-/* NOTE: caller should run SEQ_time_update_sequence(scene, seq) after. */
void SEQ_add_reload_new_file(Main *bmain, Scene *scene, Sequence *seq, const bool lock_range)
{
char path[FILE_MAX];
diff --git a/source/blender/sequencer/intern/strip_edit.c b/source/blender/sequencer/intern/strip_edit.c
index 00b3da86306..912ba9d41db 100644
--- a/source/blender/sequencer/intern/strip_edit.c
+++ b/source/blender/sequencer/intern/strip_edit.c
@@ -175,7 +175,6 @@ static void sequencer_flag_users_for_removal(Scene *scene, ListBase *seqbase, Se
}
}
-/* Flag seq and its users (effects) for removal. */
void SEQ_edit_flag_for_removal(Scene *scene, ListBase *seqbase, Sequence *seq)
{
if (seq == NULL || (seq->flag & SEQ_FLAG_DELETE) != 0) {
@@ -193,7 +192,6 @@ void SEQ_edit_flag_for_removal(Scene *scene, ListBase *seqbase, Sequence *seq)
sequencer_flag_users_for_removal(scene, seqbase, seq);
}
-/* Remove all flagged sequences, return true if sequence is removed. */
void SEQ_edit_remove_flagged_sequences(Scene *scene, ListBase *seqbase)
{
LISTBASE_FOREACH_MUTABLE (Sequence *, seq, seqbase) {
@@ -221,14 +219,6 @@ static bool seq_exists_in_seqbase(Sequence *seq, ListBase *seqbase)
return false;
}
-/**
- * Move sequence to seqbase.
- *
- * \param scene: Scene containing the editing
- * \param dst_seqbase: seqbase where `seq` is located
- * \param seq: Sequence to move
- * \param dst_seqbase: Target seqbase
- */
bool SEQ_edit_move_strip_to_seqbase(Scene *scene,
ListBase *seqbase,
Sequence *seq,
@@ -247,14 +237,6 @@ bool SEQ_edit_move_strip_to_seqbase(Scene *scene,
return true;
}
-/**
- * Move sequence to meta sequence.
- *
- * \param scene: Scene containing the editing
- * \param src_seq: Sequence to move
- * \param dst_seqm: Target Meta sequence
- * \param error_str: Error message
- */
bool SEQ_edit_move_strip_to_meta(Scene *scene,
Sequence *src_seq,
Sequence *dst_seqm,
@@ -468,17 +450,6 @@ static bool seq_edit_split_operation_permitted_check(SeqCollection *strips,
return true;
}
-/**
- * Split Sequence at timeline_frame in two.
- *
- * \param bmain: Main in which Sequence is located
- * \param scene: Scene in which Sequence is located
- * \param seqbase: ListBase in which Sequence is located
- * \param seq: Sequence to be split
- * \param timeline_frame: frame at which seq is split.
- * \param method: affects type of offset to be applied to resize Sequence
- * \return The newly created sequence strip. This is always Sequence on right side.
- */
Sequence *SEQ_edit_strip_split(Main *bmain,
Scene *scene,
ListBase *seqbase,
@@ -558,15 +529,6 @@ Sequence *SEQ_edit_strip_split(Main *bmain,
return return_seq;
}
-/**
- * Find gap after initial_frame and move strips on right side to close the gap
- *
- * \param scene: Scene in which strips are located
- * \param seqbase: ListBase in which strips are located
- * \param initial_frame: frame on timeline from where gaps are searched for
- * \param remove_all_gaps: remove all gaps instead of one gap
- * \return true if gap is removed, otherwise false
- */
bool SEQ_edit_remove_gaps(Scene *scene,
ListBase *seqbase,
const int initial_frame,
diff --git a/source/blender/sequencer/intern/strip_relations.c b/source/blender/sequencer/intern/strip_relations.c
index e6d9cd330b3..7e7fc9e6bf7 100644
--- a/source/blender/sequencer/intern/strip_relations.c
+++ b/source/blender/sequencer/intern/strip_relations.c
@@ -29,6 +29,7 @@
#include "BLI_ghash.h"
#include "BLI_listbase.h"
+#include "BLI_math.h"
#include "BLI_session_uuid.h"
#include "BKE_main.h"
@@ -281,14 +282,31 @@ void SEQ_relations_free_imbuf(Scene *scene, ListBase *seqbase, bool for_render)
}
}
-static void sequencer_all_free_anim_ibufs(ListBase *seqbase, int timeline_frame)
+static void sequencer_all_free_anim_ibufs(Editing *ed,
+ ListBase *seqbase,
+ int timeline_frame,
+ const int frame_range[2])
{
for (Sequence *seq = seqbase->first; seq != NULL; seq = seq->next) {
- if (!SEQ_time_strip_intersects_frame(seq, timeline_frame)) {
+ if (!SEQ_time_strip_intersects_frame(seq, timeline_frame) ||
+ !((frame_range[0] <= timeline_frame) && (frame_range[1] > timeline_frame))) {
SEQ_relations_sequence_free_anim(seq);
}
if (seq->type == SEQ_TYPE_META) {
- sequencer_all_free_anim_ibufs(&seq->seqbase, timeline_frame);
+ int meta_range[2];
+
+ MetaStack *ms = SEQ_meta_stack_active_get(ed);
+ if (ms != NULL && ms->parseq == seq) {
+ meta_range[0] = -MAXFRAME;
+ meta_range[1] = MAXFRAME;
+ }
+ else {
+ /* Limit frame range to meta strip. */
+ meta_range[0] = max_ii(frame_range[0], seq->startdisp);
+ meta_range[1] = min_ii(frame_range[1], seq->enddisp);
+ }
+
+ sequencer_all_free_anim_ibufs(ed, &seq->seqbase, timeline_frame, meta_range);
}
}
}
@@ -299,7 +317,9 @@ void SEQ_relations_free_all_anim_ibufs(Scene *scene, int timeline_frame)
if (ed == NULL) {
return;
}
- sequencer_all_free_anim_ibufs(&ed->seqbase, timeline_frame);
+
+ const int frame_range[2] = {-MAXFRAME, MAXFRAME};
+ sequencer_all_free_anim_ibufs(ed, &ed->seqbase, timeline_frame, frame_range);
}
static Sequence *sequencer_check_scene_recursion(Scene *scene, ListBase *seqbase)
@@ -352,7 +372,6 @@ bool SEQ_relations_check_scene_recursion(Scene *scene, ReportList *reports)
return false;
}
-/* Check if "seq_main" (indirectly) uses strip "seq". */
bool SEQ_relations_render_loop_check(Sequence *seq_main, Sequence *seq)
{
if (seq_main == NULL || seq == NULL) {
@@ -379,7 +398,6 @@ bool SEQ_relations_render_loop_check(Sequence *seq_main, Sequence *seq)
return false;
}
-/* Function to free imbuf and anim data on changes */
void SEQ_relations_sequence_free_anim(Sequence *seq)
{
while (seq->anims.last) {
@@ -432,7 +450,6 @@ void SEQ_relations_check_uuids_unique_and_report(const Scene *scene)
BLI_gset_free(used_uuids, NULL);
}
-/* Return immediate parent meta of sequence */
struct Sequence *SEQ_find_metastrip_by_sequence(ListBase *seqbase, Sequence *meta, Sequence *seq)
{
Sequence *iseq;
diff --git a/source/blender/sequencer/intern/strip_time.c b/source/blender/sequencer/intern/strip_time.c
index a8e07f37a0b..3228277ce72 100644
--- a/source/blender/sequencer/intern/strip_time.c
+++ b/source/blender/sequencer/intern/strip_time.c
@@ -434,12 +434,6 @@ float SEQ_time_sequence_get_fps(Scene *scene, Sequence *seq)
return 0.0f;
}
-/**
- * Initialize given rectangle with the Scene's timeline boundaries.
- *
- * \param scene: the Scene instance whose timeline boundaries are extracted from
- * \param rect: output parameter to be filled with timeline boundaries
- */
void SEQ_timeline_init_boundbox(const Scene *scene, rctf *rect)
{
rect->xmin = scene->r.sfra;
@@ -448,12 +442,6 @@ void SEQ_timeline_init_boundbox(const Scene *scene, rctf *rect)
rect->ymax = 8.0f;
}
-/**
- * Stretch the given rectangle to include the given strips boundaries
- *
- * \param seqbase: ListBase in which strips are located
- * \param rect: output parameter to be filled with strips' boundaries
- */
void SEQ_timeline_expand_boundbox(const ListBase *seqbase, rctf *rect)
{
if (seqbase == NULL) {
@@ -473,13 +461,6 @@ void SEQ_timeline_expand_boundbox(const ListBase *seqbase, rctf *rect)
}
}
-/**
- * Define boundary rectangle of sequencer timeline and fill in rect data
- *
- * \param scene: Scene in which strips are located
- * \param seqbase: ListBase in which strips are located
- * \param rect: data structure describing rectangle, that will be filled in by this function
- */
void SEQ_timeline_boundbox(const Scene *scene, const ListBase *seqbase, rctf *rect)
{
SEQ_timeline_init_boundbox(scene, rect);
@@ -497,14 +478,6 @@ static bool strip_exists_at_frame(SeqCollection *all_strips, const int timeline_
return false;
}
-/**
- * Find first gap between strips after initial_frame and describe it by filling data of r_gap_info
- *
- * \param scene: Scene in which strips are located
- * \param seqbase: ListBase in which strips are located
- * \param initial_frame: frame on timeline from where gaps are searched for
- * \param r_gap_info: data structure describing gap, that will be filled in by this function
- */
void seq_time_gap_info_get(const Scene *scene,
ListBase *seqbase,
const int initial_frame,
@@ -550,15 +523,6 @@ void seq_time_gap_info_get(const Scene *scene,
}
}
-/**
- * Test if strip intersects with timeline frame.
- * NOTE: This checks if strip would be rendered at this frame. For rendering it is assumed, that
- * timeline frame has width of 1 frame and therefore ends at timeline_frame + 1
- *
- * \param seq: Sequence to be checked
- * \param timeline_frame: absolute frame position
- * \return true if strip intersects with timeline frame.
- */
bool SEQ_time_strip_intersects_frame(const Sequence *seq, const int timeline_frame)
{
return (seq->startdisp <= timeline_frame) && (seq->enddisp > timeline_frame);
diff --git a/source/blender/sequencer/intern/strip_time.h b/source/blender/sequencer/intern/strip_time.h
index ca9a935bc96..aa807b6da25 100644
--- a/source/blender/sequencer/intern/strip_time.h
+++ b/source/blender/sequencer/intern/strip_time.h
@@ -40,6 +40,15 @@ typedef struct GapInfo {
int gap_length; /* Length of the gap. */
bool gap_exists; /* False if there are no gaps. */
} GapInfo;
+
+/**
+ * Find first gap between strips after initial_frame and describe it by filling data of r_gap_info
+ *
+ * \param scene: Scene in which strips are located.
+ * \param seqbase: ListBase in which strips are located.
+ * \param initial_frame: frame on timeline from where gaps are searched for.
+ * \param r_gap_info: data structure describing gap, that will be filled in by this function.
+ */
void seq_time_gap_info_get(const struct Scene *scene,
struct ListBase *seqbase,
const int initial_frame,
diff --git a/source/blender/sequencer/intern/strip_transform.c b/source/blender/sequencer/intern/strip_transform.c
index 63ab4a30edc..ce5917b999f 100644
--- a/source/blender/sequencer/intern/strip_transform.c
+++ b/source/blender/sequencer/intern/strip_transform.c
@@ -86,8 +86,6 @@ void SEQ_transform_set_right_handle_frame(Sequence *seq, int val)
}
}
-/* used so we can do a quick check for single image seq
- * since they work a bit differently to normal image seq's (during transform) */
bool SEQ_transform_single_image_check(Sequence *seq)
{
return ((seq->len == 1) &&
@@ -95,7 +93,6 @@ bool SEQ_transform_single_image_check(Sequence *seq)
((seq->type & SEQ_TYPE_EFFECT) && SEQ_effect_get_num_inputs(seq->type) == 0)));
}
-/* check if the selected seq's reference unselected seq's */
bool SEQ_transform_seqbase_isolated_sel_check(ListBase *seqbase)
{
Sequence *seq;
@@ -137,10 +134,6 @@ bool SEQ_transform_seqbase_isolated_sel_check(ListBase *seqbase)
return true;
}
-/**
- * Use to impose limits when dragging/extending - so impossible situations don't happen.
- * Can't use the #SEQ_LEFTSEL and #SEQ_LEFTSEL directly because the strip may be in a meta-strip.
- */
void SEQ_transform_handle_xlimits(Sequence *seq, int leftflag, int rightflag)
{
if (leftflag) {
@@ -257,7 +250,6 @@ void SEQ_transform_translate_sequence(Scene *evil_scene, Sequence *seq, int delt
SEQ_time_update_sequence(evil_scene, seqbase, seq);
}
-/* return 0 if there weren't enough space */
bool SEQ_transform_seqbase_shuffle_ex(ListBase *seqbasep,
Sequence *test,
Scene *evil_scene,
@@ -393,14 +385,6 @@ bool SEQ_transform_seqbase_shuffle_time(SeqCollection *strips_to_shuffle,
return offset ? false : true;
}
-/**
- * Move strips and markers (if not locked) that start after timeline_frame by delta frames
- *
- * \param scene: Scene in which strips are located
- * \param seqbase: ListBase in which strips are located
- * \param delta: offset in frames to be applied
- * \param timeline_frame: frame on timeline from where strips are moved
- */
void SEQ_transform_offset_after_frame(Scene *scene,
ListBase *seqbase,
const int delta,
@@ -436,14 +420,6 @@ void SEQ_image_transform_mirror_factor_get(const Sequence *seq, float r_mirror[2
}
}
-/**
- * Get strip transform origin offset from image center
- * Note: This function does not apply axis mirror.
- *
- * \param scene: Scene in which strips are located
- * \param seq: Sequence to calculate image transform origin
- * \param r_origin: return value
- */
void SEQ_image_transform_origin_offset_pixelspace_get(const Scene *scene,
const Sequence *seq,
float r_origin[2])
@@ -463,9 +439,11 @@ void SEQ_image_transform_origin_offset_pixelspace_get(const Scene *scene,
r_origin[0] = (image_size[0] * transform->origin[0]) - (image_size[0] * 0.5f) + transform->xofs;
r_origin[1] = (image_size[1] * transform->origin[1]) - (image_size[1] * 0.5f) + transform->yofs;
+ const float viewport_pixel_aspect[2] = {scene->r.xasp / scene->r.yasp, 1.0f};
float mirror[2];
SEQ_image_transform_mirror_factor_get(seq, mirror);
mul_v2_v2(r_origin, mirror);
+ mul_v2_v2(r_origin, viewport_pixel_aspect);
}
static void seq_image_transform_quad_get_ex(const Scene *scene,
@@ -483,7 +461,6 @@ static void seq_image_transform_quad_get_ex(const Scene *scene,
}
float transform_matrix[4][4];
-
float rotation_matrix[3][3];
axis_angle_to_mat3_single(rotation_matrix, 'Z', apply_rotation ? transform->rotation : 0.0f);
loc_rot_size_to_mat4(transform_matrix,
@@ -512,22 +489,16 @@ static void seq_image_transform_quad_get_ex(const Scene *scene,
float mirror[2];
SEQ_image_transform_mirror_factor_get(seq, mirror);
+ const float viewport_pixel_aspect[2] = {scene->r.xasp / scene->r.yasp, 1.0f};
+
for (int i = 0; i < 4; i++) {
mul_m4_v3(transform_matrix, quad_temp[i]);
mul_v2_v2(quad_temp[i], mirror);
+ mul_v2_v2(quad_temp[i], viewport_pixel_aspect);
copy_v2_v2(r_quad[i], quad_temp[i]);
}
}
-/**
- * Get 4 corner points of strip image, optionally without rotation component applied.
- * Corner vectors are in viewport space.
- *
- * \param scene: Scene in which strips are located
- * \param seq: Sequence to calculate transformed image quad
- * \param apply_rotation: Apply sequence rotation transform to the quad
- * \param r_quad: array of 4 2D vectors
- */
void SEQ_image_transform_quad_get(const Scene *scene,
const Sequence *seq,
bool apply_rotation,
@@ -536,13 +507,6 @@ void SEQ_image_transform_quad_get(const Scene *scene,
seq_image_transform_quad_get_ex(scene, seq, apply_rotation, r_quad);
}
-/**
- * Get 4 corner points of strip image. Corner vectors are in viewport space.
- *
- * \param scene: Scene in which strips are located
- * \param seq: Sequence to calculate transformed image quad
- * \param r_quad: array of 4 2D vectors
- */
void SEQ_image_transform_final_quad_get(const Scene *scene,
const Sequence *seq,
float r_quad[4][2])
diff --git a/source/blender/sequencer/intern/utils.c b/source/blender/sequencer/intern/utils.c
index 71686065882..cd779b0b0c7 100644
--- a/source/blender/sequencer/intern/utils.c
+++ b/source/blender/sequencer/intern/utils.c
@@ -55,13 +55,6 @@
#include "proxy.h"
#include "utils.h"
-/**
- * Sort strips in provided seqbase. Effect strips are trailing the list and they are sorted by
- * channel position as well.
- * This is important for SEQ_time_update_sequence to work properly
- *
- * \param seqbase: ListBase with strips
- */
void SEQ_sort(ListBase *seqbase)
{
if (seqbase == NULL) {
@@ -432,7 +425,6 @@ const Sequence *SEQ_get_topmost_sequence(const Scene *scene, int frame)
return best_seq;
}
-/* in cases where we don't know the sequence's listbase */
ListBase *SEQ_get_seqbase_by_seq(ListBase *seqbase, Sequence *seq)
{
Sequence *iseq;
@@ -465,10 +457,6 @@ Sequence *SEQ_get_meta_by_seqbase(ListBase *seqbase_main, ListBase *meta_seqbase
return seq;
}
-/**
- * Only use as last resort when the StripElem is available but no the Sequence.
- * (needed for RNA)
- */
Sequence *SEQ_sequence_from_strip_elem(ListBase *seqbase, StripElem *se)
{
Sequence *iseq;
@@ -525,10 +513,10 @@ void SEQ_alpha_mode_from_file_extension(Sequence *seq)
}
}
-/* called on draw, needs to be fast,
- * we could cache and use a flag if we want to make checks for file paths resolving for eg. */
bool SEQ_sequence_has_source(const Sequence *seq)
{
+ /* Called on draw, needs to be fast,
+ * we could cache and use a flag if we want to make checks for file paths resolving for eg. */
switch (seq->type) {
case SEQ_TYPE_MASK:
return (seq->mask != NULL);
@@ -589,13 +577,6 @@ void SEQ_set_scale_to_fit(const Sequence *seq,
}
}
-/**
- * Ensure, that provided Sequence has unique name. If animation data exists for this Sequence, it
- * will be duplicated and mapped onto new name
- *
- * \param seq: Sequence which name will be ensured to be unique
- * \param scene: Scene in which name must be unique
- */
void SEQ_ensure_unique_name(Sequence *seq, Scene *scene)
{
char name[SEQ_NAME_MAXSTR];
diff --git a/source/blender/shader_fx/intern/FX_ui_common.c b/source/blender/shader_fx/intern/FX_ui_common.c
index de5bef5d8d5..314aafd6b70 100644
--- a/source/blender/shader_fx/intern/FX_ui_common.c
+++ b/source/blender/shader_fx/intern/FX_ui_common.c
@@ -93,9 +93,6 @@ static void set_shaderfx_expand_flag(const bContext *UNUSED(C), Panel *panel, sh
/** \name ShaderFx Panel Layouts
* \{ */
-/**
- * Draw shaderfx error message.
- */
void shaderfx_panel_end(uiLayout *layout, PointerRNA *ptr)
{
ShaderFxData *fx = ptr->data;
@@ -105,9 +102,6 @@ void shaderfx_panel_end(uiLayout *layout, PointerRNA *ptr)
}
}
-/**
- * Gets RNA pointers for the active object and the panel's shaderfx data.
- */
PointerRNA *shaderfx_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_ptr)
{
PointerRNA *ptr = UI_panel_custom_data_get(panel);
@@ -117,7 +111,7 @@ PointerRNA *shaderfx_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_
RNA_pointer_create(ptr->owner_id, &RNA_Object, ptr->owner_id, r_ob_ptr);
}
- uiLayoutSetContextPointer(panel->layout, "shaderfx", ptr);
+ UI_panel_context_pointer_set(panel, "shaderfx", ptr);
return ptr;
}
@@ -236,9 +230,6 @@ static bool shaderfx_ui_poll(const bContext *C, PanelType *UNUSED(pt))
return (ob != NULL) && (ob->type == OB_GPENCIL);
}
-/**
- * Create a panel in the context's region
- */
PanelType *shaderfx_panel_register(ARegionType *region_type, ShaderFxType type, PanelDrawFn draw)
{
PanelType *panel_type = MEM_callocN(sizeof(PanelType), __func__);
@@ -264,12 +255,6 @@ PanelType *shaderfx_panel_register(ARegionType *region_type, ShaderFxType type,
return panel_type;
}
-/**
- * Add a child panel to the parent.
- *
- * \note To create the panel type's idname, it appends the \a name argument to the \a parent's
- * idname.
- */
PanelType *shaderfx_subpanel_register(ARegionType *region_type,
const char *name,
const char *label,
diff --git a/source/blender/shader_fx/intern/FX_ui_common.h b/source/blender/shader_fx/intern/FX_ui_common.h
index 151a2d31eb8..04982b9c0cf 100644
--- a/source/blender/shader_fx/intern/FX_ui_common.h
+++ b/source/blender/shader_fx/intern/FX_ui_common.h
@@ -32,13 +32,28 @@ struct bContext;
struct uiLayout;
typedef void (*PanelDrawFn)(const bContext *, Panel *);
+/**
+ * Draw shaderfx error message.
+ */
void shaderfx_panel_end(struct uiLayout *layout, PointerRNA *ptr);
+/**
+ * Gets RNA pointers for the active object and the panel's shaderfx data.
+ */
struct PointerRNA *shaderfx_panel_get_property_pointers(struct Panel *panel,
struct PointerRNA *r_ob_ptr);
+/**
+ * Create a panel in the context's region
+ */
PanelType *shaderfx_panel_register(ARegionType *region_type, ShaderFxType type, PanelDrawFn draw);
+/**
+ * Add a child panel to the parent.
+ *
+ * \note To create the panel type's idname, it appends the \a name argument to the \a parent's
+ * idname.
+ */
struct PanelType *shaderfx_subpanel_register(struct ARegionType *region_type,
const char *name,
const char *label,
diff --git a/source/blender/simulation/intern/ConstrainedConjugateGradient.h b/source/blender/simulation/intern/ConstrainedConjugateGradient.h
index c231d511733..d4d6057cd4c 100644
--- a/source/blender/simulation/intern/ConstrainedConjugateGradient.h
+++ b/source/blender/simulation/intern/ConstrainedConjugateGradient.h
@@ -167,10 +167,10 @@ struct traits<
* algorithm. The sparse matrix A must be self-adjoint. The vectors x and b can be either dense or
* sparse.
*
- * \tparam _MatrixType the type of the sparse matrix A, can be a dense or a sparse matrix.
- * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower
+ * \tparam _MatrixType: the type of the sparse matrix A, can be a dense or a sparse matrix.
+ * \tparam _UpLo: the triangular part that will be used for the computations. It can be Lower
* or Upper. Default is Lower.
- * \tparam _Preconditioner the type of the pre-conditioner. Default is #DiagonalPreconditioner
+ * \tparam _Preconditioner: the type of the pre-conditioner. Default is #DiagonalPreconditioner
*
* The maximal number of iterations and tolerance value can be controlled via the
* setMaxIterations() and setTolerance() methods. The defaults are the size of the problem for the
diff --git a/source/blender/simulation/intern/hair_volume.cpp b/source/blender/simulation/intern/hair_volume.cpp
index 348c8683be9..e47593eda05 100644
--- a/source/blender/simulation/intern/hair_volume.cpp
+++ b/source/blender/simulation/intern/hair_volume.cpp
@@ -633,9 +633,6 @@ BLI_INLINE void hair_volume_eval_grid_vertex_sample(HairGridVert *vert,
}
}
-/* XXX simplified test implementation using a series of discrete sample along the segment,
- * instead of finding the closest point for all affected grid vertices.
- */
void SIM_hair_volume_add_segment(HairGrid *grid,
const float UNUSED(x1[3]),
const float UNUSED(v1[3]),
@@ -649,6 +646,9 @@ void SIM_hair_volume_add_segment(HairGrid *grid,
const float UNUSED(dir2[3]),
const float UNUSED(dir3[3]))
{
+ /* XXX simplified test implementation using a series of discrete sample along the segment,
+ * instead of finding the closest point for all affected grid vertices. */
+
const float radius = 1.5f;
const float dist_scale = grid->inv_cellsize;
diff --git a/source/blender/simulation/intern/implicit.h b/source/blender/simulation/intern/implicit.h
index a8693c61018..c8eab94d315 100644
--- a/source/blender/simulation/intern/implicit.h
+++ b/source/blender/simulation/intern/implicit.h
@@ -80,7 +80,8 @@ void SIM_mass_spring_get_motion_state(struct Implicit_Data *data,
void SIM_mass_spring_get_position(struct Implicit_Data *data, int index, float x[3]);
void SIM_mass_spring_get_velocity(struct Implicit_Data *data, int index, float v[3]);
-/* access to modified motion state during solver step */
+/* Access to modified motion state during solver step. */
+
void SIM_mass_spring_get_new_position(struct Implicit_Data *data, int index, float x[3]);
void SIM_mass_spring_set_new_position(struct Implicit_Data *data, int index, const float x[3]);
void SIM_mass_spring_get_new_velocity(struct Implicit_Data *data, int index, float v[3]);
@@ -106,44 +107,64 @@ bool SIM_mass_spring_solve_velocities(struct Implicit_Data *data,
bool SIM_mass_spring_solve_positions(struct Implicit_Data *data, float dt);
void SIM_mass_spring_apply_result(struct Implicit_Data *data);
-/* Clear the force vector at the beginning of the time step */
+/**
+ * Clear the force vector at the beginning of the time step.
+ */
void SIM_mass_spring_clear_forces(struct Implicit_Data *data);
-/* Fictitious forces introduced by moving coordinate systems */
+/**
+ * Fictitious forces introduced by moving coordinate systems.
+ */
void SIM_mass_spring_force_reference_frame(struct Implicit_Data *data,
int index,
const float acceleration[3],
const float omega[3],
const float domega_dt[3],
float mass);
-/* Simple uniform gravity force */
+/**
+ * Simple uniform gravity force.
+ */
void SIM_mass_spring_force_gravity(struct Implicit_Data *data,
int index,
float mass,
const float g[3]);
-/* Global drag force (velocity damping) */
+/**
+ * Global drag force (velocity damping).
+ */
void SIM_mass_spring_force_drag(struct Implicit_Data *data, float drag);
-/* Custom external force */
+/**
+ * Custom external force.
+ */
void SIM_mass_spring_force_extern(
struct Implicit_Data *data, int i, const float f[3], float dfdx[3][3], float dfdv[3][3]);
-/* Wind force, acting on a face (only generates pressure from the normal component) */
+/**
+ * Wind force, acting on a face (only generates pressure from the normal component).
+ */
void SIM_mass_spring_force_face_wind(
struct Implicit_Data *data, int v1, int v2, int v3, const float (*winvec)[3]);
-/* Arbitrary per-unit-area vector force field acting on a face. */
+/**
+ * Arbitrary per-unit-area vector force field acting on a face..
+ */
void SIM_mass_spring_force_face_extern(
struct Implicit_Data *data, int v1, int v2, int v3, const float (*forcevec)[3]);
-/* Wind force, acting on an edge */
+/**
+ * Wind force, acting on an edge.
+ */
void SIM_mass_spring_force_edge_wind(struct Implicit_Data *data,
int v1,
int v2,
float radius1,
float radius2,
const float (*winvec)[3]);
-/* Wind force, acting on a vertex */
+/**
+ * Wind force, acting on a vertex.
+ */
void SIM_mass_spring_force_vertex_wind(struct Implicit_Data *data,
int v,
float radius,
const float (*winvec)[3]);
-/* Linear spring force between two points */
+/**
+ * Linear spring force between two points.
+ */
bool SIM_mass_spring_force_spring_linear(struct Implicit_Data *data,
int i,
int j,
@@ -155,7 +176,9 @@ bool SIM_mass_spring_force_spring_linear(struct Implicit_Data *data,
bool resist_compress,
bool new_compress,
float clamp_force);
-/* Angular spring force between two polygons */
+/**
+ * Angular spring force between two polygons.
+ */
bool SIM_mass_spring_force_spring_angular(struct Implicit_Data *data,
int i,
int j,
@@ -166,10 +189,14 @@ bool SIM_mass_spring_force_spring_angular(struct Implicit_Data *data,
float restang,
float stiffness,
float damping);
-/* Bending force, forming a triangle at the base of two structural springs */
+/**
+ * Bending force, forming a triangle at the base of two structural springs.
+ */
bool SIM_mass_spring_force_spring_bending(
struct Implicit_Data *data, int i, int j, float restlen, float kb, float cb);
-/* Angular bending force based on local target vectors */
+/**
+ * Angular bending force based on local target vectors.
+ */
bool SIM_mass_spring_force_spring_bending_hair(struct Implicit_Data *data,
int i,
int j,
@@ -177,7 +204,9 @@ bool SIM_mass_spring_force_spring_bending_hair(struct Implicit_Data *data,
const float target[3],
float stiffness,
float damping);
-/* Global goal spring */
+/**
+ * Global goal spring.
+ */
bool SIM_mass_spring_force_spring_goal(struct Implicit_Data *data,
int i,
const float goal_x[3],
@@ -242,13 +271,15 @@ void SIM_hair_volume_grid_interpolate(struct HairGrid *grid,
float density_gradient[3],
float velocity_gradient[3][3]);
-/* Effect of fluid simulation grid on velocities.
+/**
+ * Effect of fluid simulation grid on velocities.
* fluid_factor controls blending between PIC (Particle-in-Cell)
* and FLIP (Fluid-Implicit-Particle) methods (0 = only PIC, 1 = only FLIP)
*/
void SIM_hair_volume_grid_velocity(
struct HairGrid *grid, const float x[3], const float v[3], float fluid_factor, float r_v[3]);
-/* XXX Warning: expressing grid effects on velocity as a force is not very stable,
+/**
+ * WARNING: expressing grid effects on velocity as a force is not very stable,
* due to discontinuities in interpolated values!
* Better use hybrid approaches such as described in
* "Detail Preserving Continuum Simulation of Straight Hair"
diff --git a/source/blender/simulation/intern/implicit_blender.c b/source/blender/simulation/intern/implicit_blender.c
index ad903e9da4a..add047bf8c8 100644
--- a/source/blender/simulation/intern/implicit_blender.c
+++ b/source/blender/simulation/intern/implicit_blender.c
@@ -1475,11 +1475,12 @@ static float calc_nor_area_tri(float nor[3],
return normalize_v3(nor) / 2.0f;
}
-/* XXX does not support force jacobians yet, since the effector system does not provide them either
- */
void SIM_mass_spring_force_face_wind(
Implicit_Data *data, int v1, int v2, int v3, const float (*winvec)[3])
{
+ /* XXX does not support force jacobians yet,
+ * since the effector system does not provide them either. */
+
const float effector_scale = 0.02f;
const int vs[3] = {v1, v2, v3};
float win[3], nor[3], area;
@@ -1854,10 +1855,11 @@ bool SIM_mass_spring_force_spring_linear(Implicit_Data *data,
return true;
}
-/* See "Stable but Responsive Cloth" (Choi, Ko 2005) */
bool SIM_mass_spring_force_spring_bending(
Implicit_Data *data, int i, int j, float restlen, float kb, float cb)
{
+ /* See "Stable but Responsive Cloth" (Choi, Ko 2005). */
+
float extent[3], length, dir[3], vel[3];
/* calculate elongation */
@@ -1959,8 +1961,6 @@ BLI_INLINE void spring_angle(Implicit_Data *data,
sub_v3_v3(r_vel_b, vel_e);
}
-/* Angular springs roughly based on the bending model proposed by Baraff and Witkin in "Large Steps
- * in Cloth Simulation". */
bool SIM_mass_spring_force_spring_angular(Implicit_Data *data,
int i,
int j,
@@ -2179,9 +2179,6 @@ BLI_INLINE void spring_hairbend_estimate_dfdv(Implicit_Data *data,
}
}
-/* Angular spring that pulls the vertex toward the local target
- * See "Artistic Simulation of Curly Hair" (Pixar technical memo #12-03a)
- */
bool SIM_mass_spring_force_spring_bending_hair(Implicit_Data *data,
int i,
int j,
@@ -2190,6 +2187,9 @@ bool SIM_mass_spring_force_spring_bending_hair(Implicit_Data *data,
float stiffness,
float damping)
{
+ /* Angular springs roughly based on the bending model proposed by Baraff and Witkin in
+ * "Large Steps in Cloth Simulation". */
+
float goal[3];
float fj[3], fk[3];
float dfj_dxi[3][3], dfj_dxj[3][3], dfk_dxi[3][3], dfk_dxj[3][3], dfk_dxk[3][3];
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index 8d25ece3753..4ffd31a9923 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -84,11 +84,24 @@ typedef struct wmGizmoMap wmGizmoMap;
typedef struct wmGizmoMapType wmGizmoMapType;
typedef struct wmJob wmJob;
-/* general API */
+/* General API. */
+
+/**
+ * Used for setting app-template from the command line:
+ * - non-empty string: overrides.
+ * - empty string: override, using no app template.
+ * - NULL: clears override.
+ */
void WM_init_state_app_template_set(const char *app_template);
const char *WM_init_state_app_template_get(void);
+/**
+ * Called when no ghost system was initialized.
+ */
void WM_init_state_size_set(int stax, int stay, int sizx, int sizy);
+/**
+ * For border-less and border windows set from command-line.
+ */
void WM_init_state_fullscreen_set(void);
void WM_init_state_normal_set(void);
void WM_init_state_maximized_set(void);
@@ -97,9 +110,21 @@ void WM_init_window_focus_set(bool do_it);
void WM_init_native_pixels(bool do_it);
void WM_init_tablet_api(void);
+/**
+ * Initialize Blender and load the startup file & preferences
+ * (only called once).
+ */
void WM_init(struct bContext *C, int argc, const char **argv);
+/**
+ * \note doesn't run exit() call #WM_exit() for that.
+ */
void WM_exit_ex(struct bContext *C, const bool do_python);
+/**
+ * \brief Main exit function to close Blender ordinarily.
+ * \note Use #wm_exit_schedule_delayed() to close Blender from an operator.
+ * Might leak memory otherwise.
+ */
void WM_exit(struct bContext *C) ATTR_NORETURN;
void WM_main(struct bContext *C) ATTR_NORETURN;
@@ -111,6 +136,10 @@ void WM_init_opengl(void);
void WM_check(struct bContext *C);
void WM_reinit_gizmomap_all(struct Main *bmain);
+/**
+ * Needed for cases when operators are re-registered
+ * (when operator type pointers are stored).
+ */
void WM_script_tag_reload(void);
wmWindow *WM_window_find_under_cursor(const wmWindowManager *wm,
@@ -125,13 +154,30 @@ void WM_window_pixel_sample_read(const wmWindowManager *wm,
uint *WM_window_pixels_read(struct wmWindowManager *wm, struct wmWindow *win, int r_size[2]);
+/**
+ * Support for native pixel size
+ *
+ * \note macOS retina opens window in size X, but it has up to 2 x more pixels.
+ */
int WM_window_pixels_x(const struct wmWindow *win);
int WM_window_pixels_y(const struct wmWindow *win);
+/**
+ * Get boundaries usable by all window contents, including global areas.
+ */
void WM_window_rect_calc(const struct wmWindow *win, struct rcti *r_rect);
+/**
+ * Get boundaries usable by screen-layouts, excluding global areas.
+ * \note Depends on #U.dpi_fac. Should that be outdated, call #WM_window_set_dpi first.
+ */
void WM_window_screen_rect_calc(const struct wmWindow *win, struct rcti *r_rect);
bool WM_window_is_fullscreen(const struct wmWindow *win);
bool WM_window_is_maximized(const struct wmWindow *win);
+/**
+ * Some editor data may need to be synced with scene data (3D View camera and layers).
+ * This function ensures data is synced for editors
+ * in visible work-spaces and their visible layouts.
+ */
void WM_windows_scene_data_sync(const ListBase *win_lb, struct Scene *scene) ATTR_NONNULL();
struct Scene *WM_windows_scene_get_from_screen(const struct wmWindowManager *wm,
const struct bScreen *screen)
@@ -145,6 +191,9 @@ struct WorkSpace *WM_windows_workspace_get_from_screen(const wmWindowManager *wm
struct Scene *WM_window_get_active_scene(const struct wmWindow *win)
ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+/**
+ * \warning Only call outside of area/region loops.
+ */
void WM_window_set_active_scene(struct Main *bmain,
struct bContext *C,
struct wmWindow *win,
@@ -159,6 +208,9 @@ struct WorkSpaceLayout *WM_window_get_active_layout(const struct wmWindow *win)
void WM_window_set_active_layout(struct wmWindow *win,
struct WorkSpace *workspace,
struct WorkSpaceLayout *layout) ATTR_NONNULL(1);
+/**
+ * Get the active screen of the active workspace in \a win.
+ */
struct bScreen *WM_window_get_active_screen(const struct wmWindow *win)
ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
void WM_window_set_active_screen(struct wmWindow *win,
@@ -185,6 +237,14 @@ typedef enum eWindowAlignment {
WIN_ALIGN_PARENT_CENTER,
} eWindowAlignment;
+/**
+ * \param space_type: SPACE_VIEW3D, SPACE_INFO, ... (eSpace_Type)
+ * \param toplevel: Not a child owned by other windows. A peer of main window.
+ * \param dialog: whether this should be made as a dialog-style window
+ * \param temp: whether this is considered a short-lived window
+ * \param alignment: how this window is positioned relative to its parent
+ * \return the window or NULL in case of failure.
+ */
struct wmWindow *WM_window_open(struct bContext *C,
const char *title,
int x,
@@ -208,6 +268,10 @@ void WM_autosave_init(struct wmWindowManager *wm);
bool WM_recover_last_session(struct bContext *C, struct ReportList *reports);
void WM_file_tag_modified(void);
+/**
+ * \note `scene` (and related `view_layer` and `v3d`) pointers may be NULL,
+ * in which case no instantiation of linked objects, collections etc. will be performed.
+ */
struct ID *WM_file_link_datablock(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,
@@ -216,6 +280,10 @@ struct ID *WM_file_link_datablock(struct Main *bmain,
const short id_code,
const char *id_name,
int flag);
+/**
+ * \note `scene` (and related `view_layer` and `v3d`) pointers may be NULL,
+ * in which case no instantiation of appended objects, collections etc. will be performed.
+ */
struct ID *WM_file_append_datablock(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,
@@ -226,14 +294,24 @@ struct ID *WM_file_append_datablock(struct Main *bmain,
int flag);
void WM_lib_reload(struct Library *lib, struct bContext *C, struct ReportList *reports);
-/* mouse cursors */
+/* Mouse cursors. */
+
void WM_cursor_set(struct wmWindow *win, int curs);
bool WM_cursor_set_from_tool(struct wmWindow *win, const ScrArea *area, const ARegion *region);
void WM_cursor_modal_set(struct wmWindow *win, int val);
void WM_cursor_modal_restore(struct wmWindow *win);
+/**
+ * To allow usage all over, we do entire WM.
+ */
void WM_cursor_wait(bool val);
+/**
+ * \param bounds: can be NULL
+ */
void WM_cursor_grab_enable(struct wmWindow *win, int wrap, bool hide, int bounds[4]);
void WM_cursor_grab_disable(struct wmWindow *win, const int mouse_ungrab_xy[2]);
+/**
+ * After this you can call restore too.
+ */
void WM_cursor_time(struct wmWindow *win, int nr);
struct wmPaintCursor *WM_paint_cursor_activate(
@@ -249,10 +327,16 @@ void WM_paint_cursor_remove_by_type(struct wmWindowManager *wm,
void (*free)(void *));
void WM_paint_cursor_tag_redraw(struct wmWindow *win, struct ARegion *region);
+/**
+ * This function requires access to the GHOST_SystemHandle (g_system).
+ */
void WM_cursor_warp(struct wmWindow *win, int x, int y);
+/**
+ * Set x, y to values we can actually position the cursor to.
+ */
void WM_cursor_compatible_xy(wmWindow *win, int *x, int *y);
-/* handlers */
+/* Handlers. */
typedef bool (*EventHandlerPoll)(const ARegion *region, const struct wmEvent *event);
struct wmEventHandler_Keymap *WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap *keymap);
@@ -261,7 +345,9 @@ struct wmEventHandler_Keymap *WM_event_add_keymap_handler_poll(ListBase *handler
EventHandlerPoll poll);
struct wmEventHandler_Keymap *WM_event_add_keymap_handler_v2d_mask(ListBase *handlers,
wmKeyMap *keymap);
-/* priority not implemented, it adds in begin */
+/**
+ * \note Priorities not implemented yet, for time being just insert in begin of list.
+ */
struct wmEventHandler_Keymap *WM_event_add_keymap_handler_priority(ListBase *handlers,
wmKeyMap *keymap,
int priority);
@@ -319,6 +405,10 @@ struct wmEventHandler_UI *WM_event_add_ui_handler(const struct bContext *C,
wmUIHandlerRemoveFunc remove_fn,
void *user_data,
const char flag);
+/**
+ * \param postpone: Enable for `win->modalhandlers`,
+ * this is in a running for () loop in wm_handlers_do().
+ */
void WM_event_remove_ui_handler(ListBase *handlers,
wmUIHandlerFunc handle_fn,
wmUIHandlerRemoveFunc remove_fn,
@@ -331,13 +421,24 @@ void WM_event_free_ui_handler_all(struct bContext *C,
wmUIHandlerRemoveFunc remove_fn);
struct wmEventHandler_Op *WM_event_add_modal_handler(struct bContext *C, struct wmOperator *op);
+/**
+ * Modal handlers store a pointer to an area which might be freed while the handler runs.
+ * Use this function to NULL all handler pointers to \a old_area.
+ */
void WM_event_modal_handler_area_replace(wmWindow *win,
const struct ScrArea *old_area,
struct ScrArea *new_area);
+/**
+ * Modal handlers store a pointer to a region which might be freed while the handler runs.
+ * Use this function to NULL all handler pointers to \a old_region.
+ */
void WM_event_modal_handler_region_replace(wmWindow *win,
const struct ARegion *old_region,
struct ARegion *new_region);
+/**
+ * Called on exit or remove area, only here call cancel callback.
+ */
void WM_event_remove_handlers(struct bContext *C, ListBase *handlers);
/* handler flag */
@@ -366,11 +467,20 @@ void WM_event_add_notifier_ex(struct wmWindowManager *wm,
void *reference);
void WM_event_add_notifier(const struct bContext *C, unsigned int type, void *reference);
void WM_main_add_notifier(unsigned int type, void *reference);
+/**
+ * Clear notifiers by reference, Used so listeners don't act on freed data.
+ */
void WM_main_remove_notifier_reference(const void *reference);
void WM_main_remap_editor_id_reference(struct ID *old_id, struct ID *new_id);
/* reports */
+/**
+ * Show the report in the info header.
+ */
void WM_report_banner_show(void);
+/**
+ * Hide all currently displayed banners and abort their timer.
+ */
void WM_report_banners_cancel(struct Main *bmain);
void WM_report(eReportType type, const char *message);
void WM_reportf(eReportType type, const char *format, ...) ATTR_PRINTF_FORMAT(2, 3);
@@ -398,44 +508,87 @@ void WM_event_remove_timer(struct wmWindowManager *wm,
void WM_event_remove_timer_notifier(struct wmWindowManager *wm,
struct wmWindow *win,
struct wmTimer *timer);
+/**
+ * To (de)activate running timers temporary.
+ */
void WM_event_timer_sleep(struct wmWindowManager *wm,
struct wmWindow *win,
struct wmTimer *timer,
bool do_sleep);
-/* operator api, default callbacks */
-/* invoke callback, uses enum property named "type" */
+/* Operator API, default callbacks. */
+
+/**
+ * Helper to get select and tweak-transform to work conflict free and as desired. See
+ * #WM_operator_properties_generic_select() for details.
+ *
+ * To be used together with #WM_generic_select_invoke() and
+ * #WM_operator_properties_generic_select().
+ */
int WM_generic_select_modal(struct bContext *C,
struct wmOperator *op,
const struct wmEvent *event);
+/**
+ * Helper to get select and tweak-transform to work conflict free and as desired. See
+ * #WM_operator_properties_generic_select() for details.
+ *
+ * To be used together with #WM_generic_select_modal() and
+ * #WM_operator_properties_generic_select().
+ */
int WM_generic_select_invoke(struct bContext *C,
struct wmOperator *op,
const struct wmEvent *event);
void WM_operator_view3d_unit_defaults(struct bContext *C, struct wmOperator *op);
int WM_operator_smooth_viewtx_get(const struct wmOperator *op);
+/**
+ * Invoke callback, uses enum property named "type".
+ */
int WM_menu_invoke_ex(struct bContext *C, struct wmOperator *op, wmOperatorCallContext opcontext);
int WM_menu_invoke(struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
+/**
+ * Call an existent menu. The menu can be created in C or Python.
+ */
void WM_menu_name_call(struct bContext *C, const char *menu_name, short context);
+/**
+ * Similar to #WM_enum_search_invoke, but draws previews. Also, this can't
+ * be used as invoke callback directly since it needs additional info.
+ */
int WM_enum_search_invoke_previews(struct bContext *C,
struct wmOperator *op,
short prv_cols,
short prv_rows);
int WM_enum_search_invoke(struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
-/* invoke callback, confirm menu + exec */
+/**
+ * Invoke callback, confirm menu + exec.
+ */
int WM_operator_confirm(struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
int WM_operator_confirm_or_exec(struct bContext *C,
struct wmOperator *op,
const struct wmEvent *event);
-/* invoke callback, file selector "filepath" unset + exec */
+/**
+ * Invoke callback, file selector "filepath" unset + exec.
+ *
+ * #wmOperatorType.invoke, opens file-select if path property not set, otherwise executes.
+ */
int WM_operator_filesel(struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
bool WM_operator_filesel_ensure_ext_imtype(wmOperator *op,
const struct ImageFormatData *im_format);
-/* poll callback, context checks */
+/** Callback for #wmOperatorType.poll */
bool WM_operator_winactive(struct bContext *C);
-/* invoke callback, exec + redo popup */
+/**
+ * Invoke callback, exec + redo popup.
+ *
+ * Same as #WM_operator_props_popup but don't use operator redo.
+ * just wraps #WM_operator_props_dialog_popup.
+ */
int WM_operator_props_popup_confirm(struct bContext *C,
struct wmOperator *op,
const struct wmEvent *event);
+/**
+ * Same as #WM_operator_props_popup but call the operator first,
+ * This way - the button values correspond to the result of the operator.
+ * Without this, first access to a button will make the result jump, see T32452.
+ */
int WM_operator_props_popup_call(struct bContext *C,
struct wmOperator *op,
const struct wmEvent *event);
@@ -446,6 +599,9 @@ int WM_operator_props_dialog_popup(struct bContext *C, struct wmOperator *op, in
int WM_operator_redo_popup(struct bContext *C, struct wmOperator *op);
int WM_operator_ui_popup(struct bContext *C, struct wmOperator *op, int width);
+/**
+ * Can't be used as an invoke directly, needs message arg (can be NULL).
+ */
int WM_operator_confirm_message_ex(struct bContext *C,
struct wmOperator *op,
const char *title,
@@ -454,22 +610,60 @@ int WM_operator_confirm_message_ex(struct bContext *C,
const wmOperatorCallContext opcontext);
int WM_operator_confirm_message(struct bContext *C, struct wmOperator *op, const char *message);
-/* operator api */
+/* Operator API. */
+
void WM_operator_free(struct wmOperator *op);
void WM_operator_free_all_after(wmWindowManager *wm, struct wmOperator *op);
+/**
+ * Use with extreme care!
+ * Properties, custom-data etc - must be compatible.
+ *
+ * \param op: Operator to assign the type to.
+ * \param ot: Operator type to assign.
+ */
void WM_operator_type_set(struct wmOperator *op, struct wmOperatorType *ot);
void WM_operator_stack_clear(struct wmWindowManager *wm);
+/**
+ * This function is needed in the case when an addon id disabled
+ * while a modal operator it defined is running.
+ */
void WM_operator_handlers_clear(wmWindowManager *wm, struct wmOperatorType *ot);
bool WM_operator_poll(struct bContext *C, struct wmOperatorType *ot);
bool WM_operator_poll_context(struct bContext *C, struct wmOperatorType *ot, short context);
+/**
+ * For running operators with frozen context (modal handlers, menus).
+ *
+ * \param store: Store settings for re-use.
+ *
+ * \warning do not use this within an operator to call its self! T29537.
+ */
int WM_operator_call_ex(struct bContext *C, struct wmOperator *op, const bool store);
int WM_operator_call(struct bContext *C, struct wmOperator *op);
+/**
+ * This is intended to be used when an invoke operator wants to call exec on its self
+ * and is basically like running op->type->exec() directly, no poll checks no freeing,
+ * since we assume whoever called invoke will take care of that
+ */
int WM_operator_call_notest(struct bContext *C, struct wmOperator *op);
+/**
+ * Execute this operator again, put here so it can share above code
+ */
int WM_operator_repeat(struct bContext *C, struct wmOperator *op);
int WM_operator_repeat_last(struct bContext *C, struct wmOperator *op);
+/**
+ * \return true if #WM_operator_repeat can run.
+ * Simple check for now but may become more involved.
+ * To be sure the operator can run call `WM_operator_poll(C, op->type)` also, since this call
+ * checks if #WM_operator_repeat() can run at all, not that it WILL run at any time.
+ */
bool WM_operator_repeat_check(const struct bContext *C, struct wmOperator *op);
bool WM_operator_is_repeat(const struct bContext *C, const struct wmOperator *op);
+
+bool WM_operator_name_poll(struct bContext *C, const char *opstring);
+/**
+ * Invokes operator in context.
+ */
int WM_operator_name_call_ptr(struct bContext *C,
struct wmOperatorType *ot,
wmOperatorCallContext context,
@@ -482,6 +676,13 @@ int WM_operator_name_call_with_properties(struct bContext *C,
const char *opstring,
wmOperatorCallContext context,
struct IDProperty *properties);
+/**
+ * Similar to #WM_operator_name_call called with #WM_OP_EXEC_DEFAULT context.
+ *
+ * - #wmOperatorType is used instead of operator name since python already has the operator type.
+ * - `poll()` must be called by python before this runs.
+ * - reports can be passed to this function (so python can report them as exceptions).
+ */
int WM_operator_call_py(struct bContext *C,
struct wmOperatorType *ot,
wmOperatorCallContext context,
@@ -495,15 +696,30 @@ void WM_operator_name_call_ptr_with_depends_on_cursor(struct bContext *C,
PointerRNA *properties,
const char *drawstr);
-/* Used for keymap and macro items. */
+/**
+ * Similar to the function above except its uses ID properties used for key-maps and macros.
+ */
void WM_operator_properties_alloc(struct PointerRNA **ptr,
struct IDProperty **properties,
const char *opstring);
-/* Make props context sensitive or not. */
+/**
+ * Make props context sensitive or not.
+ */
void WM_operator_properties_sanitize(struct PointerRNA *ptr, const bool no_context);
+/**
+ * Set all props to their default.
+ *
+ * \param do_update: Only update un-initialized props.
+ *
+ * \note There's nothing specific to operators here.
+ * This could be made a general function.
+ */
bool WM_operator_properties_default(struct PointerRNA *ptr, const bool do_update);
+/**
+ * Remove all props without #PROP_SKIP_SAVE.
+ */
void WM_operator_properties_reset(struct wmOperator *op);
void WM_operator_properties_create(struct PointerRNA *ptr, const char *opstring);
void WM_operator_properties_create_ptr(struct PointerRNA *ptr, struct wmOperatorType *ot);
@@ -511,18 +727,28 @@ void WM_operator_properties_clear(struct PointerRNA *ptr);
void WM_operator_properties_free(struct PointerRNA *ptr);
bool WM_operator_check_ui_empty(struct wmOperatorType *ot);
+/**
+ * Return false, if the UI should be disabled.
+ */
bool WM_operator_check_ui_enabled(const struct bContext *C, const char *idname);
IDProperty *WM_operator_last_properties_ensure_idprops(struct wmOperatorType *ot);
void WM_operator_last_properties_ensure(struct wmOperatorType *ot, struct PointerRNA *ptr);
wmOperator *WM_operator_last_redo(const struct bContext *C);
+/**
+ * Use for drag & drop a path or name with operators invoke() function.
+ */
ID *WM_operator_drop_load_path(struct bContext *C, struct wmOperator *op, const short idcode);
bool WM_operator_last_properties_init(struct wmOperator *op);
bool WM_operator_last_properties_store(struct wmOperator *op);
/* wm_operator_props.c */
+
void WM_operator_properties_confirm_or_exec(struct wmOperatorType *ot);
+/**
+ * Default properties for file-select.
+ */
void WM_operator_properties_filesel(struct wmOperatorType *ot,
int filter,
short type,
@@ -530,36 +756,91 @@ void WM_operator_properties_filesel(struct wmOperatorType *ot,
short flag,
short display,
short sort);
+/**
+ * Disable using cursor position,
+ * use when view operators are initialized from buttons.
+ */
void WM_operator_properties_use_cursor_init(struct wmOperatorType *ot);
void WM_operator_properties_border(struct wmOperatorType *ot);
void WM_operator_properties_border_to_rcti(struct wmOperator *op, struct rcti *rect);
void WM_operator_properties_border_to_rctf(struct wmOperator *op, rctf *rect);
+/**
+ * Use with #WM_gesture_box_invoke
+ */
void WM_operator_properties_gesture_box_ex(struct wmOperatorType *ot, bool deselect, bool extend);
void WM_operator_properties_gesture_box(struct wmOperatorType *ot);
void WM_operator_properties_gesture_box_select(struct wmOperatorType *ot);
void WM_operator_properties_gesture_box_zoom(struct wmOperatorType *ot);
+/**
+ * Use with #WM_gesture_lasso_invoke
+ */
void WM_operator_properties_gesture_lasso(struct wmOperatorType *ot);
+/**
+ * Use with #WM_gesture_straightline_invoke
+ */
void WM_operator_properties_gesture_straightline(struct wmOperatorType *ot, int cursor);
+/**
+ * Use with #WM_gesture_circle_invoke
+ */
void WM_operator_properties_gesture_circle(struct wmOperatorType *ot);
void WM_operator_properties_mouse_select(struct wmOperatorType *ot);
void WM_operator_properties_select_all(struct wmOperatorType *ot);
void WM_operator_properties_select_action(struct wmOperatorType *ot,
int default_action,
bool hide_gui);
+/**
+ * Only #SELECT / #DESELECT.
+ */
void WM_operator_properties_select_action_simple(struct wmOperatorType *ot,
int default_action,
bool hide_gui);
+/**
+ * Use for all select random operators.
+ * Adds properties: percent, seed, action.
+ */
void WM_operator_properties_select_random(struct wmOperatorType *ot);
int WM_operator_properties_select_random_seed_increment_get(wmOperator *op);
void WM_operator_properties_select_operation(struct wmOperatorType *ot);
+/**
+ * \note Some tools don't support XOR/AND.
+ */
void WM_operator_properties_select_operation_simple(struct wmOperatorType *ot);
void WM_operator_properties_select_walk_direction(struct wmOperatorType *ot);
+/**
+ * Selecting and tweaking items are overlapping operations. Getting both to work without conflicts
+ * requires special care. See
+ * https://wiki.blender.org/wiki/Human_Interface_Guidelines/Selection#Select-tweaking for the
+ * desired behavior.
+ *
+ * For default click selection (with no modifier keys held), the select operators can do the
+ * following:
+ * - On a mouse press on an unselected item, change selection and finish immediately after.
+ * This sends an undo push and allows transform to take over should a tweak event be caught now.
+ * - On a mouse press on a selected item, don't change selection state, but start modal execution
+ * of the operator. Idea is that we wait with deselecting other items until we know that the
+ * intention wasn't to tweak (mouse press+drag) all selected items.
+ * - If a tweak is recognized before the release event happens, cancel the operator, so that
+ * transform can take over and no undo-push is sent.
+ * - If the release event occurs rather than a tweak one, deselect all items but the one under the
+ * cursor, and finish the modal operator.
+ *
+ * This utility, together with #WM_generic_select_invoke() and #WM_generic_select_modal() should
+ * help getting the wanted behavior to work. Most generic logic should be handled in these, so that
+ * the select operators only have to care for the case dependent handling.
+ *
+ * Every select operator has slightly different requirements, e.g. sequencer strip selection
+ * also needs to account for handle selection. This should be the baseline behavior though.
+ */
void WM_operator_properties_generic_select(struct wmOperatorType *ot);
+
struct CheckerIntervalParams {
int nth; /* bypass when set to zero */
int skip;
int offset;
};
+/**
+ * \param nth_can_disable: Enable if we want to be able to select no interval at all.
+ */
void WM_operator_properties_checker_interval(struct wmOperatorType *ot, bool nth_can_disable);
void WM_operator_properties_checker_interval_from_op(struct wmOperator *op,
struct CheckerIntervalParams *op_params);
@@ -576,7 +857,17 @@ bool WM_operator_properties_checker_interval_test(const struct CheckerIntervalPa
/* Show the properties sidebar by default. */
#define WM_FILESEL_SHOW_PROPS (1 << 5)
-/* operator as a python command (resultuing string must be freed) */
+/**
+ * Operator as a Python command (resulting string must be freed).
+ *
+ * Print a string representation of the operator,
+ * with the arguments that it runs so Python can run it again.
+ *
+ * When calling from an existing #wmOperator, better to use simple version:
+ * `WM_operator_pystring(C, op);`
+ *
+ * \note Both \a op and \a opptr may be `NULL` (\a op is only used for macro operators).
+ */
char *WM_operator_pystring_ex(struct bContext *C,
struct wmOperator *op,
const bool all_args,
@@ -587,16 +878,32 @@ char *WM_operator_pystring(struct bContext *C,
struct wmOperator *op,
const bool all_args,
const bool macro_args);
+/**
+ * \return true if the string was shortened.
+ */
bool WM_operator_pystring_abbreviate(char *str, int str_len_max);
char *WM_prop_pystring_assign(struct bContext *C,
struct PointerRNA *ptr,
struct PropertyRNA *prop,
int index);
+/**
+ * Convert: `some.op` -> `SOME_OT_op` or leave as-is.
+ */
void WM_operator_bl_idname(char *to, const char *from);
+/**
+ * Convert: `SOME_OT_op` -> `some.op` or leave as-is.
+ */
void WM_operator_py_idname(char *to, const char *from);
+/**
+ * Sanity check to ensure #WM_operator_bl_idname won't fail.
+ * \returns true when there are no problems with \a idname, otherwise report an error.
+ */
bool WM_operator_py_idname_ok_or_report(struct ReportList *reports,
const char *classname,
const char *idname);
+/**
+ * Calculate the path to `ptr` from context `C`, or return NULL if it can't be calculated.
+ */
char *WM_context_path_resolve_property_full(const struct bContext *C,
const PointerRNA *ptr,
PropertyRNA *prop,
@@ -604,16 +911,46 @@ char *WM_context_path_resolve_property_full(const struct bContext *C,
char *WM_context_path_resolve_full(struct bContext *C, const PointerRNA *ptr);
/* wm_operator_type.c */
+
struct wmOperatorType *WM_operatortype_find(const char *idname, bool quiet);
+/**
+ * \note Caller must free.
+ */
void WM_operatortype_iter(struct GHashIterator *ghi);
void WM_operatortype_append(void (*opfunc)(struct wmOperatorType *));
void WM_operatortype_append_ptr(void (*opfunc)(struct wmOperatorType *, void *), void *userdata);
void WM_operatortype_append_macro_ptr(void (*opfunc)(struct wmOperatorType *, void *),
void *userdata);
+/**
+ * Called on initialize WM_exit().
+ */
void WM_operatortype_remove_ptr(struct wmOperatorType *ot);
bool WM_operatortype_remove(const char *idname);
+/**
+ * Remove memory of all previously executed tools.
+ */
void WM_operatortype_last_properties_clear_all(void);
+/**
+ * Tag all operator-properties of \a ot defined after calling this, until
+ * the next #WM_operatortype_props_advanced_end call (if available), with
+ * #OP_PROP_TAG_ADVANCED. Previously defined ones properties not touched.
+ *
+ * Calling this multiple times without a call to #WM_operatortype_props_advanced_end,
+ * all calls after the first one are ignored. Meaning all proprieties defined after the
+ * first call are tagged as advanced.
+ *
+ * This doesn't do the actual tagging, #WM_operatortype_props_advanced_end does which is
+ * called for all operators during registration (see #wm_operatortype_append__end).
+ */
void WM_operatortype_props_advanced_begin(struct wmOperatorType *ot);
+/**
+ * Tags all operator-properties of \a ot defined since the first
+ * #WM_operatortype_props_advanced_begin call,
+ * or the last #WM_operatortype_props_advanced_end call, with #OP_PROP_TAG_ADVANCED.
+ *
+ * \note This is called for all operators during registration (see #wm_operatortype_append__end).
+ * So it does not need to be explicitly called in operator-type definition.
+ */
void WM_operatortype_props_advanced_end(struct wmOperatorType *ot);
#define WM_operatortype_prop_tag(property, tags) \
@@ -623,6 +960,9 @@ void WM_operatortype_props_advanced_end(struct wmOperatorType *ot);
} \
(void)0
+/**
+ * \note Names have to be static for now.
+ */
struct wmOperatorType *WM_operatortype_append_macro(const char *idname,
const char *name,
const char *description,
@@ -634,26 +974,57 @@ const char *WM_operatortype_name(struct wmOperatorType *ot, struct PointerRNA *p
char *WM_operatortype_description(struct bContext *C,
struct wmOperatorType *ot,
struct PointerRNA *properties);
+/**
+ * Use when we want a label, preferring the description.
+ */
char *WM_operatortype_description_or_name(struct bContext *C,
struct wmOperatorType *ot,
struct PointerRNA *properties);
/* wm_operator_utils.c */
+
+/**
+ * Allow an operator with only and execute function to run modally,
+ * re-doing the action, using vertex coordinate store/restore instead of operator undo.
+ */
void WM_operator_type_modal_from_exec_for_object_edit_coords(struct wmOperatorType *ot);
/* wm_uilist_type.c */
+
+/**
+ * Called on initialize #WM_init()
+ */
void WM_uilisttype_init(void);
struct uiListType *WM_uilisttype_find(const char *idname, bool quiet);
bool WM_uilisttype_add(struct uiListType *ult);
void WM_uilisttype_remove_ptr(struct Main *bmain, struct uiListType *ult);
void WM_uilisttype_free(void);
+/**
+ * The "full" list-ID is an internal name used for storing and identifying a list. It is built like
+ * this:
+ * "{uiListType.idname}_{list_id}", whereby "list_id" is an optional parameter passed to
+ * `UILayout.template_list()`. If it is not set, the full list-ID is just "{uiListType.idname}_".
+ *
+ * Note that whenever the Python API refers to the list-ID, it's the short, "non-full" one it
+ * passed to `UILayout.template_list()`. C code can query that through
+ * #WM_uilisttype_list_id_get().
+ */
void WM_uilisttype_to_full_list_id(const struct uiListType *ult,
const char *list_id,
char r_full_list_id[]);
+/**
+ * Get the "non-full" list-ID, see #WM_uilisttype_to_full_list_id() for details.
+ *
+ * \note Assumes `uiList.list_id` was set using #WM_uilisttype_to_full_list_id()!
+ */
const char *WM_uilisttype_list_id_get(const struct uiListType *ult, struct uiList *list);
/* wm_menu_type.c */
+
+/**
+ * \note Called on initialize #WM_init().
+ */
void WM_menutype_init(void);
struct MenuType *WM_menutype_find(const char *idname, bool quiet);
void WM_menutype_iter(struct GHashIterator *ghi);
@@ -663,6 +1034,10 @@ void WM_menutype_free(void);
bool WM_menutype_poll(struct bContext *C, struct MenuType *mt);
/* wm_panel_type.c */
+
+/**
+ * Called on initialize #WM_init().
+ */
void WM_paneltype_init(void);
void WM_paneltype_clear(void);
struct PanelType *WM_paneltype_find(const char *idname, bool quiet);
@@ -690,6 +1065,11 @@ int WM_gesture_lasso_invoke(struct bContext *C,
const struct wmEvent *event);
int WM_gesture_lasso_modal(struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
void WM_gesture_lasso_cancel(struct bContext *C, struct wmOperator *op);
+/**
+ * helper function, we may want to add options for conversion to view space
+ *
+ * caller must free.
+ */
const int (*WM_gesture_lasso_path_to_array(struct bContext *C,
struct wmOperator *op,
int *mcoords_len))[2];
@@ -697,18 +1077,38 @@ const int (*WM_gesture_lasso_path_to_array(struct bContext *C,
int WM_gesture_straightline_invoke(struct bContext *C,
struct wmOperator *op,
const struct wmEvent *event);
+/**
+ * This invoke callback starts the straight-line gesture with a viewport preview to the right side
+ * of the line.
+ */
int WM_gesture_straightline_active_side_invoke(struct bContext *C,
struct wmOperator *op,
const struct wmEvent *event);
+/**
+ * This modal callback calls exec once per mouse move event while the gesture is active with the
+ * updated line start and end values, so it can be used for tools that have a real time preview
+ * (like a gradient updating in real time over the mesh).
+ */
int WM_gesture_straightline_modal(struct bContext *C,
struct wmOperator *op,
const struct wmEvent *event);
+/**
+ * This modal one-shot callback only calls exec once after the gesture finishes without any updates
+ * during the gesture execution. Should be used for operations that are intended to be applied once
+ * without real time preview (like a trimming tool that only applies the bisect operation once
+ * after finishing the gesture as the bisect operation is too heavy to be computed in real time for
+ * a preview).
+ */
int WM_gesture_straightline_oneshot_modal(struct bContext *C,
struct wmOperator *op,
const struct wmEvent *event);
void WM_gesture_straightline_cancel(struct bContext *C, struct wmOperator *op);
/* Gesture manager API */
+
+/**
+ * Context checked on having screen, window and area.
+ */
struct wmGesture *WM_gesture_new(struct wmWindow *window,
const struct ARegion *region,
const struct wmEvent *event,
@@ -718,15 +1118,34 @@ void WM_gestures_remove(struct wmWindow *win);
void WM_gestures_free_all(struct wmWindow *win);
bool WM_gesture_is_modal_first(const struct wmGesture *gesture);
-/* fileselecting support */
+/* File-selecting support. */
+
+/**
+ * The idea here is to keep a handler alive on window queue, owning the operator.
+ * The file window can send event to make it execute, thus ensuring
+ * executing happens outside of lower level queues, with UI refreshed.
+ * Should also allow multi-window solutions.
+ */
void WM_event_add_fileselect(struct bContext *C, struct wmOperator *op);
void WM_event_fileselect_event(struct wmWindowManager *wm, void *ophandle, int eventval);
+/**
+ * Sets the active region for this space from the context.
+ *
+ * \see #BKE_area_find_region_active_win
+ */
void WM_operator_region_active_win_set(struct bContext *C);
+/**
+ * Only finish + pass through for press events (allowing press-tweak).
+ */
int WM_operator_flag_only_pass_through_on_press(int retval, const struct wmEvent *event);
-/* drag and drop */
+/* Drag and drop. */
+
+/**
+ * Note that the pointer should be valid allocated and not on stack.
+ */
struct wmDrag *WM_event_start_drag(
struct bContext *C, int icon, int type, void *poin, double value, unsigned int flags);
void WM_event_drag_image(struct wmDrag *, struct ImBuf *, float scale, int sx, int sy);
@@ -748,30 +1167,61 @@ void WM_drag_draw_default_fn(struct bContext *C,
struct wmWindow *win,
struct wmDrag *drag,
const int xy[2]);
+/**
+ * `spaceid` / `regionid` are zero for window drop maps.
+ */
ListBase *WM_dropboxmap_find(const char *idname, int spaceid, int regionid);
/* ID drag and drop */
+
+/**
+ * \param flag_extra: Additional linking flags (from #eFileSel_Params_Flag).
+ */
ID *WM_drag_asset_id_import(wmDragAsset *asset_drag, int flag_extra);
bool WM_drag_asset_will_import_linked(const wmDrag *drag);
void WM_drag_add_local_ID(struct wmDrag *drag, struct ID *id, struct ID *from_parent);
struct ID *WM_drag_get_local_ID(const struct wmDrag *drag, short idcode);
struct ID *WM_drag_get_local_ID_from_event(const struct wmEvent *event, short idcode);
+/**
+ * Check if the drag data is either a local ID or an external ID asset of type \a idcode.
+ */
bool WM_drag_is_ID_type(const struct wmDrag *drag, int idcode);
+/**
+ * \note: Does not store \a asset in any way, so it's fine to pass a temporary.
+ */
wmDragAsset *WM_drag_create_asset_data(const struct AssetHandle *asset,
struct AssetMetaData *metadata,
const char *path,
int import_type);
struct wmDragAsset *WM_drag_get_asset_data(const struct wmDrag *drag, int idcode);
struct AssetMetaData *WM_drag_get_asset_meta_data(const struct wmDrag *drag, int idcode);
+/**
+ * When dragging a local ID, return that. Otherwise, if dragging an asset-handle, link or append
+ * that depending on what was chosen by the drag-box (currently append only in fact).
+ *
+ * Use #WM_drag_free_imported_drag_ID() as cancel callback of the drop-box, so that the asset
+ * import is rolled back if the drop operator fails.
+ */
struct ID *WM_drag_get_local_ID_or_import_from_asset(const struct wmDrag *drag, int idcode);
+/**
+ * \brief Free asset ID imported for canceled drop.
+ *
+ * If the asset was imported (linked/appended) using #WM_drag_get_local_ID_or_import_from_asset()`
+ * (typically via a #wmDropBox.copy() callback), we want the ID to be removed again if the drop
+ * operator cancels.
+ * This is for use as #wmDropBox.cancel() callback.
+ */
void WM_drag_free_imported_drag_ID(struct Main *bmain,
struct wmDrag *drag,
struct wmDropBox *drop);
struct wmDragAssetCatalog *WM_drag_get_asset_catalog_data(const struct wmDrag *drag);
+/**
+ * \note: Does not store \a asset in any way, so it's fine to pass a temporary.
+ */
void WM_drag_add_asset_list_item(wmDrag *drag,
const struct bContext *C,
const struct AssetLibraryReference *asset_library_ref,
@@ -788,6 +1238,10 @@ void wmWindowViewport(struct wmWindow *win);
/* OpenGL utilities with safety check */
void wmOrtho2(float x1, float x2, float y1, float y2);
/* use for conventions (avoid hard-coded offsets all over) */
+
+/**
+ * Default pixel alignment for regions.
+ */
void wmOrtho2_region_pixelspace(const struct ARegion *region);
void wmOrtho2_pixelspace(const float x, const float y);
void wmGetProjectionMatrix(float mat[4][4], const struct rcti *winrct);
@@ -834,6 +1288,12 @@ enum {
* if having hard coded values is a problem */
};
+/**
+ * \return current job or adds new job, but doesn't run it.
+ *
+ * \note every owner only gets a single job,
+ * adding a new one will stop running job and when stopped it starts the new one.
+ */
struct wmJob *WM_jobs_get(struct wmWindowManager *wm,
struct wmWindow *win,
const void *owner,
@@ -841,9 +1301,15 @@ struct wmJob *WM_jobs_get(struct wmWindowManager *wm,
int flag,
int job_type);
+/**
+ * Returns true if job runs, for UI (progress) indicators.
+ */
bool WM_jobs_test(const struct wmWindowManager *wm, const void *owner, int job_type);
float WM_jobs_progress(const struct wmWindowManager *wm, const void *owner);
const char *WM_jobs_name(const struct wmWindowManager *wm, const void *owner);
+/**
+ * Time that job started.
+ */
double WM_jobs_starttime(const struct wmWindowManager *wm, const void *owner);
void *WM_jobs_customdata(struct wmWindowManager *wm, const void *owner);
void *WM_jobs_customdata_from_type(struct wmWindowManager *wm, int job_type);
@@ -865,12 +1331,28 @@ void WM_jobs_callbacks(struct wmJob *,
void (*update)(void *),
void (*endjob)(void *));
+/**
+ * If job running, the same owner gave it a new job.
+ * if different owner starts existing startjob, it suspends itself
+ */
void WM_jobs_start(struct wmWindowManager *wm, struct wmJob *);
+/**
+ * Signal job(s) from this owner or callback to stop, timer is required to get handled.
+ */
void WM_jobs_stop(struct wmWindowManager *wm, const void *owner, void *startjob);
+/**
+ * Actually terminate thread and job timer.
+ */
void WM_jobs_kill(struct wmWindowManager *wm,
void *owner,
void (*)(void *, short int *, short int *, float *));
+/**
+ * Wait until every job ended.
+ */
void WM_jobs_kill_all(struct wmWindowManager *wm);
+/**
+ * Wait until every job ended, except for one owner (used in undo to keep screen job alive).
+ */
void WM_jobs_kill_all_except(struct wmWindowManager *wm, const void *owner);
void WM_jobs_kill_type(struct wmWindowManager *wm, const void *owner, int job_type);
@@ -879,16 +1361,27 @@ bool WM_jobs_has_running(const struct wmWindowManager *wm);
void WM_job_main_thread_lock_acquire(struct wmJob *job);
void WM_job_main_thread_lock_release(struct wmJob *job);
-/* clipboard */
+/* Clipboard. */
+
+/**
+ * Return text from the clipboard.
+ *
+ * \note Caller needs to check for valid utf8 if this is a requirement.
+ */
char *WM_clipboard_text_get(bool selection, int *r_len);
+/**
+ * Convenience function for pasting to areas of Blender which don't support newlines.
+ */
char *WM_clipboard_text_get_firstline(bool selection, int *r_len);
void WM_clipboard_text_set(const char *buf, bool selection);
/* progress */
+
void WM_progress_set(struct wmWindow *win, float progress);
void WM_progress_clear(struct wmWindow *win);
/* Draw (for screenshot) */
+
void *WM_draw_cb_activate(struct wmWindow *win,
void (*draw)(const struct wmWindow *, void *),
void *customdata);
@@ -900,21 +1393,29 @@ void WM_draw_region_viewport_bind(struct ARegion *region);
void WM_draw_region_viewport_unbind(struct ARegion *region);
/* Region drawing */
+
void WM_draw_region_free(struct ARegion *region, bool hide);
struct GPUViewport *WM_draw_region_get_viewport(struct ARegion *region);
struct GPUViewport *WM_draw_region_get_bound_viewport(struct ARegion *region);
void WM_main_playanim(int argc, const char **argv);
-/* debugging only, convenience function to write on crash */
+/**
+ * Debugging only, convenience function to write on crash.
+ * Convenient to save a blend file from a debugger.
+ */
bool write_crash_blend(void);
-/* Lock the interface for any communication */
+/**
+ * Lock the interface for any communication.
+ */
void WM_set_locked_interface(struct wmWindowManager *wm, bool lock);
void WM_event_tablet_data_default_set(struct wmTabletData *tablet_data);
-/* For testing only 'G_FLAG_EVENT_SIMULATE' */
+/**
+ * For testing only, see #G_FLAG_EVENT_SIMULATE.
+ */
struct wmEvent *WM_event_add_simulate(struct wmWindow *win, const struct wmEvent *event_to_add);
const char *WM_window_cursor_keymap_status_get(const struct wmWindow *win,
@@ -923,28 +1424,60 @@ const char *WM_window_cursor_keymap_status_get(const struct wmWindow *win,
void WM_window_cursor_keymap_status_refresh(struct bContext *C, struct wmWindow *win);
void WM_window_status_area_tag_redraw(struct wmWindow *win);
+/**
+ * Similar to #BKE_screen_area_map_find_area_xy and related functions,
+ * use here since the area is stored in the window manager.
+ */
struct ScrArea *WM_window_status_area_find(struct wmWindow *win, struct bScreen *screen);
bool WM_window_modal_keymap_status_draw(struct bContext *C,
struct wmWindow *win,
struct uiLayout *layout);
/* wm_event_query.c */
+
+/**
+ * For debugging only, getting inspecting events manually is tedious.
+ */
void WM_event_print(const struct wmEvent *event);
int WM_event_modifier_flag(const struct wmEvent *event);
+/**
+ * For modal callbacks, check configuration for how to interpret exit with tweaks.
+ */
bool WM_event_is_modal_tweak_exit(const struct wmEvent *event, int tweak_event);
bool WM_event_is_last_mousemove(const struct wmEvent *event);
bool WM_event_is_mouse_drag(const struct wmEvent *event);
bool WM_event_is_mouse_drag_or_press(const wmEvent *event);
+/**
+ * Detect motion between selection (callers should only use this for selection picking),
+ * typically mouse press/click events.
+ *
+ * \param mval: Region relative coordinates, call with (-1, -1) resets the last cursor location.
+ * \returns True when there was motion since last called.
+ *
+ * NOTE(@campbellbarton): The logic used here isn't foolproof.
+ * It's possible that users move the cursor past #WM_EVENT_CURSOR_MOTION_THRESHOLD then back to
+ * a position within the threshold (between mouse clicks).
+ * In practice users never reported this since the threshold is very small (a few pixels).
+ * To prevent the unlikely case of values matching from another region,
+ * changing regions resets this value to (-1, -1).
+ */
bool WM_cursor_test_motion_and_update(const int mval[2]) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
int WM_event_drag_threshold(const struct wmEvent *event);
bool WM_event_drag_test(const struct wmEvent *event, const int prev_xy[2]);
bool WM_event_drag_test_with_delta(const struct wmEvent *event, const int delta[2]);
-/* event map */
+/**
+ * Event map that takes preferences into account.
+ */
int WM_userdef_event_map(int kmitype);
+/**
+ * Use so we can check if 'wmEvent.type' is released in modal operators.
+ *
+ * An alternative would be to add a 'wmEvent.type_nokeymap'... or similar.
+ */
int WM_userdef_event_type_from_keymap_type(int kmitype);
#ifdef WITH_INPUT_NDOF
@@ -961,6 +1494,10 @@ void WM_event_ndof_to_quat(const struct wmNDOFMotionData *ndof, float q[4]);
bool WM_event_is_xr(const struct wmEvent *event);
#endif
+/**
+ * If this is a tablet event, return tablet pressure and set `*pen_flip`
+ * to 1 if the eraser tool is being used, 0 otherwise.
+ */
float WM_event_tablet_data(const struct wmEvent *event, int *pen_flip, float tilt[2]);
bool WM_event_is_tablet(const struct wmEvent *event);
@@ -972,6 +1509,7 @@ bool WM_event_is_ime_switch(const struct wmEvent *event);
#endif
/* wm_tooltip.c */
+
typedef struct ARegion *(*wmTooltipInitFn)(struct bContext *C,
struct ARegion *region,
int *pass,
@@ -1001,6 +1539,7 @@ void WM_tooltip_refresh(struct bContext *C, struct wmWindow *win);
double WM_tooltip_time_closed(void);
/* wm_utils.c */
+
struct wmGenericCallback *WM_generic_callback_steal(struct wmGenericCallback *callback);
void WM_generic_callback_free(struct wmGenericCallback *callback);
@@ -1010,7 +1549,15 @@ bool WM_region_use_viewport(struct ScrArea *area, struct ARegion *region);
#ifdef WITH_XR_OPENXR
/* wm_xr_session.c */
+
+/**
+ * Check if the XR-Session was triggered.
+ * If an error happened while trying to start a session, this returns false too.
+ */
bool WM_xr_session_exists(const wmXrData *xr);
+/**
+ * Check if the session is running, according to the OpenXR definition.
+ */
bool WM_xr_session_is_ready(const wmXrData *xr);
struct wmXrSessionState *WM_xr_session_state_handle_get(const wmXrData *xr);
struct ScrArea *WM_xr_session_area_get(const wmXrData *xr);
@@ -1043,8 +1590,10 @@ void WM_xr_session_state_navigation_reset(struct wmXrSessionState *state);
struct ARegionType *WM_xr_surface_controller_region_type_get(void);
/* wm_xr_actions.c */
+
/* XR action functions to be called pre-XR session start.
* NOTE: The "destroy" functions can also be called post-session start. */
+
bool WM_xr_action_set_create(wmXrData *xr, const char *action_set_name);
void WM_xr_action_set_destroy(wmXrData *xr, const char *action_set_name);
bool WM_xr_action_create(wmXrData *xr,
@@ -1078,7 +1627,9 @@ void WM_xr_action_binding_destroy(wmXrData *xr,
const char *action_name,
const char *profile_path);
-/* If action_set_name is NULL, then all action sets will be treated as active. */
+/**
+ * If action_set_name is NULL, then all action sets will be treated as active.
+ */
bool WM_xr_active_action_set_set(wmXrData *xr, const char *action_set_name);
bool WM_xr_controller_pose_actions_set(wmXrData *xr,
@@ -1086,7 +1637,9 @@ bool WM_xr_controller_pose_actions_set(wmXrData *xr,
const char *grip_action_name,
const char *aim_action_name);
-/* XR action functions to be called post-XR session start. */
+/**
+ * XR action functions to be called post-XR session start.
+ */
bool WM_xr_action_state_get(const wmXrData *xr,
const char *action_set_name,
const char *action_name,
@@ -1105,9 +1658,13 @@ void WM_xr_haptic_action_stop(wmXrData *xr,
const char *subaction_path);
/* wm_xr_actionmap.c */
+
XrActionMap *WM_xr_actionmap_new(struct wmXrRuntimeData *runtime,
const char *name,
bool replace_existing);
+/**
+ * Ensure unique name among all action maps.
+ */
void WM_xr_actionmap_ensure_unique(struct wmXrRuntimeData *runtime, XrActionMap *actionmap);
XrActionMap *WM_xr_actionmap_add_copy(struct wmXrRuntimeData *runtime, XrActionMap *am_src);
bool WM_xr_actionmap_remove(struct wmXrRuntimeData *runtime, XrActionMap *actionmap);
@@ -1123,15 +1680,25 @@ void WM_xr_actionmap_selected_index_set(struct wmXrRuntimeData *runtime, short i
XrActionMapItem *WM_xr_actionmap_item_new(XrActionMap *actionmap,
const char *name,
bool replace_existing);
+/**
+ * Ensure unique name among all action map items.
+ */
void WM_xr_actionmap_item_ensure_unique(XrActionMap *actionmap, XrActionMapItem *ami);
XrActionMapItem *WM_xr_actionmap_item_add_copy(XrActionMap *actionmap, XrActionMapItem *ami_src);
bool WM_xr_actionmap_item_remove(XrActionMap *actionmap, XrActionMapItem *ami);
XrActionMapItem *WM_xr_actionmap_item_find(XrActionMap *actionmap, const char *name);
+/**
+ * Similar to #wm_xr_actionmap_item_properties_set()
+ * but checks for the #eXrActionType and #wmOperatorType having changed.
+ */
void WM_xr_actionmap_item_properties_update_ot(XrActionMapItem *ami);
XrActionMapBinding *WM_xr_actionmap_binding_new(XrActionMapItem *ami,
const char *name,
bool replace_existing);
+/**
+ * Ensure unique name among all action map bindings.
+ */
void WM_xr_actionmap_binding_ensure_unique(XrActionMapItem *ami, XrActionMapBinding *amb);
XrActionMapBinding *WM_xr_actionmap_binding_add_copy(XrActionMapItem *ami,
XrActionMapBinding *amb_src);
diff --git a/source/blender/windowmanager/WM_keymap.h b/source/blender/windowmanager/WM_keymap.h
index 0633ffe55ea..4d1f2d979cb 100644
--- a/source/blender/windowmanager/WM_keymap.h
+++ b/source/blender/windowmanager/WM_keymap.h
@@ -55,6 +55,9 @@ void WM_keyconfig_update_operatortype(void);
void WM_keymap_clear(struct wmKeyMap *keymap);
+/**
+ * Always add item.
+ */
wmKeyMapItem *WM_keymap_add_item(
struct wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier);
wmKeyMapItem *WM_keymap_add_item_copy(struct wmKeyMap *keymap, wmKeyMapItem *kmi_src);
@@ -91,16 +94,30 @@ bool WM_keymap_item_compare(const struct wmKeyMapItem *k1, const struct wmKeyMap
/* keymap_utils.c */
-/** Wrappers for #WM_keymap_add_item */
+/* Wrappers for #WM_keymap_add_item */
+
+/**
+ * Menu wrapper for #WM_keymap_add_item.
+ */
wmKeyMapItem *WM_keymap_add_menu(
struct wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier);
+/**
+ * Pie-menu wrapper for #WM_keymap_add_item.
+ */
wmKeyMapItem *WM_keymap_add_menu_pie(
struct wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier);
+/**
+ * Panel (popover) wrapper for #WM_keymap_add_item.
+ */
wmKeyMapItem *WM_keymap_add_panel(
struct wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier);
+/**
+ * Tool wrapper for #WM_keymap_add_item.
+ */
wmKeyMapItem *WM_keymap_add_tool(
struct wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier);
+/** Useful for mapping numbers to an enum. */
void WM_keymap_add_context_enum_set_items(wmKeyMap *keymap,
const struct EnumPropertyItem *items,
const char *data_path,
@@ -110,6 +127,12 @@ void WM_keymap_add_context_enum_set_items(wmKeyMap *keymap,
int keymodifier);
wmKeyMap *WM_keymap_guess_from_context(const struct bContext *C);
+
+/**
+ * Guess an appropriate key-map from the operator name.
+ *
+ * \note Needs to be kept up to date with Key-map and Operator naming.
+ */
wmKeyMap *WM_keymap_guess_opname(const struct bContext *C, const char *opname);
bool WM_keymap_uses_event_modifier(const wmKeyMap *keymap, const int event_modifier);
@@ -149,6 +172,9 @@ void WM_modalkeymap_assign(struct wmKeyMap *km, const char *opname);
/* Keymap Editor */
void WM_keymap_restore_to_default(struct wmKeyMap *keymap, struct wmWindowManager *wm);
+/**
+ * Properties can be NULL, otherwise the arg passed is used and ownership is given to the `kmi`.
+ */
void WM_keymap_item_properties_reset(struct wmKeyMapItem *kmi, struct IDProperty *properties);
void WM_keymap_item_restore_to_default(wmWindowManager *wm,
struct wmKeyMap *keymap,
@@ -168,6 +194,10 @@ int WM_keymap_item_raw_to_string(const short shift,
const bool compact,
char *result,
const int result_len);
+/**
+ * \param include_mask, exclude_mask:
+ * Event types to include/exclude when looking up keys (#eEventType_Mask).
+ */
wmKeyMapItem *WM_key_event_operator(const struct bContext *C,
const char *opname,
wmOperatorCallContext opcontext,
diff --git a/source/blender/windowmanager/WM_toolsystem.h b/source/blender/windowmanager/WM_toolsystem.h
index eb89fca7b56..32b9cf1d7ba 100644
--- a/source/blender/windowmanager/WM_toolsystem.h
+++ b/source/blender/windowmanager/WM_toolsystem.h
@@ -69,6 +69,9 @@ void WM_toolsystem_unlink(struct bContext *C, struct WorkSpace *workspace, const
void WM_toolsystem_refresh(struct bContext *C, struct WorkSpace *workspace, const bToolKey *tkey);
void WM_toolsystem_reinit(struct bContext *C, struct WorkSpace *workspace, const bToolKey *tkey);
+/**
+ * Operate on all active tools.
+ */
void WM_toolsystem_unlink_all(struct bContext *C, struct WorkSpace *workspace);
void WM_toolsystem_refresh_all(struct bContext *C, struct WorkSpace *workspace);
void WM_toolsystem_reinit_all(struct bContext *C, struct wmWindow *win);
@@ -79,6 +82,12 @@ void WM_toolsystem_ref_set_from_runtime(struct bContext *C,
const struct bToolRef_Runtime *tref_rt,
const char *idname);
+/**
+ * Sync the internal active state of a tool back into the tool system,
+ * this is needed for active brushes where the real active state is not stored in the tool system.
+ *
+ * \see #toolsystem_ref_link
+ */
void WM_toolsystem_ref_sync_from_context(struct Main *bmain,
struct WorkSpace *workspace,
struct bToolRef *tref);
@@ -98,8 +107,12 @@ void WM_toolsystem_update_from_context(struct bContext *C,
struct ViewLayer *view_layer,
struct ScrArea *area);
+/**
+ * For paint modes to support non-brush tools.
+ */
bool WM_toolsystem_active_tool_is_brush(const struct bContext *C);
+/** Follow #wmMsgNotifyFn spec. */
void WM_toolsystem_do_msg_notify_tag_refresh(struct bContext *C,
struct wmMsgSubscribeKey *msg_key,
struct wmMsgSubscribeValue *msg_val);
@@ -129,6 +142,14 @@ void WM_toolsystem_ref_properties_init_for_keymap(struct bToolRef *tref,
struct PointerRNA *src_ptr,
struct wmOperatorType *ot);
+/**
+ * Use to update the active tool (shown in the top bar) in the least disruptive way.
+ *
+ * This is a little involved since there may be multiple valid active tools
+ * depending on the mode and space type.
+ *
+ * Used when undoing since the active mode may have changed.
+ */
void WM_toolsystem_refresh_active(struct bContext *C);
void WM_toolsystem_refresh_screen_area(struct WorkSpace *workspace,
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index b8fe3786bde..3d56303a424 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -972,10 +972,10 @@ typedef void (*wmPaintCursorDraw)(struct bContext *C, int, int, void *customdata
#define WM_DRAG_DATASTACK 8
#define WM_DRAG_ASSET_CATALOG 9
-typedef enum wmDragFlags {
+typedef enum eWM_DragFlags {
WM_DRAG_NOP = 0,
WM_DRAG_FREE_DATA = 1,
-} wmDragFlags;
+} eWM_DragFlags;
/* NOTE: structs need not exported? */
@@ -1070,7 +1070,7 @@ typedef struct wmDrag {
wmDragActiveDropState drop_state;
- unsigned int flags;
+ eWM_DragFlags flags;
/** List of wmDragIDs, all are guaranteed to have the same ID type. */
ListBase ids;
diff --git a/source/blender/windowmanager/gizmo/WM_gizmo_api.h b/source/blender/windowmanager/gizmo/WM_gizmo_api.h
index c7a4b064d0e..497e4f6e5fc 100644
--- a/source/blender/windowmanager/gizmo/WM_gizmo_api.h
+++ b/source/blender/windowmanager/gizmo/WM_gizmo_api.h
@@ -61,19 +61,42 @@ extern "C" {
struct wmGizmo *WM_gizmo_new_ptr(const struct wmGizmoType *gzt,
struct wmGizmoGroup *gzgroup,
struct PointerRNA *properties);
+/**
+ * \param idname: Must be a valid gizmo type name,
+ * if you need to check it exists use #WM_gizmo_new_ptr
+ * because callers of this function don't NULL check the return value.
+ */
struct wmGizmo *WM_gizmo_new(const char *idname,
struct wmGizmoGroup *gzgroup,
struct PointerRNA *properties);
+/**
+ * \warning this doesn't check #wmGizmoMap (highlight, selection etc).
+ * Typical use is when freeing the windowing data,
+ * where caller can manage clearing selection, highlight... etc.
+ */
void WM_gizmo_free(struct wmGizmo *gz);
+/**
+ * Free \a gizmo and unlink from \a gizmolist.
+ * \a gizmolist is allowed to be NULL.
+ */
void WM_gizmo_unlink(ListBase *gizmolist,
struct wmGizmoMap *gzmap,
struct wmGizmo *gz,
struct bContext *C);
+/**
+ * Remove from selection array without running callbacks.
+ */
bool WM_gizmo_select_unlink(struct wmGizmoMap *gzmap, struct wmGizmo *gz);
bool WM_gizmo_select_set(struct wmGizmoMap *gzmap, struct wmGizmo *gz, bool select);
bool WM_gizmo_highlight_set(struct wmGizmoMap *gzmap, struct wmGizmo *gz);
+/**
+ * Special function to run from setup so gizmos start out interactive.
+ *
+ * We could do this when linking them,
+ * but this complicates things since the window update code needs to run first.
+ */
void WM_gizmo_modal_set_from_setup(struct wmGizmoMap *gzmap,
struct bContext *C,
struct wmGizmo *gz,
@@ -87,17 +110,30 @@ struct PointerRNA *WM_gizmo_operator_set(struct wmGizmo *gz,
struct IDProperty *properties);
int WM_gizmo_operator_invoke(struct bContext *C, struct wmGizmo *gz, struct wmGizmoOpElem *gzop);
-/* callbacks */
+/* Callbacks. */
+
void WM_gizmo_set_fn_custom_modal(struct wmGizmo *gz, wmGizmoFnModal fn);
void WM_gizmo_set_matrix_location(struct wmGizmo *gz, const float origin[3]);
+/**
+ * #wmGizmo.matrix utility, set the orientation by it's Z axis.
+ */
void WM_gizmo_set_matrix_rotation_from_z_axis(struct wmGizmo *gz, const float z_axis[3]);
+/**
+ * #wmGizmo.matrix utility, set the orientation by it's Y/Z axis.
+ */
void WM_gizmo_set_matrix_rotation_from_yz_axis(struct wmGizmo *gz,
const float y_axis[3],
const float z_axis[3]);
void WM_gizmo_set_matrix_offset_location(struct wmGizmo *gz, const float offset[3]);
+/**
+ * #wmGizmo.matrix_offset utility, set the orientation by it's Z axis.
+ */
void WM_gizmo_set_matrix_offset_rotation_from_z_axis(struct wmGizmo *gz, const float z_axis[3]);
+/**
+ * #wmGizmo.matrix_offset utility, set the orientation by it's Y/Z axis.
+ */
void WM_gizmo_set_matrix_offset_rotation_from_yz_axis(struct wmGizmo *gz,
const float y_axis[3],
const float z_axis[3]);
@@ -128,14 +164,30 @@ void WM_gizmo_calc_matrix_final_no_offset(const struct wmGizmo *gz, float r_mat[
void WM_gizmo_calc_matrix_final(const struct wmGizmo *gz, float r_mat[4][4]);
-/* properties */
+/* Properties. */
+
void WM_gizmo_properties_create_ptr(struct PointerRNA *ptr, struct wmGizmoType *gzt);
void WM_gizmo_properties_create(struct PointerRNA *ptr, const char *gtstring);
+/**
+ * Similar to #WM_gizmo_properties_create
+ * except its uses ID properties used for key-maps and macros.
+ */
void WM_gizmo_properties_alloc(struct PointerRNA **ptr,
struct IDProperty **properties,
const char *gtstring);
void WM_gizmo_properties_sanitize(struct PointerRNA *ptr, const bool no_context);
+/**
+ * Set all props to their default.
+ *
+ * \param do_update: Only update un-initialized props.
+ *
+ * \note There's nothing specific to gizmos here.
+ * This could be made a general function.
+ */
bool WM_gizmo_properties_default(struct PointerRNA *ptr, const bool do_update);
+/**
+ * Remove all props without #PROP_SKIP_SAVE.
+ */
void WM_gizmo_properties_reset(struct wmGizmo *gz);
void WM_gizmo_properties_clear(struct PointerRNA *ptr);
void WM_gizmo_properties_free(struct PointerRNA *ptr);
@@ -146,7 +198,13 @@ void WM_gizmotype_append(void (*gtfunc)(struct wmGizmoType *));
void WM_gizmotype_append_ptr(void (*gtfunc)(struct wmGizmoType *, void *), void *userdata);
bool WM_gizmotype_remove(struct bContext *C, struct Main *bmain, const char *idname);
void WM_gizmotype_remove_ptr(struct bContext *C, struct Main *bmain, struct wmGizmoType *gzt);
+/**
+ * Free but don't remove from ghash.
+ */
void WM_gizmotype_free_ptr(struct wmGizmoType *gzt);
+/**
+ * Caller must free.
+ */
void WM_gizmotype_iter(struct GHashIterator *ghi);
/* wm_gizmo_group_type.c */
@@ -155,8 +213,15 @@ struct wmGizmoGroupType *WM_gizmogrouptype_append(void (*wtfunc)(struct wmGizmoG
struct wmGizmoGroupType *WM_gizmogrouptype_append_ptr(void (*wtfunc)(struct wmGizmoGroupType *,
void *),
void *userdata);
+/**
+ * Caller must free.
+ */
void WM_gizmogrouptype_iter(struct GHashIterator *ghi);
+/**
+ * Append and insert into a gizmo typemap.
+ * This is most common for C gizmos which are enabled by default.
+ */
struct wmGizmoGroupTypeRef *WM_gizmogrouptype_append_and_link(
struct wmGizmoMapType *gzmap_type, void (*wtfunc)(struct wmGizmoGroupType *));
@@ -167,6 +232,10 @@ void WM_gizmoconfig_update_tag_group_type_init(struct wmGizmoMapType *gzmap_type
struct wmGizmoGroupType *gzgt);
void WM_gizmoconfig_update_tag_group_type_remove(struct wmGizmoMapType *gzmap_type,
struct wmGizmoGroupType *gzgt);
+/**
+ * Run in case new types have been added (runs often, early exit where possible).
+ * Follows #WM_keyconfig_update conventions.
+ */
void WM_gizmoconfig_update(struct Main *bmain);
void WM_gizmoconfig_update_tag_group_remove(struct wmGizmoMap *gzmap);
@@ -222,7 +291,8 @@ bool WM_gizmo_target_property_float_range_get(const struct wmGizmo *gz,
int WM_gizmo_target_property_array_length(const struct wmGizmo *gz,
struct wmGizmoProperty *gz_prop);
-/* definitions */
+/* Definitions. */
+
const struct wmGizmoPropertyType *WM_gizmotype_target_property_find(const struct wmGizmoType *gzt,
const char *idname);
void WM_gizmotype_target_property_def(struct wmGizmoType *gzt,
@@ -230,14 +300,21 @@ void WM_gizmotype_target_property_def(struct wmGizmoType *gzt,
int data_type,
int array_length);
-/* utilities */
+/* Utilities. */
+
void WM_gizmo_do_msg_notify_tag_refresh(struct bContext *C,
struct wmMsgSubscribeKey *msg_key,
struct wmMsgSubscribeValue *msg_val);
+/**
+ * Runs on the "prepare draw" pass, drawing the region clears.
+ */
void WM_gizmo_target_property_subscribe_all(struct wmGizmo *gz,
struct wmMsgBus *mbus,
struct ARegion *region);
+/**
+ * Auto-key function if auto-key is enabled.
+ */
void WM_gizmo_target_property_anim_autokey(struct bContext *C,
const struct wmGizmo *gz,
struct wmGizmoProperty *gz_prop);
@@ -256,6 +333,7 @@ struct wmKeyMap *WM_gizmogroup_setup_keymap_generic_maybe_drag(const struct wmGi
struct wmKeyConfig *kc);
/* Utility functions (not callbacks). */
+
struct wmKeyMap *WM_gizmo_keymap_generic_with_keyconfig(struct wmKeyConfig *kc);
struct wmKeyMap *WM_gizmo_keymap_generic(struct wmWindowManager *wm);
@@ -268,19 +346,29 @@ struct wmKeyMap *WM_gizmo_keymap_generic_drag(struct wmWindowManager *wm);
struct wmKeyMap *WM_gizmo_keymap_generic_click_drag_with_keyconfig(struct wmKeyConfig *kc);
struct wmKeyMap *WM_gizmo_keymap_generic_click_drag(struct wmWindowManager *wm);
+/**
+ * Drag or press depending on preference.
+ */
struct wmKeyMap *WM_gizmo_keymap_generic_maybe_drag_with_keyconfig(struct wmKeyConfig *kc);
struct wmKeyMap *WM_gizmo_keymap_generic_maybe_drag(struct wmWindowManager *wm);
void WM_gizmogroup_ensure_init(const struct bContext *C, struct wmGizmoGroup *gzgroup);
/* Sort utilities for use with 'BLI_listbase_sort'. */
+
int WM_gizmo_cmp_temp_fl(const void *gz_a_ptr, const void *gz_b_ptr);
int WM_gizmo_cmp_temp_fl_reverse(const void *gz_a_ptr, const void *gz_b_ptr);
/* -------------------------------------------------------------------- */
/* wmGizmoMap */
+/**
+ * Creates a gizmo-map with all registered gizmos for that type
+ */
struct wmGizmoMap *WM_gizmomap_new_from_type(const struct wmGizmoMapType_Params *gzmap_params);
+/**
+ * Re-create the gizmos (use when changing theme settings).
+ */
void WM_gizmomap_reinit(struct wmGizmoMap *gzmap);
const struct ListBase *WM_gizmomap_group_list(struct wmGizmoMap *gzmap);
struct wmGizmoGroup *WM_gizmomap_group_find(struct wmGizmoMap *gzmap, const char *idname);
@@ -298,6 +386,12 @@ void WM_gizmomap_draw(struct wmGizmoMap *gzmap,
const struct bContext *C,
const eWM_GizmoFlagMapDrawStep drawstep);
void WM_gizmomap_add_handlers(struct ARegion *region, struct wmGizmoMap *gzmap);
+/**
+ * Select/Deselect all selectable gizmos in \a gzmap.
+ * \return if selection has changed.
+ *
+ * TODO: select all by type.
+ */
bool WM_gizmomap_select_all(struct bContext *C, struct wmGizmoMap *gzmap, const int action);
bool WM_gizmomap_cursor_set(const struct wmGizmoMap *gzmap, struct wmWindow *win);
void WM_gizmomap_message_subscribe(const struct bContext *C,
@@ -305,6 +399,9 @@ void WM_gizmomap_message_subscribe(const struct bContext *C,
struct ARegion *region,
struct wmMsgBus *mbus);
bool WM_gizmomap_is_any_selected(const struct wmGizmoMap *gzmap);
+/**
+ * \note We could use a callback to define bounds, for now just use matrix location.
+ */
bool WM_gizmomap_minmax(const struct wmGizmoMap *gzmap,
bool use_hidden,
bool use_select,
@@ -327,6 +424,10 @@ struct wmGizmoGroupTypeRef *WM_gizmomaptype_group_find(struct wmGizmoMapType *gz
const char *idname);
struct wmGizmoGroupTypeRef *WM_gizmomaptype_group_find_ptr(struct wmGizmoMapType *gzmap_type,
const struct wmGizmoGroupType *gzgt);
+/**
+ * Use this for registering gizmos on startup.
+ * For runtime, use #WM_gizmomaptype_group_link_runtime.
+ */
struct wmGizmoGroupTypeRef *WM_gizmomaptype_group_link(struct wmGizmoMapType *gzmap_type,
const char *idname);
struct wmGizmoGroupTypeRef *WM_gizmomaptype_group_link_ptr(struct wmGizmoMapType *gzmap_type,
@@ -345,6 +446,9 @@ void WM_gizmomaptype_group_unlink(struct bContext *C,
struct wmGizmoMapType *gzmap_type,
const struct wmGizmoGroupType *gzgt);
+/**
+ * Unlike #WM_gizmomaptype_group_unlink this doesn't maintain correct state, simply free.
+ */
void WM_gizmomaptype_group_free(struct wmGizmoGroupTypeRef *gzgt);
/* -------------------------------------------------------------------- */
@@ -362,6 +466,9 @@ bool WM_gizmo_group_type_ensure_ptr_ex(struct wmGizmoGroupType *gzgt,
bool WM_gizmo_group_type_ensure_ptr(struct wmGizmoGroupType *gzgt);
bool WM_gizmo_group_type_ensure(const char *idname);
+/**
+ * Call #WM_gizmo_group_type_free_ptr after to remove & free.
+ */
void WM_gizmo_group_type_remove_ptr_ex(struct Main *bmain,
struct wmGizmoGroupType *gzgt,
struct wmGizmoMapType *gzmap_type);
@@ -380,7 +487,9 @@ void WM_gizmo_group_unlink_delayed_ptr_from_space(struct wmGizmoGroupType *gzgt,
void WM_gizmo_group_type_free_ptr(wmGizmoGroupType *gzgt);
bool WM_gizmo_group_type_free(const char *idname);
-/* Has the result of unlinking and linking (re-initializes gizmo's). */
+/**
+ * Has the result of unlinking and linking (re-initializes gizmo's).
+ */
void WM_gizmo_group_type_reinit_ptr_ex(struct Main *bmain,
struct wmGizmoGroupType *gzgt,
struct wmGizmoMapType *gzmap_type);
@@ -388,6 +497,7 @@ void WM_gizmo_group_type_reinit_ptr(struct Main *bmain, struct wmGizmoGroupType
void WM_gizmo_group_type_reinit(struct Main *bmain, const char *idname);
/* Utilities */
+
bool WM_gizmo_context_check_drawstep(const struct bContext *C, eWM_GizmoFlagMapDrawStep step);
void WM_gizmo_group_remove_by_tool(struct bContext *C,
@@ -398,6 +508,7 @@ void WM_gizmo_group_remove_by_tool(struct bContext *C,
void WM_gizmo_group_tag_remove(struct wmGizmoGroup *gzgroup);
/* Wrap Group Type Callbacks. */
+
bool WM_gizmo_group_type_poll(const struct bContext *C, const struct wmGizmoGroupType *gzgt);
void WM_gizmo_group_refresh(const struct bContext *C, struct wmGizmoGroup *gzgroup);
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo.c
index cfedd67b2f0..d4f11c79d46 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo.c
@@ -106,11 +106,6 @@ wmGizmo *WM_gizmo_new_ptr(const wmGizmoType *gzt, wmGizmoGroup *gzgroup, Pointer
return gz;
}
-/**
- * \param idname: Must be a valid gizmo type name,
- * if you need to check it exists use #WM_gizmo_new_ptr
- * because callers of this function don't NULL check the return value.
- */
wmGizmo *WM_gizmo_new(const char *idname, wmGizmoGroup *gzgroup, PointerRNA *properties)
{
const wmGizmoType *gzt = WM_gizmotype_find(idname, false);
@@ -143,11 +138,6 @@ static void wm_gizmo_register(wmGizmoGroup *gzgroup, wmGizmo *gz)
wm_gizmogroup_gizmo_register(gzgroup, gz);
}
-/**
- * \warning this doesn't check #wmGizmoMap (highlight, selection etc).
- * Typical use is when freeing the windowing data,
- * where caller can manage clearing selection, highlight... etc.
- */
void WM_gizmo_free(wmGizmo *gz)
{
if (gz->type->free != NULL) {
@@ -187,10 +177,6 @@ void WM_gizmo_free(wmGizmo *gz)
MEM_freeN(gz);
}
-/**
- * Free \a gizmo and unlink from \a gizmolist.
- * \a gizmolist is allowed to be NULL.
- */
void WM_gizmo_unlink(ListBase *gizmolist, wmGizmoMap *gzmap, wmGizmo *gz, bContext *C)
{
if (gz->state & WM_GIZMO_STATE_HIGHLIGHT) {
@@ -300,9 +286,6 @@ static void wm_gizmo_set_matrix_rotation_from_yz_axis__internal(float matrix[4][
normalize_v3(matrix[0]);
}
-/**
- * wmGizmo.matrix utils.
- */
void WM_gizmo_set_matrix_rotation_from_z_axis(wmGizmo *gz, const float z_axis[3])
{
wm_gizmo_set_matrix_rotation_from_z_axis__internal(gz->matrix_basis, z_axis);
@@ -318,9 +301,6 @@ void WM_gizmo_set_matrix_location(wmGizmo *gz, const float origin[3])
copy_v3_v3(gz->matrix_basis[3], origin);
}
-/**
- * wmGizmo.matrix_offset utils.
- */
void WM_gizmo_set_matrix_offset_rotation_from_z_axis(wmGizmo *gz, const float z_axis[3])
{
wm_gizmo_set_matrix_rotation_from_z_axis__internal(gz->matrix_offset, z_axis);
@@ -388,12 +368,7 @@ void WM_gizmo_set_fn_custom_modal(struct wmGizmo *gz, wmGizmoFnModal fn)
/** \} */
/* -------------------------------------------------------------------- */
-/**
- * Add/Remove \a gizmo to selection.
- * Reallocates memory for selected gizmos so better not call for selecting multiple ones.
- *
- * \return if the selection has changed.
- */
+
bool wm_gizmo_select_set_ex(
wmGizmoMap *gzmap, wmGizmo *gz, bool select, bool use_array, bool use_callback)
{
@@ -429,7 +404,6 @@ bool wm_gizmo_select_set_ex(
return changed;
}
-/* Remove from selection array without running callbacks. */
bool WM_gizmo_select_unlink(wmGizmoMap *gzmap, wmGizmo *gz)
{
return wm_gizmo_select_set_ex(gzmap, gz, false, true, false);
@@ -454,12 +428,6 @@ bool wm_gizmo_select_and_highlight(bContext *C, wmGizmoMap *gzmap, wmGizmo *gz)
return false;
}
-/**
- * Special function to run from setup so gizmos start out interactive.
- *
- * We could do this when linking them,
- * but this complicates things since the window update code needs to run first.
- */
void WM_gizmo_modal_set_from_setup(struct wmGizmoMap *gzmap,
struct bContext *C,
struct wmGizmo *gz,
@@ -634,8 +602,6 @@ void WM_gizmo_properties_create(PointerRNA *ptr, const char *gtstring)
}
}
-/* similar to the function above except its uses ID properties
- * used for keymaps and macros */
void WM_gizmo_properties_alloc(PointerRNA **ptr, IDProperty **properties, const char *gtstring)
{
if (*properties == NULL) {
@@ -680,14 +646,6 @@ void WM_gizmo_properties_sanitize(PointerRNA *ptr, const bool no_context)
RNA_STRUCT_END;
}
-/**
- * Set all props to their default.
- *
- * \param do_update: Only update un-initialized props.
- *
- * \note There's nothing specific to gizmos here.
- * This could be made a general function.
- */
bool WM_gizmo_properties_default(PointerRNA *ptr, const bool do_update)
{
bool changed = false;
@@ -715,7 +673,6 @@ bool WM_gizmo_properties_default(PointerRNA *ptr, const bool do_update)
return changed;
}
-/* remove all props without PROP_SKIP_SAVE */
void WM_gizmo_properties_reset(wmGizmo *gz)
{
if (gz->ptr->data) {
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c
index b6d759eb95f..6f10e4f3f0d 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c
@@ -63,9 +63,6 @@
/** \name wmGizmoGroup
* \{ */
-/**
- * Create a new gizmo-group from \a gzgt.
- */
wmGizmoGroup *wm_gizmogroup_new_from_type(wmGizmoMap *gzmap, wmGizmoGroupType *gzgt)
{
wmGizmoGroup *gzgroup = MEM_callocN(sizeof(*gzgroup), "gizmo-group");
@@ -148,9 +145,6 @@ void WM_gizmo_group_tag_remove(wmGizmoGroup *gzgroup)
}
}
-/**
- * Add \a gizmo to \a gzgroup and make sure its name is unique within the group.
- */
void wm_gizmogroup_gizmo_register(wmGizmoGroup *gzgroup, wmGizmo *gz)
{
BLI_assert(BLI_findindex(&gzgroup->gizmos, gz) == -1);
@@ -234,10 +228,6 @@ wmGizmo *wm_gizmogroup_find_intersected_gizmo(wmWindowManager *wm,
return NULL;
}
-/**
- * Adds all gizmos of \a gzgroup that can be selected to the head of \a listbase.
- * Added items need freeing!
- */
void wm_gizmogroup_intersectable_gizmos_to_list(wmWindowManager *wm,
const wmGizmoGroup *gzgroup,
const int event_modifier,
@@ -345,10 +335,9 @@ bool wm_gizmogroup_is_any_selected(const wmGizmoGroup *gzgroup)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Gizmo operators
+/** \name Gizmo Operators
*
* Basic operators for gizmo interaction with user configurable keymaps.
- *
* \{ */
static int gizmo_select_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
@@ -641,8 +630,6 @@ void GIZMOGROUP_OT_gizmo_tweak(wmOperatorType *ot)
#endif
}
-/** \} */
-
wmKeyMap *wm_gizmogroup_tweak_modal_keymap(wmKeyConfig *keyconf)
{
wmKeyMap *keymap;
@@ -774,11 +761,12 @@ wmKeyMap *WM_gizmogroup_setup_keymap_generic_select(const wmGizmoGroupType *UNUS
return WM_gizmogroup_keymap_template_select_ex(kc, "Generic Gizmo Select", &params);
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name wmGizmo (Key-map access)
*
* Key config version so these can be called from #wmGizmoGroupFnSetupKeymap.
- *
* \{ */
struct wmKeyMap *WM_gizmo_keymap_generic_with_keyconfig(wmKeyConfig *kc)
@@ -821,7 +809,6 @@ struct wmKeyMap *WM_gizmo_keymap_generic_click_drag(wmWindowManager *wm)
return WM_gizmo_keymap_generic_click_drag_with_keyconfig(wm->defaultconf);
}
-/** Drag or press depending on preference. */
struct wmKeyMap *WM_gizmo_keymap_generic_maybe_drag_with_keyconfig(wmKeyConfig *kc)
{
const char *idname = "Generic Gizmo Maybe Drag";
@@ -862,10 +849,6 @@ struct wmGizmoGroupTypeRef *WM_gizmomaptype_group_find(struct wmGizmoMapType *gz
return NULL;
}
-/**
- * Use this for registering gizmos on startup.
- * For runtime, use #WM_gizmomaptype_group_link_runtime.
- */
wmGizmoGroupTypeRef *WM_gizmomaptype_group_link(wmGizmoMapType *gzmap_type, const char *idname)
{
wmGizmoGroupType *gzgt = WM_gizmogrouptype_find(idname, false);
@@ -939,9 +922,6 @@ wmGizmoGroup *WM_gizmomaptype_group_init_runtime_with_region(wmGizmoMapType *gzm
return gzgroup;
}
-/**
- * Unlike #WM_gizmomaptype_group_unlink this doesn't maintain correct state, simply free.
- */
void WM_gizmomaptype_group_free(wmGizmoGroupTypeRef *gzgt_ref)
{
MEM_freeN(gzgt_ref);
@@ -1017,7 +997,6 @@ void wm_gizmogrouptype_setup_keymap(wmGizmoGroupType *gzgt, wmKeyConfig *keyconf
* but for general purpose API this is too detailed & annoying.
*
* \note We may want to return a value if there is nothing to remove.
- *
* \{ */
void WM_gizmo_group_type_add_ptr_ex(wmGizmoGroupType *gzgt, wmGizmoMapType *gzmap_type)
@@ -1059,9 +1038,6 @@ bool WM_gizmo_group_type_ensure(const char *idname)
return WM_gizmo_group_type_ensure_ptr(gzgt);
}
-/**
- * Call #WM_gizmo_group_type_free_ptr after to remove & free.
- */
void WM_gizmo_group_type_remove_ptr_ex(struct Main *bmain,
wmGizmoGroupType *gzgt,
wmGizmoMapType *gzmap_type)
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_group_type.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_group_type.c
index 6a793d52f74..0a36068bb21 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_group_type.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_group_type.c
@@ -71,7 +71,6 @@ wmGizmoGroupType *WM_gizmogrouptype_find(const char *idname, bool quiet)
return NULL;
}
-/* caller must free */
void WM_gizmogrouptype_iter(GHashIterator *ghi)
{
BLI_ghashIterator_init(ghi, global_gizmogrouptype_hash);
@@ -127,10 +126,6 @@ wmGizmoGroupType *WM_gizmogrouptype_append_ptr(void (*wtfunc)(struct wmGizmoGrou
return gzgt;
}
-/**
- * Append and insert into a gizmo typemap.
- * This is most common for C gizmos which are enabled by default.
- */
wmGizmoGroupTypeRef *WM_gizmogrouptype_append_and_link(wmGizmoMapType *gzmap_type,
void (*wtfunc)(struct wmGizmoGroupType *))
{
@@ -190,7 +185,6 @@ void wm_gizmogrouptype_free(void)
global_gizmogrouptype_hash = NULL;
}
-/* called on initialize WM_init() */
void wm_gizmogrouptype_init(void)
{
/* reserve size is set based on blender default setup */
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_intern.h b/source/blender/windowmanager/gizmo/intern/wm_gizmo_intern.h
index dd2db209771..b6912d79076 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_intern.h
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_intern.h
@@ -29,6 +29,12 @@ struct wmKeyConfig;
/* -------------------------------------------------------------------- */
/* wmGizmo */
+/**
+ * Add/Remove \a gizmo to selection.
+ * Reallocates memory for selected gizmos so better not call for selecting multiple ones.
+ *
+ * \return if the selection has changed.
+ */
bool wm_gizmo_select_set_ex(
struct wmGizmoMap *gzmap, struct wmGizmo *gz, bool select, bool use_array, bool use_callback);
bool wm_gizmo_select_and_highlight(bContext *C, struct wmGizmoMap *gzmap, struct wmGizmo *gz);
@@ -54,9 +60,15 @@ enum {
TWEAK_MODAL_SNAP_OFF,
};
+/**
+ * Create a new gizmo-group from \a gzgt.
+ */
struct wmGizmoGroup *wm_gizmogroup_new_from_type(struct wmGizmoMap *gzmap,
struct wmGizmoGroupType *gzgt);
void wm_gizmogroup_free(bContext *C, struct wmGizmoGroup *gzgroup);
+/**
+ * Add \a gizmo to \a gzgroup and make sure its name is unique within the group.
+ */
void wm_gizmogroup_gizmo_register(struct wmGizmoGroup *gzgroup, struct wmGizmo *gz);
struct wmGizmoGroup *wm_gizmogroup_find_by_type(const struct wmGizmoMap *gzmap,
const struct wmGizmoGroupType *gzgt);
@@ -66,6 +78,10 @@ struct wmGizmo *wm_gizmogroup_find_intersected_gizmo(wmWindowManager *wm,
const int event_modifier,
const int mval[2],
int *r_part);
+/**
+ * Adds all gizmos of \a gzgroup that can be selected to the head of \a listbase.
+ * Added items need freeing!
+ */
void wm_gizmogroup_intersectable_gizmos_to_list(wmWindowManager *wm,
const struct wmGizmoGroup *gzgroup,
const int event_modifier,
@@ -137,6 +153,10 @@ struct wmGizmoMapType {
};
void wm_gizmomap_select_array_clear(struct wmGizmoMap *gzmap);
+/**
+ * Deselect all selected gizmos in \a gzmap.
+ * \return if selection has changed.
+ */
bool wm_gizmomap_deselect_all(struct wmGizmoMap *gzmap);
void wm_gizmomap_select_array_shrink(struct wmGizmoMap *gzmap, int len_subtract);
void wm_gizmomap_select_array_push_back(struct wmGizmoMap *gzmap, wmGizmo *gz);
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
index 6f952bc9526..d3e682f1490 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
@@ -176,9 +176,6 @@ static wmGizmoMap *wm_gizmomap_new_from_type_ex(struct wmGizmoMapType *gzmap_typ
return gzmap;
}
-/**
- * Creates a gizmo-map with all registered gizmos for that type
- */
wmGizmoMap *WM_gizmomap_new_from_type(const struct wmGizmoMapType_Params *gzmap_params)
{
wmGizmoMapType *gzmap_type = WM_gizmomaptype_ensure(gzmap_params);
@@ -207,7 +204,6 @@ void wm_gizmomap_remove(wmGizmoMap *gzmap)
MEM_freeN(gzmap);
}
-/** Re-create the gizmos (use when changing theme settings). */
void WM_gizmomap_reinit(wmGizmoMap *gzmap)
{
wmGizmoMapType *gzmap_type = gzmap->type;
@@ -246,9 +242,6 @@ bool WM_gizmomap_is_any_selected(const wmGizmoMap *gzmap)
return gzmap->gzmap_context.select.len != 0;
}
-/**
- * \note We could use a callback to define bounds, for now just use matrix location.
- */
bool WM_gizmomap_minmax(const wmGizmoMap *gzmap,
bool UNUSED(use_hidden),
bool use_select,
@@ -713,10 +706,6 @@ static wmGizmo *gizmo_find_intersected_3d(bContext *C,
return result;
}
-/**
- * Try to find a gizmo under the mouse position. 2D intersections have priority over
- * 3D ones (could check for smallest screen-space distance but not needed right now).
- */
wmGizmo *wm_gizmomap_highlight_find(wmGizmoMap *gzmap,
bContext *C,
const wmEvent *event,
@@ -843,10 +832,6 @@ void wm_gizmomaps_handled_modal_update(bContext *C, wmEvent *event, wmEventHandl
CTX_wm_region_set(C, region);
}
-/**
- * Deselect all selected gizmos in \a gzmap.
- * \return if selection has changed.
- */
bool wm_gizmomap_deselect_all(wmGizmoMap *gzmap)
{
wmGizmoMapSelectState *msel = &gzmap->gzmap_context.select;
@@ -903,12 +888,6 @@ static bool wm_gizmomap_select_all_intern(bContext *C, wmGizmoMap *gzmap)
return changed;
}
-/**
- * Select/Deselect all selectable gizmos in \a gzmap.
- * \return if selection has changed.
- *
- * TODO: select all by type.
- */
bool WM_gizmomap_select_all(bContext *C, wmGizmoMap *gzmap, const int action)
{
bool changed = false;
@@ -932,10 +911,6 @@ bool WM_gizmomap_select_all(bContext *C, wmGizmoMap *gzmap, const int action)
return changed;
}
-/**
- * Prepare context for gizmo handling (but only if area/region is
- * part of screen). Version of #wm_handler_op_context for gizmos.
- */
void wm_gizmomap_handler_context_op(bContext *C, wmEventHandler_Op *handler)
{
bScreen *screen = CTX_wm_screen(C);
@@ -1037,9 +1012,6 @@ wmGizmo *wm_gizmomap_highlight_get(wmGizmoMap *gzmap)
return gzmap->gzmap_context.highlight;
}
-/**
- * Caller should call exit when (enable == False).
- */
void wm_gizmomap_modal_set(
wmGizmoMap *gzmap, bContext *C, wmGizmo *gz, const wmEvent *event, bool enable)
{
@@ -1247,9 +1219,6 @@ void wm_gizmomaptypes_free(void)
}
}
-/**
- * Initialize keymaps for all existing gizmo-groups
- */
void wm_gizmos_keymap(wmKeyConfig *keyconf)
{
LISTBASE_FOREACH (wmGizmoMapType *, gzmap_type, &gizmomaptypes) {
@@ -1293,10 +1262,6 @@ void WM_gizmoconfig_update_tag_group_remove(wmGizmoMap *gzmap)
wm_gzmap_type_update_flag |= WM_GIZMOTYPE_GLOBAL_UPDATE_REMOVE;
}
-/**
- * Run in case new types have been added (runs often, early exit where possible).
- * Follows #WM_keyconfig_update conventions.
- */
void WM_gizmoconfig_update(struct Main *bmain)
{
if (G.background) {
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c
index 63e833d73c3..57555fb5416 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c
@@ -319,10 +319,6 @@ void WM_gizmo_do_msg_notify_tag_refresh(bContext *UNUSED(C),
WM_gizmomap_tag_refresh(gzmap);
}
-/**
- * Runs on the "prepare draw" pass,
- * drawing the region clears.
- */
void WM_gizmo_target_property_subscribe_all(wmGizmo *gz, struct wmMsgBus *mbus, ARegion *region)
{
if (gz->type->target_property_defs_len) {
@@ -355,9 +351,6 @@ void WM_gizmo_target_property_subscribe_all(wmGizmo *gz, struct wmMsgBus *mbus,
}
}
-/**
- * Auto-key function if auto-key is enabled.
- */
void WM_gizmo_target_property_anim_autokey(bContext *C,
const wmGizmo *UNUSED(gz),
wmGizmoProperty *gz_prop)
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_type.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_type.c
index 1523246d08b..602100a624e 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_type.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_type.c
@@ -78,7 +78,6 @@ const wmGizmoType *WM_gizmotype_find(const char *idname, bool quiet)
return NULL;
}
-/* caller must free */
void WM_gizmotype_iter(GHashIterator *ghi)
{
BLI_ghashIterator_init(ghi, global_gizmotype_hash);
@@ -118,9 +117,6 @@ void WM_gizmotype_append_ptr(void (*gtfunc)(struct wmGizmoType *, void *), void
wm_gizmotype_append__end(mt);
}
-/**
- * Free but don't remove from ghash.
- */
void WM_gizmotype_free_ptr(wmGizmoType *gzt)
{
if (gzt->rna_ext.srna) { /* python gizmo, allocs own string */
@@ -195,7 +191,6 @@ void wm_gizmotype_free(void)
global_gizmotype_hash = NULL;
}
-/* called on initialize WM_init() */
void wm_gizmotype_init(void)
{
/* reserve size is set based on blender default setup */
diff --git a/source/blender/windowmanager/gizmo/wm_gizmo_wmapi.h b/source/blender/windowmanager/gizmo/wm_gizmo_wmapi.h
index 18b3f40aba6..0612ba97db0 100644
--- a/source/blender/windowmanager/gizmo/wm_gizmo_wmapi.h
+++ b/source/blender/windowmanager/gizmo/wm_gizmo_wmapi.h
@@ -40,37 +40,63 @@ extern "C" {
#endif
/* -------------------------------------------------------------------- */
-/* wmGizmo */
+/** \name #wmGizmo
+ * \{ */
/* wm_gizmo_type.c, for init/exit */
+
void wm_gizmotype_free(void);
+/**
+ * Called on initialize #WM_init().
+ */
void wm_gizmotype_init(void);
/* wm_gizmogroup_type.c, for init/exit */
+
void wm_gizmogrouptype_free(void);
+/**
+ * Called on initialize #WM_init().
+ */
void wm_gizmogrouptype_init(void);
+/** \} */
+
/* -------------------------------------------------------------------- */
-/* wmGizmoGroup */
+/** \name #wmGizmoGroup
+ * \{ */
void GIZMOGROUP_OT_gizmo_select(struct wmOperatorType *ot);
void GIZMOGROUP_OT_gizmo_tweak(struct wmOperatorType *ot);
bool wm_gizmogroup_is_any_selected(const struct wmGizmoGroup *gzgroup);
+/** \} */
+
/* -------------------------------------------------------------------- */
-/* wmGizmoMap */
+/** \name #wmGizmoMap
+ * \{ */
void wm_gizmomap_remove(struct wmGizmoMap *gzmap);
+/**
+ * Initialize key-maps for all existing gizmo-groups
+ */
void wm_gizmos_keymap(struct wmKeyConfig *keyconf);
void wm_gizmomaps_handled_modal_update(bContext *C,
struct wmEvent *event,
struct wmEventHandler_Op *handler);
+/**
+ * Prepare context for gizmo handling (but only if area/region is
+ * part of screen). Version of #wm_handler_op_context for gizmos.
+ */
void wm_gizmomap_handler_context_op(bContext *C, struct wmEventHandler_Op *handler);
void wm_gizmomap_handler_context_gizmo(bContext *C, struct wmEventHandler_Gizmo *handler);
+/**
+ * Try to find a gizmo under the mouse position. 2D intersections have priority over
+ * 3D ones (could check for smallest screen-space distance but not needed right now).
+ */
struct wmGizmo *wm_gizmomap_highlight_find(struct wmGizmoMap *gzmap,
bContext *C,
const struct wmEvent *event,
@@ -80,6 +106,9 @@ bool wm_gizmomap_highlight_set(struct wmGizmoMap *gzmap,
struct wmGizmo *gz,
int part);
struct wmGizmo *wm_gizmomap_highlight_get(struct wmGizmoMap *gzmap);
+/**
+ * Caller should call exit when (enable == False).
+ */
void wm_gizmomap_modal_set(struct wmGizmoMap *gzmap,
bContext *C,
struct wmGizmo *gz,
@@ -90,11 +119,16 @@ struct wmGizmo *wm_gizmomap_modal_get(struct wmGizmoMap *gzmap);
struct wmGizmo **wm_gizmomap_selected_get(wmGizmoMap *gzmap, int *r_selected_len);
struct ListBase *wm_gizmomap_groups_get(wmGizmoMap *gzmap);
+/** \} */
+
/* -------------------------------------------------------------------- */
-/* wmGizmoMapType */
+/** \name #wmGizmoMapType
+ * \{ */
void wm_gizmomaptypes_free(void);
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c
index 47ee296823b..40f8da63e11 100644
--- a/source/blender/windowmanager/intern/wm.c
+++ b/source/blender/windowmanager/intern/wm.c
@@ -272,6 +272,7 @@ IDTypeInfo IDType_ID_WM = {
.name_plural = "window_managers",
.translation_context = BLT_I18NCONTEXT_ID_WINDOWMANAGER,
.flags = IDTYPE_FLAGS_NO_COPY | IDTYPE_FLAGS_NO_LIBLINKING | IDTYPE_FLAGS_NO_ANIMDATA,
+ .asset_type_info = NULL,
.init_data = NULL,
.copy_data = NULL,
@@ -279,6 +280,7 @@ IDTypeInfo IDType_ID_WM = {
.make_local = NULL,
.foreach_id = window_manager_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = window_manager_blend_write,
@@ -339,13 +341,6 @@ void WM_operator_free_all_after(wmWindowManager *wm, struct wmOperator *op)
}
}
-/**
- * Use with extreme care!,
- * properties, custom-data etc - must be compatible.
- *
- * \param op: Operator to assign the type to.
- * \param ot: Operator type to assign.
- */
void WM_operator_type_set(wmOperator *op, wmOperatorType *ot)
{
/* Not supported for Python. */
@@ -375,8 +370,6 @@ static void wm_reports_free(wmWindowManager *wm)
WM_event_remove_timer(wm, NULL, wm->reports.reporttimer);
}
-/* All operations get registered in the windowmanager here. */
-/* Called on event handling by event_system.c. */
void wm_operator_register(bContext *C, wmOperator *op)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -413,10 +406,6 @@ void WM_operator_stack_clear(wmWindowManager *wm)
WM_main_add_notifier(NC_WM | ND_HISTORY, NULL);
}
-/**
- * This function is needed in the case when an addon id disabled
- * while a modal operator it defined is running.
- */
void WM_operator_handlers_clear(wmWindowManager *wm, wmOperatorType *ot)
{
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
@@ -549,7 +538,6 @@ void wm_clear_default_size(bContext *C)
}
}
-/* On startup, it adds all data, for matching. */
void wm_add_default(Main *bmain, bContext *C)
{
wmWindowManager *wm = BKE_libblock_alloc(bmain, ID_WM, "WinMan", 0);
@@ -571,7 +559,6 @@ void wm_add_default(Main *bmain, bContext *C)
wm_window_make_drawable(wm, win);
}
-/* Context is allowed to be NULL, do not free wm itself (lib_id.c). */
void wm_close_and_free(bContext *C, wmWindowManager *wm)
{
if (wm->autosavetimer) {
diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c
index 9c020b16234..74ec2bcd41f 100644
--- a/source/blender/windowmanager/intern/wm_cursors.c
+++ b/source/blender/windowmanager/intern/wm_cursors.c
@@ -222,7 +222,6 @@ void WM_cursor_modal_restore(wmWindow *win)
win->lastcursor = 0;
}
-/* to allow usage all over, we do entire WM */
void WM_cursor_wait(bool val)
{
if (!G.background) {
@@ -240,9 +239,6 @@ void WM_cursor_wait(bool val)
}
}
-/**
- * \param bounds: can be NULL
- */
void WM_cursor_grab_enable(wmWindow *win, int wrap, bool hide, int bounds[4])
{
/* Only grab cursor when not running debug.
@@ -307,9 +303,10 @@ static void wm_cursor_warp_relative(wmWindow *win, int x, int y)
WM_cursor_warp(win, cx + x, cy + y);
}
-/* give it a modal keymap one day? */
bool wm_cursor_arrow_move(wmWindow *win, const wmEvent *event)
{
+ /* TODO: give it a modal keymap? Hard coded for now */
+
if (win && event->val == KM_PRESS) {
/* Must move at least this much to avoid rounding in WM_cursor_warp. */
float fac = GHOST_GetNativePixelSize(win->ghostwin);
@@ -334,7 +331,6 @@ bool wm_cursor_arrow_move(wmWindow *win, const wmEvent *event)
return 0;
}
-/* after this you can call restore too */
void WM_cursor_time(wmWindow *win, int nr)
{
/* 10 8x8 digits */
diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c
index bc87347b2f3..e1017c4236e 100644
--- a/source/blender/windowmanager/intern/wm_dragdrop.c
+++ b/source/blender/windowmanager/intern/wm_dragdrop.c
@@ -89,7 +89,6 @@ typedef struct wmDropBoxMap {
} wmDropBoxMap;
-/* spaceid/regionid is zero for window drop maps */
ListBase *WM_dropboxmap_find(const char *idname, int spaceid, int regionid)
{
LISTBASE_FOREACH (wmDropBoxMap *, dm, &dropboxes) {
@@ -153,7 +152,6 @@ void wm_dropbox_free(void)
/* *********************************** */
-/* note that the pointer should be valid allocated and not on stack */
wmDrag *WM_event_start_drag(
struct bContext *C, int icon, int type, void *poin, double value, unsigned int flags)
{
@@ -208,11 +206,6 @@ wmDrag *WM_event_start_drag(
return drag;
}
-/**
- * Additional work to cleanly end dragging. Additional because this doesn't actually remove the
- * drag items. Should be called whenever dragging is stopped (successful or not, also when
- * canceled).
- */
void wm_drags_exit(wmWindowManager *wm, wmWindow *win)
{
bool any_active = false;
@@ -403,7 +396,6 @@ void wm_drop_prepare(bContext *C, wmDrag *drag, wmDropBox *drop)
wm_drags_exit(CTX_wm_manager(C), CTX_wm_window(C));
}
-/* called in inner handler loop, region context */
void wm_drags_check_ops(bContext *C, const wmEvent *event)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -424,11 +416,6 @@ void wm_drags_check_ops(bContext *C, const wmEvent *event)
}
}
-/**
- * The operator of a dropbox should always be executed in the context determined by the mouse
- * coordinates. The dropbox poll should check the context area and region as needed.
- * So this always returns #WM_OP_INVOKE_DEFAULT.
- */
wmOperatorCallContext wm_drop_operator_context_get(const wmDropBox *UNUSED(drop))
{
return WM_OP_INVOKE_DEFAULT;
@@ -484,17 +471,11 @@ ID *WM_drag_get_local_ID_from_event(const wmEvent *event, short idcode)
return WM_drag_get_local_ID(lb->first, idcode);
}
-/**
- * Check if the drag data is either a local ID or an external ID asset of type \a idcode.
- */
bool WM_drag_is_ID_type(const wmDrag *drag, int idcode)
{
return WM_drag_get_local_ID(drag, idcode) || WM_drag_get_asset_data(drag, idcode);
}
-/**
- * \note: Does not store \a asset in any way, so it's fine to pass a temporary.
- */
wmDragAsset *WM_drag_create_asset_data(const AssetHandle *asset,
AssetMetaData *metadata,
const char *path,
@@ -542,9 +523,6 @@ struct AssetMetaData *WM_drag_get_asset_meta_data(const wmDrag *drag, int idcode
return NULL;
}
-/**
- * \param flag_extra: Additional linking flags (from #eFileSel_Params_Flag).
- */
ID *WM_drag_asset_id_import(wmDragAsset *asset_drag, const int flag_extra)
{
/* Only support passing in limited flags. */
@@ -603,15 +581,6 @@ bool WM_drag_asset_will_import_linked(const wmDrag *drag)
return asset_drag->import_type == FILE_ASSET_IMPORT_LINK;
}
-/**
- * When dragging a local ID, return that. Otherwise, if dragging an asset-handle, link or append
- * that depending on what was chosen by the drag-box (currently append only in fact).
- *
- * Use #WM_drag_free_imported_drag_ID() as cancel callback of the drop-box, so that the asset
- * import is rolled back if the drop operator fails.
- *
- * \param flag: #eFileSel_Params_Flag passed to linking code.
- */
ID *WM_drag_get_local_ID_or_import_from_asset(const wmDrag *drag, int idcode)
{
if (!ELEM(drag->type, WM_DRAG_ASSET, WM_DRAG_ID)) {
@@ -631,14 +600,6 @@ ID *WM_drag_get_local_ID_or_import_from_asset(const wmDrag *drag, int idcode)
return WM_drag_asset_id_import(asset_drag, 0);
}
-/**
- * \brief Free asset ID imported for canceled drop.
- *
- * If the asset was imported (linked/appended) using #WM_drag_get_local_ID_or_import_from_asset()`
- * (typically via a #wmDropBox.copy() callback), we want the ID to be removed again if the drop
- * operator cancels.
- * This is for use as #wmDropBox.cancel() callback.
- */
void WM_drag_free_imported_drag_ID(struct Main *bmain, wmDrag *drag, wmDropBox *drop)
{
if (drag->type != WM_DRAG_ASSET) {
@@ -673,9 +634,6 @@ wmDragAssetCatalog *WM_drag_get_asset_catalog_data(const wmDrag *drag)
return drag->poin;
}
-/**
- * \note: Does not store \a asset in any way, so it's fine to pass a temporary.
- */
void WM_drag_add_asset_list_item(
wmDrag *drag,
/* Context only needed for the hack in #ED_asset_handle_get_full_library_path(). */
@@ -912,7 +870,6 @@ void WM_drag_draw_default_fn(bContext *C, wmWindow *win, wmDrag *drag, const int
wm_drag_draw_default(C, win, drag, xy);
}
-/* Called in #wm_draw_window_onscreen. */
void wm_drags_draw(bContext *C, wmWindow *win)
{
int xy[2];
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index d8d57a9370c..ab9de6ce4d4 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -148,6 +148,7 @@ static void wm_region_draw_overlay(bContext *C, ScrArea *area, ARegion *region)
}
/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Internal Utilities
* \{ */
diff --git a/source/blender/windowmanager/intern/wm_event_query.c b/source/blender/windowmanager/intern/wm_event_query.c
index ef733837bf7..22cd68ddbd7 100644
--- a/source/blender/windowmanager/intern/wm_event_query.c
+++ b/source/blender/windowmanager/intern/wm_event_query.c
@@ -71,7 +71,6 @@ static void event_ids_from_type_and_value(const short type,
}
}
-/* for debugging only, getting inspecting events manually is tedious */
void WM_event_print(const wmEvent *event)
{
if (event) {
@@ -218,7 +217,6 @@ bool WM_event_type_mask_test(const int event_type, const enum eEventType_Mask ma
/** \name Event Motion Queries
* \{ */
-/* for modal callbacks, check configuration for how to interpret exit with tweaks. */
bool WM_event_is_modal_tweak_exit(const wmEvent *event, int tweak_event)
{
/* if the release-confirm userpref setting is enabled,
@@ -276,20 +274,6 @@ bool WM_event_is_mouse_drag_or_press(const wmEvent *event)
(ISMOUSE_BUTTON(event->type) && (event->val == KM_PRESS));
}
-/**
- * Detect motion between selection (callers should only use this for selection picking),
- * typically mouse press/click events.
- *
- * \param mval: Region relative coordinates, call with (-1, -1) resets the last cursor location.
- * \returns True when there was motion since last called.
- *
- * NOTE(@campbellbarton): The logic used here isn't foolproof.
- * It's possible that users move the cursor past #WM_EVENT_CURSOR_MOTION_THRESHOLD then back to
- * a position within the threshold (between mouse clicks).
- * In practice users never reported this since the threshold is very small (a few pixels).
- * To prevent the unlikely case of values matching from another region,
- * changing regions resets this value to (-1, -1).
- */
bool WM_cursor_test_motion_and_update(const int mval[2])
{
static int mval_prev[2] = {-1, -1};
@@ -360,11 +344,6 @@ int WM_userdef_event_map(int kmitype)
return kmitype;
}
-/**
- * Use so we can check if 'wmEvent.type' is released in modal operators.
- *
- * An alternative would be to add a 'wmEvent.type_nokeymap'... or similar.
- */
int WM_userdef_event_type_from_keymap_type(int kmitype)
{
switch (kmitype) {
@@ -447,7 +426,6 @@ bool WM_event_is_xr(const struct wmEvent *event)
/** \name Event Tablet Input Access
* \{ */
-/* applies the global tablet pressure correction curve */
float wm_pressure_curve(float pressure)
{
if (U.pressure_threshold_max != 0.0f) {
@@ -463,8 +441,6 @@ float wm_pressure_curve(float pressure)
return pressure;
}
-/* if this is a tablet event, return tablet pressure and set *pen_flip
- * to 1 if the eraser tool is being used, 0 otherwise */
float WM_event_tablet_data(const wmEvent *event, int *pen_flip, float tilt[2])
{
if (tilt) {
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index f51c8c48c48..1b6df9fb0db 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -64,6 +64,7 @@
#include "ED_asset.h"
#include "ED_fileselect.h"
#include "ED_info.h"
+#include "ED_render.h"
#include "ED_screen.h"
#include "ED_undo.h"
#include "ED_util.h"
@@ -83,6 +84,7 @@
#include "wm.h"
#include "wm_event_system.h"
#include "wm_event_types.h"
+#include "wm_surface.h"
#include "wm_window.h"
#include "DEG_depsgraph.h"
@@ -287,9 +289,6 @@ void WM_main_add_notifier(unsigned int type, void *reference)
note->reference = reference;
}
-/**
- * Clear notifiers by reference, Used so listeners don't act on freed data.
- */
void WM_main_remove_notifier_reference(const void *reference)
{
Main *bmain = G_MAIN;
@@ -384,13 +383,10 @@ void wm_event_do_depsgraph(bContext *C, bool is_after_open_file)
DEG_make_active(depsgraph);
BKE_scene_graph_update_tagged(depsgraph, bmain);
}
+
+ wm_surfaces_do_depsgraph(C);
}
-/**
- * Was part of #wm_event_do_notifiers,
- * split out so it can be called once before entering the #WM_main loop.
- * This ensures operators don't run before the UI and depsgraph are initialized.
- */
void wm_event_do_refresh_wm_and_depsgraph(bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -427,7 +423,6 @@ static void wm_event_execute_timers(bContext *C)
CTX_wm_window_set(C, NULL);
}
-/* Called in mainloop. */
void wm_event_do_notifiers(bContext *C)
{
/* Run the timer before assigning 'wm' in the unlikely case a timer loads a file, see T80028. */
@@ -457,6 +452,9 @@ void wm_event_do_notifiers(bContext *C)
else if (note->data == ND_DATACHANGED) {
wm_window_title(wm, win);
}
+ else if (note->data == ND_UNDO) {
+ ED_preview_restart_queue_work(C);
+ }
}
if (note->window == win) {
if (note->category == NC_SCREEN) {
@@ -752,9 +750,6 @@ static void wm_event_handler_ui_cancel(bContext *C)
* Access to #wmWindowManager.reports
* \{ */
-/**
- * Show the report in the info header.
- */
void WM_report_banner_show(void)
{
wmWindowManager *wm = G_MAIN->wm.first;
@@ -770,9 +765,6 @@ void WM_report_banner_show(void)
wm_reports->reporttimer->customdata = rti;
}
-/**
- * Hide all currently displayed banners and abort their timer.
- */
void WM_report_banners_cancel(Main *bmain)
{
wmWindowManager *wm = bmain->wm.first;
@@ -855,9 +847,9 @@ bool WM_operator_poll(bContext *C, wmOperatorType *ot)
return true;
}
-/* sets up the new context and calls 'wm_operator_invoke()' with poll_only */
bool WM_operator_poll_context(bContext *C, wmOperatorType *ot, short context)
{
+ /* Sets up the new context and calls #wm_operator_invoke() with poll_only. */
return wm_operator_call_internal(C, ot, NULL, NULL, context, true, NULL);
}
@@ -892,11 +884,6 @@ bool WM_operator_check_ui_empty(wmOperatorType *ot)
return true;
}
-/**
- * Sets the active region for this space from the context.
- *
- * \see #BKE_area_find_region_active_win
- */
void WM_operator_region_active_win_set(bContext *C)
{
ScrArea *area = CTX_wm_area(C);
@@ -1103,13 +1090,6 @@ static int wm_operator_exec_notest(bContext *C, wmOperator *op)
return retval;
}
-/**
- * For running operators with frozen context (modal handlers, menus).
- *
- * \param store: Store settings for re-use.
- *
- * \warning do not use this within an operator to call its self! T29537.
- */
int WM_operator_call_ex(bContext *C, wmOperator *op, const bool store)
{
return wm_operator_exec(C, op, false, store);
@@ -1120,19 +1100,11 @@ int WM_operator_call(bContext *C, wmOperator *op)
return WM_operator_call_ex(C, op, false);
}
-/**
- * This is intended to be used when an invoke operator wants to call exec on its self
- * and is basically like running op->type->exec() directly, no poll checks no freeing,
- * since we assume whoever called invoke will take care of that
- */
int WM_operator_call_notest(bContext *C, wmOperator *op)
{
return wm_operator_exec_notest(C, op);
}
-/**
- * Execute this operator again, put here so it can share above code
- */
int WM_operator_repeat(bContext *C, wmOperator *op)
{
const int op_flag = OP_IS_REPEAT;
@@ -1149,12 +1121,6 @@ int WM_operator_repeat_last(bContext *C, wmOperator *op)
op->flag &= ~op_flag;
return ret;
}
-/**
- * \return true if #WM_operator_repeat can run.
- * Simple check for now but may become more involved.
- * To be sure the operator can run call `WM_operator_poll(C, op->type)` also, since this call
- * checks if #WM_operator_repeat() can run at all, not that it WILL run at any time.
- */
bool WM_operator_repeat_check(const bContext *UNUSED(C), wmOperator *op)
{
if (op->type->exec != NULL) {
@@ -1592,7 +1558,6 @@ static int wm_operator_call_internal(bContext *C,
return 0;
}
-/* Invokes operator in context. */
int WM_operator_name_call_ptr(bContext *C,
wmOperatorType *ot,
wmOperatorCallContext context,
@@ -1614,6 +1579,16 @@ int WM_operator_name_call(bContext *C,
return 0;
}
+bool WM_operator_name_poll(bContext *C, const char *opstring)
+{
+ wmOperatorType *ot = WM_operatortype_find(opstring, 0);
+ if (!ot) {
+ return false;
+ }
+
+ return WM_operator_poll(C, ot);
+}
+
int WM_operator_name_call_with_properties(struct bContext *C,
const char *opstring,
wmOperatorCallContext context,
@@ -1625,9 +1600,6 @@ int WM_operator_name_call_with_properties(struct bContext *C,
return WM_operator_name_call_ptr(C, ot, context, &props_ptr);
}
-/**
- * Call an existent menu. The menu can be created in C or Python.
- */
void WM_menu_name_call(bContext *C, const char *menu_name, short context)
{
wmOperatorType *ot = WM_operatortype_find("WM_OT_call_menu", false);
@@ -1638,13 +1610,6 @@ void WM_menu_name_call(bContext *C, const char *menu_name, short context)
WM_operator_properties_free(&ptr);
}
-/**
- * Similar to #WM_operator_name_call called with #WM_OP_EXEC_DEFAULT context.
- *
- * - #wmOperatorType is used instead of operator name since python already has the operator type.
- * - `poll()` must be called by python before this runs.
- * - reports can be passed to this function (so python can report them as exceptions).
- */
int WM_operator_call_py(bContext *C,
wmOperatorType *ot,
wmOperatorCallContext context,
@@ -1849,9 +1814,9 @@ void WM_operator_name_call_ptr_with_depends_on_cursor(bContext *C,
* General API for different handler types.
* \{ */
-/* Future extra customadata free? */
void wm_event_free_handler(wmEventHandler *handler)
{
+ /* Future extra customa-data free? */
MEM_freeN(handler);
}
@@ -1923,7 +1888,6 @@ static void wm_handler_op_context(bContext *C, wmEventHandler_Op *handler, const
}
}
-/* Called on exit or remove area, only here call cancel callback. */
void WM_event_remove_handlers(bContext *C, ListBase *handlers)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -3525,8 +3489,6 @@ static void wm_event_handle_xrevent(bContext *C,
}
#endif /* WITH_XR_OPENXR */
-/* Called in main loop. */
-/* Goes over entire hierarchy: events -> window -> screen -> area -> region. */
void wm_event_do_handlers(bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -3836,12 +3798,6 @@ void WM_event_fileselect_event(wmWindowManager *wm, void *ophandle, int eventval
/* Operator is supposed to have a filled "path" property. */
/* Optional property: file-type (XXX enum?) */
-/**
- * The idea here is to keep a handler alive on window queue, owning the operator.
- * The file window can send event to make it execute, thus ensuring
- * executing happens outside of lower level queues, with UI refreshed.
- * Should also allow multiwin solutions.
- */
void WM_event_add_fileselect(bContext *C, wmOperator *op)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -3940,10 +3896,6 @@ wmEventHandler_Op *WM_event_add_modal_handler(bContext *C, wmOperator *op)
return handler;
}
-/**
- * Modal handlers store a pointer to an area which might be freed while the handler runs.
- * Use this function to NULL all handler pointers to \a old_area.
- */
void WM_event_modal_handler_area_replace(wmWindow *win, const ScrArea *old_area, ScrArea *new_area)
{
LISTBASE_FOREACH (wmEventHandler *, handler_base, &win->modalhandlers) {
@@ -3958,10 +3910,6 @@ void WM_event_modal_handler_area_replace(wmWindow *win, const ScrArea *old_area,
}
}
-/**
- * Modal handlers store a pointer to a region which might be freed while the handler runs.
- * Use this function to NULL all handler pointers to \a old_region.
- */
void WM_event_modal_handler_region_replace(wmWindow *win,
const ARegion *old_region,
ARegion *new_region)
@@ -4152,7 +4100,6 @@ struct wmEventHandler_Keymap *WM_event_add_keymap_handler_dynamic(
return handler;
}
-/* Priorities not implemented yet, for time being just insert in begin of list. */
wmEventHandler_Keymap *WM_event_add_keymap_handler_priority(ListBase *handlers,
wmKeyMap *keymap,
int UNUSED(priority))
@@ -4259,7 +4206,6 @@ wmEventHandler_UI *WM_event_add_ui_handler(const bContext *C,
return handler;
}
-/* Set "postpone" for win->modalhandlers, this is in a running for () loop in wm_handlers_do(). */
void WM_event_remove_ui_handler(ListBase *handlers,
wmUIHandlerFunc handle_fn,
wmUIHandlerRemoveFunc remove_fn,
@@ -4324,9 +4270,10 @@ wmEventHandler_Dropbox *WM_event_add_dropbox_handler(ListBase *handlers, ListBas
return handler;
}
-/* XXX(ton): solution works, still better check the real cause. */
void WM_event_remove_area_handler(ListBase *handlers, void *area)
{
+ /* XXX(ton): solution works, still better check the real cause. */
+
LISTBASE_FOREACH_MUTABLE (wmEventHandler *, handler_base, handlers) {
if (handler_base->type == WM_HANDLER_TYPE_UI) {
wmEventHandler_UI *handler = (wmEventHandler_UI *)handler_base;
@@ -4752,9 +4699,6 @@ static wmEvent *wm_event_add_trackpad(wmWindow *win, const wmEvent *event, int d
return event_new;
}
-/**
- * Windows store own event queues #wmWindow.event_queue (no #bContext here).
- */
void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void *customdata)
{
if (UNLIKELY(G.f & G_FLAG_EVENT_SIMULATE)) {
@@ -5372,10 +5316,6 @@ const char *WM_window_cursor_keymap_status_get(const wmWindow *win,
return NULL;
}
-/**
- * Similar to #BKE_screen_area_map_find_area_xy and related functions,
- * use here since the area is stored in the window manager.
- */
ScrArea *WM_window_status_area_find(wmWindow *win, bScreen *screen)
{
if (screen->state == SCREENFULL) {
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index a301b17227d..1d3fa158ac1 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -111,6 +111,7 @@
#include "ED_fileselect.h"
#include "ED_image.h"
#include "ED_outliner.h"
+#include "ED_render.h"
#include "ED_screen.h"
#include "ED_undo.h"
#include "ED_util.h"
@@ -170,9 +171,6 @@ void WM_file_tag_modified(void)
}
}
-/**
- * Check if there is data that would be lost when closing the current file without saving.
- */
bool wm_file_or_session_data_has_unsaved_changes(const Main *bmain, const wmWindowManager *wm)
{
return !wm->file_saved || ED_image_should_save_modified(bmain) ||
@@ -620,6 +618,8 @@ static void wm_file_read_pre(bContext *C, bool use_data, bool UNUSED(use_userdef
/* Always do this as both startup and preferences may have loaded in many font's
* at a different zoom level to the file being loaded. */
UI_view2d_zoom_cache_reset();
+
+ ED_preview_restart_queue_free();
}
/**
@@ -955,16 +955,6 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
/* #BKE_blendfile_read_result_setup sets new Main into context. */
Main *bmain = CTX_data_main(C);
- /* When recovering a session from an unsaved file, this can have a blank path. */
- if (BKE_main_blendfile_path(bmain)[0] != '\0') {
- G.save_over = 1;
- G.relbase_valid = 1;
- }
- else {
- G.save_over = 0;
- G.relbase_valid = 0;
- }
-
/* match the read WM with current WM */
wm_window_match_do(C, &wmbase, &bmain->wm, &bmain->wm);
WM_check(C); /* opens window(s), checks keymaps */
@@ -1032,12 +1022,6 @@ static struct {
bool override;
} wm_init_state_app_template = {{0}};
-/**
- * Used for setting app-template from the command line:
- * - non-empty string: overrides.
- * - empty string: override, using no app template.
- * - NULL: clears override.
- */
void WM_init_state_app_template_set(const char *app_template)
{
if (app_template) {
@@ -1061,16 +1045,6 @@ const char *WM_init_state_app_template_get(void)
/** \name Read Startup & Preferences Blend-File API
* \{ */
-/**
- * Called on startup, (context entirely filled with NULLs)
- * or called for 'New File' both `startup.blend` and `userpref.blend` are checked.
- *
- * \param r_params_file_read_post: Support postponed initialization,
- * needed for initial startup when only some sub-systems have been initialized.
- * When non-null, #wm_file_read_post doesn't run, instead it's arguments are stored
- * in this return argument.
- * The caller is responsible for calling #wm_homefile_read_post with this return argument.
- */
void wm_homefile_read_ex(bContext *C,
const struct wmHomeFileRead_Params *params_homefile,
ReportList *reports,
@@ -1167,8 +1141,6 @@ void wm_homefile_read_ex(bContext *C,
wm_file_read_pre(C, use_data, use_userdef);
if (use_data) {
- G.relbase_valid = 0;
-
/* put aside screens to match with persistent windows later */
wm_window_match_init(C, &wmbase);
}
@@ -1372,10 +1344,7 @@ void wm_homefile_read_ex(bContext *C,
if (use_data) {
WM_check(C); /* opens window(s), checks keymaps */
- bmain->name[0] = '\0';
-
- /* start with save preference untitled.blend */
- G.save_over = 0;
+ bmain->filepath[0] = '\0';
}
{
@@ -1406,10 +1375,6 @@ void wm_homefile_read(bContext *C,
wm_homefile_read_ex(C, params_homefile, reports, NULL);
}
-/**
- * Special case, support deferred execution of #wm_file_read_post,
- * Needed when loading for the first time to workaround order of initialization bug, see T89046.
- */
void wm_homefile_read_post(struct bContext *C,
const struct wmFileReadPost_Params *params_file_read_post)
{
@@ -1417,6 +1382,8 @@ void wm_homefile_read_post(struct bContext *C,
MEM_freeN((void *)params_file_read_post);
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Blend-File History API
* \{ */
@@ -1514,18 +1481,18 @@ static void wm_history_file_write(void)
static void wm_history_file_update(void)
{
RecentFile *recent;
- const char *blendfile_name = BKE_main_blendfile_path_from_global();
+ const char *blendfile_path = BKE_main_blendfile_path_from_global();
- /* no write history for recovered startup files */
- if (blendfile_name[0] == '\0') {
+ /* No write history for recovered startup files. */
+ if (blendfile_path[0] == '\0') {
return;
}
recent = G.recent_files.first;
/* refresh recent-files.txt of recent opened files, when current file was changed */
- if (!(recent) || (BLI_path_cmp(recent->filepath, blendfile_name) != 0)) {
+ if (!(recent) || (BLI_path_cmp(recent->filepath, blendfile_path) != 0)) {
- recent = wm_file_history_find(blendfile_name);
+ recent = wm_file_history_find(blendfile_path);
if (recent) {
BLI_remlink(&G.recent_files, recent);
}
@@ -1536,7 +1503,7 @@ static void wm_history_file_update(void)
recent_next = recent->next;
wm_history_file_free(recent);
}
- recent = wm_history_file_new(blendfile_name);
+ recent = wm_history_file_new(blendfile_path);
}
/* add current file to the beginning of list */
@@ -1546,7 +1513,7 @@ static void wm_history_file_update(void)
wm_history_file_write();
/* also update most recent files on System */
- GHOST_addToSystemRecentFiles(blendfile_name);
+ GHOST_addToSystemRecentFiles(blendfile_path);
}
}
@@ -1721,7 +1688,6 @@ static ImBuf *blend_file_thumb_from_camera(const bContext *C,
return ibuf;
}
-/* easy access from gdb */
bool write_crash_blend(void)
{
char path[FILE_MAX];
@@ -1817,8 +1783,9 @@ static bool wm_file_write(bContext *C,
if (file_preview_type == USER_FILE_PREVIEW_AUTO) {
Scene *scene = CTX_data_scene(C);
- bool do_render = (scene != NULL && scene->camera != NULL &&
- (BKE_screen_find_big_area(CTX_wm_screen(C), SPACE_VIEW3D, 0) != NULL));
+ bScreen *screen = CTX_wm_screen(C);
+ bool do_render = (scene != NULL && scene->camera != NULL && screen != NULL &&
+ (BKE_screen_find_big_area(screen, SPACE_VIEW3D, 0) != NULL));
file_preview_type = do_render ? USER_FILE_PREVIEW_CAMERA : USER_FILE_PREVIEW_SCREENSHOT;
}
@@ -1846,16 +1813,10 @@ static bool wm_file_write(bContext *C,
ED_editors_flush_edits(bmain);
- /* First time saving. */
- /* XXX(ton): temp solution to solve bug, real fix coming. */
- if ((BKE_main_blendfile_path(bmain)[0] == '\0') && (use_save_as_copy == false)) {
- BLI_strncpy(bmain->name, filepath, sizeof(bmain->name));
- }
-
/* XXX(ton): temp solution to solve bug, real fix coming. */
bmain->recovered = 0;
- if (BLO_write_file(CTX_data_main(C),
+ if (BLO_write_file(bmain,
filepath,
fileflags,
&(const struct BlendFileWriteParams){
@@ -1869,10 +1830,7 @@ static bool wm_file_write(bContext *C,
(CTX_wm_manager(C)->op_undo_depth == 0);
if (use_save_as_copy == false) {
- G.relbase_valid = 1;
- BLI_strncpy(bmain->name, filepath, sizeof(bmain->name)); /* is guaranteed current file */
-
- G.save_over = 1; /* disable untitled.blend convention */
+ STRNCPY(bmain->filepath, filepath); /* is guaranteed current file */
}
SET_FLAG_FROM_TEST(G.fileflags, fileflags & G_FILE_COMPRESS, G_FILE_COMPRESS);
@@ -1923,8 +1881,13 @@ static void wm_autosave_location(char *filepath)
const char *savedir;
#endif
- if (G_MAIN && G.relbase_valid) {
- const char *basename = BLI_path_basename(BKE_main_blendfile_path_from_global());
+ /* Normally there is no need to check for this to be NULL,
+ * however this runs on exit when it may be cleared. */
+ Main *bmain = G_MAIN;
+ const char *blendfile_path = bmain ? BKE_main_blendfile_path(bmain) : NULL;
+
+ if (blendfile_path && (blendfile_path[0] != '\0')) {
+ const char *basename = BLI_path_basename(blendfile_path);
int len = strlen(basename) - 6;
BLI_snprintf(path, sizeof(path), "%.*s_%d_autosave.blend", len, basename, pid);
}
@@ -2006,9 +1969,6 @@ void WM_autosave_init(wmWindowManager *wm)
wm_autosave_timer_begin(wm);
}
-/**
- * Run the auto-save timer action.
- */
void wm_autosave_timer(Main *bmain, wmWindowManager *wm, wmTimer *UNUSED(wt))
{
wm_autosave_timer_end(wm);
@@ -2137,7 +2097,7 @@ static int wm_homefile_write_exec(bContext *C, wmOperator *op)
fileflags,
&(const struct BlendFileWriteParams){
/* Make all paths absolute when saving the startup file.
- * On load the `G.relbase_valid` will be false so the paths
+ * On load the `G.main->filepath` will be empty so the paths
* won't have a base for resolving the relative paths. */
.remap_mode = BLO_WRITE_PATH_REMAP_ABSOLUTE,
/* Don't apply any path changes to the current blend file. */
@@ -2150,7 +2110,6 @@ static int wm_homefile_write_exec(bContext *C, wmOperator *op)
printf("ok\n");
BKE_report(op->reports, RPT_INFO, "Startup file saved");
- G.save_over = 0;
BKE_callback_exec_null(bmain, BKE_CB_EVT_SAVE_POST);
@@ -2637,7 +2596,7 @@ static int wm_open_mainfile__select_file_path(bContext *C, wmOperator *op)
set_next_operator_state(op, OPEN_MAINFILE_STATE_OPEN);
Main *bmain = CTX_data_main(C);
- const char *openname = BKE_main_blendfile_path(bmain);
+ const char *blendfile_path = BKE_main_blendfile_path(bmain);
if (CTX_wm_window(C) == NULL) {
/* in rare cases this could happen, when trying to invoke in background
@@ -2650,10 +2609,10 @@ static int wm_open_mainfile__select_file_path(bContext *C, wmOperator *op)
/* if possible, get the name of the most recently used .blend file */
if (G.recent_files.first) {
struct RecentFile *recent = G.recent_files.first;
- openname = recent->filepath;
+ blendfile_path = recent->filepath;
}
- RNA_string_set(op->ptr, "filepath", openname);
+ RNA_string_set(op->ptr, "filepath", blendfile_path);
wm_open_init_load_ui(op, true);
wm_open_init_use_scripts(op, true);
op->customdata = NULL;
@@ -2876,7 +2835,8 @@ static int wm_revert_mainfile_exec(bContext *C, wmOperator *op)
static bool wm_revert_mainfile_poll(bContext *UNUSED(C))
{
- return G.relbase_valid;
+ const char *blendfile_path = BKE_main_blendfile_path_from_global();
+ return (blendfile_path[0] != '\0');
}
void WM_OT_revert_mainfile(wmOperatorType *ot)
@@ -3033,9 +2993,9 @@ void WM_OT_recover_auto_save(wmOperatorType *ot)
* Both #WM_OT_save_as_mainfile & #WM_OT_save_mainfile.
* \{ */
-static void wm_filepath_default(char *filepath)
+static void wm_filepath_default(const Main *bmain, char *filepath)
{
- if (G.save_over == false) {
+ if (bmain->filepath[0] == '\0') {
BLI_path_filename_ensure(filepath, FILE_MAX, "untitled.blend");
}
}
@@ -3046,7 +3006,8 @@ static void save_set_compress(wmOperator *op)
prop = RNA_struct_find_property(op->ptr, "compress");
if (!RNA_property_is_set(op->ptr, prop)) {
- if (G.save_over) { /* keep flag for existing file */
+ const char *blendfile_path = BKE_main_blendfile_path_from_global();
+ if (blendfile_path[0] != '\0') { /* Keep flag for existing file. */
RNA_property_boolean_set(op->ptr, prop, (G.fileflags & G_FILE_COMPRESS) != 0);
}
else { /* use userdef for new file */
@@ -3059,21 +3020,22 @@ static void save_set_filepath(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
PropertyRNA *prop;
- char name[FILE_MAX];
+ char filepath[FILE_MAX];
prop = RNA_struct_find_property(op->ptr, "filepath");
if (!RNA_property_is_set(op->ptr, prop)) {
+ const char *blendfile_path = BKE_main_blendfile_path(bmain);
/* if not saved before, get the name of the most recently used .blend file */
- if (BKE_main_blendfile_path(bmain)[0] == '\0' && G.recent_files.first) {
+ if ((blendfile_path[0] == '\0') && G.recent_files.first) {
struct RecentFile *recent = G.recent_files.first;
- BLI_strncpy(name, recent->filepath, FILE_MAX);
+ STRNCPY(filepath, recent->filepath);
}
else {
- BLI_strncpy(name, bmain->name, FILE_MAX);
+ STRNCPY(filepath, blendfile_path);
}
- wm_filepath_default(name);
- RNA_property_string_set(op->ptr, prop, name);
+ wm_filepath_default(bmain, filepath);
+ RNA_property_string_set(op->ptr, prop, filepath);
}
}
@@ -3105,12 +3067,32 @@ static int wm_save_as_mainfile_exec(bContext *C, wmOperator *op)
BLO_WRITE_PATH_REMAP_NONE;
save_set_compress(op);
- if (RNA_struct_property_is_set(op->ptr, "filepath")) {
+ const bool is_filepath_set = RNA_struct_property_is_set(op->ptr, "filepath");
+ if (is_filepath_set) {
RNA_string_get(op->ptr, "filepath", path);
}
else {
- BLI_strncpy(path, BKE_main_blendfile_path(bmain), FILE_MAX);
- wm_filepath_default(path);
+ STRNCPY(path, BKE_main_blendfile_path(bmain));
+ }
+
+ if (path[0] == '\0') {
+ BKE_report(op->reports,
+ RPT_ERROR,
+ "Unable to save an unsaved file with an empty or unset \"filepath\" property");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* NOTE(@campbellbarton): only check this for file-path properties so saving an already
+ * saved file never fails with an error.
+ * Even though this should never happen, there may be some corner case where a malformed
+ * path is stored in `G.main->filepath`: when the file path is initialized from recovering
+ * a blend file - for example, so in this case failing to save isn't ideal. */
+ if (is_filepath_set && !BLI_path_is_abs_from_cwd(path)) {
+ BKE_reportf(op->reports,
+ RPT_ERROR,
+ "The \"filepath\" property was not an absolute path: \"%s\"",
+ path);
+ return OPERATOR_CANCELLED;
}
const int fileflags_orig = G.fileflags;
@@ -3227,14 +3209,15 @@ static int wm_save_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *U
/* if we're saving for the first time and prefer relative paths -
* any existing paths will be absolute,
* enable the option to remap paths to avoid confusion T37240. */
- if ((G.relbase_valid == false) && (U.flag & USER_RELPATHS)) {
+ const char *blendfile_path = BKE_main_blendfile_path_from_global();
+ if ((blendfile_path[0] == '\0') && (U.flag & USER_RELPATHS)) {
PropertyRNA *prop = RNA_struct_find_property(op->ptr, "relative_remap");
if (!RNA_property_is_set(op->ptr, prop)) {
RNA_property_boolean_set(op->ptr, prop, true);
}
}
- if (G.save_over) {
+ if (blendfile_path[0] != '\0') {
char path[FILE_MAX];
RNA_string_get(op->ptr, "filepath", path);
@@ -3336,6 +3319,7 @@ static uiBlock *block_create_autorun_warning(struct bContext *C,
struct ARegion *region,
void *UNUSED(arg1))
{
+ const char *blendfile_path = BKE_main_blendfile_path_from_global();
wmWindowManager *wm = CTX_wm_manager(C);
uiBlock *block = UI_block_begin(C, region, "autorun_warning_popup", UI_EMBOSS);
@@ -3383,7 +3367,7 @@ static uiBlock *block_create_autorun_warning(struct bContext *C,
/* Allow reload if we have a saved file.
* Otherwise just enable scripts and reset the depsgraphs. */
- if (G.relbase_valid && wm->file_saved) {
+ if ((blendfile_path[0] != '\0') && wm->file_saved) {
but = uiDefIconTextBut(block,
UI_BTYPE_BUT,
0,
@@ -3640,10 +3624,10 @@ static uiBlock *block_create__close_file_dialog(struct bContext *C,
uiItemL_ex(layout, TIP_("Save changes before closing?"), ICON_NONE, true, false);
/* Filename. */
- const char *blendfile_pathpath = BKE_main_blendfile_path(CTX_data_main(C));
+ const char *blendfile_path = BKE_main_blendfile_path(CTX_data_main(C));
char filename[FILE_MAX];
- if (blendfile_pathpath[0] != '\0') {
- BLI_split_file_part(blendfile_pathpath, filename, sizeof(filename));
+ if (blendfile_path[0] != '\0') {
+ BLI_split_file_part(blendfile_path, filename, sizeof(filename));
}
else {
STRNCPY(filename, "untitled.blend");
@@ -3810,10 +3794,6 @@ static void wm_free_operator_properties_callback(void *user_data)
IDP_FreeProperty(properties);
}
-/**
- * \return True if the dialog was created, the calling operator should return #OPERATOR_INTERFACE
- * then.
- */
bool wm_operator_close_file_dialog_if_needed(bContext *C,
wmOperator *op,
wmGenericCallbackFn post_action_fn)
diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c
index d373ecdac77..cf6ecd55757 100644
--- a/source/blender/windowmanager/intern/wm_files_link.c
+++ b/source/blender/windowmanager/intern/wm_files_link.c
@@ -52,9 +52,8 @@
#include "BLO_readfile.h"
-#include "BLT_translation.h"
-
#include "BKE_armature.h"
+#include "BKE_blendfile_link_append.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_key.h"
@@ -114,12 +113,13 @@ static bool wm_link_append_poll(bContext *C)
static int wm_link_append_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+ const char *blendfile_path = BKE_main_blendfile_path_from_global();
if (G.lib[0] != '\0') {
RNA_string_set(op->ptr, "filepath", G.lib);
}
- else if (G.relbase_valid) {
+ else if (blendfile_path[0] != '\0') {
char path[FILE_MAX];
- BLI_strncpy(path, BKE_main_blendfile_path_from_global(), sizeof(path));
+ STRNCPY(path, blendfile_path);
BLI_path_parent_dir(path);
RNA_string_set(op->ptr, "filepath", path);
}
@@ -168,841 +168,6 @@ static int wm_link_append_flag(wmOperator *op)
return flag;
}
-typedef struct WMLinkAppendDataItem {
- char *name;
- BLI_bitmap
- *libraries; /* All libs (from WMLinkAppendData.libraries) to try to load this ID from. */
- short idcode;
-
- /** Type of action to do to append this item, and other append-specific information. */
- char append_action;
- char append_tag;
-
- ID *new_id;
- Library *source_library;
- void *customdata;
-} WMLinkAppendDataItem;
-
-typedef struct WMLinkAppendData {
- LinkNodePair libraries;
- LinkNodePair items;
- int num_libraries;
- int num_items;
- /**
- * Combines #eFileSel_Params_Flag from DNA_space_types.h & #eBLOLibLinkFlags from BLO_readfile.h
- */
- int flag;
-
- /** Allows to easily find an existing items from an ID pointer. Used by append code. */
- GHash *new_id_to_item;
-
- /** Runtime info used by append code to manage re-use of already appended matching IDs. */
- GHash *library_weak_reference_mapping;
-
- /* Internal 'private' data */
- MemArena *memarena;
-} WMLinkAppendData;
-
-typedef struct WMLinkAppendDataCallBack {
- WMLinkAppendData *lapp_data;
- WMLinkAppendDataItem *item;
- ReportList *reports;
-
-} WMLinkAppendDataCallBack;
-
-enum {
- WM_APPEND_ACT_UNSET = 0,
- WM_APPEND_ACT_KEEP_LINKED,
- WM_APPEND_ACT_REUSE_LOCAL,
- WM_APPEND_ACT_MAKE_LOCAL,
- WM_APPEND_ACT_COPY_LOCAL,
-};
-
-enum {
- WM_APPEND_TAG_INDIRECT = 1 << 0,
-};
-
-static WMLinkAppendData *wm_link_append_data_new(const int flag)
-{
- MemArena *ma = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
- WMLinkAppendData *lapp_data = BLI_memarena_calloc(ma, sizeof(*lapp_data));
-
- lapp_data->flag = flag;
- lapp_data->memarena = ma;
-
- return lapp_data;
-}
-
-static void wm_link_append_data_free(WMLinkAppendData *lapp_data)
-{
- if (lapp_data->new_id_to_item != NULL) {
- BLI_ghash_free(lapp_data->new_id_to_item, NULL, NULL);
- }
-
- BLI_assert(lapp_data->library_weak_reference_mapping == NULL);
-
- BLI_memarena_free(lapp_data->memarena);
-}
-
-/* WARNING! *Never* call wm_link_append_data_library_add() after having added some items! */
-
-static void wm_link_append_data_library_add(WMLinkAppendData *lapp_data, const char *libname)
-{
- size_t len = strlen(libname) + 1;
- char *libpath = BLI_memarena_alloc(lapp_data->memarena, len);
-
- BLI_strncpy(libpath, libname, len);
- BLI_linklist_append_arena(&lapp_data->libraries, libpath, lapp_data->memarena);
- lapp_data->num_libraries++;
-}
-
-static WMLinkAppendDataItem *wm_link_append_data_item_add(WMLinkAppendData *lapp_data,
- const char *idname,
- const short idcode,
- void *customdata)
-{
- WMLinkAppendDataItem *item = BLI_memarena_calloc(lapp_data->memarena, sizeof(*item));
- size_t len = strlen(idname) + 1;
-
- item->name = BLI_memarena_alloc(lapp_data->memarena, len);
- BLI_strncpy(item->name, idname, len);
- item->idcode = idcode;
- item->libraries = BLI_BITMAP_NEW_MEMARENA(lapp_data->memarena, lapp_data->num_libraries);
-
- item->new_id = NULL;
- item->append_action = WM_APPEND_ACT_UNSET;
- item->customdata = customdata;
-
- BLI_linklist_append_arena(&lapp_data->items, item, lapp_data->memarena);
- lapp_data->num_items++;
-
- return item;
-}
-
-/* -------------------------------------------------------------------- */
-/** \name Library appending helper functions.
- *
- * FIXME: Deduplicate code with similar one in readfile.c
- * \{ */
-
-static bool object_in_any_scene(Main *bmain, Object *ob)
-{
- LISTBASE_FOREACH (Scene *, sce, &bmain->scenes) {
- if (BKE_scene_object_find(sce, ob)) {
- return true;
- }
- }
-
- return false;
-}
-
-static bool object_in_any_collection(Main *bmain, Object *ob)
-{
- LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
- if (BKE_collection_has_object(collection, ob)) {
- return true;
- }
- }
-
- LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
- if (scene->master_collection != NULL &&
- BKE_collection_has_object(scene->master_collection, ob)) {
- return true;
- }
- }
-
- return false;
-}
-
-static ID *wm_append_loose_data_instantiate_process_check(WMLinkAppendDataItem *item)
-{
- /* We consider that if we either kept it linked, or re-used already local data, instantiation
- * status of those should not be modified. */
- if (!ELEM(item->append_action, WM_APPEND_ACT_COPY_LOCAL, WM_APPEND_ACT_MAKE_LOCAL)) {
- return NULL;
- }
-
- ID *id = item->new_id;
- if (id == NULL) {
- return NULL;
- }
-
- if (item->append_action == WM_APPEND_ACT_COPY_LOCAL) {
- BLI_assert(ID_IS_LINKED(id));
- id = id->newid;
- if (id == NULL) {
- return NULL;
- }
-
- BLI_assert(!ID_IS_LINKED(id));
- return id;
- }
-
- BLI_assert(!ID_IS_LINKED(id));
- return id;
-}
-
-static void wm_append_loose_data_instantiate_ensure_active_collection(
- WMLinkAppendData *lapp_data,
- Main *bmain,
- Scene *scene,
- ViewLayer *view_layer,
- Collection **r_active_collection)
-{
- /* Find or add collection as needed. */
- if (*r_active_collection == NULL) {
- if (lapp_data->flag & FILE_ACTIVE_COLLECTION) {
- LayerCollection *lc = BKE_layer_collection_get_active(view_layer);
- *r_active_collection = lc->collection;
- }
- else {
- *r_active_collection = BKE_collection_add(
- bmain, scene->master_collection, DATA_("Appended Data"));
- }
- }
-}
-
-/* TODO: De-duplicate this code with the one in readfile.c, think we need some utils code for that
- * in BKE. */
-static void wm_append_loose_data_instantiate(WMLinkAppendData *lapp_data,
- Main *bmain,
- Scene *scene,
- ViewLayer *view_layer,
- const View3D *v3d)
-{
- if (scene == NULL) {
- /* In some cases, like the asset drag&drop e.g., the caller code manages instantiation itself.
- */
- return;
- }
-
- LinkNode *itemlink;
- Collection *active_collection = NULL;
- const bool do_obdata = (lapp_data->flag & BLO_LIBLINK_OBDATA_INSTANCE) != 0;
-
- /* Do NOT make base active here! screws up GUI stuff,
- * if you want it do it at the editor level. */
- const bool object_set_active = false;
-
- /* First pass on obdata to enable their instantiation by default, then do a second pass on
- * objects to clear it for any obdata already in use. */
- if (do_obdata) {
- for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) {
- WMLinkAppendDataItem *item = itemlink->link;
- ID *id = wm_append_loose_data_instantiate_process_check(item);
- if (id == NULL) {
- continue;
- }
- const ID_Type idcode = GS(id->name);
- if (!OB_DATA_SUPPORT_ID(idcode)) {
- continue;
- }
-
- id->tag |= LIB_TAG_DOIT;
- }
- for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) {
- WMLinkAppendDataItem *item = itemlink->link;
- ID *id = item->new_id;
- if (id == NULL || GS(id->name) != ID_OB) {
- continue;
- }
-
- Object *ob = (Object *)id;
- Object *new_ob = (Object *)id->newid;
- if (ob->data != NULL) {
- ((ID *)(ob->data))->tag &= ~LIB_TAG_DOIT;
- }
- if (new_ob != NULL && new_ob->data != NULL) {
- ((ID *)(new_ob->data))->tag &= ~LIB_TAG_DOIT;
- }
- }
- }
-
- /* First do collections, then objects, then obdata. */
-
- /* NOTE: For collections we only view_layer-instantiate duplicated collections that have
- * non-instantiated objects in them. */
- for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) {
- WMLinkAppendDataItem *item = itemlink->link;
- ID *id = wm_append_loose_data_instantiate_process_check(item);
- if (id == NULL || GS(id->name) != ID_GR) {
- continue;
- }
-
- /* We do not want to force instantiation of indirectly appended collections. Users can now
- * easily instantiate collections (and their objects) as needed by themselves. See T67032. */
- /* We need to check that objects in that collections are already instantiated in a scene.
- * Otherwise, it's better to add the collection to the scene's active collection, than to
- * instantiate its objects in active scene's collection directly. See T61141.
- *
- * NOTE: We only check object directly into that collection, not recursively into its
- * children.
- */
- Collection *collection = (Collection *)id;
- /* We always add collections directly selected by the user. */
- bool do_add_collection = (item->append_tag & WM_APPEND_TAG_INDIRECT) == 0;
- if (!do_add_collection) {
- LISTBASE_FOREACH (CollectionObject *, coll_ob, &collection->gobject) {
- Object *ob = coll_ob->ob;
- if (!object_in_any_scene(bmain, ob)) {
- do_add_collection = true;
- break;
- }
- }
- }
- if (do_add_collection) {
- wm_append_loose_data_instantiate_ensure_active_collection(
- lapp_data, bmain, scene, view_layer, &active_collection);
-
- /* In case user requested instantiation of collections as empties, we do so for the one they
- * explicitly selected (originally directly linked IDs). */
- if ((lapp_data->flag & BLO_LIBLINK_COLLECTION_INSTANCE) != 0 &&
- (item->append_tag & WM_APPEND_TAG_INDIRECT) == 0) {
- /* BKE_object_add(...) messes with the selection. */
- Object *ob = BKE_object_add_only_object(bmain, OB_EMPTY, collection->id.name + 2);
- ob->type = OB_EMPTY;
- ob->empty_drawsize = U.collection_instance_empty_size;
-
- const bool set_selected = (lapp_data->flag & FILE_AUTOSELECT) != 0;
- /* TODO: why is it OK to make this active here but not in other situations?
- * See other callers of #object_base_instance_init */
- const bool set_active = set_selected;
- BLO_object_instantiate_object_base_instance_init(
- bmain, active_collection, ob, view_layer, v3d, lapp_data->flag, set_active);
-
- /* Assign the collection. */
- ob->instance_collection = collection;
- id_us_plus(&collection->id);
- ob->transflag |= OB_DUPLICOLLECTION;
- copy_v3_v3(ob->loc, scene->cursor.location);
- }
- else {
- /* Add collection as child of active collection. */
- BKE_collection_child_add(bmain, active_collection, collection);
-
- if ((lapp_data->flag & FILE_AUTOSELECT) != 0) {
- LISTBASE_FOREACH (CollectionObject *, coll_ob, &collection->gobject) {
- Object *ob = coll_ob->ob;
- Base *base = BKE_view_layer_base_find(view_layer, ob);
- if (base) {
- base->flag |= BASE_SELECTED;
- BKE_scene_object_base_flag_sync_from_base(base);
- }
- }
- }
- }
- }
- }
-
- /* NOTE: For objects we only view_layer-instantiate duplicated objects that are not yet used
- * anywhere. */
- for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) {
- WMLinkAppendDataItem *item = itemlink->link;
- ID *id = wm_append_loose_data_instantiate_process_check(item);
- if (id == NULL || GS(id->name) != ID_OB) {
- continue;
- }
-
- Object *ob = (Object *)id;
-
- if (object_in_any_collection(bmain, ob)) {
- continue;
- }
-
- wm_append_loose_data_instantiate_ensure_active_collection(
- lapp_data, bmain, scene, view_layer, &active_collection);
-
- CLAMP_MIN(ob->id.us, 0);
- ob->mode = OB_MODE_OBJECT;
-
- BLO_object_instantiate_object_base_instance_init(
- bmain, active_collection, ob, view_layer, v3d, lapp_data->flag, object_set_active);
- }
-
- if (!do_obdata) {
- return;
- }
-
- for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) {
- WMLinkAppendDataItem *item = itemlink->link;
- ID *id = wm_append_loose_data_instantiate_process_check(item);
- if (id == NULL) {
- continue;
- }
- const ID_Type idcode = GS(id->name);
- if (!OB_DATA_SUPPORT_ID(idcode)) {
- continue;
- }
- if ((id->tag & LIB_TAG_DOIT) == 0) {
- continue;
- }
-
- wm_append_loose_data_instantiate_ensure_active_collection(
- lapp_data, bmain, scene, view_layer, &active_collection);
-
- const int type = BKE_object_obdata_to_type(id);
- BLI_assert(type != -1);
- Object *ob = BKE_object_add_only_object(bmain, type, id->name + 2);
- ob->data = id;
- id_us_plus(id);
- BKE_object_materials_test(bmain, ob, ob->data);
-
- BLO_object_instantiate_object_base_instance_init(
- bmain, active_collection, ob, view_layer, v3d, lapp_data->flag, object_set_active);
-
- copy_v3_v3(ob->loc, scene->cursor.location);
-
- id->tag &= ~LIB_TAG_DOIT;
- }
-
- /* Finally, add rigid body objects and constraints to current RB world(s). */
- for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) {
- WMLinkAppendDataItem *item = itemlink->link;
- ID *id = wm_append_loose_data_instantiate_process_check(item);
- if (id == NULL || GS(id->name) != ID_OB) {
- continue;
- }
- BKE_rigidbody_ensure_local_object(bmain, (Object *)id);
- }
-}
-
-/** \} */
-
-static int foreach_libblock_append_callback(LibraryIDLinkCallbackData *cb_data)
-{
- /* NOTE: It is important to also skip liboverride references here, as those should never be made
- * local. */
- if (cb_data->cb_flag & (IDWALK_CB_EMBEDDED | IDWALK_CB_INTERNAL | IDWALK_CB_LOOPBACK |
- IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE)) {
- return IDWALK_RET_NOP;
- }
-
- WMLinkAppendDataCallBack *data = cb_data->user_data;
- ID *id = *cb_data->id_pointer;
-
- if (id == NULL) {
- return IDWALK_RET_NOP;
- }
-
- if (!BKE_idtype_idcode_is_linkable(GS(id->name))) {
- /* While we do not want to add non-linkable ID (shape keys...) to the list of linked items,
- * unfortunately they can use fully linkable valid IDs too, like actions. Those need to be
- * processed, so we need to recursively deal with them here. */
- /* NOTE: Since we are by-passing checks in `BKE_library_foreach_ID_link` by manually calling it
- * recursively, we need to take care of potential recursion cases ourselves (e.g.animdata of
- * shapekey referencing the shapekey itself). */
- if (id != cb_data->id_self) {
- BKE_library_foreach_ID_link(
- cb_data->bmain, id, foreach_libblock_append_callback, data, IDWALK_NOP);
- }
- return IDWALK_RET_NOP;
- }
-
- const bool do_recursive = (data->lapp_data->flag & BLO_LIBLINK_APPEND_RECURSIVE) != 0;
- if (!do_recursive && cb_data->id_owner->lib != id->lib) {
- /* When `do_recursive` is false, we only make local IDs from same library(-ies) as the
- * initially directly linked ones. */
- return IDWALK_RET_NOP;
- }
-
- WMLinkAppendDataItem *item = BLI_ghash_lookup(data->lapp_data->new_id_to_item, id);
- if (item == NULL) {
- item = wm_link_append_data_item_add(data->lapp_data, id->name, GS(id->name), NULL);
- item->new_id = id;
- item->source_library = id->lib;
- /* Since we did not have an item for that ID yet, we know user did not selected it explicitly,
- * it was rather linked indirectly. This info is important for instantiation of collections. */
- item->append_tag |= WM_APPEND_TAG_INDIRECT;
- BLI_ghash_insert(data->lapp_data->new_id_to_item, id, item);
- }
-
- /* NOTE: currently there is no need to do anything else here, but in the future this would be
- * the place to add specific per-usage decisions on how to append an ID. */
-
- return IDWALK_RET_NOP;
-}
-
-/* Perform append operation, using modern ID usage looper to detect which ID should be kept linked,
- * made local, duplicated as local, re-used from local etc.
- *
- * TODO: Expose somehow this logic to the two other parts of code performing actual append
- * (i.e. copy/paste and `bpy` link/append API).
- * Then we can heavily simplify #BKE_library_make_local(). */
-static void wm_append_do(WMLinkAppendData *lapp_data,
- ReportList *reports,
- Main *bmain,
- Scene *scene,
- ViewLayer *view_layer,
- const View3D *v3d)
-{
- BLI_assert((lapp_data->flag & FILE_LINK) == 0);
-
- const bool set_fakeuser = (lapp_data->flag & BLO_LIBLINK_APPEND_SET_FAKEUSER) != 0;
- const bool do_reuse_local_id = (lapp_data->flag & BLO_LIBLINK_APPEND_LOCAL_ID_REUSE) != 0;
-
- const int make_local_common_flags = LIB_ID_MAKELOCAL_FULL_LIBRARY |
- ((lapp_data->flag & BLO_LIBLINK_APPEND_ASSET_DATA_CLEAR) !=
- 0 ?
- LIB_ID_MAKELOCAL_ASSET_DATA_CLEAR :
- 0);
-
- LinkNode *itemlink;
-
- /* Generate a mapping between newly linked IDs and their items, and tag linked IDs used as
- * liboverride references as already existing. */
- lapp_data->new_id_to_item = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
- for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) {
- WMLinkAppendDataItem *item = itemlink->link;
- ID *id = item->new_id;
- if (id == NULL) {
- continue;
- }
- BLI_ghash_insert(lapp_data->new_id_to_item, id, item);
-
- /* This ensures that if a liboverride reference is also linked/used by some other appended
- * data, it gets a local copy instead of being made directly local, so that the liboverride
- * references remain valid (i.e. linked data). */
- if (ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
- id->override_library->reference->tag |= LIB_TAG_PRE_EXISTING;
- }
- }
-
- lapp_data->library_weak_reference_mapping = BKE_main_library_weak_reference_create(bmain);
-
- /* NOTE: Since we append items for IDs not already listed (i.e. implicitly linked indirect
- * dependencies), this list will grow and we will process those IDs later, leading to a flatten
- * recursive processing of all the linked dependencies. */
- for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) {
- WMLinkAppendDataItem *item = itemlink->link;
- ID *id = item->new_id;
- if (id == NULL) {
- continue;
- }
- BLI_assert(item->customdata == NULL);
-
- /* In Append case linked IDs should never be marked as needing post-processing (instantiation
- * of loose objects etc.). */
- BLI_assert((id->tag & LIB_TAG_DOIT) == 0);
-
- ID *existing_local_id = BKE_idtype_idcode_append_is_reusable(GS(id->name)) ?
- BKE_main_library_weak_reference_search_item(
- lapp_data->library_weak_reference_mapping,
- id->lib->filepath,
- id->name) :
- NULL;
-
- if (item->append_action != WM_APPEND_ACT_UNSET) {
- /* Already set, pass. */
- }
- if (GS(id->name) == ID_OB && ((Object *)id)->proxy_from != NULL) {
- CLOG_INFO(&LOG, 3, "Appended ID '%s' is proxified, keeping it linked...", id->name);
- item->append_action = WM_APPEND_ACT_KEEP_LINKED;
- }
- else if (do_reuse_local_id && existing_local_id != NULL) {
- CLOG_INFO(&LOG, 3, "Appended ID '%s' as a matching local one, re-using it...", id->name);
- item->append_action = WM_APPEND_ACT_REUSE_LOCAL;
- item->customdata = existing_local_id;
- }
- else if (id->tag & LIB_TAG_PRE_EXISTING) {
- CLOG_INFO(&LOG, 3, "Appended ID '%s' was already linked, need to copy it...", id->name);
- item->append_action = WM_APPEND_ACT_COPY_LOCAL;
- }
- else {
- CLOG_INFO(&LOG, 3, "Appended ID '%s' will be made local...", id->name);
- item->append_action = WM_APPEND_ACT_MAKE_LOCAL;
- }
-
- /* Only check dependencies if we are not keeping linked data, nor re-using existing local data.
- */
- if (!ELEM(item->append_action, WM_APPEND_ACT_KEEP_LINKED, WM_APPEND_ACT_REUSE_LOCAL)) {
- WMLinkAppendDataCallBack cb_data = {
- .lapp_data = lapp_data, .item = item, .reports = reports};
- BKE_library_foreach_ID_link(
- bmain, id, foreach_libblock_append_callback, &cb_data, IDWALK_NOP);
- }
-
- /* If we found a matching existing local id but are not re-using it, we need to properly clear
- * its weak reference to linked data. */
- if (existing_local_id != NULL &&
- !ELEM(item->append_action, WM_APPEND_ACT_KEEP_LINKED, WM_APPEND_ACT_REUSE_LOCAL)) {
- BKE_main_library_weak_reference_remove_item(lapp_data->library_weak_reference_mapping,
- id->lib->filepath,
- id->name,
- existing_local_id);
- }
- }
-
- /* Effectively perform required operation on every linked ID. */
- for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) {
- WMLinkAppendDataItem *item = itemlink->link;
- ID *id = item->new_id;
- if (id == NULL) {
- continue;
- }
-
- ID *local_appended_new_id = NULL;
- char lib_filepath[FILE_MAX];
- BLI_strncpy(lib_filepath, id->lib->filepath, sizeof(lib_filepath));
- char lib_id_name[MAX_ID_NAME];
- BLI_strncpy(lib_id_name, id->name, sizeof(lib_id_name));
-
- switch (item->append_action) {
- case WM_APPEND_ACT_COPY_LOCAL:
- BKE_lib_id_make_local(bmain, id, make_local_common_flags | LIB_ID_MAKELOCAL_FORCE_COPY);
- local_appended_new_id = id->newid;
- break;
- case WM_APPEND_ACT_MAKE_LOCAL:
- BKE_lib_id_make_local(bmain,
- id,
- make_local_common_flags | LIB_ID_MAKELOCAL_FORCE_LOCAL |
- LIB_ID_MAKELOCAL_OBJECT_NO_PROXY_CLEARING);
- BLI_assert(id->newid == NULL);
- local_appended_new_id = id;
- break;
- case WM_APPEND_ACT_KEEP_LINKED:
- /* Nothing to do here. */
- break;
- case WM_APPEND_ACT_REUSE_LOCAL:
- /* We only need to set `newid` to ID found in previous loop, for proper remapping. */
- ID_NEW_SET(id, item->customdata);
- /* This is not a 'new' local appended id, do not set `local_appended_new_id` here. */
- break;
- case WM_APPEND_ACT_UNSET:
- CLOG_ERROR(
- &LOG, "Unexpected unset append action for '%s' ID, assuming 'keep link'", id->name);
- break;
- default:
- BLI_assert(0);
- }
-
- if (local_appended_new_id != NULL) {
- if (BKE_idtype_idcode_append_is_reusable(GS(local_appended_new_id->name))) {
- BKE_main_library_weak_reference_add_item(lapp_data->library_weak_reference_mapping,
- lib_filepath,
- lib_id_name,
- local_appended_new_id);
- }
-
- if (set_fakeuser) {
- if (!ELEM(GS(local_appended_new_id->name), ID_OB, ID_GR)) {
- /* Do not set fake user on objects nor collections (instancing). */
- id_fake_user_set(local_appended_new_id);
- }
- }
- }
- }
-
- BKE_main_library_weak_reference_destroy(lapp_data->library_weak_reference_mapping);
- lapp_data->library_weak_reference_mapping = NULL;
-
- /* Remap IDs as needed. */
- for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) {
- WMLinkAppendDataItem *item = itemlink->link;
-
- if (item->append_action == WM_APPEND_ACT_KEEP_LINKED) {
- continue;
- }
-
- ID *id = item->new_id;
- if (id == NULL) {
- continue;
- }
- if (ELEM(item->append_action, WM_APPEND_ACT_COPY_LOCAL, WM_APPEND_ACT_REUSE_LOCAL)) {
- BLI_assert(ID_IS_LINKED(id));
- id = id->newid;
- if (id == NULL) {
- continue;
- }
- }
-
- BLI_assert(!ID_IS_LINKED(id));
-
- BKE_libblock_relink_to_newid(bmain, id, 0);
- }
-
- /* Remove linked IDs when a local existing data has been reused instead. */
- BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
- for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) {
- WMLinkAppendDataItem *item = itemlink->link;
-
- if (item->append_action != WM_APPEND_ACT_REUSE_LOCAL) {
- continue;
- }
-
- ID *id = item->new_id;
- if (id == NULL) {
- continue;
- }
- BLI_assert(ID_IS_LINKED(id));
- BLI_assert(id->newid != NULL);
-
- id->tag |= LIB_TAG_DOIT;
- item->new_id = id->newid;
- }
- BKE_id_multi_tagged_delete(bmain);
-
- /* Instantiate newly created (duplicated) IDs as needed. */
- wm_append_loose_data_instantiate(lapp_data, bmain, scene, view_layer, v3d);
-
- /* Attempt to deal with object proxies.
- *
- * NOTE: Copied from `BKE_library_make_local`, but this is not really working (as in, not
- * producing any useful result in any known use case), neither here nor in
- * `BKE_library_make_local` currently.
- * Proxies are end of life anyway, so not worth spending time on this. */
- for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) {
- WMLinkAppendDataItem *item = itemlink->link;
-
- if (item->append_action != WM_APPEND_ACT_COPY_LOCAL) {
- continue;
- }
-
- ID *id = item->new_id;
- if (id == NULL) {
- continue;
- }
- BLI_assert(ID_IS_LINKED(id));
-
- /* Attempt to re-link copied proxy objects. This allows appending of an entire scene
- * from another blend file into this one, even when that blend file contains proxified
- * armatures that have local references. Since the proxified object needs to be linked
- * (not local), this will only work when the "Localize all" checkbox is disabled.
- * TL;DR: this is a dirty hack on top of an already weak feature (proxies). */
- if (GS(id->name) == ID_OB && ((Object *)id)->proxy != NULL) {
- Object *ob = (Object *)id;
- Object *ob_new = (Object *)id->newid;
- bool is_local = false, is_lib = false;
-
- /* Proxies only work when the proxified object is linked-in from a library. */
- if (!ID_IS_LINKED(ob->proxy)) {
- CLOG_WARN(&LOG,
- "Proxy object %s will lose its link to %s, because the "
- "proxified object is local",
- id->newid->name,
- ob->proxy->id.name);
- continue;
- }
-
- BKE_library_ID_test_usages(bmain, id, &is_local, &is_lib);
-
- /* We can only switch the proxy'ing to a made-local proxy if it is no longer
- * referred to from a library. Not checking for local use; if new local proxy
- * was not used locally would be a nasty bug! */
- if (is_local || is_lib) {
- CLOG_WARN(&LOG,
- "Made-local proxy object %s will lose its link to %s, "
- "because the linked-in proxy is referenced (is_local=%i, is_lib=%i)",
- id->newid->name,
- ob->proxy->id.name,
- is_local,
- is_lib);
- }
- else {
- /* we can switch the proxy'ing from the linked-in to the made-local proxy.
- * BKE_object_make_proxy() shouldn't be used here, as it allocates memory that
- * was already allocated by object_make_local() (which called BKE_object_copy). */
- ob_new->proxy = ob->proxy;
- ob_new->proxy_group = ob->proxy_group;
- ob_new->proxy_from = ob->proxy_from;
- ob_new->proxy->proxy_from = ob_new;
- ob->proxy = ob->proxy_from = ob->proxy_group = NULL;
- }
- }
- }
-
- BKE_main_id_newptr_and_tag_clear(bmain);
-}
-
-static void wm_link_do(WMLinkAppendData *lapp_data,
- ReportList *reports,
- Main *bmain,
- Scene *scene,
- ViewLayer *view_layer,
- const View3D *v3d)
-{
- Main *mainl;
- BlendHandle *bh;
- Library *lib;
-
- const int flag = lapp_data->flag;
- const int id_tag_extra = 0;
-
- LinkNode *liblink, *itemlink;
- int lib_idx, item_idx;
-
- BLI_assert(lapp_data->num_items && lapp_data->num_libraries);
-
- for (lib_idx = 0, liblink = lapp_data->libraries.list; liblink;
- lib_idx++, liblink = liblink->next) {
- char *libname = liblink->link;
- BlendFileReadReport bf_reports = {.reports = reports};
-
- if (STREQ(libname, BLO_EMBEDDED_STARTUP_BLEND)) {
- bh = BLO_blendhandle_from_memory(
- datatoc_startup_blend, datatoc_startup_blend_size, &bf_reports);
- }
- else {
- bh = BLO_blendhandle_from_file(libname, &bf_reports);
- }
-
- if (bh == NULL) {
- /* Unlikely since we just browsed it, but possible
- * Error reports will have been made by BLO_blendhandle_from_file() */
- continue;
- }
-
- /* here appending/linking starts */
- struct LibraryLink_Params liblink_params;
- BLO_library_link_params_init_with_context(
- &liblink_params, bmain, flag, id_tag_extra, scene, view_layer, v3d);
- /* In case of append, do not handle instantiation in linking process, but during append phase
- * (see #wm_append_loose_data_instantiate ). */
- if ((flag & FILE_LINK) == 0) {
- liblink_params.flag &= ~BLO_LIBLINK_NEEDS_ID_TAG_DOIT;
- }
-
- mainl = BLO_library_link_begin(&bh, libname, &liblink_params);
- lib = mainl->curlib;
- BLI_assert(lib);
- UNUSED_VARS_NDEBUG(lib);
-
- if (mainl->versionfile < 250) {
- BKE_reportf(reports,
- RPT_WARNING,
- "Linking or appending from a very old .blend file format (%d.%d), no animation "
- "conversion will "
- "be done! You may want to re-save your lib file with current Blender",
- mainl->versionfile,
- mainl->subversionfile);
- }
-
- /* For each lib file, we try to link all items belonging to that lib,
- * and tag those successful to not try to load them again with the other libs. */
- for (item_idx = 0, itemlink = lapp_data->items.list; itemlink;
- item_idx++, itemlink = itemlink->next) {
- WMLinkAppendDataItem *item = itemlink->link;
- ID *new_id;
-
- if (!BLI_BITMAP_TEST(item->libraries, lib_idx)) {
- continue;
- }
-
- new_id = BLO_library_link_named_part(mainl, &bh, item->idcode, item->name, &liblink_params);
-
- if (new_id) {
- /* If the link is successful, clear item's libs 'todo' flags.
- * This avoids trying to link same item with other libraries to come. */
- BLI_bitmap_set_all(item->libraries, false, lapp_data->num_libraries);
- item->new_id = new_id;
- item->source_library = new_id->lib;
- }
- }
-
- BLO_library_link_end(mainl, &bh, &liblink_params);
- BLO_blendhandle_close(bh);
- }
-}
-
/**
* Check if an item defined by \a name and \a group can be appended/linked.
*
@@ -1053,7 +218,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
PropertyRNA *prop;
- WMLinkAppendData *lapp_data;
+ BlendfileLinkAppendContext *lapp_context;
char path[FILE_MAX_LIBEXTRA], root[FILE_MAXDIR], libname[FILE_MAX_LIBEXTRA], relname[FILE_MAX];
char *group, *name;
int totfiles = 0;
@@ -1120,7 +285,14 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
/* We define our working data...
* Note that here, each item 'uses' one library, and only one. */
- lapp_data = wm_link_append_data_new(flag);
+ LibraryLink_Params lapp_params;
+ BLO_library_link_params_init_with_context(
+ &lapp_params, bmain, flag, 0, scene, view_layer, CTX_wm_view3d(C));
+
+ lapp_context = BKE_blendfile_link_append_context_new(&lapp_params);
+ BKE_blendfile_link_append_context_embedded_blendfile_set(
+ lapp_context, datatoc_startup_blend, datatoc_startup_blend_size);
+
if (totfiles != 0) {
GHash *libraries = BLI_ghash_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, __func__);
int lib_idx = 0;
@@ -1138,7 +310,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
if (!BLI_ghash_haskey(libraries, libname)) {
BLI_ghash_insert(libraries, BLI_strdup(libname), POINTER_FROM_INT(lib_idx));
lib_idx++;
- wm_link_append_data_library_add(lapp_data, libname);
+ BKE_blendfile_link_append_context_library_add(lapp_context, libname, NULL);
}
}
}
@@ -1150,7 +322,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
BLI_join_dirfile(path, sizeof(path), root, relname);
if (BLO_library_path_explode(path, libname, &group, &name)) {
- WMLinkAppendDataItem *item;
+ BlendfileLinkAppendContextItem *item;
if (!wm_link_append_item_poll(op->reports, path, group, name, do_append)) {
continue;
@@ -1158,9 +330,9 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
lib_idx = POINTER_AS_INT(BLI_ghash_lookup(libraries, libname));
- item = wm_link_append_data_item_add(
- lapp_data, name, BKE_idtype_idcode_from_name(group), NULL);
- BLI_BITMAP_ENABLE(item->libraries, lib_idx);
+ item = BKE_blendfile_link_append_context_item_add(
+ lapp_context, name, BKE_idtype_idcode_from_name(group), NULL);
+ BKE_blendfile_link_append_context_item_library_index_enable(lapp_context, item, lib_idx);
}
}
RNA_END;
@@ -1168,16 +340,17 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
BLI_ghash_free(libraries, MEM_freeN, NULL);
}
else {
- WMLinkAppendDataItem *item;
+ BlendfileLinkAppendContextItem *item;
- wm_link_append_data_library_add(lapp_data, libname);
- item = wm_link_append_data_item_add(lapp_data, name, BKE_idtype_idcode_from_name(group), NULL);
- BLI_BITMAP_ENABLE(item->libraries, 0);
+ BKE_blendfile_link_append_context_library_add(lapp_context, libname, NULL);
+ item = BKE_blendfile_link_append_context_item_add(
+ lapp_context, name, BKE_idtype_idcode_from_name(group), NULL);
+ BKE_blendfile_link_append_context_item_library_index_enable(lapp_context, item, 0);
}
- if (lapp_data->num_items == 0) {
+ if (BKE_blendfile_link_append_context_is_empty(lapp_context)) {
/* Early out in case there is nothing to link. */
- wm_link_append_data_free(lapp_data);
+ BKE_blendfile_link_append_context_free(lapp_context);
/* Clear pre existing tag. */
BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
return OPERATOR_CANCELLED;
@@ -1186,7 +359,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
/* XXX We'd need re-entrant locking on Main for this to work... */
// BKE_main_lock(bmain);
- wm_link_do(lapp_data, op->reports, bmain, scene, view_layer, CTX_wm_view3d(C));
+ BKE_blendfile_link(lapp_context, op->reports);
// BKE_main_unlock(bmain);
@@ -1196,10 +369,10 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
/* append, rather than linking */
if (do_append) {
- wm_append_do(lapp_data, op->reports, bmain, scene, view_layer, CTX_wm_view3d(C));
+ BKE_blendfile_append(lapp_context, op->reports);
}
- wm_link_append_data_free(lapp_data);
+ BKE_blendfile_link_append_context_free(lapp_context);
/* important we unset, otherwise these object won't
* link into other scenes from this blend file */
@@ -1351,33 +524,35 @@ static ID *wm_file_link_append_datablock_ex(Main *bmain,
BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
/* Define working data, with just the one item we want to link. */
- WMLinkAppendData *lapp_data = wm_link_append_data_new(flag);
+ LibraryLink_Params lapp_params;
+ BLO_library_link_params_init_with_context(&lapp_params, bmain, flag, 0, scene, view_layer, v3d);
+
+ BlendfileLinkAppendContext *lapp_context = BKE_blendfile_link_append_context_new(&lapp_params);
+ BKE_blendfile_link_append_context_embedded_blendfile_set(
+ lapp_context, datatoc_startup_blend, datatoc_startup_blend_size);
- wm_link_append_data_library_add(lapp_data, filepath);
- WMLinkAppendDataItem *item = wm_link_append_data_item_add(lapp_data, id_name, id_code, NULL);
- BLI_BITMAP_ENABLE(item->libraries, 0);
+ BKE_blendfile_link_append_context_library_add(lapp_context, filepath, NULL);
+ BlendfileLinkAppendContextItem *item = BKE_blendfile_link_append_context_item_add(
+ lapp_context, id_name, id_code, NULL);
+ BKE_blendfile_link_append_context_item_library_index_enable(lapp_context, item, 0);
/* Link datablock. */
- wm_link_do(lapp_data, NULL, bmain, scene, view_layer, v3d);
+ BKE_blendfile_link(lapp_context, NULL);
if (do_append) {
- wm_append_do(lapp_data, NULL, bmain, scene, view_layer, v3d);
+ BKE_blendfile_append(lapp_context, NULL);
}
/* Get linked datablock and free working data. */
- ID *id = item->new_id;
+ ID *id = BKE_blendfile_link_append_context_item_newid_get(lapp_context, item);
- wm_link_append_data_free(lapp_data);
+ BKE_blendfile_link_append_context_free(lapp_context);
BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
return id;
}
-/*
- * NOTE: `scene` (and related `view_layer` and `v3d`) pointers may be NULL, in which case no
- * instantiation of linked objects, collections etc. will be performed.
- */
ID *WM_file_link_datablock(Main *bmain,
Scene *scene,
ViewLayer *view_layer,
@@ -1392,10 +567,6 @@ ID *WM_file_link_datablock(Main *bmain,
bmain, scene, view_layer, v3d, filepath, id_code, id_name, flag);
}
-/*
- * NOTE: `scene` (and related `view_layer` and `v3d`) pointers may be NULL, in which case no
- * instantiation of appended objects, collections etc. will be performed.
- */
ID *WM_file_append_datablock(Main *bmain,
Scene *scene,
ViewLayer *view_layer,
@@ -1444,291 +615,6 @@ static int wm_lib_relocate_invoke(bContext *C, wmOperator *op, const wmEvent *UN
return OPERATOR_CANCELLED;
}
-static void lib_relocate_do_remap(Main *bmain,
- ID *old_id,
- ID *new_id,
- ReportList *reports,
- const bool do_reload,
- const short remap_flags)
-{
- BLI_assert(old_id);
- if (do_reload) {
- /* Since we asked for placeholders in case of missing IDs,
- * we expect to always get a valid one. */
- BLI_assert(new_id);
- }
- if (new_id) {
- CLOG_INFO(&LOG,
- 4,
- "Before remap of %s, old_id users: %d, new_id users: %d",
- old_id->name,
- old_id->us,
- new_id->us);
- BKE_libblock_remap_locked(bmain, old_id, new_id, remap_flags);
-
- if (old_id->flag & LIB_FAKEUSER) {
- id_fake_user_clear(old_id);
- id_fake_user_set(new_id);
- }
-
- CLOG_INFO(&LOG,
- 4,
- "After remap of %s, old_id users: %d, new_id users: %d",
- old_id->name,
- old_id->us,
- new_id->us);
-
- /* In some cases, new_id might become direct link, remove parent of library in this case. */
- if (new_id->lib->parent && (new_id->tag & LIB_TAG_INDIRECT) == 0) {
- if (do_reload) {
- BLI_assert_unreachable(); /* Should not happen in 'pure' reload case... */
- }
- new_id->lib->parent = NULL;
- }
- }
-
- if (old_id->us > 0 && new_id && old_id->lib == new_id->lib) {
- /* Note that this *should* not happen - but better be safe than sorry in this area,
- * at least until we are 100% sure this cannot ever happen.
- * Also, we can safely assume names were unique so far,
- * so just replacing '.' by '~' should work,
- * but this does not totally rules out the possibility of name collision. */
- size_t len = strlen(old_id->name);
- size_t dot_pos;
- bool has_num = false;
-
- for (dot_pos = len; dot_pos--;) {
- char c = old_id->name[dot_pos];
- if (c == '.') {
- break;
- }
- if (c < '0' || c > '9') {
- has_num = false;
- break;
- }
- has_num = true;
- }
-
- if (has_num) {
- old_id->name[dot_pos] = '~';
- }
- else {
- len = MIN2(len, MAX_ID_NAME - 7);
- BLI_strncpy(&old_id->name[len], "~000", 7);
- }
-
- id_sort_by_name(which_libbase(bmain, GS(old_id->name)), old_id, NULL);
-
- BKE_reportf(
- reports,
- RPT_WARNING,
- "Lib Reload: Replacing all references to old data-block '%s' by reloaded one failed, "
- "old one (%d remaining users) had to be kept and was renamed to '%s'",
- new_id->name,
- old_id->us,
- old_id->name);
- }
-}
-
-static void lib_relocate_do(bContext *C,
- Library *library,
- WMLinkAppendData *lapp_data,
- ReportList *reports,
- const bool do_reload)
-{
- ListBase *lbarray[INDEX_ID_MAX];
- int lba_idx;
-
- LinkNode *itemlink;
- int item_idx;
-
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
-
- /* Remove all IDs to be reloaded from Main. */
- lba_idx = set_listbasepointers(bmain, lbarray);
- while (lba_idx--) {
- ID *id = lbarray[lba_idx]->first;
- const short idcode = id ? GS(id->name) : 0;
-
- if (!id || !BKE_idtype_idcode_is_linkable(idcode)) {
- /* No need to reload non-linkable datatypes,
- * those will get relinked with their 'users ID'. */
- continue;
- }
-
- for (; id; id = id->next) {
- if (id->lib == library) {
- WMLinkAppendDataItem *item;
-
- /* We remove it from current Main, and add it to items to link... */
- /* Note that non-linkable IDs (like e.g. shapekeys) are also explicitly linked here... */
- BLI_remlink(lbarray[lba_idx], id);
- /* Usual special code for ShapeKeys snowflakes... */
- Key *old_key = BKE_key_from_id(id);
- if (old_key != NULL) {
- BLI_remlink(which_libbase(bmain, GS(old_key->id.name)), &old_key->id);
- }
-
- item = wm_link_append_data_item_add(lapp_data, id->name + 2, idcode, id);
- BLI_bitmap_set_all(item->libraries, true, lapp_data->num_libraries);
-
- CLOG_INFO(&LOG, 4, "Datablock to seek for: %s", id->name);
- }
- }
- }
-
- if (lapp_data->num_items == 0) {
- /* Early out in case there is nothing to do. */
- return;
- }
-
- BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
-
- /* We do not want any instantiation here! */
- wm_link_do(lapp_data, reports, bmain, NULL, NULL, NULL);
-
- BKE_main_lock(bmain);
-
- /* We add back old id to bmain.
- * We need to do this in a first, separated loop, otherwise some of those may not be handled by
- * ID remapping, which means they would still reference old data to be deleted... */
- for (item_idx = 0, itemlink = lapp_data->items.list; itemlink;
- item_idx++, itemlink = itemlink->next) {
- WMLinkAppendDataItem *item = itemlink->link;
- ID *old_id = item->customdata;
-
- BLI_assert(old_id);
- BLI_addtail(which_libbase(bmain, GS(old_id->name)), old_id);
-
- /* Usual special code for ShapeKeys snowflakes... */
- Key *old_key = BKE_key_from_id(old_id);
- if (old_key != NULL) {
- BLI_addtail(which_libbase(bmain, GS(old_key->id.name)), &old_key->id);
- }
- }
-
- /* Since our (old) reloaded IDs were removed from main, the user count done for them in linking
- * code is wrong, we need to redo it here after adding them back to main. */
- BKE_main_id_refcount_recompute(bmain, false);
-
- /* Note that in reload case, we also want to replace indirect usages. */
- const short remap_flags = ID_REMAP_SKIP_NEVER_NULL_USAGE |
- ID_REMAP_NO_INDIRECT_PROXY_DATA_USAGE |
- (do_reload ? 0 : ID_REMAP_SKIP_INDIRECT_USAGE);
- for (item_idx = 0, itemlink = lapp_data->items.list; itemlink;
- item_idx++, itemlink = itemlink->next) {
- WMLinkAppendDataItem *item = itemlink->link;
- ID *old_id = item->customdata;
- ID *new_id = item->new_id;
-
- lib_relocate_do_remap(bmain, old_id, new_id, reports, do_reload, remap_flags);
- if (new_id == NULL) {
- continue;
- }
- /* Usual special code for ShapeKeys snowflakes... */
- Key **old_key_p = BKE_key_from_id_p(old_id);
- if (old_key_p == NULL) {
- continue;
- }
- Key *old_key = *old_key_p;
- Key *new_key = BKE_key_from_id(new_id);
- if (old_key != NULL) {
- *old_key_p = NULL;
- id_us_min(&old_key->id);
- lib_relocate_do_remap(bmain, &old_key->id, &new_key->id, reports, do_reload, remap_flags);
- *old_key_p = old_key;
- id_us_plus_no_lib(&old_key->id);
- }
- }
-
- BKE_main_unlock(bmain);
-
- for (item_idx = 0, itemlink = lapp_data->items.list; itemlink;
- item_idx++, itemlink = itemlink->next) {
- WMLinkAppendDataItem *item = itemlink->link;
- ID *old_id = item->customdata;
-
- if (old_id->us == 0) {
- BKE_id_free(bmain, old_id);
- }
- }
-
- /* Some datablocks can get reloaded/replaced 'silently' because they are not linkable
- * (shape keys e.g.), so we need another loop here to clear old ones if possible. */
- lba_idx = set_listbasepointers(bmain, lbarray);
- while (lba_idx--) {
- ID *id, *id_next;
- for (id = lbarray[lba_idx]->first; id; id = id_next) {
- id_next = id->next;
- /* XXX That check may be a bit to generic/permissive? */
- if (id->lib && (id->flag & LIB_TAG_PRE_EXISTING) && id->us == 0) {
- BKE_id_free(bmain, id);
- }
- }
- }
-
- /* Get rid of no more used libraries... */
- BKE_main_id_tag_idcode(bmain, ID_LI, LIB_TAG_DOIT, true);
- lba_idx = set_listbasepointers(bmain, lbarray);
- while (lba_idx--) {
- ID *id;
- for (id = lbarray[lba_idx]->first; id; id = id->next) {
- if (id->lib) {
- id->lib->id.tag &= ~LIB_TAG_DOIT;
- }
- }
- }
- Library *lib, *lib_next;
- for (lib = which_libbase(bmain, ID_LI)->first; lib; lib = lib_next) {
- lib_next = lib->id.next;
- if (lib->id.tag & LIB_TAG_DOIT) {
- id_us_clear_real(&lib->id);
- if (lib->id.us == 0) {
- BKE_id_free(bmain, (ID *)lib);
- }
- }
- }
-
- /* Update overrides of reloaded linked data-blocks. */
- ID *id;
- FOREACH_MAIN_ID_BEGIN (bmain, id) {
- if (ID_IS_LINKED(id) || !ID_IS_OVERRIDE_LIBRARY_REAL(id) ||
- (id->tag & LIB_TAG_PRE_EXISTING) == 0) {
- continue;
- }
- if ((id->override_library->reference->tag & LIB_TAG_PRE_EXISTING) == 0) {
- BKE_lib_override_library_update(bmain, id);
- }
- }
- FOREACH_MAIN_ID_END;
-
- /* Resync overrides if needed. */
- if (!USER_EXPERIMENTAL_TEST(&U, no_override_auto_resync)) {
- BKE_lib_override_library_main_resync(bmain,
- scene,
- view_layer,
- &(struct BlendFileReadReport){
- .reports = reports,
- });
- /* We need to rebuild some of the deleted override rules (for UI feedback purpose). */
- BKE_lib_override_library_main_operations_create(bmain, true);
- }
-
- BKE_main_collection_sync(bmain);
-
- BKE_main_lib_objects_recalc_all(bmain);
- IMB_colormanagement_check_file_config(bmain);
-
- /* important we unset, otherwise these object won't
- * link into other scenes from this blend file */
- BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
-
- /* recreate dependency graph to include new objects */
- DEG_relations_tag_update(bmain);
-}
-
void WM_lib_reload(Library *lib, bContext *C, ReportList *reports)
{
if (!BLO_has_bfile_extension(lib->filepath_abs)) {
@@ -1745,14 +631,34 @@ void WM_lib_reload(Library *lib, bContext *C, ReportList *reports)
return;
}
- WMLinkAppendData *lapp_data = wm_link_append_data_new(BLO_LIBLINK_USE_PLACEHOLDERS |
- BLO_LIBLINK_FORCE_INDIRECT);
+ Main *bmain = CTX_data_main(C);
+ LibraryLink_Params lapp_params;
+ BLO_library_link_params_init_with_context(&lapp_params,
+ bmain,
+ BLO_LIBLINK_USE_PLACEHOLDERS |
+ BLO_LIBLINK_FORCE_INDIRECT,
+ 0,
+ CTX_data_scene(C),
+ CTX_data_view_layer(C),
+ NULL);
- wm_link_append_data_library_add(lapp_data, lib->filepath_abs);
+ BlendfileLinkAppendContext *lapp_context = BKE_blendfile_link_append_context_new(&lapp_params);
+
+ BKE_blendfile_link_append_context_library_add(lapp_context, lib->filepath_abs, NULL);
+
+ BKE_blendfile_library_relocate(lapp_context, reports, lib, true);
+
+ BKE_blendfile_link_append_context_free(lapp_context);
+
+ BKE_main_lib_objects_recalc_all(bmain);
+ IMB_colormanagement_check_file_config(bmain);
- lib_relocate_do(C, lib, lapp_data, reports, true);
+ /* Important we unset, otherwise these object won't link into other scenes from this blend file.
+ */
+ BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
- wm_link_append_data_free(lapp_data);
+ /* Recreate dependency graph to include new IDs. */
+ DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_WINDOW, NULL);
}
@@ -1768,7 +674,7 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload)
if (lib) {
Main *bmain = CTX_data_main(C);
PropertyRNA *prop;
- WMLinkAppendData *lapp_data;
+ BlendfileLinkAppendContext *lapp_context;
char path[FILE_MAX], root[FILE_MAXDIR], libname[FILE_MAX], relname[FILE_MAX];
short flag = 0;
@@ -1813,13 +719,17 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload)
return OPERATOR_CANCELLED;
}
+ LibraryLink_Params lapp_params;
+ BLO_library_link_params_init_with_context(
+ &lapp_params, bmain, flag, 0, CTX_data_scene(C), CTX_data_view_layer(C), NULL);
+
if (BLI_path_cmp(lib->filepath_abs, path) == 0) {
CLOG_INFO(&LOG, 4, "We are supposed to reload '%s' lib (%d)", lib->filepath, lib->id.us);
do_reload = true;
- lapp_data = wm_link_append_data_new(flag);
- wm_link_append_data_library_add(lapp_data, path);
+ lapp_context = BKE_blendfile_link_append_context_new(&lapp_params);
+ BKE_blendfile_link_append_context_library_add(lapp_context, path, NULL);
}
else {
int totfiles = 0;
@@ -1839,7 +749,7 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload)
}
}
- lapp_data = wm_link_append_data_new(flag);
+ lapp_context = BKE_blendfile_link_append_context_new(&lapp_params);
if (totfiles) {
RNA_BEGIN (op->ptr, itemptr, "files") {
@@ -1852,27 +762,39 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload)
}
CLOG_INFO(&LOG, 4, "\tCandidate new lib to reload datablocks from: %s", path);
- wm_link_append_data_library_add(lapp_data, path);
+ BKE_blendfile_link_append_context_library_add(lapp_context, path, NULL);
}
RNA_END;
}
else {
CLOG_INFO(&LOG, 4, "\tCandidate new lib to reload datablocks from: %s", path);
- wm_link_append_data_library_add(lapp_data, path);
+ BKE_blendfile_link_append_context_library_add(lapp_context, path, NULL);
}
}
if (do_reload) {
- lapp_data->flag |= BLO_LIBLINK_USE_PLACEHOLDERS | BLO_LIBLINK_FORCE_INDIRECT;
+ BKE_blendfile_link_append_context_flag_set(
+ lapp_context, BLO_LIBLINK_USE_PLACEHOLDERS | BLO_LIBLINK_FORCE_INDIRECT, true);
}
- lib_relocate_do(C, lib, lapp_data, op->reports, do_reload);
+ BKE_blendfile_library_relocate(lapp_context, op->reports, lib, do_reload);
- wm_link_append_data_free(lapp_data);
+ BKE_blendfile_link_append_context_free(lapp_context);
/* XXX TODO: align G.lib with other directory storage (like last opened image etc...) */
BLI_strncpy(G.lib, root, FILE_MAX);
+ BKE_main_lib_objects_recalc_all(bmain);
+ IMB_colormanagement_check_file_config(bmain);
+
+ /* Important we unset, otherwise these object won't link into other scenes from this blend
+ * file.
+ */
+ BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
+
+ /* Recreate dependency graph to include new IDs. */
+ DEG_relations_tag_update(bmain);
+
WM_event_add_notifier(C, NC_WINDOW, NULL);
return OPERATOR_FINISHED;
diff --git a/source/blender/windowmanager/intern/wm_gesture.c b/source/blender/windowmanager/intern/wm_gesture.c
index ab971901a20..47f51214a8e 100644
--- a/source/blender/windowmanager/intern/wm_gesture.c
+++ b/source/blender/windowmanager/intern/wm_gesture.c
@@ -50,7 +50,6 @@
#include "BIF_glutil.h"
-/* context checked on having screen, window and area */
wmGesture *WM_gesture_new(wmWindow *window, const ARegion *region, const wmEvent *event, int type)
{
wmGesture *gesture = MEM_callocN(sizeof(wmGesture), "new gesture");
@@ -129,7 +128,6 @@ bool WM_gesture_is_modal_first(const wmGesture *gesture)
return (gesture->is_active_prev == false);
}
-/* tweak and line gestures */
int wm_gesture_evaluate(wmGesture *gesture, const wmEvent *event)
{
if (gesture->type == WM_GESTURE_TWEAK) {
@@ -515,7 +513,6 @@ static void wm_gesture_draw_cross(wmWindow *win, wmGesture *gt)
immUnbindProgram();
}
-/* called in wm_draw.c */
void wm_gesture_draw(wmWindow *win)
{
wmGesture *gt = (wmGesture *)win->gesture.first;
diff --git a/source/blender/windowmanager/intern/wm_gesture_ops.c b/source/blender/windowmanager/intern/wm_gesture_ops.c
index 19b678d79d8..8d45d5aed67 100644
--- a/source/blender/windowmanager/intern/wm_gesture_ops.c
+++ b/source/blender/windowmanager/intern/wm_gesture_ops.c
@@ -124,6 +124,7 @@ static int UNUSED_FUNCTION(gesture_modal_state_from_operator)(wmOperator *op)
}
return GESTURE_MODAL_NOP;
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -569,7 +570,6 @@ static void gesture_tweak_modal(bContext *C, const wmEvent *event)
}
}
-/* standard tweak, called after window handlers passed on event */
void wm_tweakevent_test(bContext *C, const wmEvent *event, int action)
{
wmWindow *win = CTX_wm_window(C);
@@ -750,11 +750,6 @@ void WM_gesture_lines_cancel(bContext *C, wmOperator *op)
gesture_modal_end(C, op);
}
-/**
- * helper function, we may want to add options for conversion to view space
- *
- * caller must free.
- */
const int (*WM_gesture_lasso_path_to_array(bContext *UNUSED(C),
wmOperator *op,
int *r_mcoords_len))[2]
@@ -889,10 +884,6 @@ int WM_gesture_straightline_invoke(bContext *C, wmOperator *op, const wmEvent *e
return OPERATOR_RUNNING_MODAL;
}
-/**
- * This invoke callback starts the straightline gesture with a viewport preview to the right side
- * of the line.
- */
int WM_gesture_straightline_active_side_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
WM_gesture_straightline_invoke(C, op, event);
@@ -928,11 +919,6 @@ static void wm_gesture_straightline_do_angle_snap(rcti *rect)
rect->ymax = (int)line_snapped_end[1];
}
-/**
- * This modal callback calls exec once per mouse move event while the gesture is active with the
- * updated line start and end values, so it can be used for tools that have a real time preview
- * (like a gradient updating in real time over the mesh).
- */
int WM_gesture_straightline_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
wmGesture *gesture = op->customdata;
@@ -1012,13 +998,6 @@ int WM_gesture_straightline_modal(bContext *C, wmOperator *op, const wmEvent *ev
return OPERATOR_RUNNING_MODAL;
}
-/**
- * This modal one-shot callback only calls exec once after the gesture finishes without any updates
- * during the gesture execution. Should be used for operations that are intended to be applied once
- * without real time preview (like a trimming tool that only applies the bisect operation once
- * after finishing the gesture as the bisect operation is too heavy to be computed in real time for
- * a preview).
- */
int WM_gesture_straightline_oneshot_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
wmGesture *gesture = op->customdata;
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index c382af03c4a..2f87e5789fe 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -223,10 +223,6 @@ static void sound_jack_sync_callback(Main *bmain, int mode, double time)
}
}
-/**
- * Initialize Blender and load the startup file & preferences
- * (only called once).
- */
void WM_init(bContext *C, int argc, const char **argv)
{
@@ -318,9 +314,9 @@ void WM_init(bContext *C, int argc, const char **argv)
NULL,
&params_file_read_post);
- /* NOTE: leave `G_MAIN->name` set to an empty string since this
+ /* NOTE: leave `G_MAIN->filepath` set to an empty string since this
* matches behavior after loading a new file. */
- BLI_assert(G_MAIN->name[0] == '\0');
+ BLI_assert(G_MAIN->filepath[0] == '\0');
/* Call again to set from preferences. */
BLT_lang_set(NULL);
@@ -432,10 +428,6 @@ static int wm_exit_handler(bContext *C, const wmEvent *event, void *userdata)
return WM_UI_HANDLER_BREAK;
}
-/**
- * Cause a delayed #WM_exit()
- * call to avoid leaking memory when trying to exit from within operators.
- */
void wm_exit_schedule_delayed(const bContext *C)
{
/* What we do here is a little bit hacky, but quite simple and doesn't require bigger
@@ -449,9 +441,6 @@ void wm_exit_schedule_delayed(const bContext *C)
WM_event_add_mousemove(win); /* ensure handler actually gets called */
}
-/**
- * \note doesn't run exit() call #WM_exit() for that.
- */
void WM_exit_ex(bContext *C, const bool do_python)
{
wmWindowManager *wm = C ? CTX_wm_manager(C) : NULL;
@@ -547,6 +536,7 @@ void WM_exit_ex(bContext *C, const bool do_python)
RE_engines_exit();
ED_preview_free_dbase(); /* frees a Main dbase, before BKE_blender_free! */
+ ED_preview_restart_queue_free();
ED_assetlist_storage_exit();
if (wm) {
@@ -655,11 +645,6 @@ void WM_exit_ex(bContext *C, const bool do_python)
BKE_tempdir_session_purge();
}
-/**
- * \brief Main exit function to close Blender ordinarily.
- * \note Use #wm_exit_schedule_delayed() to close Blender from an operator.
- * Might leak memory otherwise.
- */
void WM_exit(bContext *C)
{
WM_exit_ex(C, true);
@@ -677,10 +662,6 @@ void WM_exit(bContext *C)
exit(G.is_break == true);
}
-/**
- * Needed for cases when operators are re-registered
- * (when operator type pointers are stored).
- */
void WM_script_tag_reload(void)
{
UI_interface_tag_script_reload();
diff --git a/source/blender/windowmanager/intern/wm_jobs.c b/source/blender/windowmanager/intern/wm_jobs.c
index 2604105896d..66277ec57f4 100644
--- a/source/blender/windowmanager/intern/wm_jobs.c
+++ b/source/blender/windowmanager/intern/wm_jobs.c
@@ -187,12 +187,6 @@ static wmJob *wm_job_find(const wmWindowManager *wm, const void *owner, const in
/* ******************* public API ***************** */
-/**
- * \return current job or adds new job, but doesn't run it.
- *
- * \note every owner only gets a single job,
- * adding a new one will stop running job and when stopped it starts the new one.
- */
wmJob *WM_jobs_get(wmWindowManager *wm,
wmWindow *win,
const void *owner,
@@ -223,7 +217,6 @@ wmJob *WM_jobs_get(wmWindowManager *wm,
return wm_job;
}
-/* returns true if job runs, for UI (progress) indicators */
bool WM_jobs_test(const wmWindowManager *wm, const void *owner, int job_type)
{
/* job can be running or about to run (suspended) */
@@ -281,7 +274,6 @@ static void wm_jobs_update_progress_bars(wmWindowManager *wm)
}
}
-/* time that job started */
double WM_jobs_starttime(const wmWindowManager *wm, const void *owner)
{
const wmJob *wm_job = wm_job_find(wm, owner, WM_JOB_TYPE_ANY);
@@ -447,10 +439,6 @@ static void wm_jobs_test_suspend_stop(wmWindowManager *wm, wmJob *test)
#endif
}
-/**
- * if job running, the same owner gave it a new job.
- * if different owner starts existing startjob, it suspends itself
- */
void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
{
if (wm_job->running) {
@@ -550,7 +538,6 @@ static void wm_jobs_kill_job(wmWindowManager *wm, wmJob *wm_job)
}
}
-/* wait until every job ended */
void WM_jobs_kill_all(wmWindowManager *wm)
{
wmJob *wm_job;
@@ -563,7 +550,6 @@ void WM_jobs_kill_all(wmWindowManager *wm)
SEQ_prefetch_stop_all();
}
-/* wait until every job ended, except for one owner (used in undo to keep screen job alive) */
void WM_jobs_kill_all_except(wmWindowManager *wm, const void *owner)
{
LISTBASE_FOREACH_MUTABLE (wmJob *, wm_job, &wm->jobs) {
@@ -584,7 +570,6 @@ void WM_jobs_kill_type(struct wmWindowManager *wm, const void *owner, int job_ty
}
}
-/* signal job(s) from this owner or callback to stop, timer is required to get handled */
void WM_jobs_stop(wmWindowManager *wm, const void *owner, void *startjob)
{
LISTBASE_FOREACH (wmJob *, wm_job, &wm->jobs) {
@@ -596,7 +581,6 @@ void WM_jobs_stop(wmWindowManager *wm, const void *owner, void *startjob)
}
}
-/* actually terminate thread and job timer */
void WM_jobs_kill(wmWindowManager *wm,
void *owner,
void (*startjob)(void *, short int *, short int *, float *))
@@ -608,7 +592,6 @@ void WM_jobs_kill(wmWindowManager *wm,
}
}
-/* kill job entirely, also removes timer itself */
void wm_jobs_timer_end(wmWindowManager *wm, wmTimer *wt)
{
LISTBASE_FOREACH (wmJob *, wm_job, &wm->jobs) {
@@ -619,7 +602,6 @@ void wm_jobs_timer_end(wmWindowManager *wm, wmTimer *wt)
}
}
-/* hardcoded to event TIMERJOBS */
void wm_jobs_timer(wmWindowManager *wm, wmTimer *wt)
{
LISTBASE_FOREACH_MUTABLE (wmJob *, wm_job, &wm->jobs) {
diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c
index 35f6ce40dba..0214fce59b2 100644
--- a/source/blender/windowmanager/intern/wm_keymap.c
+++ b/source/blender/windowmanager/intern/wm_keymap.c
@@ -189,7 +189,6 @@ static bool wm_keymap_item_equals(wmKeyMapItem *a, wmKeyMapItem *b)
(a->flag & KMI_REPEAT_IGNORE) == (b->flag & KMI_REPEAT_IGNORE)));
}
-/* properties can be NULL, otherwise the arg passed is used and ownership is given to the kmi */
void WM_keymap_item_properties_reset(wmKeyMapItem *kmi, struct IDProperty *properties)
{
if (LIKELY(kmi->ptr)) {
@@ -514,7 +513,6 @@ static void keymap_item_set_id(wmKeyMap *keymap, wmKeyMapItem *kmi)
}
}
-/* always add item */
wmKeyMapItem *WM_keymap_add_item(
wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier)
{
@@ -1150,7 +1148,6 @@ const char *WM_key_event_string(const short type, const bool compact)
return CTX_IFACE_(BLT_I18NCONTEXT_UI_EVENTS, it->name);
}
-/* TODO: also support (some) value, like e.g. double-click? */
int WM_keymap_item_raw_to_string(const short shift,
const short ctrl,
const short alt,
@@ -1162,6 +1159,8 @@ int WM_keymap_item_raw_to_string(const short shift,
char *result,
const int result_len)
{
+ /* TODO: also support (some) value, like e.g. double-click? */
+
#define ADD_SEP \
if (p != buf) { \
*p++ = ' '; \
@@ -1307,6 +1306,10 @@ char *WM_modalkeymap_operator_items_to_string_buf(wmOperatorType *ot,
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Keymap Finding Utilities
+ * \{ */
+
static wmKeyMapItem *wm_keymap_item_find_in_keymap(wmKeyMap *keymap,
const char *opname,
IDProperty *properties,
@@ -1676,10 +1679,6 @@ static bool kmi_filter_is_visible_type_mask(const wmKeyMap *km,
kmi_filter_is_visible(km, kmi, user_data));
}
-/**
- * \param include_mask, exclude_mask:
- * Event types to include/exclude when looking up keys (#eEventType_Mask).
- */
wmKeyMapItem *WM_key_event_operator(const bContext *C,
const char *opname,
wmOperatorCallContext opcontext,
diff --git a/source/blender/windowmanager/intern/wm_keymap_utils.c b/source/blender/windowmanager/intern/wm_keymap_utils.c
index 795f78e215f..d424eef8262 100644
--- a/source/blender/windowmanager/intern/wm_keymap_utils.c
+++ b/source/blender/windowmanager/intern/wm_keymap_utils.c
@@ -43,7 +43,6 @@
/** \name Wrappers for #WM_keymap_add_item
* \{ */
-/* menu wrapper for WM_keymap_add_item */
wmKeyMapItem *WM_keymap_add_menu(
wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier)
{
@@ -73,7 +72,6 @@ wmKeyMapItem *WM_keymap_add_panel(
return kmi;
}
-/* tool wrapper for WM_keymap_add_item */
wmKeyMapItem *WM_keymap_add_tool(
wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier)
{
@@ -83,7 +81,6 @@ wmKeyMapItem *WM_keymap_add_tool(
return kmi;
}
-/** Useful for mapping numbers to an enum. */
void WM_keymap_add_context_enum_set_items(wmKeyMap *keymap,
const EnumPropertyItem *items,
const char *data_path,
@@ -203,8 +200,6 @@ wmKeyMap *WM_keymap_guess_from_context(const bContext *C)
return km;
}
-/* Guess an appropriate keymap from the operator name */
-/* Needs to be kept up to date with Keymap and Operator naming */
wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname)
{
/* Op types purposely skipped for now:
diff --git a/source/blender/windowmanager/intern/wm_menu_type.c b/source/blender/windowmanager/intern/wm_menu_type.c
index bcaa2243f9f..799b6fc2e52 100644
--- a/source/blender/windowmanager/intern/wm_menu_type.c
+++ b/source/blender/windowmanager/intern/wm_menu_type.c
@@ -77,7 +77,6 @@ void WM_menutype_freelink(MenuType *mt)
UNUSED_VARS_NDEBUG(ok);
}
-/* called on initialize WM_init() */
void WM_menutype_init(void)
{
/* reserve size is set based on blender default setup */
diff --git a/source/blender/windowmanager/intern/wm_operator_props.c b/source/blender/windowmanager/intern/wm_operator_props.c
index 898671706d1..a5887fc07b3 100644
--- a/source/blender/windowmanager/intern/wm_operator_props.c
+++ b/source/blender/windowmanager/intern/wm_operator_props.c
@@ -72,7 +72,6 @@ static const EnumPropertyItem *wm_operator_properties_filesel_sort_items_itemf(
return items;
}
-/* default properties for fileselect */
void WM_operator_properties_filesel(wmOperatorType *ot,
int filter,
short type,
@@ -262,9 +261,6 @@ void WM_operator_properties_select_action(wmOperatorType *ot, int default_action
wm_operator_properties_select_action_ex(ot, default_action, select_actions, hide_gui);
}
-/**
- * only SELECT/DESELECT
- */
void WM_operator_properties_select_action_simple(wmOperatorType *ot,
int default_action,
bool hide_gui)
@@ -278,10 +274,6 @@ void WM_operator_properties_select_action_simple(wmOperatorType *ot,
wm_operator_properties_select_action_ex(ot, default_action, select_actions, hide_gui);
}
-/**
- * Use for all select random operators.
- * Adds properties: percent, seed, action.
- */
void WM_operator_properties_select_random(wmOperatorType *ot)
{
RNA_def_float_factor(ot->srna,
@@ -357,9 +349,6 @@ void WM_operator_properties_border_to_rctf(struct wmOperator *op, rctf *rect)
BLI_rctf_rcti_copy(rect, &rect_i);
}
-/**
- * Use with #WM_gesture_box_invoke
- */
void WM_operator_properties_gesture_box_ex(wmOperatorType *ot, bool deselect, bool extend)
{
PropertyRNA *prop;
@@ -381,10 +370,6 @@ void WM_operator_properties_gesture_box_ex(wmOperatorType *ot, bool deselect, bo
}
}
-/**
- * Disable using cursor position,
- * use when view operators are initialized from buttons.
- */
void WM_operator_properties_use_cursor_init(wmOperatorType *ot)
{
PropertyRNA *prop = RNA_def_boolean(ot->srna,
@@ -418,7 +403,6 @@ void WM_operator_properties_select_operation(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/* Some tools don't support XOR/AND. */
void WM_operator_properties_select_operation_simple(wmOperatorType *ot)
{
static const EnumPropertyItem select_mode_items[] = {
@@ -450,31 +434,6 @@ void WM_operator_properties_select_walk_direction(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/**
- * Selecting and tweaking items are overlapping operations. Getting both to work without conflicts
- * requires special care. See
- * https://wiki.blender.org/wiki/Human_Interface_Guidelines/Selection#Select-tweaking for the
- * desired behavior.
- *
- * For default click selection (with no modifier keys held), the select operators can do the
- * following:
- * - On a mouse press on an unselected item, change selection and finish immediately after.
- * This sends an undo push and allows transform to take over should a tweak event be caught now.
- * - On a mouse press on a selected item, don't change selection state, but start modal execution
- * of the operator. Idea is that we wait with deselecting other items until we know that the
- * intention wasn't to tweak (mouse press+drag) all selected items.
- * - If a tweak is recognized before the release event happens, cancel the operator, so that
- * transform can take over and no undo-push is sent.
- * - If the release event occurs rather than a tweak one, deselect all items but the one under the
- * cursor, and finish the modal operator.
- *
- * This utility, together with #WM_generic_select_invoke() and #WM_generic_select_modal() should
- * help getting the wanted behavior to work. Most generic logic should be handled in these, so that
- * the select operators only have to care for the case dependent handling.
- *
- * Every select operator has slightly different requirements, e.g. sequencer strip selection
- * also needs to account for handle selection. This should be the baseline behavior though.
- */
void WM_operator_properties_generic_select(wmOperatorType *ot)
{
/* On the initial mouse press, this is set by #WM_generic_select_modal() to let the select
@@ -499,9 +458,6 @@ void WM_operator_properties_gesture_box_zoom(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
-/**
- * Use with #WM_gesture_lasso_invoke
- */
void WM_operator_properties_gesture_lasso(wmOperatorType *ot)
{
PropertyRNA *prop;
@@ -509,9 +465,6 @@ void WM_operator_properties_gesture_lasso(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
-/**
- * Use with #WM_gesture_straightline_invoke
- */
void WM_operator_properties_gesture_straightline(wmOperatorType *ot, int cursor)
{
PropertyRNA *prop;
@@ -541,9 +494,6 @@ void WM_operator_properties_gesture_straightline(wmOperatorType *ot, int cursor)
}
}
-/**
- * Use with #WM_gesture_circle_invoke
- */
void WM_operator_properties_gesture_circle(wmOperatorType *ot)
{
PropertyRNA *prop;
@@ -582,9 +532,6 @@ void WM_operator_properties_mouse_select(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/**
- * \param nth_can_disable: Enable if we want to be able to select no interval at all.
- */
void WM_operator_properties_checker_interval(wmOperatorType *ot, bool nth_can_disable)
{
const int nth_default = nth_can_disable ? 0 : 1;
diff --git a/source/blender/windowmanager/intern/wm_operator_type.c b/source/blender/windowmanager/intern/wm_operator_type.c
index 0e30df4ec99..0f6096e7b8b 100644
--- a/source/blender/windowmanager/intern/wm_operator_type.c
+++ b/source/blender/windowmanager/intern/wm_operator_type.c
@@ -89,7 +89,6 @@ wmOperatorType *WM_operatortype_find(const char *idname, bool quiet)
return NULL;
}
-/* caller must free */
void WM_operatortype_iter(GHashIterator *ghi)
{
BLI_ghashIterator_init(ghi, global_ops_hash);
@@ -132,7 +131,8 @@ static void wm_operatortype_append__end(wmOperatorType *ot)
BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot);
}
-/* all ops in 1 list (for time being... needs evaluation later) */
+/* All ops in 1 list (for time being... needs evaluation later). */
+
void WM_operatortype_append(void (*opfunc)(wmOperatorType *))
{
wmOperatorType *ot = wm_operatortype_append__begin();
@@ -149,7 +149,6 @@ void WM_operatortype_append_ptr(void (*opfunc)(wmOperatorType *, void *), void *
/** \} */
-/* called on initialize WM_exit() */
void WM_operatortype_remove_ptr(wmOperatorType *ot)
{
BLI_assert(ot == WM_operatortype_find(ot->idname, false));
@@ -184,7 +183,6 @@ bool WM_operatortype_remove(const char *idname)
return true;
}
-/* called on initialize WM_init() */
void wm_operatortype_init(void)
{
/* reserve size is set based on blender default setup */
@@ -215,18 +213,6 @@ void wm_operatortype_free(void)
global_ops_hash = NULL;
}
-/**
- * Tag all operator-properties of \a ot defined after calling this, until
- * the next #WM_operatortype_props_advanced_end call (if available), with
- * #OP_PROP_TAG_ADVANCED. Previously defined ones properties not touched.
- *
- * Calling this multiple times without a call to #WM_operatortype_props_advanced_end,
- * all calls after the first one are ignored. Meaning all proprieties defined after the
- * first call are tagged as advanced.
- *
- * This doesn't do the actual tagging, #WM_operatortype_props_advanced_end does which is
- * called for all operators during registration (see #wm_operatortype_append__end).
- */
void WM_operatortype_props_advanced_begin(wmOperatorType *ot)
{
if (ot_prop_basic_count == -1) {
@@ -235,14 +221,6 @@ void WM_operatortype_props_advanced_begin(wmOperatorType *ot)
}
}
-/**
- * Tags all operator-properties of \a ot defined since the first
- * #WM_operatortype_props_advanced_begin call,
- * or the last #WM_operatortype_props_advanced_end call, with #OP_PROP_TAG_ADVANCED.
- *
- * \note This is called for all operators during registration (see #wm_operatortype_append__end).
- * So it does not need to be explicitly called in operator-type definition.
- */
void WM_operatortype_props_advanced_end(wmOperatorType *ot)
{
PointerRNA struct_ptr;
@@ -266,9 +244,6 @@ void WM_operatortype_props_advanced_end(wmOperatorType *ot)
ot_prop_basic_count = -1;
}
-/**
- * Remove memory of all previously executed tools.
- */
void WM_operatortype_last_properties_clear_all(void)
{
GHashIterator iter;
@@ -471,7 +446,6 @@ static void wm_macro_cancel(bContext *C, wmOperator *op)
wm_macro_end(op, OPERATOR_CANCELLED);
}
-/* Names have to be static for now */
wmOperatorType *WM_operatortype_append_macro(const char *idname,
const char *name,
const char *description,
@@ -613,9 +587,6 @@ char *WM_operatortype_description(struct bContext *C,
return NULL;
}
-/**
- * Use when we want a label, preferring the description.
- */
char *WM_operatortype_description_or_name(struct bContext *C,
struct wmOperatorType *ot,
struct PointerRNA *properties)
diff --git a/source/blender/windowmanager/intern/wm_operator_utils.c b/source/blender/windowmanager/intern/wm_operator_utils.c
index 85a0a28de79..dbcfd814692 100644
--- a/source/blender/windowmanager/intern/wm_operator_utils.c
+++ b/source/blender/windowmanager/intern/wm_operator_utils.c
@@ -44,9 +44,6 @@
/** \name Generic Utilities
* \{ */
-/**
- * Only finish + pass through for press events (allowing press-tweak).
- */
int WM_operator_flag_only_pass_through_on_press(int retval, const struct wmEvent *event)
{
if ((event->val != KM_PRESS) &&
@@ -337,10 +334,6 @@ static int op_generic_value_modal(bContext *C, wmOperator *op, const wmEvent *ev
return OPERATOR_RUNNING_MODAL;
}
-/**
- * Allow an operator with only and execute function to run modally,
- * re-doing the action, using vertex coordinate store/restore instead of operator undo.
- */
void WM_operator_type_modal_from_exec_for_object_edit_coords(wmOperatorType *ot)
{
PropertyRNA *prop;
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index ffdc99152b1..6c9b0af5186 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -116,13 +116,10 @@
#define UNDOCUMENTED_OPERATOR_TIP N_("(undocumented operator)")
-/** \} */
-
/* -------------------------------------------------------------------- */
/** \name Operator API
* \{ */
-/* SOME_OT_op -> some.op */
void WM_operator_py_idname(char *to, const char *from)
{
const char *sep = strstr(from, "_OT_");
@@ -143,7 +140,6 @@ void WM_operator_py_idname(char *to, const char *from)
}
}
-/* some.op -> SOME_OT_op */
void WM_operator_bl_idname(char *to, const char *from)
{
if (from) {
@@ -167,10 +163,6 @@ void WM_operator_bl_idname(char *to, const char *from)
}
}
-/**
- * Sanity check to ensure #WM_operator_bl_idname won't fail.
- * \returns true when there are no problems with \a idname, otherwise report an error.
- */
bool WM_operator_py_idname_ok_or_report(ReportList *reports,
const char *classname,
const char *idname)
@@ -219,15 +211,6 @@ bool WM_operator_py_idname_ok_or_report(ReportList *reports,
return true;
}
-/**
- * Print a string representation of the operator,
- * with the args that it runs so python can run it again.
- *
- * When calling from an existing wmOperator, better to use simple version:
- * `WM_operator_pystring(C, op);`
- *
- * \note Both \a op and \a opptr may be `NULL` (\a op is only used for macro operators).
- */
char *WM_operator_pystring_ex(bContext *C,
wmOperator *op,
const bool all_args,
@@ -308,9 +291,6 @@ char *WM_operator_pystring(bContext *C, wmOperator *op, const bool all_args, con
return WM_operator_pystring_ex(C, op, all_args, macro_args, op->type, op->ptr);
}
-/**
- * \return true if the string was shortened
- */
bool WM_operator_pystring_abbreviate(char *str, int str_len_max)
{
const int str_len = strlen(str);
@@ -608,9 +588,6 @@ static const char *wm_context_member_from_ptr(const bContext *C,
}
#endif
-/**
- * Calculate the path to `ptr` from context `C`, or return NULL if it can't be calculated.
- */
char *WM_context_path_resolve_property_full(const bContext *C,
const PointerRNA *ptr,
PropertyRNA *prop,
@@ -711,8 +688,6 @@ void WM_operator_properties_create(PointerRNA *ptr, const char *opstring)
}
}
-/* similar to the function above except its uses ID properties
- * used for keymaps and macros */
void WM_operator_properties_alloc(PointerRNA **ptr, IDProperty **properties, const char *opstring)
{
IDProperty *tmp_properties = NULL;
@@ -763,14 +738,6 @@ void WM_operator_properties_sanitize(PointerRNA *ptr, const bool no_context)
RNA_STRUCT_END;
}
-/**
- * Set all props to their default.
- *
- * \param do_update: Only update un-initialized props.
- *
- * \note There's nothing specific to operators here.
- * This could be made a general function.
- */
bool WM_operator_properties_default(PointerRNA *ptr, const bool do_update)
{
bool changed = false;
@@ -798,7 +765,6 @@ bool WM_operator_properties_default(PointerRNA *ptr, const bool do_update)
return changed;
}
-/* remove all props without PROP_SKIP_SAVE */
void WM_operator_properties_reset(wmOperator *op)
{
if (op->ptr->data) {
@@ -945,13 +911,6 @@ bool WM_operator_last_properties_store(wmOperator *UNUSED(op))
/** \name Default Operator Callbacks
* \{ */
-/**
- * Helper to get select and tweak-transform to work conflict free and as desired. See
- * #WM_operator_properties_generic_select() for details.
- *
- * To be used together with #WM_generic_select_invoke() and
- * #WM_operator_properties_generic_select().
- */
int WM_generic_select_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
PropertyRNA *wait_to_deselect_prop = RNA_struct_find_property(op->ptr,
@@ -1012,13 +971,6 @@ int WM_generic_select_modal(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH;
}
-/**
- * Helper to get select and tweak-transform to work conflict free and as desired. See
- * #WM_operator_properties_generic_select() for details.
- *
- * To be used together with #WM_generic_select_modal() and
- * #WM_operator_properties_generic_select().
- */
int WM_generic_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
RNA_int_set(op->ptr, "mouse_x", event->mval[0]);
@@ -1063,7 +1015,6 @@ int WM_operator_smooth_viewtx_get(const wmOperator *op)
return (op->flag & OP_IS_INVOKE) ? U.smooth_viewtx : 0;
}
-/* invoke callback, uses enum property named "type" */
int WM_menu_invoke_ex(bContext *C, wmOperator *op, wmOperatorCallContext opcontext)
{
PropertyRNA *prop = op->type->prop;
@@ -1184,10 +1135,6 @@ static uiBlock *wm_enum_search_menu(bContext *C, ARegion *region, void *arg)
return block;
}
-/**
- * Similar to #WM_enum_search_invoke, but draws previews. Also, this can't
- * be used as invoke callback directly since it needs additional info.
- */
int WM_enum_search_invoke_previews(bContext *C, wmOperator *op, short prv_cols, short prv_rows)
{
static struct EnumSearchMenu search_menu;
@@ -1210,7 +1157,6 @@ int WM_enum_search_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(eve
return OPERATOR_INTERFACE;
}
-/* Can't be used as an invoke directly, needs message arg (can be NULL) */
int WM_operator_confirm_message_ex(bContext *C,
wmOperator *op,
const char *title,
@@ -1255,7 +1201,6 @@ int WM_operator_confirm_or_exec(bContext *C, wmOperator *op, const wmEvent *UNUS
return op->type->exec(C, op);
}
-/* op->invoke, opens fileselect if path property not set, otherwise executes */
int WM_operator_filesel(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
if (RNA_struct_property_is_set(op->ptr, "filepath")) {
@@ -1280,7 +1225,6 @@ bool WM_operator_filesel_ensure_ext_imtype(wmOperator *op, const struct ImageFor
return false;
}
-/* op->poll */
bool WM_operator_winactive(bContext *C)
{
if (CTX_wm_window(C) == NULL) {
@@ -1289,7 +1233,6 @@ bool WM_operator_winactive(bContext *C)
return 1;
}
-/* return false, if the UI should be disabled */
bool WM_operator_check_ui_enabled(const bContext *C, const char *idname)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -1327,9 +1270,6 @@ void WM_operator_last_properties_ensure(wmOperatorType *ot, PointerRNA *ptr)
RNA_pointer_create(G_MAIN->wm.first, ot->srna, props, ptr);
}
-/**
- * Use for drag & drop a path or name with operators invoke() function.
- */
ID *WM_operator_drop_load_path(struct bContext *C, wmOperator *op, const short idcode)
{
Main *bmain = CTX_data_main(C);
@@ -1633,20 +1573,11 @@ static int wm_operator_props_popup_ex(bContext *C,
return OPERATOR_RUNNING_MODAL;
}
-/**
- * Same as #WM_operator_props_popup but don't use operator redo.
- * just wraps #WM_operator_props_dialog_popup.
- */
int WM_operator_props_popup_confirm(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
return wm_operator_props_popup_ex(C, op, false, false);
}
-/**
- * Same as #WM_operator_props_popup but call the operator first,
- * This way - the button values correspond to the result of the operator.
- * Without this, first access to a button will make the result jump, see T32452.
- */
int WM_operator_props_popup_call(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
return wm_operator_props_popup_ex(C, op, true, true);
@@ -3999,7 +3930,6 @@ static void gesture_zoom_border_modal_keymap(wmKeyConfig *keyconf)
WM_modalkeymap_assign(keymap, "IMAGE_OT_view_zoom_border");
}
-/* default keymap for windows and screens, only call once per WM */
void wm_window_keymap(wmKeyConfig *keyconf)
{
WM_keymap_ensure(keyconf, "Window", 0, 0);
@@ -4067,7 +3997,8 @@ static const EnumPropertyItem *rna_id_itemf(bool *r_free,
return item;
}
-/* can add more as needed */
+/* Can add more ID types as needed. */
+
const EnumPropertyItem *RNA_action_itemf(bContext *C,
PointerRNA *UNUSED(ptr),
PropertyRNA *UNUSED(prop),
diff --git a/source/blender/windowmanager/intern/wm_panel_type.c b/source/blender/windowmanager/intern/wm_panel_type.c
index 24508c377a6..609bb55e075 100644
--- a/source/blender/windowmanager/intern/wm_panel_type.c
+++ b/source/blender/windowmanager/intern/wm_panel_type.c
@@ -69,7 +69,6 @@ void WM_paneltype_remove(PanelType *pt)
UNUSED_VARS_NDEBUG(ok);
}
-/* called on initialize WM_init() */
void WM_paneltype_init(void)
{
/* reserve size is set based on blender default setup */
diff --git a/source/blender/windowmanager/intern/wm_stereo.c b/source/blender/windowmanager/intern/wm_stereo.c
index 16a17484f4f..a62ced1a4bf 100644
--- a/source/blender/windowmanager/intern/wm_stereo.c
+++ b/source/blender/windowmanager/intern/wm_stereo.c
@@ -177,10 +177,6 @@ bool WM_stereo3d_enabled(wmWindow *win, bool skip_stereo3d_check)
return true;
}
-/**
- * If needed, adjust \a r_mouse_xy
- * so that drawn cursor and handled mouse position are matching visually.
- */
void wm_stereo3d_mouse_offset_apply(wmWindow *win, int r_mouse_xy[2])
{
if (!WM_stereo3d_enabled(win, false)) {
diff --git a/source/blender/windowmanager/intern/wm_subwindow.c b/source/blender/windowmanager/intern/wm_subwindow.c
index 0cb76404258..524580ac88f 100644
--- a/source/blender/windowmanager/intern/wm_subwindow.c
+++ b/source/blender/windowmanager/intern/wm_subwindow.c
@@ -116,7 +116,6 @@ static void wmOrtho2_offset(const float x, const float y, const float ofs)
wmOrtho2(ofs, x + ofs, ofs, y + ofs);
}
-/* Default pixel alignment for regions. */
void wmOrtho2_region_pixelspace(const ARegion *region)
{
wmOrtho2_offset(region->winx, region->winy, -0.01f);
diff --git a/source/blender/windowmanager/intern/wm_surface.c b/source/blender/windowmanager/intern/wm_surface.c
index 715f72d70cf..385b55f36f9 100644
--- a/source/blender/windowmanager/intern/wm_surface.c
+++ b/source/blender/windowmanager/intern/wm_surface.c
@@ -45,11 +45,24 @@ static wmSurface *g_drawable = NULL;
void wm_surfaces_iter(bContext *C, void (*cb)(bContext *C, wmSurface *))
{
- LISTBASE_FOREACH (wmSurface *, surf, &global_surface_list) {
+ /* Mutable iterator in case a surface is freed. */
+ LISTBASE_FOREACH_MUTABLE (wmSurface *, surf, &global_surface_list) {
cb(C, surf);
}
}
+static void wm_surface_do_depsgraph_fn(bContext *C, wmSurface *surface)
+{
+ if (surface->do_depsgraph) {
+ surface->do_depsgraph(C);
+ }
+}
+
+void wm_surfaces_do_depsgraph(bContext *C)
+{
+ wm_surfaces_iter(C, wm_surface_do_depsgraph_fn);
+}
+
void wm_surface_clear_drawable(void)
{
if (g_drawable) {
@@ -107,6 +120,9 @@ void wm_surface_add(wmSurface *surface)
void wm_surface_remove(wmSurface *surface)
{
+ if (surface == g_drawable) {
+ wm_surface_clear_drawable();
+ }
BLI_remlink(&global_surface_list, surface);
surface->free_data(surface);
MEM_freeN(surface);
diff --git a/source/blender/windowmanager/intern/wm_toolsystem.c b/source/blender/windowmanager/intern/wm_toolsystem.c
index 3ac1a7c0be1..7b8feac45b4 100644
--- a/source/blender/windowmanager/intern/wm_toolsystem.c
+++ b/source/blender/windowmanager/intern/wm_toolsystem.c
@@ -251,7 +251,6 @@ void WM_toolsystem_reinit(bContext *C, WorkSpace *workspace, const bToolKey *tke
}
}
-/* Operate on all active tools. */
void WM_toolsystem_unlink_all(struct bContext *C, struct WorkSpace *workspace)
{
LISTBASE_FOREACH (bToolRef *, tref, &workspace->tools) {
@@ -362,12 +361,6 @@ void WM_toolsystem_ref_set_from_runtime(struct bContext *C,
}
}
-/**
- * Sync the internal active state of a tool back into the tool system,
- * this is needed for active brushes where the real active state is not stored in the tool system.
- *
- * \see #toolsystem_ref_link
- */
void WM_toolsystem_ref_sync_from_context(Main *bmain, WorkSpace *workspace, bToolRef *tref)
{
bToolRef_Runtime *tref_rt = tref->runtime;
@@ -505,14 +498,6 @@ bool WM_toolsystem_key_from_context(ViewLayer *view_layer, ScrArea *area, bToolK
return false;
}
-/**
- * Use to update the active tool (shown in the top bar) in the least disruptive way.
- *
- * This is a little involved since there may be multiple valid active tools
- * depending on the mode and space type.
- *
- * Used when undoing since the active mode may have changed.
- */
void WM_toolsystem_refresh_active(bContext *C)
{
Main *bmain = CTX_data_main(C);
@@ -800,16 +785,12 @@ void WM_toolsystem_update_from_context(bContext *C,
}
}
-/**
- * For paint modes to support non-brush tools.
- */
bool WM_toolsystem_active_tool_is_brush(const bContext *C)
{
bToolRef_Runtime *tref_rt = WM_toolsystem_runtime_from_context((bContext *)C);
return tref_rt && (tref_rt->data_block[0] != '\0');
}
-/* Follow wmMsgNotifyFn spec */
void WM_toolsystem_do_msg_notify_tag_refresh(bContext *C,
wmMsgSubscribeKey *UNUSED(msg_key),
wmMsgSubscribeValue *msg_val)
diff --git a/source/blender/windowmanager/intern/wm_uilist_type.c b/source/blender/windowmanager/intern/wm_uilist_type.c
index 82ba4aa6e6f..a2ae42d5ead 100644
--- a/source/blender/windowmanager/intern/wm_uilist_type.c
+++ b/source/blender/windowmanager/intern/wm_uilist_type.c
@@ -131,7 +131,6 @@ void WM_uilisttype_remove_ptr(Main *bmain, uiListType *ult)
UNUSED_VARS_NDEBUG(ok);
}
-/* called on initialize WM_init() */
void WM_uilisttype_init(void)
{
uilisttypes_hash = BLI_ghash_str_new_ex("uilisttypes_hash gh", 16);
@@ -151,16 +150,6 @@ void WM_uilisttype_free(void)
uilisttypes_hash = NULL;
}
-/**
- * The "full" list-ID is an internal name used for storing and identifying a list. It is built like
- * this:
- * "{uiListType.idname}_{list_id}", whereby "list_id" is an optional parameter passed to
- * `UILayout.template_list()`. If it is not set, the full list-ID is just "{uiListType.idname}_".
- *
- * Note that whenever the Python API refers to the list-ID, it's the short, "non-full" one it
- * passed to `UILayout.template_list()`. C code can query that through
- * #WM_uilisttype_list_id_get().
- */
void WM_uilisttype_to_full_list_id(const uiListType *ult,
const char *list_id,
char r_full_list_id[/*UI_MAX_NAME_STR*/])
@@ -169,11 +158,6 @@ void WM_uilisttype_to_full_list_id(const uiListType *ult,
BLI_snprintf(r_full_list_id, UI_MAX_NAME_STR, "%s_%s", ult->idname, list_id ? list_id : "");
}
-/**
- * Get the "non-full" list-ID, see #WM_uilisttype_to_full_list_id() for details.
- *
- * \note Assumes `uiList.list_id` was set using #WM_uilisttype_to_full_list_id()!
- */
const char *WM_uilisttype_list_id_get(const uiListType *ult, uiList *list)
{
/* Some sanity check for the assumed behavior of #WM_uilisttype_to_full_list_id(). */
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index 5f684a752d8..29c9f53f735 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -136,8 +136,6 @@ static struct WMInitStruct {
static void wm_window_set_drawable(wmWindowManager *wm, wmWindow *win, bool activate);
static bool wm_window_timer(const bContext *C);
-/* XXX this one should correctly check for apple top header...
- * done for Cocoa : returns window contents (and not frame) max size. */
void wm_get_screensize(int *r_width, int *r_height)
{
unsigned int uiwidth;
@@ -148,7 +146,6 @@ void wm_get_screensize(int *r_width, int *r_height)
*r_height = uiheight;
}
-/* size of all screens (desktop), useful since the mouse is bound by this */
void wm_get_desktopsize(int *r_width, int *r_height)
{
unsigned int uiwidth;
@@ -198,8 +195,6 @@ static void wm_ghostwindow_destroy(wmWindowManager *wm, wmWindow *win)
}
}
-/* including window itself, C can be NULL.
- * ED_screen_exit should have been called */
void wm_window_free(bContext *C, wmWindowManager *wm, wmWindow *win)
{
/* update context */
@@ -260,7 +255,6 @@ static int find_free_winid(wmWindowManager *wm)
return id;
}
-/* don't change context itself */
wmWindow *wm_window_new(const Main *bmain, wmWindowManager *wm, wmWindow *parent, bool dialog)
{
wmWindow *win = MEM_callocN(sizeof(wmWindow), "window");
@@ -276,7 +270,6 @@ wmWindow *wm_window_new(const Main *bmain, wmWindowManager *wm, wmWindow *parent
return win;
}
-/* part of wm_window.c api */
wmWindow *wm_window_copy(Main *bmain,
wmWindowManager *wm,
wmWindow *win_src,
@@ -307,10 +300,6 @@ wmWindow *wm_window_copy(Main *bmain,
return win_dst;
}
-/**
- * A higher level version of copy that tests the new window can be added.
- * (called from the operator directly)
- */
wmWindow *wm_window_copy_test(bContext *C,
wmWindow *win_src,
const bool duplicate_layout,
@@ -353,13 +342,6 @@ static void wm_confirm_quit(bContext *C)
wm_close_file_dialog(C, action);
}
-/**
- * Call the quit confirmation prompt or exit directly if needed. The use can
- * still cancel via the confirmation popup. Also, this may not quit Blender
- * immediately, but rather schedule the closing.
- *
- * \param win: The window to show the confirmation popup/window in.
- */
void wm_quit_with_optional_confirmation_prompt(bContext *C, wmWindow *win)
{
wmWindow *win_ctx = CTX_wm_window(C);
@@ -387,7 +369,6 @@ void wm_quit_with_optional_confirmation_prompt(bContext *C, wmWindow *win)
/** \} */
-/* this is event from ghost, or exit-blender op */
void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win)
{
wmWindow *win_other;
@@ -447,13 +428,14 @@ void wm_window_title(wmWindowManager *wm, wmWindow *win)
}
else if (win->ghostwin) {
/* this is set to 1 if you don't have startup.blend open */
- if (G.save_over && BKE_main_blendfile_path_from_global()[0]) {
- char str[sizeof(((Main *)NULL)->name) + 24];
+ const char *blendfile_path = BKE_main_blendfile_path_from_global();
+ if (blendfile_path[0] != '\0') {
+ char str[sizeof(((Main *)NULL)->filepath) + 24];
BLI_snprintf(str,
sizeof(str),
"Blender%s [%s%s]",
wm->file_saved ? "" : "*",
- BKE_main_blendfile_path_from_global(),
+ blendfile_path,
G_MAIN->recovered ? " (Recovered)" : "");
GHOST_SetTitle(win->ghostwin, str);
}
@@ -679,19 +661,6 @@ static void wm_window_ghostwindow_ensure(wmWindowManager *wm, wmWindow *win, boo
ED_screen_global_areas_refresh(win);
}
-/**
- * Initialize #wmWindow without ghostwin, open these and clear.
- *
- * window size is read from window, if 0 it uses prefsize
- * called in #WM_check, also inits stuff after file read.
- *
- * \warning
- * After running, 'win->ghostwin' can be NULL in rare cases
- * (where OpenGL driver fails to create a context for eg).
- * We could remove them with #wm_window_ghostwindows_remove_invalid
- * but better not since caller may continue to use.
- * Instead, caller needs to handle the error case and cleanup.
- */
void wm_window_ghostwindows_ensure(wmWindowManager *wm)
{
BLI_assert(G.background == false);
@@ -715,10 +684,6 @@ void wm_window_ghostwindows_ensure(wmWindowManager *wm)
}
}
-/**
- * Call after #wm_window_ghostwindows_ensure or #WM_check
- * (after loading a new file) in the unlikely event a window couldn't be created.
- */
void wm_window_ghostwindows_remove_invalid(bContext *C, wmWindowManager *wm)
{
BLI_assert(G.background == false);
@@ -756,14 +721,6 @@ static bool wm_window_update_size_position(wmWindow *win)
return false;
}
-/**
- * \param space_type: SPACE_VIEW3D, SPACE_INFO, ... (eSpace_Type)
- * \param toplevel: Not a child owned by other windows. A peer of main window.
- * \param dialog: whether this should be made as a dialog-style window
- * \param temp: whether this is considered a short-lived window
- * \param alignment: how this window is positioned relative to its parent
- * \return the window or NULL in case of failure.
- */
wmWindow *WM_window_open(bContext *C,
const char *title,
int x,
@@ -952,7 +909,6 @@ int wm_window_new_main_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-/* fullscreen operator callback */
int wm_window_fullscreen_toggle_exec(bContext *C, wmOperator *UNUSED(op))
{
wmWindow *window = CTX_wm_window(C);
@@ -1083,7 +1039,6 @@ void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win)
}
}
-/* Reset active the current window opengl drawing context. */
void wm_window_reset_drawable(void)
{
BLI_assert(BLI_thread_is_main());
@@ -1585,10 +1540,6 @@ void wm_window_process_events(const bContext *C)
/** \name Ghost Init/Exit
* \{ */
-/**
- * \note #bContext can be null in background mode because we don't
- * need to event handling.
- */
void wm_ghost_init(bContext *C)
{
if (!g_system) {
@@ -1627,7 +1578,6 @@ void wm_ghost_exit(void)
/** \name Event Timer
* \{ */
-/* to (de)activate running timers temporary */
void WM_event_timer_sleep(wmWindowManager *wm,
wmWindow *UNUSED(win),
wmTimer *timer,
@@ -1769,19 +1719,11 @@ static char *wm_clipboard_text_get_ex(bool selection, int *r_len, bool firstline
return newbuf;
}
-/**
- * Return text from the clipboard.
- *
- * \note Caller needs to check for valid utf8 if this is a requirement.
- */
char *WM_clipboard_text_get(bool selection, int *r_len)
{
return wm_clipboard_text_get_ex(selection, r_len, false);
}
-/**
- * Convenience function for pasting to areas of Blender which don't support newlines.
- */
char *WM_clipboard_text_get_firstline(bool selection, int *r_len)
{
return wm_clipboard_text_get_ex(selection, r_len, true);
@@ -1890,9 +1832,6 @@ void wm_window_raise(wmWindow *win)
/** \name Window Buffers
* \{ */
-/**
- * \brief Push rendered buffer to the screen.
- */
void wm_window_swap_buffers(wmWindow *win)
{
GHOST_SwapWindowBuffers(win->ghostwin);
@@ -1913,6 +1852,7 @@ bool wm_window_get_swap_interval(wmWindow *win, int *intervalOut)
/* -------------------------------------------------------------------- */
/** \name Find Window Utility
* \{ */
+
static void wm_window_desktop_pos_get(const wmWindow *win,
const int screen_pos[2],
int r_desk_pos[2])
@@ -2034,7 +1974,6 @@ uint *WM_window_pixels_read(wmWindowManager *wm, wmWindow *win, int r_size[2])
/** \name Initial Window State API
* \{ */
-/* called whem no ghost system was initialized */
void WM_init_state_size_set(int stax, int stay, int sizx, int sizy)
{
wm_init_state.start_x = stax; /* left hand pos */
@@ -2044,7 +1983,6 @@ void WM_init_state_size_set(int stax, int stay, int sizx, int sizy)
wm_init_state.override_flag |= WIN_OVERRIDE_GEOM;
}
-/* for borderless and border windows set from command-line */
void WM_init_state_fullscreen_set(void)
{
wm_init_state.windowstate = GHOST_kWindowStateFullScreen;
@@ -2097,7 +2035,6 @@ void WM_init_tablet_api(void)
}
}
-/* This function requires access to the GHOST_SystemHandle (g_system) */
void WM_cursor_warp(wmWindow *win, int x, int y)
{
if (win && win->ghostwin) {
@@ -2114,9 +2051,6 @@ void WM_cursor_warp(wmWindow *win, int x, int y)
}
}
-/**
- * Set x, y to values we can actually position the cursor to.
- */
void WM_cursor_compatible_xy(wmWindow *win, int *x, int *y)
{
float f = GHOST_GetNativePixelSize(win->ghostwin);
@@ -2132,11 +2066,6 @@ void WM_cursor_compatible_xy(wmWindow *win, int *x, int *y)
/** \name Window Size (public)
* \{ */
-/**
- * Support for native pixel size
- *
- * \note macOS retina opens window in size X, but it has up to 2 x more pixels.
- */
int WM_window_pixels_x(const wmWindow *win)
{
float f = GHOST_GetNativePixelSize(win->ghostwin);
@@ -2150,17 +2079,10 @@ int WM_window_pixels_y(const wmWindow *win)
return (int)(f * (float)win->sizey);
}
-/**
- * Get boundaries usable by all window contents, including global areas.
- */
void WM_window_rect_calc(const wmWindow *win, rcti *r_rect)
{
BLI_rcti_init(r_rect, 0, WM_window_pixels_x(win), 0, WM_window_pixels_y(win));
}
-/**
- * Get boundaries usable by screen-layouts, excluding global areas.
- * \note Depends on U.dpi_fac. Should that be outdated, call #WM_window_set_dpi first.
- */
void WM_window_screen_rect_calc(const wmWindow *win, rcti *r_rect)
{
rcti window_rect, screen_rect;
@@ -2210,11 +2132,6 @@ bool WM_window_is_maximized(const wmWindow *win)
/** \name Window Screen/Scene/WorkSpaceViewLayer API
* \{ */
-/**
- * Some editor data may need to be synced with scene data (3D View camera and layers).
- * This function ensures data is synced for editors
- * in visible workspaces and their visible layouts.
- */
void WM_windows_scene_data_sync(const ListBase *win_lb, Scene *scene)
{
LISTBASE_FOREACH (wmWindow *, win, win_lb) {
@@ -2261,9 +2178,6 @@ Scene *WM_window_get_active_scene(const wmWindow *win)
return win->scene;
}
-/**
- * \warning Only call outside of area/region loops
- */
void WM_window_set_active_scene(Main *bmain, bContext *C, wmWindow *win, Scene *scene)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -2376,9 +2290,6 @@ void WM_window_set_active_layout(wmWindow *win, WorkSpace *workspace, WorkSpaceL
BKE_workspace_active_layout_set(win->workspace_hook, win->winid, workspace, layout);
}
-/**
- * Get the active screen of the active workspace in \a win.
- */
bScreen *WM_window_get_active_screen(const wmWindow *win)
{
const WorkSpace *workspace = WM_window_get_active_workspace(win);
@@ -2481,4 +2392,5 @@ void WM_ghost_show_message_box(const char *title,
BLI_assert(g_system);
GHOST_ShowMessageBox(g_system, title, message, help_label, continue_label, link, dialog_options);
}
+
/** \} */
diff --git a/source/blender/windowmanager/message_bus/intern/wm_message_bus.c b/source/blender/windowmanager/message_bus/intern/wm_message_bus.c
index 86a106462c3..81ef8c881f5 100644
--- a/source/blender/windowmanager/message_bus/intern/wm_message_bus.c
+++ b/source/blender/windowmanager/message_bus/intern/wm_message_bus.c
@@ -147,16 +147,6 @@ void WM_msgbus_handle(struct wmMsgBus *mbus, struct bContext *C)
// printf("msgbus: keys=%u values=%u\n", a, b);
}
-/**
- * \param msg_key_test: Needs following #wmMsgSubscribeKey fields filled in:
- * - msg.params
- * - msg.head.type
- * - msg.head.id
- * .. other values should be zeroed.
- *
- * \return The key for this subscription.
- * note that this is only needed in rare cases when the key needs further manipulation.
- */
wmMsgSubscribeKey *WM_msg_subscribe_with_key(struct wmMsgBus *mbus,
const wmMsgSubscribeKey *msg_key_test,
const wmMsgSubscribeValue *msg_val_params)
@@ -239,9 +229,6 @@ void WM_msg_id_remove(struct wmMsgBus *mbus, const struct ID *id)
* \note While we could have a separate type for ID's, use RNA since there is enough overlap.
* \{ */
-/**
- * \note #wmMsgBus.messages_tag_count isn't updated, caller must handle.
- */
void wm_msg_subscribe_value_free(wmMsgSubscribeKey *msg_key, wmMsgSubscribeValueLink *msg_lnk)
{
if (msg_lnk->params.free_data) {
diff --git a/source/blender/windowmanager/message_bus/intern/wm_message_bus_intern.h b/source/blender/windowmanager/message_bus/intern/wm_message_bus_intern.h
index 24c0192fe14..18df17c3d1c 100644
--- a/source/blender/windowmanager/message_bus/intern/wm_message_bus_intern.h
+++ b/source/blender/windowmanager/message_bus/intern/wm_message_bus_intern.h
@@ -30,6 +30,9 @@ struct wmMsgBus {
uint messages_tag_count;
};
+/**
+ * \note #wmMsgBus.messages_tag_count isn't updated, caller must handle.
+ */
void wm_msg_subscribe_value_free(struct wmMsgSubscribeKey *msg_key,
struct wmMsgSubscribeValueLink *msg_lnk);
diff --git a/source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c b/source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c
index 460dca57e4f..bc083793395 100644
--- a/source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c
+++ b/source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c
@@ -35,7 +35,9 @@
#include "RNA_access.h"
-/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------- */
+/** \name Internal Utilities
+ * \{ */
BLI_INLINE uint void_hash_uint(const void *key)
{
@@ -208,7 +210,11 @@ void WM_msgtypeinfo_init_rna(wmMsgTypeInfo *msgtype_info)
msgtype_info->msg_key_size = sizeof(wmMsgSubscribeKey_RNA);
}
-/* -------------------------------------------------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name RNA API
+ * \{ */
wmMsgSubscribeKey_RNA *WM_msg_lookup_rna(struct wmMsgBus *mbus,
const wmMsgParams_RNA *msg_key_params)
diff --git a/source/blender/windowmanager/message_bus/wm_message_bus.h b/source/blender/windowmanager/message_bus/wm_message_bus.h
index 7ae356cf806..7ee2e5b6ee6 100644
--- a/source/blender/windowmanager/message_bus/wm_message_bus.h
+++ b/source/blender/windowmanager/message_bus/wm_message_bus.h
@@ -79,7 +79,7 @@ typedef struct wmMsg {
} wmMsg;
typedef struct wmMsgSubscribeKey {
- /** Linked list for predicable ordering, otherwise we would depend on ghash bucketing. */
+ /** Linked list for predicable ordering, otherwise we would depend on #GHash bucketing. */
struct wmMsgSubscribeKey *next, *prev;
ListBase values;
/* over-alloc, eg: wmMsgSubscribeKey_RNA */
@@ -124,6 +124,16 @@ void WM_msg_dump(struct wmMsgBus *mbus, const char *info);
void WM_msgbus_handle(struct wmMsgBus *mbus, struct bContext *C);
void WM_msg_publish_with_key(struct wmMsgBus *mbus, wmMsgSubscribeKey *msg_key);
+/**
+ * \param msg_key_test: Needs following #wmMsgSubscribeKey fields filled in:
+ * - `msg.params`
+ * - `msg.head.type`
+ * - `msg.head.id`
+ * .. other values should be zeroed.
+ *
+ * \return The key for this subscription.
+ * note that this is only needed in rare cases when the key needs further manipulation.
+ */
wmMsgSubscribeKey *WM_msg_subscribe_with_key(struct wmMsgBus *mbus,
const wmMsgSubscribeKey *msg_key_test,
const wmMsgSubscribeValue *msg_val_params);
diff --git a/source/blender/windowmanager/wm.h b/source/blender/windowmanager/wm.h
index cfef70b7dcc..e67b1581875 100644
--- a/source/blender/windowmanager/wm.h
+++ b/source/blender/windowmanager/wm.h
@@ -43,49 +43,98 @@ typedef struct wmPaintCursor {
short region_type;
} wmPaintCursor;
+/**
+ * Cause a delayed #WM_exit()
+ * call to avoid leaking memory when trying to exit from within operators.
+ */
void wm_exit_schedule_delayed(const bContext *C);
+/**
+ * Context is allowed to be NULL, do not free wm itself (lib_id.c).
+ */
extern void wm_close_and_free(bContext *C, wmWindowManager *);
extern void wm_close_and_free_all(bContext *C, ListBase *);
+/**
+ * On startup, it adds all data, for matching.
+ */
extern void wm_add_default(struct Main *bmain, bContext *C);
extern void wm_clear_default_size(bContext *C);
/* register to windowmanager for redo or macro */
+
+/**
+ * Called on event handling by `event_system.c`.
+ *
+ * All operations get registered in the windowmanager here.
+ */
void wm_operator_register(bContext *C, wmOperator *op);
/* wm_operator.c, for init/exit */
+
void wm_operatortype_free(void);
+/**
+ * Called on initialize #WM_init().
+ */
void wm_operatortype_init(void);
+/**
+ * Default key-map for windows and screens, only call once per WM.
+ */
void wm_window_keymap(wmKeyConfig *keyconf);
void wm_operatortypes_register(void);
/* wm_gesture.c */
+/* called in wm_draw.c */
+
void wm_gesture_draw(struct wmWindow *win);
+/**
+ * Tweak and line gestures.
+ */
int wm_gesture_evaluate(wmGesture *gesture, const struct wmEvent *event);
void wm_gesture_tag_redraw(struct wmWindow *win);
/* wm_gesture_ops.c */
+
+/**
+ * Standard tweak, called after window handlers passed on event.
+ */
void wm_tweakevent_test(bContext *C, const wmEvent *event, int action);
/* wm_jobs.c */
+
+/**
+ * Hard-coded to event #TIMERJOBS.
+ */
void wm_jobs_timer(wmWindowManager *wm, wmTimer *wt);
+/**
+ * Kill job entirely, also removes timer itself.
+ */
void wm_jobs_timer_end(wmWindowManager *wm, wmTimer *wt);
/* wm_files.c */
+
+/**
+ * Run the auto-save timer action.
+ */
void wm_autosave_timer(struct Main *bmain, wmWindowManager *wm, wmTimer *wt);
void wm_autosave_timer_begin(struct wmWindowManager *wm);
void wm_autosave_timer_end(wmWindowManager *wm);
void wm_autosave_delete(void);
/* wm_splash_screen.c */
+
void WM_OT_splash(wmOperatorType *ot);
void WM_OT_splash_about(wmOperatorType *ot);
/* wm_stereo.c */
+
void wm_stereo3d_draw_sidebyside(wmWindow *win, int view);
void wm_stereo3d_draw_topbottom(wmWindow *win, int view);
+/**
+ * If needed, adjust \a r_mouse_xy
+ * so that drawn cursor and handled mouse position are matching visually.
+ */
void wm_stereo3d_mouse_offset_apply(wmWindow *win, int r_mouse_xy[2]);
int wm_stereo3d_set_exec(bContext *C, wmOperator *op);
int wm_stereo3d_set_invoke(bContext *C, wmOperator *op, const wmEvent *event);
@@ -93,7 +142,9 @@ void wm_stereo3d_set_draw(bContext *C, wmOperator *op);
bool wm_stereo3d_set_check(bContext *C, wmOperator *op);
void wm_stereo3d_set_cancel(bContext *C, wmOperator *op);
-/* init operator properties */
+/**
+ * Initialize operator properties.
+ */
void wm_open_init_load_ui(wmOperator *op, bool use_prefs);
void wm_open_init_use_scripts(wmOperator *op, bool use_prefs);
diff --git a/source/blender/windowmanager/wm_event_system.h b/source/blender/windowmanager/wm_event_system.h
index 9b0f128d071..925be8ab183 100644
--- a/source/blender/windowmanager/wm_event_system.h
+++ b/source/blender/windowmanager/wm_event_system.h
@@ -144,20 +144,36 @@ typedef struct wmEventHandler_Dropbox {
} wmEventHandler_Dropbox;
/* wm_event_system.c */
+
void wm_event_free_all(wmWindow *win);
void wm_event_free(wmEvent *event);
void wm_event_free_handler(wmEventHandler *handler);
-/* goes over entire hierarchy: events -> window -> screen -> area -> region */
+/**
+ * Goes over entire hierarchy: events -> window -> screen -> area -> region.
+ *
+ * \note Called in main loop.
+ */
void wm_event_do_handlers(bContext *C);
+/**
+ * Windows store own event queues #wmWindow.event_queue (no #bContext here).
+ */
void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void *customdata);
#ifdef WITH_XR_OPENXR
void wm_event_add_xrevent(wmWindow *win, struct wmXrActionData *actiondata, short val);
#endif
void wm_event_do_depsgraph(bContext *C, bool is_after_open_file);
+/**
+ * Was part of #wm_event_do_notifiers,
+ * split out so it can be called once before entering the #WM_main loop.
+ * This ensures operators don't run before the UI and depsgraph are initialized.
+ */
void wm_event_do_refresh_wm_and_depsgraph(bContext *C);
+/**
+ * Called in main-loop.
+ */
void wm_event_do_notifiers(bContext *C);
void wm_event_handler_ui_cancel_ex(bContext *C,
@@ -166,17 +182,36 @@ void wm_event_handler_ui_cancel_ex(bContext *C,
bool reactivate_button);
/* wm_event_query.c */
+
+/**
+ * Applies the global tablet pressure correction curve.
+ */
float wm_pressure_curve(float raw_pressure);
void wm_tablet_data_from_ghost(const struct GHOST_TabletData *tablet_data, wmTabletData *wmtab);
-/* wm_keymap.c */
-
/* wm_dropbox.c */
+
void wm_dropbox_free(void);
+/**
+ * Additional work to cleanly end dragging. Additional because this doesn't actually remove the
+ * drag items. Should be called whenever dragging is stopped
+ * (successful or not, also when canceled).
+ */
void wm_drags_exit(wmWindowManager *wm, wmWindow *win);
void wm_drop_prepare(bContext *C, wmDrag *drag, wmDropBox *drop);
+/**
+ * Called in inner handler loop, region context.
+ */
void wm_drags_check_ops(bContext *C, const wmEvent *event);
+/**
+ * The operator of a dropbox should always be executed in the context determined by the mouse
+ * coordinates. The dropbox poll should check the context area and region as needed.
+ * So this always returns #WM_OP_INVOKE_DEFAULT.
+ */
wmOperatorCallContext wm_drop_operator_context_get(const wmDropBox *drop);
+/**
+ * Called in #wm_draw_window_onscreen.
+ */
void wm_drags_draw(bContext *C, wmWindow *win);
#ifdef __cplusplus
diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h
index c175c211db6..437bd1057c2 100644
--- a/source/blender/windowmanager/wm_event_types.h
+++ b/source/blender/windowmanager/wm_event_types.h
@@ -405,7 +405,7 @@ enum {
#define _VA_IS_EVENT_MOD4(v, a, b, c) (_VA_IS_EVENT_MOD3(v, a, b) || ((v)->c))
#define _VA_IS_EVENT_MOD5(v, a, b, c, d) (_VA_IS_EVENT_MOD4(v, a, b, c) || ((v)->d))
-/* reusable IS_EVENT_MOD(event, shift, ctrl, alt, oskey), macro */
+/** Reusable `IS_EVENT_MOD(event, shift, ctrl, alt, oskey)` macro. */
#define IS_EVENT_MOD(...) VA_NARGS_CALL_OVERLOAD(_VA_IS_EVENT_MOD, __VA_ARGS__)
enum eEventType_Mask {
diff --git a/source/blender/windowmanager/wm_files.h b/source/blender/windowmanager/wm_files.h
index 135f31cf8ac..e63afb2ed2f 100644
--- a/source/blender/windowmanager/wm_files.h
+++ b/source/blender/windowmanager/wm_files.h
@@ -33,6 +33,7 @@ extern "C" {
#endif
/* wm_files.c */
+
void wm_history_file_read(void);
struct wmHomeFileRead_Params {
@@ -62,6 +63,16 @@ struct wmHomeFileRead_Params {
const char *app_template_override;
};
+/**
+ * Called on startup, (context entirely filled with NULLs)
+ * or called for 'New File' both `startup.blend` and `userpref.blend` are checked.
+ *
+ * \param r_params_file_read_post: Support postponed initialization,
+ * needed for initial startup when only some sub-systems have been initialized.
+ * When non-null, #wm_file_read_post doesn't run, instead it's arguments are stored
+ * in this return argument.
+ * The caller is responsible for calling #wm_homefile_read_post with this return argument.
+ */
void wm_homefile_read_ex(struct bContext *C,
const struct wmHomeFileRead_Params *params_homefile,
struct ReportList *reports,
@@ -70,15 +81,26 @@ void wm_homefile_read(struct bContext *C,
const struct wmHomeFileRead_Params *params_homefile,
struct ReportList *reports);
+/**
+ * Special case, support deferred execution of #wm_file_read_post,
+ * Needed when loading for the first time to workaround order of initialization bug, see T89046.
+ */
void wm_homefile_read_post(struct bContext *C,
const struct wmFileReadPost_Params *params_file_read_post);
void wm_file_read_report(bContext *C, struct Main *bmain);
void wm_close_file_dialog(bContext *C, struct wmGenericCallback *post_action);
+/**
+ * \return True if the dialog was created, the calling operator should return #OPERATOR_INTERFACE
+ * then.
+ */
bool wm_operator_close_file_dialog_if_needed(bContext *C,
wmOperator *op,
wmGenericCallbackFn exec_fn);
+/**
+ * Check if there is data that would be lost when closing the current file without saving.
+ */
bool wm_file_or_session_data_has_unsaved_changes(const Main *bmain, const wmWindowManager *wm);
void WM_OT_save_homefile(struct wmOperatorType *ot);
@@ -99,6 +121,7 @@ void WM_OT_save_as_mainfile(struct wmOperatorType *ot);
void WM_OT_save_mainfile(struct wmOperatorType *ot);
/* wm_files_link.c */
+
void WM_OT_link(struct wmOperatorType *ot);
void WM_OT_append(struct wmOperatorType *ot);
diff --git a/source/blender/windowmanager/wm_surface.h b/source/blender/windowmanager/wm_surface.h
index a2483d38154..e924b1e47ad 100644
--- a/source/blender/windowmanager/wm_surface.h
+++ b/source/blender/windowmanager/wm_surface.h
@@ -39,6 +39,8 @@ typedef struct wmSurface {
void *customdata;
void (*draw)(struct bContext *);
+ /* To evaluate the surface's depsgraph. Called as part of the main loop. */
+ void (*do_depsgraph)(struct bContext *C);
/** Free customdata, not the surface itself (done by wm_surface API) */
void (*free_data)(struct wmSurface *);
@@ -56,6 +58,9 @@ void wm_surfaces_free(void);
/* Utils */
void wm_surfaces_iter(struct bContext *C, void (*cb)(struct bContext *, wmSurface *));
+/* Evaluation. */
+void wm_surfaces_do_depsgraph(struct bContext *C);
+
/* Drawing */
void wm_surface_make_drawable(wmSurface *surface);
void wm_surface_clear_drawable(void);
diff --git a/source/blender/windowmanager/wm_window.h b/source/blender/windowmanager/wm_window.h
index f205f923ec8..e44a39ecf1a 100644
--- a/source/blender/windowmanager/wm_window.h
+++ b/source/blender/windowmanager/wm_window.h
@@ -30,41 +30,93 @@ extern "C" {
#endif
/* *************** internal api ************** */
+
+/**
+ * \note #bContext can be null in background mode because we don't
+ * need to event handling.
+ */
void wm_ghost_init(bContext *C);
void wm_ghost_exit(void);
+/**
+ * This one should correctly check for apple top header...
+ * done for Cocoa: returns window contents (and not frame) max size.
+ */
void wm_get_screensize(int *r_width, int *r_height);
+/**
+ * Size of all screens (desktop), useful since the mouse is bound by this.
+ */
void wm_get_desktopsize(int *r_width, int *r_height);
+/**
+ * Don't change context itself.
+ */
wmWindow *wm_window_new(const struct Main *bmain,
wmWindowManager *wm,
wmWindow *parent,
bool dialog);
+/**
+ * Part of `wm_window.c` API.
+ */
wmWindow *wm_window_copy(struct Main *bmain,
wmWindowManager *wm,
wmWindow *win_src,
const bool duplicate_layout,
const bool child);
+/**
+ * A higher level version of copy that tests the new window can be added.
+ * (called from the operator directly).
+ */
wmWindow *wm_window_copy_test(bContext *C,
wmWindow *win_src,
const bool duplicate_layout,
const bool child);
+/**
+ * Including window itself.
+ * \param C: can be NULL.
+ * \note #ED_screen_exit should have been called.
+ */
void wm_window_free(bContext *C, wmWindowManager *wm, wmWindow *win);
+/**
+ * This is event from ghost, or exit-Blender operator.
+ */
void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win);
void wm_window_title(wmWindowManager *wm, wmWindow *win);
+/**
+ * Initialize #wmWindow without `ghostwin`, open these and clear.
+ *
+ * Window size is read from window, if 0 it uses prefsize
+ * called in #WM_check, also initialize stuff after file read.
+ *
+ * \warning After running, `win->ghostwin` can be NULL in rare cases
+ * (where OpenGL driver fails to create a context for eg).
+ * We could remove them with #wm_window_ghostwindows_remove_invalid
+ * but better not since caller may continue to use.
+ * Instead, caller needs to handle the error case and cleanup.
+ */
void wm_window_ghostwindows_ensure(wmWindowManager *wm);
+/**
+ * Call after #wm_window_ghostwindows_ensure or #WM_check
+ * (after loading a new file) in the unlikely event a window couldn't be created.
+ */
void wm_window_ghostwindows_remove_invalid(bContext *C, wmWindowManager *wm);
void wm_window_process_events(const bContext *C);
void wm_window_clear_drawable(wmWindowManager *wm);
void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win);
+/**
+ * Reset active the current window opengl drawing context.
+ */
void wm_window_reset_drawable(void);
void wm_window_raise(wmWindow *win);
void wm_window_lower(wmWindow *win);
void wm_window_set_size(wmWindow *win, int width, int height);
void wm_window_get_position(wmWindow *win, int *r_pos_x, int *r_pos_y);
+/**
+ * \brief Push rendered buffer to the screen.
+ */
void wm_window_swap_buffers(wmWindow *win);
void wm_window_set_swap_interval(wmWindow *win, int interval);
bool wm_window_get_swap_interval(wmWindow *win, int *intervalOut);
@@ -79,8 +131,19 @@ void wm_window_IME_end(wmWindow *win);
#endif
/* *************** window operators ************** */
+
int wm_window_close_exec(bContext *C, struct wmOperator *op);
+/**
+ * Full-screen operator callback.
+ */
int wm_window_fullscreen_toggle_exec(bContext *C, struct wmOperator *op);
+/**
+ * Call the quit confirmation prompt or exit directly if needed. The use can
+ * still cancel via the confirmation popup. Also, this may not quit Blender
+ * immediately, but rather schedule the closing.
+ *
+ * \param win: The window to show the confirmation popup/window in.
+ */
void wm_quit_with_optional_confirmation_prompt(bContext *C, wmWindow *win) ATTR_NONNULL();
int wm_window_new_exec(bContext *C, struct wmOperator *op);
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_actionmap.c b/source/blender/windowmanager/xr/intern/wm_xr_actionmap.c
index 8903305adb4..076f279ccbb 100644
--- a/source/blender/windowmanager/xr/intern/wm_xr_actionmap.c
+++ b/source/blender/windowmanager/xr/intern/wm_xr_actionmap.c
@@ -85,9 +85,6 @@ static XrActionMapBinding *wm_xr_actionmap_binding_find_except(XrActionMapItem *
return NULL;
}
-/**
- * Ensure unique name among all action map bindings.
- */
void WM_xr_actionmap_binding_ensure_unique(XrActionMapItem *ami, XrActionMapBinding *amb)
{
char name[MAX_NAME];
@@ -118,7 +115,6 @@ void WM_xr_actionmap_binding_ensure_unique(XrActionMapItem *ami, XrActionMapBind
static XrActionMapBinding *wm_xr_actionmap_binding_copy(XrActionMapBinding *amb_src)
{
XrActionMapBinding *amb_dst = MEM_dupallocN(amb_src);
-
amb_dst->prev = amb_dst->next = NULL;
return amb_dst;
@@ -198,10 +194,6 @@ static void wm_xr_actionmap_item_properties_free(XrActionMapItem *ami)
}
}
-/**
- * Similar to #wm_xr_actionmap_item_properties_set()
- * but checks for the #eXrActionType and #wmOperatorType having changed.
- */
void WM_xr_actionmap_item_properties_update_ot(XrActionMapItem *ami)
{
switch (ami->type) {
@@ -278,9 +270,6 @@ static XrActionMapItem *wm_xr_actionmap_item_find_except(XrActionMap *actionmap,
return NULL;
}
-/**
- * Ensure unique name among all action map items.
- */
void WM_xr_actionmap_item_ensure_unique(XrActionMap *actionmap, XrActionMapItem *ami)
{
char name[MAX_NAME];
@@ -308,25 +297,29 @@ void WM_xr_actionmap_item_ensure_unique(XrActionMap *actionmap, XrActionMapItem
BLI_strncpy(ami->name, name, MAX_NAME);
}
-static XrActionMapItem *wm_xr_actionmap_item_copy(XrActionMapItem *ami)
+static XrActionMapItem *wm_xr_actionmap_item_copy(XrActionMapItem *ami_src)
{
- XrActionMapItem *amin = MEM_dupallocN(ami);
-
- amin->prev = amin->next = NULL;
+ XrActionMapItem *ami_dst = MEM_dupallocN(ami_src);
+ ami_dst->prev = ami_dst->next = NULL;
- if (amin->op_properties) {
- amin->op_properties_ptr = MEM_callocN(sizeof(PointerRNA), "wmOpItemPtr");
- WM_operator_properties_create(amin->op_properties_ptr, amin->op);
+ BLI_listbase_clear(&ami_dst->bindings);
+ LISTBASE_FOREACH (XrActionMapBinding *, amb, &ami_src->bindings) {
+ XrActionMapBinding *amb_new = wm_xr_actionmap_binding_copy(amb);
+ BLI_addtail(&ami_dst->bindings, amb_new);
+ }
- amin->op_properties = IDP_CopyProperty(amin->op_properties);
- amin->op_properties_ptr->data = amin->op_properties;
+ if (ami_dst->op_properties) {
+ ami_dst->op_properties_ptr = MEM_callocN(sizeof(PointerRNA), "wmOpItemPtr");
+ WM_operator_properties_create(ami_dst->op_properties_ptr, ami_dst->op);
+ ami_dst->op_properties = IDP_CopyProperty(ami_src->op_properties);
+ ami_dst->op_properties_ptr->data = ami_dst->op_properties;
}
else {
- amin->op_properties = NULL;
- amin->op_properties_ptr = NULL;
+ ami_dst->op_properties = NULL;
+ ami_dst->op_properties_ptr = NULL;
}
- return amin;
+ return ami_dst;
}
XrActionMapItem *WM_xr_actionmap_item_add_copy(XrActionMap *actionmap, XrActionMapItem *ami_src)
@@ -411,9 +404,6 @@ static XrActionMap *wm_xr_actionmap_find_except(wmXrRuntimeData *runtime,
return NULL;
}
-/**
- * Ensure unique name among all action maps.
- */
void WM_xr_actionmap_ensure_unique(wmXrRuntimeData *runtime, XrActionMap *actionmap)
{
char name[MAX_NAME];
@@ -444,10 +434,9 @@ void WM_xr_actionmap_ensure_unique(wmXrRuntimeData *runtime, XrActionMap *action
static XrActionMap *wm_xr_actionmap_copy(XrActionMap *am_src)
{
XrActionMap *am_dst = MEM_dupallocN(am_src);
-
am_dst->prev = am_dst->next = NULL;
- BLI_listbase_clear(&am_dst->items);
+ BLI_listbase_clear(&am_dst->items);
LISTBASE_FOREACH (XrActionMapItem *, ami, &am_src->items) {
XrActionMapItem *ami_new = wm_xr_actionmap_item_copy(ami);
BLI_addtail(&am_dst->items, ami_new);
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_draw.c b/source/blender/windowmanager/xr/intern/wm_xr_draw.c
index 72d88bb3043..5d0163af5e1 100644
--- a/source/blender/windowmanager/xr/intern/wm_xr_draw.c
+++ b/source/blender/windowmanager/xr/intern/wm_xr_draw.c
@@ -139,12 +139,6 @@ static void wm_xr_draw_viewport_buffers_to_active_framebuffer(
GPU_viewport_draw_to_screen_ex(vp->viewport, 0, &rect, draw_view->expects_srgb_buffer, true);
}
-/**
- * \brief Draw a viewport for a single eye.
- *
- * This is the main viewport drawing function for VR sessions. It's assigned to Ghost-XR as a
- * callback (see GHOST_XrDrawViewFunc()) and executed for each view (read: eye).
- */
void wm_xr_draw_view(const GHOST_XrDrawViewInfo *draw_view, void *customdata)
{
wmXrDrawData *draw_data = customdata;
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_intern.h b/source/blender/windowmanager/xr/intern/wm_xr_intern.h
index 7de1f254224..e2368901757 100644
--- a/source/blender/windowmanager/xr/intern/wm_xr_intern.h
+++ b/source/blender/windowmanager/xr/intern/wm_xr_intern.h
@@ -213,6 +213,11 @@ void wm_xr_session_draw_data_update(wmXrSessionState *state,
const XrSessionSettings *settings,
const GHOST_XrDrawViewInfo *draw_view,
wmXrDrawData *draw_data);
+/**
+ * Update information that is only stored for external state queries. E.g. for Python API to
+ * request the current (as in, last known) viewer pose.
+ * Controller data and action sets will be updated separately via wm_xr_session_actions_update().
+ */
void wm_xr_session_state_update(const XrSessionSettings *settings,
const wmXrDrawData *draw_data,
const GHOST_XrDrawViewInfo *draw_view,
@@ -230,9 +235,16 @@ void wm_xr_session_controller_data_populate(const wmXrAction *grip_action,
void wm_xr_session_controller_data_clear(wmXrSessionState *state);
/* wm_xr_draw.c */
+
void wm_xr_pose_to_mat(const GHOST_XrPose *pose, float r_mat[4][4]);
void wm_xr_pose_scale_to_mat(const GHOST_XrPose *pose, float scale, float r_mat[4][4]);
void wm_xr_pose_to_imat(const GHOST_XrPose *pose, float r_imat[4][4]);
void wm_xr_pose_scale_to_imat(const GHOST_XrPose *pose, float scale, float r_imat[4][4]);
+/**
+ * \brief Draw a viewport for a single eye.
+ *
+ * This is the main viewport drawing function for VR sessions. It's assigned to Ghost-XR as a
+ * callback (see GHOST_XrDrawViewFunc()) and executed for each view (read: eye).
+ */
void wm_xr_draw_view(const GHOST_XrDrawViewInfo *draw_view, void *customdata);
void wm_xr_draw_controllers(const struct bContext *C, struct ARegion *region, void *customdata);
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_operators.c b/source/blender/windowmanager/xr/intern/wm_xr_operators.c
index f3470edf2f7..c503f5d4fee 100644
--- a/source/blender/windowmanager/xr/intern/wm_xr_operators.c
+++ b/source/blender/windowmanager/xr/intern/wm_xr_operators.c
@@ -553,7 +553,7 @@ static int wm_xr_navigation_grab_modal(bContext *C, wmOperator *op, const wmEven
wm_xr_navigation_grab_bimanual_state_update(actiondata, data);
- /* Note: KM_PRESS and KM_RELEASE are the only two values supported by XR events during event
+ /* NOTE: #KM_PRESS and #KM_RELEASE are the only two values supported by XR events during event
* dispatching (see #wm_xr_session_action_states_interpret()). For modal XR operators, modal
* handling starts when an input is "pressed" (action state exceeds the action threshold) and
* ends when the input is "released" (state falls below the threshold). */
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_session.c b/source/blender/windowmanager/xr/intern/wm_xr_session.c
index 3224869b04a..bad735ee598 100644
--- a/source/blender/windowmanager/xr/intern/wm_xr_session.c
+++ b/source/blender/windowmanager/xr/intern/wm_xr_session.c
@@ -30,6 +30,7 @@
#include "BLI_math.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
#include "DNA_camera_types.h"
#include "DNA_space_types.h"
@@ -154,10 +155,6 @@ void wm_xr_session_toggle(wmWindowManager *wm,
}
}
-/**
- * Check if the XR-Session was triggered.
- * If an error happened while trying to start a session, this returns false too.
- */
bool WM_xr_session_exists(const wmXrData *xr)
{
return xr->runtime && xr->runtime->context && xr->runtime->session_state.is_started;
@@ -168,9 +165,6 @@ 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.
- */
bool WM_xr_session_is_ready(const wmXrData *xr)
{
return WM_xr_session_exists(xr) && GHOST_XrSessionIsRunning(xr->runtime->context);
@@ -250,10 +244,9 @@ wmWindow *wm_xr_session_root_window_or_fallback_get(const wmWindowManager *wm,
* It's important that the VR session follows some existing window, otherwise it would need to have
* an own depsgraph, which is an expense we should avoid.
*/
-static void wm_xr_session_scene_and_evaluated_depsgraph_get(Main *bmain,
- const wmWindowManager *wm,
- Scene **r_scene,
- Depsgraph **r_depsgraph)
+static void wm_xr_session_scene_and_depsgraph_get(const wmWindowManager *wm,
+ Scene **r_scene,
+ Depsgraph **r_depsgraph)
{
const wmWindow *root_win = wm_xr_session_root_window_or_fallback_get(wm, wm->xr.runtime);
@@ -263,7 +256,6 @@ static void wm_xr_session_scene_and_evaluated_depsgraph_get(Main *bmain,
Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer);
BLI_assert(scene && view_layer && depsgraph);
- BKE_scene_graph_evaluated_ensure(depsgraph, bmain);
*r_scene = scene;
*r_depsgraph = depsgraph;
}
@@ -354,11 +346,6 @@ void wm_xr_session_draw_data_update(wmXrSessionState *state,
}
}
-/**
- * Update information that is only stored for external state queries. E.g. for Python API to
- * request the current (as in, last known) viewer pose.
- * Controller data and action sets will be updated separately via wm_xr_session_actions_update().
- */
void wm_xr_session_state_update(const XrSessionSettings *settings,
const wmXrDrawData *draw_data,
const GHOST_XrDrawViewInfo *draw_view,
@@ -1314,7 +1301,6 @@ void wm_xr_session_controller_data_clear(wmXrSessionState *state)
static void wm_xr_session_surface_draw(bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
- Main *bmain = CTX_data_main(C);
wmXrDrawData draw_data;
if (!WM_xr_session_is_ready(&wm->xr)) {
@@ -1323,12 +1309,32 @@ static void wm_xr_session_surface_draw(bContext *C)
Scene *scene;
Depsgraph *depsgraph;
- wm_xr_session_scene_and_evaluated_depsgraph_get(bmain, wm, &scene, &depsgraph);
+ wm_xr_session_scene_and_depsgraph_get(wm, &scene, &depsgraph);
+ /* Might fail when force-redrawing windows with #WM_redraw_windows(), which is done on file
+ * writing for example. */
+ // BLI_assert(DEG_is_fully_evaluated(depsgraph));
wm_xr_session_draw_data_populate(&wm->xr, scene, depsgraph, &draw_data);
GHOST_XrSessionDrawViews(wm->xr.runtime->context, &draw_data);
- GPU_framebuffer_restore();
+ /* There's no active framebuffer if the session was cancelled (exception while drawing views). */
+ if (GPU_framebuffer_active_get()) {
+ GPU_framebuffer_restore();
+ }
+}
+
+static void wm_xr_session_do_depsgraph(bContext *C)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+
+ if (!WM_xr_session_is_ready(&wm->xr)) {
+ return;
+ }
+
+ Scene *scene;
+ Depsgraph *depsgraph;
+ wm_xr_session_scene_and_depsgraph_get(wm, &scene, &depsgraph);
+ BKE_scene_graph_evaluated_ensure(depsgraph, CTX_data_main(C));
}
bool wm_xr_session_surface_offscreen_ensure(wmXrSurfaceData *surface_data,
@@ -1439,6 +1445,7 @@ static wmSurface *wm_xr_session_surface_create(void)
data->controller_art = MEM_callocN(sizeof(*(data->controller_art)), "XrControllerRegionType");
surface->draw = wm_xr_session_surface_draw;
+ surface->do_depsgraph = wm_xr_session_do_depsgraph;
surface->free_data = wm_xr_session_surface_free_data;
surface->activate = DRW_xr_drawing_begin;
surface->deactivate = DRW_xr_drawing_end;
diff --git a/source/creator/creator.c b/source/creator/creator.c
index 6daaea38c34..c50b6ac4c79 100644
--- a/source/creator/creator.c
+++ b/source/creator/creator.c
@@ -58,6 +58,7 @@
#include "BKE_gpencil_modifier.h"
#include "BKE_idtype.h"
#include "BKE_image.h"
+#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_modifier.h"
#include "BKE_node.h"
@@ -242,6 +243,7 @@ void gmp_blender_init_allocator()
mp_set_memory_functions(gmp_alloc, gmp_realloc, gmp_free);
}
#endif
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -552,7 +554,8 @@ int main(int argc,
}
else {
/* When no file is loaded, show the splash screen. */
- if (!G.relbase_valid) {
+ const char *blendfile_path = BKE_main_blendfile_path_from_global();
+ if (blendfile_path[0] == '\0') {
WM_init_splash(C);
}
WM_main(C);
diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c
index 896d29e0583..d3cec093980 100644
--- a/source/creator/creator_args.c
+++ b/source/creator/creator_args.c
@@ -1994,9 +1994,7 @@ static int arg_handle_load_file(int UNUSED(argc), const char **argv, void *data)
if (BLO_has_bfile_extension(filename)) {
/* Just pretend a file was loaded, so the user can press Save and it'll
* save at the filename from the CLI. */
- BLI_strncpy(G_MAIN->name, filename, FILE_MAX);
- G.relbase_valid = true;
- G.save_over = true;
+ STRNCPY(G_MAIN->filepath, filename);
printf("... opened default scene instead; saving will write to: %s\n", filename);
}
else {
diff --git a/source/creator/creator_signals.c b/source/creator/creator_signals.c
index b74264fdddd..c23664d746f 100644
--- a/source/creator/creator_signals.c
+++ b/source/creator/creator_signals.c
@@ -117,11 +117,11 @@ static void sig_handle_crash(int signum)
if (memfile) {
char fname[FILE_MAX];
- if (!(G_MAIN && G_MAIN->name[0])) {
+ if (!(G_MAIN && G_MAIN->filepath[0])) {
BLI_join_dirfile(fname, sizeof(fname), BKE_tempdir_base(), "crash.blend");
}
else {
- BLI_strncpy(fname, G_MAIN->name, sizeof(fname));
+ STRNCPY(fname, G_MAIN->filepath);
BLI_path_extension_replace(fname, sizeof(fname), ".crash.blend");
}
@@ -138,11 +138,12 @@ static void sig_handle_crash(int signum)
char fname[FILE_MAX];
- if (!(G_MAIN && G_MAIN->name[0])) {
+ if (!(G_MAIN && G_MAIN->filepath[0])) {
BLI_join_dirfile(fname, sizeof(fname), BKE_tempdir_base(), "blender.crash.txt");
}
else {
- BLI_join_dirfile(fname, sizeof(fname), BKE_tempdir_base(), BLI_path_basename(G_MAIN->name));
+ BLI_join_dirfile(
+ fname, sizeof(fname), BKE_tempdir_base(), BLI_path_basename(G_MAIN->filepath));
BLI_path_extension_replace(fname, sizeof(fname), ".crash.txt");
}
diff --git a/source/tools b/source/tools
-Subproject 2e8c879248822c8e500ed49d79acc605e5aa75b
+Subproject b22d19e47f4d0353082f3d9f30ee8d244c5266d
diff --git a/tests/python/CMakeLists.txt b/tests/python/CMakeLists.txt
index fa63bdadd80..7f221e1c4eb 100644
--- a/tests/python/CMakeLists.txt
+++ b/tests/python/CMakeLists.txt
@@ -639,6 +639,7 @@ if(WITH_CYCLES OR WITH_OPENGL_RENDER_TESTS)
MESSAGE(STATUS "Disabling Cycles tests because WITH_OPENCOLORIO is disabled")
else()
set(render_tests
+ camera
bsdf
hair
image_colorspace
@@ -648,6 +649,7 @@ if(WITH_CYCLES OR WITH_OPENGL_RENDER_TESTS)
integrator
light
mesh
+ pointcloud
shader
shadow_catcher
sss
diff --git a/tests/python/bl_pyapi_idprop_datablock.py b/tests/python/bl_pyapi_idprop_datablock.py
index 5a7e4bee4fc..ddea613aae1 100644
--- a/tests/python/bl_pyapi_idprop_datablock.py
+++ b/tests/python/bl_pyapi_idprop_datablock.py
@@ -71,7 +71,7 @@ def expect_exception_or_abort(*, fn, ex):
print_fail_msg_and_exit("test failed")
-def expect_ouput_or_abort(*, fn, match_stderr=None, match_stdout=None):
+def expect_output_or_abort(*, fn, match_stderr=None, match_stdout=None):
stdout, stderr = io.StringIO(), io.StringIO()
@@ -278,7 +278,7 @@ def test_restrictions1():
expect_false_or_abort(not hasattr(op, "id_prop"))
bpy.utils.register_class(TEST_PT_DatablockProp)
- expect_ouput_or_abort(
+ expect_output_or_abort(
fn=lambda: bpy.utils.register_class(TEST_Op),
match_stderr="^ValueError: bpy_struct \"SCENE_OT_test_op\" registration error:",
)
diff --git a/tests/python/modules/mesh_test.py b/tests/python/modules/mesh_test.py
index 3cee4d88498..e3990bc207b 100644
--- a/tests/python/modules/mesh_test.py
+++ b/tests/python/modules/mesh_test.py
@@ -42,6 +42,7 @@
from abc import ABC, abstractmethod
import bpy
+import bmesh
import functools
import inspect
import os
@@ -102,14 +103,22 @@ class OperatorSpecEditMode:
"""
Holds one operator and its parameters.
"""
-
- def __init__(self, operator_name: str, operator_parameters: dict, select_mode: str, selection: set):
+ def __init__(
+ self,
+ operator_name: str,
+ operator_parameters: dict,
+ select_mode: str,
+ selection,
+ *,
+ select_history: bool = False,
+ ):
"""
Constructs an OperatorSpecEditMode. Raises ValueError if selec_mode is invalid.
:param operator_name: str - name of mesh operator from bpy.ops.mesh, e.g. "bevel" or "fill"
:param operator_parameters: dict - {name : val} dictionary containing operator parameters.
:param select_mode: str - mesh selection mode, must be either 'VERT', 'EDGE' or 'FACE'
- :param selection: set - set of vertices/edges/faces indices to select, e.g. [0, 9, 10].
+ :param selection: sequence - vertices/edges/faces indices to select, e.g. [0, 9, 10].
+ :param: select_history: bool - load selection into bmesh selection history.
"""
self.operator_name = operator_name
self.operator_parameters = operator_parameters
@@ -117,10 +126,12 @@ class OperatorSpecEditMode:
raise ValueError("select_mode must be either {}, {} or {}".format('VERT', 'EDGE', 'FACE'))
self.select_mode = select_mode
self.selection = selection
+ self.select_history = select_history
def __str__(self):
return "Operator: " + self.operator_name + " with parameters: " + str(self.operator_parameters) + \
- " in selection mode: " + self.select_mode + ", selecting " + str(self.selection)
+ " in selection mode: " + self.select_mode + ", selecting " + str(self.selection) + \
+ ("and loading bmesh selection history" if (self.select_history) else "")
class OperatorSpecObjectMode:
@@ -306,33 +317,51 @@ class MeshTest(ABC):
print("\nPASSED {} test successfully.".format(self.test_name))
self._print_result(result)
- def do_selection(self, mesh: bpy.types.Mesh, select_mode: str, selection: set):
+ def do_selection(self, mesh: bpy.types.Mesh, select_mode: str, selection, select_history: bool):
"""
Do selection on a mesh.
:param mesh: bpy.types.Mesh - input mesh
:param: select_mode: str - selection mode. Must be 'VERT', 'EDGE' or 'FACE'
- :param: selection: set - indices of selection.
+ :param: selection: sequence - indices of selection.
+ :param: select_history: bool - load selection into bmesh selection history
Example: select_mode='VERT' and selection={1,2,3} selects veritces 1, 2 and 3 of input mesh
"""
+ if select_history and isinstance(selection, set):
+ raise Exception("'selection' must be an ordered sequence, not a 'set' type when 'select_history=True'")
+
# Deselect all objects.
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_all(action='DESELECT')
- bpy.ops.object.mode_set(mode='OBJECT')
+
+ bm = bmesh.from_edit_mesh(mesh)
+
+ #bpy.ops.object.mode_set(mode='OBJECT')
bpy.context.tool_settings.mesh_select_mode = (select_mode == 'VERT',
select_mode == 'EDGE',
select_mode == 'FACE')
- items = (mesh.vertices if select_mode == 'VERT'
- else mesh.edges if select_mode == 'EDGE'
- else mesh.polygons if select_mode == 'FACE'
- else None)
+ items = (
+ bm.verts if select_mode == 'VERT' else
+ bm.edges if select_mode == 'EDGE' else
+ bm.faces if select_mode == 'FACE' else None
+ )
+
+ items.ensure_lookup_table()
+
if items is None:
raise ValueError("Invalid selection mode")
for index in selection:
items[index].select = True
+ if select_history:
+ for index in selection:
+ bm.select_history.add(items[index])
+ bm.select_history.validate()
+
+ bpy.ops.object.mode_set(mode='OBJECT')
+
def update_failed_test(self):
"""
Updates expected object.
@@ -344,8 +373,7 @@ class MeshTest(ABC):
bpy.data.objects.remove(self.expected_object, do_unlink=True)
self.evaluated_object.name = expected_object_name
- self.do_selection(self.evaluated_object.data,
- "VERT", evaluated_selection)
+ self.do_selection(self.evaluated_object.data, "VERT", evaluated_selection, False)
# Save file.
bpy.ops.wm.save_as_mainfile(filepath=bpy.data.filepath)
@@ -639,7 +667,11 @@ class SpecMeshTest(MeshTest):
:param operator: OperatorSpecEditMode - OperatorSpecEditMode object with parameters.
"""
self.do_selection(
- test_object.data, operator.select_mode, operator.selection)
+ test_object.data,
+ operator.select_mode,
+ operator.selection,
+ select_history=operator.select_history,
+ )
# Apply operator in edit mode.
bpy.ops.object.mode_set(mode='EDIT')
@@ -654,7 +686,7 @@ class SpecMeshTest(MeshTest):
raise TypeError("Incorrect operator parameters {!r} raised {!r}".format(operator.operator_parameters, ex))
if retval != {'FINISHED'}:
- raise RuntimeError("Unexpected operator return value: {}".format(retval))
+ raise RuntimeError("Unexpected operator return value: {}".format(operator.operator_name))
if self.verbose:
print("Applied {}".format(operator))
diff --git a/tests/python/operators.py b/tests/python/operators.py
index 9e5ac0054e8..e2a5e78cff7 100644
--- a/tests/python/operators.py
+++ b/tests/python/operators.py
@@ -204,6 +204,14 @@ def main():
SpecMeshTest("CubeShadeFlat", "testCubeShadeFlat", "expectedCubeShadeFlat",
[OperatorSpecEditMode("faces_shade_flat", {}, "FACE", {i for i in range(6)})]),
+ # hide
+ SpecMeshTest("HideFace", "testCubeHideFace", "expectedCubeHideFace",
+ [OperatorSpecEditMode("hide", {}, "FACE", {3})]),
+ SpecMeshTest("HideEdge", "testCubeHideEdge", "expectedCubeHideEdge",
+ [OperatorSpecEditMode("hide", {}, "EDGE", {1})]),
+ SpecMeshTest("HideVertex", "testCubeHideVertex", "expectedCubeHideVertex",
+ [OperatorSpecEditMode("hide", {}, "VERT", {0})]),
+
# inset faces
SpecMeshTest("CubeInset",
"testCubeInset", "expectedCubeInset", [OperatorSpecEditMode("inset", {"thickness": 0.2}, "VERT",
@@ -312,11 +320,60 @@ def main():
SpecMeshTest("CircleSelect2nd", "testCircleSelect2nd", "expectedCircleSelect2nd",
[OperatorSpecEditMode("select_nth", {}, "VERT", {i for i in range(32)})]),
+ # Subdivide edgering - Not currently functional, operator returns inconsistently
+ #SpecMeshTest("SubdivideEdgeringSurface", "testCylinderSubdivideEdgering", "expectedCylinderSubdivideEdgeringSurface",
+ # [OperatorSpecEditMode("subdivide_edgering", {"number_cuts": 5, "interpolation": 'SURFACE', "profile_shape_factor": 0.1}, "EDGE", {0, (i for i in range(96) if (i % 3))})]),
+ #SpecMeshTest("SubdivideEdgeringPath", "testCylinderSubdivideEdgering", "expectedCylinderSubdivideEdgeringPath",
+ # [OperatorSpecEditMode("subdivide_edgering", {"number_cuts": 5, "interpolation": 'PATH', "profile_shape_factor": 0.1}, "EDGE", {0, (i for i in range(96) if (i % 3))})]),
+ #SpecMeshTest("SubdivideEdgeringLinear", "testCylinderSubdivideEdgering", "expectedCylinderSubdivideEdgeringLinear",
+ # [OperatorSpecEditMode("subdivide_edgering", {"number_cuts": 5, "interpolation": 'LINEAR', "profile_shape_factor": 0.1}, "EDGE", {0, (i for i in range(96) if (i % 3))})]),
+
+ # Symmetry Snap
+ SpecMeshTest("SymmetrySnap", "testPlaneSymmetrySnap", "expectedPlaneSymmetrySnap",
+ [OperatorSpecEditMode("symmetry_snap", {"direction": 'POSITIVE_X', "threshold": 1, "factor": 0.75,
+ "use_center": False}, "VERT", {i for i in range(5)})]),
+ SpecMeshTest("SymmetrySnapCenter", "testPlaneSymmetrySnap", "expectedPlaneSymmetrySnapCenter",
+ [OperatorSpecEditMode("symmetry_snap", {"direction": 'NEGATIVE_X', "threshold": 1, "factor": 0.75,
+ "use_center": True}, "VERT", {i for i in range(5)})]),
+
+ # Tris to Quads
+ SpecMeshTest("TrisToQuads", "testPlanesTrisToQuad", "expectedPlanesTrisToQuad",
+ [OperatorSpecEditMode("tris_convert_to_quads", {"face_threshold":0.174533, "shape_threshold":0.174533,
+ "uvs":True, "vcols":True, "seam":True, "sharp":True, "materials":True}, "VERT", {i for i in range(32)})]),
+
# unsubdivide
# normal case
SpecMeshTest("CubeFaceUnsubdivide", "testCubeUnsubdivide", "expectedCubeUnsubdivide",
[OperatorSpecEditMode("unsubdivide", {}, "FACE", {i for i in range(6)})]),
+ # UV Manipulation
+ SpecMeshTest("UVRotate", "testCubeUV", "expectedCubeUVRotate",
+ [OperatorSpecEditMode("uvs_rotate", {}, "FACE", {2})]),
+ SpecMeshTest("UVRotateCCW", "testCubeUV", "expectedCubeUVRotateCCW",
+ [OperatorSpecEditMode("uvs_rotate", {"use_ccw": True}, "FACE", {2})]),
+ SpecMeshTest("UVReverse", "testCubeUV", "expectedCubeUVReverse",
+ [OperatorSpecEditMode("uvs_reverse", {}, "FACE", {2})]),
+ SpecMeshTest("UVAdd", "testCubeUV", "expectedCubeUVAdd",
+ [OperatorSpecEditMode("uv_texture_add", {}, "FACE", {})]),
+ SpecMeshTest("UVRemove", "testCubeUV", "expectedCubeUVRemove",
+ [OperatorSpecEditMode("uv_texture_remove", {}, "FACE", {})]),
+
+
+ # Vert Connect Concave
+ SpecMeshTest("VertexConnectConcave", "testPlaneVertConnectConcave", "expectedPlaneVertConnectConcave",
+ [OperatorSpecEditMode("vert_connect_concave", {}, "FACE", {0})]),
+ SpecMeshTest("VertexConnectConcaveConvexPentagon", "testPentagonVertConnectConcave", "expectedPentagonVertConnectConcave",
+ [OperatorSpecEditMode("vert_connect_concave", {}, "FACE", {0})]),
+ SpecMeshTest("VertexConnectConcaveQuad", "testPlaneVertConnectConcaveQuad", "expectedPlaneVertConnectConcaveQuad",
+ [OperatorSpecEditMode("vert_connect_concave", {}, "FACE", {0})]),
+
+ # Vert Connect Nonplanar
+ SpecMeshTest("VertexConnectNonplanar", "testPlaneVertConnectNonplanar", "expectedPlaneVertConnectNonplanar",
+ [OperatorSpecEditMode("vert_connect_nonplanar", {"angle_limit": 0.17453292}, "VERT", {i for i in range(9)})]),
+ SpecMeshTest("VertexConnectNonplanarNgon", "testPlaneVertConnectNonplanarNgon", "expectedPlaneVertConnectNonplanarNgon",
+ [OperatorSpecEditMode("vert_connect_nonplanar", {"angle_limit": 0.218166}, "VERT", {i for i in range(6)})]),
+
+
# T87259 - test cases
SpecMeshTest("CubeEdgeUnsubdivide", "testCubeEdgeUnsubdivide", "expectedCubeEdgeUnsubdivide",
[OperatorSpecEditMode("unsubdivide", {}, "EDGE", {i for i in range(6)})]),
@@ -325,8 +382,69 @@ def main():
# vert connect path
# Tip: It works only if there is an already existing face or more than 2 vertices.
- SpecMeshTest("CubeVertConnectPath", "testCubeVertConnectPath", "expectedCubeVertConnectPath",
- [OperatorSpecEditMode("vert_connect_path", {}, "VERT", {0, 5})]),
+ SpecMeshTest(
+ "PlaneVertConnectPath", "testPlaneVertConnectPath", "expectedPlaneVertConnectPath",
+ [OperatorSpecEditMode(
+ "vert_connect_path", {}, "VERT", (0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14),
+ select_history=True,
+ )],
+ ),
+
+ # Vertex Colors
+ SpecMeshTest(
+ "VertexColorAdd", "testCubeColorAdd", "expectedCubeColorAdd",
+ [OperatorSpecEditMode("vertex_color_add", {}, "VERT", {})],
+ ),
+ SpecMeshTest(
+ "VertexColorRemove", "testCubeColorRemove", "expectedCubeColorRemove",
+ [OperatorSpecEditMode("vertex_color_remove", {}, "VERT", {})],
+ ),
+ SpecMeshTest(
+ "VertexColorSculptAdd", "testCubeSculptAdd", "expectedCubeSculptAdd",
+ [OperatorSpecEditMode("sculpt_vertex_color_add", {}, "VERT", {})],
+ ),
+ SpecMeshTest(
+ "VertexColorSculptRemove", "testCubeSculptRemove", "expectedCubeSculptRemove",
+ [OperatorSpecEditMode("sculpt_vertex_color_remove", {}, "VERT", {})],
+ ),
+
+ # Laplacian Smooth
+ SpecMeshTest(
+ "LaplacianSmoothDefault", "testSphereLaplacianSmoothDefault", "expectedSphereLaplacianSmoothDefault",
+ [OperatorSpecEditMode("vertices_smooth_laplacian", {"preserve_volume": False}, "VERT", {i for i in range(482)})],
+ ),
+ SpecMeshTest(
+ "LaplacianSmoothHighValues", "testSphereLaplacianSmoothHigh", "expectedSphereLaplacianSmoothHigh",
+ [OperatorSpecEditMode("vertices_smooth_laplacian", {"preserve_volume": False, "repeat": 100, "lambda_factor": 10.0}, "VERT", {i for i in range(482)})],
+ ),
+ SpecMeshTest(
+ "LaplacianSmoothBorder", "testCubeLaplacianSmoothBorder", "expectedCubeLaplacianSmoothBorder",
+ [OperatorSpecEditMode("vertices_smooth_laplacian", {"preserve_volume": False, "lambda_border": 1.0}, "VERT", {i for i in range(25)})],
+ ),
+ SpecMeshTest(
+ "LaplacianSmoothHighBorder", "testCubeLaplacianSmoothHighBorder", "expectedCubeLaplacianSmoothHighBorder",
+ [OperatorSpecEditMode("vertices_smooth_laplacian", {"preserve_volume": False, "lambda_border": 100.0}, "VERT", {i for i in range(25)})],
+ ),
+ SpecMeshTest(
+ "LaplacianSmoothPreserveVolume", "testSphereLaplacianSmoothPreserveVol", "expectedSphereLaplacianSmoothPreserveVol",
+ [OperatorSpecEditMode("vertices_smooth_laplacian", {"preserve_volume": True}, "VERT", {i for i in range(482)})],
+ ),
+
+
+ # wireframe
+ SpecMeshTest(
+ "WireFrameDefault", "testCubeWireframeDefault", "expectedCubeWireframeDefault",
+ [OperatorSpecEditMode("wireframe", {}, "FACE", {i for i in range(6)})],
+ ),
+ SpecMeshTest(
+ "WireFrameAlt", "testCubeWireframeAlt", "expectedCubeWireframeAlt",
+ [OperatorSpecEditMode(
+ "wireframe", {
+ "use_boundary": False, "use_even_offset": False,
+ "use_relative_offset": True, "use_replace": False, "thickness": 0.3, "offset": 0.3,
+ "use_crease": True, "crease_weight": 0.01,
+ }, "FACE", {i for i in range(6)})],
+ ),
]